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 for (auto incfile : included_children_) {
1983 FileName inc = makeAbsPath(incfile, filepath.absFileName());
1984 string mangled = DocFileName(changeExtension(inc.absFileName(), ".tex")).
1986 if (!features.runparams().nice)
1988 // \includeonly doesn't want an extension
1989 incfile = changeExtension(incfile, string());
1990 incfile = support::latex_path(incfile);
1991 if (!incfile.empty()) {
1994 os << from_utf8(incfile);
2001 if (!features.isProvided("geometry")
2002 && (use_geometry || !class_supported_papersize)) {
2003 odocstringstream ods;
2004 if (!getGraphicsDriver("geometry").empty())
2005 ods << getGraphicsDriver("geometry");
2006 if (orientation == ORIENTATION_LANDSCAPE)
2007 ods << ",landscape";
2008 switch (papersize) {
2010 if (!paperwidth.empty())
2011 ods << ",paperwidth="
2012 << from_ascii(paperwidth);
2013 if (!paperheight.empty())
2014 ods << ",paperheight="
2015 << from_ascii(paperheight);
2017 case PAPER_USLETTER:
2019 case PAPER_USEXECUTIVE:
2048 ods << "," << from_ascii(string_papersize_geometry[papersize]);
2053 docstring g_options = trim(ods.str(), ",");
2054 os << "\\usepackage";
2055 // geometry-light means that the class works with geometry, but overwrites
2056 // the package options and paper sizes (memoir does this).
2057 // In this case, all options need to go to \geometry
2058 // and the standard paper sizes need to go to the class options.
2059 if (!g_options.empty() && !features.isProvided("geometry-light")) {
2060 os << '[' << g_options << ']';
2063 os << "{geometry}\n";
2064 if (use_geometry || features.isProvided("geometry-light")) {
2065 os << "\\geometry{verbose";
2066 if (!g_options.empty())
2067 // Output general options here with "geometry light".
2068 os << "," << g_options;
2069 // output this only if use_geometry is true
2071 if (!topmargin.empty())
2072 os << ",tmargin=" << from_ascii(Length(topmargin).asLatexString());
2073 if (!bottommargin.empty())
2074 os << ",bmargin=" << from_ascii(Length(bottommargin).asLatexString());
2075 if (!leftmargin.empty())
2076 os << ",lmargin=" << from_ascii(Length(leftmargin).asLatexString());
2077 if (!rightmargin.empty())
2078 os << ",rmargin=" << from_ascii(Length(rightmargin).asLatexString());
2079 if (!headheight.empty())
2080 os << ",headheight=" << from_ascii(Length(headheight).asLatexString());
2081 if (!headsep.empty())
2082 os << ",headsep=" << from_ascii(Length(headsep).asLatexString());
2083 if (!footskip.empty())
2084 os << ",footskip=" << from_ascii(Length(footskip).asLatexString());
2085 if (!columnsep.empty())
2086 os << ",columnsep=" << from_ascii(Length(columnsep).asLatexString());
2090 } else if (orientation == ORIENTATION_LANDSCAPE
2091 || papersize != PAPER_DEFAULT) {
2092 features.require("papersize");
2095 if (tokenPos(tclass.opt_pagestyle(), '|', pagestyle) >= 0) {
2096 if (pagestyle == "fancy")
2097 os << "\\usepackage{fancyhdr}\n";
2098 os << "\\pagestyle{" << from_ascii(pagestyle) << "}\n";
2101 // only output when the background color is not default
2102 if (isbackgroundcolor) {
2103 // only require color here, the background color will be defined
2104 // in LaTeXFeatures.cpp to avoid interferences with the LaTeX
2106 features.require("color");
2107 features.require("pagecolor");
2110 // only output when the font color is not default
2112 // only require color here, the font color will be defined
2113 // in LaTeXFeatures.cpp to avoid interferences with the LaTeX
2115 features.require("color");
2116 features.require("fontcolor");
2119 // Only if class has a ToC hierarchy
2120 if (tclass.hasTocLevels()) {
2121 if (secnumdepth != tclass.secnumdepth()) {
2122 os << "\\setcounter{secnumdepth}{"
2126 if (tocdepth != tclass.tocdepth()) {
2127 os << "\\setcounter{tocdepth}{"
2133 if (paragraph_separation) {
2134 // when skip separation
2136 switch (getDefSkip().kind()) {
2137 case VSpace::SMALLSKIP:
2138 psopt = "\\smallskipamount";
2140 case VSpace::MEDSKIP:
2141 psopt = "\\medskipamount";
2143 case VSpace::BIGSKIP:
2144 psopt = "\\bigskipamount";
2146 case VSpace::HALFLINE:
2147 // default (no option)
2149 case VSpace::FULLLINE:
2150 psopt = "\\baselineskip";
2152 case VSpace::LENGTH:
2153 psopt = getDefSkip().length().asLatexString();
2158 if (!features.isProvided("parskip")) {
2160 psopt = "[skip=" + psopt + "]";
2161 os << "\\usepackage" + psopt + "{parskip}\n";
2163 os << "\\setlength{\\parskip}{" + psopt + "}\n";
2166 // when separation by indentation
2167 // only output something when a width is given
2168 if (!getParIndent().empty()) {
2169 os << "\\setlength{\\parindent}{"
2170 << from_utf8(getParIndent().asLatexString())
2175 if (is_math_indent) {
2176 // when formula indentation
2177 // only output something when it is not the default
2178 if (!getMathIndent().empty()) {
2179 os << "\\setlength{\\mathindent}{"
2180 << from_utf8(getMathIndent().asString())
2185 // Now insert the LyX specific LaTeX commands...
2186 features.resolveAlternatives();
2187 features.expandMultiples();
2190 if (!output_sync_macro.empty())
2191 os << from_utf8(output_sync_macro) +"\n";
2192 else if (features.runparams().flavor == Flavor::LaTeX)
2193 os << "\\usepackage[active]{srcltx}\n";
2194 else if (features.runparams().flavor == Flavor::PdfLaTeX)
2195 os << "\\synctex=-1\n";
2198 // due to interferences with babel and hyperref, the color package has to
2199 // be loaded (when it is not already loaded) before babel when hyperref
2200 // is used with the colorlinks option, see
2201 // http://www.lyx.org/trac/ticket/5291
2202 // we decided therefore to load color always before babel, see
2203 // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg144349.html
2204 os << from_ascii(features.getColorOptions());
2206 // If we use hyperref, jurabib, japanese or varioref,
2207 // we have to call babel before
2209 && (features.isRequired("jurabib")
2210 || features.isRequired("hyperref")
2211 || features.isRequired("varioref")
2212 || features.isRequired("japanese"))) {
2213 os << features.getBabelPresettings();
2215 os << from_utf8(babelCall(language_options.str(),
2216 !lyxrc.language_global_options)) + '\n';
2217 os << features.getBabelPostsettings();
2220 // The optional packages;
2221 os << from_ascii(features.getPackages());
2223 // Additional Indices
2224 if (features.isRequired("splitidx")) {
2225 for (auto const & idx : indiceslist()) {
2226 os << "\\newindex{";
2227 os << escape(idx.shortcut());
2233 os << from_utf8(spacing().writePreamble(features.isProvided("SetSpace")));
2236 // * Hyperref manual: "Make sure it comes last of your loaded
2237 // packages, to give it a fighting chance of not being over-written,
2238 // since its job is to redefine many LaTeX commands."
2239 // * Email from Heiko Oberdiek: "It is usually better to load babel
2240 // before hyperref. Then hyperref has a chance to detect babel.
2241 // * Has to be loaded before the "LyX specific LaTeX commands" to
2242 // avoid errors with algorithm floats.
2243 // use hyperref explicitly if it is required
2244 if (features.isRequired("hyperref")) {
2245 OutputParams tmp_params = features.runparams();
2246 pdfoptions().writeLaTeX(tmp_params, os,
2247 features.isProvided("hyperref"));
2248 // correctly break URLs with hyperref and dvi/ps output
2249 if (features.runparams().hyperref_driver == "dvips"
2250 && features.isAvailable("breakurl"))
2251 os << "\\usepackage{breakurl}\n";
2252 } else if (features.isRequired("nameref"))
2253 // hyperref loads this automatically
2254 os << "\\usepackage{nameref}\n";
2257 os << "\\usepackage";
2258 if (!lineno_opts.empty())
2259 os << "[" << lineno_opts << "]";
2261 os << "\\linenumbers\n";
2264 // bibtopic needs to be loaded after hyperref.
2265 // the dot provides the aux file naming which LyX can detect.
2266 if (features.mustProvide("bibtopic"))
2267 os << "\\usepackage[dot]{bibtopic}\n";
2269 // Will be surrounded by \makeatletter and \makeatother when not empty
2270 otexstringstream atlyxpreamble;
2272 // Some macros LyX will need
2274 TexString tmppreamble = features.getMacros();
2275 if (!tmppreamble.str.empty())
2276 atlyxpreamble << "\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
2277 "LyX specific LaTeX commands.\n"
2278 << move(tmppreamble)
2281 // the text class specific preamble
2283 docstring tmppreamble = features.getTClassPreamble();
2284 if (!tmppreamble.empty())
2285 atlyxpreamble << "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
2286 "Textclass specific LaTeX commands.\n"
2290 // suppress date if selected
2291 // use \@ifundefined because we cannot be sure that every document class
2292 // has a \date command
2294 atlyxpreamble << "\\@ifundefined{date}{}{\\date{}}\n";
2296 /* the user-defined preamble */
2297 if (!containsOnly(preamble, " \n\t")) {
2299 atlyxpreamble << "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
2300 "User specified LaTeX commands.\n";
2302 // Check if the user preamble contains uncodable glyphs
2303 odocstringstream user_preamble;
2304 docstring uncodable_glyphs;
2305 Encoding const * const enc = features.runparams().encoding;
2307 for (char_type c : preamble) {
2308 if (!enc->encodable(c)) {
2309 docstring const glyph(1, c);
2310 LYXERR0("Uncodable character '"
2312 << "' in user preamble!");
2313 uncodable_glyphs += glyph;
2314 if (features.runparams().dryrun) {
2315 user_preamble << "<" << _("LyX Warning: ")
2316 << _("uncodable character") << " '";
2317 user_preamble.put(c);
2318 user_preamble << "'>";
2321 user_preamble.put(c);
2324 user_preamble << preamble;
2326 // On BUFFER_VIEW|UPDATE, warn user if we found uncodable glyphs
2327 if (!features.runparams().dryrun && !uncodable_glyphs.empty()) {
2328 frontend::Alert::warning(
2329 _("Uncodable character in user preamble"),
2331 _("The user preamble of your document contains glyphs "
2332 "that are unknown in the current document encoding "
2333 "(namely %1$s).\nThese glyphs are omitted "
2334 " from the output, which may result in "
2335 "incomplete output."
2336 "\n\nPlease select an appropriate "
2337 "document encoding\n"
2338 "(such as utf8) or change the "
2339 "preamble code accordingly."),
2342 atlyxpreamble << user_preamble.str() << '\n';
2345 // footmisc must be loaded after setspace
2346 // Load it here to avoid clashes with footmisc loaded in the user
2347 // preamble. For that reason we also pass the options via
2348 // \PassOptionsToPackage in getPreamble() and not here.
2349 if (features.mustProvide("footmisc"))
2350 atlyxpreamble << "\\usepackage{footmisc}\n";
2352 // subfig loads internally the LaTeX package "caption". As
2353 // caption is a very popular package, users will load it in
2354 // the preamble. Therefore we must load subfig behind the
2355 // user-defined preamble and check if the caption package was
2356 // loaded or not. For the case that caption is loaded before
2357 // subfig, there is the subfig option "caption=false". This
2358 // option also works when a koma-script class is used and
2359 // koma's own caption commands are used instead of caption. We
2360 // use \PassOptionsToPackage here because the user could have
2361 // already loaded subfig in the preamble.
2362 if (features.mustProvide("subfig"))
2363 atlyxpreamble << "\\ifdefined\\showcaptionsetup\n"
2364 " % Caption package is used. Advise subfig not to load it again.\n"
2365 " \\PassOptionsToPackage{caption=false}{subfig}\n"
2367 "\\usepackage{subfig}\n";
2369 // Itemize bullet settings need to be last in case the user
2370 // defines their own bullets that use a package included
2371 // in the user-defined preamble -- ARRae
2372 // Actually it has to be done much later than that
2373 // since some packages like frenchb make modifications
2374 // at \begin{document} time -- JMarc
2375 docstring bullets_def;
2376 for (int i = 0; i < 4; ++i) {
2377 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
2378 if (bullets_def.empty())
2379 bullets_def += "\\AtBeginDocument{\n";
2380 bullets_def += " \\def\\labelitemi";
2382 // `i' is one less than the item to modify
2389 bullets_def += "ii";
2395 bullets_def += '{' +
2396 user_defined_bullet(i).getText()
2401 if (!bullets_def.empty())
2402 atlyxpreamble << bullets_def << "}\n\n";
2404 if (!atlyxpreamble.empty())
2405 os << "\n\\makeatletter\n"
2406 << atlyxpreamble.release()
2407 << "\\makeatother\n\n";
2409 // We try to load babel late, in case it interferes with other packages.
2410 // Jurabib, hyperref, varioref, bicaption, menukeys and listings (bug 8995)
2411 // have to be called after babel, though.
2412 if (use_babel && !features.isRequired("jurabib")
2413 && !features.isRequired("hyperref")
2414 && !features.isRequired("varioref")
2415 && !features.isRequired("japanese")) {
2416 os << features.getBabelPresettings();
2418 os << from_utf8(babelCall(language_options.str(),
2419 !lyxrc.language_global_options)) + '\n';
2420 os << features.getBabelPostsettings();
2422 // In documents containing text in Thai language,
2423 // we must load inputenc after babel (see lib/languages).
2424 if (contains(features.getBabelPostsettings(), from_ascii("thai.ldf")))
2425 writeEncodingPreamble(os, features);
2427 // font selection must be done after babel with non-TeX fonts
2428 if (!fonts.empty() && features.useBabel() && useNonTeXFonts)
2429 os << from_utf8(fonts);
2431 if (features.isRequired("bicaption"))
2432 os << "\\usepackage{bicaption}\n";
2433 if (!listings_params.empty()
2434 || features.mustProvide("listings")
2435 || features.mustProvide("minted")) {
2437 os << "\\usepackage{minted}\n";
2439 os << "\\usepackage{listings}\n";
2441 string lst_params = listings_params;
2442 // If minted, do not output the language option (bug 11203)
2443 if (use_minted && contains(lst_params, "language=")) {
2444 vector<string> opts =
2445 getVectorFromString(lst_params, ",", false);
2446 for (size_t i = 0; i < opts.size(); ++i) {
2447 if (prefixIs(opts[i], "language="))
2448 opts.erase(opts.begin() + i--);
2450 lst_params = getStringFromVector(opts, ",");
2452 if (!lst_params.empty()) {
2454 os << "\\setminted{";
2457 // do not test validity because listings_params is
2458 // supposed to be valid
2460 InsetListingsParams(lst_params).separatedParams(true);
2461 os << from_utf8(par);
2465 // xunicode only needs to be loaded if tipa is used
2466 // (the rest is obsoleted by the new TU encoding).
2467 // It needs to be loaded at least after amsmath, amssymb,
2468 // esint and the other packages that provide special glyphs
2469 if (features.mustProvide("tipa") && useNonTeXFonts
2470 && !features.isProvided("xunicode")) {
2471 // The `xunicode` package officially only supports XeTeX,
2472 // but also works with LuaTeX. We work around its XeTeX test.
2473 if (features.runparams().flavor != Flavor::XeTeX) {
2474 os << "% Pretend to xunicode that we are XeTeX\n"
2475 << "\\def\\XeTeXpicfile{}\n";
2477 os << "\\usepackage{xunicode}\n";
2480 // covington must be loaded after beamerarticle
2481 if (features.isRequired("covington"))
2482 os << "\\usepackage{covington}\n";
2484 // Polyglossia must be loaded last ...
2485 if (use_polyglossia) {
2487 os << "\\usepackage{polyglossia}\n";
2488 // set the main language
2489 os << "\\setdefaultlanguage";
2490 if (!language->polyglossiaOpts().empty())
2491 os << "[" << from_ascii(language->polyglossiaOpts()) << "]";
2492 os << "{" << from_ascii(language->polyglossia()) << "}\n";
2493 // now setup the other languages
2494 set<string> const polylangs =
2495 features.getPolyglossiaLanguages();
2496 for (auto const & pl : polylangs) {
2497 // We do not output the options here; they are output in
2498 // the language switch commands. This is safer if multiple
2499 // varieties are used.
2500 if (pl == language->polyglossia())
2502 os << "\\setotherlanguage";
2503 os << "{" << from_ascii(pl) << "}\n";
2507 // ... but before biblatex (see #7065)
2508 if ((features.mustProvide("biblatex")
2509 || features.isRequired("biblatex-chicago"))
2510 && !features.isProvided("biblatex-chicago")
2511 && !features.isProvided("biblatex-natbib")
2512 && !features.isProvided("natbib-internal")
2513 && !features.isProvided("natbib")
2514 && !features.isProvided("jurabib")) {
2515 // The biblatex-chicago package has a differing interface
2516 // it uses a wrapper package and loads styles via fixed options
2517 bool const chicago = features.isRequired("biblatex-chicago");
2520 os << "\\usepackage";
2521 if (!biblatex_bibstyle.empty()
2522 && (biblatex_bibstyle == biblatex_citestyle)
2524 opts = "style=" + biblatex_bibstyle;
2526 } else if (!chicago) {
2527 if (!biblatex_bibstyle.empty()) {
2528 opts = "bibstyle=" + biblatex_bibstyle;
2531 if (!biblatex_citestyle.empty()) {
2532 opts += delim + "citestyle=" + biblatex_citestyle;
2536 if (!multibib.empty() && multibib != "child") {
2537 opts += delim + "refsection=" + multibib;
2540 if (bibtexCommand() == "bibtex8"
2541 || prefixIs(bibtexCommand(), "bibtex8 ")) {
2542 opts += delim + "backend=bibtex8";
2544 } else if (bibtexCommand() == "bibtex"
2545 || prefixIs(bibtexCommand(), "bibtex ")) {
2546 opts += delim + "backend=bibtex";
2549 if (!bib_encoding.empty() && encodings.fromLyXName(bib_encoding)) {
2550 opts += delim + "bibencoding="
2551 + encodings.fromLyXName(bib_encoding)->latexName();
2554 if (!biblio_opts.empty())
2555 opts += delim + biblio_opts;
2557 os << "[" << opts << "]";
2559 os << "{biblatex-chicago}\n";
2561 os << "{biblatex}\n";
2565 // Load custom language package here
2566 if (features.langPackage() == LaTeXFeatures::LANG_PACK_CUSTOM) {
2567 if (lang_package == "default")
2568 os << from_utf8(lyxrc.language_custom_package);
2570 os << from_utf8(lang_package);
2574 // Since menukeys uses catoptions, which does some heavy changes on key-value options,
2575 // it is recommended to load menukeys as the last package (even after hyperref)
2576 if (features.isRequired("menukeys"))
2577 os << "\\usepackage{menukeys}\n";
2579 docstring const i18npreamble =
2580 features.getTClassI18nPreamble(use_babel, use_polyglossia,
2582 if (!i18npreamble.empty())
2583 os << i18npreamble + '\n';
2589 void BufferParams::useClassDefaults()
2591 DocumentClass const & tclass = documentClass();
2593 sides = tclass.sides();
2594 columns = tclass.columns();
2595 pagestyle = tclass.pagestyle();
2596 tablestyle = tclass.tablestyle();
2597 use_default_options = true;
2598 // Only if class has a ToC hierarchy
2599 if (tclass.hasTocLevels()) {
2600 secnumdepth = tclass.secnumdepth();
2601 tocdepth = tclass.tocdepth();
2606 bool BufferParams::hasClassDefaults() const
2608 DocumentClass const & tclass = documentClass();
2610 return sides == tclass.sides()
2611 && columns == tclass.columns()
2612 && pagestyle == tclass.pagestyle()
2613 && tablestyle == tclass.tablestyle()
2614 && use_default_options
2615 && secnumdepth == tclass.secnumdepth()
2616 && tocdepth == tclass.tocdepth();
2620 DocumentClass const & BufferParams::documentClass() const
2626 DocumentClassConstPtr BufferParams::documentClassPtr() const
2632 void BufferParams::setDocumentClass(DocumentClassConstPtr tc)
2634 // evil, but this function is evil
2635 doc_class_ = const_pointer_cast<DocumentClass>(tc);
2636 invalidateConverterCache();
2640 bool BufferParams::setBaseClass(string const & classname, string const & path)
2642 LYXERR(Debug::TCLASS, "setBaseClass: " << classname);
2643 LayoutFileList & bcl = LayoutFileList::get();
2644 if (!bcl.haveClass(classname)) {
2646 bformat(_("The layout file:\n"
2648 "could not be found. A default textclass with default\n"
2649 "layouts will be used. LyX will not be able to produce\n"
2651 from_utf8(classname));
2652 frontend::Alert::error(_("Document class not found"), s);
2653 bcl.addEmptyClass(classname);
2656 bool const success = bcl[classname].load(path);
2659 bformat(_("Due to some error in it, the layout file:\n"
2661 "could not be loaded. A default textclass with default\n"
2662 "layouts will be used. LyX will not be able to produce\n"
2664 from_utf8(classname));
2665 frontend::Alert::error(_("Could not load class"), s);
2666 bcl.addEmptyClass(classname);
2669 pimpl_->baseClass_ = classname;
2670 layout_modules_.adaptToBaseClass(baseClass(), removed_modules_);
2675 LayoutFile const * BufferParams::baseClass() const
2677 if (LayoutFileList::get().haveClass(pimpl_->baseClass_))
2678 return &(LayoutFileList::get()[pimpl_->baseClass_]);
2684 LayoutFileIndex const & BufferParams::baseClassID() const
2686 return pimpl_->baseClass_;
2690 void BufferParams::makeDocumentClass(bool clone, bool internal)
2695 invalidateConverterCache();
2696 LayoutModuleList mods;
2697 for (auto const & mod : layout_modules_)
2698 mods.push_back(mod);
2700 doc_class_ = getDocumentClass(*baseClass(), mods, cite_engine_, clone, internal);
2702 TextClass::ReturnValues success = TextClass::OK;
2703 if (!forced_local_layout_.empty())
2704 success = doc_class_->read(to_utf8(forced_local_layout_),
2706 if (!local_layout_.empty() &&
2707 (success == TextClass::OK || success == TextClass::OK_OLDFORMAT))
2708 success = doc_class_->read(to_utf8(local_layout_), TextClass::MODULE);
2709 if (success != TextClass::OK && success != TextClass::OK_OLDFORMAT) {
2710 docstring const msg = _("Error reading internal layout information");
2711 frontend::Alert::warning(_("Read Error"), msg);
2716 bool BufferParams::layoutModuleCanBeAdded(string const & modName) const
2718 return layout_modules_.moduleCanBeAdded(modName, baseClass());
2722 docstring BufferParams::getLocalLayout(bool forced) const
2725 return from_utf8(doc_class_->forcedLayouts());
2727 return local_layout_;
2731 void BufferParams::setLocalLayout(docstring const & layout, bool forced)
2734 forced_local_layout_ = layout;
2736 local_layout_ = layout;
2740 bool BufferParams::addLayoutModule(string const & modName)
2742 for (auto const & mod : layout_modules_)
2745 layout_modules_.push_back(modName);
2750 string BufferParams::bufferFormat() const
2752 return documentClass().outputFormat();
2756 bool BufferParams::isExportable(string const & format, bool need_viewable) const
2758 FormatList const & formats = exportableFormats(need_viewable);
2759 for (auto const & fmt : formats) {
2760 if (fmt->name() == format)
2767 FormatList const & BufferParams::exportableFormats(bool only_viewable) const
2769 FormatList & cached = only_viewable ?
2770 pimpl_->viewableFormatList : pimpl_->exportableFormatList;
2771 bool & valid = only_viewable ?
2772 pimpl_->isViewCacheValid : pimpl_->isExportCacheValid;
2776 vector<string> const backs = backends();
2777 set<string> excludes;
2778 if (useNonTeXFonts) {
2779 excludes.insert("latex");
2780 excludes.insert("pdflatex");
2781 } else if (inputenc != "ascii" && inputenc != "utf8-plain") {
2782 // XeTeX with TeX fonts requires input encoding ascii (#10600).
2783 excludes.insert("xetex");
2787 theConverters().getReachable(backs[0], only_viewable, true, excludes);
2788 vector<string>::const_iterator it = backs.begin() + 1;
2789 for (; it != backs.end(); ++it) {
2790 FormatList r = theConverters().getReachable(*it, only_viewable,
2792 result.insert(result.end(), r.begin(), r.end());
2794 sort(result.begin(), result.end(), Format::formatSorter);
2801 vector<string> BufferParams::backends() const
2804 string const buffmt = bufferFormat();
2806 // FIXME: Don't hardcode format names here, but use a flag
2807 if (buffmt == "latex") {
2808 if (encoding().package() == Encoding::japanese)
2809 v.push_back("platex");
2811 if (!useNonTeXFonts) {
2812 v.push_back("pdflatex");
2813 v.push_back("latex");
2816 || inputenc == "ascii" || inputenc == "utf8-plain")
2817 v.push_back("xetex");
2818 v.push_back("luatex");
2819 v.push_back("dviluatex");
2822 string rbuffmt = buffmt;
2823 // If we use an OutputFormat in Japanese docs,
2824 // we need special format in order to get the path
2825 // via pLaTeX (#8823)
2826 if (documentClass().hasOutputFormat()
2827 && encoding().package() == Encoding::japanese)
2829 v.push_back(rbuffmt);
2832 v.push_back("xhtml");
2833 v.push_back("docbook5");
2834 v.push_back("text");
2840 Flavor BufferParams::getOutputFlavor(string const & format) const
2842 string const dformat = (format.empty() || format == "default") ?
2843 getDefaultOutputFormat() : format;
2844 DefaultFlavorCache::const_iterator it =
2845 default_flavors_.find(dformat);
2847 if (it != default_flavors_.end())
2850 Flavor result = Flavor::LaTeX;
2852 // FIXME It'd be better not to hardcode this, but to do
2853 // something with formats.
2854 if (dformat == "xhtml")
2855 result = Flavor::Html;
2856 else if (dformat == "docbook5")
2857 result = Flavor::DocBook5;
2858 else if (dformat == "text")
2859 result = Flavor::Text;
2860 else if (dformat == "lyx")
2861 result = Flavor::LyX;
2862 else if (dformat == "pdflatex")
2863 result = Flavor::PdfLaTeX;
2864 else if (dformat == "xetex")
2865 result = Flavor::XeTeX;
2866 else if (dformat == "luatex")
2867 result = Flavor::LuaTeX;
2868 else if (dformat == "dviluatex")
2869 result = Flavor::DviLuaTeX;
2871 // Try to determine flavor of default output format
2872 vector<string> backs = backends();
2873 if (find(backs.begin(), backs.end(), dformat) == backs.end()) {
2874 // Get shortest path to format
2875 Graph::EdgePath path;
2876 for (auto const & bvar : backs) {
2877 Graph::EdgePath p = theConverters().getPath(bvar, dformat);
2878 if (!p.empty() && (path.empty() || p.size() < path.size())) {
2883 result = theConverters().getFlavor(path);
2886 // cache this flavor
2887 default_flavors_[dformat] = result;
2892 string BufferParams::getDefaultOutputFormat() const
2894 if (!default_output_format.empty()
2895 && default_output_format != "default")
2896 return default_output_format;
2897 if (encoding().package() == Encoding::japanese)
2898 return lyxrc.default_platex_view_format;
2900 return lyxrc.default_otf_view_format;
2901 return lyxrc.default_view_format;
2904 Font const BufferParams::getFont() const
2906 FontInfo f = documentClass().defaultfont();
2907 if (fonts_default_family == "rmdefault")
2908 f.setFamily(ROMAN_FAMILY);
2909 else if (fonts_default_family == "sfdefault")
2910 f.setFamily(SANS_FAMILY);
2911 else if (fonts_default_family == "ttdefault")
2912 f.setFamily(TYPEWRITER_FAMILY);
2913 return Font(f, language);
2917 QuoteStyle BufferParams::getQuoteStyle(string const & qs) const
2919 return quotesstyletranslator().find(qs);
2923 bool BufferParams::isLatex() const
2925 return documentClass().outputType() == LATEX;
2929 bool BufferParams::isLiterate() const
2931 return documentClass().outputType() == LITERATE;
2935 void BufferParams::readPreamble(Lexer & lex)
2937 if (lex.getString() != "\\begin_preamble")
2938 lyxerr << "Error (BufferParams::readPreamble):"
2939 "consistency check failed." << endl;
2941 preamble = lex.getLongString(from_ascii("\\end_preamble"));
2945 void BufferParams::readDocumentMetadata(Lexer & lex)
2947 if (lex.getString() != "\\begin_metadata")
2948 lyxerr << "Error (BufferParams::readDocumentMetadata):"
2949 "consistency check failed." << endl;
2951 document_metadata = lex.getLongString(from_ascii("\\end_metadata"));
2955 void BufferParams::readLocalLayout(Lexer & lex, bool forced)
2957 string const expected = forced ? "\\begin_forced_local_layout" :
2958 "\\begin_local_layout";
2959 if (lex.getString() != expected)
2960 lyxerr << "Error (BufferParams::readLocalLayout):"
2961 "consistency check failed." << endl;
2964 forced_local_layout_ =
2965 lex.getLongString(from_ascii("\\end_forced_local_layout"));
2967 local_layout_ = lex.getLongString(from_ascii("\\end_local_layout"));
2971 bool BufferParams::setLanguage(string const & lang)
2973 Language const *new_language = languages.getLanguage(lang);
2974 if (!new_language) {
2975 // Language lang was not found
2978 language = new_language;
2983 void BufferParams::readLanguage(Lexer & lex)
2985 if (!lex.next()) return;
2987 string const tmptok = lex.getString();
2989 // check if tmptok is part of tex_babel in tex-defs.h
2990 if (!setLanguage(tmptok)) {
2991 // Language tmptok was not found
2992 language = default_language;
2993 lyxerr << "Warning: Setting language `"
2994 << tmptok << "' to `" << language->lang()
3000 void BufferParams::readGraphicsDriver(Lexer & lex)
3005 string const tmptok = lex.getString();
3006 // check if tmptok is part of tex_graphics in tex_defs.h
3009 string const test = tex_graphics[n++];
3011 if (test == tmptok) {
3012 graphics_driver = tmptok;
3017 "Warning: graphics driver `$$Token' not recognized!\n"
3018 " Setting graphics driver to `default'.\n");
3019 graphics_driver = "default";
3026 void BufferParams::readBullets(Lexer & lex)
3031 int const index = lex.getInteger();
3033 int temp_int = lex.getInteger();
3034 user_defined_bullet(index).setFont(temp_int);
3035 temp_bullet(index).setFont(temp_int);
3037 user_defined_bullet(index).setCharacter(temp_int);
3038 temp_bullet(index).setCharacter(temp_int);
3040 user_defined_bullet(index).setSize(temp_int);
3041 temp_bullet(index).setSize(temp_int);
3045 void BufferParams::readBulletsLaTeX(Lexer & lex)
3047 // The bullet class should be able to read this.
3050 int const index = lex.getInteger();
3052 docstring const temp_str = lex.getDocString();
3054 user_defined_bullet(index).setText(temp_str);
3055 temp_bullet(index).setText(temp_str);
3059 void BufferParams::readModules(Lexer & lex)
3061 if (!lex.eatLine()) {
3062 lyxerr << "Error (BufferParams::readModules):"
3063 "Unexpected end of input." << endl;
3067 string mod = lex.getString();
3068 if (mod == "\\end_modules")
3070 addLayoutModule(mod);
3076 void BufferParams::readRemovedModules(Lexer & lex)
3078 if (!lex.eatLine()) {
3079 lyxerr << "Error (BufferParams::readRemovedModules):"
3080 "Unexpected end of input." << endl;
3084 string mod = lex.getString();
3085 if (mod == "\\end_removed_modules")
3087 removed_modules_.push_back(mod);
3090 // now we want to remove any removed modules that were previously
3091 // added. normally, that will be because default modules were added in
3092 // setBaseClass(), which gets called when \textclass is read at the
3093 // start of the read.
3094 for (auto const & rm : removed_modules_) {
3095 LayoutModuleList::iterator const mit = layout_modules_.begin();
3096 LayoutModuleList::iterator const men = layout_modules_.end();
3097 LayoutModuleList::iterator found = find(mit, men, rm);
3100 layout_modules_.erase(found);
3105 void BufferParams::readIncludeonly(Lexer & lex)
3107 if (!lex.eatLine()) {
3108 lyxerr << "Error (BufferParams::readIncludeonly):"
3109 "Unexpected end of input." << endl;
3113 string child = lex.getString();
3114 if (child == "\\end_includeonly")
3116 included_children_.push_back(child);
3122 string BufferParams::paperSizeName(PapersizePurpose purpose, string const & psize) const
3124 PAPER_SIZE ppsize = psize.empty() ? papersize : papersizetranslator().find(psize);
3127 if (documentClass().pagesize() == "default")
3128 // could be anything, so don't guess
3130 return paperSizeName(purpose, documentClass().pagesize());
3131 case PAPER_CUSTOM: {
3132 if (purpose == XDVI && !paperwidth.empty() &&
3133 !paperheight.empty()) {
3134 // heightxwidth<unit>
3135 string first = paperwidth;
3136 string second = paperheight;
3137 if (orientation == ORIENTATION_LANDSCAPE)
3140 return first.erase(first.length() - 2)
3146 // dvips and dvipdfm do not know this
3147 if (purpose == DVIPS || purpose == DVIPDFM)
3151 if (purpose == DVIPS || purpose == DVIPDFM)
3155 if (purpose == DVIPS || purpose == DVIPDFM)
3165 if (purpose == DVIPS || purpose == DVIPDFM)
3169 if (purpose == DVIPS || purpose == DVIPDFM)
3173 if (purpose == DVIPS || purpose == DVIPDFM)
3177 if (purpose == DVIPS || purpose == DVIPDFM)
3181 if (purpose == DVIPS || purpose == DVIPDFM)
3185 // dvipdfm does not know this
3186 if (purpose == DVIPDFM)
3190 if (purpose == DVIPDFM)
3194 if (purpose == DVIPS || purpose == DVIPDFM)
3198 if (purpose == DVIPS || purpose == DVIPDFM)
3202 if (purpose == DVIPS || purpose == DVIPDFM)
3206 if (purpose == DVIPS || purpose == DVIPDFM)
3210 if (purpose == DVIPS || purpose == DVIPDFM)
3214 if (purpose == DVIPS || purpose == DVIPDFM)
3218 if (purpose == DVIPS || purpose == DVIPDFM)
3222 if (purpose == DVIPS || purpose == DVIPDFM)
3226 if (purpose == DVIPS || purpose == DVIPDFM)
3230 if (purpose == DVIPS || purpose == DVIPDFM)
3234 if (purpose == DVIPS || purpose == DVIPDFM)
3238 if (purpose == DVIPS || purpose == DVIPDFM)
3242 if (purpose == DVIPS || purpose == DVIPDFM)
3246 if (purpose == DVIPS || purpose == DVIPDFM)
3250 if (purpose == DVIPS || purpose == DVIPDFM)
3253 case PAPER_USEXECUTIVE:
3254 // dvipdfm does not know this
3255 if (purpose == DVIPDFM)
3260 case PAPER_USLETTER:
3262 if (purpose == XDVI)
3269 string const BufferParams::dvips_options() const
3273 // If the class loads the geometry package, we do not know which
3274 // paper size is used, since we do not set it (bug 7013).
3275 // Therefore we must not specify any argument here.
3276 // dvips gets the correct paper size via DVI specials in this case
3277 // (if the class uses the geometry package correctly).
3278 if (documentClass().provides("geometry"))
3282 && papersize == PAPER_CUSTOM
3283 && !lyxrc.print_paper_dimension_flag.empty()
3284 && !paperwidth.empty()
3285 && !paperheight.empty()) {
3286 // using a custom papersize
3287 result = lyxrc.print_paper_dimension_flag;
3288 result += ' ' + paperwidth;
3289 result += ',' + paperheight;
3291 string const paper_option = paperSizeName(DVIPS);
3292 if (!paper_option.empty() && (paper_option != "letter" ||
3293 orientation != ORIENTATION_LANDSCAPE)) {
3294 // dvips won't accept -t letter -t landscape.
3295 // In all other cases, include the paper size
3297 result = lyxrc.print_paper_flag;
3298 result += ' ' + paper_option;
3301 if (orientation == ORIENTATION_LANDSCAPE &&
3302 papersize != PAPER_CUSTOM)
3303 result += ' ' + lyxrc.print_landscape_flag;
3308 string const BufferParams::main_font_encoding() const
3310 vector<string> const fencs = font_encodings();
3311 if (fencs.empty()) {
3312 if (ascii_lowercase(language->fontenc(*this)) == "none")
3316 return fencs.back();
3320 vector<string> const BufferParams::font_encodings() const
3322 string doc_fontenc = (fontenc == "auto") ? string() : fontenc;
3324 vector<string> fontencs;
3326 // "default" means "no explicit font encoding"
3327 if (doc_fontenc != "default") {
3328 if (!doc_fontenc.empty())
3329 // If we have a custom setting, we use only that!
3330 return getVectorFromString(doc_fontenc);
3331 string const lfe = language->fontenc(*this);
3333 && ascii_lowercase(language->fontenc(*this)) != "none") {
3334 vector<string> fencs = getVectorFromString(lfe);
3335 for (auto & fe : fencs) {
3336 if (find(fontencs.begin(), fontencs.end(), fe) == fontencs.end())
3337 fontencs.push_back(fe);
3346 string BufferParams::babelCall(string const & lang_opts, bool const langoptions) const
3348 // suppress the babel call if there is no BabelName defined
3349 // for the document language in the lib/languages file and if no
3350 // other languages are used (lang_opts is then empty)
3351 if (lang_opts.empty())
3353 // The prefs may require the languages to
3354 // be submitted to babel itself (not the class).
3356 return "\\usepackage[" + lang_opts + "]{babel}";
3357 return "\\usepackage{babel}";
3361 docstring BufferParams::getGraphicsDriver(string const & package) const
3365 if (package == "geometry") {
3366 if (graphics_driver == "dvips"
3367 || graphics_driver == "dvipdfm"
3368 || graphics_driver == "pdftex"
3369 || graphics_driver == "vtex")
3370 result = from_ascii(graphics_driver);
3371 else if (graphics_driver == "dvipdfmx")
3372 result = from_ascii("dvipdfm");
3379 void BufferParams::writeEncodingPreamble(otexstream & os,
3380 LaTeXFeatures & features) const
3382 // With no-TeX fonts we use utf8-plain without encoding package.
3386 if (inputenc == "auto-legacy") {
3387 string const doc_encoding =
3388 language->encoding()->latexName();
3389 Encoding::Package const package =
3390 language->encoding()->package();
3392 // Create list of inputenc options:
3393 set<string> encoding_set;
3394 // luainputenc fails with more than one encoding
3395 if (features.runparams().flavor != Flavor::LuaTeX
3396 && features.runparams().flavor != Flavor::DviLuaTeX)
3397 // list all input encodings used in the document
3398 encoding_set = features.getEncodingSet(doc_encoding);
3400 // The "japanese" babel-language requires the pLaTeX engine
3401 // which conflicts with "inputenc".
3402 // See http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129680.html
3403 if ((!encoding_set.empty() || package == Encoding::inputenc)
3404 && !features.isRequired("japanese")
3405 && !features.isProvided("inputenc")) {
3406 os << "\\usepackage[";
3407 set<string>::const_iterator it = encoding_set.begin();
3408 set<string>::const_iterator const end = encoding_set.end();
3410 os << from_ascii(*it);
3413 for (; it != end; ++it)
3414 os << ',' << from_ascii(*it);
3415 if (package == Encoding::inputenc) {
3416 if (!encoding_set.empty())
3418 os << from_ascii(doc_encoding);
3420 if (features.runparams().flavor == Flavor::LuaTeX
3421 || features.runparams().flavor == Flavor::DviLuaTeX)
3422 os << "]{luainputenc}\n";
3424 os << "]{inputenc}\n";
3426 } else if (inputenc != "auto-legacy-plain") {
3427 switch (encoding().package()) {
3428 case Encoding::none:
3430 case Encoding::japanese:
3431 if (encoding().iconvName() != "UTF-8"
3432 && !features.runparams().isFullUnicode())
3433 // don't default to [utf8]{inputenc} with TeXLive >= 18
3434 os << "\\ifdefined\\UseRawInputEncoding\n"
3435 << " \\UseRawInputEncoding\\fi\n";
3437 case Encoding::inputenc:
3438 // do not load inputenc if japanese is used
3439 // or if the class provides inputenc
3440 if (features.isRequired("japanese")
3441 || features.isProvided("inputenc"))
3443 os << "\\usepackage[" << from_ascii(encoding().latexName());
3444 if (features.runparams().flavor == Flavor::LuaTeX
3445 || features.runparams().flavor == Flavor::DviLuaTeX)
3446 os << "]{luainputenc}\n";
3448 os << "]{inputenc}\n";
3452 if (inputenc == "auto-legacy-plain" || features.isRequired("japanese")) {
3453 // don't default to [utf8]{inputenc} with TeXLive >= 18
3454 os << "\\ifdefined\\UseRawInputEncoding\n";
3455 os << " \\UseRawInputEncoding\\fi\n";
3460 string const BufferParams::parseFontName(string const & name) const
3462 string mangled = name;
3463 size_t const idx = mangled.find('[');
3464 if (idx == string::npos || idx == 0)
3467 return mangled.substr(0, idx - 1);
3471 string const BufferParams::loadFonts(LaTeXFeatures & features) const
3473 if (fontsRoman() == "default" && fontsSans() == "default"
3474 && fontsTypewriter() == "default"
3475 && (fontsMath() == "default" || fontsMath() == "auto"))
3481 /* Fontspec (XeTeX, LuaTeX): we provide GUI support for oldstyle
3482 * numbers (Numbers=OldStyle) and sf/tt scaling. The Ligatures=TeX/
3483 * Mapping=tex-text option assures TeX ligatures (such as "--")
3484 * are resolved. Note that tt does not use these ligatures.
3486 * -- add more GUI options?
3487 * -- add more fonts (fonts for other scripts)
3488 * -- if there's a way to find out if a font really supports
3489 * OldStyle, enable/disable the widget accordingly.
3491 if (useNonTeXFonts && features.isAvailable("fontspec")) {
3492 // "Mapping=tex-text" and "Ligatures=TeX" are equivalent.
3493 // However, until v.2 (2010/07/11) fontspec only knew
3494 // Mapping=tex-text (for XeTeX only); then "Ligatures=TeX"
3495 // was introduced for both XeTeX and LuaTeX (LuaTeX
3496 // didn't understand "Mapping=tex-text", while XeTeX
3497 // understood both. With most recent versions, both
3498 // variants are understood by both engines. However,
3499 // we want to provide support for at least TeXLive 2009
3500 // (for XeTeX; LuaTeX is only supported as of v.2)
3501 // As of 2017/11/03, Babel has its own higher-level
3502 // interface on top of fontspec that is to be used.
3503 bool const babelfonts = features.useBabel()
3504 && features.isAvailable("babel-2017/11/03");
3505 string const texmapping =
3506 (features.runparams().flavor == Flavor::XeTeX) ?
3507 "Mapping=tex-text" : "Ligatures=TeX";
3508 if (fontsRoman() != "default") {
3510 os << "\\babelfont{rm}[";
3512 os << "\\setmainfont[";
3513 if (!font_roman_opts.empty())
3514 os << font_roman_opts << ',';
3516 if (fonts_roman_osf)
3517 os << ",Numbers=OldStyle";
3518 os << "]{" << parseFontName(fontsRoman()) << "}\n";
3520 if (fontsSans() != "default") {
3521 string const sans = parseFontName(fontsSans());
3522 if (fontsSansScale() != 100) {
3524 os << "\\babelfont{sf}";
3526 os << "\\setsansfont";
3528 << float(fontsSansScale()) / 100 << ',';
3530 os << "Numbers=OldStyle,";
3531 if (!font_sans_opts.empty())
3532 os << font_sans_opts << ',';
3533 os << texmapping << "]{"
3537 os << "\\babelfont{sf}[";
3539 os << "\\setsansfont[";
3541 os << "Numbers=OldStyle,";
3542 if (!font_sans_opts.empty())
3543 os << font_sans_opts << ',';
3544 os << texmapping << "]{"
3548 if (fontsTypewriter() != "default") {
3549 string const mono = parseFontName(fontsTypewriter());
3550 if (fontsTypewriterScale() != 100) {
3552 os << "\\babelfont{tt}";
3554 os << "\\setmonofont";
3556 << float(fontsTypewriterScale()) / 100;
3557 if (fonts_typewriter_osf)
3558 os << ",Numbers=OldStyle";
3559 if (!font_typewriter_opts.empty())
3560 os << ',' << font_typewriter_opts;
3565 os << "\\babelfont{tt}";
3567 os << "\\setmonofont";
3568 if (!font_typewriter_opts.empty() || fonts_typewriter_osf) {
3570 if (fonts_typewriter_osf)
3571 os << "Numbers=OldStyle";
3572 if (!font_typewriter_opts.empty()) {
3573 if (fonts_typewriter_osf)
3575 os << font_typewriter_opts;
3579 os << '{' << mono << "}\n";
3586 bool const ot1 = (features.runparams().main_fontenc == "default"
3587 || features.runparams().main_fontenc == "OT1");
3588 bool const dryrun = features.runparams().dryrun;
3589 bool const complete = (fontsSans() == "default" && fontsTypewriter() == "default");
3590 bool const nomath = (fontsMath() != "auto");
3593 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsRoman())).getLaTeXCode(
3594 dryrun, ot1, complete, fonts_expert_sc, fonts_roman_osf,
3595 nomath, font_roman_opts);
3598 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsSans())).getLaTeXCode(
3599 dryrun, ot1, complete, fonts_expert_sc, fonts_sans_osf,
3600 nomath, font_sans_opts, fontsSansScale());
3602 // MONOSPACED/TYPEWRITER
3603 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsTypewriter())).getLaTeXCode(
3604 dryrun, ot1, complete, fonts_expert_sc, fonts_typewriter_osf,
3605 nomath, font_typewriter_opts, fontsTypewriterScale());
3608 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsMath())).getLaTeXCode(
3609 dryrun, ot1, complete, fonts_expert_sc, fonts_roman_osf,
3616 Encoding const & BufferParams::encoding() const
3618 // Main encoding for LaTeX output.
3620 return *(encodings.fromLyXName("utf8-plain"));
3621 if (inputenc == "auto-legacy" || inputenc == "auto-legacy-plain")
3622 return *language->encoding();
3623 if (inputenc == "utf8" && language->lang() == "japanese")
3624 return *(encodings.fromLyXName("utf8-platex"));
3625 Encoding const * const enc = encodings.fromLyXName(inputenc);
3628 LYXERR0("Unknown inputenc value `" << inputenc
3629 << "'. Using `auto' instead.");
3630 return *language->encoding();
3634 string const & BufferParams::defaultBiblioStyle() const
3636 if (!biblio_style.empty())
3637 return biblio_style;
3639 map<string, string> const & bs = documentClass().defaultBiblioStyle();
3640 auto cit = bs.find(theCiteEnginesList.getTypeAsString(citeEngineType()));
3641 if (cit != bs.end())
3644 return empty_string();
3648 bool BufferParams::fullAuthorList() const
3650 return documentClass().fullAuthorList();
3654 string BufferParams::getCiteAlias(string const & s) const
3656 vector<string> commands =
3657 documentClass().citeCommands(citeEngineType());
3658 // If it is a real command, don't treat it as an alias
3659 if (find(commands.begin(), commands.end(), s) != commands.end())
3661 map<string,string> aliases = documentClass().citeCommandAliases();
3662 if (aliases.find(s) != aliases.end())
3668 vector<string> BufferParams::citeCommands() const
3670 static CitationStyle const default_style;
3671 vector<string> commands =
3672 documentClass().citeCommands(citeEngineType());
3673 if (commands.empty())
3674 commands.push_back(default_style.name);
3679 vector<CitationStyle> BufferParams::citeStyles() const
3681 static CitationStyle const default_style;
3682 vector<CitationStyle> styles =
3683 documentClass().citeStyles(citeEngineType());
3685 styles.push_back(default_style);
3690 string const BufferParams::getBibtexCommand(string const cmd, bool const warn) const
3692 // split from options
3694 split(cmd, command_in, ' ');
3696 // Look if the requested command is available. If so, use that.
3697 for (auto const & alts : lyxrc.bibtex_alternatives) {
3698 string command_prov;
3699 split(alts, command_prov, ' ');
3700 if (command_in == command_prov)
3704 // If not, find the most suitable fallback for the current cite framework,
3705 // and warn. Note that we omit options in any such case.
3707 if (useBiblatex()) {
3708 // For Biblatex, we prefer biber (also for Japanese)
3709 // and try to fall back to bibtex8
3710 if (lyxrc.bibtex_alternatives.find("biber") != lyxrc.bibtex_alternatives.end())
3712 else if (lyxrc.bibtex_alternatives.find("bibtex8") != lyxrc.bibtex_alternatives.end())
3713 fallback = "bibtex8";
3715 // For classic BibTeX and as last resort for biblatex, try bibtex
3716 if (fallback.empty()) {
3717 if (lyxrc.bibtex_alternatives.find("bibtex") != lyxrc.bibtex_alternatives.end())
3718 fallback = "bibtex";
3724 if (fallback.empty()) {
3725 frontend::Alert::warning(
3726 _("No bibliography processor found!"),
3728 _("The bibliography processor requested by this document "
3729 "(%1$s) is not available and no appropriate "
3730 "alternative has been found. "
3731 "No bibliography and references will be generated.\n"
3732 "Please fix your installation!"),
3735 frontend::Alert::warning(
3736 _("Requested bibliography processor not found!"),
3738 _("The bibliography processor requested by this document "
3739 "(%1$s) is not available. "
3740 "As a fallback, '%2$s' will be used, options are omitted. "
3741 "This might result in errors or unwanted changes in "
3742 "the bibliography. Please check carefully!\n"
3743 "It is suggested to install the missing processor."),
3744 from_utf8(cmd), from_utf8(fallback)));
3750 string const BufferParams::bibtexCommand(bool const warn) const
3752 // Return document-specific setting if available
3753 if (bibtex_command != "default")
3754 return getBibtexCommand(bibtex_command, warn);
3756 // If we have "default" in document settings, consult the prefs
3757 // 1. Japanese (uses a specific processor)
3758 if (encoding().package() == Encoding::japanese) {
3759 if (lyxrc.jbibtex_command != "automatic")
3760 // Return the specified program, if "automatic" is not set
3761 return lyxrc.jbibtex_command;
3762 else if (!useBiblatex()) {
3763 // With classic BibTeX, return pbibtex, jbibtex, bibtex
3764 if (lyxrc.jbibtex_alternatives.find("pbibtex") != lyxrc.jbibtex_alternatives.end())
3766 if (lyxrc.jbibtex_alternatives.find("jbibtex") != lyxrc.jbibtex_alternatives.end())
3771 // 2. All other languages
3772 else if (lyxrc.bibtex_command != "automatic")
3773 // Return the specified program, if "automatic" is not set
3774 return getBibtexCommand(lyxrc.bibtex_command, warn);
3776 // 3. Automatic: find the most suitable for the current cite framework
3777 if (useBiblatex()) {
3778 // For Biblatex, we prefer biber (also for Japanese)
3779 // and fall back to bibtex8 and, as last resort, bibtex
3780 if (lyxrc.bibtex_alternatives.find("biber") != lyxrc.bibtex_alternatives.end())
3782 else if (lyxrc.bibtex_alternatives.find("bibtex8") != lyxrc.bibtex_alternatives.end())
3789 bool BufferParams::useBiblatex() const
3791 return theCiteEnginesList[citeEngine()]->getCiteFramework() == "biblatex";
3795 void BufferParams::invalidateConverterCache() const
3797 pimpl_->isExportCacheValid = false;
3798 pimpl_->isViewCacheValid = false;
3802 // We shouldn't need to reset the params here, since anything
3803 // we need will be recopied.
3804 void BufferParams::copyForAdvFR(const BufferParams & bp)
3806 string const & lang = bp.language->lang();
3808 layout_modules_ = bp.layout_modules_;
3809 string const & doc_class = bp.documentClass().name();
3810 setBaseClass(doc_class);
3814 void BufferParams::setBibFileEncoding(string const & file, string const & enc)
3816 bib_encodings[file] = enc;
3820 string const BufferParams::bibFileEncoding(string const & file) const
3822 if (bib_encodings.find(file) == bib_encodings.end())
3824 return bib_encodings.find(file)->second;