2 * \file BufferParams.cpp
3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
6 * \author Alfredo Braunstein
7 * \author Lars Gullik Bjønnes
8 * \author Jean-Marc Lasgouttes
10 * \author André Pönitz
11 * \author Martin Vermeer
13 * Full author contact details are available in file CREDITS.
18 #include "BufferParams.h"
21 #include "LayoutFile.h"
22 #include "BranchList.h"
25 #include "CiteEnginesList.h"
28 #include "Converter.h"
31 #include "IndicesList.h"
33 #include "LaTeXFeatures.h"
34 #include "LaTeXFonts.h"
38 #include "OutputParams.h"
40 #include "texstream.h"
43 #include "PDFOptions.h"
45 #include "frontends/alert.h"
47 #include "insets/InsetListingsParams.h"
48 #include "insets/InsetQuotes.h"
50 #include "support/convert.h"
51 #include "support/debug.h"
52 #include "support/FileName.h"
53 #include "support/filetools.h"
54 #include "support/gettext.h"
55 #include "support/Length.h"
56 #include "support/Messages.h"
57 #include "support/mutex.h"
58 #include "support/Package.h"
59 #include "support/Translator.h"
60 #include "support/lstrings.h"
66 using namespace lyx::support;
69 static char const * const string_paragraph_separation[] = {
74 static char const * const string_quotes_style[] = {
75 "english", "swedish", "german", "polish", "swiss", "danish", "plain",
76 "british", "swedishg", "french", "frenchin", "russian", "cjk", "cjkangle",
81 static char const * const string_papersize[] = {
82 "default", "custom", "letter", "legal", "executive",
83 "a0", "a1", "a2", "a3", "a4", "a5", "a6",
84 "b0", "b1", "b2", "b3", "b4", "b5", "b6",
85 "c0", "c1", "c2", "c3", "c4", "c5", "c6",
86 "b0j", "b1j", "b2j", "b3j", "b4j", "b5j", "b6j", ""
90 static char const * const string_papersize_geometry[] = {
91 "default", "custom", "letterpaper", "legalpaper", "executivepaper",
92 "a0paper", "a1paper", "a2paper", "a3paper", "a4paper", "a5paper", "a6paper",
93 "b0paper", "b1paper", "b2paper", "b3paper", "b4paper", "b5paper", "b6paper",
94 "c0paper", "c1paper", "c2paper", "c3paper", "c4paper", "c5paper", "c6paper",
95 "b0j", "b1j", "b2j", "b3j", "b4j", "b5j", "b6j", ""
99 static char const * const string_orientation[] = {
100 "portrait", "landscape", ""
104 static char const * const tex_graphics[] = {
105 "default", "dvialw", "dvilaser", "dvipdf", "dvipdfm", "dvipdfmx",
106 "dvips", "dvipsone", "dvitops", "dviwin", "dviwindo", "dvi2ps", "emtex",
107 "ln", "oztex", "pctexhp", "pctexps", "pctexwin", "pctex32", "pdftex",
108 "psprint", "pubps", "tcidvi", "textures", "truetex", "vtex", "xdvi",
118 // Paragraph separation
119 typedef Translator<string, BufferParams::ParagraphSeparation> ParSepTranslator;
122 ParSepTranslator const init_parseptranslator()
124 ParSepTranslator translator
125 (string_paragraph_separation[0], BufferParams::ParagraphIndentSeparation);
126 translator.addPair(string_paragraph_separation[1], BufferParams::ParagraphSkipSeparation);
131 ParSepTranslator const & parseptranslator()
133 static ParSepTranslator const translator =
134 init_parseptranslator();
140 typedef Translator<string, QuoteStyle> QuotesStyleTranslator;
143 QuotesStyleTranslator const init_quotesstyletranslator()
145 QuotesStyleTranslator translator
146 (string_quotes_style[0], QuoteStyle::English);
147 translator.addPair(string_quotes_style[1], QuoteStyle::Swedish);
148 translator.addPair(string_quotes_style[2], QuoteStyle::German);
149 translator.addPair(string_quotes_style[3], QuoteStyle::Polish);
150 translator.addPair(string_quotes_style[4], QuoteStyle::Swiss);
151 translator.addPair(string_quotes_style[5], QuoteStyle::Danish);
152 translator.addPair(string_quotes_style[6], QuoteStyle::Plain);
153 translator.addPair(string_quotes_style[7], QuoteStyle::British);
154 translator.addPair(string_quotes_style[8], QuoteStyle::SwedishG);
155 translator.addPair(string_quotes_style[9], QuoteStyle::French);
156 translator.addPair(string_quotes_style[10], QuoteStyle::FrenchIN);
157 translator.addPair(string_quotes_style[11], QuoteStyle::Russian);
158 translator.addPair(string_quotes_style[12], QuoteStyle::CJK);
159 translator.addPair(string_quotes_style[13], QuoteStyle::CJKAngle);
160 translator.addPair(string_quotes_style[14], QuoteStyle::Hungarian);
165 QuotesStyleTranslator const & quotesstyletranslator()
167 static QuotesStyleTranslator const translator =
168 init_quotesstyletranslator();
174 typedef Translator<string, PAPER_SIZE> PaperSizeTranslator;
177 static PaperSizeTranslator initPaperSizeTranslator()
179 PaperSizeTranslator translator(string_papersize[0], PAPER_DEFAULT);
180 translator.addPair(string_papersize[1], PAPER_CUSTOM);
181 translator.addPair(string_papersize[2], PAPER_USLETTER);
182 translator.addPair(string_papersize[3], PAPER_USLEGAL);
183 translator.addPair(string_papersize[4], PAPER_USEXECUTIVE);
184 translator.addPair(string_papersize[5], PAPER_A0);
185 translator.addPair(string_papersize[6], PAPER_A1);
186 translator.addPair(string_papersize[7], PAPER_A2);
187 translator.addPair(string_papersize[8], PAPER_A3);
188 translator.addPair(string_papersize[9], PAPER_A4);
189 translator.addPair(string_papersize[10], PAPER_A5);
190 translator.addPair(string_papersize[11], PAPER_A6);
191 translator.addPair(string_papersize[12], PAPER_B0);
192 translator.addPair(string_papersize[13], PAPER_B1);
193 translator.addPair(string_papersize[14], PAPER_B2);
194 translator.addPair(string_papersize[15], PAPER_B3);
195 translator.addPair(string_papersize[16], PAPER_B4);
196 translator.addPair(string_papersize[17], PAPER_B5);
197 translator.addPair(string_papersize[18], PAPER_B6);
198 translator.addPair(string_papersize[19], PAPER_C0);
199 translator.addPair(string_papersize[20], PAPER_C1);
200 translator.addPair(string_papersize[21], PAPER_C2);
201 translator.addPair(string_papersize[22], PAPER_C3);
202 translator.addPair(string_papersize[23], PAPER_C4);
203 translator.addPair(string_papersize[24], PAPER_C5);
204 translator.addPair(string_papersize[25], PAPER_C6);
205 translator.addPair(string_papersize[26], PAPER_JISB0);
206 translator.addPair(string_papersize[27], PAPER_JISB1);
207 translator.addPair(string_papersize[28], PAPER_JISB2);
208 translator.addPair(string_papersize[29], PAPER_JISB3);
209 translator.addPair(string_papersize[30], PAPER_JISB4);
210 translator.addPair(string_papersize[31], PAPER_JISB5);
211 translator.addPair(string_papersize[32], PAPER_JISB6);
216 PaperSizeTranslator const & papersizetranslator()
218 static PaperSizeTranslator const translator =
219 initPaperSizeTranslator();
225 typedef Translator<string, PAPER_ORIENTATION> PaperOrientationTranslator;
228 PaperOrientationTranslator const init_paperorientationtranslator()
230 PaperOrientationTranslator translator(string_orientation[0], ORIENTATION_PORTRAIT);
231 translator.addPair(string_orientation[1], ORIENTATION_LANDSCAPE);
236 PaperOrientationTranslator const & paperorientationtranslator()
238 static PaperOrientationTranslator const translator =
239 init_paperorientationtranslator();
245 typedef Translator<int, PageSides> SidesTranslator;
248 SidesTranslator const init_sidestranslator()
250 SidesTranslator translator(1, OneSide);
251 translator.addPair(2, TwoSides);
256 SidesTranslator const & sidestranslator()
258 static SidesTranslator const translator = init_sidestranslator();
264 typedef Translator<int, BufferParams::Package> PackageTranslator;
267 PackageTranslator const init_packagetranslator()
269 PackageTranslator translator(0, BufferParams::package_off);
270 translator.addPair(1, BufferParams::package_auto);
271 translator.addPair(2, BufferParams::package_on);
276 PackageTranslator const & packagetranslator()
278 static PackageTranslator const translator =
279 init_packagetranslator();
285 typedef Translator<string, Spacing::Space> SpaceTranslator;
288 SpaceTranslator const init_spacetranslator()
290 SpaceTranslator translator("default", Spacing::Default);
291 translator.addPair("single", Spacing::Single);
292 translator.addPair("onehalf", Spacing::Onehalf);
293 translator.addPair("double", Spacing::Double);
294 translator.addPair("other", Spacing::Other);
299 SpaceTranslator const & spacetranslator()
301 static SpaceTranslator const translator = init_spacetranslator();
306 bool inSystemDir(FileName const & document_dir, string & system_dir)
308 // A document is assumed to be in a system LyX directory (not
309 // necessarily the system directory of the running instance)
310 // if both "configure.py" and "chkconfig.ltx" are found in
311 // either document_dir/../ or document_dir/../../.
312 // If true, the system directory path is returned in system_dir
313 // with a trailing path separator.
315 string const msg = "Checking whether document is in a system dir...";
317 string dir = document_dir.absFileName();
319 for (int i = 0; i < 3; ++i) {
320 dir = addPath(dir, "..");
321 if (!fileSearch(dir, "configure.py").empty() &&
322 !fileSearch(dir, "chkconfig.ltx").empty()) {
323 LYXERR(Debug::FILES, msg << " yes");
324 system_dir = addPath(FileName(dir).realPath(), "");
329 LYXERR(Debug::FILES, msg << " no");
330 system_dir = string();
337 class BufferParams::Impl
342 AuthorList authorlist;
343 BranchList branchlist;
344 WordLangTable spellignore;
345 Bullet temp_bullets[4];
346 Bullet user_defined_bullets[4];
347 IndicesList indiceslist;
351 /** This is the amount of space used for paragraph_separation "skip",
352 * and for detached paragraphs in "indented" documents.
355 PDFOptions pdfoptions;
356 LayoutFileIndex baseClass_;
357 FormatList exportableFormatList;
358 FormatList viewableFormatList;
359 bool isViewCacheValid;
360 bool isExportCacheValid;
364 BufferParams::Impl::Impl()
365 : defskip(VSpace::MEDSKIP), baseClass_(string("")),
366 isViewCacheValid(false), isExportCacheValid(false)
368 // set initial author
370 authorlist.record(Author(from_utf8(lyxrc.user_name),
371 from_utf8(lyxrc.user_email),
372 from_utf8(lyxrc.user_initials)));
377 BufferParams::MemoryTraits::clone(BufferParams::Impl const * ptr)
380 return new BufferParams::Impl(*ptr);
384 void BufferParams::MemoryTraits::destroy(BufferParams::Impl * ptr)
390 BufferParams::BufferParams()
393 setBaseClass(defaultBaseclass());
394 cite_engine_ = "basic";
395 cite_engine_type_ = ENGINE_TYPE_DEFAULT;
397 paragraph_separation = ParagraphIndentSeparation;
398 is_math_indent = false;
399 math_numbering_side = DEFAULT;
400 quotes_style = QuoteStyle::English;
401 dynamic_quotes = false;
402 fontsize = "default";
405 papersize = PAPER_DEFAULT;
406 orientation = ORIENTATION_PORTRAIT;
407 use_geometry = false;
408 biblio_style = string();
409 use_bibtopic = false;
412 save_transient_properties = true;
413 track_changes = false;
414 output_changes = false;
416 postpone_fragile_content = true;
417 use_default_options = true;
418 maintain_unincluded_children = CM_None;
421 language = default_language;
423 fonts_roman[0] = "default";
424 fonts_roman[1] = "default";
425 fonts_sans[0] = "default";
426 fonts_sans[1] = "default";
427 fonts_typewriter[0] = "default";
428 fonts_typewriter[1] = "default";
429 fonts_math[0] = "auto";
430 fonts_math[1] = "auto";
431 fonts_default_family = "default";
432 useNonTeXFonts = false;
433 use_microtype = false;
434 use_dash_ligatures = true;
435 fonts_expert_sc = false;
436 fonts_roman_osf = false;
437 fonts_sans_osf = false;
438 fonts_typewriter_osf = false;
439 fonts_sans_scale[0] = 100;
440 fonts_sans_scale[1] = 100;
441 fonts_typewriter_scale[0] = 100;
442 fonts_typewriter_scale[1] = 100;
444 lang_package = "default";
445 graphics_driver = "default";
446 default_output_format = "default";
447 bibtex_command = "default";
448 index_command = "default";
451 listings_params = string();
452 pagestyle = "default";
453 tablestyle = "default";
454 float_alignment = "class";
455 float_placement = "class";
456 suppress_date = false;
457 justification = true;
458 // no color is the default (white)
459 backgroundcolor = lyx::rgbFromHexName("#ffffff");
460 isbackgroundcolor = false;
461 // no color is the default (black)
462 fontcolor = lyx::rgbFromHexName("#000000");
464 // light gray is the default font color for greyed-out notes
465 notefontcolor = lyx::rgbFromHexName("#cccccc");
466 isnotefontcolor = false;
467 boxbgcolor = lyx::rgbFromHexName("#ff0000");
468 isboxbgcolor = false;
469 compressed = lyxrc.save_compressed;
470 for (int iter = 0; iter < 4; ++iter) {
471 user_defined_bullet(iter) = ITEMIZE_DEFAULTS[iter];
472 temp_bullet(iter) = ITEMIZE_DEFAULTS[iter];
475 indiceslist().addDefault(B_("Index"));
476 html_be_strict = false;
477 html_math_output = MathML;
478 html_math_img_scale = 1.0;
479 html_css_as_file = false;
480 docbook_table_output = HTMLTable;
481 docbook_mathml_prefix = MPrefix;
482 display_pixel_ratio = 1.0;
484 shell_escape = false;
490 // map current author
491 author_map_[pimpl_->authorlist.get(0).bufferId()] = 0;
495 docstring BufferParams::B_(string const & l10n) const
497 LASSERT(language, return from_utf8(l10n));
498 return getMessages(language->code()).get(l10n);
502 BufferParams::Package BufferParams::use_package(std::string const & p) const
504 PackageMap::const_iterator it = use_packages.find(p);
505 if (it == use_packages.end())
511 void BufferParams::use_package(std::string const & p, BufferParams::Package u)
517 map<string, string> const & BufferParams::auto_packages()
519 static map<string, string> packages;
520 if (packages.empty()) {
521 // We could have a race condition here that two threads
522 // discover an empty map at the same time and want to fill
523 // it, but that is no problem, since the same contents is
524 // filled in twice then. Having the locker inside the
525 // packages.empty() condition has the advantage that we
526 // don't need the mutex overhead for simple reading.
528 Mutex::Locker locker(&mutex);
529 // adding a package here implies a file format change!
530 packages["amsmath"] =
531 N_("The LaTeX package amsmath is only used if AMS formula types or symbols from the AMS math toolbars are inserted into formulas");
532 packages["amssymb"] =
533 N_("The LaTeX package amssymb is only used if symbols from the AMS math toolbars are inserted into formulas");
535 N_("The LaTeX package cancel is only used if \\cancel commands are used in formulas");
537 N_("The LaTeX package esint is only used if special integral symbols are inserted into formulas");
538 packages["mathdots"] =
539 N_("The LaTeX package mathdots is only used if the command \\iddots is inserted into formulas");
540 packages["mathtools"] =
541 N_("The LaTeX package mathtools is only used if some mathematical relations are inserted into formulas");
543 N_("The LaTeX package mhchem is only used if either the command \\ce or \\cf is inserted into formulas");
544 packages["stackrel"] =
545 N_("The LaTeX package stackrel is only used if the command \\stackrel with subscript is inserted into formulas");
546 packages["stmaryrd"] =
547 N_("The LaTeX package stmaryrd is only used if symbols from the St Mary's Road symbol font for theoretical computer science are inserted into formulas");
548 packages["undertilde"] =
549 N_("The LaTeX package undertilde is only used if you use the math frame decoration 'utilde'");
555 bool BufferParams::useBibtopic() const
559 return (use_bibtopic || (!multibib.empty() && multibib != "child"));
563 AuthorList & BufferParams::authors()
565 return pimpl_->authorlist;
569 AuthorList const & BufferParams::authors() const
571 return pimpl_->authorlist;
575 void BufferParams::addAuthor(Author const & a)
577 author_map_[a.bufferId()] = pimpl_->authorlist.record(a);
581 BranchList & BufferParams::branchlist()
583 return pimpl_->branchlist;
587 BranchList const & BufferParams::branchlist() const
589 return pimpl_->branchlist;
593 IndicesList & BufferParams::indiceslist()
595 return pimpl_->indiceslist;
599 IndicesList const & BufferParams::indiceslist() const
601 return pimpl_->indiceslist;
605 WordLangTable & BufferParams::spellignore()
607 return pimpl_->spellignore;
611 WordLangTable const & BufferParams::spellignore() const
613 return pimpl_->spellignore;
617 bool BufferParams::spellignored(WordLangTuple const & wl) const
619 bool has_item = false;
620 vector<WordLangTuple> il = spellignore();
621 vector<WordLangTuple>::const_iterator it = il.begin();
622 for (; it != il.end(); ++it) {
623 if (it->lang()->code() != wl.lang()->code())
625 if (it->word() == wl.word()) {
634 Bullet & BufferParams::temp_bullet(lyx::size_type const index)
636 LASSERT(index < 4, return pimpl_->temp_bullets[0]);
637 return pimpl_->temp_bullets[index];
641 Bullet const & BufferParams::temp_bullet(lyx::size_type const index) const
643 LASSERT(index < 4, return pimpl_->temp_bullets[0]);
644 return pimpl_->temp_bullets[index];
648 Bullet & BufferParams::user_defined_bullet(lyx::size_type const index)
650 LASSERT(index < 4, return pimpl_->temp_bullets[0]);
651 return pimpl_->user_defined_bullets[index];
655 Bullet const & BufferParams::user_defined_bullet(lyx::size_type const index) const
657 LASSERT(index < 4, return pimpl_->temp_bullets[0]);
658 return pimpl_->user_defined_bullets[index];
662 Spacing & BufferParams::spacing()
664 return pimpl_->spacing;
668 Spacing const & BufferParams::spacing() const
670 return pimpl_->spacing;
674 PDFOptions & BufferParams::pdfoptions()
676 return pimpl_->pdfoptions;
680 PDFOptions const & BufferParams::pdfoptions() const
682 return pimpl_->pdfoptions;
686 Length const & BufferParams::getMathIndent() const
688 return pimpl_->mathindent;
692 void BufferParams::setMathIndent(Length const & indent)
694 pimpl_->mathindent = indent;
698 Length const & BufferParams::getParIndent() const
700 return pimpl_->parindent;
704 void BufferParams::setParIndent(Length const & indent)
706 pimpl_->parindent = indent;
710 VSpace const & BufferParams::getDefSkip() const
712 return pimpl_->defskip;
716 void BufferParams::setDefSkip(VSpace const & vs)
718 // DEFSKIP will cause an infinite loop
719 LASSERT(vs.kind() != VSpace::DEFSKIP, return);
720 pimpl_->defskip = vs;
724 BufferParams::MathNumber BufferParams::getMathNumber() const
726 if (math_numbering_side != DEFAULT)
727 return math_numbering_side;
728 // FIXME: do not hardcode language here
729 else if (language->lang() == "arabic_arabi"
730 || documentClass().provides("leqno"))
737 string BufferParams::readToken(Lexer & lex, string const & token,
738 FileName const & filename)
741 FileName const & filepath = filename.onlyPath();
743 if (token == "\\textclass") {
745 string const classname = lex.getString();
746 // if there exists a local layout file, ignore the system one
747 // NOTE: in this case, the textclass (.cls file) is assumed to
750 LayoutFileList & bcl = LayoutFileList::get();
751 if (!filepath.empty()) {
752 // If classname is an absolute path, the document is
753 // using a local layout file which could not be accessed
754 // by a relative path. In this case the path is correct
755 // even if the document was moved to a different
756 // location. However, we will have a problem if the
757 // document was generated on a different platform.
758 bool isabsolute = FileName::isAbsolute(classname);
759 string const classpath = onlyPath(classname);
760 string const path = isabsolute ? classpath
761 : FileName(addPath(filepath.absFileName(),
762 classpath)).realPath();
763 string const oldpath = isabsolute ? string()
764 : FileName(addPath(origin, classpath)).realPath();
765 tcp = bcl.addLocalLayout(onlyFileName(classname), path, oldpath);
767 // that returns non-empty if a "local" layout file is found.
769 result = to_utf8(makeRelPath(from_utf8(onlyPath(tcp)),
770 from_utf8(filepath.absFileName())));
773 setBaseClass(onlyFileName(tcp));
775 setBaseClass(onlyFileName(classname));
776 // We assume that a tex class exists for local or unknown
777 // layouts so this warning, will only be given for system layouts.
778 if (!baseClass()->isTeXClassAvailable()) {
779 docstring const desc =
780 translateIfPossible(from_utf8(baseClass()->description()));
781 docstring const prereqs =
782 from_utf8(baseClass()->prerequisites());
783 docstring const msg =
784 bformat(_("The selected document class\n"
786 "requires external files that are not available.\n"
787 "The document class can still be used, but the\n"
788 "document cannot be compiled until the following\n"
789 "prerequisites are installed:\n"
791 "See section 3.1.2.2 (Class Availability) of the\n"
792 "User's Guide for more information."), desc, prereqs);
793 frontend::Alert::warning(_("Document class not available"),
796 } else if (token == "\\save_transient_properties") {
797 lex >> save_transient_properties;
798 } else if (token == "\\origin") {
800 origin = lex.getString();
801 string const sysdirprefix = "/systemlyxdir/";
802 if (prefixIs(origin, sysdirprefix)) {
804 if (inSystemDir(filepath, docsys))
805 origin.replace(0, sysdirprefix.length() - 1, docsys);
807 origin.replace(0, sysdirprefix.length() - 1,
808 package().system_support().absFileName());
810 } else if (token == "\\begin_metadata") {
811 readDocumentMetadata(lex);
812 } else if (token == "\\begin_preamble") {
814 } else if (token == "\\begin_local_layout") {
815 readLocalLayout(lex, false);
816 } else if (token == "\\begin_forced_local_layout") {
817 readLocalLayout(lex, true);
818 } else if (token == "\\begin_modules") {
820 } else if (token == "\\begin_removed_modules") {
821 readRemovedModules(lex);
822 } else if (token == "\\begin_includeonly") {
823 readIncludeonly(lex);
824 } else if (token == "\\maintain_unincluded_children") {
828 maintain_unincluded_children = CM_None;
829 else if (tmp == "mostly")
830 maintain_unincluded_children = CM_Mostly;
831 else if (tmp == "strict")
832 maintain_unincluded_children = CM_Strict;
833 } else if (token == "\\options") {
835 options = lex.getString();
836 } else if (token == "\\use_default_options") {
837 lex >> use_default_options;
838 } else if (token == "\\master") {
840 master = lex.getString();
841 if (!filepath.empty() && FileName::isAbsolute(origin)) {
842 bool const isabs = FileName::isAbsolute(master);
843 FileName const abspath(isabs ? master : origin + master);
844 bool const moved = filepath != FileName(origin);
845 if (moved && abspath.exists()) {
846 docstring const path = isabs
848 : from_utf8(abspath.realPath());
849 docstring const refpath =
850 from_utf8(filepath.absFileName());
851 master = to_utf8(makeRelPath(path, refpath));
854 } else if (token == "\\suppress_date") {
855 lex >> suppress_date;
856 } else if (token == "\\justification") {
857 lex >> justification;
858 } else if (token == "\\language") {
860 } else if (token == "\\language_package") {
862 lang_package = lex.getString();
863 } else if (token == "\\inputencoding") {
865 } else if (token == "\\graphics") {
866 readGraphicsDriver(lex);
867 } else if (token == "\\default_output_format") {
868 lex >> default_output_format;
869 } else if (token == "\\bibtex_command") {
871 bibtex_command = lex.getString();
872 } else if (token == "\\index_command") {
874 index_command = lex.getString();
875 } else if (token == "\\fontencoding") {
877 fontenc = lex.getString();
878 } else if (token == "\\font_roman") {
879 lex >> fonts_roman[0];
880 lex >> fonts_roman[1];
881 } else if (token == "\\font_sans") {
882 lex >> fonts_sans[0];
883 lex >> fonts_sans[1];
884 } else if (token == "\\font_typewriter") {
885 lex >> fonts_typewriter[0];
886 lex >> fonts_typewriter[1];
887 } else if (token == "\\font_math") {
888 lex >> fonts_math[0];
889 lex >> fonts_math[1];
890 } else if (token == "\\font_default_family") {
891 lex >> fonts_default_family;
892 } else if (token == "\\use_non_tex_fonts") {
893 lex >> useNonTeXFonts;
894 } else if (token == "\\font_sc") {
895 lex >> fonts_expert_sc;
896 } else if (token == "\\font_roman_osf") {
897 lex >> fonts_roman_osf;
898 } else if (token == "\\font_sans_osf") {
899 lex >> fonts_sans_osf;
900 } else if (token == "\\font_typewriter_osf") {
901 lex >> fonts_typewriter_osf;
902 } else if (token == "\\font_roman_opts") {
903 lex >> font_roman_opts;
904 } else if (token == "\\font_sf_scale") {
905 lex >> fonts_sans_scale[0];
906 lex >> fonts_sans_scale[1];
907 } else if (token == "\\font_sans_opts") {
908 lex >> font_sans_opts;
909 } else if (token == "\\font_tt_scale") {
910 lex >> fonts_typewriter_scale[0];
911 lex >> fonts_typewriter_scale[1];
912 } else if (token == "\\font_typewriter_opts") {
913 lex >> font_typewriter_opts;
914 } else if (token == "\\font_cjk") {
916 } else if (token == "\\use_microtype") {
917 lex >> use_microtype;
918 } else if (token == "\\use_dash_ligatures") {
919 lex >> use_dash_ligatures;
920 } else if (token == "\\paragraph_separation") {
923 paragraph_separation = parseptranslator().find(parsep);
924 } else if (token == "\\paragraph_indentation") {
926 string parindent = lex.getString();
927 if (parindent == "default")
928 pimpl_->parindent = Length();
930 pimpl_->parindent = Length(parindent);
931 } else if (token == "\\defskip") {
933 string const defskip = lex.getString();
934 pimpl_->defskip = VSpace(defskip);
935 if (pimpl_->defskip.kind() == VSpace::DEFSKIP)
937 pimpl_->defskip = VSpace(VSpace::MEDSKIP);
938 } else if (token == "\\is_math_indent") {
939 lex >> is_math_indent;
940 } else if (token == "\\math_indentation") {
942 string mathindent = lex.getString();
943 if (mathindent == "default")
944 pimpl_->mathindent = Length();
946 pimpl_->mathindent = Length(mathindent);
947 } else if (token == "\\math_numbering_side") {
951 math_numbering_side = LEFT;
952 else if (tmp == "right")
953 math_numbering_side = RIGHT;
955 math_numbering_side = DEFAULT;
956 } else if (token == "\\quotes_style") {
959 quotes_style = quotesstyletranslator().find(qstyle);
960 } else if (token == "\\dynamic_quotes") {
961 lex >> dynamic_quotes;
962 } else if (token == "\\papersize") {
965 papersize = papersizetranslator().find(ppsize);
966 } else if (token == "\\use_geometry") {
968 } else if (token == "\\use_package") {
973 use_package(package, packagetranslator().find(use));
974 } else if (token == "\\cite_engine") {
976 cite_engine_ = lex.getString();
977 } else if (token == "\\cite_engine_type") {
980 cite_engine_type_ = theCiteEnginesList.getType(engine_type);
981 } else if (token == "\\biblio_style") {
983 biblio_style = lex.getString();
984 } else if (token == "\\biblio_options") {
986 biblio_opts = trim(lex.getString());
987 } else if (token == "\\biblatex_bibstyle") {
989 biblatex_bibstyle = trim(lex.getString());
990 } else if (token == "\\biblatex_citestyle") {
992 biblatex_citestyle = trim(lex.getString());
993 } else if (token == "\\use_bibtopic") {
995 } else if (token == "\\multibib") {
997 } else if (token == "\\use_indices") {
999 } else if (token == "\\tracking_changes") {
1000 lex >> track_changes;
1001 } else if (token == "\\output_changes") {
1002 lex >> output_changes;
1003 } else if (token == "\\change_bars") {
1005 } else if (token == "\\postpone_fragile_content") {
1006 lex >> postpone_fragile_content;
1007 } else if (token == "\\branch") {
1009 docstring branch = lex.getDocString();
1010 branchlist().add(branch);
1013 string const tok = lex.getString();
1014 if (tok == "\\end_branch")
1016 Branch * branch_ptr = branchlist().find(branch);
1017 if (tok == "\\selected") {
1020 branch_ptr->setSelected(lex.getInteger());
1022 if (tok == "\\filename_suffix") {
1025 branch_ptr->setFileNameSuffix(lex.getInteger());
1027 if (tok == "\\color") {
1029 vector<string> const colors = getVectorFromString(lex.getString(), " ");
1030 string const lmcolor = colors.front();
1032 if (colors.size() > 1)
1033 dmcolor = colors.back();
1035 branch_ptr->setColors(lmcolor, dmcolor);
1038 } else if (token == "\\index") {
1040 docstring index = lex.getDocString();
1042 indiceslist().add(index);
1045 string const tok = lex.getString();
1046 if (tok == "\\end_index")
1048 Index * index_ptr = indiceslist().find(index);
1049 if (tok == "\\shortcut") {
1051 shortcut = lex.getDocString();
1053 index_ptr->setShortcut(shortcut);
1055 if (tok == "\\color") {
1057 string color = lex.getString();
1059 index_ptr->setColor(color);
1060 // Update also the Color table:
1061 if (color == "none")
1062 color = lcolor.getX11HexName(Color_background);
1064 if (!shortcut.empty())
1065 lcolor.setColor(to_utf8(shortcut)+ "@" + filename.absFileName(), color);
1068 } else if (token == "\\spellchecker_ignore") {
1070 docstring wl = lex.getDocString();
1072 docstring word = split(wl, language, ' ');
1073 Language const * lang = languages.getLanguage(to_ascii(language));
1075 spellignore().push_back(WordLangTuple(word, lang));
1076 } else if (token == "\\author") {
1078 istringstream ss(lex.getString());
1082 } else if (token == "\\paperorientation") {
1085 orientation = paperorientationtranslator().find(orient);
1086 } else if (token == "\\backgroundcolor") {
1088 backgroundcolor = lyx::rgbFromHexName(lex.getString());
1089 isbackgroundcolor = true;
1090 } else if (token == "\\fontcolor") {
1092 fontcolor = lyx::rgbFromHexName(lex.getString());
1094 } else if (token == "\\notefontcolor") {
1096 string color = lex.getString();
1097 notefontcolor = lyx::rgbFromHexName(color);
1098 lcolor.setColor("notefontcolor", color);
1099 lcolor.setLaTeXName("notefontcolor", "note_fontcolor");
1100 lcolor.setGUIName("notefontcolor", N_("greyedout inset text"));
1101 // set a local name for the painter
1102 lcolor.setColor("notefontcolor@" + filename.absFileName(), color);
1103 isnotefontcolor = true;
1104 } else if (token == "\\boxbgcolor") {
1106 string color = lex.getString();
1107 boxbgcolor = lyx::rgbFromHexName(color);
1108 lcolor.setColor("boxbgcolor@" + filename.absFileName(), color);
1109 isboxbgcolor = true;
1110 } else if (token == "\\paperwidth") {
1112 } else if (token == "\\paperheight") {
1114 } else if (token == "\\leftmargin") {
1116 } else if (token == "\\topmargin") {
1118 } else if (token == "\\rightmargin") {
1120 } else if (token == "\\bottommargin") {
1121 lex >> bottommargin;
1122 } else if (token == "\\headheight") {
1124 } else if (token == "\\headsep") {
1126 } else if (token == "\\footskip") {
1128 } else if (token == "\\columnsep") {
1130 } else if (token == "\\paperfontsize") {
1132 } else if (token == "\\papercolumns") {
1134 } else if (token == "\\listings_params") {
1137 listings_params = InsetListingsParams(par).params();
1138 } else if (token == "\\papersides") {
1141 sides = sidestranslator().find(psides);
1142 } else if (token == "\\paperpagestyle") {
1144 } else if (token == "\\tablestyle") {
1146 } else if (token == "\\bullet") {
1148 } else if (token == "\\bulletLaTeX") {
1149 readBulletsLaTeX(lex);
1150 } else if (token == "\\secnumdepth") {
1152 } else if (token == "\\tocdepth") {
1154 } else if (token == "\\spacing") {
1158 if (nspacing == "other") {
1161 spacing().set(spacetranslator().find(nspacing), tmp_val);
1162 } else if (token == "\\float_placement") {
1163 lex >> float_placement;
1164 } else if (token == "\\float_alignment") {
1165 lex >> float_alignment;
1167 } else if (prefixIs(token, "\\pdf_") || token == "\\use_hyperref") {
1168 string toktmp = pdfoptions().readToken(lex, token);
1169 if (!toktmp.empty()) {
1170 lyxerr << "PDFOptions::readToken(): Unknown token: " <<
1174 } else if (token == "\\html_math_output") {
1177 html_math_output = static_cast<MathOutput>(temp);
1178 } else if (token == "\\html_be_strict") {
1179 lex >> html_be_strict;
1180 } else if (token == "\\html_css_as_file") {
1181 lex >> html_css_as_file;
1182 } else if (token == "\\html_math_img_scale") {
1183 lex >> html_math_img_scale;
1184 } else if (token == "\\html_latex_start") {
1186 html_latex_start = lex.getString();
1187 } else if (token == "\\html_latex_end") {
1189 html_latex_end = lex.getString();
1190 } else if (token == "\\docbook_table_output") {
1193 docbook_table_output = static_cast<TableOutput>(temp);
1194 } else if (token == "\\docbook_mathml_prefix") {
1197 docbook_mathml_prefix = static_cast<MathMLNameSpacePrefix>(temp);
1198 } else if (token == "\\output_sync") {
1200 } else if (token == "\\output_sync_macro") {
1201 lex >> output_sync_macro;
1202 } else if (token == "\\use_refstyle") {
1203 lex >> use_refstyle;
1204 } else if (token == "\\use_minted") {
1206 } else if (token == "\\use_lineno") {
1208 } else if (token == "\\lineno_options") {
1210 lineno_opts = trim(lex.getString());
1212 lyxerr << "BufferParams::readToken(): Unknown token: " <<
1222 // Quote argument if it contains spaces
1223 string quoteIfNeeded(string const & str) {
1224 if (contains(str, ' '))
1225 return "\"" + str + "\"";
1231 void BufferParams::writeFile(ostream & os, Buffer const * buf) const
1233 // The top of the file is written by the buffer.
1234 // Prints out the buffer info into the .lyx file given by file
1236 os << "\\save_transient_properties "
1237 << convert<string>(save_transient_properties) << '\n';
1239 // the document directory (must end with a path separator)
1240 // realPath() is used to resolve symlinks, while addPath(..., "")
1241 // ensures a trailing path separator.
1243 string filepath = addPath(buf->fileName().onlyPath().realPath(), "");
1244 string const sysdir = inSystemDir(FileName(filepath), docsys) ? docsys
1245 : addPath(package().system_support().realPath(), "");
1246 string const relpath =
1247 to_utf8(makeRelPath(from_utf8(filepath), from_utf8(sysdir)));
1248 if (!prefixIs(relpath, "../") && !FileName::isAbsolute(relpath))
1249 filepath = addPath("/systemlyxdir", relpath);
1250 else if (!save_transient_properties || !lyxrc.save_origin)
1251 filepath = "unavailable";
1252 os << "\\origin " << quoteIfNeeded(filepath) << '\n';
1255 os << "\\textclass "
1256 << quoteIfNeeded(buf->includedFilePath(addName(buf->layoutPos(),
1257 baseClass()->name()), "layout"))
1260 // then document metadata
1261 if (!document_metadata.empty()) {
1262 // remove '\n' from the end of document_metadata
1263 docstring const tmpmd = rtrim(document_metadata, "\n");
1264 os << "\\begin_metadata\n"
1266 << "\n\\end_metadata\n";
1269 // then the preamble
1270 if (!preamble.empty()) {
1271 // remove '\n' from the end of preamble
1272 docstring const tmppreamble = rtrim(preamble, "\n");
1273 os << "\\begin_preamble\n"
1274 << to_utf8(tmppreamble)
1275 << "\n\\end_preamble\n";
1279 if (!options.empty()) {
1280 os << "\\options " << options << '\n';
1283 // use the class options defined in the layout?
1284 os << "\\use_default_options "
1285 << convert<string>(use_default_options) << "\n";
1287 // the master document
1288 if (!master.empty()) {
1289 os << "\\master " << master << '\n';
1293 if (!removed_modules_.empty()) {
1294 os << "\\begin_removed_modules" << '\n';
1295 for (auto const & mod : removed_modules_)
1297 os << "\\end_removed_modules" << '\n';
1301 if (!layout_modules_.empty()) {
1302 os << "\\begin_modules" << '\n';
1303 for (auto const & mod : layout_modules_)
1305 os << "\\end_modules" << '\n';
1309 if (!included_children_.empty()) {
1310 os << "\\begin_includeonly" << '\n';
1311 for (auto const & c : included_children_)
1313 os << "\\end_includeonly" << '\n';
1316 switch (maintain_unincluded_children) {
1327 os << "\\maintain_unincluded_children " << muc << '\n';
1329 // local layout information
1330 docstring const local_layout = getLocalLayout(false);
1331 if (!local_layout.empty()) {
1332 // remove '\n' from the end
1333 docstring const tmplocal = rtrim(local_layout, "\n");
1334 os << "\\begin_local_layout\n"
1335 << to_utf8(tmplocal)
1336 << "\n\\end_local_layout\n";
1338 docstring const forced_local_layout = getLocalLayout(true);
1339 if (!forced_local_layout.empty()) {
1340 // remove '\n' from the end
1341 docstring const tmplocal = rtrim(forced_local_layout, "\n");
1342 os << "\\begin_forced_local_layout\n"
1343 << to_utf8(tmplocal)
1344 << "\n\\end_forced_local_layout\n";
1347 // then the text parameters
1348 if (language != ignore_language)
1349 os << "\\language " << language->lang() << '\n';
1350 os << "\\language_package " << lang_package
1351 << "\n\\inputencoding " << inputenc
1352 << "\n\\fontencoding " << fontenc
1353 << "\n\\font_roman \"" << fonts_roman[0]
1354 << "\" \"" << fonts_roman[1] << '"'
1355 << "\n\\font_sans \"" << fonts_sans[0]
1356 << "\" \"" << fonts_sans[1] << '"'
1357 << "\n\\font_typewriter \"" << fonts_typewriter[0]
1358 << "\" \"" << fonts_typewriter[1] << '"'
1359 << "\n\\font_math \"" << fonts_math[0]
1360 << "\" \"" << fonts_math[1] << '"'
1361 << "\n\\font_default_family " << fonts_default_family
1362 << "\n\\use_non_tex_fonts " << convert<string>(useNonTeXFonts)
1363 << "\n\\font_sc " << convert<string>(fonts_expert_sc)
1364 << "\n\\font_roman_osf " << convert<string>(fonts_roman_osf)
1365 << "\n\\font_sans_osf " << convert<string>(fonts_sans_osf)
1366 << "\n\\font_typewriter_osf " << convert<string>(fonts_typewriter_osf);
1367 if (!font_roman_opts.empty())
1368 os << "\n\\font_roman_opts \"" << font_roman_opts << "\"";
1369 os << "\n\\font_sf_scale " << fonts_sans_scale[0]
1370 << ' ' << fonts_sans_scale[1];
1371 if (!font_sans_opts.empty())
1372 os << "\n\\font_sans_opts \"" << font_sans_opts << "\"";
1373 os << "\n\\font_tt_scale " << fonts_typewriter_scale[0]
1374 << ' ' << fonts_typewriter_scale[1];
1375 if (!font_typewriter_opts.empty())
1376 os << "\n\\font_typewriter_opts \"" << font_typewriter_opts << "\"";
1378 if (!fonts_cjk.empty())
1379 os << "\\font_cjk " << fonts_cjk << '\n';
1380 os << "\\use_microtype " << convert<string>(use_microtype) << '\n';
1381 os << "\\use_dash_ligatures " << convert<string>(use_dash_ligatures) << '\n';
1382 os << "\\graphics " << graphics_driver << '\n';
1383 os << "\\default_output_format " << default_output_format << '\n';
1384 os << "\\output_sync " << output_sync << '\n';
1385 if (!output_sync_macro.empty())
1386 os << "\\output_sync_macro \"" << output_sync_macro << "\"\n";
1387 os << "\\bibtex_command " << bibtex_command << '\n';
1388 os << "\\index_command " << index_command << '\n';
1390 if (!float_placement.empty())
1391 os << "\\float_placement " << float_placement << '\n';
1392 if (!float_alignment.empty())
1393 os << "\\float_alignment " << float_alignment << '\n';
1394 os << "\\paperfontsize " << fontsize << '\n';
1396 spacing().writeFile(os);
1397 pdfoptions().writeFile(os);
1399 os << "\\papersize " << string_papersize[papersize]
1400 << "\n\\use_geometry " << convert<string>(use_geometry);
1401 map<string, string> const & packages = auto_packages();
1402 for (auto const & pack : packages)
1403 os << "\n\\use_package " << pack.first << ' '
1404 << use_package(pack.first);
1406 os << "\n\\cite_engine ";
1408 if (!cite_engine_.empty())
1413 os << "\n\\cite_engine_type " << theCiteEnginesList.getTypeAsString(cite_engine_type_);
1415 if (!biblio_style.empty())
1416 os << "\n\\biblio_style " << biblio_style;
1417 if (!biblio_opts.empty())
1418 os << "\n\\biblio_options " << biblio_opts;
1419 if (!biblatex_bibstyle.empty())
1420 os << "\n\\biblatex_bibstyle " << biblatex_bibstyle;
1421 if (!biblatex_citestyle.empty())
1422 os << "\n\\biblatex_citestyle " << biblatex_citestyle;
1423 if (!multibib.empty())
1424 os << "\n\\multibib " << multibib;
1426 os << "\n\\use_bibtopic " << convert<string>(use_bibtopic)
1427 << "\n\\use_indices " << convert<string>(use_indices)
1428 << "\n\\paperorientation " << string_orientation[orientation]
1429 << "\n\\suppress_date " << convert<string>(suppress_date)
1430 << "\n\\justification " << convert<string>(justification)
1431 << "\n\\use_refstyle " << use_refstyle
1432 << "\n\\use_minted " << use_minted
1433 << "\n\\use_lineno " << use_lineno
1436 if (!lineno_opts.empty())
1437 os << "\\lineno_options " << lineno_opts << '\n';
1439 if (isbackgroundcolor)
1440 os << "\\backgroundcolor " << lyx::X11hexname(backgroundcolor) << '\n';
1442 os << "\\fontcolor " << lyx::X11hexname(fontcolor) << '\n';
1443 if (isnotefontcolor)
1444 os << "\\notefontcolor " << lyx::X11hexname(notefontcolor) << '\n';
1446 os << "\\boxbgcolor " << lyx::X11hexname(boxbgcolor) << '\n';
1448 for (auto const & br : branchlist()) {
1449 os << "\\branch " << to_utf8(br.branch())
1450 << "\n\\selected " << br.isSelected()
1451 << "\n\\filename_suffix " << br.hasFileNameSuffix()
1452 << "\n\\color " << br.lightModeColor() << " " << br.darkModeColor()
1457 for (auto const & id : indiceslist()) {
1458 os << "\\index " << to_utf8(id.index())
1459 << "\n\\shortcut " << to_utf8(id.shortcut())
1460 << "\n\\color " << lyx::X11hexname(id.color())
1465 for (auto const & si : spellignore()) {
1466 os << "\\spellchecker_ignore " << si.lang()->lang()
1467 << " " << to_utf8(si.word())
1471 if (!paperwidth.empty())
1472 os << "\\paperwidth "
1473 << VSpace(paperwidth).asLyXCommand() << '\n';
1474 if (!paperheight.empty())
1475 os << "\\paperheight "
1476 << VSpace(paperheight).asLyXCommand() << '\n';
1477 if (!leftmargin.empty())
1478 os << "\\leftmargin "
1479 << VSpace(leftmargin).asLyXCommand() << '\n';
1480 if (!topmargin.empty())
1481 os << "\\topmargin "
1482 << VSpace(topmargin).asLyXCommand() << '\n';
1483 if (!rightmargin.empty())
1484 os << "\\rightmargin "
1485 << VSpace(rightmargin).asLyXCommand() << '\n';
1486 if (!bottommargin.empty())
1487 os << "\\bottommargin "
1488 << VSpace(bottommargin).asLyXCommand() << '\n';
1489 if (!headheight.empty())
1490 os << "\\headheight "
1491 << VSpace(headheight).asLyXCommand() << '\n';
1492 if (!headsep.empty())
1494 << VSpace(headsep).asLyXCommand() << '\n';
1495 if (!footskip.empty())
1497 << VSpace(footskip).asLyXCommand() << '\n';
1498 if (!columnsep.empty())
1499 os << "\\columnsep "
1500 << VSpace(columnsep).asLyXCommand() << '\n';
1501 os << "\\secnumdepth " << secnumdepth
1502 << "\n\\tocdepth " << tocdepth
1503 << "\n\\paragraph_separation "
1504 << string_paragraph_separation[paragraph_separation];
1505 if (!paragraph_separation)
1506 os << "\n\\paragraph_indentation "
1507 << (getParIndent().empty() ? "default" : getParIndent().asString());
1509 os << "\n\\defskip " << getDefSkip().asLyXCommand();
1510 os << "\n\\is_math_indent " << is_math_indent;
1512 os << "\n\\math_indentation "
1513 << (getMathIndent().empty() ? "default" : getMathIndent().asString());
1514 os << "\n\\math_numbering_side ";
1515 switch(math_numbering_side) {
1525 os << "\n\\quotes_style "
1526 << string_quotes_style[static_cast<int>(quotes_style)]
1527 << "\n\\dynamic_quotes " << dynamic_quotes
1528 << "\n\\papercolumns " << columns
1529 << "\n\\papersides " << sides
1530 << "\n\\paperpagestyle " << pagestyle
1531 << "\n\\tablestyle " << tablestyle << '\n';
1532 if (!listings_params.empty())
1533 os << "\\listings_params \"" <<
1534 InsetListingsParams(listings_params).encodedString() << "\"\n";
1535 for (int i = 0; i < 4; ++i) {
1536 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
1537 if (user_defined_bullet(i).getFont() != -1) {
1538 os << "\\bullet " << i << " "
1539 << user_defined_bullet(i).getFont() << " "
1540 << user_defined_bullet(i).getCharacter() << " "
1541 << user_defined_bullet(i).getSize() << "\n";
1545 os << "\\bulletLaTeX " << i << " \""
1546 << lyx::to_ascii(user_defined_bullet(i).getText())
1552 os << "\\tracking_changes "
1553 << (save_transient_properties ? convert<string>(track_changes) : "false")
1556 os << "\\output_changes "
1557 << (save_transient_properties ? convert<string>(output_changes) : "false")
1560 os << "\\change_bars "
1561 << (save_transient_properties ? convert<string>(change_bars) : "false")
1564 os << "\\postpone_fragile_content " << convert<string>(postpone_fragile_content) << '\n';
1566 os << "\\html_math_output " << html_math_output << '\n'
1567 << "\\html_css_as_file " << html_css_as_file << '\n'
1568 << "\\html_be_strict " << convert<string>(html_be_strict) << '\n';
1570 os << "\\docbook_table_output " << docbook_table_output << '\n';
1571 os << "\\docbook_mathml_prefix " << docbook_mathml_prefix << '\n';
1573 if (html_math_img_scale != 1.0)
1574 os << "\\html_math_img_scale " << convert<string>(html_math_img_scale) << '\n';
1575 if (!html_latex_start.empty())
1576 os << "\\html_latex_start " << html_latex_start << '\n';
1577 if (!html_latex_end.empty())
1578 os << "\\html_latex_end " << html_latex_end << '\n';
1580 os << pimpl_->authorlist;
1584 void BufferParams::validate(LaTeXFeatures & features) const
1586 features.require(documentClass().required());
1588 if (columns > 1 && language->rightToLeft())
1589 features.require("rtloutputdblcol");
1591 if (output_changes) {
1592 bool xcolorulem = LaTeXFeatures::isAvailable("ulem") &&
1593 LaTeXFeatures::isAvailable("xcolor");
1595 switch (features.runparams().flavor) {
1597 case Flavor::DviLuaTeX:
1599 features.require("ct-xcolor-ulem");
1600 features.require("ulem");
1601 features.require("xcolor");
1603 features.require("ct-none");
1606 case Flavor::LuaTeX:
1607 case Flavor::PdfLaTeX:
1610 features.require("ct-xcolor-ulem");
1611 features.require("ulem");
1612 features.require("xcolor");
1613 // improves color handling in PDF output
1614 features.require("pdfcolmk");
1616 features.require("ct-none");
1623 features.require("changebar");
1626 // Floats with 'Here definitely' as default setting.
1627 if (float_placement.find('H') != string::npos)
1628 features.require("float");
1630 for (auto const & pm : use_packages) {
1631 if (pm.first == "amsmath") {
1632 // AMS Style is at document level
1633 if (pm.second == package_on ||
1634 features.isProvided("amsmath"))
1635 features.require(pm.first);
1636 } else if (pm.second == package_on)
1637 features.require(pm.first);
1640 // Document-level line spacing
1641 if (spacing().getSpace() != Spacing::Single && !spacing().isDefault())
1642 features.require("setspace");
1644 // the bullet shapes are buffer level not paragraph level
1645 // so they are tested here
1646 for (int i = 0; i < 4; ++i) {
1647 if (user_defined_bullet(i) == ITEMIZE_DEFAULTS[i])
1649 int const font = user_defined_bullet(i).getFont();
1651 int const c = user_defined_bullet(i).getCharacter();
1657 features.require("latexsym");
1659 } else if (font == 1) {
1660 features.require("amssymb");
1661 } else if (font >= 2 && font <= 5) {
1662 features.require("pifont");
1666 if (pdfoptions().use_hyperref) {
1667 features.require("hyperref");
1668 // due to interferences with babel and hyperref, the color package has to
1669 // be loaded after hyperref when hyperref is used with the colorlinks
1670 // option, see http://www.lyx.org/trac/ticket/5291
1671 if (pdfoptions().colorlinks)
1672 features.require("color");
1674 if (!listings_params.empty()) {
1675 // do not test validity because listings_params is
1676 // supposed to be valid
1678 InsetListingsParams(listings_params).separatedParams(true);
1679 // we can't support all packages, but we should load the color package
1680 if (par.find("\\color", 0) != string::npos)
1681 features.require("color");
1684 // some languages are only available via polyglossia
1685 if (features.hasPolyglossiaExclusiveLanguages())
1686 features.require("polyglossia");
1688 if (useNonTeXFonts && fontsMath() != "auto")
1689 features.require("unicode-math");
1692 features.require("microtype");
1694 if (!language->required().empty())
1695 features.require(language->required());
1699 bool BufferParams::writeLaTeX(otexstream & os, LaTeXFeatures & features,
1700 FileName const & filepath) const
1702 // DocumentMetadata must come before anything else
1703 if (features.isAvailable("LaTeX-2022/06/01")
1704 && !containsOnly(document_metadata, " \n\t")) {
1705 // Check if the user preamble contains uncodable glyphs
1706 odocstringstream doc_metadata;
1707 docstring uncodable_glyphs;
1708 Encoding const * const enc = features.runparams().encoding;
1710 for (char_type c : document_metadata) {
1711 if (!enc->encodable(c)) {
1712 docstring const glyph(1, c);
1713 LYXERR0("Uncodable character '"
1715 << "' in document metadata!");
1716 uncodable_glyphs += glyph;
1717 if (features.runparams().dryrun) {
1718 doc_metadata << "<" << _("LyX Warning: ")
1719 << _("uncodable character") << " '";
1720 doc_metadata.put(c);
1721 doc_metadata << "'>";
1724 doc_metadata.put(c);
1727 doc_metadata << document_metadata;
1729 // On BUFFER_VIEW|UPDATE, warn user if we found uncodable glyphs
1730 if (!features.runparams().dryrun && !uncodable_glyphs.empty()) {
1731 frontend::Alert::warning(
1732 _("Uncodable character in document metadata"),
1734 _("The metadata of your document contains glyphs "
1735 "that are unknown in the current document encoding "
1736 "(namely %1$s).\nThese glyphs are omitted "
1737 " from the output, which may result in "
1738 "incomplete output."
1739 "\n\nPlease select an appropriate "
1740 "document encoding\n"
1741 "(such as utf8) or change the "
1742 "preamble code accordingly."),
1745 if (!doc_metadata.str().empty()) {
1746 os << "\\DocumentMetadata{\n"
1747 << doc_metadata.str()
1752 // http://www.tug.org/texmf-dist/doc/latex/base/fixltx2e.pdf
1753 // !! To use the Fix-cm package, load it before \documentclass, and use the command
1754 // \RequirePackage to do so, rather than the normal \usepackage
1755 // Do not try to load any other package before the document class, unless you
1756 // have a thorough understanding of the LATEX internals and know exactly what you
1758 if (features.mustProvide("fix-cm"))
1759 os << "\\RequirePackage{fix-cm}\n";
1760 // Likewise for fixltx2e. If other packages conflict with this policy,
1761 // treat it as a package bug (and report it!)
1762 // See http://www.latex-project.org/cgi-bin/ltxbugs2html?pr=latex/4407
1763 if (features.mustProvide("fixltx2e"))
1764 os << "\\RequirePackage{fixltx2e}\n";
1766 os << "\\documentclass";
1768 DocumentClass const & tclass = documentClass();
1770 ostringstream clsoptions; // the document class options.
1772 if (tokenPos(tclass.opt_fontsize(),
1773 '|', fontsize) >= 0) {
1774 // only write if existing in list (and not default)
1775 clsoptions << subst(tclass.fontsizeformat(), "$$s", fontsize) << ",";
1778 // paper sizes not supported by the class itself need the
1780 vector<string> classpsizes = getVectorFromString(tclass.opt_pagesize(), "|");
1781 bool class_supported_papersize = papersize == PAPER_DEFAULT
1782 || find(classpsizes.begin(), classpsizes.end(), string_papersize[papersize]) != classpsizes.end();
1784 if ((!use_geometry || features.isProvided("geometry-light"))
1785 && class_supported_papersize && papersize != PAPER_DEFAULT)
1786 clsoptions << subst(tclass.pagesizeformat(), "$$s", string_papersize[papersize]) << ",";
1789 if (sides != tclass.sides()) {
1792 clsoptions << "oneside,";
1795 clsoptions << "twoside,";
1801 if (columns != tclass.columns()) {
1803 clsoptions << "twocolumn,";
1805 clsoptions << "onecolumn,";
1809 && orientation == ORIENTATION_LANDSCAPE)
1810 clsoptions << "landscape,";
1813 clsoptions << "fleqn,";
1815 switch(math_numbering_side) {
1817 clsoptions << "leqno,";
1820 clsoptions << "reqno,";
1821 features.require("amsmath");
1827 // language should be a parameter to \documentclass
1828 if (language->babel() == "hebrew"
1829 && default_language->babel() != "hebrew")
1830 // This seems necessary
1831 features.useLanguage(default_language);
1833 ostringstream language_options;
1834 bool const use_babel = features.useBabel() && !features.isProvided("babel");
1835 bool const use_polyglossia = features.usePolyglossia();
1836 bool const global = lyxrc.language_global_options;
1837 if (features.useBabel() || (use_polyglossia && global)) {
1838 language_options << features.getBabelLanguages();
1839 if (!language->babel().empty()) {
1840 if (!language_options.str().empty())
1841 language_options << ',';
1842 language_options << language->babel();
1844 if (global && !language_options.str().empty())
1845 clsoptions << language_options.str() << ',';
1848 // the predefined options from the layout
1849 if (use_default_options && !tclass.options().empty())
1850 clsoptions << tclass.options() << ',';
1852 // the user-defined options
1853 if (!options.empty()) {
1854 clsoptions << options << ',';
1857 docstring const strOptions = from_utf8(clsoptions.str());
1858 if (!strOptions.empty()) {
1859 // Check if class options contain uncodable glyphs
1860 docstring uncodable_glyphs;
1861 docstring options_encodable;
1862 Encoding const * const enc = features.runparams().encoding;
1864 for (char_type c : strOptions) {
1865 if (!enc->encodable(c)) {
1866 docstring const glyph(1, c);
1867 LYXERR0("Uncodable character '"
1869 << "' in class options!");
1870 uncodable_glyphs += glyph;
1871 if (features.runparams().dryrun) {
1872 options_encodable += "<" + _("LyX Warning: ")
1873 + _("uncodable character") + " '";
1874 options_encodable += c;
1875 options_encodable += "'>";
1878 options_encodable += c;
1881 options_encodable = strOptions;
1883 // On BUFFER_VIEW|UPDATE, warn user if we found uncodable glyphs
1884 if (!features.runparams().dryrun && !uncodable_glyphs.empty()) {
1885 frontend::Alert::warning(
1886 _("Uncodable character in class options"),
1888 _("The class options of your document contain glyphs "
1889 "that are unknown in the current document encoding "
1890 "(namely %1$s).\nThese glyphs are omitted "
1891 " from the output, which may result in "
1892 "incomplete output."
1893 "\n\nPlease select an appropriate "
1894 "document encoding\n"
1895 "(such as utf8) or change the "
1896 "class options accordingly."),
1899 options_encodable = rtrim(options_encodable, ",");
1900 os << '[' << options_encodable << ']';
1903 os << '{' << from_ascii(tclass.latexname()) << "}\n";
1904 // end of \documentclass defs
1906 // The package options (via \PassOptionsToPackage)
1907 os << from_ascii(features.getPackageOptions());
1909 // if we use fontspec or newtxmath, we have to load the AMS packages here
1910 string const ams = features.loadAMSPackages();
1911 string const main_font_enc = features.runparams().main_fontenc;
1912 bool const ot1 = (main_font_enc == "default" || main_font_enc == "OT1");
1913 bool const use_newtxmath =
1914 theLaTeXFonts().getLaTeXFont(from_ascii(fontsMath())).getUsedPackage(
1915 ot1, false, false) == "newtxmath";
1916 if ((useNonTeXFonts || use_newtxmath) && !ams.empty())
1917 os << from_ascii(ams);
1919 if (useNonTeXFonts) {
1920 // Babel (as of 2017/11/03) loads fontspec itself
1921 if (!features.isProvided("fontspec")
1922 && !(features.useBabel() && features.isAvailable("babel-2017/11/03")))
1923 os << "\\usepackage{fontspec}\n";
1924 if (features.mustProvide("unicode-math")
1925 && features.isAvailable("unicode-math"))
1926 os << "\\usepackage{unicode-math}\n";
1929 // load CJK support package before font selection
1930 // (see autotests/export/latex/CJK/micro-sign_utf8-cjk-libertine.lyx)
1931 if (!useNonTeXFonts && encoding().package() != Encoding::none && inputenc != "utf8x"
1932 && (encoding().package() == Encoding::CJK || features.mustProvide("CJK"))) {
1933 if (inputenc == "utf8-cjk" || inputenc == "utf8")
1934 os << "\\usepackage{CJKutf8}\n";
1936 os << "\\usepackage[encapsulated]{CJK}\n";
1939 // font selection must be done before loading fontenc.sty
1940 // but after babel with non-TeX fonts
1941 string const fonts = loadFonts(features);
1942 if (!fonts.empty() && (!features.useBabel() || !useNonTeXFonts))
1943 os << from_utf8(fonts);
1945 if (fonts_default_family != "default")
1946 os << "\\renewcommand{\\familydefault}{\\"
1947 << from_ascii(fonts_default_family) << "}\n";
1949 // set font encoding
1950 // non-TeX fonts use font encoding TU (set by fontspec)
1951 if (!useNonTeXFonts && !features.isProvided("fontenc")
1952 && main_font_enc != "default") {
1953 // get main font encodings
1954 vector<string> fontencs = font_encodings();
1955 // get font encodings of secondary languages
1956 // FIXME: some languages (hebrew, ...) assume a standard font encoding as last
1957 // option (for text in other languages).
1958 features.getFontEncodings(fontencs);
1959 if (!fontencs.empty()) {
1960 os << "\\usepackage["
1961 << from_ascii(getStringFromVector(fontencs))
1966 // Load textcomp and pmboxdraw before (lua)inputenc (#11454)
1967 if (features.mustProvide("textcomp"))
1968 os << "\\usepackage{textcomp}\n";
1969 if (features.mustProvide("pmboxdraw"))
1970 os << "\\usepackage{pmboxdraw}\n";
1972 // handle inputenc etc.
1973 // (In documents containing text in Thai language,
1974 // we must load inputenc after babel, see lib/languages).
1975 if (!contains(features.getBabelPostsettings(), from_ascii("thai.ldf")))
1976 writeEncodingPreamble(os, features);
1979 if (!features.runparams().includeall && !included_children_.empty()) {
1980 os << "\\includeonly{";
1982 // we do not use "auto const &" here, because incfile is modified later
1983 // coverity[auto_causes_copy]
1984 for (auto incfile : included_children_) {
1985 FileName inc = makeAbsPath(incfile, filepath.absFileName());
1986 string mangled = DocFileName(changeExtension(inc.absFileName(), ".tex")).
1988 if (!features.runparams().nice)
1990 // \includeonly doesn't want an extension
1991 incfile = changeExtension(incfile, string());
1992 incfile = support::latex_path(incfile);
1993 if (!incfile.empty()) {
1996 os << from_utf8(incfile);
2003 if (!features.isProvided("geometry")
2004 && (use_geometry || !class_supported_papersize)) {
2005 odocstringstream ods;
2006 if (!getGraphicsDriver("geometry").empty())
2007 ods << getGraphicsDriver("geometry");
2008 if (orientation == ORIENTATION_LANDSCAPE)
2009 ods << ",landscape";
2010 switch (papersize) {
2012 if (!paperwidth.empty())
2013 ods << ",paperwidth="
2014 << from_ascii(paperwidth);
2015 if (!paperheight.empty())
2016 ods << ",paperheight="
2017 << from_ascii(paperheight);
2019 case PAPER_USLETTER:
2021 case PAPER_USEXECUTIVE:
2050 ods << "," << from_ascii(string_papersize_geometry[papersize]);
2055 docstring g_options = trim(ods.str(), ",");
2056 os << "\\usepackage";
2057 // geometry-light means that the class works with geometry, but overwrites
2058 // the package options and paper sizes (memoir does this).
2059 // In this case, all options need to go to \geometry
2060 // and the standard paper sizes need to go to the class options.
2061 if (!g_options.empty() && !features.isProvided("geometry-light")) {
2062 os << '[' << g_options << ']';
2065 os << "{geometry}\n";
2066 if (use_geometry || features.isProvided("geometry-light")) {
2067 os << "\\geometry{verbose";
2068 if (!g_options.empty())
2069 // Output general options here with "geometry light".
2070 os << "," << g_options;
2071 // output this only if use_geometry is true
2073 if (!topmargin.empty())
2074 os << ",tmargin=" << from_ascii(Length(topmargin).asLatexString());
2075 if (!bottommargin.empty())
2076 os << ",bmargin=" << from_ascii(Length(bottommargin).asLatexString());
2077 if (!leftmargin.empty())
2078 os << ",lmargin=" << from_ascii(Length(leftmargin).asLatexString());
2079 if (!rightmargin.empty())
2080 os << ",rmargin=" << from_ascii(Length(rightmargin).asLatexString());
2081 if (!headheight.empty())
2082 os << ",headheight=" << from_ascii(Length(headheight).asLatexString());
2083 if (!headsep.empty())
2084 os << ",headsep=" << from_ascii(Length(headsep).asLatexString());
2085 if (!footskip.empty())
2086 os << ",footskip=" << from_ascii(Length(footskip).asLatexString());
2087 if (!columnsep.empty())
2088 os << ",columnsep=" << from_ascii(Length(columnsep).asLatexString());
2092 } else if (orientation == ORIENTATION_LANDSCAPE
2093 || papersize != PAPER_DEFAULT) {
2094 features.require("papersize");
2097 if (tokenPos(tclass.opt_pagestyle(), '|', pagestyle) >= 0) {
2098 if (pagestyle == "fancy")
2099 os << "\\usepackage{fancyhdr}\n";
2100 os << "\\pagestyle{" << from_ascii(pagestyle) << "}\n";
2103 // only output when the background color is not default
2104 if (isbackgroundcolor) {
2105 // only require color here, the background color will be defined
2106 // in LaTeXFeatures.cpp to avoid interferences with the LaTeX
2108 features.require("color");
2109 features.require("pagecolor");
2112 // only output when the font color is not default
2114 // only require color here, the font color will be defined
2115 // in LaTeXFeatures.cpp to avoid interferences with the LaTeX
2117 features.require("color");
2118 features.require("fontcolor");
2121 // Only if class has a ToC hierarchy
2122 if (tclass.hasTocLevels()) {
2123 if (secnumdepth != tclass.secnumdepth()) {
2124 os << "\\setcounter{secnumdepth}{"
2128 if (tocdepth != tclass.tocdepth()) {
2129 os << "\\setcounter{tocdepth}{"
2135 if (paragraph_separation) {
2136 // when skip separation
2138 switch (getDefSkip().kind()) {
2139 case VSpace::SMALLSKIP:
2140 psopt = "\\smallskipamount";
2142 case VSpace::MEDSKIP:
2143 psopt = "\\medskipamount";
2145 case VSpace::BIGSKIP:
2146 psopt = "\\bigskipamount";
2148 case VSpace::HALFLINE:
2149 // default (no option)
2151 case VSpace::FULLLINE:
2152 psopt = "\\baselineskip";
2154 case VSpace::LENGTH:
2155 psopt = getDefSkip().length().asLatexString();
2160 if (!features.isProvided("parskip")) {
2162 psopt = "[skip=" + psopt + "]";
2163 os << "\\usepackage" + psopt + "{parskip}\n";
2165 os << "\\setlength{\\parskip}{" + psopt + "}\n";
2168 // when separation by indentation
2169 // only output something when a width is given
2170 if (!getParIndent().empty()) {
2171 os << "\\setlength{\\parindent}{"
2172 << from_utf8(getParIndent().asLatexString())
2177 if (is_math_indent) {
2178 // when formula indentation
2179 // only output something when it is not the default
2180 if (!getMathIndent().empty()) {
2181 os << "\\setlength{\\mathindent}{"
2182 << from_utf8(getMathIndent().asString())
2187 // Now insert the LyX specific LaTeX commands...
2188 features.resolveAlternatives();
2189 features.expandMultiples();
2192 if (!output_sync_macro.empty())
2193 os << from_utf8(output_sync_macro) +"\n";
2194 else if (features.runparams().flavor == Flavor::LaTeX)
2195 os << "\\usepackage[active]{srcltx}\n";
2197 os << "\\synctex=-1\n";
2200 // due to interferences with babel and hyperref, the color package has to
2201 // be loaded (when it is not already loaded) before babel when hyperref
2202 // is used with the colorlinks option, see
2203 // http://www.lyx.org/trac/ticket/5291
2204 // we decided therefore to load color always before babel, see
2205 // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg144349.html
2206 os << from_ascii(features.getColorOptions());
2208 // If we use hyperref, jurabib, japanese or varioref,
2209 // we have to call babel before
2211 && (features.isRequired("jurabib")
2212 || features.isRequired("hyperref")
2213 || features.isRequired("varioref")
2214 || features.isRequired("japanese"))) {
2215 os << features.getBabelPresettings();
2217 os << from_utf8(babelCall(language_options.str(),
2218 !lyxrc.language_global_options)) + '\n';
2219 os << features.getBabelPostsettings();
2222 // The optional packages;
2223 os << from_ascii(features.getPackages());
2225 // Additional Indices
2226 if (features.isRequired("splitidx")) {
2227 for (auto const & idx : indiceslist()) {
2228 os << "\\newindex{";
2229 os << escape(idx.shortcut());
2235 os << from_utf8(spacing().writePreamble(features.isProvided("SetSpace")));
2238 // * Hyperref manual: "Make sure it comes last of your loaded
2239 // packages, to give it a fighting chance of not being over-written,
2240 // since its job is to redefine many LaTeX commands."
2241 // * Email from Heiko Oberdiek: "It is usually better to load babel
2242 // before hyperref. Then hyperref has a chance to detect babel.
2243 // * Has to be loaded before the "LyX specific LaTeX commands" to
2244 // avoid errors with algorithm floats.
2245 // use hyperref explicitly if it is required
2246 if (features.isRequired("hyperref")) {
2247 OutputParams tmp_params = features.runparams();
2248 pdfoptions().writeLaTeX(tmp_params, os,
2249 features.isProvided("hyperref"));
2250 // correctly break URLs with hyperref and dvi/ps output
2251 if (features.runparams().hyperref_driver == "dvips"
2252 && features.isAvailable("breakurl"))
2253 os << "\\usepackage{breakurl}\n";
2254 } else if (features.isRequired("nameref"))
2255 // hyperref loads this automatically
2256 os << "\\usepackage{nameref}\n";
2259 os << "\\usepackage";
2260 if (!lineno_opts.empty())
2261 os << "[" << lineno_opts << "]";
2263 os << "\\linenumbers\n";
2266 // bibtopic needs to be loaded after hyperref.
2267 // the dot provides the aux file naming which LyX can detect.
2268 if (features.mustProvide("bibtopic"))
2269 os << "\\usepackage[dot]{bibtopic}\n";
2271 // Will be surrounded by \makeatletter and \makeatother when not empty
2272 otexstringstream atlyxpreamble;
2274 // Some macros LyX will need
2276 TexString tmppreamble = features.getMacros();
2277 if (!tmppreamble.str.empty())
2278 atlyxpreamble << "\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
2279 "LyX specific LaTeX commands.\n"
2280 << std::move(tmppreamble)
2283 // the text class specific preamble
2285 docstring tmppreamble = features.getTClassPreamble();
2286 if (!tmppreamble.empty())
2287 atlyxpreamble << "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
2288 "Textclass specific LaTeX commands.\n"
2292 // suppress date if selected
2293 // use \@ifundefined because we cannot be sure that every document class
2294 // has a \date command
2296 atlyxpreamble << "\\@ifundefined{date}{}{\\date{}}\n";
2298 /* the user-defined preamble */
2299 if (!containsOnly(preamble, " \n\t")) {
2301 atlyxpreamble << "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
2302 "User specified LaTeX commands.\n";
2304 // Check if the user preamble contains uncodable glyphs
2305 odocstringstream user_preamble;
2306 docstring uncodable_glyphs;
2307 Encoding const * const enc = features.runparams().encoding;
2309 for (char_type c : preamble) {
2310 if (!enc->encodable(c)) {
2311 docstring const glyph(1, c);
2312 LYXERR0("Uncodable character '"
2314 << "' in user preamble!");
2315 uncodable_glyphs += glyph;
2316 if (features.runparams().dryrun) {
2317 user_preamble << "<" << _("LyX Warning: ")
2318 << _("uncodable character") << " '";
2319 user_preamble.put(c);
2320 user_preamble << "'>";
2323 user_preamble.put(c);
2326 user_preamble << preamble;
2328 // On BUFFER_VIEW|UPDATE, warn user if we found uncodable glyphs
2329 if (!features.runparams().dryrun && !uncodable_glyphs.empty()) {
2330 frontend::Alert::warning(
2331 _("Uncodable character in user preamble"),
2333 _("The user preamble of your document contains glyphs "
2334 "that are unknown in the current document encoding "
2335 "(namely %1$s).\nThese glyphs are omitted "
2336 " from the output, which may result in "
2337 "incomplete output."
2338 "\n\nPlease select an appropriate "
2339 "document encoding\n"
2340 "(such as utf8) or change the "
2341 "preamble code accordingly."),
2344 atlyxpreamble << user_preamble.str() << '\n';
2347 // footmisc must be loaded after setspace
2348 // Load it here to avoid clashes with footmisc loaded in the user
2349 // preamble. For that reason we also pass the options via
2350 // \PassOptionsToPackage in getPreamble() and not here.
2351 if (features.mustProvide("footmisc"))
2352 atlyxpreamble << "\\usepackage{footmisc}\n";
2354 // subfig loads internally the LaTeX package "caption". As
2355 // caption is a very popular package, users will load it in
2356 // the preamble. Therefore we must load subfig behind the
2357 // user-defined preamble and check if the caption package was
2358 // loaded or not. For the case that caption is loaded before
2359 // subfig, there is the subfig option "caption=false". This
2360 // option also works when a koma-script class is used and
2361 // koma's own caption commands are used instead of caption. We
2362 // use \PassOptionsToPackage here because the user could have
2363 // already loaded subfig in the preamble.
2364 if (features.mustProvide("subfig"))
2365 atlyxpreamble << "\\ifdefined\\showcaptionsetup\n"
2366 " % Caption package is used. Advise subfig not to load it again.\n"
2367 " \\PassOptionsToPackage{caption=false}{subfig}\n"
2369 "\\usepackage{subfig}\n";
2371 // Itemize bullet settings need to be last in case the user
2372 // defines their own bullets that use a package included
2373 // in the user-defined preamble -- ARRae
2374 // Actually it has to be done much later than that
2375 // since some packages like frenchb make modifications
2376 // at \begin{document} time -- JMarc
2377 docstring bullets_def;
2378 for (int i = 0; i < 4; ++i) {
2379 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
2380 if (bullets_def.empty())
2381 bullets_def += "\\AtBeginDocument{\n";
2382 bullets_def += " \\def\\labelitemi";
2384 // `i' is one less than the item to modify
2391 bullets_def += "ii";
2397 bullets_def += '{' +
2398 user_defined_bullet(i).getText()
2403 if (!bullets_def.empty())
2404 atlyxpreamble << bullets_def << "}\n\n";
2406 if (!atlyxpreamble.empty())
2407 os << "\n\\makeatletter\n"
2408 << atlyxpreamble.release()
2409 << "\\makeatother\n\n";
2411 // We try to load babel late, in case it interferes with other packages.
2412 // Jurabib, hyperref, varioref, bicaption, menukeys and listings (bug 8995)
2413 // have to be called after babel, though.
2414 if (use_babel && !features.isRequired("jurabib")
2415 && !features.isRequired("hyperref")
2416 && !features.isRequired("varioref")
2417 && !features.isRequired("japanese")) {
2418 os << features.getBabelPresettings();
2420 os << from_utf8(babelCall(language_options.str(),
2421 !lyxrc.language_global_options)) + '\n';
2422 os << features.getBabelPostsettings();
2424 // In documents containing text in Thai language,
2425 // we must load inputenc after babel (see lib/languages).
2426 if (contains(features.getBabelPostsettings(), from_ascii("thai.ldf")))
2427 writeEncodingPreamble(os, features);
2429 // font selection must be done after babel with non-TeX fonts
2430 if (!fonts.empty() && features.useBabel() && useNonTeXFonts)
2431 os << from_utf8(fonts);
2433 if (features.isRequired("bicaption"))
2434 os << "\\usepackage{bicaption}\n";
2435 if (!listings_params.empty()
2436 || features.mustProvide("listings")
2437 || features.mustProvide("minted")) {
2439 os << "\\usepackage{minted}\n";
2441 os << "\\usepackage{listings}\n";
2443 string lst_params = listings_params;
2444 // If minted, do not output the language option (bug 11203)
2445 if (use_minted && contains(lst_params, "language=")) {
2446 vector<string> opts =
2447 getVectorFromString(lst_params, ",", false);
2448 for (size_t i = 0; i < opts.size(); ++i) {
2449 if (prefixIs(opts[i], "language="))
2450 opts.erase(opts.begin() + i--);
2452 lst_params = getStringFromVector(opts, ",");
2454 if (!lst_params.empty()) {
2456 os << "\\setminted{";
2459 // do not test validity because listings_params is
2460 // supposed to be valid
2462 InsetListingsParams(lst_params).separatedParams(true);
2463 os << from_utf8(par);
2467 // xunicode only needs to be loaded if tipa is used
2468 // (the rest is obsoleted by the new TU encoding).
2469 // It needs to be loaded at least after amsmath, amssymb,
2470 // esint and the other packages that provide special glyphs
2471 if (features.mustProvide("tipa") && useNonTeXFonts
2472 && !features.isProvided("xunicode")) {
2473 // The `xunicode` package officially only supports XeTeX,
2474 // but also works with LuaTeX. We work around its XeTeX test.
2475 if (features.runparams().flavor != Flavor::XeTeX) {
2476 os << "% Pretend to xunicode that we are XeTeX\n"
2477 << "\\def\\XeTeXpicfile{}\n";
2479 os << "\\usepackage{xunicode}\n";
2482 // covington must be loaded after beamerarticle
2483 if (features.isRequired("covington"))
2484 os << "\\usepackage{covington}\n";
2486 // Polyglossia must be loaded last ...
2487 if (use_polyglossia) {
2489 os << "\\usepackage{polyglossia}\n";
2490 // set the main language
2491 os << "\\setdefaultlanguage";
2492 if (!language->polyglossiaOpts().empty())
2493 os << "[" << from_ascii(language->polyglossiaOpts()) << "]";
2494 os << "{" << from_ascii(language->polyglossia()) << "}\n";
2495 // now setup the other languages
2496 set<string> const polylangs =
2497 features.getPolyglossiaLanguages();
2498 for (auto const & pl : polylangs) {
2499 // We do not output the options here; they are output in
2500 // the language switch commands. This is safer if multiple
2501 // varieties are used.
2502 if (pl == language->polyglossia())
2504 os << "\\setotherlanguage";
2505 os << "{" << from_ascii(pl) << "}\n";
2509 // ... but before biblatex (see #7065)
2510 if ((features.mustProvide("biblatex")
2511 || features.isRequired("biblatex-chicago"))
2512 && !features.isProvided("biblatex-chicago")
2513 && !features.isProvided("biblatex-natbib")
2514 && !features.isProvided("natbib-internal")
2515 && !features.isProvided("natbib")
2516 && !features.isProvided("jurabib")) {
2517 // The biblatex-chicago package has a differing interface
2518 // it uses a wrapper package and loads styles via fixed options
2519 bool const chicago = features.isRequired("biblatex-chicago");
2522 os << "\\usepackage";
2523 if (!biblatex_bibstyle.empty()
2524 && (biblatex_bibstyle == biblatex_citestyle)
2526 opts = "style=" + biblatex_bibstyle;
2528 } else if (!chicago) {
2529 if (!biblatex_bibstyle.empty()) {
2530 opts = "bibstyle=" + biblatex_bibstyle;
2533 if (!biblatex_citestyle.empty()) {
2534 opts += delim + "citestyle=" + biblatex_citestyle;
2538 if (!multibib.empty() && multibib != "child") {
2539 opts += delim + "refsection=" + multibib;
2542 if (bibtexCommand() == "bibtex8"
2543 || prefixIs(bibtexCommand(), "bibtex8 ")) {
2544 opts += delim + "backend=bibtex8";
2546 } else if (bibtexCommand() == "bibtex"
2547 || prefixIs(bibtexCommand(), "bibtex ")) {
2548 opts += delim + "backend=bibtex";
2551 if (!bib_encoding.empty() && encodings.fromLyXName(bib_encoding)) {
2552 opts += delim + "bibencoding="
2553 + encodings.fromLyXName(bib_encoding)->latexName();
2556 if (!biblio_opts.empty())
2557 opts += delim + biblio_opts;
2559 os << "[" << opts << "]";
2561 os << "{biblatex-chicago}\n";
2563 os << "{biblatex}\n";
2567 // Load custom language package here
2568 if (features.langPackage() == LaTeXFeatures::LANG_PACK_CUSTOM) {
2569 if (lang_package == "default")
2570 os << from_utf8(lyxrc.language_custom_package);
2572 os << from_utf8(lang_package);
2576 // Since menukeys uses catoptions, which does some heavy changes on key-value options,
2577 // it is recommended to load menukeys as the last package (even after hyperref)
2578 if (features.isRequired("menukeys"))
2579 os << "\\usepackage{menukeys}\n";
2581 docstring const i18npreamble =
2582 features.getTClassI18nPreamble(use_babel, use_polyglossia,
2584 if (!i18npreamble.empty())
2585 os << i18npreamble + '\n';
2591 void BufferParams::useClassDefaults()
2593 DocumentClass const & tclass = documentClass();
2595 sides = tclass.sides();
2596 columns = tclass.columns();
2597 pagestyle = tclass.pagestyle();
2598 tablestyle = tclass.tablestyle();
2599 use_default_options = true;
2600 // Only if class has a ToC hierarchy
2601 if (tclass.hasTocLevels()) {
2602 secnumdepth = tclass.secnumdepth();
2603 tocdepth = tclass.tocdepth();
2608 bool BufferParams::hasClassDefaults() const
2610 DocumentClass const & tclass = documentClass();
2612 return sides == tclass.sides()
2613 && columns == tclass.columns()
2614 && pagestyle == tclass.pagestyle()
2615 && tablestyle == tclass.tablestyle()
2616 && use_default_options
2617 && secnumdepth == tclass.secnumdepth()
2618 && tocdepth == tclass.tocdepth();
2622 DocumentClass const & BufferParams::documentClass() const
2628 DocumentClassConstPtr BufferParams::documentClassPtr() const
2634 void BufferParams::setDocumentClass(DocumentClassConstPtr tc)
2636 // evil, but this function is evil
2637 doc_class_ = const_pointer_cast<DocumentClass>(tc);
2638 invalidateConverterCache();
2642 bool BufferParams::setBaseClass(string const & classname, string const & path)
2644 LYXERR(Debug::TCLASS, "setBaseClass: " << classname);
2645 LayoutFileList & bcl = LayoutFileList::get();
2646 if (!bcl.haveClass(classname)) {
2648 bformat(_("The layout file:\n"
2650 "could not be found. A default textclass with default\n"
2651 "layouts will be used. LyX will not be able to produce\n"
2653 from_utf8(classname));
2654 frontend::Alert::error(_("Document class not found"), s);
2655 bcl.addEmptyClass(classname);
2658 bool const success = bcl[classname].load(path);
2661 bformat(_("Due to some error in it, the layout file:\n"
2663 "could not be loaded. A default textclass with default\n"
2664 "layouts will be used. LyX will not be able to produce\n"
2666 from_utf8(classname));
2667 frontend::Alert::error(_("Could not load class"), s);
2668 bcl.addEmptyClass(classname);
2671 pimpl_->baseClass_ = classname;
2672 layout_modules_.adaptToBaseClass(baseClass(), removed_modules_);
2677 LayoutFile const * BufferParams::baseClass() const
2679 if (LayoutFileList::get().haveClass(pimpl_->baseClass_))
2680 return &(LayoutFileList::get()[pimpl_->baseClass_]);
2686 LayoutFileIndex const & BufferParams::baseClassID() const
2688 return pimpl_->baseClass_;
2692 void BufferParams::makeDocumentClass(bool clone, bool internal)
2697 invalidateConverterCache();
2698 LayoutModuleList mods;
2699 for (auto const & mod : layout_modules_)
2700 mods.push_back(mod);
2702 doc_class_ = getDocumentClass(*baseClass(), mods, cite_engine_, clone, internal);
2704 TextClass::ReturnValues success = TextClass::OK;
2705 if (!forced_local_layout_.empty())
2706 success = doc_class_->read(to_utf8(forced_local_layout_),
2708 if (!local_layout_.empty() &&
2709 (success == TextClass::OK || success == TextClass::OK_OLDFORMAT))
2710 success = doc_class_->read(to_utf8(local_layout_), TextClass::MODULE);
2711 if (success != TextClass::OK && success != TextClass::OK_OLDFORMAT) {
2712 docstring const msg = _("Error reading internal layout information");
2713 frontend::Alert::warning(_("Read Error"), msg);
2718 bool BufferParams::layoutModuleCanBeAdded(string const & modName) const
2720 return layout_modules_.moduleCanBeAdded(modName, baseClass());
2724 docstring BufferParams::getLocalLayout(bool forced) const
2727 return from_utf8(doc_class_->forcedLayouts());
2729 return local_layout_;
2733 void BufferParams::setLocalLayout(docstring const & layout, bool forced)
2736 forced_local_layout_ = layout;
2738 local_layout_ = layout;
2742 bool BufferParams::addLayoutModule(string const & modName)
2744 for (auto const & mod : layout_modules_)
2747 layout_modules_.push_back(modName);
2752 string BufferParams::bufferFormat() const
2754 return documentClass().outputFormat();
2758 bool BufferParams::isExportable(string const & format, bool need_viewable) const
2760 FormatList const & formats = exportableFormats(need_viewable);
2761 for (auto const & fmt : formats) {
2762 if (fmt->name() == format)
2769 FormatList const & BufferParams::exportableFormats(bool only_viewable) const
2771 FormatList & cached = only_viewable ?
2772 pimpl_->viewableFormatList : pimpl_->exportableFormatList;
2773 bool & valid = only_viewable ?
2774 pimpl_->isViewCacheValid : pimpl_->isExportCacheValid;
2778 vector<string> const backs = backends();
2779 set<string> excludes;
2780 if (useNonTeXFonts) {
2781 excludes.insert("latex");
2782 excludes.insert("pdflatex");
2783 } else if (inputenc != "ascii" && inputenc != "utf8-plain") {
2784 // XeTeX with TeX fonts requires input encoding ascii (#10600).
2785 excludes.insert("xetex");
2789 theConverters().getReachable(backs[0], only_viewable, true, excludes);
2790 vector<string>::const_iterator it = backs.begin() + 1;
2791 for (; it != backs.end(); ++it) {
2792 FormatList r = theConverters().getReachable(*it, only_viewable,
2794 result.insert(result.end(), r.begin(), r.end());
2796 sort(result.begin(), result.end(), Format::formatSorter);
2803 vector<string> BufferParams::backends() const
2806 string const buffmt = bufferFormat();
2808 // FIXME: Don't hardcode format names here, but use a flag
2809 if (buffmt == "latex") {
2810 if (encoding().package() == Encoding::japanese)
2811 v.push_back("platex");
2813 if (!useNonTeXFonts) {
2814 v.push_back("pdflatex");
2815 v.push_back("latex");
2818 || inputenc == "ascii" || inputenc == "utf8-plain")
2819 v.push_back("xetex");
2820 v.push_back("luatex");
2821 v.push_back("dviluatex");
2824 string rbuffmt = buffmt;
2825 // If we use an OutputFormat in Japanese docs,
2826 // we need special format in order to get the path
2827 // via pLaTeX (#8823)
2828 if (documentClass().hasOutputFormat()
2829 && encoding().package() == Encoding::japanese)
2831 v.push_back(rbuffmt);
2834 v.push_back("xhtml");
2835 v.push_back("docbook5");
2836 v.push_back("text");
2842 Flavor BufferParams::getOutputFlavor(string const & format) const
2844 string const dformat = (format.empty() || format == "default") ?
2845 getDefaultOutputFormat() : format;
2846 DefaultFlavorCache::const_iterator it =
2847 default_flavors_.find(dformat);
2849 if (it != default_flavors_.end())
2852 Flavor result = Flavor::LaTeX;
2854 // FIXME It'd be better not to hardcode this, but to do
2855 // something with formats.
2856 if (dformat == "xhtml")
2857 result = Flavor::Html;
2858 else if (dformat == "docbook5")
2859 result = Flavor::DocBook5;
2860 else if (dformat == "text")
2861 result = Flavor::Text;
2862 else if (dformat == "lyx")
2863 result = Flavor::LyX;
2864 else if (dformat == "pdflatex")
2865 result = Flavor::PdfLaTeX;
2866 else if (dformat == "xetex")
2867 result = Flavor::XeTeX;
2868 else if (dformat == "luatex")
2869 result = Flavor::LuaTeX;
2870 else if (dformat == "dviluatex")
2871 result = Flavor::DviLuaTeX;
2873 // Try to determine flavor of default output format
2874 vector<string> backs = backends();
2875 if (find(backs.begin(), backs.end(), dformat) == backs.end()) {
2876 // Get shortest path to format
2877 Graph::EdgePath path;
2878 for (auto const & bvar : backs) {
2879 Graph::EdgePath p = theConverters().getPath(bvar, dformat);
2880 if (!p.empty() && (path.empty() || p.size() < path.size())) {
2885 result = theConverters().getFlavor(path);
2888 // cache this flavor
2889 default_flavors_[dformat] = result;
2894 string BufferParams::getDefaultOutputFormat() const
2896 if (!default_output_format.empty()
2897 && default_output_format != "default")
2898 return default_output_format;
2899 if (encoding().package() == Encoding::japanese)
2900 return lyxrc.default_platex_view_format;
2902 return lyxrc.default_otf_view_format;
2903 return lyxrc.default_view_format;
2906 Font const BufferParams::getFont() const
2908 FontInfo f = documentClass().defaultfont();
2909 if (fonts_default_family == "rmdefault")
2910 f.setFamily(ROMAN_FAMILY);
2911 else if (fonts_default_family == "sfdefault")
2912 f.setFamily(SANS_FAMILY);
2913 else if (fonts_default_family == "ttdefault")
2914 f.setFamily(TYPEWRITER_FAMILY);
2915 return Font(f, language);
2919 QuoteStyle BufferParams::getQuoteStyle(string const & qs) const
2921 return quotesstyletranslator().find(qs);
2925 bool BufferParams::isLatex() const
2927 return documentClass().outputType() == LATEX;
2931 bool BufferParams::isLiterate() const
2933 return documentClass().outputType() == LITERATE;
2937 void BufferParams::readPreamble(Lexer & lex)
2939 if (lex.getString() != "\\begin_preamble")
2940 lyxerr << "Error (BufferParams::readPreamble):"
2941 "consistency check failed." << endl;
2943 preamble = lex.getLongString(from_ascii("\\end_preamble"));
2947 void BufferParams::readDocumentMetadata(Lexer & lex)
2949 if (lex.getString() != "\\begin_metadata")
2950 lyxerr << "Error (BufferParams::readDocumentMetadata):"
2951 "consistency check failed." << endl;
2953 document_metadata = lex.getLongString(from_ascii("\\end_metadata"));
2957 void BufferParams::readLocalLayout(Lexer & lex, bool forced)
2959 string const expected = forced ? "\\begin_forced_local_layout" :
2960 "\\begin_local_layout";
2961 if (lex.getString() != expected)
2962 lyxerr << "Error (BufferParams::readLocalLayout):"
2963 "consistency check failed." << endl;
2966 forced_local_layout_ =
2967 lex.getLongString(from_ascii("\\end_forced_local_layout"));
2969 local_layout_ = lex.getLongString(from_ascii("\\end_local_layout"));
2973 bool BufferParams::setLanguage(string const & lang)
2975 Language const *new_language = languages.getLanguage(lang);
2976 if (!new_language) {
2977 // Language lang was not found
2980 language = new_language;
2985 void BufferParams::readLanguage(Lexer & lex)
2987 if (!lex.next()) return;
2989 string const tmptok = lex.getString();
2991 // check if tmptok is part of tex_babel in tex-defs.h
2992 if (!setLanguage(tmptok)) {
2993 // Language tmptok was not found
2994 language = default_language;
2995 lyxerr << "Warning: Setting language `"
2996 << tmptok << "' to `" << language->lang()
3002 void BufferParams::readGraphicsDriver(Lexer & lex)
3007 string const tmptok = lex.getString();
3008 // check if tmptok is part of tex_graphics in tex_defs.h
3011 string const test = tex_graphics[n++];
3013 if (test == tmptok) {
3014 graphics_driver = tmptok;
3019 "Warning: graphics driver `$$Token' not recognized!\n"
3020 " Setting graphics driver to `default'.\n");
3021 graphics_driver = "default";
3028 void BufferParams::readBullets(Lexer & lex)
3033 int const index = lex.getInteger();
3035 int temp_int = lex.getInteger();
3036 user_defined_bullet(index).setFont(temp_int);
3037 temp_bullet(index).setFont(temp_int);
3039 user_defined_bullet(index).setCharacter(temp_int);
3040 temp_bullet(index).setCharacter(temp_int);
3042 user_defined_bullet(index).setSize(temp_int);
3043 temp_bullet(index).setSize(temp_int);
3047 void BufferParams::readBulletsLaTeX(Lexer & lex)
3049 // The bullet class should be able to read this.
3052 int const index = lex.getInteger();
3054 docstring const temp_str = lex.getDocString();
3056 user_defined_bullet(index).setText(temp_str);
3057 temp_bullet(index).setText(temp_str);
3061 void BufferParams::readModules(Lexer & lex)
3063 if (!lex.eatLine()) {
3064 lyxerr << "Error (BufferParams::readModules):"
3065 "Unexpected end of input." << endl;
3069 string mod = lex.getString();
3070 if (mod == "\\end_modules")
3072 addLayoutModule(mod);
3078 void BufferParams::readRemovedModules(Lexer & lex)
3080 if (!lex.eatLine()) {
3081 lyxerr << "Error (BufferParams::readRemovedModules):"
3082 "Unexpected end of input." << endl;
3086 string mod = lex.getString();
3087 if (mod == "\\end_removed_modules")
3089 removed_modules_.push_back(mod);
3092 // now we want to remove any removed modules that were previously
3093 // added. normally, that will be because default modules were added in
3094 // setBaseClass(), which gets called when \textclass is read at the
3095 // start of the read.
3096 for (auto const & rm : removed_modules_) {
3097 LayoutModuleList::iterator const mit = layout_modules_.begin();
3098 LayoutModuleList::iterator const men = layout_modules_.end();
3099 LayoutModuleList::iterator found = find(mit, men, rm);
3102 layout_modules_.erase(found);
3107 void BufferParams::readIncludeonly(Lexer & lex)
3109 if (!lex.eatLine()) {
3110 lyxerr << "Error (BufferParams::readIncludeonly):"
3111 "Unexpected end of input." << endl;
3115 string child = lex.getString();
3116 if (child == "\\end_includeonly")
3118 included_children_.push_back(child);
3124 string BufferParams::paperSizeName(PapersizePurpose purpose, string const & psize) const
3126 PAPER_SIZE ppsize = psize.empty() ? papersize : papersizetranslator().find(psize);
3129 if (documentClass().pagesize() == "default")
3130 // could be anything, so don't guess
3132 return paperSizeName(purpose, documentClass().pagesize());
3133 case PAPER_CUSTOM: {
3134 if (purpose == XDVI && !paperwidth.empty() &&
3135 !paperheight.empty()) {
3136 // heightxwidth<unit>
3137 string first = paperwidth;
3138 string second = paperheight;
3139 if (orientation == ORIENTATION_LANDSCAPE)
3142 return first.erase(first.length() - 2)
3148 // dvips and dvipdfm do not know this
3149 if (purpose == DVIPS || purpose == DVIPDFM)
3153 if (purpose == DVIPS || purpose == DVIPDFM)
3157 if (purpose == DVIPS || purpose == DVIPDFM)
3167 if (purpose == DVIPS || purpose == DVIPDFM)
3171 if (purpose == DVIPS || purpose == DVIPDFM)
3175 if (purpose == DVIPS || purpose == DVIPDFM)
3179 if (purpose == DVIPS || purpose == DVIPDFM)
3183 if (purpose == DVIPS || purpose == DVIPDFM)
3187 // dvipdfm does not know this
3188 if (purpose == DVIPDFM)
3192 if (purpose == DVIPDFM)
3196 if (purpose == DVIPS || purpose == DVIPDFM)
3200 if (purpose == DVIPS || purpose == DVIPDFM)
3204 if (purpose == DVIPS || purpose == DVIPDFM)
3208 if (purpose == DVIPS || purpose == DVIPDFM)
3212 if (purpose == DVIPS || purpose == DVIPDFM)
3216 if (purpose == DVIPS || purpose == DVIPDFM)
3220 if (purpose == DVIPS || purpose == DVIPDFM)
3224 if (purpose == DVIPS || purpose == DVIPDFM)
3228 if (purpose == DVIPS || purpose == DVIPDFM)
3232 if (purpose == DVIPS || purpose == DVIPDFM)
3236 if (purpose == DVIPS || purpose == DVIPDFM)
3240 if (purpose == DVIPS || purpose == DVIPDFM)
3244 if (purpose == DVIPS || purpose == DVIPDFM)
3248 if (purpose == DVIPS || purpose == DVIPDFM)
3252 if (purpose == DVIPS || purpose == DVIPDFM)
3255 case PAPER_USEXECUTIVE:
3256 // dvipdfm does not know this
3257 if (purpose == DVIPDFM)
3262 case PAPER_USLETTER:
3264 if (purpose == XDVI)
3271 string const BufferParams::dvips_options() const
3275 // If the class loads the geometry package, we do not know which
3276 // paper size is used, since we do not set it (bug 7013).
3277 // Therefore we must not specify any argument here.
3278 // dvips gets the correct paper size via DVI specials in this case
3279 // (if the class uses the geometry package correctly).
3280 if (documentClass().provides("geometry"))
3284 && papersize == PAPER_CUSTOM
3285 && !lyxrc.print_paper_dimension_flag.empty()
3286 && !paperwidth.empty()
3287 && !paperheight.empty()) {
3288 // using a custom papersize
3289 result = lyxrc.print_paper_dimension_flag;
3290 result += ' ' + paperwidth;
3291 result += ',' + paperheight;
3293 string const paper_option = paperSizeName(DVIPS);
3294 if (!paper_option.empty() && (paper_option != "letter" ||
3295 orientation != ORIENTATION_LANDSCAPE)) {
3296 // dvips won't accept -t letter -t landscape.
3297 // In all other cases, include the paper size
3299 result = lyxrc.print_paper_flag;
3300 result += ' ' + paper_option;
3303 if (orientation == ORIENTATION_LANDSCAPE &&
3304 papersize != PAPER_CUSTOM)
3305 result += ' ' + lyxrc.print_landscape_flag;
3310 string const BufferParams::main_font_encoding() const
3312 vector<string> const fencs = font_encodings();
3313 if (fencs.empty()) {
3314 if (ascii_lowercase(language->fontenc(*this)) == "none")
3318 return fencs.back();
3322 vector<string> const BufferParams::font_encodings() const
3324 string doc_fontenc = (fontenc == "auto") ? string() : fontenc;
3326 vector<string> fontencs;
3328 // "default" means "no explicit font encoding"
3329 if (doc_fontenc != "default") {
3330 if (!doc_fontenc.empty())
3331 // If we have a custom setting, we use only that!
3332 return getVectorFromString(doc_fontenc);
3333 string const lfe = language->fontenc(*this);
3335 && ascii_lowercase(language->fontenc(*this)) != "none") {
3336 vector<string> fencs = getVectorFromString(lfe);
3337 for (auto & fe : fencs) {
3338 if (find(fontencs.begin(), fontencs.end(), fe) == fontencs.end())
3339 fontencs.push_back(fe);
3348 string BufferParams::babelCall(string const & lang_opts, bool const langoptions) const
3350 // suppress the babel call if there is no BabelName defined
3351 // for the document language in the lib/languages file and if no
3352 // other languages are used (lang_opts is then empty)
3353 if (lang_opts.empty())
3355 // The prefs may require the languages to
3356 // be submitted to babel itself (not the class).
3358 return "\\usepackage[" + lang_opts + "]{babel}";
3359 return "\\usepackage{babel}";
3363 docstring BufferParams::getGraphicsDriver(string const & package) const
3367 if (package == "geometry") {
3368 if (graphics_driver == "dvips"
3369 || graphics_driver == "dvipdfm"
3370 || graphics_driver == "pdftex"
3371 || graphics_driver == "vtex")
3372 result = from_ascii(graphics_driver);
3373 else if (graphics_driver == "dvipdfmx")
3374 result = from_ascii("dvipdfm");
3381 void BufferParams::writeEncodingPreamble(otexstream & os,
3382 LaTeXFeatures & features) const
3384 // With no-TeX fonts we use utf8-plain without encoding package.
3388 if (inputenc == "auto-legacy") {
3389 string const doc_encoding =
3390 language->encoding()->latexName();
3391 Encoding::Package const package =
3392 language->encoding()->package();
3394 // Create list of inputenc options:
3395 set<string> encoding_set;
3396 // luainputenc fails with more than one encoding
3397 if (features.runparams().flavor != Flavor::LuaTeX
3398 && features.runparams().flavor != Flavor::DviLuaTeX)
3399 // list all input encodings used in the document
3400 encoding_set = features.getEncodingSet(doc_encoding);
3402 // The "japanese" babel-language requires the pLaTeX engine
3403 // which conflicts with "inputenc".
3404 // See http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129680.html
3405 if ((!encoding_set.empty() || package == Encoding::inputenc)
3406 && !features.isRequired("japanese")
3407 && !features.isProvided("inputenc")) {
3408 os << "\\usepackage[";
3409 set<string>::const_iterator it = encoding_set.begin();
3410 set<string>::const_iterator const end = encoding_set.end();
3412 os << from_ascii(*it);
3415 for (; it != end; ++it)
3416 os << ',' << from_ascii(*it);
3417 if (package == Encoding::inputenc) {
3418 if (!encoding_set.empty())
3420 os << from_ascii(doc_encoding);
3422 if (features.runparams().flavor == Flavor::LuaTeX
3423 || features.runparams().flavor == Flavor::DviLuaTeX)
3424 os << "]{luainputenc}\n";
3426 os << "]{inputenc}\n";
3428 } else if (inputenc != "auto-legacy-plain") {
3429 switch (encoding().package()) {
3430 case Encoding::none:
3432 case Encoding::japanese:
3433 if (encoding().iconvName() != "UTF-8"
3434 && !features.runparams().isFullUnicode())
3435 // don't default to [utf8]{inputenc} with TeXLive >= 18
3436 os << "\\ifdefined\\UseRawInputEncoding\n"
3437 << " \\UseRawInputEncoding\\fi\n";
3439 case Encoding::inputenc:
3440 // do not load inputenc if japanese is used
3441 // or if the class provides inputenc
3442 if (features.isRequired("japanese")
3443 || features.isProvided("inputenc"))
3445 string const doc_encoding = encoding().latexName();
3446 // The 2022 release of ucs.sty uses the default utf8
3447 // inputenc encoding with 'utf8x' inputenc if the ucs
3448 // package is not loaded before inputenc.
3449 // This breaks existing documents that use utf8x
3450 // and also makes utf8x redundant.
3451 // Thus we load ucs.sty in order to keep functionality
3452 // that would otherwise be silently dropped.
3453 if (doc_encoding == "utf8x"
3454 && features.isAvailable("ucs-2022/08/07")
3455 && !features.isProvided("ucs"))
3456 os << "\\usepackage{ucs}\n";
3457 os << "\\usepackage[" << from_ascii(doc_encoding);
3458 if (features.runparams().flavor == Flavor::LuaTeX
3459 || features.runparams().flavor == Flavor::DviLuaTeX)
3460 os << "]{luainputenc}\n";
3462 os << "]{inputenc}\n";
3466 if (inputenc == "auto-legacy-plain" || features.isRequired("japanese")) {
3467 // don't default to [utf8]{inputenc} with TeXLive >= 18
3468 os << "\\ifdefined\\UseRawInputEncoding\n";
3469 os << " \\UseRawInputEncoding\\fi\n";
3474 string const BufferParams::parseFontName(string const & name) const
3476 string mangled = name;
3477 size_t const idx = mangled.find('[');
3478 if (idx == string::npos || idx == 0)
3481 return mangled.substr(0, idx - 1);
3485 string const BufferParams::loadFonts(LaTeXFeatures & features) const
3487 if (fontsRoman() == "default" && fontsSans() == "default"
3488 && fontsTypewriter() == "default"
3489 && (fontsMath() == "default" || fontsMath() == "auto"))
3495 /* Fontspec (XeTeX, LuaTeX): we provide GUI support for oldstyle
3496 * numbers (Numbers=OldStyle) and sf/tt scaling. The Ligatures=TeX/
3497 * Mapping=tex-text option assures TeX ligatures (such as "--")
3498 * are resolved. Note that tt does not use these ligatures.
3500 * -- add more GUI options?
3501 * -- add more fonts (fonts for other scripts)
3502 * -- if there's a way to find out if a font really supports
3503 * OldStyle, enable/disable the widget accordingly.
3505 if (useNonTeXFonts && features.isAvailable("fontspec")) {
3506 // "Mapping=tex-text" and "Ligatures=TeX" are equivalent.
3507 // However, until v.2 (2010/07/11) fontspec only knew
3508 // Mapping=tex-text (for XeTeX only); then "Ligatures=TeX"
3509 // was introduced for both XeTeX and LuaTeX (LuaTeX
3510 // didn't understand "Mapping=tex-text", while XeTeX
3511 // understood both. With most recent versions, both
3512 // variants are understood by both engines. However,
3513 // we want to provide support for at least TeXLive 2009
3514 // (for XeTeX; LuaTeX is only supported as of v.2)
3515 // As of 2017/11/03, Babel has its own higher-level
3516 // interface on top of fontspec that is to be used.
3517 bool const babelfonts = features.useBabel()
3518 && features.isAvailable("babel-2017/11/03");
3519 string const texmapping =
3520 (features.runparams().flavor == Flavor::XeTeX) ?
3521 "Mapping=tex-text" : "Ligatures=TeX";
3522 if (fontsRoman() != "default") {
3524 os << "\\babelfont{rm}[";
3526 os << "\\setmainfont[";
3527 if (!font_roman_opts.empty())
3528 os << font_roman_opts << ',';
3530 if (fonts_roman_osf)
3531 os << ",Numbers=OldStyle";
3532 os << "]{" << parseFontName(fontsRoman()) << "}\n";
3534 if (fontsSans() != "default") {
3535 string const sans = parseFontName(fontsSans());
3536 if (fontsSansScale() != 100) {
3538 os << "\\babelfont{sf}";
3540 os << "\\setsansfont";
3542 << float(fontsSansScale()) / 100 << ',';
3544 os << "Numbers=OldStyle,";
3545 if (!font_sans_opts.empty())
3546 os << font_sans_opts << ',';
3547 os << texmapping << "]{"
3551 os << "\\babelfont{sf}[";
3553 os << "\\setsansfont[";
3555 os << "Numbers=OldStyle,";
3556 if (!font_sans_opts.empty())
3557 os << font_sans_opts << ',';
3558 os << texmapping << "]{"
3562 if (fontsTypewriter() != "default") {
3563 string const mono = parseFontName(fontsTypewriter());
3564 if (fontsTypewriterScale() != 100) {
3566 os << "\\babelfont{tt}";
3568 os << "\\setmonofont";
3570 << float(fontsTypewriterScale()) / 100;
3571 if (fonts_typewriter_osf)
3572 os << ",Numbers=OldStyle";
3573 if (!font_typewriter_opts.empty())
3574 os << ',' << font_typewriter_opts;
3579 os << "\\babelfont{tt}";
3581 os << "\\setmonofont";
3582 if (!font_typewriter_opts.empty() || fonts_typewriter_osf) {
3584 if (fonts_typewriter_osf)
3585 os << "Numbers=OldStyle";
3586 if (!font_typewriter_opts.empty()) {
3587 if (fonts_typewriter_osf)
3589 os << font_typewriter_opts;
3593 os << '{' << mono << "}\n";
3600 bool const ot1 = (features.runparams().main_fontenc == "default"
3601 || features.runparams().main_fontenc == "OT1");
3602 bool const dryrun = features.runparams().dryrun;
3603 bool const complete = (fontsSans() == "default" && fontsTypewriter() == "default");
3604 bool const nomath = (fontsMath() != "auto");
3607 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsRoman())).getLaTeXCode(
3608 dryrun, ot1, complete, fonts_expert_sc, fonts_roman_osf,
3609 nomath, font_roman_opts);
3612 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsSans())).getLaTeXCode(
3613 dryrun, ot1, complete, fonts_expert_sc, fonts_sans_osf,
3614 nomath, font_sans_opts, fontsSansScale());
3616 // MONOSPACED/TYPEWRITER
3617 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsTypewriter())).getLaTeXCode(
3618 dryrun, ot1, complete, fonts_expert_sc, fonts_typewriter_osf,
3619 nomath, font_typewriter_opts, fontsTypewriterScale());
3622 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsMath())).getLaTeXCode(
3623 dryrun, ot1, complete, fonts_expert_sc, fonts_roman_osf,
3630 Encoding const & BufferParams::encoding() const
3632 // Main encoding for LaTeX output.
3634 return *(encodings.fromLyXName("utf8-plain"));
3635 if (inputenc == "auto-legacy" || inputenc == "auto-legacy-plain")
3636 return *language->encoding();
3637 if (inputenc == "utf8" && language->lang() == "japanese")
3638 return *(encodings.fromLyXName("utf8-platex"));
3639 Encoding const * const enc = encodings.fromLyXName(inputenc);
3642 LYXERR0("Unknown inputenc value `" << inputenc
3643 << "'. Using `auto' instead.");
3644 return *language->encoding();
3648 string const & BufferParams::defaultBiblioStyle() const
3650 if (!biblio_style.empty())
3651 return biblio_style;
3653 map<string, string> const & bs = documentClass().defaultBiblioStyle();
3654 auto cit = bs.find(theCiteEnginesList.getTypeAsString(citeEngineType()));
3655 if (cit != bs.end())
3658 return empty_string();
3662 bool BufferParams::fullAuthorList() const
3664 return documentClass().fullAuthorList();
3668 string BufferParams::getCiteAlias(string const & s) const
3670 vector<string> commands =
3671 documentClass().citeCommands(citeEngineType());
3672 // If it is a real command, don't treat it as an alias
3673 if (find(commands.begin(), commands.end(), s) != commands.end())
3675 map<string,string> aliases = documentClass().citeCommandAliases();
3676 if (aliases.find(s) != aliases.end())
3682 vector<string> BufferParams::citeCommands() const
3684 static CitationStyle const default_style;
3685 vector<string> commands =
3686 documentClass().citeCommands(citeEngineType());
3687 if (commands.empty())
3688 commands.push_back(default_style.name);
3693 vector<CitationStyle> BufferParams::citeStyles() const
3695 static CitationStyle const default_style;
3696 vector<CitationStyle> styles =
3697 documentClass().citeStyles(citeEngineType());
3699 styles.push_back(default_style);
3704 string const BufferParams::getBibtexCommand(string const cmd, bool const warn) const
3706 // split from options
3708 split(cmd, command_in, ' ');
3710 // Look if the requested command is available. If so, use that.
3711 for (auto const & alts : lyxrc.bibtex_alternatives) {
3712 string command_prov;
3713 split(alts, command_prov, ' ');
3714 if (command_in == command_prov)
3718 // If not, find the most suitable fallback for the current cite framework,
3719 // and warn. Note that we omit options in any such case.
3721 if (useBiblatex()) {
3722 // For Biblatex, we prefer biber (also for Japanese)
3723 // and try to fall back to bibtex8
3724 if (lyxrc.bibtex_alternatives.find("biber") != lyxrc.bibtex_alternatives.end())
3726 else if (lyxrc.bibtex_alternatives.find("bibtex8") != lyxrc.bibtex_alternatives.end())
3727 fallback = "bibtex8";
3729 // For classic BibTeX and as last resort for biblatex, try bibtex
3730 if (fallback.empty()) {
3731 if (lyxrc.bibtex_alternatives.find("bibtex") != lyxrc.bibtex_alternatives.end())
3732 fallback = "bibtex";
3738 if (fallback.empty()) {
3739 frontend::Alert::warning(
3740 _("No bibliography processor found!"),
3742 _("The bibliography processor requested by this document "
3743 "(%1$s) is not available and no appropriate "
3744 "alternative has been found. "
3745 "No bibliography and references will be generated.\n"
3746 "Please fix your installation!"),
3749 frontend::Alert::warning(
3750 _("Requested bibliography processor not found!"),
3752 _("The bibliography processor requested by this document "
3753 "(%1$s) is not available. "
3754 "As a fallback, '%2$s' will be used, options are omitted. "
3755 "This might result in errors or unwanted changes in "
3756 "the bibliography. Please check carefully!\n"
3757 "It is suggested to install the missing processor."),
3758 from_utf8(cmd), from_utf8(fallback)));
3764 string const BufferParams::bibtexCommand(bool const warn) const
3766 // Return document-specific setting if available
3767 if (bibtex_command != "default")
3768 return getBibtexCommand(bibtex_command, warn);
3770 // If we have "default" in document settings, consult the prefs
3771 // 1. Japanese (uses a specific processor)
3772 if (encoding().package() == Encoding::japanese) {
3773 if (lyxrc.jbibtex_command != "automatic")
3774 // Return the specified program, if "automatic" is not set
3775 return lyxrc.jbibtex_command;
3776 else if (!useBiblatex()) {
3777 // With classic BibTeX, return pbibtex, jbibtex, bibtex
3778 if (lyxrc.jbibtex_alternatives.find("pbibtex") != lyxrc.jbibtex_alternatives.end())
3780 if (lyxrc.jbibtex_alternatives.find("jbibtex") != lyxrc.jbibtex_alternatives.end())
3785 // 2. All other languages
3786 else if (lyxrc.bibtex_command != "automatic")
3787 // Return the specified program, if "automatic" is not set
3788 return getBibtexCommand(lyxrc.bibtex_command, warn);
3790 // 3. Automatic: find the most suitable for the current cite framework
3791 if (useBiblatex()) {
3792 // For Biblatex, we prefer biber (also for Japanese)
3793 // and fall back to bibtex8 and, as last resort, bibtex
3794 if (lyxrc.bibtex_alternatives.find("biber") != lyxrc.bibtex_alternatives.end())
3796 else if (lyxrc.bibtex_alternatives.find("bibtex8") != lyxrc.bibtex_alternatives.end())
3803 bool BufferParams::useBiblatex() const
3805 return theCiteEnginesList[citeEngine()]->getCiteFramework() == "biblatex";
3809 void BufferParams::invalidateConverterCache() const
3811 pimpl_->isExportCacheValid = false;
3812 pimpl_->isViewCacheValid = false;
3816 // We shouldn't need to reset the params here, since anything
3817 // we need will be recopied.
3818 void BufferParams::copyForAdvFR(const BufferParams & bp)
3820 string const & lang = bp.language->lang();
3822 quotes_style = bp.quotes_style;
3823 layout_modules_ = bp.layout_modules_;
3824 string const & doc_class = bp.documentClass().name();
3825 setBaseClass(doc_class);
3829 void BufferParams::setBibFileEncoding(string const & file, string const & enc)
3831 bib_encodings[file] = enc;
3835 string const BufferParams::bibFileEncoding(string const & file) const
3837 if (bib_encodings.find(file) == bib_encodings.end())
3839 return bib_encodings.find(file)->second;
3843 BufferParams const & defaultBufferParams()
3845 static BufferParams default_params;
3846 return default_params;