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 Bullet temp_bullets[4];
345 Bullet user_defined_bullets[4];
346 IndicesList indiceslist;
350 /** This is the amount of space used for paragraph_separation "skip",
351 * and for detached paragraphs in "indented" documents.
354 PDFOptions pdfoptions;
355 LayoutFileIndex baseClass_;
356 FormatList exportableFormatList;
357 FormatList viewableFormatList;
358 bool isViewCacheValid;
359 bool isExportCacheValid;
363 BufferParams::Impl::Impl()
364 : defskip(VSpace::MEDSKIP), baseClass_(string("")),
365 isViewCacheValid(false), isExportCacheValid(false)
367 // set initial author
369 authorlist.record(Author(from_utf8(lyxrc.user_name),
370 from_utf8(lyxrc.user_email),
371 from_utf8(lyxrc.user_initials)));
376 BufferParams::MemoryTraits::clone(BufferParams::Impl const * ptr)
379 return new BufferParams::Impl(*ptr);
383 void BufferParams::MemoryTraits::destroy(BufferParams::Impl * ptr)
389 BufferParams::BufferParams()
392 setBaseClass(defaultBaseclass());
393 cite_engine_ = "basic";
394 cite_engine_type_ = ENGINE_TYPE_DEFAULT;
396 paragraph_separation = ParagraphIndentSeparation;
397 is_math_indent = false;
398 math_numbering_side = DEFAULT;
399 quotes_style = QuoteStyle::English;
400 dynamic_quotes = false;
401 fontsize = "default";
404 papersize = PAPER_DEFAULT;
405 orientation = ORIENTATION_PORTRAIT;
406 use_geometry = false;
407 biblio_style = string();
408 use_bibtopic = false;
411 save_transient_properties = true;
412 track_changes = false;
413 output_changes = false;
415 postpone_fragile_content = true;
416 use_default_options = true;
417 maintain_unincluded_children = CM_None;
420 language = default_language;
422 fonts_roman[0] = "default";
423 fonts_roman[1] = "default";
424 fonts_sans[0] = "default";
425 fonts_sans[1] = "default";
426 fonts_typewriter[0] = "default";
427 fonts_typewriter[1] = "default";
428 fonts_math[0] = "auto";
429 fonts_math[1] = "auto";
430 fonts_default_family = "default";
431 useNonTeXFonts = false;
432 use_microtype = false;
433 use_dash_ligatures = true;
434 fonts_expert_sc = false;
435 fonts_roman_osf = false;
436 fonts_sans_osf = false;
437 fonts_typewriter_osf = false;
438 fonts_sans_scale[0] = 100;
439 fonts_sans_scale[1] = 100;
440 fonts_typewriter_scale[0] = 100;
441 fonts_typewriter_scale[1] = 100;
443 lang_package = "default";
444 graphics_driver = "default";
445 default_output_format = "default";
446 bibtex_command = "default";
447 index_command = "default";
450 listings_params = string();
451 pagestyle = "default";
452 tablestyle = "default";
453 float_alignment = "class";
454 float_placement = "class";
455 suppress_date = false;
456 justification = true;
457 // no color is the default (white)
458 backgroundcolor = lyx::rgbFromHexName("#ffffff");
459 isbackgroundcolor = false;
460 // no color is the default (black)
461 fontcolor = lyx::rgbFromHexName("#000000");
463 // light gray is the default font color for greyed-out notes
464 notefontcolor = lyx::rgbFromHexName("#cccccc");
465 boxbgcolor = lyx::rgbFromHexName("#ff0000");
466 compressed = lyxrc.save_compressed;
467 for (int iter = 0; iter < 4; ++iter) {
468 user_defined_bullet(iter) = ITEMIZE_DEFAULTS[iter];
469 temp_bullet(iter) = ITEMIZE_DEFAULTS[iter];
472 indiceslist().addDefault(B_("Index"));
473 html_be_strict = false;
474 html_math_output = MathML;
475 html_math_img_scale = 1.0;
476 html_css_as_file = false;
477 docbook_table_output = HTMLTable;
478 display_pixel_ratio = 1.0;
480 shell_escape = false;
486 // map current author
487 author_map_[pimpl_->authorlist.get(0).bufferId()] = 0;
491 docstring BufferParams::B_(string const & l10n) const
493 LASSERT(language, return from_utf8(l10n));
494 return getMessages(language->code()).get(l10n);
498 BufferParams::Package BufferParams::use_package(std::string const & p) const
500 PackageMap::const_iterator it = use_packages.find(p);
501 if (it == use_packages.end())
507 void BufferParams::use_package(std::string const & p, BufferParams::Package u)
513 map<string, string> const & BufferParams::auto_packages()
515 static map<string, string> packages;
516 if (packages.empty()) {
517 // We could have a race condition here that two threads
518 // discover an empty map at the same time and want to fill
519 // it, but that is no problem, since the same contents is
520 // filled in twice then. Having the locker inside the
521 // packages.empty() condition has the advantage that we
522 // don't need the mutex overhead for simple reading.
524 Mutex::Locker locker(&mutex);
525 // adding a package here implies a file format change!
526 packages["amsmath"] =
527 N_("The LaTeX package amsmath is only used if AMS formula types or symbols from the AMS math toolbars are inserted into formulas");
528 packages["amssymb"] =
529 N_("The LaTeX package amssymb is only used if symbols from the AMS math toolbars are inserted into formulas");
531 N_("The LaTeX package cancel is only used if \\cancel commands are used in formulas");
533 N_("The LaTeX package esint is only used if special integral symbols are inserted into formulas");
534 packages["mathdots"] =
535 N_("The LaTeX package mathdots is only used if the command \\iddots is inserted into formulas");
536 packages["mathtools"] =
537 N_("The LaTeX package mathtools is only used if some mathematical relations are inserted into formulas");
539 N_("The LaTeX package mhchem is only used if either the command \\ce or \\cf is inserted into formulas");
540 packages["stackrel"] =
541 N_("The LaTeX package stackrel is only used if the command \\stackrel with subscript is inserted into formulas");
542 packages["stmaryrd"] =
543 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");
544 packages["undertilde"] =
545 N_("The LaTeX package undertilde is only used if you use the math frame decoration 'utilde'");
551 bool BufferParams::useBibtopic() const
555 return (use_bibtopic || (!multibib.empty() && multibib != "child"));
559 AuthorList & BufferParams::authors()
561 return pimpl_->authorlist;
565 AuthorList const & BufferParams::authors() const
567 return pimpl_->authorlist;
571 void BufferParams::addAuthor(Author const & a)
573 author_map_[a.bufferId()] = pimpl_->authorlist.record(a);
577 BranchList & BufferParams::branchlist()
579 return pimpl_->branchlist;
583 BranchList const & BufferParams::branchlist() const
585 return pimpl_->branchlist;
589 IndicesList & BufferParams::indiceslist()
591 return pimpl_->indiceslist;
595 IndicesList const & BufferParams::indiceslist() const
597 return pimpl_->indiceslist;
601 Bullet & BufferParams::temp_bullet(lyx::size_type const index)
603 LASSERT(index < 4, return pimpl_->temp_bullets[0]);
604 return pimpl_->temp_bullets[index];
608 Bullet const & BufferParams::temp_bullet(lyx::size_type const index) const
610 LASSERT(index < 4, return pimpl_->temp_bullets[0]);
611 return pimpl_->temp_bullets[index];
615 Bullet & BufferParams::user_defined_bullet(lyx::size_type const index)
617 LASSERT(index < 4, return pimpl_->temp_bullets[0]);
618 return pimpl_->user_defined_bullets[index];
622 Bullet const & BufferParams::user_defined_bullet(lyx::size_type const index) const
624 LASSERT(index < 4, return pimpl_->temp_bullets[0]);
625 return pimpl_->user_defined_bullets[index];
629 Spacing & BufferParams::spacing()
631 return pimpl_->spacing;
635 Spacing const & BufferParams::spacing() const
637 return pimpl_->spacing;
641 PDFOptions & BufferParams::pdfoptions()
643 return pimpl_->pdfoptions;
647 PDFOptions const & BufferParams::pdfoptions() const
649 return pimpl_->pdfoptions;
653 Length const & BufferParams::getMathIndent() const
655 return pimpl_->mathindent;
659 void BufferParams::setMathIndent(Length const & indent)
661 pimpl_->mathindent = indent;
665 Length const & BufferParams::getParIndent() const
667 return pimpl_->parindent;
671 void BufferParams::setParIndent(Length const & indent)
673 pimpl_->parindent = indent;
677 VSpace const & BufferParams::getDefSkip() const
679 return pimpl_->defskip;
683 void BufferParams::setDefSkip(VSpace const & vs)
685 // DEFSKIP will cause an infinite loop
686 LASSERT(vs.kind() != VSpace::DEFSKIP, return);
687 pimpl_->defskip = vs;
691 BufferParams::MathNumber BufferParams::getMathNumber() const
693 if (math_numbering_side != DEFAULT)
694 return math_numbering_side;
695 // FIXME: do not hardcode language here
696 else if (language->lang() == "arabic_arabi"
697 || documentClass().provides("leqno"))
704 string BufferParams::readToken(Lexer & lex, string const & token,
705 FileName const & filepath)
709 if (token == "\\textclass") {
711 string const classname = lex.getString();
712 // if there exists a local layout file, ignore the system one
713 // NOTE: in this case, the textclass (.cls file) is assumed to
716 LayoutFileList & bcl = LayoutFileList::get();
717 if (!filepath.empty()) {
718 // If classname is an absolute path, the document is
719 // using a local layout file which could not be accessed
720 // by a relative path. In this case the path is correct
721 // even if the document was moved to a different
722 // location. However, we will have a problem if the
723 // document was generated on a different platform.
724 bool isabsolute = FileName::isAbsolute(classname);
725 string const classpath = onlyPath(classname);
726 string const path = isabsolute ? classpath
727 : FileName(addPath(filepath.absFileName(),
728 classpath)).realPath();
729 string const oldpath = isabsolute ? string()
730 : FileName(addPath(origin, classpath)).realPath();
731 tcp = bcl.addLocalLayout(onlyFileName(classname), path, oldpath);
733 // that returns non-empty if a "local" layout file is found.
735 result = to_utf8(makeRelPath(from_utf8(onlyPath(tcp)),
736 from_utf8(filepath.absFileName())));
739 setBaseClass(onlyFileName(tcp));
741 setBaseClass(onlyFileName(classname));
742 // We assume that a tex class exists for local or unknown
743 // layouts so this warning, will only be given for system layouts.
744 if (!baseClass()->isTeXClassAvailable()) {
745 docstring const desc =
746 translateIfPossible(from_utf8(baseClass()->description()));
747 docstring const prereqs =
748 from_utf8(baseClass()->prerequisites());
749 docstring const msg =
750 bformat(_("The selected document class\n"
752 "requires external files that are not available.\n"
753 "The document class can still be used, but the\n"
754 "document cannot be compiled until the following\n"
755 "prerequisites are installed:\n"
757 "See section 3.1.2.2 (Class Availability) of the\n"
758 "User's Guide for more information."), desc, prereqs);
759 frontend::Alert::warning(_("Document class not available"),
762 } else if (token == "\\save_transient_properties") {
763 lex >> save_transient_properties;
764 } else if (token == "\\origin") {
766 origin = lex.getString();
767 string const sysdirprefix = "/systemlyxdir/";
768 if (prefixIs(origin, sysdirprefix)) {
770 if (inSystemDir(filepath, docsys))
771 origin.replace(0, sysdirprefix.length() - 1, docsys);
773 origin.replace(0, sysdirprefix.length() - 1,
774 package().system_support().absFileName());
776 } else if (token == "\\begin_preamble") {
778 } else if (token == "\\begin_local_layout") {
779 readLocalLayout(lex, false);
780 } else if (token == "\\begin_forced_local_layout") {
781 readLocalLayout(lex, true);
782 } else if (token == "\\begin_modules") {
784 } else if (token == "\\begin_removed_modules") {
785 readRemovedModules(lex);
786 } else if (token == "\\begin_includeonly") {
787 readIncludeonly(lex);
788 } else if (token == "\\maintain_unincluded_children") {
792 maintain_unincluded_children = CM_None;
793 else if (tmp == "mostly")
794 maintain_unincluded_children = CM_Mostly;
795 else if (tmp == "strict")
796 maintain_unincluded_children = CM_Strict;
797 } else if (token == "\\options") {
799 options = lex.getString();
800 } else if (token == "\\use_default_options") {
801 lex >> use_default_options;
802 } else if (token == "\\master") {
804 master = lex.getString();
805 if (!filepath.empty() && FileName::isAbsolute(origin)) {
806 bool const isabs = FileName::isAbsolute(master);
807 FileName const abspath(isabs ? master : origin + master);
808 bool const moved = filepath != FileName(origin);
809 if (moved && abspath.exists()) {
810 docstring const path = isabs
812 : from_utf8(abspath.realPath());
813 docstring const refpath =
814 from_utf8(filepath.absFileName());
815 master = to_utf8(makeRelPath(path, refpath));
818 } else if (token == "\\suppress_date") {
819 lex >> suppress_date;
820 } else if (token == "\\justification") {
821 lex >> justification;
822 } else if (token == "\\language") {
824 } else if (token == "\\language_package") {
826 lang_package = lex.getString();
827 } else if (token == "\\inputencoding") {
829 } else if (token == "\\graphics") {
830 readGraphicsDriver(lex);
831 } else if (token == "\\default_output_format") {
832 lex >> default_output_format;
833 } else if (token == "\\bibtex_command") {
835 bibtex_command = lex.getString();
836 } else if (token == "\\index_command") {
838 index_command = lex.getString();
839 } else if (token == "\\fontencoding") {
841 fontenc = lex.getString();
842 } else if (token == "\\font_roman") {
843 lex >> fonts_roman[0];
844 lex >> fonts_roman[1];
845 } else if (token == "\\font_sans") {
846 lex >> fonts_sans[0];
847 lex >> fonts_sans[1];
848 } else if (token == "\\font_typewriter") {
849 lex >> fonts_typewriter[0];
850 lex >> fonts_typewriter[1];
851 } else if (token == "\\font_math") {
852 lex >> fonts_math[0];
853 lex >> fonts_math[1];
854 } else if (token == "\\font_default_family") {
855 lex >> fonts_default_family;
856 } else if (token == "\\use_non_tex_fonts") {
857 lex >> useNonTeXFonts;
858 } else if (token == "\\font_sc") {
859 lex >> fonts_expert_sc;
860 } else if (token == "\\font_roman_osf") {
861 lex >> fonts_roman_osf;
862 } else if (token == "\\font_sans_osf") {
863 lex >> fonts_sans_osf;
864 } else if (token == "\\font_typewriter_osf") {
865 lex >> fonts_typewriter_osf;
866 } else if (token == "\\font_roman_opts") {
867 lex >> font_roman_opts;
868 } else if (token == "\\font_sf_scale") {
869 lex >> fonts_sans_scale[0];
870 lex >> fonts_sans_scale[1];
871 } else if (token == "\\font_sans_opts") {
872 lex >> font_sans_opts;
873 } else if (token == "\\font_tt_scale") {
874 lex >> fonts_typewriter_scale[0];
875 lex >> fonts_typewriter_scale[1];
876 } else if (token == "\\font_typewriter_opts") {
877 lex >> font_typewriter_opts;
878 } else if (token == "\\font_cjk") {
880 } else if (token == "\\use_microtype") {
881 lex >> use_microtype;
882 } else if (token == "\\use_dash_ligatures") {
883 lex >> use_dash_ligatures;
884 } else if (token == "\\paragraph_separation") {
887 paragraph_separation = parseptranslator().find(parsep);
888 } else if (token == "\\paragraph_indentation") {
890 string parindent = lex.getString();
891 if (parindent == "default")
892 pimpl_->parindent = Length();
894 pimpl_->parindent = Length(parindent);
895 } else if (token == "\\defskip") {
897 string const defskip = lex.getString();
898 pimpl_->defskip = VSpace(defskip);
899 if (pimpl_->defskip.kind() == VSpace::DEFSKIP)
901 pimpl_->defskip = VSpace(VSpace::MEDSKIP);
902 } else if (token == "\\is_math_indent") {
903 lex >> is_math_indent;
904 } else if (token == "\\math_indentation") {
906 string mathindent = lex.getString();
907 if (mathindent == "default")
908 pimpl_->mathindent = Length();
910 pimpl_->mathindent = Length(mathindent);
911 } else if (token == "\\math_numbering_side") {
915 math_numbering_side = LEFT;
916 else if (tmp == "right")
917 math_numbering_side = RIGHT;
919 math_numbering_side = DEFAULT;
920 } else if (token == "\\quotes_style") {
923 quotes_style = quotesstyletranslator().find(qstyle);
924 } else if (token == "\\dynamic_quotes") {
925 lex >> dynamic_quotes;
926 } else if (token == "\\papersize") {
929 papersize = papersizetranslator().find(ppsize);
930 } else if (token == "\\use_geometry") {
932 } else if (token == "\\use_package") {
937 use_package(package, packagetranslator().find(use));
938 } else if (token == "\\cite_engine") {
940 cite_engine_ = lex.getString();
941 } else if (token == "\\cite_engine_type") {
944 cite_engine_type_ = theCiteEnginesList.getType(engine_type);
945 } else if (token == "\\biblio_style") {
947 biblio_style = lex.getString();
948 } else if (token == "\\biblio_options") {
950 biblio_opts = trim(lex.getString());
951 } else if (token == "\\biblatex_bibstyle") {
953 biblatex_bibstyle = trim(lex.getString());
954 } else if (token == "\\biblatex_citestyle") {
956 biblatex_citestyle = trim(lex.getString());
957 } else if (token == "\\use_bibtopic") {
959 } else if (token == "\\multibib") {
961 } else if (token == "\\use_indices") {
963 } else if (token == "\\tracking_changes") {
964 lex >> track_changes;
965 } else if (token == "\\output_changes") {
966 lex >> output_changes;
967 } else if (token == "\\change_bars") {
969 } else if (token == "\\postpone_fragile_content") {
970 lex >> postpone_fragile_content;
971 } else if (token == "\\branch") {
973 docstring branch = lex.getDocString();
974 branchlist().add(branch);
977 string const tok = lex.getString();
978 if (tok == "\\end_branch")
980 Branch * branch_ptr = branchlist().find(branch);
981 if (tok == "\\selected") {
984 branch_ptr->setSelected(lex.getInteger());
986 if (tok == "\\filename_suffix") {
989 branch_ptr->setFileNameSuffix(lex.getInteger());
991 if (tok == "\\color") {
993 string color = lex.getString();
995 branch_ptr->setColor(color);
998 } else if (token == "\\index") {
1000 docstring index = lex.getDocString();
1002 indiceslist().add(index);
1005 string const tok = lex.getString();
1006 if (tok == "\\end_index")
1008 Index * index_ptr = indiceslist().find(index);
1009 if (tok == "\\shortcut") {
1011 shortcut = lex.getDocString();
1013 index_ptr->setShortcut(shortcut);
1015 if (tok == "\\color") {
1017 string color = lex.getString();
1019 index_ptr->setColor(color);
1020 // Update also the Color table:
1021 if (color == "none")
1022 color = lcolor.getX11HexName(Color_background);
1024 if (!shortcut.empty())
1025 lcolor.setColor(to_utf8(shortcut), color);
1028 } else if (token == "\\author") {
1030 istringstream ss(lex.getString());
1034 } else if (token == "\\paperorientation") {
1037 orientation = paperorientationtranslator().find(orient);
1038 } else if (token == "\\backgroundcolor") {
1040 backgroundcolor = lyx::rgbFromHexName(lex.getString());
1041 isbackgroundcolor = true;
1042 } else if (token == "\\fontcolor") {
1044 fontcolor = lyx::rgbFromHexName(lex.getString());
1046 } else if (token == "\\notefontcolor") {
1048 string color = lex.getString();
1049 notefontcolor = lyx::rgbFromHexName(color);
1050 lcolor.setColor("notefontcolor", color);
1051 } else if (token == "\\boxbgcolor") {
1053 string color = lex.getString();
1054 boxbgcolor = lyx::rgbFromHexName(color);
1055 lcolor.setColor("boxbgcolor", color);
1056 } else if (token == "\\paperwidth") {
1058 } else if (token == "\\paperheight") {
1060 } else if (token == "\\leftmargin") {
1062 } else if (token == "\\topmargin") {
1064 } else if (token == "\\rightmargin") {
1066 } else if (token == "\\bottommargin") {
1067 lex >> bottommargin;
1068 } else if (token == "\\headheight") {
1070 } else if (token == "\\headsep") {
1072 } else if (token == "\\footskip") {
1074 } else if (token == "\\columnsep") {
1076 } else if (token == "\\paperfontsize") {
1078 } else if (token == "\\papercolumns") {
1080 } else if (token == "\\listings_params") {
1083 listings_params = InsetListingsParams(par).params();
1084 } else if (token == "\\papersides") {
1087 sides = sidestranslator().find(psides);
1088 } else if (token == "\\paperpagestyle") {
1090 } else if (token == "\\tablestyle") {
1092 } else if (token == "\\bullet") {
1094 } else if (token == "\\bulletLaTeX") {
1095 readBulletsLaTeX(lex);
1096 } else if (token == "\\secnumdepth") {
1098 } else if (token == "\\tocdepth") {
1100 } else if (token == "\\spacing") {
1104 if (nspacing == "other") {
1107 spacing().set(spacetranslator().find(nspacing), tmp_val);
1108 } else if (token == "\\float_placement") {
1109 lex >> float_placement;
1110 } else if (token == "\\float_alignment") {
1111 lex >> float_alignment;
1113 } else if (prefixIs(token, "\\pdf_") || token == "\\use_hyperref") {
1114 string toktmp = pdfoptions().readToken(lex, token);
1115 if (!toktmp.empty()) {
1116 lyxerr << "PDFOptions::readToken(): Unknown token: " <<
1120 } else if (token == "\\html_math_output") {
1123 html_math_output = static_cast<MathOutput>(temp);
1124 } else if (token == "\\html_be_strict") {
1125 lex >> html_be_strict;
1126 } else if (token == "\\html_css_as_file") {
1127 lex >> html_css_as_file;
1128 } else if (token == "\\html_math_img_scale") {
1129 lex >> html_math_img_scale;
1130 } else if (token == "\\html_latex_start") {
1132 html_latex_start = lex.getString();
1133 } else if (token == "\\html_latex_end") {
1135 html_latex_end = lex.getString();
1136 } else if (token == "\\docbook_table_output") {
1139 docbook_table_output = static_cast<TableOutput>(temp);
1140 } else if (token == "\\output_sync") {
1142 } else if (token == "\\output_sync_macro") {
1143 lex >> output_sync_macro;
1144 } else if (token == "\\use_refstyle") {
1145 lex >> use_refstyle;
1146 } else if (token == "\\use_minted") {
1148 } else if (token == "\\use_lineno") {
1150 } else if (token == "\\lineno_options") {
1152 lineno_opts = trim(lex.getString());
1154 lyxerr << "BufferParams::readToken(): Unknown token: " <<
1164 // Quote argument if it contains spaces
1165 string quoteIfNeeded(string const & str) {
1166 if (contains(str, ' '))
1167 return "\"" + str + "\"";
1173 void BufferParams::writeFile(ostream & os, Buffer const * buf) const
1175 // The top of the file is written by the buffer.
1176 // Prints out the buffer info into the .lyx file given by file
1178 os << "\\save_transient_properties "
1179 << convert<string>(save_transient_properties) << '\n';
1181 // the document directory (must end with a path separator)
1182 // realPath() is used to resolve symlinks, while addPath(..., "")
1183 // ensures a trailing path separator.
1185 string filepath = addPath(buf->fileName().onlyPath().realPath(), "");
1186 string const sysdir = inSystemDir(FileName(filepath), docsys) ? docsys
1187 : addPath(package().system_support().realPath(), "");
1188 string const relpath =
1189 to_utf8(makeRelPath(from_utf8(filepath), from_utf8(sysdir)));
1190 if (!prefixIs(relpath, "../") && !FileName::isAbsolute(relpath))
1191 filepath = addPath("/systemlyxdir", relpath);
1192 else if (!save_transient_properties || !lyxrc.save_origin)
1193 filepath = "unavailable";
1194 os << "\\origin " << quoteIfNeeded(filepath) << '\n';
1197 os << "\\textclass "
1198 << quoteIfNeeded(buf->includedFilePath(addName(buf->layoutPos(),
1199 baseClass()->name()), "layout"))
1202 // then the preamble
1203 if (!preamble.empty()) {
1204 // remove '\n' from the end of preamble
1205 docstring const tmppreamble = rtrim(preamble, "\n");
1206 os << "\\begin_preamble\n"
1207 << to_utf8(tmppreamble)
1208 << "\n\\end_preamble\n";
1212 if (!options.empty()) {
1213 os << "\\options " << options << '\n';
1216 // use the class options defined in the layout?
1217 os << "\\use_default_options "
1218 << convert<string>(use_default_options) << "\n";
1220 // the master document
1221 if (!master.empty()) {
1222 os << "\\master " << master << '\n';
1226 if (!removed_modules_.empty()) {
1227 os << "\\begin_removed_modules" << '\n';
1228 for (auto const & mod : removed_modules_)
1230 os << "\\end_removed_modules" << '\n';
1234 if (!layout_modules_.empty()) {
1235 os << "\\begin_modules" << '\n';
1236 for (auto const & mod : layout_modules_)
1238 os << "\\end_modules" << '\n';
1242 if (!included_children_.empty()) {
1243 os << "\\begin_includeonly" << '\n';
1244 for (auto const & c : included_children_)
1246 os << "\\end_includeonly" << '\n';
1249 switch (maintain_unincluded_children) {
1260 os << "\\maintain_unincluded_children " << muc << '\n';
1262 // local layout information
1263 docstring const local_layout = getLocalLayout(false);
1264 if (!local_layout.empty()) {
1265 // remove '\n' from the end
1266 docstring const tmplocal = rtrim(local_layout, "\n");
1267 os << "\\begin_local_layout\n"
1268 << to_utf8(tmplocal)
1269 << "\n\\end_local_layout\n";
1271 docstring const forced_local_layout = getLocalLayout(true);
1272 if (!forced_local_layout.empty()) {
1273 // remove '\n' from the end
1274 docstring const tmplocal = rtrim(forced_local_layout, "\n");
1275 os << "\\begin_forced_local_layout\n"
1276 << to_utf8(tmplocal)
1277 << "\n\\end_forced_local_layout\n";
1280 // then the text parameters
1281 if (language != ignore_language)
1282 os << "\\language " << language->lang() << '\n';
1283 os << "\\language_package " << lang_package
1284 << "\n\\inputencoding " << inputenc
1285 << "\n\\fontencoding " << fontenc
1286 << "\n\\font_roman \"" << fonts_roman[0]
1287 << "\" \"" << fonts_roman[1] << '"'
1288 << "\n\\font_sans \"" << fonts_sans[0]
1289 << "\" \"" << fonts_sans[1] << '"'
1290 << "\n\\font_typewriter \"" << fonts_typewriter[0]
1291 << "\" \"" << fonts_typewriter[1] << '"'
1292 << "\n\\font_math \"" << fonts_math[0]
1293 << "\" \"" << fonts_math[1] << '"'
1294 << "\n\\font_default_family " << fonts_default_family
1295 << "\n\\use_non_tex_fonts " << convert<string>(useNonTeXFonts)
1296 << "\n\\font_sc " << convert<string>(fonts_expert_sc)
1297 << "\n\\font_roman_osf " << convert<string>(fonts_roman_osf)
1298 << "\n\\font_sans_osf " << convert<string>(fonts_sans_osf)
1299 << "\n\\font_typewriter_osf " << convert<string>(fonts_typewriter_osf);
1300 if (!font_roman_opts.empty())
1301 os << "\n\\font_roman_opts \"" << font_roman_opts << "\"";
1302 os << "\n\\font_sf_scale " << fonts_sans_scale[0]
1303 << ' ' << fonts_sans_scale[1];
1304 if (!font_sans_opts.empty())
1305 os << "\n\\font_sans_opts \"" << font_sans_opts << "\"";
1306 os << "\n\\font_tt_scale " << fonts_typewriter_scale[0]
1307 << ' ' << fonts_typewriter_scale[1];
1308 if (!font_typewriter_opts.empty())
1309 os << "\n\\font_typewriter_opts \"" << font_typewriter_opts << "\"";
1311 if (!fonts_cjk.empty())
1312 os << "\\font_cjk " << fonts_cjk << '\n';
1313 os << "\\use_microtype " << convert<string>(use_microtype) << '\n';
1314 os << "\\use_dash_ligatures " << convert<string>(use_dash_ligatures) << '\n';
1315 os << "\\graphics " << graphics_driver << '\n';
1316 os << "\\default_output_format " << default_output_format << '\n';
1317 os << "\\output_sync " << output_sync << '\n';
1318 if (!output_sync_macro.empty())
1319 os << "\\output_sync_macro \"" << output_sync_macro << "\"\n";
1320 os << "\\bibtex_command " << bibtex_command << '\n';
1321 os << "\\index_command " << index_command << '\n';
1323 if (!float_placement.empty())
1324 os << "\\float_placement " << float_placement << '\n';
1325 if (!float_alignment.empty())
1326 os << "\\float_alignment " << float_alignment << '\n';
1327 os << "\\paperfontsize " << fontsize << '\n';
1329 spacing().writeFile(os);
1330 pdfoptions().writeFile(os);
1332 os << "\\papersize " << string_papersize[papersize]
1333 << "\n\\use_geometry " << convert<string>(use_geometry);
1334 map<string, string> const & packages = auto_packages();
1335 for (auto const & pack : packages)
1336 os << "\n\\use_package " << pack.first << ' '
1337 << use_package(pack.first);
1339 os << "\n\\cite_engine ";
1341 if (!cite_engine_.empty())
1346 os << "\n\\cite_engine_type " << theCiteEnginesList.getTypeAsString(cite_engine_type_);
1348 if (!biblio_style.empty())
1349 os << "\n\\biblio_style " << biblio_style;
1350 if (!biblio_opts.empty())
1351 os << "\n\\biblio_options " << biblio_opts;
1352 if (!biblatex_bibstyle.empty())
1353 os << "\n\\biblatex_bibstyle " << biblatex_bibstyle;
1354 if (!biblatex_citestyle.empty())
1355 os << "\n\\biblatex_citestyle " << biblatex_citestyle;
1356 if (!multibib.empty())
1357 os << "\n\\multibib " << multibib;
1359 os << "\n\\use_bibtopic " << convert<string>(use_bibtopic)
1360 << "\n\\use_indices " << convert<string>(use_indices)
1361 << "\n\\paperorientation " << string_orientation[orientation]
1362 << "\n\\suppress_date " << convert<string>(suppress_date)
1363 << "\n\\justification " << convert<string>(justification)
1364 << "\n\\use_refstyle " << use_refstyle
1365 << "\n\\use_minted " << use_minted
1366 << "\n\\use_lineno " << use_lineno
1369 if (!lineno_opts.empty())
1370 os << "\\lineno_options " << lineno_opts << '\n';
1372 if (isbackgroundcolor)
1373 os << "\\backgroundcolor " << lyx::X11hexname(backgroundcolor) << '\n';
1375 os << "\\fontcolor " << lyx::X11hexname(fontcolor) << '\n';
1376 if (notefontcolor != lyx::rgbFromHexName("#cccccc"))
1377 os << "\\notefontcolor " << lyx::X11hexname(notefontcolor) << '\n';
1378 if (boxbgcolor != lyx::rgbFromHexName("#ff0000"))
1379 os << "\\boxbgcolor " << lyx::X11hexname(boxbgcolor) << '\n';
1381 for (auto const & br : branchlist()) {
1382 os << "\\branch " << to_utf8(br.branch())
1383 << "\n\\selected " << br.isSelected()
1384 << "\n\\filename_suffix " << br.hasFileNameSuffix()
1385 << "\n\\color " << br.color()
1390 for (auto const & id : indiceslist()) {
1391 os << "\\index " << to_utf8(id.index())
1392 << "\n\\shortcut " << to_utf8(id.shortcut())
1393 << "\n\\color " << lyx::X11hexname(id.color())
1398 if (!paperwidth.empty())
1399 os << "\\paperwidth "
1400 << VSpace(paperwidth).asLyXCommand() << '\n';
1401 if (!paperheight.empty())
1402 os << "\\paperheight "
1403 << VSpace(paperheight).asLyXCommand() << '\n';
1404 if (!leftmargin.empty())
1405 os << "\\leftmargin "
1406 << VSpace(leftmargin).asLyXCommand() << '\n';
1407 if (!topmargin.empty())
1408 os << "\\topmargin "
1409 << VSpace(topmargin).asLyXCommand() << '\n';
1410 if (!rightmargin.empty())
1411 os << "\\rightmargin "
1412 << VSpace(rightmargin).asLyXCommand() << '\n';
1413 if (!bottommargin.empty())
1414 os << "\\bottommargin "
1415 << VSpace(bottommargin).asLyXCommand() << '\n';
1416 if (!headheight.empty())
1417 os << "\\headheight "
1418 << VSpace(headheight).asLyXCommand() << '\n';
1419 if (!headsep.empty())
1421 << VSpace(headsep).asLyXCommand() << '\n';
1422 if (!footskip.empty())
1424 << VSpace(footskip).asLyXCommand() << '\n';
1425 if (!columnsep.empty())
1426 os << "\\columnsep "
1427 << VSpace(columnsep).asLyXCommand() << '\n';
1428 os << "\\secnumdepth " << secnumdepth
1429 << "\n\\tocdepth " << tocdepth
1430 << "\n\\paragraph_separation "
1431 << string_paragraph_separation[paragraph_separation];
1432 if (!paragraph_separation)
1433 os << "\n\\paragraph_indentation "
1434 << (getParIndent().empty() ? "default" : getParIndent().asString());
1436 os << "\n\\defskip " << getDefSkip().asLyXCommand();
1437 os << "\n\\is_math_indent " << is_math_indent;
1439 os << "\n\\math_indentation "
1440 << (getMathIndent().empty() ? "default" : getMathIndent().asString());
1441 os << "\n\\math_numbering_side ";
1442 switch(math_numbering_side) {
1452 os << "\n\\quotes_style "
1453 << string_quotes_style[static_cast<int>(quotes_style)]
1454 << "\n\\dynamic_quotes " << dynamic_quotes
1455 << "\n\\papercolumns " << columns
1456 << "\n\\papersides " << sides
1457 << "\n\\paperpagestyle " << pagestyle
1458 << "\n\\tablestyle " << tablestyle << '\n';
1459 if (!listings_params.empty())
1460 os << "\\listings_params \"" <<
1461 InsetListingsParams(listings_params).encodedString() << "\"\n";
1462 for (int i = 0; i < 4; ++i) {
1463 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
1464 if (user_defined_bullet(i).getFont() != -1) {
1465 os << "\\bullet " << i << " "
1466 << user_defined_bullet(i).getFont() << " "
1467 << user_defined_bullet(i).getCharacter() << " "
1468 << user_defined_bullet(i).getSize() << "\n";
1472 os << "\\bulletLaTeX " << i << " \""
1473 << lyx::to_ascii(user_defined_bullet(i).getText())
1479 os << "\\tracking_changes "
1480 << (save_transient_properties ? convert<string>(track_changes) : "false")
1483 os << "\\output_changes "
1484 << (save_transient_properties ? convert<string>(output_changes) : "false")
1487 os << "\\change_bars "
1488 << (save_transient_properties ? convert<string>(change_bars) : "false")
1491 os << "\\postpone_fragile_content " << convert<string>(postpone_fragile_content) << '\n';
1493 os << "\\html_math_output " << html_math_output << '\n'
1494 << "\\html_css_as_file " << html_css_as_file << '\n'
1495 << "\\html_be_strict " << convert<string>(html_be_strict) << '\n';
1497 os << "\\docbook_table_output " << docbook_table_output << '\n';
1499 if (html_math_img_scale != 1.0)
1500 os << "\\html_math_img_scale " << convert<string>(html_math_img_scale) << '\n';
1501 if (!html_latex_start.empty())
1502 os << "\\html_latex_start " << html_latex_start << '\n';
1503 if (!html_latex_end.empty())
1504 os << "\\html_latex_end " << html_latex_end << '\n';
1506 os << pimpl_->authorlist;
1510 void BufferParams::validate(LaTeXFeatures & features) const
1512 features.require(documentClass().required());
1514 if (columns > 1 && language->rightToLeft())
1515 features.require("rtloutputdblcol");
1517 if (output_changes) {
1518 bool xcolorulem = LaTeXFeatures::isAvailable("ulem") &&
1519 LaTeXFeatures::isAvailable("xcolor");
1521 switch (features.runparams().flavor) {
1523 case Flavor::DviLuaTeX:
1525 features.require("ct-xcolor-ulem");
1526 features.require("ulem");
1527 features.require("xcolor");
1529 features.require("ct-none");
1532 case Flavor::LuaTeX:
1533 case Flavor::PdfLaTeX:
1536 features.require("ct-xcolor-ulem");
1537 features.require("ulem");
1538 features.require("xcolor");
1539 // improves color handling in PDF output
1540 features.require("pdfcolmk");
1542 features.require("ct-none");
1549 features.require("changebar");
1552 // Floats with 'Here definitely' as default setting.
1553 if (float_placement.find('H') != string::npos)
1554 features.require("float");
1556 for (auto const & pm : use_packages) {
1557 if (pm.first == "amsmath") {
1558 // AMS Style is at document level
1559 if (pm.second == package_on ||
1560 features.isProvided("amsmath"))
1561 features.require(pm.first);
1562 } else if (pm.second == package_on)
1563 features.require(pm.first);
1566 // Document-level line spacing
1567 if (spacing().getSpace() != Spacing::Single && !spacing().isDefault())
1568 features.require("setspace");
1570 // the bullet shapes are buffer level not paragraph level
1571 // so they are tested here
1572 for (int i = 0; i < 4; ++i) {
1573 if (user_defined_bullet(i) == ITEMIZE_DEFAULTS[i])
1575 int const font = user_defined_bullet(i).getFont();
1577 int const c = user_defined_bullet(i).getCharacter();
1583 features.require("latexsym");
1585 } else if (font == 1) {
1586 features.require("amssymb");
1587 } else if (font >= 2 && font <= 5) {
1588 features.require("pifont");
1592 if (pdfoptions().use_hyperref) {
1593 features.require("hyperref");
1594 // due to interferences with babel and hyperref, the color package has to
1595 // be loaded after hyperref when hyperref is used with the colorlinks
1596 // option, see http://www.lyx.org/trac/ticket/5291
1597 if (pdfoptions().colorlinks)
1598 features.require("color");
1600 if (!listings_params.empty()) {
1601 // do not test validity because listings_params is
1602 // supposed to be valid
1604 InsetListingsParams(listings_params).separatedParams(true);
1605 // we can't support all packages, but we should load the color package
1606 if (par.find("\\color", 0) != string::npos)
1607 features.require("color");
1610 // some languages are only available via polyglossia
1611 if (features.hasPolyglossiaExclusiveLanguages())
1612 features.require("polyglossia");
1614 if (useNonTeXFonts && fontsMath() != "auto")
1615 features.require("unicode-math");
1618 features.require("microtype");
1620 if (!language->required().empty())
1621 features.require(language->required());
1625 bool BufferParams::writeLaTeX(otexstream & os, LaTeXFeatures & features,
1626 FileName const & filepath) const
1628 // http://www.tug.org/texmf-dist/doc/latex/base/fixltx2e.pdf
1629 // !! To use the Fix-cm package, load it before \documentclass, and use the command
1630 // \RequirePackage to do so, rather than the normal \usepackage
1631 // Do not try to load any other package before the document class, unless you
1632 // have a thorough understanding of the LATEX internals and know exactly what you
1634 if (features.mustProvide("fix-cm"))
1635 os << "\\RequirePackage{fix-cm}\n";
1636 // Likewise for fixltx2e. If other packages conflict with this policy,
1637 // treat it as a package bug (and report it!)
1638 // See http://www.latex-project.org/cgi-bin/ltxbugs2html?pr=latex/4407
1639 if (features.mustProvide("fixltx2e"))
1640 os << "\\RequirePackage{fixltx2e}\n";
1642 os << "\\documentclass";
1644 DocumentClass const & tclass = documentClass();
1646 ostringstream clsoptions; // the document class options.
1648 if (tokenPos(tclass.opt_fontsize(),
1649 '|', fontsize) >= 0) {
1650 // only write if existing in list (and not default)
1651 clsoptions << subst(tclass.fontsizeformat(), "$$s", fontsize) << ",";
1654 // paper sizes not supported by the class itself need the
1656 vector<string> classpsizes = getVectorFromString(tclass.opt_pagesize(), "|");
1657 bool class_supported_papersize = papersize == PAPER_DEFAULT
1658 || find(classpsizes.begin(), classpsizes.end(), string_papersize[papersize]) != classpsizes.end();
1660 if ((!use_geometry || features.isProvided("geometry-light"))
1661 && class_supported_papersize && papersize != PAPER_DEFAULT)
1662 clsoptions << subst(tclass.pagesizeformat(), "$$s", string_papersize[papersize]) << ",";
1665 if (sides != tclass.sides()) {
1668 clsoptions << "oneside,";
1671 clsoptions << "twoside,";
1677 if (columns != tclass.columns()) {
1679 clsoptions << "twocolumn,";
1681 clsoptions << "onecolumn,";
1685 && orientation == ORIENTATION_LANDSCAPE)
1686 clsoptions << "landscape,";
1689 clsoptions << "fleqn,";
1691 switch(math_numbering_side) {
1693 clsoptions << "leqno,";
1696 clsoptions << "reqno,";
1697 features.require("amsmath");
1703 // language should be a parameter to \documentclass
1704 if (language->babel() == "hebrew"
1705 && default_language->babel() != "hebrew")
1706 // This seems necessary
1707 features.useLanguage(default_language);
1709 ostringstream language_options;
1710 bool const use_babel = features.useBabel() && !features.isProvided("babel");
1711 bool const use_polyglossia = features.usePolyglossia();
1712 bool const global = lyxrc.language_global_options;
1713 if (features.useBabel() || (use_polyglossia && global)) {
1714 language_options << features.getBabelLanguages();
1715 if (!language->babel().empty()) {
1716 if (!language_options.str().empty())
1717 language_options << ',';
1718 language_options << language->babel();
1720 if (global && !language_options.str().empty())
1721 clsoptions << language_options.str() << ',';
1724 // the predefined options from the layout
1725 if (use_default_options && !tclass.options().empty())
1726 clsoptions << tclass.options() << ',';
1728 // the user-defined options
1729 if (!options.empty()) {
1730 clsoptions << options << ',';
1733 docstring const strOptions = from_utf8(clsoptions.str());
1734 if (!strOptions.empty()) {
1735 // Check if class options contain uncodable glyphs
1736 docstring uncodable_glyphs;
1737 docstring options_encodable;
1738 Encoding const * const enc = features.runparams().encoding;
1740 for (char_type c : strOptions) {
1741 if (!enc->encodable(c)) {
1742 docstring const glyph(1, c);
1743 LYXERR0("Uncodable character '"
1745 << "' in class options!");
1746 uncodable_glyphs += glyph;
1747 if (features.runparams().dryrun) {
1748 options_encodable += "<" + _("LyX Warning: ")
1749 + _("uncodable character") + " '";
1750 options_encodable += c;
1751 options_encodable += "'>";
1754 options_encodable += c;
1757 options_encodable = strOptions;
1759 // On BUFFER_VIEW|UPDATE, warn user if we found uncodable glyphs
1760 if (!features.runparams().dryrun && !uncodable_glyphs.empty()) {
1761 frontend::Alert::warning(
1762 _("Uncodable character in class options"),
1764 _("The class options of your document contain glyphs "
1765 "that are unknown in the current document encoding "
1766 "(namely %1$s).\nThese glyphs are omitted "
1767 " from the output, which may result in "
1768 "incomplete output."
1769 "\n\nPlease select an appropriate "
1770 "document encoding\n"
1771 "(such as utf8) or change the "
1772 "class options accordingly."),
1775 options_encodable = rtrim(options_encodable, ",");
1776 os << '[' << options_encodable << ']';
1779 os << '{' << from_ascii(tclass.latexname()) << "}\n";
1780 // end of \documentclass defs
1782 // The package options (via \PassOptionsToPackage)
1783 os << from_ascii(features.getPackageOptions());
1785 // if we use fontspec or newtxmath, we have to load the AMS packages here
1786 string const ams = features.loadAMSPackages();
1787 bool const ot1 = (main_font_encoding() == "default" || main_font_encoding() == "OT1");
1788 bool const use_newtxmath =
1789 theLaTeXFonts().getLaTeXFont(from_ascii(fontsMath())).getUsedPackage(
1790 ot1, false, false) == "newtxmath";
1791 if ((useNonTeXFonts || use_newtxmath) && !ams.empty())
1792 os << from_ascii(ams);
1794 if (useNonTeXFonts) {
1795 // Babel (as of 2017/11/03) loads fontspec itself
1796 if (!features.isProvided("fontspec")
1797 && !(features.useBabel() && features.isAvailable("babel-2017/11/03")))
1798 os << "\\usepackage{fontspec}\n";
1799 if (features.mustProvide("unicode-math")
1800 && features.isAvailable("unicode-math"))
1801 os << "\\usepackage{unicode-math}\n";
1804 // load CJK support package before font selection
1805 // (see autotests/export/latex/CJK/micro-sign_utf8-cjk-libertine.lyx)
1806 if (!useNonTeXFonts && encoding().package() != Encoding::none && inputenc != "utf8x"
1807 && (encoding().package() == Encoding::CJK || features.mustProvide("CJK"))) {
1808 if (inputenc == "utf8-cjk" || inputenc == "utf8")
1809 os << "\\usepackage{CJKutf8}\n";
1811 os << "\\usepackage[encapsulated]{CJK}\n";
1814 // font selection must be done before loading fontenc.sty
1815 // but after babel with non-TeX fonts
1816 string const fonts = loadFonts(features);
1817 if (!fonts.empty() && (!features.useBabel() || !useNonTeXFonts))
1818 os << from_utf8(fonts);
1820 if (fonts_default_family != "default")
1821 os << "\\renewcommand{\\familydefault}{\\"
1822 << from_ascii(fonts_default_family) << "}\n";
1824 // set font encoding
1825 // non-TeX fonts use font encoding TU (set by fontspec)
1826 if (!useNonTeXFonts && !features.isProvided("fontenc")
1827 && main_font_encoding() != "default") {
1828 // get main font encodings
1829 vector<string> fontencs = font_encodings();
1830 // get font encodings of secondary languages
1831 // FIXME: some languages (hebrew, ...) assume a standard font encoding as last
1832 // option (for text in other languages).
1833 features.getFontEncodings(fontencs);
1834 if (!fontencs.empty()) {
1835 os << "\\usepackage["
1836 << from_ascii(getStringFromVector(fontencs))
1841 // Load textcomp and pmboxdraw before (lua)inputenc (#11454)
1842 if (features.mustProvide("textcomp"))
1843 os << "\\usepackage{textcomp}\n";
1844 if (features.mustProvide("pmboxdraw"))
1845 os << "\\usepackage{pmboxdraw}\n";
1847 // handle inputenc etc.
1848 // (In documents containing text in Thai language,
1849 // we must load inputenc after babel, see lib/languages).
1850 if (!contains(features.getBabelPostsettings(), from_ascii("thai.ldf")))
1851 writeEncodingPreamble(os, features);
1854 if (!features.runparams().includeall && !included_children_.empty()) {
1855 os << "\\includeonly{";
1857 for (auto incfile : included_children_) {
1858 FileName inc = makeAbsPath(incfile, filepath.absFileName());
1859 string mangled = DocFileName(changeExtension(inc.absFileName(), ".tex")).
1861 if (!features.runparams().nice)
1863 // \includeonly doesn't want an extension
1864 incfile = changeExtension(incfile, string());
1865 incfile = support::latex_path(incfile);
1866 if (!incfile.empty()) {
1869 os << from_utf8(incfile);
1876 if (!features.isProvided("geometry")
1877 && (use_geometry || !class_supported_papersize)) {
1878 odocstringstream ods;
1879 if (!getGraphicsDriver("geometry").empty())
1880 ods << getGraphicsDriver("geometry");
1881 if (orientation == ORIENTATION_LANDSCAPE)
1882 ods << ",landscape";
1883 switch (papersize) {
1885 if (!paperwidth.empty())
1886 ods << ",paperwidth="
1887 << from_ascii(paperwidth);
1888 if (!paperheight.empty())
1889 ods << ",paperheight="
1890 << from_ascii(paperheight);
1892 case PAPER_USLETTER:
1894 case PAPER_USEXECUTIVE:
1923 ods << "," << from_ascii(string_papersize_geometry[papersize]);
1928 docstring g_options = trim(ods.str(), ",");
1929 os << "\\usepackage";
1930 // geometry-light means that the class works with geometry, but overwrites
1931 // the package options and paper sizes (memoir does this).
1932 // In this case, all options need to go to \geometry
1933 // and the standard paper sizes need to go to the class options.
1934 if (!g_options.empty() && !features.isProvided("geometry-light")) {
1935 os << '[' << g_options << ']';
1938 os << "{geometry}\n";
1939 if (use_geometry || features.isProvided("geometry-light")) {
1940 os << "\\geometry{verbose";
1941 if (!g_options.empty())
1942 // Output general options here with "geometry light".
1943 os << "," << g_options;
1944 // output this only if use_geometry is true
1946 if (!topmargin.empty())
1947 os << ",tmargin=" << from_ascii(Length(topmargin).asLatexString());
1948 if (!bottommargin.empty())
1949 os << ",bmargin=" << from_ascii(Length(bottommargin).asLatexString());
1950 if (!leftmargin.empty())
1951 os << ",lmargin=" << from_ascii(Length(leftmargin).asLatexString());
1952 if (!rightmargin.empty())
1953 os << ",rmargin=" << from_ascii(Length(rightmargin).asLatexString());
1954 if (!headheight.empty())
1955 os << ",headheight=" << from_ascii(Length(headheight).asLatexString());
1956 if (!headsep.empty())
1957 os << ",headsep=" << from_ascii(Length(headsep).asLatexString());
1958 if (!footskip.empty())
1959 os << ",footskip=" << from_ascii(Length(footskip).asLatexString());
1960 if (!columnsep.empty())
1961 os << ",columnsep=" << from_ascii(Length(columnsep).asLatexString());
1965 } else if (orientation == ORIENTATION_LANDSCAPE
1966 || papersize != PAPER_DEFAULT) {
1967 features.require("papersize");
1970 if (tokenPos(tclass.opt_pagestyle(), '|', pagestyle) >= 0) {
1971 if (pagestyle == "fancy")
1972 os << "\\usepackage{fancyhdr}\n";
1973 os << "\\pagestyle{" << from_ascii(pagestyle) << "}\n";
1976 // only output when the background color is not default
1977 if (isbackgroundcolor) {
1978 // only require color here, the background color will be defined
1979 // in LaTeXFeatures.cpp to avoid interferences with the LaTeX
1981 features.require("color");
1982 features.require("pagecolor");
1985 // only output when the font color is not default
1987 // only require color here, the font color will be defined
1988 // in LaTeXFeatures.cpp to avoid interferences with the LaTeX
1990 features.require("color");
1991 features.require("fontcolor");
1994 // Only if class has a ToC hierarchy
1995 if (tclass.hasTocLevels()) {
1996 if (secnumdepth != tclass.secnumdepth()) {
1997 os << "\\setcounter{secnumdepth}{"
2001 if (tocdepth != tclass.tocdepth()) {
2002 os << "\\setcounter{tocdepth}{"
2008 if (paragraph_separation) {
2009 // when skip separation
2011 switch (getDefSkip().kind()) {
2012 case VSpace::SMALLSKIP:
2013 psopt = "\\smallskipamount";
2015 case VSpace::MEDSKIP:
2016 psopt = "\\medskipamount";
2018 case VSpace::BIGSKIP:
2019 psopt = "\\bigskipamount";
2021 case VSpace::HALFLINE:
2022 // default (no option)
2024 case VSpace::FULLLINE:
2025 psopt = "\\baselineskip";
2027 case VSpace::LENGTH:
2028 psopt = getDefSkip().length().asLatexString();
2033 if (!features.isProvided("parskip")) {
2035 psopt = "[skip=" + psopt + "]";
2036 os << "\\usepackage" + psopt + "{parskip}\n";
2038 os << "\\setlength{\\parskip}{" + psopt + "}\n";
2041 // when separation by indentation
2042 // only output something when a width is given
2043 if (!getParIndent().empty()) {
2044 os << "\\setlength{\\parindent}{"
2045 << from_utf8(getParIndent().asLatexString())
2050 if (is_math_indent) {
2051 // when formula indentation
2052 // only output something when it is not the default
2053 if (!getMathIndent().empty()) {
2054 os << "\\setlength{\\mathindent}{"
2055 << from_utf8(getMathIndent().asString())
2060 // Now insert the LyX specific LaTeX commands...
2061 features.resolveAlternatives();
2062 features.expandMultiples();
2065 if (!output_sync_macro.empty())
2066 os << from_utf8(output_sync_macro) +"\n";
2067 else if (features.runparams().flavor == Flavor::LaTeX)
2068 os << "\\usepackage[active]{srcltx}\n";
2069 else if (features.runparams().flavor == Flavor::PdfLaTeX)
2070 os << "\\synctex=-1\n";
2073 // due to interferences with babel and hyperref, the color package has to
2074 // be loaded (when it is not already loaded) before babel when hyperref
2075 // is used with the colorlinks option, see
2076 // http://www.lyx.org/trac/ticket/5291
2077 // we decided therefore to load color always before babel, see
2078 // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg144349.html
2079 os << from_ascii(features.getColorOptions());
2081 // If we use hyperref, jurabib, japanese or varioref,
2082 // we have to call babel before
2084 && (features.isRequired("jurabib")
2085 || features.isRequired("hyperref")
2086 || features.isRequired("varioref")
2087 || features.isRequired("japanese"))) {
2088 os << features.getBabelPresettings();
2090 os << from_utf8(babelCall(language_options.str(),
2091 !lyxrc.language_global_options)) + '\n';
2092 os << features.getBabelPostsettings();
2095 // The optional packages;
2096 os << from_ascii(features.getPackages());
2098 // Additional Indices
2099 if (features.isRequired("splitidx")) {
2100 for (auto const & idx : indiceslist()) {
2101 os << "\\newindex{";
2102 os << escape(idx.shortcut());
2108 os << from_utf8(spacing().writePreamble(features.isProvided("SetSpace")));
2111 // * Hyperref manual: "Make sure it comes last of your loaded
2112 // packages, to give it a fighting chance of not being over-written,
2113 // since its job is to redefine many LaTeX commands."
2114 // * Email from Heiko Oberdiek: "It is usually better to load babel
2115 // before hyperref. Then hyperref has a chance to detect babel.
2116 // * Has to be loaded before the "LyX specific LaTeX commands" to
2117 // avoid errors with algorithm floats.
2118 // use hyperref explicitly if it is required
2119 if (features.isRequired("hyperref")) {
2120 OutputParams tmp_params = features.runparams();
2121 pdfoptions().writeLaTeX(tmp_params, os,
2122 features.isProvided("hyperref"));
2123 // correctly break URLs with hyperref and dvi/ps output
2124 if (features.runparams().hyperref_driver == "dvips"
2125 && features.isAvailable("breakurl"))
2126 os << "\\usepackage{breakurl}\n";
2127 } else if (features.isRequired("nameref"))
2128 // hyperref loads this automatically
2129 os << "\\usepackage{nameref}\n";
2132 os << "\\usepackage";
2133 if (!lineno_opts.empty())
2134 os << "[" << lineno_opts << "]";
2136 os << "\\linenumbers\n";
2139 // bibtopic needs to be loaded after hyperref.
2140 // the dot provides the aux file naming which LyX can detect.
2141 if (features.mustProvide("bibtopic"))
2142 os << "\\usepackage[dot]{bibtopic}\n";
2144 // Will be surrounded by \makeatletter and \makeatother when not empty
2145 otexstringstream atlyxpreamble;
2147 // Some macros LyX will need
2149 TexString tmppreamble = features.getMacros();
2150 if (!tmppreamble.str.empty())
2151 atlyxpreamble << "\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
2152 "LyX specific LaTeX commands.\n"
2153 << move(tmppreamble)
2156 // the text class specific preamble
2158 docstring tmppreamble = features.getTClassPreamble();
2159 if (!tmppreamble.empty())
2160 atlyxpreamble << "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
2161 "Textclass specific LaTeX commands.\n"
2165 // suppress date if selected
2166 // use \@ifundefined because we cannot be sure that every document class
2167 // has a \date command
2169 atlyxpreamble << "\\@ifundefined{date}{}{\\date{}}\n";
2171 /* the user-defined preamble */
2172 if (!containsOnly(preamble, " \n\t")) {
2174 atlyxpreamble << "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
2175 "User specified LaTeX commands.\n";
2177 // Check if the user preamble contains uncodable glyphs
2178 odocstringstream user_preamble;
2179 docstring uncodable_glyphs;
2180 Encoding const * const enc = features.runparams().encoding;
2182 for (char_type c : preamble) {
2183 if (!enc->encodable(c)) {
2184 docstring const glyph(1, c);
2185 LYXERR0("Uncodable character '"
2187 << "' in user preamble!");
2188 uncodable_glyphs += glyph;
2189 if (features.runparams().dryrun) {
2190 user_preamble << "<" << _("LyX Warning: ")
2191 << _("uncodable character") << " '";
2192 user_preamble.put(c);
2193 user_preamble << "'>";
2196 user_preamble.put(c);
2199 user_preamble << preamble;
2201 // On BUFFER_VIEW|UPDATE, warn user if we found uncodable glyphs
2202 if (!features.runparams().dryrun && !uncodable_glyphs.empty()) {
2203 frontend::Alert::warning(
2204 _("Uncodable character in user preamble"),
2206 _("The user preamble of your document contains glyphs "
2207 "that are unknown in the current document encoding "
2208 "(namely %1$s).\nThese glyphs are omitted "
2209 " from the output, which may result in "
2210 "incomplete output."
2211 "\n\nPlease select an appropriate "
2212 "document encoding\n"
2213 "(such as utf8) or change the "
2214 "preamble code accordingly."),
2217 atlyxpreamble << user_preamble.str() << '\n';
2220 // footmisc must be loaded after setspace
2221 // Load it here to avoid clashes with footmisc loaded in the user
2222 // preamble. For that reason we also pass the options via
2223 // \PassOptionsToPackage in getPreamble() and not here.
2224 if (features.mustProvide("footmisc"))
2225 atlyxpreamble << "\\usepackage{footmisc}\n";
2227 // subfig loads internally the LaTeX package "caption". As
2228 // caption is a very popular package, users will load it in
2229 // the preamble. Therefore we must load subfig behind the
2230 // user-defined preamble and check if the caption package was
2231 // loaded or not. For the case that caption is loaded before
2232 // subfig, there is the subfig option "caption=false". This
2233 // option also works when a koma-script class is used and
2234 // koma's own caption commands are used instead of caption. We
2235 // use \PassOptionsToPackage here because the user could have
2236 // already loaded subfig in the preamble.
2237 if (features.mustProvide("subfig"))
2238 atlyxpreamble << "\\ifdefined\\showcaptionsetup\n"
2239 " % Caption package is used. Advise subfig not to load it again.\n"
2240 " \\PassOptionsToPackage{caption=false}{subfig}\n"
2242 "\\usepackage{subfig}\n";
2244 // Itemize bullet settings need to be last in case the user
2245 // defines their own bullets that use a package included
2246 // in the user-defined preamble -- ARRae
2247 // Actually it has to be done much later than that
2248 // since some packages like frenchb make modifications
2249 // at \begin{document} time -- JMarc
2250 docstring bullets_def;
2251 for (int i = 0; i < 4; ++i) {
2252 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
2253 if (bullets_def.empty())
2254 bullets_def += "\\AtBeginDocument{\n";
2255 bullets_def += " \\def\\labelitemi";
2257 // `i' is one less than the item to modify
2264 bullets_def += "ii";
2270 bullets_def += '{' +
2271 user_defined_bullet(i).getText()
2276 if (!bullets_def.empty())
2277 atlyxpreamble << bullets_def << "}\n\n";
2279 if (!atlyxpreamble.empty())
2280 os << "\n\\makeatletter\n"
2281 << atlyxpreamble.release()
2282 << "\\makeatother\n\n";
2284 // We try to load babel late, in case it interferes with other packages.
2285 // Jurabib, hyperref, varioref, bicaption, menukeys and listings (bug 8995)
2286 // have to be called after babel, though.
2287 if (use_babel && !features.isRequired("jurabib")
2288 && !features.isRequired("hyperref")
2289 && !features.isRequired("varioref")
2290 && !features.isRequired("japanese")) {
2291 os << features.getBabelPresettings();
2293 os << from_utf8(babelCall(language_options.str(),
2294 !lyxrc.language_global_options)) + '\n';
2295 os << features.getBabelPostsettings();
2297 // In documents containing text in Thai language,
2298 // we must load inputenc after babel (see lib/languages).
2299 if (contains(features.getBabelPostsettings(), from_ascii("thai.ldf")))
2300 writeEncodingPreamble(os, features);
2302 // font selection must be done after babel with non-TeX fonts
2303 if (!fonts.empty() && features.useBabel() && useNonTeXFonts)
2304 os << from_utf8(fonts);
2306 if (features.isRequired("bicaption"))
2307 os << "\\usepackage{bicaption}\n";
2308 if (!listings_params.empty()
2309 || features.mustProvide("listings")
2310 || features.mustProvide("minted")) {
2312 os << "\\usepackage{minted}\n";
2314 os << "\\usepackage{listings}\n";
2316 string lst_params = listings_params;
2317 // If minted, do not output the language option (bug 11203)
2318 if (use_minted && contains(lst_params, "language=")) {
2319 vector<string> opts =
2320 getVectorFromString(lst_params, ",", false);
2321 for (size_t i = 0; i < opts.size(); ++i) {
2322 if (prefixIs(opts[i], "language="))
2323 opts.erase(opts.begin() + i--);
2325 lst_params = getStringFromVector(opts, ",");
2327 if (!lst_params.empty()) {
2329 os << "\\setminted{";
2332 // do not test validity because listings_params is
2333 // supposed to be valid
2335 InsetListingsParams(lst_params).separatedParams(true);
2336 os << from_utf8(par);
2340 // xunicode only needs to be loaded if tipa is used
2341 // (the rest is obsoleted by the new TU encoding).
2342 // It needs to be loaded at least after amsmath, amssymb,
2343 // esint and the other packages that provide special glyphs
2344 if (features.mustProvide("tipa") && useNonTeXFonts
2345 && !features.isProvided("xunicode")) {
2346 // The `xunicode` package officially only supports XeTeX,
2347 // but also works with LuaTeX. We work around its XeTeX test.
2348 if (features.runparams().flavor != Flavor::XeTeX) {
2349 os << "% Pretend to xunicode that we are XeTeX\n"
2350 << "\\def\\XeTeXpicfile{}\n";
2352 os << "\\usepackage{xunicode}\n";
2355 // covington must be loaded after beamerarticle
2356 if (features.isRequired("covington"))
2357 os << "\\usepackage{covington}\n";
2359 // Polyglossia must be loaded last ...
2360 if (use_polyglossia) {
2362 os << "\\usepackage{polyglossia}\n";
2363 // set the main language
2364 os << "\\setdefaultlanguage";
2365 if (!language->polyglossiaOpts().empty())
2366 os << "[" << from_ascii(language->polyglossiaOpts()) << "]";
2367 os << "{" << from_ascii(language->polyglossia()) << "}\n";
2368 // now setup the other languages
2369 set<string> const polylangs =
2370 features.getPolyglossiaLanguages();
2371 for (auto const & pl : polylangs) {
2372 // We do not output the options here; they are output in
2373 // the language switch commands. This is safer if multiple
2374 // varieties are used.
2375 if (pl == language->polyglossia())
2377 os << "\\setotherlanguage";
2378 os << "{" << from_ascii(pl) << "}\n";
2382 // ... but before biblatex (see #7065)
2383 if ((features.mustProvide("biblatex")
2384 || features.isRequired("biblatex-chicago"))
2385 && !features.isProvided("biblatex-chicago")
2386 && !features.isProvided("biblatex-natbib")
2387 && !features.isProvided("natbib-internal")
2388 && !features.isProvided("natbib")
2389 && !features.isProvided("jurabib")) {
2390 // The biblatex-chicago package has a differing interface
2391 // it uses a wrapper package and loads styles via fixed options
2392 bool const chicago = features.isRequired("biblatex-chicago");
2395 os << "\\usepackage";
2396 if (!biblatex_bibstyle.empty()
2397 && (biblatex_bibstyle == biblatex_citestyle)
2399 opts = "style=" + biblatex_bibstyle;
2401 } else if (!chicago) {
2402 if (!biblatex_bibstyle.empty()) {
2403 opts = "bibstyle=" + biblatex_bibstyle;
2406 if (!biblatex_citestyle.empty()) {
2407 opts += delim + "citestyle=" + biblatex_citestyle;
2411 if (!multibib.empty() && multibib != "child") {
2412 opts += delim + "refsection=" + multibib;
2415 if (bibtexCommand() == "bibtex8"
2416 || prefixIs(bibtexCommand(), "bibtex8 ")) {
2417 opts += delim + "backend=bibtex8";
2419 } else if (bibtexCommand() == "bibtex"
2420 || prefixIs(bibtexCommand(), "bibtex ")) {
2421 opts += delim + "backend=bibtex";
2424 if (!bib_encoding.empty() && encodings.fromLyXName(bib_encoding)) {
2425 opts += delim + "bibencoding="
2426 + encodings.fromLyXName(bib_encoding)->latexName();
2429 if (!biblio_opts.empty())
2430 opts += delim + biblio_opts;
2432 os << "[" << opts << "]";
2434 os << "{biblatex-chicago}\n";
2436 os << "{biblatex}\n";
2440 // Load custom language package here
2441 if (features.langPackage() == LaTeXFeatures::LANG_PACK_CUSTOM) {
2442 if (lang_package == "default")
2443 os << from_utf8(lyxrc.language_custom_package);
2445 os << from_utf8(lang_package);
2449 // Since menukeys uses catoptions, which does some heavy changes on key-value options,
2450 // it is recommended to load menukeys as the last package (even after hyperref)
2451 if (features.isRequired("menukeys"))
2452 os << "\\usepackage{menukeys}\n";
2454 docstring const i18npreamble =
2455 features.getTClassI18nPreamble(use_babel, use_polyglossia,
2457 if (!i18npreamble.empty())
2458 os << i18npreamble + '\n';
2464 void BufferParams::useClassDefaults()
2466 DocumentClass const & tclass = documentClass();
2468 sides = tclass.sides();
2469 columns = tclass.columns();
2470 pagestyle = tclass.pagestyle();
2471 tablestyle = tclass.tablestyle();
2472 use_default_options = true;
2473 // Only if class has a ToC hierarchy
2474 if (tclass.hasTocLevels()) {
2475 secnumdepth = tclass.secnumdepth();
2476 tocdepth = tclass.tocdepth();
2481 bool BufferParams::hasClassDefaults() const
2483 DocumentClass const & tclass = documentClass();
2485 return sides == tclass.sides()
2486 && columns == tclass.columns()
2487 && pagestyle == tclass.pagestyle()
2488 && tablestyle == tclass.tablestyle()
2489 && use_default_options
2490 && secnumdepth == tclass.secnumdepth()
2491 && tocdepth == tclass.tocdepth();
2495 DocumentClass const & BufferParams::documentClass() const
2501 DocumentClassConstPtr BufferParams::documentClassPtr() const
2507 void BufferParams::setDocumentClass(DocumentClassConstPtr tc)
2509 // evil, but this function is evil
2510 doc_class_ = const_pointer_cast<DocumentClass>(tc);
2511 invalidateConverterCache();
2515 bool BufferParams::setBaseClass(string const & classname, string const & path)
2517 LYXERR(Debug::TCLASS, "setBaseClass: " << classname);
2518 LayoutFileList & bcl = LayoutFileList::get();
2519 if (!bcl.haveClass(classname)) {
2521 bformat(_("The layout file:\n"
2523 "could not be found. A default textclass with default\n"
2524 "layouts will be used. LyX will not be able to produce\n"
2526 from_utf8(classname));
2527 frontend::Alert::error(_("Document class not found"), s);
2528 bcl.addEmptyClass(classname);
2531 bool const success = bcl[classname].load(path);
2534 bformat(_("Due to some error in it, the layout file:\n"
2536 "could not be loaded. A default textclass with default\n"
2537 "layouts will be used. LyX will not be able to produce\n"
2539 from_utf8(classname));
2540 frontend::Alert::error(_("Could not load class"), s);
2541 bcl.addEmptyClass(classname);
2544 pimpl_->baseClass_ = classname;
2545 layout_modules_.adaptToBaseClass(baseClass(), removed_modules_);
2550 LayoutFile const * BufferParams::baseClass() const
2552 if (LayoutFileList::get().haveClass(pimpl_->baseClass_))
2553 return &(LayoutFileList::get()[pimpl_->baseClass_]);
2559 LayoutFileIndex const & BufferParams::baseClassID() const
2561 return pimpl_->baseClass_;
2565 void BufferParams::makeDocumentClass(bool clone, bool internal)
2570 invalidateConverterCache();
2571 LayoutModuleList mods;
2572 for (auto const & mod : layout_modules_)
2573 mods.push_back(mod);
2575 doc_class_ = getDocumentClass(*baseClass(), mods, cite_engine_, clone, internal);
2577 TextClass::ReturnValues success = TextClass::OK;
2578 if (!forced_local_layout_.empty())
2579 success = doc_class_->read(to_utf8(forced_local_layout_),
2581 if (!local_layout_.empty() &&
2582 (success == TextClass::OK || success == TextClass::OK_OLDFORMAT))
2583 success = doc_class_->read(to_utf8(local_layout_), TextClass::MODULE);
2584 if (success != TextClass::OK && success != TextClass::OK_OLDFORMAT) {
2585 docstring const msg = _("Error reading internal layout information");
2586 frontend::Alert::warning(_("Read Error"), msg);
2591 bool BufferParams::layoutModuleCanBeAdded(string const & modName) const
2593 return layout_modules_.moduleCanBeAdded(modName, baseClass());
2597 docstring BufferParams::getLocalLayout(bool forced) const
2600 return from_utf8(doc_class_->forcedLayouts());
2602 return local_layout_;
2606 void BufferParams::setLocalLayout(docstring const & layout, bool forced)
2609 forced_local_layout_ = layout;
2611 local_layout_ = layout;
2615 bool BufferParams::addLayoutModule(string const & modName)
2617 for (auto const & mod : layout_modules_)
2620 layout_modules_.push_back(modName);
2625 string BufferParams::bufferFormat() const
2627 return documentClass().outputFormat();
2631 bool BufferParams::isExportable(string const & format, bool need_viewable) const
2633 FormatList const & formats = exportableFormats(need_viewable);
2634 for (auto const & fmt : formats) {
2635 if (fmt->name() == format)
2642 FormatList const & BufferParams::exportableFormats(bool only_viewable) const
2644 FormatList & cached = only_viewable ?
2645 pimpl_->viewableFormatList : pimpl_->exportableFormatList;
2646 bool & valid = only_viewable ?
2647 pimpl_->isViewCacheValid : pimpl_->isExportCacheValid;
2651 vector<string> const backs = backends();
2652 set<string> excludes;
2653 if (useNonTeXFonts) {
2654 excludes.insert("latex");
2655 excludes.insert("pdflatex");
2656 } else if (inputenc != "ascii" && inputenc != "utf8-plain") {
2657 // XeTeX with TeX fonts requires input encoding ascii (#10600).
2658 excludes.insert("xetex");
2662 theConverters().getReachable(backs[0], only_viewable, true, excludes);
2663 vector<string>::const_iterator it = backs.begin() + 1;
2664 for (; it != backs.end(); ++it) {
2665 FormatList r = theConverters().getReachable(*it, only_viewable,
2667 result.insert(result.end(), r.begin(), r.end());
2669 sort(result.begin(), result.end(), Format::formatSorter);
2676 vector<string> BufferParams::backends() const
2679 string const buffmt = bufferFormat();
2681 // FIXME: Don't hardcode format names here, but use a flag
2682 if (buffmt == "latex") {
2683 if (encoding().package() == Encoding::japanese)
2684 v.push_back("platex");
2686 if (!useNonTeXFonts) {
2687 v.push_back("pdflatex");
2688 v.push_back("latex");
2691 || inputenc == "ascii" || inputenc == "utf8-plain")
2692 v.push_back("xetex");
2693 v.push_back("luatex");
2694 v.push_back("dviluatex");
2697 string rbuffmt = buffmt;
2698 // If we use an OutputFormat in Japanese docs,
2699 // we need special format in order to get the path
2700 // via pLaTeX (#8823)
2701 if (documentClass().hasOutputFormat()
2702 && encoding().package() == Encoding::japanese)
2704 v.push_back(rbuffmt);
2707 v.push_back("xhtml");
2708 v.push_back("docbook5");
2709 v.push_back("text");
2715 Flavor BufferParams::getOutputFlavor(string const & format) const
2717 string const dformat = (format.empty() || format == "default") ?
2718 getDefaultOutputFormat() : format;
2719 DefaultFlavorCache::const_iterator it =
2720 default_flavors_.find(dformat);
2722 if (it != default_flavors_.end())
2725 Flavor result = Flavor::LaTeX;
2727 // FIXME It'd be better not to hardcode this, but to do
2728 // something with formats.
2729 if (dformat == "xhtml")
2730 result = Flavor::Html;
2731 else if (dformat == "docbook5")
2732 result = Flavor::DocBook5;
2733 else if (dformat == "text")
2734 result = Flavor::Text;
2735 else if (dformat == "lyx")
2736 result = Flavor::LyX;
2737 else if (dformat == "pdflatex")
2738 result = Flavor::PdfLaTeX;
2739 else if (dformat == "xetex")
2740 result = Flavor::XeTeX;
2741 else if (dformat == "luatex")
2742 result = Flavor::LuaTeX;
2743 else if (dformat == "dviluatex")
2744 result = Flavor::DviLuaTeX;
2746 // Try to determine flavor of default output format
2747 vector<string> backs = backends();
2748 if (find(backs.begin(), backs.end(), dformat) == backs.end()) {
2749 // Get shortest path to format
2750 Graph::EdgePath path;
2751 for (auto const & bvar : backs) {
2752 Graph::EdgePath p = theConverters().getPath(bvar, dformat);
2753 if (!p.empty() && (path.empty() || p.size() < path.size())) {
2758 result = theConverters().getFlavor(path);
2761 // cache this flavor
2762 default_flavors_[dformat] = result;
2767 string BufferParams::getDefaultOutputFormat() const
2769 if (!default_output_format.empty()
2770 && default_output_format != "default")
2771 return default_output_format;
2772 if (encoding().package() == Encoding::japanese)
2773 return lyxrc.default_platex_view_format;
2775 return lyxrc.default_otf_view_format;
2776 return lyxrc.default_view_format;
2779 Font const BufferParams::getFont() const
2781 FontInfo f = documentClass().defaultfont();
2782 if (fonts_default_family == "rmdefault")
2783 f.setFamily(ROMAN_FAMILY);
2784 else if (fonts_default_family == "sfdefault")
2785 f.setFamily(SANS_FAMILY);
2786 else if (fonts_default_family == "ttdefault")
2787 f.setFamily(TYPEWRITER_FAMILY);
2788 return Font(f, language);
2792 QuoteStyle BufferParams::getQuoteStyle(string const & qs) const
2794 return quotesstyletranslator().find(qs);
2798 bool BufferParams::isLatex() const
2800 return documentClass().outputType() == LATEX;
2804 bool BufferParams::isLiterate() const
2806 return documentClass().outputType() == LITERATE;
2810 void BufferParams::readPreamble(Lexer & lex)
2812 if (lex.getString() != "\\begin_preamble")
2813 lyxerr << "Error (BufferParams::readPreamble):"
2814 "consistency check failed." << endl;
2816 preamble = lex.getLongString(from_ascii("\\end_preamble"));
2820 void BufferParams::readLocalLayout(Lexer & lex, bool forced)
2822 string const expected = forced ? "\\begin_forced_local_layout" :
2823 "\\begin_local_layout";
2824 if (lex.getString() != expected)
2825 lyxerr << "Error (BufferParams::readLocalLayout):"
2826 "consistency check failed." << endl;
2829 forced_local_layout_ =
2830 lex.getLongString(from_ascii("\\end_forced_local_layout"));
2832 local_layout_ = lex.getLongString(from_ascii("\\end_local_layout"));
2836 bool BufferParams::setLanguage(string const & lang)
2838 Language const *new_language = languages.getLanguage(lang);
2839 if (!new_language) {
2840 // Language lang was not found
2843 language = new_language;
2848 void BufferParams::readLanguage(Lexer & lex)
2850 if (!lex.next()) return;
2852 string const tmptok = lex.getString();
2854 // check if tmptok is part of tex_babel in tex-defs.h
2855 if (!setLanguage(tmptok)) {
2856 // Language tmptok was not found
2857 language = default_language;
2858 lyxerr << "Warning: Setting language `"
2859 << tmptok << "' to `" << language->lang()
2865 void BufferParams::readGraphicsDriver(Lexer & lex)
2870 string const tmptok = lex.getString();
2871 // check if tmptok is part of tex_graphics in tex_defs.h
2874 string const test = tex_graphics[n++];
2876 if (test == tmptok) {
2877 graphics_driver = tmptok;
2882 "Warning: graphics driver `$$Token' not recognized!\n"
2883 " Setting graphics driver to `default'.\n");
2884 graphics_driver = "default";
2891 void BufferParams::readBullets(Lexer & lex)
2896 int const index = lex.getInteger();
2898 int temp_int = lex.getInteger();
2899 user_defined_bullet(index).setFont(temp_int);
2900 temp_bullet(index).setFont(temp_int);
2902 user_defined_bullet(index).setCharacter(temp_int);
2903 temp_bullet(index).setCharacter(temp_int);
2905 user_defined_bullet(index).setSize(temp_int);
2906 temp_bullet(index).setSize(temp_int);
2910 void BufferParams::readBulletsLaTeX(Lexer & lex)
2912 // The bullet class should be able to read this.
2915 int const index = lex.getInteger();
2917 docstring const temp_str = lex.getDocString();
2919 user_defined_bullet(index).setText(temp_str);
2920 temp_bullet(index).setText(temp_str);
2924 void BufferParams::readModules(Lexer & lex)
2926 if (!lex.eatLine()) {
2927 lyxerr << "Error (BufferParams::readModules):"
2928 "Unexpected end of input." << endl;
2932 string mod = lex.getString();
2933 if (mod == "\\end_modules")
2935 addLayoutModule(mod);
2941 void BufferParams::readRemovedModules(Lexer & lex)
2943 if (!lex.eatLine()) {
2944 lyxerr << "Error (BufferParams::readRemovedModules):"
2945 "Unexpected end of input." << endl;
2949 string mod = lex.getString();
2950 if (mod == "\\end_removed_modules")
2952 removed_modules_.push_back(mod);
2955 // now we want to remove any removed modules that were previously
2956 // added. normally, that will be because default modules were added in
2957 // setBaseClass(), which gets called when \textclass is read at the
2958 // start of the read.
2959 for (auto const & rm : removed_modules_) {
2960 LayoutModuleList::iterator const mit = layout_modules_.begin();
2961 LayoutModuleList::iterator const men = layout_modules_.end();
2962 LayoutModuleList::iterator found = find(mit, men, rm);
2965 layout_modules_.erase(found);
2970 void BufferParams::readIncludeonly(Lexer & lex)
2972 if (!lex.eatLine()) {
2973 lyxerr << "Error (BufferParams::readIncludeonly):"
2974 "Unexpected end of input." << endl;
2978 string child = lex.getString();
2979 if (child == "\\end_includeonly")
2981 included_children_.push_back(child);
2987 string BufferParams::paperSizeName(PapersizePurpose purpose, string const & psize) const
2989 PAPER_SIZE ppsize = psize.empty() ? papersize : papersizetranslator().find(psize);
2992 if (documentClass().pagesize() == "default")
2993 // could be anything, so don't guess
2995 return paperSizeName(purpose, documentClass().pagesize());
2996 case PAPER_CUSTOM: {
2997 if (purpose == XDVI && !paperwidth.empty() &&
2998 !paperheight.empty()) {
2999 // heightxwidth<unit>
3000 string first = paperwidth;
3001 string second = paperheight;
3002 if (orientation == ORIENTATION_LANDSCAPE)
3005 return first.erase(first.length() - 2)
3011 // dvips and dvipdfm do not know this
3012 if (purpose == DVIPS || purpose == DVIPDFM)
3016 if (purpose == DVIPS || purpose == DVIPDFM)
3020 if (purpose == DVIPS || purpose == DVIPDFM)
3030 if (purpose == DVIPS || purpose == DVIPDFM)
3034 if (purpose == DVIPS || purpose == DVIPDFM)
3038 if (purpose == DVIPS || purpose == DVIPDFM)
3042 if (purpose == DVIPS || purpose == DVIPDFM)
3046 if (purpose == DVIPS || purpose == DVIPDFM)
3050 // dvipdfm does not know this
3051 if (purpose == DVIPDFM)
3055 if (purpose == DVIPDFM)
3059 if (purpose == DVIPS || purpose == DVIPDFM)
3063 if (purpose == DVIPS || purpose == DVIPDFM)
3067 if (purpose == DVIPS || purpose == DVIPDFM)
3071 if (purpose == DVIPS || purpose == DVIPDFM)
3075 if (purpose == DVIPS || purpose == DVIPDFM)
3079 if (purpose == DVIPS || purpose == DVIPDFM)
3083 if (purpose == DVIPS || purpose == DVIPDFM)
3087 if (purpose == DVIPS || purpose == DVIPDFM)
3091 if (purpose == DVIPS || purpose == DVIPDFM)
3095 if (purpose == DVIPS || purpose == DVIPDFM)
3099 if (purpose == DVIPS || purpose == DVIPDFM)
3103 if (purpose == DVIPS || purpose == DVIPDFM)
3107 if (purpose == DVIPS || purpose == DVIPDFM)
3111 if (purpose == DVIPS || purpose == DVIPDFM)
3115 if (purpose == DVIPS || purpose == DVIPDFM)
3118 case PAPER_USEXECUTIVE:
3119 // dvipdfm does not know this
3120 if (purpose == DVIPDFM)
3125 case PAPER_USLETTER:
3127 if (purpose == XDVI)
3134 string const BufferParams::dvips_options() const
3138 // If the class loads the geometry package, we do not know which
3139 // paper size is used, since we do not set it (bug 7013).
3140 // Therefore we must not specify any argument here.
3141 // dvips gets the correct paper size via DVI specials in this case
3142 // (if the class uses the geometry package correctly).
3143 if (documentClass().provides("geometry"))
3147 && papersize == PAPER_CUSTOM
3148 && !lyxrc.print_paper_dimension_flag.empty()
3149 && !paperwidth.empty()
3150 && !paperheight.empty()) {
3151 // using a custom papersize
3152 result = lyxrc.print_paper_dimension_flag;
3153 result += ' ' + paperwidth;
3154 result += ',' + paperheight;
3156 string const paper_option = paperSizeName(DVIPS);
3157 if (!paper_option.empty() && (paper_option != "letter" ||
3158 orientation != ORIENTATION_LANDSCAPE)) {
3159 // dvips won't accept -t letter -t landscape.
3160 // In all other cases, include the paper size
3162 result = lyxrc.print_paper_flag;
3163 result += ' ' + paper_option;
3166 if (orientation == ORIENTATION_LANDSCAPE &&
3167 papersize != PAPER_CUSTOM)
3168 result += ' ' + lyxrc.print_landscape_flag;
3173 string const BufferParams::main_font_encoding() const
3175 if (font_encodings().empty()) {
3176 if (ascii_lowercase(language->fontenc(*this)) == "none")
3180 return font_encodings().back();
3184 vector<string> const BufferParams::font_encodings() const
3186 string doc_fontenc = (fontenc == "auto") ? string() : fontenc;
3188 vector<string> fontencs;
3190 // "default" means "no explicit font encoding"
3191 if (doc_fontenc != "default") {
3192 if (!doc_fontenc.empty())
3193 // If we have a custom setting, we use only that!
3194 return getVectorFromString(doc_fontenc);
3195 if (!language->fontenc(*this).empty()
3196 && ascii_lowercase(language->fontenc(*this)) != "none") {
3197 vector<string> fencs = getVectorFromString(language->fontenc(*this));
3198 for (auto & fe : fencs) {
3199 if (find(fontencs.begin(), fontencs.end(), fe) == fontencs.end())
3200 fontencs.push_back(fe);
3209 string BufferParams::babelCall(string const & lang_opts, bool const langoptions) const
3211 // suppress the babel call if there is no BabelName defined
3212 // for the document language in the lib/languages file and if no
3213 // other languages are used (lang_opts is then empty)
3214 if (lang_opts.empty())
3216 // The prefs may require the languages to
3217 // be submitted to babel itself (not the class).
3219 return "\\usepackage[" + lang_opts + "]{babel}";
3220 return "\\usepackage{babel}";
3224 docstring BufferParams::getGraphicsDriver(string const & package) const
3228 if (package == "geometry") {
3229 if (graphics_driver == "dvips"
3230 || graphics_driver == "dvipdfm"
3231 || graphics_driver == "pdftex"
3232 || graphics_driver == "vtex")
3233 result = from_ascii(graphics_driver);
3234 else if (graphics_driver == "dvipdfmx")
3235 result = from_ascii("dvipdfm");
3242 void BufferParams::writeEncodingPreamble(otexstream & os,
3243 LaTeXFeatures & features) const
3245 // With no-TeX fonts we use utf8-plain without encoding package.
3249 if (inputenc == "auto-legacy") {
3250 string const doc_encoding =
3251 language->encoding()->latexName();
3252 Encoding::Package const package =
3253 language->encoding()->package();
3255 // Create list of inputenc options:
3256 set<string> encoding_set;
3257 // luainputenc fails with more than one encoding
3258 if (features.runparams().flavor != Flavor::LuaTeX
3259 && features.runparams().flavor != Flavor::DviLuaTeX)
3260 // list all input encodings used in the document
3261 encoding_set = features.getEncodingSet(doc_encoding);
3263 // The "japanese" babel-language requires the pLaTeX engine
3264 // which conflicts with "inputenc".
3265 // See http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129680.html
3266 if ((!encoding_set.empty() || package == Encoding::inputenc)
3267 && !features.isRequired("japanese")
3268 && !features.isProvided("inputenc")) {
3269 os << "\\usepackage[";
3270 set<string>::const_iterator it = encoding_set.begin();
3271 set<string>::const_iterator const end = encoding_set.end();
3273 os << from_ascii(*it);
3276 for (; it != end; ++it)
3277 os << ',' << from_ascii(*it);
3278 if (package == Encoding::inputenc) {
3279 if (!encoding_set.empty())
3281 os << from_ascii(doc_encoding);
3283 if (features.runparams().flavor == Flavor::LuaTeX
3284 || features.runparams().flavor == Flavor::DviLuaTeX)
3285 os << "]{luainputenc}\n";
3287 os << "]{inputenc}\n";
3289 } else if (inputenc != "auto-legacy-plain") {
3290 switch (encoding().package()) {
3291 case Encoding::none:
3293 case Encoding::japanese:
3294 if (encoding().iconvName() != "UTF-8"
3295 && !features.runparams().isFullUnicode())
3296 // don't default to [utf8]{inputenc} with TeXLive >= 18
3297 os << "\\ifdefined\\UseRawInputEncoding\n"
3298 << " \\UseRawInputEncoding\\fi\n";
3300 case Encoding::inputenc:
3301 // do not load inputenc if japanese is used
3302 // or if the class provides inputenc
3303 if (features.isRequired("japanese")
3304 || features.isProvided("inputenc"))
3306 os << "\\usepackage[" << from_ascii(encoding().latexName());
3307 if (features.runparams().flavor == Flavor::LuaTeX
3308 || features.runparams().flavor == Flavor::DviLuaTeX)
3309 os << "]{luainputenc}\n";
3311 os << "]{inputenc}\n";
3315 if (inputenc == "auto-legacy-plain" || features.isRequired("japanese")) {
3316 // don't default to [utf8]{inputenc} with TeXLive >= 18
3317 os << "\\ifdefined\\UseRawInputEncoding\n";
3318 os << " \\UseRawInputEncoding\\fi\n";
3323 string const BufferParams::parseFontName(string const & name) const
3325 string mangled = name;
3326 size_t const idx = mangled.find('[');
3327 if (idx == string::npos || idx == 0)
3330 return mangled.substr(0, idx - 1);
3334 string const BufferParams::loadFonts(LaTeXFeatures & features) const
3336 if (fontsRoman() == "default" && fontsSans() == "default"
3337 && fontsTypewriter() == "default"
3338 && (fontsMath() == "default" || fontsMath() == "auto"))
3344 /* Fontspec (XeTeX, LuaTeX): we provide GUI support for oldstyle
3345 * numbers (Numbers=OldStyle) and sf/tt scaling. The Ligatures=TeX/
3346 * Mapping=tex-text option assures TeX ligatures (such as "--")
3347 * are resolved. Note that tt does not use these ligatures.
3349 * -- add more GUI options?
3350 * -- add more fonts (fonts for other scripts)
3351 * -- if there's a way to find out if a font really supports
3352 * OldStyle, enable/disable the widget accordingly.
3354 if (useNonTeXFonts && features.isAvailable("fontspec")) {
3355 // "Mapping=tex-text" and "Ligatures=TeX" are equivalent.
3356 // However, until v.2 (2010/07/11) fontspec only knew
3357 // Mapping=tex-text (for XeTeX only); then "Ligatures=TeX"
3358 // was introduced for both XeTeX and LuaTeX (LuaTeX
3359 // didn't understand "Mapping=tex-text", while XeTeX
3360 // understood both. With most recent versions, both
3361 // variants are understood by both engines. However,
3362 // we want to provide support for at least TeXLive 2009
3363 // (for XeTeX; LuaTeX is only supported as of v.2)
3364 // As of 2017/11/03, Babel has its own higher-level
3365 // interface on top of fontspec that is to be used.
3366 bool const babelfonts = features.useBabel()
3367 && features.isAvailable("babel-2017/11/03");
3368 string const texmapping =
3369 (features.runparams().flavor == Flavor::XeTeX) ?
3370 "Mapping=tex-text" : "Ligatures=TeX";
3371 if (fontsRoman() != "default") {
3373 os << "\\babelfont{rm}[";
3375 os << "\\setmainfont[";
3376 if (!font_roman_opts.empty())
3377 os << font_roman_opts << ',';
3379 if (fonts_roman_osf)
3380 os << ",Numbers=OldStyle";
3381 os << "]{" << parseFontName(fontsRoman()) << "}\n";
3383 if (fontsSans() != "default") {
3384 string const sans = parseFontName(fontsSans());
3385 if (fontsSansScale() != 100) {
3387 os << "\\babelfont{sf}";
3389 os << "\\setsansfont";
3391 << float(fontsSansScale()) / 100 << ',';
3393 os << "Numbers=OldStyle,";
3394 if (!font_sans_opts.empty())
3395 os << font_sans_opts << ',';
3396 os << texmapping << "]{"
3400 os << "\\babelfont{sf}[";
3402 os << "\\setsansfont[";
3404 os << "Numbers=OldStyle,";
3405 if (!font_sans_opts.empty())
3406 os << font_sans_opts << ',';
3407 os << texmapping << "]{"
3411 if (fontsTypewriter() != "default") {
3412 string const mono = parseFontName(fontsTypewriter());
3413 if (fontsTypewriterScale() != 100) {
3415 os << "\\babelfont{tt}";
3417 os << "\\setmonofont";
3419 << float(fontsTypewriterScale()) / 100;
3420 if (fonts_typewriter_osf)
3421 os << ",Numbers=OldStyle";
3422 if (!font_typewriter_opts.empty())
3423 os << ',' << font_typewriter_opts;
3428 os << "\\babelfont{tt}";
3430 os << "\\setmonofont";
3431 if (!font_typewriter_opts.empty() || fonts_typewriter_osf) {
3433 if (fonts_typewriter_osf)
3434 os << "Numbers=OldStyle";
3435 if (!font_typewriter_opts.empty()) {
3436 if (fonts_typewriter_osf)
3438 os << font_typewriter_opts;
3442 os << '{' << mono << "}\n";
3449 bool const ot1 = (main_font_encoding() == "default" || main_font_encoding() == "OT1");
3450 bool const dryrun = features.runparams().dryrun;
3451 bool const complete = (fontsSans() == "default" && fontsTypewriter() == "default");
3452 bool const nomath = (fontsMath() != "auto");
3455 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsRoman())).getLaTeXCode(
3456 dryrun, ot1, complete, fonts_expert_sc, fonts_roman_osf,
3457 nomath, font_roman_opts);
3460 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsSans())).getLaTeXCode(
3461 dryrun, ot1, complete, fonts_expert_sc, fonts_sans_osf,
3462 nomath, font_sans_opts, fontsSansScale());
3464 // MONOSPACED/TYPEWRITER
3465 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsTypewriter())).getLaTeXCode(
3466 dryrun, ot1, complete, fonts_expert_sc, fonts_typewriter_osf,
3467 nomath, font_typewriter_opts, fontsTypewriterScale());
3470 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsMath())).getLaTeXCode(
3471 dryrun, ot1, complete, fonts_expert_sc, fonts_roman_osf,
3478 Encoding const & BufferParams::encoding() const
3480 // Main encoding for LaTeX output.
3482 return *(encodings.fromLyXName("utf8-plain"));
3483 if (inputenc == "auto-legacy" || inputenc == "auto-legacy-plain")
3484 return *language->encoding();
3485 if (inputenc == "utf8" && language->lang() == "japanese")
3486 return *(encodings.fromLyXName("utf8-platex"));
3487 Encoding const * const enc = encodings.fromLyXName(inputenc);
3490 LYXERR0("Unknown inputenc value `" << inputenc
3491 << "'. Using `auto' instead.");
3492 return *language->encoding();
3496 string const & BufferParams::defaultBiblioStyle() const
3498 if (!biblio_style.empty())
3499 return biblio_style;
3501 map<string, string> const & bs = documentClass().defaultBiblioStyle();
3502 auto cit = bs.find(theCiteEnginesList.getTypeAsString(citeEngineType()));
3503 if (cit != bs.end())
3506 return empty_string();
3510 bool BufferParams::fullAuthorList() const
3512 return documentClass().fullAuthorList();
3516 string BufferParams::getCiteAlias(string const & s) const
3518 vector<string> commands =
3519 documentClass().citeCommands(citeEngineType());
3520 // If it is a real command, don't treat it as an alias
3521 if (find(commands.begin(), commands.end(), s) != commands.end())
3523 map<string,string> aliases = documentClass().citeCommandAliases();
3524 if (aliases.find(s) != aliases.end())
3530 vector<string> BufferParams::citeCommands() const
3532 static CitationStyle const default_style;
3533 vector<string> commands =
3534 documentClass().citeCommands(citeEngineType());
3535 if (commands.empty())
3536 commands.push_back(default_style.name);
3541 vector<CitationStyle> BufferParams::citeStyles() const
3543 static CitationStyle const default_style;
3544 vector<CitationStyle> styles =
3545 documentClass().citeStyles(citeEngineType());
3547 styles.push_back(default_style);
3552 string const BufferParams::bibtexCommand() const
3554 // Return document-specific setting if available
3555 if (bibtex_command != "default")
3556 return bibtex_command;
3558 // If we have "default" in document settings, consult the prefs
3559 // 1. Japanese (uses a specific processor)
3560 if (encoding().package() == Encoding::japanese) {
3561 if (lyxrc.jbibtex_command != "automatic")
3562 // Return the specified program, if "automatic" is not set
3563 return lyxrc.jbibtex_command;
3564 else if (!useBiblatex()) {
3565 // With classic BibTeX, return pbibtex, jbibtex, bibtex
3566 if (lyxrc.jbibtex_alternatives.find("pbibtex") != lyxrc.jbibtex_alternatives.end())
3568 if (lyxrc.jbibtex_alternatives.find("jbibtex") != lyxrc.jbibtex_alternatives.end())
3573 // 2. All other languages
3574 else if (lyxrc.bibtex_command != "automatic")
3575 // Return the specified program, if "automatic" is not set
3576 return lyxrc.bibtex_command;
3578 // 3. Automatic: find the most suitable for the current cite framework
3579 if (useBiblatex()) {
3580 // For Biblatex, we prefer biber (also for Japanese)
3581 // and fall back to bibtex8 and, as last resort, bibtex
3582 if (lyxrc.bibtex_alternatives.find("biber") != lyxrc.bibtex_alternatives.end())
3584 else if (lyxrc.bibtex_alternatives.find("bibtex8") != lyxrc.bibtex_alternatives.end())
3591 bool BufferParams::useBiblatex() const
3593 return theCiteEnginesList[citeEngine()]->getCiteFramework() == "biblatex";
3597 void BufferParams::invalidateConverterCache() const
3599 pimpl_->isExportCacheValid = false;
3600 pimpl_->isViewCacheValid = false;
3604 // We shouldn't need to reset the params here, since anything
3605 // we need will be recopied.
3606 void BufferParams::copyForAdvFR(const BufferParams & bp)
3608 string const & lang = bp.language->lang();
3610 layout_modules_ = bp.layout_modules_;
3611 string const & doc_class = bp.documentClass().name();
3612 setBaseClass(doc_class);
3616 void BufferParams::setBibFileEncoding(string const & file, string const & enc)
3618 bib_encodings[file] = enc;
3622 string const BufferParams::bibFileEncoding(string const & file) const
3624 if (bib_encodings.find(file) == bib_encodings.end())
3626 return bib_encodings.find(file)->second;