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 IgnoreList 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 display_pixel_ratio = 1.0;
483 shell_escape = false;
489 // map current author
490 author_map_[pimpl_->authorlist.get(0).bufferId()] = 0;
494 docstring BufferParams::B_(string const & l10n) const
496 LASSERT(language, return from_utf8(l10n));
497 return getMessages(language->code()).get(l10n);
501 BufferParams::Package BufferParams::use_package(std::string const & p) const
503 PackageMap::const_iterator it = use_packages.find(p);
504 if (it == use_packages.end())
510 void BufferParams::use_package(std::string const & p, BufferParams::Package u)
516 map<string, string> const & BufferParams::auto_packages()
518 static map<string, string> packages;
519 if (packages.empty()) {
520 // We could have a race condition here that two threads
521 // discover an empty map at the same time and want to fill
522 // it, but that is no problem, since the same contents is
523 // filled in twice then. Having the locker inside the
524 // packages.empty() condition has the advantage that we
525 // don't need the mutex overhead for simple reading.
527 Mutex::Locker locker(&mutex);
528 // adding a package here implies a file format change!
529 packages["amsmath"] =
530 N_("The LaTeX package amsmath is only used if AMS formula types or symbols from the AMS math toolbars are inserted into formulas");
531 packages["amssymb"] =
532 N_("The LaTeX package amssymb is only used if symbols from the AMS math toolbars are inserted into formulas");
534 N_("The LaTeX package cancel is only used if \\cancel commands are used in formulas");
536 N_("The LaTeX package esint is only used if special integral symbols are inserted into formulas");
537 packages["mathdots"] =
538 N_("The LaTeX package mathdots is only used if the command \\iddots is inserted into formulas");
539 packages["mathtools"] =
540 N_("The LaTeX package mathtools is only used if some mathematical relations are inserted into formulas");
542 N_("The LaTeX package mhchem is only used if either the command \\ce or \\cf is inserted into formulas");
543 packages["stackrel"] =
544 N_("The LaTeX package stackrel is only used if the command \\stackrel with subscript is inserted into formulas");
545 packages["stmaryrd"] =
546 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");
547 packages["undertilde"] =
548 N_("The LaTeX package undertilde is only used if you use the math frame decoration 'utilde'");
554 bool BufferParams::useBibtopic() const
558 return (use_bibtopic || (!multibib.empty() && multibib != "child"));
562 AuthorList & BufferParams::authors()
564 return pimpl_->authorlist;
568 AuthorList const & BufferParams::authors() const
570 return pimpl_->authorlist;
574 void BufferParams::addAuthor(Author const & a)
576 author_map_[a.bufferId()] = pimpl_->authorlist.record(a);
580 BranchList & BufferParams::branchlist()
582 return pimpl_->branchlist;
586 BranchList const & BufferParams::branchlist() const
588 return pimpl_->branchlist;
592 IndicesList & BufferParams::indiceslist()
594 return pimpl_->indiceslist;
598 IndicesList const & BufferParams::indiceslist() const
600 return pimpl_->indiceslist;
604 typedef std::vector<WordLangTuple> IgnoreList;
607 IgnoreList & BufferParams::spellignore()
609 return pimpl_->spellignore;
613 IgnoreList const & BufferParams::spellignore() const
615 return pimpl_->spellignore;
619 bool BufferParams::spellignored(WordLangTuple const & wl) const
621 bool has_item = false;
622 vector<WordLangTuple> il = spellignore();
623 vector<WordLangTuple>::const_iterator it = il.begin();
624 for (; it != il.end(); ++it) {
625 if (it->lang()->code() != wl.lang()->code())
627 if (it->word() == wl.word()) {
636 Bullet & BufferParams::temp_bullet(lyx::size_type const index)
638 LASSERT(index < 4, return pimpl_->temp_bullets[0]);
639 return pimpl_->temp_bullets[index];
643 Bullet const & BufferParams::temp_bullet(lyx::size_type const index) const
645 LASSERT(index < 4, return pimpl_->temp_bullets[0]);
646 return pimpl_->temp_bullets[index];
650 Bullet & BufferParams::user_defined_bullet(lyx::size_type const index)
652 LASSERT(index < 4, return pimpl_->temp_bullets[0]);
653 return pimpl_->user_defined_bullets[index];
657 Bullet const & BufferParams::user_defined_bullet(lyx::size_type const index) const
659 LASSERT(index < 4, return pimpl_->temp_bullets[0]);
660 return pimpl_->user_defined_bullets[index];
664 Spacing & BufferParams::spacing()
666 return pimpl_->spacing;
670 Spacing const & BufferParams::spacing() const
672 return pimpl_->spacing;
676 PDFOptions & BufferParams::pdfoptions()
678 return pimpl_->pdfoptions;
682 PDFOptions const & BufferParams::pdfoptions() const
684 return pimpl_->pdfoptions;
688 Length const & BufferParams::getMathIndent() const
690 return pimpl_->mathindent;
694 void BufferParams::setMathIndent(Length const & indent)
696 pimpl_->mathindent = indent;
700 Length const & BufferParams::getParIndent() const
702 return pimpl_->parindent;
706 void BufferParams::setParIndent(Length const & indent)
708 pimpl_->parindent = indent;
712 VSpace const & BufferParams::getDefSkip() const
714 return pimpl_->defskip;
718 void BufferParams::setDefSkip(VSpace const & vs)
720 // DEFSKIP will cause an infinite loop
721 LASSERT(vs.kind() != VSpace::DEFSKIP, return);
722 pimpl_->defskip = vs;
726 BufferParams::MathNumber BufferParams::getMathNumber() const
728 if (math_numbering_side != DEFAULT)
729 return math_numbering_side;
730 // FIXME: do not hardcode language here
731 else if (language->lang() == "arabic_arabi"
732 || documentClass().provides("leqno"))
739 string BufferParams::readToken(Lexer & lex, string const & token,
740 FileName const & filename)
743 FileName const & filepath = filename.onlyPath();
745 if (token == "\\textclass") {
747 string const classname = lex.getString();
748 // if there exists a local layout file, ignore the system one
749 // NOTE: in this case, the textclass (.cls file) is assumed to
752 LayoutFileList & bcl = LayoutFileList::get();
753 if (!filepath.empty()) {
754 // If classname is an absolute path, the document is
755 // using a local layout file which could not be accessed
756 // by a relative path. In this case the path is correct
757 // even if the document was moved to a different
758 // location. However, we will have a problem if the
759 // document was generated on a different platform.
760 bool isabsolute = FileName::isAbsolute(classname);
761 string const classpath = onlyPath(classname);
762 string const path = isabsolute ? classpath
763 : FileName(addPath(filepath.absFileName(),
764 classpath)).realPath();
765 string const oldpath = isabsolute ? string()
766 : FileName(addPath(origin, classpath)).realPath();
767 tcp = bcl.addLocalLayout(onlyFileName(classname), path, oldpath);
769 // that returns non-empty if a "local" layout file is found.
771 result = to_utf8(makeRelPath(from_utf8(onlyPath(tcp)),
772 from_utf8(filepath.absFileName())));
775 setBaseClass(onlyFileName(tcp));
777 setBaseClass(onlyFileName(classname));
778 // We assume that a tex class exists for local or unknown
779 // layouts so this warning, will only be given for system layouts.
780 if (!baseClass()->isTeXClassAvailable()) {
781 docstring const desc =
782 translateIfPossible(from_utf8(baseClass()->description()));
783 docstring const prereqs =
784 from_utf8(baseClass()->prerequisites());
785 docstring const msg =
786 bformat(_("The selected document class\n"
788 "requires external files that are not available.\n"
789 "The document class can still be used, but the\n"
790 "document cannot be compiled until the following\n"
791 "prerequisites are installed:\n"
793 "See section 3.1.2.2 (Class Availability) of the\n"
794 "User's Guide for more information."), desc, prereqs);
795 frontend::Alert::warning(_("Document class not available"),
798 } else if (token == "\\save_transient_properties") {
799 lex >> save_transient_properties;
800 } else if (token == "\\origin") {
802 origin = lex.getString();
803 string const sysdirprefix = "/systemlyxdir/";
804 if (prefixIs(origin, sysdirprefix)) {
806 if (inSystemDir(filepath, docsys))
807 origin.replace(0, sysdirprefix.length() - 1, docsys);
809 origin.replace(0, sysdirprefix.length() - 1,
810 package().system_support().absFileName());
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 == "\\output_sync") {
1196 } else if (token == "\\output_sync_macro") {
1197 lex >> output_sync_macro;
1198 } else if (token == "\\use_refstyle") {
1199 lex >> use_refstyle;
1200 } else if (token == "\\use_minted") {
1202 } else if (token == "\\use_lineno") {
1204 } else if (token == "\\lineno_options") {
1206 lineno_opts = trim(lex.getString());
1208 lyxerr << "BufferParams::readToken(): Unknown token: " <<
1218 // Quote argument if it contains spaces
1219 string quoteIfNeeded(string const & str) {
1220 if (contains(str, ' '))
1221 return "\"" + str + "\"";
1227 void BufferParams::writeFile(ostream & os, Buffer const * buf) const
1229 // The top of the file is written by the buffer.
1230 // Prints out the buffer info into the .lyx file given by file
1232 os << "\\save_transient_properties "
1233 << convert<string>(save_transient_properties) << '\n';
1235 // the document directory (must end with a path separator)
1236 // realPath() is used to resolve symlinks, while addPath(..., "")
1237 // ensures a trailing path separator.
1239 string filepath = addPath(buf->fileName().onlyPath().realPath(), "");
1240 string const sysdir = inSystemDir(FileName(filepath), docsys) ? docsys
1241 : addPath(package().system_support().realPath(), "");
1242 string const relpath =
1243 to_utf8(makeRelPath(from_utf8(filepath), from_utf8(sysdir)));
1244 if (!prefixIs(relpath, "../") && !FileName::isAbsolute(relpath))
1245 filepath = addPath("/systemlyxdir", relpath);
1246 else if (!save_transient_properties || !lyxrc.save_origin)
1247 filepath = "unavailable";
1248 os << "\\origin " << quoteIfNeeded(filepath) << '\n';
1251 os << "\\textclass "
1252 << quoteIfNeeded(buf->includedFilePath(addName(buf->layoutPos(),
1253 baseClass()->name()), "layout"))
1256 // then the preamble
1257 if (!preamble.empty()) {
1258 // remove '\n' from the end of preamble
1259 docstring const tmppreamble = rtrim(preamble, "\n");
1260 os << "\\begin_preamble\n"
1261 << to_utf8(tmppreamble)
1262 << "\n\\end_preamble\n";
1266 if (!options.empty()) {
1267 os << "\\options " << options << '\n';
1270 // use the class options defined in the layout?
1271 os << "\\use_default_options "
1272 << convert<string>(use_default_options) << "\n";
1274 // the master document
1275 if (!master.empty()) {
1276 os << "\\master " << master << '\n';
1280 if (!removed_modules_.empty()) {
1281 os << "\\begin_removed_modules" << '\n';
1282 for (auto const & mod : removed_modules_)
1284 os << "\\end_removed_modules" << '\n';
1288 if (!layout_modules_.empty()) {
1289 os << "\\begin_modules" << '\n';
1290 for (auto const & mod : layout_modules_)
1292 os << "\\end_modules" << '\n';
1296 if (!included_children_.empty()) {
1297 os << "\\begin_includeonly" << '\n';
1298 for (auto const & c : included_children_)
1300 os << "\\end_includeonly" << '\n';
1303 switch (maintain_unincluded_children) {
1314 os << "\\maintain_unincluded_children " << muc << '\n';
1316 // local layout information
1317 docstring const local_layout = getLocalLayout(false);
1318 if (!local_layout.empty()) {
1319 // remove '\n' from the end
1320 docstring const tmplocal = rtrim(local_layout, "\n");
1321 os << "\\begin_local_layout\n"
1322 << to_utf8(tmplocal)
1323 << "\n\\end_local_layout\n";
1325 docstring const forced_local_layout = getLocalLayout(true);
1326 if (!forced_local_layout.empty()) {
1327 // remove '\n' from the end
1328 docstring const tmplocal = rtrim(forced_local_layout, "\n");
1329 os << "\\begin_forced_local_layout\n"
1330 << to_utf8(tmplocal)
1331 << "\n\\end_forced_local_layout\n";
1334 // then the text parameters
1335 if (language != ignore_language)
1336 os << "\\language " << language->lang() << '\n';
1337 os << "\\language_package " << lang_package
1338 << "\n\\inputencoding " << inputenc
1339 << "\n\\fontencoding " << fontenc
1340 << "\n\\font_roman \"" << fonts_roman[0]
1341 << "\" \"" << fonts_roman[1] << '"'
1342 << "\n\\font_sans \"" << fonts_sans[0]
1343 << "\" \"" << fonts_sans[1] << '"'
1344 << "\n\\font_typewriter \"" << fonts_typewriter[0]
1345 << "\" \"" << fonts_typewriter[1] << '"'
1346 << "\n\\font_math \"" << fonts_math[0]
1347 << "\" \"" << fonts_math[1] << '"'
1348 << "\n\\font_default_family " << fonts_default_family
1349 << "\n\\use_non_tex_fonts " << convert<string>(useNonTeXFonts)
1350 << "\n\\font_sc " << convert<string>(fonts_expert_sc)
1351 << "\n\\font_roman_osf " << convert<string>(fonts_roman_osf)
1352 << "\n\\font_sans_osf " << convert<string>(fonts_sans_osf)
1353 << "\n\\font_typewriter_osf " << convert<string>(fonts_typewriter_osf);
1354 if (!font_roman_opts.empty())
1355 os << "\n\\font_roman_opts \"" << font_roman_opts << "\"";
1356 os << "\n\\font_sf_scale " << fonts_sans_scale[0]
1357 << ' ' << fonts_sans_scale[1];
1358 if (!font_sans_opts.empty())
1359 os << "\n\\font_sans_opts \"" << font_sans_opts << "\"";
1360 os << "\n\\font_tt_scale " << fonts_typewriter_scale[0]
1361 << ' ' << fonts_typewriter_scale[1];
1362 if (!font_typewriter_opts.empty())
1363 os << "\n\\font_typewriter_opts \"" << font_typewriter_opts << "\"";
1365 if (!fonts_cjk.empty())
1366 os << "\\font_cjk " << fonts_cjk << '\n';
1367 os << "\\use_microtype " << convert<string>(use_microtype) << '\n';
1368 os << "\\use_dash_ligatures " << convert<string>(use_dash_ligatures) << '\n';
1369 os << "\\graphics " << graphics_driver << '\n';
1370 os << "\\default_output_format " << default_output_format << '\n';
1371 os << "\\output_sync " << output_sync << '\n';
1372 if (!output_sync_macro.empty())
1373 os << "\\output_sync_macro \"" << output_sync_macro << "\"\n";
1374 os << "\\bibtex_command " << bibtex_command << '\n';
1375 os << "\\index_command " << index_command << '\n';
1377 if (!float_placement.empty())
1378 os << "\\float_placement " << float_placement << '\n';
1379 if (!float_alignment.empty())
1380 os << "\\float_alignment " << float_alignment << '\n';
1381 os << "\\paperfontsize " << fontsize << '\n';
1383 spacing().writeFile(os);
1384 pdfoptions().writeFile(os);
1386 os << "\\papersize " << string_papersize[papersize]
1387 << "\n\\use_geometry " << convert<string>(use_geometry);
1388 map<string, string> const & packages = auto_packages();
1389 for (auto const & pack : packages)
1390 os << "\n\\use_package " << pack.first << ' '
1391 << use_package(pack.first);
1393 os << "\n\\cite_engine ";
1395 if (!cite_engine_.empty())
1400 os << "\n\\cite_engine_type " << theCiteEnginesList.getTypeAsString(cite_engine_type_);
1402 if (!biblio_style.empty())
1403 os << "\n\\biblio_style " << biblio_style;
1404 if (!biblio_opts.empty())
1405 os << "\n\\biblio_options " << biblio_opts;
1406 if (!biblatex_bibstyle.empty())
1407 os << "\n\\biblatex_bibstyle " << biblatex_bibstyle;
1408 if (!biblatex_citestyle.empty())
1409 os << "\n\\biblatex_citestyle " << biblatex_citestyle;
1410 if (!multibib.empty())
1411 os << "\n\\multibib " << multibib;
1413 os << "\n\\use_bibtopic " << convert<string>(use_bibtopic)
1414 << "\n\\use_indices " << convert<string>(use_indices)
1415 << "\n\\paperorientation " << string_orientation[orientation]
1416 << "\n\\suppress_date " << convert<string>(suppress_date)
1417 << "\n\\justification " << convert<string>(justification)
1418 << "\n\\use_refstyle " << use_refstyle
1419 << "\n\\use_minted " << use_minted
1420 << "\n\\use_lineno " << use_lineno
1423 if (!lineno_opts.empty())
1424 os << "\\lineno_options " << lineno_opts << '\n';
1426 if (isbackgroundcolor)
1427 os << "\\backgroundcolor " << lyx::X11hexname(backgroundcolor) << '\n';
1429 os << "\\fontcolor " << lyx::X11hexname(fontcolor) << '\n';
1430 if (isnotefontcolor)
1431 os << "\\notefontcolor " << lyx::X11hexname(notefontcolor) << '\n';
1433 os << "\\boxbgcolor " << lyx::X11hexname(boxbgcolor) << '\n';
1435 for (auto const & br : branchlist()) {
1436 os << "\\branch " << to_utf8(br.branch())
1437 << "\n\\selected " << br.isSelected()
1438 << "\n\\filename_suffix " << br.hasFileNameSuffix()
1439 << "\n\\color " << br.lightModeColor() << " " << br.darkModeColor()
1444 for (auto const & id : indiceslist()) {
1445 os << "\\index " << to_utf8(id.index())
1446 << "\n\\shortcut " << to_utf8(id.shortcut())
1447 << "\n\\color " << lyx::X11hexname(id.color())
1452 for (auto const & si : spellignore()) {
1453 os << "\\spellchecker_ignore " << si.lang()->lang()
1454 << " " << to_utf8(si.word())
1458 if (!paperwidth.empty())
1459 os << "\\paperwidth "
1460 << VSpace(paperwidth).asLyXCommand() << '\n';
1461 if (!paperheight.empty())
1462 os << "\\paperheight "
1463 << VSpace(paperheight).asLyXCommand() << '\n';
1464 if (!leftmargin.empty())
1465 os << "\\leftmargin "
1466 << VSpace(leftmargin).asLyXCommand() << '\n';
1467 if (!topmargin.empty())
1468 os << "\\topmargin "
1469 << VSpace(topmargin).asLyXCommand() << '\n';
1470 if (!rightmargin.empty())
1471 os << "\\rightmargin "
1472 << VSpace(rightmargin).asLyXCommand() << '\n';
1473 if (!bottommargin.empty())
1474 os << "\\bottommargin "
1475 << VSpace(bottommargin).asLyXCommand() << '\n';
1476 if (!headheight.empty())
1477 os << "\\headheight "
1478 << VSpace(headheight).asLyXCommand() << '\n';
1479 if (!headsep.empty())
1481 << VSpace(headsep).asLyXCommand() << '\n';
1482 if (!footskip.empty())
1484 << VSpace(footskip).asLyXCommand() << '\n';
1485 if (!columnsep.empty())
1486 os << "\\columnsep "
1487 << VSpace(columnsep).asLyXCommand() << '\n';
1488 os << "\\secnumdepth " << secnumdepth
1489 << "\n\\tocdepth " << tocdepth
1490 << "\n\\paragraph_separation "
1491 << string_paragraph_separation[paragraph_separation];
1492 if (!paragraph_separation)
1493 os << "\n\\paragraph_indentation "
1494 << (getParIndent().empty() ? "default" : getParIndent().asString());
1496 os << "\n\\defskip " << getDefSkip().asLyXCommand();
1497 os << "\n\\is_math_indent " << is_math_indent;
1499 os << "\n\\math_indentation "
1500 << (getMathIndent().empty() ? "default" : getMathIndent().asString());
1501 os << "\n\\math_numbering_side ";
1502 switch(math_numbering_side) {
1512 os << "\n\\quotes_style "
1513 << string_quotes_style[static_cast<int>(quotes_style)]
1514 << "\n\\dynamic_quotes " << dynamic_quotes
1515 << "\n\\papercolumns " << columns
1516 << "\n\\papersides " << sides
1517 << "\n\\paperpagestyle " << pagestyle
1518 << "\n\\tablestyle " << tablestyle << '\n';
1519 if (!listings_params.empty())
1520 os << "\\listings_params \"" <<
1521 InsetListingsParams(listings_params).encodedString() << "\"\n";
1522 for (int i = 0; i < 4; ++i) {
1523 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
1524 if (user_defined_bullet(i).getFont() != -1) {
1525 os << "\\bullet " << i << " "
1526 << user_defined_bullet(i).getFont() << " "
1527 << user_defined_bullet(i).getCharacter() << " "
1528 << user_defined_bullet(i).getSize() << "\n";
1532 os << "\\bulletLaTeX " << i << " \""
1533 << lyx::to_ascii(user_defined_bullet(i).getText())
1539 os << "\\tracking_changes "
1540 << (save_transient_properties ? convert<string>(track_changes) : "false")
1543 os << "\\output_changes "
1544 << (save_transient_properties ? convert<string>(output_changes) : "false")
1547 os << "\\change_bars "
1548 << (save_transient_properties ? convert<string>(change_bars) : "false")
1551 os << "\\postpone_fragile_content " << convert<string>(postpone_fragile_content) << '\n';
1553 os << "\\html_math_output " << html_math_output << '\n'
1554 << "\\html_css_as_file " << html_css_as_file << '\n'
1555 << "\\html_be_strict " << convert<string>(html_be_strict) << '\n';
1557 os << "\\docbook_table_output " << docbook_table_output << '\n';
1559 if (html_math_img_scale != 1.0)
1560 os << "\\html_math_img_scale " << convert<string>(html_math_img_scale) << '\n';
1561 if (!html_latex_start.empty())
1562 os << "\\html_latex_start " << html_latex_start << '\n';
1563 if (!html_latex_end.empty())
1564 os << "\\html_latex_end " << html_latex_end << '\n';
1566 os << pimpl_->authorlist;
1570 void BufferParams::validate(LaTeXFeatures & features) const
1572 features.require(documentClass().required());
1574 if (columns > 1 && language->rightToLeft())
1575 features.require("rtloutputdblcol");
1577 if (output_changes) {
1578 bool xcolorulem = LaTeXFeatures::isAvailable("ulem") &&
1579 LaTeXFeatures::isAvailable("xcolor");
1581 switch (features.runparams().flavor) {
1583 case Flavor::DviLuaTeX:
1585 features.require("ct-xcolor-ulem");
1586 features.require("ulem");
1587 features.require("xcolor");
1589 features.require("ct-none");
1592 case Flavor::LuaTeX:
1593 case Flavor::PdfLaTeX:
1596 features.require("ct-xcolor-ulem");
1597 features.require("ulem");
1598 features.require("xcolor");
1599 // improves color handling in PDF output
1600 features.require("pdfcolmk");
1602 features.require("ct-none");
1609 features.require("changebar");
1612 // Floats with 'Here definitely' as default setting.
1613 if (float_placement.find('H') != string::npos)
1614 features.require("float");
1616 for (auto const & pm : use_packages) {
1617 if (pm.first == "amsmath") {
1618 // AMS Style is at document level
1619 if (pm.second == package_on ||
1620 features.isProvided("amsmath"))
1621 features.require(pm.first);
1622 } else if (pm.second == package_on)
1623 features.require(pm.first);
1626 // Document-level line spacing
1627 if (spacing().getSpace() != Spacing::Single && !spacing().isDefault())
1628 features.require("setspace");
1630 // the bullet shapes are buffer level not paragraph level
1631 // so they are tested here
1632 for (int i = 0; i < 4; ++i) {
1633 if (user_defined_bullet(i) == ITEMIZE_DEFAULTS[i])
1635 int const font = user_defined_bullet(i).getFont();
1637 int const c = user_defined_bullet(i).getCharacter();
1643 features.require("latexsym");
1645 } else if (font == 1) {
1646 features.require("amssymb");
1647 } else if (font >= 2 && font <= 5) {
1648 features.require("pifont");
1652 if (pdfoptions().use_hyperref) {
1653 features.require("hyperref");
1654 // due to interferences with babel and hyperref, the color package has to
1655 // be loaded after hyperref when hyperref is used with the colorlinks
1656 // option, see http://www.lyx.org/trac/ticket/5291
1657 if (pdfoptions().colorlinks)
1658 features.require("color");
1660 if (!listings_params.empty()) {
1661 // do not test validity because listings_params is
1662 // supposed to be valid
1664 InsetListingsParams(listings_params).separatedParams(true);
1665 // we can't support all packages, but we should load the color package
1666 if (par.find("\\color", 0) != string::npos)
1667 features.require("color");
1670 // some languages are only available via polyglossia
1671 if (features.hasPolyglossiaExclusiveLanguages())
1672 features.require("polyglossia");
1674 if (useNonTeXFonts && fontsMath() != "auto")
1675 features.require("unicode-math");
1678 features.require("microtype");
1680 if (!language->required().empty())
1681 features.require(language->required());
1685 bool BufferParams::writeLaTeX(otexstream & os, LaTeXFeatures & features,
1686 FileName const & filepath) const
1688 // http://www.tug.org/texmf-dist/doc/latex/base/fixltx2e.pdf
1689 // !! To use the Fix-cm package, load it before \documentclass, and use the command
1690 // \RequirePackage to do so, rather than the normal \usepackage
1691 // Do not try to load any other package before the document class, unless you
1692 // have a thorough understanding of the LATEX internals and know exactly what you
1694 if (features.mustProvide("fix-cm"))
1695 os << "\\RequirePackage{fix-cm}\n";
1696 // Likewise for fixltx2e. If other packages conflict with this policy,
1697 // treat it as a package bug (and report it!)
1698 // See http://www.latex-project.org/cgi-bin/ltxbugs2html?pr=latex/4407
1699 if (features.mustProvide("fixltx2e"))
1700 os << "\\RequirePackage{fixltx2e}\n";
1702 os << "\\documentclass";
1704 DocumentClass const & tclass = documentClass();
1706 ostringstream clsoptions; // the document class options.
1708 if (tokenPos(tclass.opt_fontsize(),
1709 '|', fontsize) >= 0) {
1710 // only write if existing in list (and not default)
1711 clsoptions << subst(tclass.fontsizeformat(), "$$s", fontsize) << ",";
1714 // paper sizes not supported by the class itself need the
1716 vector<string> classpsizes = getVectorFromString(tclass.opt_pagesize(), "|");
1717 bool class_supported_papersize = papersize == PAPER_DEFAULT
1718 || find(classpsizes.begin(), classpsizes.end(), string_papersize[papersize]) != classpsizes.end();
1720 if ((!use_geometry || features.isProvided("geometry-light"))
1721 && class_supported_papersize && papersize != PAPER_DEFAULT)
1722 clsoptions << subst(tclass.pagesizeformat(), "$$s", string_papersize[papersize]) << ",";
1725 if (sides != tclass.sides()) {
1728 clsoptions << "oneside,";
1731 clsoptions << "twoside,";
1737 if (columns != tclass.columns()) {
1739 clsoptions << "twocolumn,";
1741 clsoptions << "onecolumn,";
1745 && orientation == ORIENTATION_LANDSCAPE)
1746 clsoptions << "landscape,";
1749 clsoptions << "fleqn,";
1751 switch(math_numbering_side) {
1753 clsoptions << "leqno,";
1756 clsoptions << "reqno,";
1757 features.require("amsmath");
1763 // language should be a parameter to \documentclass
1764 if (language->babel() == "hebrew"
1765 && default_language->babel() != "hebrew")
1766 // This seems necessary
1767 features.useLanguage(default_language);
1769 ostringstream language_options;
1770 bool const use_babel = features.useBabel() && !features.isProvided("babel");
1771 bool const use_polyglossia = features.usePolyglossia();
1772 bool const global = lyxrc.language_global_options;
1773 if (features.useBabel() || (use_polyglossia && global)) {
1774 language_options << features.getBabelLanguages();
1775 if (!language->babel().empty()) {
1776 if (!language_options.str().empty())
1777 language_options << ',';
1778 language_options << language->babel();
1780 if (global && !language_options.str().empty())
1781 clsoptions << language_options.str() << ',';
1784 // the predefined options from the layout
1785 if (use_default_options && !tclass.options().empty())
1786 clsoptions << tclass.options() << ',';
1788 // the user-defined options
1789 if (!options.empty()) {
1790 clsoptions << options << ',';
1793 docstring const strOptions = from_utf8(clsoptions.str());
1794 if (!strOptions.empty()) {
1795 // Check if class options contain uncodable glyphs
1796 docstring uncodable_glyphs;
1797 docstring options_encodable;
1798 Encoding const * const enc = features.runparams().encoding;
1800 for (char_type c : strOptions) {
1801 if (!enc->encodable(c)) {
1802 docstring const glyph(1, c);
1803 LYXERR0("Uncodable character '"
1805 << "' in class options!");
1806 uncodable_glyphs += glyph;
1807 if (features.runparams().dryrun) {
1808 options_encodable += "<" + _("LyX Warning: ")
1809 + _("uncodable character") + " '";
1810 options_encodable += c;
1811 options_encodable += "'>";
1814 options_encodable += c;
1817 options_encodable = strOptions;
1819 // On BUFFER_VIEW|UPDATE, warn user if we found uncodable glyphs
1820 if (!features.runparams().dryrun && !uncodable_glyphs.empty()) {
1821 frontend::Alert::warning(
1822 _("Uncodable character in class options"),
1824 _("The class options of your document contain glyphs "
1825 "that are unknown in the current document encoding "
1826 "(namely %1$s).\nThese glyphs are omitted "
1827 " from the output, which may result in "
1828 "incomplete output."
1829 "\n\nPlease select an appropriate "
1830 "document encoding\n"
1831 "(such as utf8) or change the "
1832 "class options accordingly."),
1835 options_encodable = rtrim(options_encodable, ",");
1836 os << '[' << options_encodable << ']';
1839 os << '{' << from_ascii(tclass.latexname()) << "}\n";
1840 // end of \documentclass defs
1842 // The package options (via \PassOptionsToPackage)
1843 os << from_ascii(features.getPackageOptions());
1845 // if we use fontspec or newtxmath, we have to load the AMS packages here
1846 string const ams = features.loadAMSPackages();
1847 bool const ot1 = (main_font_encoding() == "default" || main_font_encoding() == "OT1");
1848 bool const use_newtxmath =
1849 theLaTeXFonts().getLaTeXFont(from_ascii(fontsMath())).getUsedPackage(
1850 ot1, false, false) == "newtxmath";
1851 if ((useNonTeXFonts || use_newtxmath) && !ams.empty())
1852 os << from_ascii(ams);
1854 if (useNonTeXFonts) {
1855 // Babel (as of 2017/11/03) loads fontspec itself
1856 if (!features.isProvided("fontspec")
1857 && !(features.useBabel() && features.isAvailable("babel-2017/11/03")))
1858 os << "\\usepackage{fontspec}\n";
1859 if (features.mustProvide("unicode-math")
1860 && features.isAvailable("unicode-math"))
1861 os << "\\usepackage{unicode-math}\n";
1864 // load CJK support package before font selection
1865 // (see autotests/export/latex/CJK/micro-sign_utf8-cjk-libertine.lyx)
1866 if (!useNonTeXFonts && encoding().package() != Encoding::none && inputenc != "utf8x"
1867 && (encoding().package() == Encoding::CJK || features.mustProvide("CJK"))) {
1868 if (inputenc == "utf8-cjk" || inputenc == "utf8")
1869 os << "\\usepackage{CJKutf8}\n";
1871 os << "\\usepackage[encapsulated]{CJK}\n";
1874 // font selection must be done before loading fontenc.sty
1875 // but after babel with non-TeX fonts
1876 string const fonts = loadFonts(features);
1877 if (!fonts.empty() && (!features.useBabel() || !useNonTeXFonts))
1878 os << from_utf8(fonts);
1880 if (fonts_default_family != "default")
1881 os << "\\renewcommand{\\familydefault}{\\"
1882 << from_ascii(fonts_default_family) << "}\n";
1884 // set font encoding
1885 // non-TeX fonts use font encoding TU (set by fontspec)
1886 if (!useNonTeXFonts && !features.isProvided("fontenc")
1887 && main_font_encoding() != "default") {
1888 // get main font encodings
1889 vector<string> fontencs = font_encodings();
1890 // get font encodings of secondary languages
1891 // FIXME: some languages (hebrew, ...) assume a standard font encoding as last
1892 // option (for text in other languages).
1893 features.getFontEncodings(fontencs);
1894 if (!fontencs.empty()) {
1895 os << "\\usepackage["
1896 << from_ascii(getStringFromVector(fontencs))
1901 // Load textcomp and pmboxdraw before (lua)inputenc (#11454)
1902 if (features.mustProvide("textcomp"))
1903 os << "\\usepackage{textcomp}\n";
1904 if (features.mustProvide("pmboxdraw"))
1905 os << "\\usepackage{pmboxdraw}\n";
1907 // handle inputenc etc.
1908 // (In documents containing text in Thai language,
1909 // we must load inputenc after babel, see lib/languages).
1910 if (!contains(features.getBabelPostsettings(), from_ascii("thai.ldf")))
1911 writeEncodingPreamble(os, features);
1914 if (!features.runparams().includeall && !included_children_.empty()) {
1915 os << "\\includeonly{";
1917 for (auto incfile : included_children_) {
1918 FileName inc = makeAbsPath(incfile, filepath.absFileName());
1919 string mangled = DocFileName(changeExtension(inc.absFileName(), ".tex")).
1921 if (!features.runparams().nice)
1923 // \includeonly doesn't want an extension
1924 incfile = changeExtension(incfile, string());
1925 incfile = support::latex_path(incfile);
1926 if (!incfile.empty()) {
1929 os << from_utf8(incfile);
1936 if (!features.isProvided("geometry")
1937 && (use_geometry || !class_supported_papersize)) {
1938 odocstringstream ods;
1939 if (!getGraphicsDriver("geometry").empty())
1940 ods << getGraphicsDriver("geometry");
1941 if (orientation == ORIENTATION_LANDSCAPE)
1942 ods << ",landscape";
1943 switch (papersize) {
1945 if (!paperwidth.empty())
1946 ods << ",paperwidth="
1947 << from_ascii(paperwidth);
1948 if (!paperheight.empty())
1949 ods << ",paperheight="
1950 << from_ascii(paperheight);
1952 case PAPER_USLETTER:
1954 case PAPER_USEXECUTIVE:
1983 ods << "," << from_ascii(string_papersize_geometry[papersize]);
1988 docstring g_options = trim(ods.str(), ",");
1989 os << "\\usepackage";
1990 // geometry-light means that the class works with geometry, but overwrites
1991 // the package options and paper sizes (memoir does this).
1992 // In this case, all options need to go to \geometry
1993 // and the standard paper sizes need to go to the class options.
1994 if (!g_options.empty() && !features.isProvided("geometry-light")) {
1995 os << '[' << g_options << ']';
1998 os << "{geometry}\n";
1999 if (use_geometry || features.isProvided("geometry-light")) {
2000 os << "\\geometry{verbose";
2001 if (!g_options.empty())
2002 // Output general options here with "geometry light".
2003 os << "," << g_options;
2004 // output this only if use_geometry is true
2006 if (!topmargin.empty())
2007 os << ",tmargin=" << from_ascii(Length(topmargin).asLatexString());
2008 if (!bottommargin.empty())
2009 os << ",bmargin=" << from_ascii(Length(bottommargin).asLatexString());
2010 if (!leftmargin.empty())
2011 os << ",lmargin=" << from_ascii(Length(leftmargin).asLatexString());
2012 if (!rightmargin.empty())
2013 os << ",rmargin=" << from_ascii(Length(rightmargin).asLatexString());
2014 if (!headheight.empty())
2015 os << ",headheight=" << from_ascii(Length(headheight).asLatexString());
2016 if (!headsep.empty())
2017 os << ",headsep=" << from_ascii(Length(headsep).asLatexString());
2018 if (!footskip.empty())
2019 os << ",footskip=" << from_ascii(Length(footskip).asLatexString());
2020 if (!columnsep.empty())
2021 os << ",columnsep=" << from_ascii(Length(columnsep).asLatexString());
2025 } else if (orientation == ORIENTATION_LANDSCAPE
2026 || papersize != PAPER_DEFAULT) {
2027 features.require("papersize");
2030 if (tokenPos(tclass.opt_pagestyle(), '|', pagestyle) >= 0) {
2031 if (pagestyle == "fancy")
2032 os << "\\usepackage{fancyhdr}\n";
2033 os << "\\pagestyle{" << from_ascii(pagestyle) << "}\n";
2036 // only output when the background color is not default
2037 if (isbackgroundcolor) {
2038 // only require color here, the background color will be defined
2039 // in LaTeXFeatures.cpp to avoid interferences with the LaTeX
2041 features.require("color");
2042 features.require("pagecolor");
2045 // only output when the font color is not default
2047 // only require color here, the font color will be defined
2048 // in LaTeXFeatures.cpp to avoid interferences with the LaTeX
2050 features.require("color");
2051 features.require("fontcolor");
2054 // Only if class has a ToC hierarchy
2055 if (tclass.hasTocLevels()) {
2056 if (secnumdepth != tclass.secnumdepth()) {
2057 os << "\\setcounter{secnumdepth}{"
2061 if (tocdepth != tclass.tocdepth()) {
2062 os << "\\setcounter{tocdepth}{"
2068 if (paragraph_separation) {
2069 // when skip separation
2071 switch (getDefSkip().kind()) {
2072 case VSpace::SMALLSKIP:
2073 psopt = "\\smallskipamount";
2075 case VSpace::MEDSKIP:
2076 psopt = "\\medskipamount";
2078 case VSpace::BIGSKIP:
2079 psopt = "\\bigskipamount";
2081 case VSpace::HALFLINE:
2082 // default (no option)
2084 case VSpace::FULLLINE:
2085 psopt = "\\baselineskip";
2087 case VSpace::LENGTH:
2088 psopt = getDefSkip().length().asLatexString();
2093 if (!features.isProvided("parskip")) {
2095 psopt = "[skip=" + psopt + "]";
2096 os << "\\usepackage" + psopt + "{parskip}\n";
2098 os << "\\setlength{\\parskip}{" + psopt + "}\n";
2101 // when separation by indentation
2102 // only output something when a width is given
2103 if (!getParIndent().empty()) {
2104 os << "\\setlength{\\parindent}{"
2105 << from_utf8(getParIndent().asLatexString())
2110 if (is_math_indent) {
2111 // when formula indentation
2112 // only output something when it is not the default
2113 if (!getMathIndent().empty()) {
2114 os << "\\setlength{\\mathindent}{"
2115 << from_utf8(getMathIndent().asString())
2120 // Now insert the LyX specific LaTeX commands...
2121 features.resolveAlternatives();
2122 features.expandMultiples();
2125 if (!output_sync_macro.empty())
2126 os << from_utf8(output_sync_macro) +"\n";
2127 else if (features.runparams().flavor == Flavor::LaTeX)
2128 os << "\\usepackage[active]{srcltx}\n";
2129 else if (features.runparams().flavor == Flavor::PdfLaTeX)
2130 os << "\\synctex=-1\n";
2133 // due to interferences with babel and hyperref, the color package has to
2134 // be loaded (when it is not already loaded) before babel when hyperref
2135 // is used with the colorlinks option, see
2136 // http://www.lyx.org/trac/ticket/5291
2137 // we decided therefore to load color always before babel, see
2138 // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg144349.html
2139 os << from_ascii(features.getColorOptions());
2141 // If we use hyperref, jurabib, japanese or varioref,
2142 // we have to call babel before
2144 && (features.isRequired("jurabib")
2145 || features.isRequired("hyperref")
2146 || features.isRequired("varioref")
2147 || features.isRequired("japanese"))) {
2148 os << features.getBabelPresettings();
2150 os << from_utf8(babelCall(language_options.str(),
2151 !lyxrc.language_global_options)) + '\n';
2152 os << features.getBabelPostsettings();
2155 // The optional packages;
2156 os << from_ascii(features.getPackages());
2158 // Additional Indices
2159 if (features.isRequired("splitidx")) {
2160 for (auto const & idx : indiceslist()) {
2161 os << "\\newindex{";
2162 os << escape(idx.shortcut());
2168 os << from_utf8(spacing().writePreamble(features.isProvided("SetSpace")));
2171 // * Hyperref manual: "Make sure it comes last of your loaded
2172 // packages, to give it a fighting chance of not being over-written,
2173 // since its job is to redefine many LaTeX commands."
2174 // * Email from Heiko Oberdiek: "It is usually better to load babel
2175 // before hyperref. Then hyperref has a chance to detect babel.
2176 // * Has to be loaded before the "LyX specific LaTeX commands" to
2177 // avoid errors with algorithm floats.
2178 // use hyperref explicitly if it is required
2179 if (features.isRequired("hyperref")) {
2180 OutputParams tmp_params = features.runparams();
2181 pdfoptions().writeLaTeX(tmp_params, os,
2182 features.isProvided("hyperref"));
2183 // correctly break URLs with hyperref and dvi/ps output
2184 if (features.runparams().hyperref_driver == "dvips"
2185 && features.isAvailable("breakurl"))
2186 os << "\\usepackage{breakurl}\n";
2187 } else if (features.isRequired("nameref"))
2188 // hyperref loads this automatically
2189 os << "\\usepackage{nameref}\n";
2192 os << "\\usepackage";
2193 if (!lineno_opts.empty())
2194 os << "[" << lineno_opts << "]";
2196 os << "\\linenumbers\n";
2199 // bibtopic needs to be loaded after hyperref.
2200 // the dot provides the aux file naming which LyX can detect.
2201 if (features.mustProvide("bibtopic"))
2202 os << "\\usepackage[dot]{bibtopic}\n";
2204 // Will be surrounded by \makeatletter and \makeatother when not empty
2205 otexstringstream atlyxpreamble;
2207 // Some macros LyX will need
2209 TexString tmppreamble = features.getMacros();
2210 if (!tmppreamble.str.empty())
2211 atlyxpreamble << "\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
2212 "LyX specific LaTeX commands.\n"
2213 << move(tmppreamble)
2216 // the text class specific preamble
2218 docstring tmppreamble = features.getTClassPreamble();
2219 if (!tmppreamble.empty())
2220 atlyxpreamble << "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
2221 "Textclass specific LaTeX commands.\n"
2225 // suppress date if selected
2226 // use \@ifundefined because we cannot be sure that every document class
2227 // has a \date command
2229 atlyxpreamble << "\\@ifundefined{date}{}{\\date{}}\n";
2231 /* the user-defined preamble */
2232 if (!containsOnly(preamble, " \n\t")) {
2234 atlyxpreamble << "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
2235 "User specified LaTeX commands.\n";
2237 // Check if the user preamble contains uncodable glyphs
2238 odocstringstream user_preamble;
2239 docstring uncodable_glyphs;
2240 Encoding const * const enc = features.runparams().encoding;
2242 for (char_type c : preamble) {
2243 if (!enc->encodable(c)) {
2244 docstring const glyph(1, c);
2245 LYXERR0("Uncodable character '"
2247 << "' in user preamble!");
2248 uncodable_glyphs += glyph;
2249 if (features.runparams().dryrun) {
2250 user_preamble << "<" << _("LyX Warning: ")
2251 << _("uncodable character") << " '";
2252 user_preamble.put(c);
2253 user_preamble << "'>";
2256 user_preamble.put(c);
2259 user_preamble << preamble;
2261 // On BUFFER_VIEW|UPDATE, warn user if we found uncodable glyphs
2262 if (!features.runparams().dryrun && !uncodable_glyphs.empty()) {
2263 frontend::Alert::warning(
2264 _("Uncodable character in user preamble"),
2266 _("The user preamble of your document contains glyphs "
2267 "that are unknown in the current document encoding "
2268 "(namely %1$s).\nThese glyphs are omitted "
2269 " from the output, which may result in "
2270 "incomplete output."
2271 "\n\nPlease select an appropriate "
2272 "document encoding\n"
2273 "(such as utf8) or change the "
2274 "preamble code accordingly."),
2277 atlyxpreamble << user_preamble.str() << '\n';
2280 // footmisc must be loaded after setspace
2281 // Load it here to avoid clashes with footmisc loaded in the user
2282 // preamble. For that reason we also pass the options via
2283 // \PassOptionsToPackage in getPreamble() and not here.
2284 if (features.mustProvide("footmisc"))
2285 atlyxpreamble << "\\usepackage{footmisc}\n";
2287 // subfig loads internally the LaTeX package "caption". As
2288 // caption is a very popular package, users will load it in
2289 // the preamble. Therefore we must load subfig behind the
2290 // user-defined preamble and check if the caption package was
2291 // loaded or not. For the case that caption is loaded before
2292 // subfig, there is the subfig option "caption=false". This
2293 // option also works when a koma-script class is used and
2294 // koma's own caption commands are used instead of caption. We
2295 // use \PassOptionsToPackage here because the user could have
2296 // already loaded subfig in the preamble.
2297 if (features.mustProvide("subfig"))
2298 atlyxpreamble << "\\ifdefined\\showcaptionsetup\n"
2299 " % Caption package is used. Advise subfig not to load it again.\n"
2300 " \\PassOptionsToPackage{caption=false}{subfig}\n"
2302 "\\usepackage{subfig}\n";
2304 // Itemize bullet settings need to be last in case the user
2305 // defines their own bullets that use a package included
2306 // in the user-defined preamble -- ARRae
2307 // Actually it has to be done much later than that
2308 // since some packages like frenchb make modifications
2309 // at \begin{document} time -- JMarc
2310 docstring bullets_def;
2311 for (int i = 0; i < 4; ++i) {
2312 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
2313 if (bullets_def.empty())
2314 bullets_def += "\\AtBeginDocument{\n";
2315 bullets_def += " \\def\\labelitemi";
2317 // `i' is one less than the item to modify
2324 bullets_def += "ii";
2330 bullets_def += '{' +
2331 user_defined_bullet(i).getText()
2336 if (!bullets_def.empty())
2337 atlyxpreamble << bullets_def << "}\n\n";
2339 if (!atlyxpreamble.empty())
2340 os << "\n\\makeatletter\n"
2341 << atlyxpreamble.release()
2342 << "\\makeatother\n\n";
2344 // We try to load babel late, in case it interferes with other packages.
2345 // Jurabib, hyperref, varioref, bicaption, menukeys and listings (bug 8995)
2346 // have to be called after babel, though.
2347 if (use_babel && !features.isRequired("jurabib")
2348 && !features.isRequired("hyperref")
2349 && !features.isRequired("varioref")
2350 && !features.isRequired("japanese")) {
2351 os << features.getBabelPresettings();
2353 os << from_utf8(babelCall(language_options.str(),
2354 !lyxrc.language_global_options)) + '\n';
2355 os << features.getBabelPostsettings();
2357 // In documents containing text in Thai language,
2358 // we must load inputenc after babel (see lib/languages).
2359 if (contains(features.getBabelPostsettings(), from_ascii("thai.ldf")))
2360 writeEncodingPreamble(os, features);
2362 // font selection must be done after babel with non-TeX fonts
2363 if (!fonts.empty() && features.useBabel() && useNonTeXFonts)
2364 os << from_utf8(fonts);
2366 if (features.isRequired("bicaption"))
2367 os << "\\usepackage{bicaption}\n";
2368 if (!listings_params.empty()
2369 || features.mustProvide("listings")
2370 || features.mustProvide("minted")) {
2372 os << "\\usepackage{minted}\n";
2374 os << "\\usepackage{listings}\n";
2376 string lst_params = listings_params;
2377 // If minted, do not output the language option (bug 11203)
2378 if (use_minted && contains(lst_params, "language=")) {
2379 vector<string> opts =
2380 getVectorFromString(lst_params, ",", false);
2381 for (size_t i = 0; i < opts.size(); ++i) {
2382 if (prefixIs(opts[i], "language="))
2383 opts.erase(opts.begin() + i--);
2385 lst_params = getStringFromVector(opts, ",");
2387 if (!lst_params.empty()) {
2389 os << "\\setminted{";
2392 // do not test validity because listings_params is
2393 // supposed to be valid
2395 InsetListingsParams(lst_params).separatedParams(true);
2396 os << from_utf8(par);
2400 // xunicode only needs to be loaded if tipa is used
2401 // (the rest is obsoleted by the new TU encoding).
2402 // It needs to be loaded at least after amsmath, amssymb,
2403 // esint and the other packages that provide special glyphs
2404 if (features.mustProvide("tipa") && useNonTeXFonts
2405 && !features.isProvided("xunicode")) {
2406 // The `xunicode` package officially only supports XeTeX,
2407 // but also works with LuaTeX. We work around its XeTeX test.
2408 if (features.runparams().flavor != Flavor::XeTeX) {
2409 os << "% Pretend to xunicode that we are XeTeX\n"
2410 << "\\def\\XeTeXpicfile{}\n";
2412 os << "\\usepackage{xunicode}\n";
2415 // covington must be loaded after beamerarticle
2416 if (features.isRequired("covington"))
2417 os << "\\usepackage{covington}\n";
2419 // Polyglossia must be loaded last ...
2420 if (use_polyglossia) {
2422 os << "\\usepackage{polyglossia}\n";
2423 // set the main language
2424 os << "\\setdefaultlanguage";
2425 if (!language->polyglossiaOpts().empty())
2426 os << "[" << from_ascii(language->polyglossiaOpts()) << "]";
2427 os << "{" << from_ascii(language->polyglossia()) << "}\n";
2428 // now setup the other languages
2429 set<string> const polylangs =
2430 features.getPolyglossiaLanguages();
2431 for (auto const & pl : polylangs) {
2432 // We do not output the options here; they are output in
2433 // the language switch commands. This is safer if multiple
2434 // varieties are used.
2435 if (pl == language->polyglossia())
2437 os << "\\setotherlanguage";
2438 os << "{" << from_ascii(pl) << "}\n";
2442 // ... but before biblatex (see #7065)
2443 if ((features.mustProvide("biblatex")
2444 || features.isRequired("biblatex-chicago"))
2445 && !features.isProvided("biblatex-chicago")
2446 && !features.isProvided("biblatex-natbib")
2447 && !features.isProvided("natbib-internal")
2448 && !features.isProvided("natbib")
2449 && !features.isProvided("jurabib")) {
2450 // The biblatex-chicago package has a differing interface
2451 // it uses a wrapper package and loads styles via fixed options
2452 bool const chicago = features.isRequired("biblatex-chicago");
2455 os << "\\usepackage";
2456 if (!biblatex_bibstyle.empty()
2457 && (biblatex_bibstyle == biblatex_citestyle)
2459 opts = "style=" + biblatex_bibstyle;
2461 } else if (!chicago) {
2462 if (!biblatex_bibstyle.empty()) {
2463 opts = "bibstyle=" + biblatex_bibstyle;
2466 if (!biblatex_citestyle.empty()) {
2467 opts += delim + "citestyle=" + biblatex_citestyle;
2471 if (!multibib.empty() && multibib != "child") {
2472 opts += delim + "refsection=" + multibib;
2475 if (bibtexCommand() == "bibtex8"
2476 || prefixIs(bibtexCommand(), "bibtex8 ")) {
2477 opts += delim + "backend=bibtex8";
2479 } else if (bibtexCommand() == "bibtex"
2480 || prefixIs(bibtexCommand(), "bibtex ")) {
2481 opts += delim + "backend=bibtex";
2484 if (!bib_encoding.empty() && encodings.fromLyXName(bib_encoding)) {
2485 opts += delim + "bibencoding="
2486 + encodings.fromLyXName(bib_encoding)->latexName();
2489 if (!biblio_opts.empty())
2490 opts += delim + biblio_opts;
2492 os << "[" << opts << "]";
2494 os << "{biblatex-chicago}\n";
2496 os << "{biblatex}\n";
2500 // Load custom language package here
2501 if (features.langPackage() == LaTeXFeatures::LANG_PACK_CUSTOM) {
2502 if (lang_package == "default")
2503 os << from_utf8(lyxrc.language_custom_package);
2505 os << from_utf8(lang_package);
2509 // Since menukeys uses catoptions, which does some heavy changes on key-value options,
2510 // it is recommended to load menukeys as the last package (even after hyperref)
2511 if (features.isRequired("menukeys"))
2512 os << "\\usepackage{menukeys}\n";
2514 docstring const i18npreamble =
2515 features.getTClassI18nPreamble(use_babel, use_polyglossia,
2517 if (!i18npreamble.empty())
2518 os << i18npreamble + '\n';
2524 void BufferParams::useClassDefaults()
2526 DocumentClass const & tclass = documentClass();
2528 sides = tclass.sides();
2529 columns = tclass.columns();
2530 pagestyle = tclass.pagestyle();
2531 tablestyle = tclass.tablestyle();
2532 use_default_options = true;
2533 // Only if class has a ToC hierarchy
2534 if (tclass.hasTocLevels()) {
2535 secnumdepth = tclass.secnumdepth();
2536 tocdepth = tclass.tocdepth();
2541 bool BufferParams::hasClassDefaults() const
2543 DocumentClass const & tclass = documentClass();
2545 return sides == tclass.sides()
2546 && columns == tclass.columns()
2547 && pagestyle == tclass.pagestyle()
2548 && tablestyle == tclass.tablestyle()
2549 && use_default_options
2550 && secnumdepth == tclass.secnumdepth()
2551 && tocdepth == tclass.tocdepth();
2555 DocumentClass const & BufferParams::documentClass() const
2561 DocumentClassConstPtr BufferParams::documentClassPtr() const
2567 void BufferParams::setDocumentClass(DocumentClassConstPtr tc)
2569 // evil, but this function is evil
2570 doc_class_ = const_pointer_cast<DocumentClass>(tc);
2571 invalidateConverterCache();
2575 bool BufferParams::setBaseClass(string const & classname, string const & path)
2577 LYXERR(Debug::TCLASS, "setBaseClass: " << classname);
2578 LayoutFileList & bcl = LayoutFileList::get();
2579 if (!bcl.haveClass(classname)) {
2581 bformat(_("The layout file:\n"
2583 "could not be found. A default textclass with default\n"
2584 "layouts will be used. LyX will not be able to produce\n"
2586 from_utf8(classname));
2587 frontend::Alert::error(_("Document class not found"), s);
2588 bcl.addEmptyClass(classname);
2591 bool const success = bcl[classname].load(path);
2594 bformat(_("Due to some error in it, the layout file:\n"
2596 "could not be loaded. A default textclass with default\n"
2597 "layouts will be used. LyX will not be able to produce\n"
2599 from_utf8(classname));
2600 frontend::Alert::error(_("Could not load class"), s);
2601 bcl.addEmptyClass(classname);
2604 pimpl_->baseClass_ = classname;
2605 layout_modules_.adaptToBaseClass(baseClass(), removed_modules_);
2610 LayoutFile const * BufferParams::baseClass() const
2612 if (LayoutFileList::get().haveClass(pimpl_->baseClass_))
2613 return &(LayoutFileList::get()[pimpl_->baseClass_]);
2619 LayoutFileIndex const & BufferParams::baseClassID() const
2621 return pimpl_->baseClass_;
2625 void BufferParams::makeDocumentClass(bool clone, bool internal)
2630 invalidateConverterCache();
2631 LayoutModuleList mods;
2632 for (auto const & mod : layout_modules_)
2633 mods.push_back(mod);
2635 doc_class_ = getDocumentClass(*baseClass(), mods, cite_engine_, clone, internal);
2637 TextClass::ReturnValues success = TextClass::OK;
2638 if (!forced_local_layout_.empty())
2639 success = doc_class_->read(to_utf8(forced_local_layout_),
2641 if (!local_layout_.empty() &&
2642 (success == TextClass::OK || success == TextClass::OK_OLDFORMAT))
2643 success = doc_class_->read(to_utf8(local_layout_), TextClass::MODULE);
2644 if (success != TextClass::OK && success != TextClass::OK_OLDFORMAT) {
2645 docstring const msg = _("Error reading internal layout information");
2646 frontend::Alert::warning(_("Read Error"), msg);
2651 bool BufferParams::layoutModuleCanBeAdded(string const & modName) const
2653 return layout_modules_.moduleCanBeAdded(modName, baseClass());
2657 docstring BufferParams::getLocalLayout(bool forced) const
2660 return from_utf8(doc_class_->forcedLayouts());
2662 return local_layout_;
2666 void BufferParams::setLocalLayout(docstring const & layout, bool forced)
2669 forced_local_layout_ = layout;
2671 local_layout_ = layout;
2675 bool BufferParams::addLayoutModule(string const & modName)
2677 for (auto const & mod : layout_modules_)
2680 layout_modules_.push_back(modName);
2685 string BufferParams::bufferFormat() const
2687 return documentClass().outputFormat();
2691 bool BufferParams::isExportable(string const & format, bool need_viewable) const
2693 FormatList const & formats = exportableFormats(need_viewable);
2694 for (auto const & fmt : formats) {
2695 if (fmt->name() == format)
2702 FormatList const & BufferParams::exportableFormats(bool only_viewable) const
2704 FormatList & cached = only_viewable ?
2705 pimpl_->viewableFormatList : pimpl_->exportableFormatList;
2706 bool & valid = only_viewable ?
2707 pimpl_->isViewCacheValid : pimpl_->isExportCacheValid;
2711 vector<string> const backs = backends();
2712 set<string> excludes;
2713 if (useNonTeXFonts) {
2714 excludes.insert("latex");
2715 excludes.insert("pdflatex");
2716 } else if (inputenc != "ascii" && inputenc != "utf8-plain") {
2717 // XeTeX with TeX fonts requires input encoding ascii (#10600).
2718 excludes.insert("xetex");
2722 theConverters().getReachable(backs[0], only_viewable, true, excludes);
2723 vector<string>::const_iterator it = backs.begin() + 1;
2724 for (; it != backs.end(); ++it) {
2725 FormatList r = theConverters().getReachable(*it, only_viewable,
2727 result.insert(result.end(), r.begin(), r.end());
2729 sort(result.begin(), result.end(), Format::formatSorter);
2736 vector<string> BufferParams::backends() const
2739 string const buffmt = bufferFormat();
2741 // FIXME: Don't hardcode format names here, but use a flag
2742 if (buffmt == "latex") {
2743 if (encoding().package() == Encoding::japanese)
2744 v.push_back("platex");
2746 if (!useNonTeXFonts) {
2747 v.push_back("pdflatex");
2748 v.push_back("latex");
2751 || inputenc == "ascii" || inputenc == "utf8-plain")
2752 v.push_back("xetex");
2753 v.push_back("luatex");
2754 v.push_back("dviluatex");
2757 string rbuffmt = buffmt;
2758 // If we use an OutputFormat in Japanese docs,
2759 // we need special format in order to get the path
2760 // via pLaTeX (#8823)
2761 if (documentClass().hasOutputFormat()
2762 && encoding().package() == Encoding::japanese)
2764 v.push_back(rbuffmt);
2767 v.push_back("xhtml");
2768 v.push_back("docbook5");
2769 v.push_back("text");
2775 Flavor BufferParams::getOutputFlavor(string const & format) const
2777 string const dformat = (format.empty() || format == "default") ?
2778 getDefaultOutputFormat() : format;
2779 DefaultFlavorCache::const_iterator it =
2780 default_flavors_.find(dformat);
2782 if (it != default_flavors_.end())
2785 Flavor result = Flavor::LaTeX;
2787 // FIXME It'd be better not to hardcode this, but to do
2788 // something with formats.
2789 if (dformat == "xhtml")
2790 result = Flavor::Html;
2791 else if (dformat == "docbook5")
2792 result = Flavor::DocBook5;
2793 else if (dformat == "text")
2794 result = Flavor::Text;
2795 else if (dformat == "lyx")
2796 result = Flavor::LyX;
2797 else if (dformat == "pdflatex")
2798 result = Flavor::PdfLaTeX;
2799 else if (dformat == "xetex")
2800 result = Flavor::XeTeX;
2801 else if (dformat == "luatex")
2802 result = Flavor::LuaTeX;
2803 else if (dformat == "dviluatex")
2804 result = Flavor::DviLuaTeX;
2806 // Try to determine flavor of default output format
2807 vector<string> backs = backends();
2808 if (find(backs.begin(), backs.end(), dformat) == backs.end()) {
2809 // Get shortest path to format
2810 Graph::EdgePath path;
2811 for (auto const & bvar : backs) {
2812 Graph::EdgePath p = theConverters().getPath(bvar, dformat);
2813 if (!p.empty() && (path.empty() || p.size() < path.size())) {
2818 result = theConverters().getFlavor(path);
2821 // cache this flavor
2822 default_flavors_[dformat] = result;
2827 string BufferParams::getDefaultOutputFormat() const
2829 if (!default_output_format.empty()
2830 && default_output_format != "default")
2831 return default_output_format;
2832 if (encoding().package() == Encoding::japanese)
2833 return lyxrc.default_platex_view_format;
2835 return lyxrc.default_otf_view_format;
2836 return lyxrc.default_view_format;
2839 Font const BufferParams::getFont() const
2841 FontInfo f = documentClass().defaultfont();
2842 if (fonts_default_family == "rmdefault")
2843 f.setFamily(ROMAN_FAMILY);
2844 else if (fonts_default_family == "sfdefault")
2845 f.setFamily(SANS_FAMILY);
2846 else if (fonts_default_family == "ttdefault")
2847 f.setFamily(TYPEWRITER_FAMILY);
2848 return Font(f, language);
2852 QuoteStyle BufferParams::getQuoteStyle(string const & qs) const
2854 return quotesstyletranslator().find(qs);
2858 bool BufferParams::isLatex() const
2860 return documentClass().outputType() == LATEX;
2864 bool BufferParams::isLiterate() const
2866 return documentClass().outputType() == LITERATE;
2870 void BufferParams::readPreamble(Lexer & lex)
2872 if (lex.getString() != "\\begin_preamble")
2873 lyxerr << "Error (BufferParams::readPreamble):"
2874 "consistency check failed." << endl;
2876 preamble = lex.getLongString(from_ascii("\\end_preamble"));
2880 void BufferParams::readLocalLayout(Lexer & lex, bool forced)
2882 string const expected = forced ? "\\begin_forced_local_layout" :
2883 "\\begin_local_layout";
2884 if (lex.getString() != expected)
2885 lyxerr << "Error (BufferParams::readLocalLayout):"
2886 "consistency check failed." << endl;
2889 forced_local_layout_ =
2890 lex.getLongString(from_ascii("\\end_forced_local_layout"));
2892 local_layout_ = lex.getLongString(from_ascii("\\end_local_layout"));
2896 bool BufferParams::setLanguage(string const & lang)
2898 Language const *new_language = languages.getLanguage(lang);
2899 if (!new_language) {
2900 // Language lang was not found
2903 language = new_language;
2908 void BufferParams::readLanguage(Lexer & lex)
2910 if (!lex.next()) return;
2912 string const tmptok = lex.getString();
2914 // check if tmptok is part of tex_babel in tex-defs.h
2915 if (!setLanguage(tmptok)) {
2916 // Language tmptok was not found
2917 language = default_language;
2918 lyxerr << "Warning: Setting language `"
2919 << tmptok << "' to `" << language->lang()
2925 void BufferParams::readGraphicsDriver(Lexer & lex)
2930 string const tmptok = lex.getString();
2931 // check if tmptok is part of tex_graphics in tex_defs.h
2934 string const test = tex_graphics[n++];
2936 if (test == tmptok) {
2937 graphics_driver = tmptok;
2942 "Warning: graphics driver `$$Token' not recognized!\n"
2943 " Setting graphics driver to `default'.\n");
2944 graphics_driver = "default";
2951 void BufferParams::readBullets(Lexer & lex)
2956 int const index = lex.getInteger();
2958 int temp_int = lex.getInteger();
2959 user_defined_bullet(index).setFont(temp_int);
2960 temp_bullet(index).setFont(temp_int);
2962 user_defined_bullet(index).setCharacter(temp_int);
2963 temp_bullet(index).setCharacter(temp_int);
2965 user_defined_bullet(index).setSize(temp_int);
2966 temp_bullet(index).setSize(temp_int);
2970 void BufferParams::readBulletsLaTeX(Lexer & lex)
2972 // The bullet class should be able to read this.
2975 int const index = lex.getInteger();
2977 docstring const temp_str = lex.getDocString();
2979 user_defined_bullet(index).setText(temp_str);
2980 temp_bullet(index).setText(temp_str);
2984 void BufferParams::readModules(Lexer & lex)
2986 if (!lex.eatLine()) {
2987 lyxerr << "Error (BufferParams::readModules):"
2988 "Unexpected end of input." << endl;
2992 string mod = lex.getString();
2993 if (mod == "\\end_modules")
2995 addLayoutModule(mod);
3001 void BufferParams::readRemovedModules(Lexer & lex)
3003 if (!lex.eatLine()) {
3004 lyxerr << "Error (BufferParams::readRemovedModules):"
3005 "Unexpected end of input." << endl;
3009 string mod = lex.getString();
3010 if (mod == "\\end_removed_modules")
3012 removed_modules_.push_back(mod);
3015 // now we want to remove any removed modules that were previously
3016 // added. normally, that will be because default modules were added in
3017 // setBaseClass(), which gets called when \textclass is read at the
3018 // start of the read.
3019 for (auto const & rm : removed_modules_) {
3020 LayoutModuleList::iterator const mit = layout_modules_.begin();
3021 LayoutModuleList::iterator const men = layout_modules_.end();
3022 LayoutModuleList::iterator found = find(mit, men, rm);
3025 layout_modules_.erase(found);
3030 void BufferParams::readIncludeonly(Lexer & lex)
3032 if (!lex.eatLine()) {
3033 lyxerr << "Error (BufferParams::readIncludeonly):"
3034 "Unexpected end of input." << endl;
3038 string child = lex.getString();
3039 if (child == "\\end_includeonly")
3041 included_children_.push_back(child);
3047 string BufferParams::paperSizeName(PapersizePurpose purpose, string const & psize) const
3049 PAPER_SIZE ppsize = psize.empty() ? papersize : papersizetranslator().find(psize);
3052 if (documentClass().pagesize() == "default")
3053 // could be anything, so don't guess
3055 return paperSizeName(purpose, documentClass().pagesize());
3056 case PAPER_CUSTOM: {
3057 if (purpose == XDVI && !paperwidth.empty() &&
3058 !paperheight.empty()) {
3059 // heightxwidth<unit>
3060 string first = paperwidth;
3061 string second = paperheight;
3062 if (orientation == ORIENTATION_LANDSCAPE)
3065 return first.erase(first.length() - 2)
3071 // dvips and dvipdfm do not know this
3072 if (purpose == DVIPS || purpose == DVIPDFM)
3076 if (purpose == DVIPS || purpose == DVIPDFM)
3080 if (purpose == DVIPS || purpose == DVIPDFM)
3090 if (purpose == DVIPS || purpose == DVIPDFM)
3094 if (purpose == DVIPS || purpose == DVIPDFM)
3098 if (purpose == DVIPS || purpose == DVIPDFM)
3102 if (purpose == DVIPS || purpose == DVIPDFM)
3106 if (purpose == DVIPS || purpose == DVIPDFM)
3110 // dvipdfm does not know this
3111 if (purpose == DVIPDFM)
3115 if (purpose == DVIPDFM)
3119 if (purpose == DVIPS || purpose == DVIPDFM)
3123 if (purpose == DVIPS || purpose == DVIPDFM)
3127 if (purpose == DVIPS || purpose == DVIPDFM)
3131 if (purpose == DVIPS || purpose == DVIPDFM)
3135 if (purpose == DVIPS || purpose == DVIPDFM)
3139 if (purpose == DVIPS || purpose == DVIPDFM)
3143 if (purpose == DVIPS || purpose == DVIPDFM)
3147 if (purpose == DVIPS || purpose == DVIPDFM)
3151 if (purpose == DVIPS || purpose == DVIPDFM)
3155 if (purpose == DVIPS || purpose == DVIPDFM)
3159 if (purpose == DVIPS || purpose == DVIPDFM)
3163 if (purpose == DVIPS || purpose == DVIPDFM)
3167 if (purpose == DVIPS || purpose == DVIPDFM)
3171 if (purpose == DVIPS || purpose == DVIPDFM)
3175 if (purpose == DVIPS || purpose == DVIPDFM)
3178 case PAPER_USEXECUTIVE:
3179 // dvipdfm does not know this
3180 if (purpose == DVIPDFM)
3185 case PAPER_USLETTER:
3187 if (purpose == XDVI)
3194 string const BufferParams::dvips_options() const
3198 // If the class loads the geometry package, we do not know which
3199 // paper size is used, since we do not set it (bug 7013).
3200 // Therefore we must not specify any argument here.
3201 // dvips gets the correct paper size via DVI specials in this case
3202 // (if the class uses the geometry package correctly).
3203 if (documentClass().provides("geometry"))
3207 && papersize == PAPER_CUSTOM
3208 && !lyxrc.print_paper_dimension_flag.empty()
3209 && !paperwidth.empty()
3210 && !paperheight.empty()) {
3211 // using a custom papersize
3212 result = lyxrc.print_paper_dimension_flag;
3213 result += ' ' + paperwidth;
3214 result += ',' + paperheight;
3216 string const paper_option = paperSizeName(DVIPS);
3217 if (!paper_option.empty() && (paper_option != "letter" ||
3218 orientation != ORIENTATION_LANDSCAPE)) {
3219 // dvips won't accept -t letter -t landscape.
3220 // In all other cases, include the paper size
3222 result = lyxrc.print_paper_flag;
3223 result += ' ' + paper_option;
3226 if (orientation == ORIENTATION_LANDSCAPE &&
3227 papersize != PAPER_CUSTOM)
3228 result += ' ' + lyxrc.print_landscape_flag;
3233 string const BufferParams::main_font_encoding() const
3235 if (font_encodings().empty()) {
3236 if (ascii_lowercase(language->fontenc(*this)) == "none")
3240 return font_encodings().back();
3244 vector<string> const BufferParams::font_encodings() const
3246 string doc_fontenc = (fontenc == "auto") ? string() : fontenc;
3248 vector<string> fontencs;
3250 // "default" means "no explicit font encoding"
3251 if (doc_fontenc != "default") {
3252 if (!doc_fontenc.empty())
3253 // If we have a custom setting, we use only that!
3254 return getVectorFromString(doc_fontenc);
3255 if (!language->fontenc(*this).empty()
3256 && ascii_lowercase(language->fontenc(*this)) != "none") {
3257 vector<string> fencs = getVectorFromString(language->fontenc(*this));
3258 for (auto & fe : fencs) {
3259 if (find(fontencs.begin(), fontencs.end(), fe) == fontencs.end())
3260 fontencs.push_back(fe);
3269 string BufferParams::babelCall(string const & lang_opts, bool const langoptions) const
3271 // suppress the babel call if there is no BabelName defined
3272 // for the document language in the lib/languages file and if no
3273 // other languages are used (lang_opts is then empty)
3274 if (lang_opts.empty())
3276 // The prefs may require the languages to
3277 // be submitted to babel itself (not the class).
3279 return "\\usepackage[" + lang_opts + "]{babel}";
3280 return "\\usepackage{babel}";
3284 docstring BufferParams::getGraphicsDriver(string const & package) const
3288 if (package == "geometry") {
3289 if (graphics_driver == "dvips"
3290 || graphics_driver == "dvipdfm"
3291 || graphics_driver == "pdftex"
3292 || graphics_driver == "vtex")
3293 result = from_ascii(graphics_driver);
3294 else if (graphics_driver == "dvipdfmx")
3295 result = from_ascii("dvipdfm");
3302 void BufferParams::writeEncodingPreamble(otexstream & os,
3303 LaTeXFeatures & features) const
3305 // With no-TeX fonts we use utf8-plain without encoding package.
3309 if (inputenc == "auto-legacy") {
3310 string const doc_encoding =
3311 language->encoding()->latexName();
3312 Encoding::Package const package =
3313 language->encoding()->package();
3315 // Create list of inputenc options:
3316 set<string> encoding_set;
3317 // luainputenc fails with more than one encoding
3318 if (features.runparams().flavor != Flavor::LuaTeX
3319 && features.runparams().flavor != Flavor::DviLuaTeX)
3320 // list all input encodings used in the document
3321 encoding_set = features.getEncodingSet(doc_encoding);
3323 // The "japanese" babel-language requires the pLaTeX engine
3324 // which conflicts with "inputenc".
3325 // See http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129680.html
3326 if ((!encoding_set.empty() || package == Encoding::inputenc)
3327 && !features.isRequired("japanese")
3328 && !features.isProvided("inputenc")) {
3329 os << "\\usepackage[";
3330 set<string>::const_iterator it = encoding_set.begin();
3331 set<string>::const_iterator const end = encoding_set.end();
3333 os << from_ascii(*it);
3336 for (; it != end; ++it)
3337 os << ',' << from_ascii(*it);
3338 if (package == Encoding::inputenc) {
3339 if (!encoding_set.empty())
3341 os << from_ascii(doc_encoding);
3343 if (features.runparams().flavor == Flavor::LuaTeX
3344 || features.runparams().flavor == Flavor::DviLuaTeX)
3345 os << "]{luainputenc}\n";
3347 os << "]{inputenc}\n";
3349 } else if (inputenc != "auto-legacy-plain") {
3350 switch (encoding().package()) {
3351 case Encoding::none:
3353 case Encoding::japanese:
3354 if (encoding().iconvName() != "UTF-8"
3355 && !features.runparams().isFullUnicode())
3356 // don't default to [utf8]{inputenc} with TeXLive >= 18
3357 os << "\\ifdefined\\UseRawInputEncoding\n"
3358 << " \\UseRawInputEncoding\\fi\n";
3360 case Encoding::inputenc:
3361 // do not load inputenc if japanese is used
3362 // or if the class provides inputenc
3363 if (features.isRequired("japanese")
3364 || features.isProvided("inputenc"))
3366 os << "\\usepackage[" << from_ascii(encoding().latexName());
3367 if (features.runparams().flavor == Flavor::LuaTeX
3368 || features.runparams().flavor == Flavor::DviLuaTeX)
3369 os << "]{luainputenc}\n";
3371 os << "]{inputenc}\n";
3375 if (inputenc == "auto-legacy-plain" || features.isRequired("japanese")) {
3376 // don't default to [utf8]{inputenc} with TeXLive >= 18
3377 os << "\\ifdefined\\UseRawInputEncoding\n";
3378 os << " \\UseRawInputEncoding\\fi\n";
3383 string const BufferParams::parseFontName(string const & name) const
3385 string mangled = name;
3386 size_t const idx = mangled.find('[');
3387 if (idx == string::npos || idx == 0)
3390 return mangled.substr(0, idx - 1);
3394 string const BufferParams::loadFonts(LaTeXFeatures & features) const
3396 if (fontsRoman() == "default" && fontsSans() == "default"
3397 && fontsTypewriter() == "default"
3398 && (fontsMath() == "default" || fontsMath() == "auto"))
3404 /* Fontspec (XeTeX, LuaTeX): we provide GUI support for oldstyle
3405 * numbers (Numbers=OldStyle) and sf/tt scaling. The Ligatures=TeX/
3406 * Mapping=tex-text option assures TeX ligatures (such as "--")
3407 * are resolved. Note that tt does not use these ligatures.
3409 * -- add more GUI options?
3410 * -- add more fonts (fonts for other scripts)
3411 * -- if there's a way to find out if a font really supports
3412 * OldStyle, enable/disable the widget accordingly.
3414 if (useNonTeXFonts && features.isAvailable("fontspec")) {
3415 // "Mapping=tex-text" and "Ligatures=TeX" are equivalent.
3416 // However, until v.2 (2010/07/11) fontspec only knew
3417 // Mapping=tex-text (for XeTeX only); then "Ligatures=TeX"
3418 // was introduced for both XeTeX and LuaTeX (LuaTeX
3419 // didn't understand "Mapping=tex-text", while XeTeX
3420 // understood both. With most recent versions, both
3421 // variants are understood by both engines. However,
3422 // we want to provide support for at least TeXLive 2009
3423 // (for XeTeX; LuaTeX is only supported as of v.2)
3424 // As of 2017/11/03, Babel has its own higher-level
3425 // interface on top of fontspec that is to be used.
3426 bool const babelfonts = features.useBabel()
3427 && features.isAvailable("babel-2017/11/03");
3428 string const texmapping =
3429 (features.runparams().flavor == Flavor::XeTeX) ?
3430 "Mapping=tex-text" : "Ligatures=TeX";
3431 if (fontsRoman() != "default") {
3433 os << "\\babelfont{rm}[";
3435 os << "\\setmainfont[";
3436 if (!font_roman_opts.empty())
3437 os << font_roman_opts << ',';
3439 if (fonts_roman_osf)
3440 os << ",Numbers=OldStyle";
3441 os << "]{" << parseFontName(fontsRoman()) << "}\n";
3443 if (fontsSans() != "default") {
3444 string const sans = parseFontName(fontsSans());
3445 if (fontsSansScale() != 100) {
3447 os << "\\babelfont{sf}";
3449 os << "\\setsansfont";
3451 << float(fontsSansScale()) / 100 << ',';
3453 os << "Numbers=OldStyle,";
3454 if (!font_sans_opts.empty())
3455 os << font_sans_opts << ',';
3456 os << texmapping << "]{"
3460 os << "\\babelfont{sf}[";
3462 os << "\\setsansfont[";
3464 os << "Numbers=OldStyle,";
3465 if (!font_sans_opts.empty())
3466 os << font_sans_opts << ',';
3467 os << texmapping << "]{"
3471 if (fontsTypewriter() != "default") {
3472 string const mono = parseFontName(fontsTypewriter());
3473 if (fontsTypewriterScale() != 100) {
3475 os << "\\babelfont{tt}";
3477 os << "\\setmonofont";
3479 << float(fontsTypewriterScale()) / 100;
3480 if (fonts_typewriter_osf)
3481 os << ",Numbers=OldStyle";
3482 if (!font_typewriter_opts.empty())
3483 os << ',' << font_typewriter_opts;
3488 os << "\\babelfont{tt}";
3490 os << "\\setmonofont";
3491 if (!font_typewriter_opts.empty() || fonts_typewriter_osf) {
3493 if (fonts_typewriter_osf)
3494 os << "Numbers=OldStyle";
3495 if (!font_typewriter_opts.empty()) {
3496 if (fonts_typewriter_osf)
3498 os << font_typewriter_opts;
3502 os << '{' << mono << "}\n";
3509 bool const ot1 = (main_font_encoding() == "default" || main_font_encoding() == "OT1");
3510 bool const dryrun = features.runparams().dryrun;
3511 bool const complete = (fontsSans() == "default" && fontsTypewriter() == "default");
3512 bool const nomath = (fontsMath() != "auto");
3515 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsRoman())).getLaTeXCode(
3516 dryrun, ot1, complete, fonts_expert_sc, fonts_roman_osf,
3517 nomath, font_roman_opts);
3520 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsSans())).getLaTeXCode(
3521 dryrun, ot1, complete, fonts_expert_sc, fonts_sans_osf,
3522 nomath, font_sans_opts, fontsSansScale());
3524 // MONOSPACED/TYPEWRITER
3525 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsTypewriter())).getLaTeXCode(
3526 dryrun, ot1, complete, fonts_expert_sc, fonts_typewriter_osf,
3527 nomath, font_typewriter_opts, fontsTypewriterScale());
3530 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsMath())).getLaTeXCode(
3531 dryrun, ot1, complete, fonts_expert_sc, fonts_roman_osf,
3538 Encoding const & BufferParams::encoding() const
3540 // Main encoding for LaTeX output.
3542 return *(encodings.fromLyXName("utf8-plain"));
3543 if (inputenc == "auto-legacy" || inputenc == "auto-legacy-plain")
3544 return *language->encoding();
3545 if (inputenc == "utf8" && language->lang() == "japanese")
3546 return *(encodings.fromLyXName("utf8-platex"));
3547 Encoding const * const enc = encodings.fromLyXName(inputenc);
3550 LYXERR0("Unknown inputenc value `" << inputenc
3551 << "'. Using `auto' instead.");
3552 return *language->encoding();
3556 string const & BufferParams::defaultBiblioStyle() const
3558 if (!biblio_style.empty())
3559 return biblio_style;
3561 map<string, string> const & bs = documentClass().defaultBiblioStyle();
3562 auto cit = bs.find(theCiteEnginesList.getTypeAsString(citeEngineType()));
3563 if (cit != bs.end())
3566 return empty_string();
3570 bool BufferParams::fullAuthorList() const
3572 return documentClass().fullAuthorList();
3576 string BufferParams::getCiteAlias(string const & s) const
3578 vector<string> commands =
3579 documentClass().citeCommands(citeEngineType());
3580 // If it is a real command, don't treat it as an alias
3581 if (find(commands.begin(), commands.end(), s) != commands.end())
3583 map<string,string> aliases = documentClass().citeCommandAliases();
3584 if (aliases.find(s) != aliases.end())
3590 vector<string> BufferParams::citeCommands() const
3592 static CitationStyle const default_style;
3593 vector<string> commands =
3594 documentClass().citeCommands(citeEngineType());
3595 if (commands.empty())
3596 commands.push_back(default_style.name);
3601 vector<CitationStyle> BufferParams::citeStyles() const
3603 static CitationStyle const default_style;
3604 vector<CitationStyle> styles =
3605 documentClass().citeStyles(citeEngineType());
3607 styles.push_back(default_style);
3612 string const BufferParams::bibtexCommand() const
3614 // Return document-specific setting if available
3615 if (bibtex_command != "default")
3616 return bibtex_command;
3618 // If we have "default" in document settings, consult the prefs
3619 // 1. Japanese (uses a specific processor)
3620 if (encoding().package() == Encoding::japanese) {
3621 if (lyxrc.jbibtex_command != "automatic")
3622 // Return the specified program, if "automatic" is not set
3623 return lyxrc.jbibtex_command;
3624 else if (!useBiblatex()) {
3625 // With classic BibTeX, return pbibtex, jbibtex, bibtex
3626 if (lyxrc.jbibtex_alternatives.find("pbibtex") != lyxrc.jbibtex_alternatives.end())
3628 if (lyxrc.jbibtex_alternatives.find("jbibtex") != lyxrc.jbibtex_alternatives.end())
3633 // 2. All other languages
3634 else if (lyxrc.bibtex_command != "automatic")
3635 // Return the specified program, if "automatic" is not set
3636 return lyxrc.bibtex_command;
3638 // 3. Automatic: find the most suitable for the current cite framework
3639 if (useBiblatex()) {
3640 // For Biblatex, we prefer biber (also for Japanese)
3641 // and fall back to bibtex8 and, as last resort, bibtex
3642 if (lyxrc.bibtex_alternatives.find("biber") != lyxrc.bibtex_alternatives.end())
3644 else if (lyxrc.bibtex_alternatives.find("bibtex8") != lyxrc.bibtex_alternatives.end())
3651 bool BufferParams::useBiblatex() const
3653 return theCiteEnginesList[citeEngine()]->getCiteFramework() == "biblatex";
3657 void BufferParams::invalidateConverterCache() const
3659 pimpl_->isExportCacheValid = false;
3660 pimpl_->isViewCacheValid = false;
3664 // We shouldn't need to reset the params here, since anything
3665 // we need will be recopied.
3666 void BufferParams::copyForAdvFR(const BufferParams & bp)
3668 string const & lang = bp.language->lang();
3670 layout_modules_ = bp.layout_modules_;
3671 string const & doc_class = bp.documentClass().name();
3672 setBaseClass(doc_class);
3676 void BufferParams::setBibFileEncoding(string const & file, string const & enc)
3678 bib_encodings[file] = enc;
3682 string const BufferParams::bibFileEncoding(string const & file) const
3684 if (bib_encodings.find(file) == bib_encodings.end())
3686 return bib_encodings.find(file)->second;