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 vector<string> const colors = getVectorFromString(lex.getString(), " ");
994 string const lmcolor = colors.front();
996 if (colors.size() > 1)
997 dmcolor = colors.back();
999 branch_ptr->setColors(lmcolor, dmcolor);
1002 } else if (token == "\\index") {
1004 docstring index = lex.getDocString();
1006 indiceslist().add(index);
1009 string const tok = lex.getString();
1010 if (tok == "\\end_index")
1012 Index * index_ptr = indiceslist().find(index);
1013 if (tok == "\\shortcut") {
1015 shortcut = lex.getDocString();
1017 index_ptr->setShortcut(shortcut);
1019 if (tok == "\\color") {
1021 string color = lex.getString();
1023 index_ptr->setColor(color);
1024 // Update also the Color table:
1025 if (color == "none")
1026 color = lcolor.getX11HexName(Color_background);
1028 if (!shortcut.empty())
1029 lcolor.setColor(to_utf8(shortcut), color);
1032 } else if (token == "\\author") {
1034 istringstream ss(lex.getString());
1038 } else if (token == "\\paperorientation") {
1041 orientation = paperorientationtranslator().find(orient);
1042 } else if (token == "\\backgroundcolor") {
1044 backgroundcolor = lyx::rgbFromHexName(lex.getString());
1045 isbackgroundcolor = true;
1046 } else if (token == "\\fontcolor") {
1048 fontcolor = lyx::rgbFromHexName(lex.getString());
1050 } else if (token == "\\notefontcolor") {
1052 string color = lex.getString();
1053 notefontcolor = lyx::rgbFromHexName(color);
1054 lcolor.setColor("notefontcolor", color);
1055 lcolor.setLaTeXName("notefontcolor", "note_fontcolor");
1056 } else if (token == "\\boxbgcolor") {
1058 string color = lex.getString();
1059 boxbgcolor = lyx::rgbFromHexName(color);
1060 lcolor.setColor("boxbgcolor", color);
1061 } else if (token == "\\paperwidth") {
1063 } else if (token == "\\paperheight") {
1065 } else if (token == "\\leftmargin") {
1067 } else if (token == "\\topmargin") {
1069 } else if (token == "\\rightmargin") {
1071 } else if (token == "\\bottommargin") {
1072 lex >> bottommargin;
1073 } else if (token == "\\headheight") {
1075 } else if (token == "\\headsep") {
1077 } else if (token == "\\footskip") {
1079 } else if (token == "\\columnsep") {
1081 } else if (token == "\\paperfontsize") {
1083 } else if (token == "\\papercolumns") {
1085 } else if (token == "\\listings_params") {
1088 listings_params = InsetListingsParams(par).params();
1089 } else if (token == "\\papersides") {
1092 sides = sidestranslator().find(psides);
1093 } else if (token == "\\paperpagestyle") {
1095 } else if (token == "\\tablestyle") {
1097 } else if (token == "\\bullet") {
1099 } else if (token == "\\bulletLaTeX") {
1100 readBulletsLaTeX(lex);
1101 } else if (token == "\\secnumdepth") {
1103 } else if (token == "\\tocdepth") {
1105 } else if (token == "\\spacing") {
1109 if (nspacing == "other") {
1112 spacing().set(spacetranslator().find(nspacing), tmp_val);
1113 } else if (token == "\\float_placement") {
1114 lex >> float_placement;
1115 } else if (token == "\\float_alignment") {
1116 lex >> float_alignment;
1118 } else if (prefixIs(token, "\\pdf_") || token == "\\use_hyperref") {
1119 string toktmp = pdfoptions().readToken(lex, token);
1120 if (!toktmp.empty()) {
1121 lyxerr << "PDFOptions::readToken(): Unknown token: " <<
1125 } else if (token == "\\html_math_output") {
1128 html_math_output = static_cast<MathOutput>(temp);
1129 } else if (token == "\\html_be_strict") {
1130 lex >> html_be_strict;
1131 } else if (token == "\\html_css_as_file") {
1132 lex >> html_css_as_file;
1133 } else if (token == "\\html_math_img_scale") {
1134 lex >> html_math_img_scale;
1135 } else if (token == "\\html_latex_start") {
1137 html_latex_start = lex.getString();
1138 } else if (token == "\\html_latex_end") {
1140 html_latex_end = lex.getString();
1141 } else if (token == "\\docbook_table_output") {
1144 docbook_table_output = static_cast<TableOutput>(temp);
1145 } else if (token == "\\output_sync") {
1147 } else if (token == "\\output_sync_macro") {
1148 lex >> output_sync_macro;
1149 } else if (token == "\\use_refstyle") {
1150 lex >> use_refstyle;
1151 } else if (token == "\\use_minted") {
1153 } else if (token == "\\use_lineno") {
1155 } else if (token == "\\lineno_options") {
1157 lineno_opts = trim(lex.getString());
1159 lyxerr << "BufferParams::readToken(): Unknown token: " <<
1169 // Quote argument if it contains spaces
1170 string quoteIfNeeded(string const & str) {
1171 if (contains(str, ' '))
1172 return "\"" + str + "\"";
1178 void BufferParams::writeFile(ostream & os, Buffer const * buf) const
1180 // The top of the file is written by the buffer.
1181 // Prints out the buffer info into the .lyx file given by file
1183 os << "\\save_transient_properties "
1184 << convert<string>(save_transient_properties) << '\n';
1186 // the document directory (must end with a path separator)
1187 // realPath() is used to resolve symlinks, while addPath(..., "")
1188 // ensures a trailing path separator.
1190 string filepath = addPath(buf->fileName().onlyPath().realPath(), "");
1191 string const sysdir = inSystemDir(FileName(filepath), docsys) ? docsys
1192 : addPath(package().system_support().realPath(), "");
1193 string const relpath =
1194 to_utf8(makeRelPath(from_utf8(filepath), from_utf8(sysdir)));
1195 if (!prefixIs(relpath, "../") && !FileName::isAbsolute(relpath))
1196 filepath = addPath("/systemlyxdir", relpath);
1197 else if (!save_transient_properties || !lyxrc.save_origin)
1198 filepath = "unavailable";
1199 os << "\\origin " << quoteIfNeeded(filepath) << '\n';
1202 os << "\\textclass "
1203 << quoteIfNeeded(buf->includedFilePath(addName(buf->layoutPos(),
1204 baseClass()->name()), "layout"))
1207 // then the preamble
1208 if (!preamble.empty()) {
1209 // remove '\n' from the end of preamble
1210 docstring const tmppreamble = rtrim(preamble, "\n");
1211 os << "\\begin_preamble\n"
1212 << to_utf8(tmppreamble)
1213 << "\n\\end_preamble\n";
1217 if (!options.empty()) {
1218 os << "\\options " << options << '\n';
1221 // use the class options defined in the layout?
1222 os << "\\use_default_options "
1223 << convert<string>(use_default_options) << "\n";
1225 // the master document
1226 if (!master.empty()) {
1227 os << "\\master " << master << '\n';
1231 if (!removed_modules_.empty()) {
1232 os << "\\begin_removed_modules" << '\n';
1233 for (auto const & mod : removed_modules_)
1235 os << "\\end_removed_modules" << '\n';
1239 if (!layout_modules_.empty()) {
1240 os << "\\begin_modules" << '\n';
1241 for (auto const & mod : layout_modules_)
1243 os << "\\end_modules" << '\n';
1247 if (!included_children_.empty()) {
1248 os << "\\begin_includeonly" << '\n';
1249 for (auto const & c : included_children_)
1251 os << "\\end_includeonly" << '\n';
1254 switch (maintain_unincluded_children) {
1265 os << "\\maintain_unincluded_children " << muc << '\n';
1267 // local layout information
1268 docstring const local_layout = getLocalLayout(false);
1269 if (!local_layout.empty()) {
1270 // remove '\n' from the end
1271 docstring const tmplocal = rtrim(local_layout, "\n");
1272 os << "\\begin_local_layout\n"
1273 << to_utf8(tmplocal)
1274 << "\n\\end_local_layout\n";
1276 docstring const forced_local_layout = getLocalLayout(true);
1277 if (!forced_local_layout.empty()) {
1278 // remove '\n' from the end
1279 docstring const tmplocal = rtrim(forced_local_layout, "\n");
1280 os << "\\begin_forced_local_layout\n"
1281 << to_utf8(tmplocal)
1282 << "\n\\end_forced_local_layout\n";
1285 // then the text parameters
1286 if (language != ignore_language)
1287 os << "\\language " << language->lang() << '\n';
1288 os << "\\language_package " << lang_package
1289 << "\n\\inputencoding " << inputenc
1290 << "\n\\fontencoding " << fontenc
1291 << "\n\\font_roman \"" << fonts_roman[0]
1292 << "\" \"" << fonts_roman[1] << '"'
1293 << "\n\\font_sans \"" << fonts_sans[0]
1294 << "\" \"" << fonts_sans[1] << '"'
1295 << "\n\\font_typewriter \"" << fonts_typewriter[0]
1296 << "\" \"" << fonts_typewriter[1] << '"'
1297 << "\n\\font_math \"" << fonts_math[0]
1298 << "\" \"" << fonts_math[1] << '"'
1299 << "\n\\font_default_family " << fonts_default_family
1300 << "\n\\use_non_tex_fonts " << convert<string>(useNonTeXFonts)
1301 << "\n\\font_sc " << convert<string>(fonts_expert_sc)
1302 << "\n\\font_roman_osf " << convert<string>(fonts_roman_osf)
1303 << "\n\\font_sans_osf " << convert<string>(fonts_sans_osf)
1304 << "\n\\font_typewriter_osf " << convert<string>(fonts_typewriter_osf);
1305 if (!font_roman_opts.empty())
1306 os << "\n\\font_roman_opts \"" << font_roman_opts << "\"";
1307 os << "\n\\font_sf_scale " << fonts_sans_scale[0]
1308 << ' ' << fonts_sans_scale[1];
1309 if (!font_sans_opts.empty())
1310 os << "\n\\font_sans_opts \"" << font_sans_opts << "\"";
1311 os << "\n\\font_tt_scale " << fonts_typewriter_scale[0]
1312 << ' ' << fonts_typewriter_scale[1];
1313 if (!font_typewriter_opts.empty())
1314 os << "\n\\font_typewriter_opts \"" << font_typewriter_opts << "\"";
1316 if (!fonts_cjk.empty())
1317 os << "\\font_cjk " << fonts_cjk << '\n';
1318 os << "\\use_microtype " << convert<string>(use_microtype) << '\n';
1319 os << "\\use_dash_ligatures " << convert<string>(use_dash_ligatures) << '\n';
1320 os << "\\graphics " << graphics_driver << '\n';
1321 os << "\\default_output_format " << default_output_format << '\n';
1322 os << "\\output_sync " << output_sync << '\n';
1323 if (!output_sync_macro.empty())
1324 os << "\\output_sync_macro \"" << output_sync_macro << "\"\n";
1325 os << "\\bibtex_command " << bibtex_command << '\n';
1326 os << "\\index_command " << index_command << '\n';
1328 if (!float_placement.empty())
1329 os << "\\float_placement " << float_placement << '\n';
1330 if (!float_alignment.empty())
1331 os << "\\float_alignment " << float_alignment << '\n';
1332 os << "\\paperfontsize " << fontsize << '\n';
1334 spacing().writeFile(os);
1335 pdfoptions().writeFile(os);
1337 os << "\\papersize " << string_papersize[papersize]
1338 << "\n\\use_geometry " << convert<string>(use_geometry);
1339 map<string, string> const & packages = auto_packages();
1340 for (auto const & pack : packages)
1341 os << "\n\\use_package " << pack.first << ' '
1342 << use_package(pack.first);
1344 os << "\n\\cite_engine ";
1346 if (!cite_engine_.empty())
1351 os << "\n\\cite_engine_type " << theCiteEnginesList.getTypeAsString(cite_engine_type_);
1353 if (!biblio_style.empty())
1354 os << "\n\\biblio_style " << biblio_style;
1355 if (!biblio_opts.empty())
1356 os << "\n\\biblio_options " << biblio_opts;
1357 if (!biblatex_bibstyle.empty())
1358 os << "\n\\biblatex_bibstyle " << biblatex_bibstyle;
1359 if (!biblatex_citestyle.empty())
1360 os << "\n\\biblatex_citestyle " << biblatex_citestyle;
1361 if (!multibib.empty())
1362 os << "\n\\multibib " << multibib;
1364 os << "\n\\use_bibtopic " << convert<string>(use_bibtopic)
1365 << "\n\\use_indices " << convert<string>(use_indices)
1366 << "\n\\paperorientation " << string_orientation[orientation]
1367 << "\n\\suppress_date " << convert<string>(suppress_date)
1368 << "\n\\justification " << convert<string>(justification)
1369 << "\n\\use_refstyle " << use_refstyle
1370 << "\n\\use_minted " << use_minted
1371 << "\n\\use_lineno " << use_lineno
1374 if (!lineno_opts.empty())
1375 os << "\\lineno_options " << lineno_opts << '\n';
1377 if (isbackgroundcolor)
1378 os << "\\backgroundcolor " << lyx::X11hexname(backgroundcolor) << '\n';
1380 os << "\\fontcolor " << lyx::X11hexname(fontcolor) << '\n';
1381 if (notefontcolor != lyx::rgbFromHexName("#cccccc"))
1382 os << "\\notefontcolor " << lyx::X11hexname(notefontcolor) << '\n';
1383 if (boxbgcolor != lyx::rgbFromHexName("#ff0000"))
1384 os << "\\boxbgcolor " << lyx::X11hexname(boxbgcolor) << '\n';
1386 for (auto const & br : branchlist()) {
1387 os << "\\branch " << to_utf8(br.branch())
1388 << "\n\\selected " << br.isSelected()
1389 << "\n\\filename_suffix " << br.hasFileNameSuffix()
1390 << "\n\\color " << br.lightModeColor() << " " << br.darkModeColor()
1395 for (auto const & id : indiceslist()) {
1396 os << "\\index " << to_utf8(id.index())
1397 << "\n\\shortcut " << to_utf8(id.shortcut())
1398 << "\n\\color " << lyx::X11hexname(id.color())
1403 if (!paperwidth.empty())
1404 os << "\\paperwidth "
1405 << VSpace(paperwidth).asLyXCommand() << '\n';
1406 if (!paperheight.empty())
1407 os << "\\paperheight "
1408 << VSpace(paperheight).asLyXCommand() << '\n';
1409 if (!leftmargin.empty())
1410 os << "\\leftmargin "
1411 << VSpace(leftmargin).asLyXCommand() << '\n';
1412 if (!topmargin.empty())
1413 os << "\\topmargin "
1414 << VSpace(topmargin).asLyXCommand() << '\n';
1415 if (!rightmargin.empty())
1416 os << "\\rightmargin "
1417 << VSpace(rightmargin).asLyXCommand() << '\n';
1418 if (!bottommargin.empty())
1419 os << "\\bottommargin "
1420 << VSpace(bottommargin).asLyXCommand() << '\n';
1421 if (!headheight.empty())
1422 os << "\\headheight "
1423 << VSpace(headheight).asLyXCommand() << '\n';
1424 if (!headsep.empty())
1426 << VSpace(headsep).asLyXCommand() << '\n';
1427 if (!footskip.empty())
1429 << VSpace(footskip).asLyXCommand() << '\n';
1430 if (!columnsep.empty())
1431 os << "\\columnsep "
1432 << VSpace(columnsep).asLyXCommand() << '\n';
1433 os << "\\secnumdepth " << secnumdepth
1434 << "\n\\tocdepth " << tocdepth
1435 << "\n\\paragraph_separation "
1436 << string_paragraph_separation[paragraph_separation];
1437 if (!paragraph_separation)
1438 os << "\n\\paragraph_indentation "
1439 << (getParIndent().empty() ? "default" : getParIndent().asString());
1441 os << "\n\\defskip " << getDefSkip().asLyXCommand();
1442 os << "\n\\is_math_indent " << is_math_indent;
1444 os << "\n\\math_indentation "
1445 << (getMathIndent().empty() ? "default" : getMathIndent().asString());
1446 os << "\n\\math_numbering_side ";
1447 switch(math_numbering_side) {
1457 os << "\n\\quotes_style "
1458 << string_quotes_style[static_cast<int>(quotes_style)]
1459 << "\n\\dynamic_quotes " << dynamic_quotes
1460 << "\n\\papercolumns " << columns
1461 << "\n\\papersides " << sides
1462 << "\n\\paperpagestyle " << pagestyle
1463 << "\n\\tablestyle " << tablestyle << '\n';
1464 if (!listings_params.empty())
1465 os << "\\listings_params \"" <<
1466 InsetListingsParams(listings_params).encodedString() << "\"\n";
1467 for (int i = 0; i < 4; ++i) {
1468 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
1469 if (user_defined_bullet(i).getFont() != -1) {
1470 os << "\\bullet " << i << " "
1471 << user_defined_bullet(i).getFont() << " "
1472 << user_defined_bullet(i).getCharacter() << " "
1473 << user_defined_bullet(i).getSize() << "\n";
1477 os << "\\bulletLaTeX " << i << " \""
1478 << lyx::to_ascii(user_defined_bullet(i).getText())
1484 os << "\\tracking_changes "
1485 << (save_transient_properties ? convert<string>(track_changes) : "false")
1488 os << "\\output_changes "
1489 << (save_transient_properties ? convert<string>(output_changes) : "false")
1492 os << "\\change_bars "
1493 << (save_transient_properties ? convert<string>(change_bars) : "false")
1496 os << "\\postpone_fragile_content " << convert<string>(postpone_fragile_content) << '\n';
1498 os << "\\html_math_output " << html_math_output << '\n'
1499 << "\\html_css_as_file " << html_css_as_file << '\n'
1500 << "\\html_be_strict " << convert<string>(html_be_strict) << '\n';
1502 os << "\\docbook_table_output " << docbook_table_output << '\n';
1504 if (html_math_img_scale != 1.0)
1505 os << "\\html_math_img_scale " << convert<string>(html_math_img_scale) << '\n';
1506 if (!html_latex_start.empty())
1507 os << "\\html_latex_start " << html_latex_start << '\n';
1508 if (!html_latex_end.empty())
1509 os << "\\html_latex_end " << html_latex_end << '\n';
1511 os << pimpl_->authorlist;
1515 void BufferParams::validate(LaTeXFeatures & features) const
1517 features.require(documentClass().required());
1519 if (columns > 1 && language->rightToLeft())
1520 features.require("rtloutputdblcol");
1522 if (output_changes) {
1523 bool xcolorulem = LaTeXFeatures::isAvailable("ulem") &&
1524 LaTeXFeatures::isAvailable("xcolor");
1526 switch (features.runparams().flavor) {
1528 case Flavor::DviLuaTeX:
1530 features.require("ct-xcolor-ulem");
1531 features.require("ulem");
1532 features.require("xcolor");
1534 features.require("ct-none");
1537 case Flavor::LuaTeX:
1538 case Flavor::PdfLaTeX:
1541 features.require("ct-xcolor-ulem");
1542 features.require("ulem");
1543 features.require("xcolor");
1544 // improves color handling in PDF output
1545 features.require("pdfcolmk");
1547 features.require("ct-none");
1554 features.require("changebar");
1557 // Floats with 'Here definitely' as default setting.
1558 if (float_placement.find('H') != string::npos)
1559 features.require("float");
1561 for (auto const & pm : use_packages) {
1562 if (pm.first == "amsmath") {
1563 // AMS Style is at document level
1564 if (pm.second == package_on ||
1565 features.isProvided("amsmath"))
1566 features.require(pm.first);
1567 } else if (pm.second == package_on)
1568 features.require(pm.first);
1571 // Document-level line spacing
1572 if (spacing().getSpace() != Spacing::Single && !spacing().isDefault())
1573 features.require("setspace");
1575 // the bullet shapes are buffer level not paragraph level
1576 // so they are tested here
1577 for (int i = 0; i < 4; ++i) {
1578 if (user_defined_bullet(i) == ITEMIZE_DEFAULTS[i])
1580 int const font = user_defined_bullet(i).getFont();
1582 int const c = user_defined_bullet(i).getCharacter();
1588 features.require("latexsym");
1590 } else if (font == 1) {
1591 features.require("amssymb");
1592 } else if (font >= 2 && font <= 5) {
1593 features.require("pifont");
1597 if (pdfoptions().use_hyperref) {
1598 features.require("hyperref");
1599 // due to interferences with babel and hyperref, the color package has to
1600 // be loaded after hyperref when hyperref is used with the colorlinks
1601 // option, see http://www.lyx.org/trac/ticket/5291
1602 if (pdfoptions().colorlinks)
1603 features.require("color");
1605 if (!listings_params.empty()) {
1606 // do not test validity because listings_params is
1607 // supposed to be valid
1609 InsetListingsParams(listings_params).separatedParams(true);
1610 // we can't support all packages, but we should load the color package
1611 if (par.find("\\color", 0) != string::npos)
1612 features.require("color");
1615 // some languages are only available via polyglossia
1616 if (features.hasPolyglossiaExclusiveLanguages())
1617 features.require("polyglossia");
1619 if (useNonTeXFonts && fontsMath() != "auto")
1620 features.require("unicode-math");
1623 features.require("microtype");
1625 if (!language->required().empty())
1626 features.require(language->required());
1630 bool BufferParams::writeLaTeX(otexstream & os, LaTeXFeatures & features,
1631 FileName const & filepath) const
1633 // http://www.tug.org/texmf-dist/doc/latex/base/fixltx2e.pdf
1634 // !! To use the Fix-cm package, load it before \documentclass, and use the command
1635 // \RequirePackage to do so, rather than the normal \usepackage
1636 // Do not try to load any other package before the document class, unless you
1637 // have a thorough understanding of the LATEX internals and know exactly what you
1639 if (features.mustProvide("fix-cm"))
1640 os << "\\RequirePackage{fix-cm}\n";
1641 // Likewise for fixltx2e. If other packages conflict with this policy,
1642 // treat it as a package bug (and report it!)
1643 // See http://www.latex-project.org/cgi-bin/ltxbugs2html?pr=latex/4407
1644 if (features.mustProvide("fixltx2e"))
1645 os << "\\RequirePackage{fixltx2e}\n";
1647 os << "\\documentclass";
1649 DocumentClass const & tclass = documentClass();
1651 ostringstream clsoptions; // the document class options.
1653 if (tokenPos(tclass.opt_fontsize(),
1654 '|', fontsize) >= 0) {
1655 // only write if existing in list (and not default)
1656 clsoptions << subst(tclass.fontsizeformat(), "$$s", fontsize) << ",";
1659 // paper sizes not supported by the class itself need the
1661 vector<string> classpsizes = getVectorFromString(tclass.opt_pagesize(), "|");
1662 bool class_supported_papersize = papersize == PAPER_DEFAULT
1663 || find(classpsizes.begin(), classpsizes.end(), string_papersize[papersize]) != classpsizes.end();
1665 if ((!use_geometry || features.isProvided("geometry-light"))
1666 && class_supported_papersize && papersize != PAPER_DEFAULT)
1667 clsoptions << subst(tclass.pagesizeformat(), "$$s", string_papersize[papersize]) << ",";
1670 if (sides != tclass.sides()) {
1673 clsoptions << "oneside,";
1676 clsoptions << "twoside,";
1682 if (columns != tclass.columns()) {
1684 clsoptions << "twocolumn,";
1686 clsoptions << "onecolumn,";
1690 && orientation == ORIENTATION_LANDSCAPE)
1691 clsoptions << "landscape,";
1694 clsoptions << "fleqn,";
1696 switch(math_numbering_side) {
1698 clsoptions << "leqno,";
1701 clsoptions << "reqno,";
1702 features.require("amsmath");
1708 // language should be a parameter to \documentclass
1709 if (language->babel() == "hebrew"
1710 && default_language->babel() != "hebrew")
1711 // This seems necessary
1712 features.useLanguage(default_language);
1714 ostringstream language_options;
1715 bool const use_babel = features.useBabel() && !features.isProvided("babel");
1716 bool const use_polyglossia = features.usePolyglossia();
1717 bool const global = lyxrc.language_global_options;
1718 if (features.useBabel() || (use_polyglossia && global)) {
1719 language_options << features.getBabelLanguages();
1720 if (!language->babel().empty()) {
1721 if (!language_options.str().empty())
1722 language_options << ',';
1723 language_options << language->babel();
1725 if (global && !language_options.str().empty())
1726 clsoptions << language_options.str() << ',';
1729 // the predefined options from the layout
1730 if (use_default_options && !tclass.options().empty())
1731 clsoptions << tclass.options() << ',';
1733 // the user-defined options
1734 if (!options.empty()) {
1735 clsoptions << options << ',';
1738 docstring const strOptions = from_utf8(clsoptions.str());
1739 if (!strOptions.empty()) {
1740 // Check if class options contain uncodable glyphs
1741 docstring uncodable_glyphs;
1742 docstring options_encodable;
1743 Encoding const * const enc = features.runparams().encoding;
1745 for (char_type c : strOptions) {
1746 if (!enc->encodable(c)) {
1747 docstring const glyph(1, c);
1748 LYXERR0("Uncodable character '"
1750 << "' in class options!");
1751 uncodable_glyphs += glyph;
1752 if (features.runparams().dryrun) {
1753 options_encodable += "<" + _("LyX Warning: ")
1754 + _("uncodable character") + " '";
1755 options_encodable += c;
1756 options_encodable += "'>";
1759 options_encodable += c;
1762 options_encodable = strOptions;
1764 // On BUFFER_VIEW|UPDATE, warn user if we found uncodable glyphs
1765 if (!features.runparams().dryrun && !uncodable_glyphs.empty()) {
1766 frontend::Alert::warning(
1767 _("Uncodable character in class options"),
1769 _("The class options of your document contain glyphs "
1770 "that are unknown in the current document encoding "
1771 "(namely %1$s).\nThese glyphs are omitted "
1772 " from the output, which may result in "
1773 "incomplete output."
1774 "\n\nPlease select an appropriate "
1775 "document encoding\n"
1776 "(such as utf8) or change the "
1777 "class options accordingly."),
1780 options_encodable = rtrim(options_encodable, ",");
1781 os << '[' << options_encodable << ']';
1784 os << '{' << from_ascii(tclass.latexname()) << "}\n";
1785 // end of \documentclass defs
1787 // The package options (via \PassOptionsToPackage)
1788 os << from_ascii(features.getPackageOptions());
1790 // if we use fontspec or newtxmath, we have to load the AMS packages here
1791 string const ams = features.loadAMSPackages();
1792 bool const ot1 = (main_font_encoding() == "default" || main_font_encoding() == "OT1");
1793 bool const use_newtxmath =
1794 theLaTeXFonts().getLaTeXFont(from_ascii(fontsMath())).getUsedPackage(
1795 ot1, false, false) == "newtxmath";
1796 if ((useNonTeXFonts || use_newtxmath) && !ams.empty())
1797 os << from_ascii(ams);
1799 if (useNonTeXFonts) {
1800 // Babel (as of 2017/11/03) loads fontspec itself
1801 if (!features.isProvided("fontspec")
1802 && !(features.useBabel() && features.isAvailable("babel-2017/11/03")))
1803 os << "\\usepackage{fontspec}\n";
1804 if (features.mustProvide("unicode-math")
1805 && features.isAvailable("unicode-math"))
1806 os << "\\usepackage{unicode-math}\n";
1809 // load CJK support package before font selection
1810 // (see autotests/export/latex/CJK/micro-sign_utf8-cjk-libertine.lyx)
1811 if (!useNonTeXFonts && encoding().package() != Encoding::none && inputenc != "utf8x"
1812 && (encoding().package() == Encoding::CJK || features.mustProvide("CJK"))) {
1813 if (inputenc == "utf8-cjk" || inputenc == "utf8")
1814 os << "\\usepackage{CJKutf8}\n";
1816 os << "\\usepackage[encapsulated]{CJK}\n";
1819 // font selection must be done before loading fontenc.sty
1820 // but after babel with non-TeX fonts
1821 string const fonts = loadFonts(features);
1822 if (!fonts.empty() && (!features.useBabel() || !useNonTeXFonts))
1823 os << from_utf8(fonts);
1825 if (fonts_default_family != "default")
1826 os << "\\renewcommand{\\familydefault}{\\"
1827 << from_ascii(fonts_default_family) << "}\n";
1829 // set font encoding
1830 // non-TeX fonts use font encoding TU (set by fontspec)
1831 if (!useNonTeXFonts && !features.isProvided("fontenc")
1832 && main_font_encoding() != "default") {
1833 // get main font encodings
1834 vector<string> fontencs = font_encodings();
1835 // get font encodings of secondary languages
1836 // FIXME: some languages (hebrew, ...) assume a standard font encoding as last
1837 // option (for text in other languages).
1838 features.getFontEncodings(fontencs);
1839 if (!fontencs.empty()) {
1840 os << "\\usepackage["
1841 << from_ascii(getStringFromVector(fontencs))
1846 // Load textcomp and pmboxdraw before (lua)inputenc (#11454)
1847 if (features.mustProvide("textcomp"))
1848 os << "\\usepackage{textcomp}\n";
1849 if (features.mustProvide("pmboxdraw"))
1850 os << "\\usepackage{pmboxdraw}\n";
1852 // handle inputenc etc.
1853 // (In documents containing text in Thai language,
1854 // we must load inputenc after babel, see lib/languages).
1855 if (!contains(features.getBabelPostsettings(), from_ascii("thai.ldf")))
1856 writeEncodingPreamble(os, features);
1859 if (!features.runparams().includeall && !included_children_.empty()) {
1860 os << "\\includeonly{";
1862 for (auto incfile : included_children_) {
1863 FileName inc = makeAbsPath(incfile, filepath.absFileName());
1864 string mangled = DocFileName(changeExtension(inc.absFileName(), ".tex")).
1866 if (!features.runparams().nice)
1868 // \includeonly doesn't want an extension
1869 incfile = changeExtension(incfile, string());
1870 incfile = support::latex_path(incfile);
1871 if (!incfile.empty()) {
1874 os << from_utf8(incfile);
1881 if (!features.isProvided("geometry")
1882 && (use_geometry || !class_supported_papersize)) {
1883 odocstringstream ods;
1884 if (!getGraphicsDriver("geometry").empty())
1885 ods << getGraphicsDriver("geometry");
1886 if (orientation == ORIENTATION_LANDSCAPE)
1887 ods << ",landscape";
1888 switch (papersize) {
1890 if (!paperwidth.empty())
1891 ods << ",paperwidth="
1892 << from_ascii(paperwidth);
1893 if (!paperheight.empty())
1894 ods << ",paperheight="
1895 << from_ascii(paperheight);
1897 case PAPER_USLETTER:
1899 case PAPER_USEXECUTIVE:
1928 ods << "," << from_ascii(string_papersize_geometry[papersize]);
1933 docstring g_options = trim(ods.str(), ",");
1934 os << "\\usepackage";
1935 // geometry-light means that the class works with geometry, but overwrites
1936 // the package options and paper sizes (memoir does this).
1937 // In this case, all options need to go to \geometry
1938 // and the standard paper sizes need to go to the class options.
1939 if (!g_options.empty() && !features.isProvided("geometry-light")) {
1940 os << '[' << g_options << ']';
1943 os << "{geometry}\n";
1944 if (use_geometry || features.isProvided("geometry-light")) {
1945 os << "\\geometry{verbose";
1946 if (!g_options.empty())
1947 // Output general options here with "geometry light".
1948 os << "," << g_options;
1949 // output this only if use_geometry is true
1951 if (!topmargin.empty())
1952 os << ",tmargin=" << from_ascii(Length(topmargin).asLatexString());
1953 if (!bottommargin.empty())
1954 os << ",bmargin=" << from_ascii(Length(bottommargin).asLatexString());
1955 if (!leftmargin.empty())
1956 os << ",lmargin=" << from_ascii(Length(leftmargin).asLatexString());
1957 if (!rightmargin.empty())
1958 os << ",rmargin=" << from_ascii(Length(rightmargin).asLatexString());
1959 if (!headheight.empty())
1960 os << ",headheight=" << from_ascii(Length(headheight).asLatexString());
1961 if (!headsep.empty())
1962 os << ",headsep=" << from_ascii(Length(headsep).asLatexString());
1963 if (!footskip.empty())
1964 os << ",footskip=" << from_ascii(Length(footskip).asLatexString());
1965 if (!columnsep.empty())
1966 os << ",columnsep=" << from_ascii(Length(columnsep).asLatexString());
1970 } else if (orientation == ORIENTATION_LANDSCAPE
1971 || papersize != PAPER_DEFAULT) {
1972 features.require("papersize");
1975 if (tokenPos(tclass.opt_pagestyle(), '|', pagestyle) >= 0) {
1976 if (pagestyle == "fancy")
1977 os << "\\usepackage{fancyhdr}\n";
1978 os << "\\pagestyle{" << from_ascii(pagestyle) << "}\n";
1981 // only output when the background color is not default
1982 if (isbackgroundcolor) {
1983 // only require color here, the background color will be defined
1984 // in LaTeXFeatures.cpp to avoid interferences with the LaTeX
1986 features.require("color");
1987 features.require("pagecolor");
1990 // only output when the font color is not default
1992 // only require color here, the font color will be defined
1993 // in LaTeXFeatures.cpp to avoid interferences with the LaTeX
1995 features.require("color");
1996 features.require("fontcolor");
1999 // Only if class has a ToC hierarchy
2000 if (tclass.hasTocLevels()) {
2001 if (secnumdepth != tclass.secnumdepth()) {
2002 os << "\\setcounter{secnumdepth}{"
2006 if (tocdepth != tclass.tocdepth()) {
2007 os << "\\setcounter{tocdepth}{"
2013 if (paragraph_separation) {
2014 // when skip separation
2016 switch (getDefSkip().kind()) {
2017 case VSpace::SMALLSKIP:
2018 psopt = "\\smallskipamount";
2020 case VSpace::MEDSKIP:
2021 psopt = "\\medskipamount";
2023 case VSpace::BIGSKIP:
2024 psopt = "\\bigskipamount";
2026 case VSpace::HALFLINE:
2027 // default (no option)
2029 case VSpace::FULLLINE:
2030 psopt = "\\baselineskip";
2032 case VSpace::LENGTH:
2033 psopt = getDefSkip().length().asLatexString();
2038 if (!features.isProvided("parskip")) {
2040 psopt = "[skip=" + psopt + "]";
2041 os << "\\usepackage" + psopt + "{parskip}\n";
2043 os << "\\setlength{\\parskip}{" + psopt + "}\n";
2046 // when separation by indentation
2047 // only output something when a width is given
2048 if (!getParIndent().empty()) {
2049 os << "\\setlength{\\parindent}{"
2050 << from_utf8(getParIndent().asLatexString())
2055 if (is_math_indent) {
2056 // when formula indentation
2057 // only output something when it is not the default
2058 if (!getMathIndent().empty()) {
2059 os << "\\setlength{\\mathindent}{"
2060 << from_utf8(getMathIndent().asString())
2065 // Now insert the LyX specific LaTeX commands...
2066 features.resolveAlternatives();
2067 features.expandMultiples();
2070 if (!output_sync_macro.empty())
2071 os << from_utf8(output_sync_macro) +"\n";
2072 else if (features.runparams().flavor == Flavor::LaTeX)
2073 os << "\\usepackage[active]{srcltx}\n";
2074 else if (features.runparams().flavor == Flavor::PdfLaTeX)
2075 os << "\\synctex=-1\n";
2078 // due to interferences with babel and hyperref, the color package has to
2079 // be loaded (when it is not already loaded) before babel when hyperref
2080 // is used with the colorlinks option, see
2081 // http://www.lyx.org/trac/ticket/5291
2082 // we decided therefore to load color always before babel, see
2083 // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg144349.html
2084 os << from_ascii(features.getColorOptions());
2086 // If we use hyperref, jurabib, japanese or varioref,
2087 // we have to call babel before
2089 && (features.isRequired("jurabib")
2090 || features.isRequired("hyperref")
2091 || features.isRequired("varioref")
2092 || features.isRequired("japanese"))) {
2093 os << features.getBabelPresettings();
2095 os << from_utf8(babelCall(language_options.str(),
2096 !lyxrc.language_global_options)) + '\n';
2097 os << features.getBabelPostsettings();
2100 // The optional packages;
2101 os << from_ascii(features.getPackages());
2103 // Additional Indices
2104 if (features.isRequired("splitidx")) {
2105 for (auto const & idx : indiceslist()) {
2106 os << "\\newindex{";
2107 os << escape(idx.shortcut());
2113 os << from_utf8(spacing().writePreamble(features.isProvided("SetSpace")));
2116 // * Hyperref manual: "Make sure it comes last of your loaded
2117 // packages, to give it a fighting chance of not being over-written,
2118 // since its job is to redefine many LaTeX commands."
2119 // * Email from Heiko Oberdiek: "It is usually better to load babel
2120 // before hyperref. Then hyperref has a chance to detect babel.
2121 // * Has to be loaded before the "LyX specific LaTeX commands" to
2122 // avoid errors with algorithm floats.
2123 // use hyperref explicitly if it is required
2124 if (features.isRequired("hyperref")) {
2125 OutputParams tmp_params = features.runparams();
2126 pdfoptions().writeLaTeX(tmp_params, os,
2127 features.isProvided("hyperref"));
2128 // correctly break URLs with hyperref and dvi/ps output
2129 if (features.runparams().hyperref_driver == "dvips"
2130 && features.isAvailable("breakurl"))
2131 os << "\\usepackage{breakurl}\n";
2132 } else if (features.isRequired("nameref"))
2133 // hyperref loads this automatically
2134 os << "\\usepackage{nameref}\n";
2137 os << "\\usepackage";
2138 if (!lineno_opts.empty())
2139 os << "[" << lineno_opts << "]";
2141 os << "\\linenumbers\n";
2144 // bibtopic needs to be loaded after hyperref.
2145 // the dot provides the aux file naming which LyX can detect.
2146 if (features.mustProvide("bibtopic"))
2147 os << "\\usepackage[dot]{bibtopic}\n";
2149 // Will be surrounded by \makeatletter and \makeatother when not empty
2150 otexstringstream atlyxpreamble;
2152 // Some macros LyX will need
2154 TexString tmppreamble = features.getMacros();
2155 if (!tmppreamble.str.empty())
2156 atlyxpreamble << "\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
2157 "LyX specific LaTeX commands.\n"
2158 << move(tmppreamble)
2161 // the text class specific preamble
2163 docstring tmppreamble = features.getTClassPreamble();
2164 if (!tmppreamble.empty())
2165 atlyxpreamble << "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
2166 "Textclass specific LaTeX commands.\n"
2170 // suppress date if selected
2171 // use \@ifundefined because we cannot be sure that every document class
2172 // has a \date command
2174 atlyxpreamble << "\\@ifundefined{date}{}{\\date{}}\n";
2176 /* the user-defined preamble */
2177 if (!containsOnly(preamble, " \n\t")) {
2179 atlyxpreamble << "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
2180 "User specified LaTeX commands.\n";
2182 // Check if the user preamble contains uncodable glyphs
2183 odocstringstream user_preamble;
2184 docstring uncodable_glyphs;
2185 Encoding const * const enc = features.runparams().encoding;
2187 for (char_type c : preamble) {
2188 if (!enc->encodable(c)) {
2189 docstring const glyph(1, c);
2190 LYXERR0("Uncodable character '"
2192 << "' in user preamble!");
2193 uncodable_glyphs += glyph;
2194 if (features.runparams().dryrun) {
2195 user_preamble << "<" << _("LyX Warning: ")
2196 << _("uncodable character") << " '";
2197 user_preamble.put(c);
2198 user_preamble << "'>";
2201 user_preamble.put(c);
2204 user_preamble << preamble;
2206 // On BUFFER_VIEW|UPDATE, warn user if we found uncodable glyphs
2207 if (!features.runparams().dryrun && !uncodable_glyphs.empty()) {
2208 frontend::Alert::warning(
2209 _("Uncodable character in user preamble"),
2211 _("The user preamble of your document contains glyphs "
2212 "that are unknown in the current document encoding "
2213 "(namely %1$s).\nThese glyphs are omitted "
2214 " from the output, which may result in "
2215 "incomplete output."
2216 "\n\nPlease select an appropriate "
2217 "document encoding\n"
2218 "(such as utf8) or change the "
2219 "preamble code accordingly."),
2222 atlyxpreamble << user_preamble.str() << '\n';
2225 // footmisc must be loaded after setspace
2226 // Load it here to avoid clashes with footmisc loaded in the user
2227 // preamble. For that reason we also pass the options via
2228 // \PassOptionsToPackage in getPreamble() and not here.
2229 if (features.mustProvide("footmisc"))
2230 atlyxpreamble << "\\usepackage{footmisc}\n";
2232 // subfig loads internally the LaTeX package "caption". As
2233 // caption is a very popular package, users will load it in
2234 // the preamble. Therefore we must load subfig behind the
2235 // user-defined preamble and check if the caption package was
2236 // loaded or not. For the case that caption is loaded before
2237 // subfig, there is the subfig option "caption=false". This
2238 // option also works when a koma-script class is used and
2239 // koma's own caption commands are used instead of caption. We
2240 // use \PassOptionsToPackage here because the user could have
2241 // already loaded subfig in the preamble.
2242 if (features.mustProvide("subfig"))
2243 atlyxpreamble << "\\ifdefined\\showcaptionsetup\n"
2244 " % Caption package is used. Advise subfig not to load it again.\n"
2245 " \\PassOptionsToPackage{caption=false}{subfig}\n"
2247 "\\usepackage{subfig}\n";
2249 // Itemize bullet settings need to be last in case the user
2250 // defines their own bullets that use a package included
2251 // in the user-defined preamble -- ARRae
2252 // Actually it has to be done much later than that
2253 // since some packages like frenchb make modifications
2254 // at \begin{document} time -- JMarc
2255 docstring bullets_def;
2256 for (int i = 0; i < 4; ++i) {
2257 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
2258 if (bullets_def.empty())
2259 bullets_def += "\\AtBeginDocument{\n";
2260 bullets_def += " \\def\\labelitemi";
2262 // `i' is one less than the item to modify
2269 bullets_def += "ii";
2275 bullets_def += '{' +
2276 user_defined_bullet(i).getText()
2281 if (!bullets_def.empty())
2282 atlyxpreamble << bullets_def << "}\n\n";
2284 if (!atlyxpreamble.empty())
2285 os << "\n\\makeatletter\n"
2286 << atlyxpreamble.release()
2287 << "\\makeatother\n\n";
2289 // We try to load babel late, in case it interferes with other packages.
2290 // Jurabib, hyperref, varioref, bicaption, menukeys and listings (bug 8995)
2291 // have to be called after babel, though.
2292 if (use_babel && !features.isRequired("jurabib")
2293 && !features.isRequired("hyperref")
2294 && !features.isRequired("varioref")
2295 && !features.isRequired("japanese")) {
2296 os << features.getBabelPresettings();
2298 os << from_utf8(babelCall(language_options.str(),
2299 !lyxrc.language_global_options)) + '\n';
2300 os << features.getBabelPostsettings();
2302 // In documents containing text in Thai language,
2303 // we must load inputenc after babel (see lib/languages).
2304 if (contains(features.getBabelPostsettings(), from_ascii("thai.ldf")))
2305 writeEncodingPreamble(os, features);
2307 // font selection must be done after babel with non-TeX fonts
2308 if (!fonts.empty() && features.useBabel() && useNonTeXFonts)
2309 os << from_utf8(fonts);
2311 if (features.isRequired("bicaption"))
2312 os << "\\usepackage{bicaption}\n";
2313 if (!listings_params.empty()
2314 || features.mustProvide("listings")
2315 || features.mustProvide("minted")) {
2317 os << "\\usepackage{minted}\n";
2319 os << "\\usepackage{listings}\n";
2321 string lst_params = listings_params;
2322 // If minted, do not output the language option (bug 11203)
2323 if (use_minted && contains(lst_params, "language=")) {
2324 vector<string> opts =
2325 getVectorFromString(lst_params, ",", false);
2326 for (size_t i = 0; i < opts.size(); ++i) {
2327 if (prefixIs(opts[i], "language="))
2328 opts.erase(opts.begin() + i--);
2330 lst_params = getStringFromVector(opts, ",");
2332 if (!lst_params.empty()) {
2334 os << "\\setminted{";
2337 // do not test validity because listings_params is
2338 // supposed to be valid
2340 InsetListingsParams(lst_params).separatedParams(true);
2341 os << from_utf8(par);
2345 // xunicode only needs to be loaded if tipa is used
2346 // (the rest is obsoleted by the new TU encoding).
2347 // It needs to be loaded at least after amsmath, amssymb,
2348 // esint and the other packages that provide special glyphs
2349 if (features.mustProvide("tipa") && useNonTeXFonts
2350 && !features.isProvided("xunicode")) {
2351 // The `xunicode` package officially only supports XeTeX,
2352 // but also works with LuaTeX. We work around its XeTeX test.
2353 if (features.runparams().flavor != Flavor::XeTeX) {
2354 os << "% Pretend to xunicode that we are XeTeX\n"
2355 << "\\def\\XeTeXpicfile{}\n";
2357 os << "\\usepackage{xunicode}\n";
2360 // covington must be loaded after beamerarticle
2361 if (features.isRequired("covington"))
2362 os << "\\usepackage{covington}\n";
2364 // Polyglossia must be loaded last ...
2365 if (use_polyglossia) {
2367 os << "\\usepackage{polyglossia}\n";
2368 // set the main language
2369 os << "\\setdefaultlanguage";
2370 if (!language->polyglossiaOpts().empty())
2371 os << "[" << from_ascii(language->polyglossiaOpts()) << "]";
2372 os << "{" << from_ascii(language->polyglossia()) << "}\n";
2373 // now setup the other languages
2374 set<string> const polylangs =
2375 features.getPolyglossiaLanguages();
2376 for (auto const & pl : polylangs) {
2377 // We do not output the options here; they are output in
2378 // the language switch commands. This is safer if multiple
2379 // varieties are used.
2380 if (pl == language->polyglossia())
2382 os << "\\setotherlanguage";
2383 os << "{" << from_ascii(pl) << "}\n";
2387 // ... but before biblatex (see #7065)
2388 if ((features.mustProvide("biblatex")
2389 || features.isRequired("biblatex-chicago"))
2390 && !features.isProvided("biblatex-chicago")
2391 && !features.isProvided("biblatex-natbib")
2392 && !features.isProvided("natbib-internal")
2393 && !features.isProvided("natbib")
2394 && !features.isProvided("jurabib")) {
2395 // The biblatex-chicago package has a differing interface
2396 // it uses a wrapper package and loads styles via fixed options
2397 bool const chicago = features.isRequired("biblatex-chicago");
2400 os << "\\usepackage";
2401 if (!biblatex_bibstyle.empty()
2402 && (biblatex_bibstyle == biblatex_citestyle)
2404 opts = "style=" + biblatex_bibstyle;
2406 } else if (!chicago) {
2407 if (!biblatex_bibstyle.empty()) {
2408 opts = "bibstyle=" + biblatex_bibstyle;
2411 if (!biblatex_citestyle.empty()) {
2412 opts += delim + "citestyle=" + biblatex_citestyle;
2416 if (!multibib.empty() && multibib != "child") {
2417 opts += delim + "refsection=" + multibib;
2420 if (bibtexCommand() == "bibtex8"
2421 || prefixIs(bibtexCommand(), "bibtex8 ")) {
2422 opts += delim + "backend=bibtex8";
2424 } else if (bibtexCommand() == "bibtex"
2425 || prefixIs(bibtexCommand(), "bibtex ")) {
2426 opts += delim + "backend=bibtex";
2429 if (!bib_encoding.empty() && encodings.fromLyXName(bib_encoding)) {
2430 opts += delim + "bibencoding="
2431 + encodings.fromLyXName(bib_encoding)->latexName();
2434 if (!biblio_opts.empty())
2435 opts += delim + biblio_opts;
2437 os << "[" << opts << "]";
2439 os << "{biblatex-chicago}\n";
2441 os << "{biblatex}\n";
2445 // Load custom language package here
2446 if (features.langPackage() == LaTeXFeatures::LANG_PACK_CUSTOM) {
2447 if (lang_package == "default")
2448 os << from_utf8(lyxrc.language_custom_package);
2450 os << from_utf8(lang_package);
2454 // Since menukeys uses catoptions, which does some heavy changes on key-value options,
2455 // it is recommended to load menukeys as the last package (even after hyperref)
2456 if (features.isRequired("menukeys"))
2457 os << "\\usepackage{menukeys}\n";
2459 docstring const i18npreamble =
2460 features.getTClassI18nPreamble(use_babel, use_polyglossia,
2462 if (!i18npreamble.empty())
2463 os << i18npreamble + '\n';
2469 void BufferParams::useClassDefaults()
2471 DocumentClass const & tclass = documentClass();
2473 sides = tclass.sides();
2474 columns = tclass.columns();
2475 pagestyle = tclass.pagestyle();
2476 tablestyle = tclass.tablestyle();
2477 use_default_options = true;
2478 // Only if class has a ToC hierarchy
2479 if (tclass.hasTocLevels()) {
2480 secnumdepth = tclass.secnumdepth();
2481 tocdepth = tclass.tocdepth();
2486 bool BufferParams::hasClassDefaults() const
2488 DocumentClass const & tclass = documentClass();
2490 return sides == tclass.sides()
2491 && columns == tclass.columns()
2492 && pagestyle == tclass.pagestyle()
2493 && tablestyle == tclass.tablestyle()
2494 && use_default_options
2495 && secnumdepth == tclass.secnumdepth()
2496 && tocdepth == tclass.tocdepth();
2500 DocumentClass const & BufferParams::documentClass() const
2506 DocumentClassConstPtr BufferParams::documentClassPtr() const
2512 void BufferParams::setDocumentClass(DocumentClassConstPtr tc)
2514 // evil, but this function is evil
2515 doc_class_ = const_pointer_cast<DocumentClass>(tc);
2516 invalidateConverterCache();
2520 bool BufferParams::setBaseClass(string const & classname, string const & path)
2522 LYXERR(Debug::TCLASS, "setBaseClass: " << classname);
2523 LayoutFileList & bcl = LayoutFileList::get();
2524 if (!bcl.haveClass(classname)) {
2526 bformat(_("The layout file:\n"
2528 "could not be found. A default textclass with default\n"
2529 "layouts will be used. LyX will not be able to produce\n"
2531 from_utf8(classname));
2532 frontend::Alert::error(_("Document class not found"), s);
2533 bcl.addEmptyClass(classname);
2536 bool const success = bcl[classname].load(path);
2539 bformat(_("Due to some error in it, the layout file:\n"
2541 "could not be loaded. A default textclass with default\n"
2542 "layouts will be used. LyX will not be able to produce\n"
2544 from_utf8(classname));
2545 frontend::Alert::error(_("Could not load class"), s);
2546 bcl.addEmptyClass(classname);
2549 pimpl_->baseClass_ = classname;
2550 layout_modules_.adaptToBaseClass(baseClass(), removed_modules_);
2555 LayoutFile const * BufferParams::baseClass() const
2557 if (LayoutFileList::get().haveClass(pimpl_->baseClass_))
2558 return &(LayoutFileList::get()[pimpl_->baseClass_]);
2564 LayoutFileIndex const & BufferParams::baseClassID() const
2566 return pimpl_->baseClass_;
2570 void BufferParams::makeDocumentClass(bool clone, bool internal)
2575 invalidateConverterCache();
2576 LayoutModuleList mods;
2577 for (auto const & mod : layout_modules_)
2578 mods.push_back(mod);
2580 doc_class_ = getDocumentClass(*baseClass(), mods, cite_engine_, clone, internal);
2582 TextClass::ReturnValues success = TextClass::OK;
2583 if (!forced_local_layout_.empty())
2584 success = doc_class_->read(to_utf8(forced_local_layout_),
2586 if (!local_layout_.empty() &&
2587 (success == TextClass::OK || success == TextClass::OK_OLDFORMAT))
2588 success = doc_class_->read(to_utf8(local_layout_), TextClass::MODULE);
2589 if (success != TextClass::OK && success != TextClass::OK_OLDFORMAT) {
2590 docstring const msg = _("Error reading internal layout information");
2591 frontend::Alert::warning(_("Read Error"), msg);
2596 bool BufferParams::layoutModuleCanBeAdded(string const & modName) const
2598 return layout_modules_.moduleCanBeAdded(modName, baseClass());
2602 docstring BufferParams::getLocalLayout(bool forced) const
2605 return from_utf8(doc_class_->forcedLayouts());
2607 return local_layout_;
2611 void BufferParams::setLocalLayout(docstring const & layout, bool forced)
2614 forced_local_layout_ = layout;
2616 local_layout_ = layout;
2620 bool BufferParams::addLayoutModule(string const & modName)
2622 for (auto const & mod : layout_modules_)
2625 layout_modules_.push_back(modName);
2630 string BufferParams::bufferFormat() const
2632 return documentClass().outputFormat();
2636 bool BufferParams::isExportable(string const & format, bool need_viewable) const
2638 FormatList const & formats = exportableFormats(need_viewable);
2639 for (auto const & fmt : formats) {
2640 if (fmt->name() == format)
2647 FormatList const & BufferParams::exportableFormats(bool only_viewable) const
2649 FormatList & cached = only_viewable ?
2650 pimpl_->viewableFormatList : pimpl_->exportableFormatList;
2651 bool & valid = only_viewable ?
2652 pimpl_->isViewCacheValid : pimpl_->isExportCacheValid;
2656 vector<string> const backs = backends();
2657 set<string> excludes;
2658 if (useNonTeXFonts) {
2659 excludes.insert("latex");
2660 excludes.insert("pdflatex");
2661 } else if (inputenc != "ascii" && inputenc != "utf8-plain") {
2662 // XeTeX with TeX fonts requires input encoding ascii (#10600).
2663 excludes.insert("xetex");
2667 theConverters().getReachable(backs[0], only_viewable, true, excludes);
2668 vector<string>::const_iterator it = backs.begin() + 1;
2669 for (; it != backs.end(); ++it) {
2670 FormatList r = theConverters().getReachable(*it, only_viewable,
2672 result.insert(result.end(), r.begin(), r.end());
2674 sort(result.begin(), result.end(), Format::formatSorter);
2681 vector<string> BufferParams::backends() const
2684 string const buffmt = bufferFormat();
2686 // FIXME: Don't hardcode format names here, but use a flag
2687 if (buffmt == "latex") {
2688 if (encoding().package() == Encoding::japanese)
2689 v.push_back("platex");
2691 if (!useNonTeXFonts) {
2692 v.push_back("pdflatex");
2693 v.push_back("latex");
2696 || inputenc == "ascii" || inputenc == "utf8-plain")
2697 v.push_back("xetex");
2698 v.push_back("luatex");
2699 v.push_back("dviluatex");
2702 string rbuffmt = buffmt;
2703 // If we use an OutputFormat in Japanese docs,
2704 // we need special format in order to get the path
2705 // via pLaTeX (#8823)
2706 if (documentClass().hasOutputFormat()
2707 && encoding().package() == Encoding::japanese)
2709 v.push_back(rbuffmt);
2712 v.push_back("xhtml");
2713 v.push_back("docbook5");
2714 v.push_back("text");
2720 Flavor BufferParams::getOutputFlavor(string const & format) const
2722 string const dformat = (format.empty() || format == "default") ?
2723 getDefaultOutputFormat() : format;
2724 DefaultFlavorCache::const_iterator it =
2725 default_flavors_.find(dformat);
2727 if (it != default_flavors_.end())
2730 Flavor result = Flavor::LaTeX;
2732 // FIXME It'd be better not to hardcode this, but to do
2733 // something with formats.
2734 if (dformat == "xhtml")
2735 result = Flavor::Html;
2736 else if (dformat == "docbook5")
2737 result = Flavor::DocBook5;
2738 else if (dformat == "text")
2739 result = Flavor::Text;
2740 else if (dformat == "lyx")
2741 result = Flavor::LyX;
2742 else if (dformat == "pdflatex")
2743 result = Flavor::PdfLaTeX;
2744 else if (dformat == "xetex")
2745 result = Flavor::XeTeX;
2746 else if (dformat == "luatex")
2747 result = Flavor::LuaTeX;
2748 else if (dformat == "dviluatex")
2749 result = Flavor::DviLuaTeX;
2751 // Try to determine flavor of default output format
2752 vector<string> backs = backends();
2753 if (find(backs.begin(), backs.end(), dformat) == backs.end()) {
2754 // Get shortest path to format
2755 Graph::EdgePath path;
2756 for (auto const & bvar : backs) {
2757 Graph::EdgePath p = theConverters().getPath(bvar, dformat);
2758 if (!p.empty() && (path.empty() || p.size() < path.size())) {
2763 result = theConverters().getFlavor(path);
2766 // cache this flavor
2767 default_flavors_[dformat] = result;
2772 string BufferParams::getDefaultOutputFormat() const
2774 if (!default_output_format.empty()
2775 && default_output_format != "default")
2776 return default_output_format;
2777 if (encoding().package() == Encoding::japanese)
2778 return lyxrc.default_platex_view_format;
2780 return lyxrc.default_otf_view_format;
2781 return lyxrc.default_view_format;
2784 Font const BufferParams::getFont() const
2786 FontInfo f = documentClass().defaultfont();
2787 if (fonts_default_family == "rmdefault")
2788 f.setFamily(ROMAN_FAMILY);
2789 else if (fonts_default_family == "sfdefault")
2790 f.setFamily(SANS_FAMILY);
2791 else if (fonts_default_family == "ttdefault")
2792 f.setFamily(TYPEWRITER_FAMILY);
2793 return Font(f, language);
2797 QuoteStyle BufferParams::getQuoteStyle(string const & qs) const
2799 return quotesstyletranslator().find(qs);
2803 bool BufferParams::isLatex() const
2805 return documentClass().outputType() == LATEX;
2809 bool BufferParams::isLiterate() const
2811 return documentClass().outputType() == LITERATE;
2815 void BufferParams::readPreamble(Lexer & lex)
2817 if (lex.getString() != "\\begin_preamble")
2818 lyxerr << "Error (BufferParams::readPreamble):"
2819 "consistency check failed." << endl;
2821 preamble = lex.getLongString(from_ascii("\\end_preamble"));
2825 void BufferParams::readLocalLayout(Lexer & lex, bool forced)
2827 string const expected = forced ? "\\begin_forced_local_layout" :
2828 "\\begin_local_layout";
2829 if (lex.getString() != expected)
2830 lyxerr << "Error (BufferParams::readLocalLayout):"
2831 "consistency check failed." << endl;
2834 forced_local_layout_ =
2835 lex.getLongString(from_ascii("\\end_forced_local_layout"));
2837 local_layout_ = lex.getLongString(from_ascii("\\end_local_layout"));
2841 bool BufferParams::setLanguage(string const & lang)
2843 Language const *new_language = languages.getLanguage(lang);
2844 if (!new_language) {
2845 // Language lang was not found
2848 language = new_language;
2853 void BufferParams::readLanguage(Lexer & lex)
2855 if (!lex.next()) return;
2857 string const tmptok = lex.getString();
2859 // check if tmptok is part of tex_babel in tex-defs.h
2860 if (!setLanguage(tmptok)) {
2861 // Language tmptok was not found
2862 language = default_language;
2863 lyxerr << "Warning: Setting language `"
2864 << tmptok << "' to `" << language->lang()
2870 void BufferParams::readGraphicsDriver(Lexer & lex)
2875 string const tmptok = lex.getString();
2876 // check if tmptok is part of tex_graphics in tex_defs.h
2879 string const test = tex_graphics[n++];
2881 if (test == tmptok) {
2882 graphics_driver = tmptok;
2887 "Warning: graphics driver `$$Token' not recognized!\n"
2888 " Setting graphics driver to `default'.\n");
2889 graphics_driver = "default";
2896 void BufferParams::readBullets(Lexer & lex)
2901 int const index = lex.getInteger();
2903 int temp_int = lex.getInteger();
2904 user_defined_bullet(index).setFont(temp_int);
2905 temp_bullet(index).setFont(temp_int);
2907 user_defined_bullet(index).setCharacter(temp_int);
2908 temp_bullet(index).setCharacter(temp_int);
2910 user_defined_bullet(index).setSize(temp_int);
2911 temp_bullet(index).setSize(temp_int);
2915 void BufferParams::readBulletsLaTeX(Lexer & lex)
2917 // The bullet class should be able to read this.
2920 int const index = lex.getInteger();
2922 docstring const temp_str = lex.getDocString();
2924 user_defined_bullet(index).setText(temp_str);
2925 temp_bullet(index).setText(temp_str);
2929 void BufferParams::readModules(Lexer & lex)
2931 if (!lex.eatLine()) {
2932 lyxerr << "Error (BufferParams::readModules):"
2933 "Unexpected end of input." << endl;
2937 string mod = lex.getString();
2938 if (mod == "\\end_modules")
2940 addLayoutModule(mod);
2946 void BufferParams::readRemovedModules(Lexer & lex)
2948 if (!lex.eatLine()) {
2949 lyxerr << "Error (BufferParams::readRemovedModules):"
2950 "Unexpected end of input." << endl;
2954 string mod = lex.getString();
2955 if (mod == "\\end_removed_modules")
2957 removed_modules_.push_back(mod);
2960 // now we want to remove any removed modules that were previously
2961 // added. normally, that will be because default modules were added in
2962 // setBaseClass(), which gets called when \textclass is read at the
2963 // start of the read.
2964 for (auto const & rm : removed_modules_) {
2965 LayoutModuleList::iterator const mit = layout_modules_.begin();
2966 LayoutModuleList::iterator const men = layout_modules_.end();
2967 LayoutModuleList::iterator found = find(mit, men, rm);
2970 layout_modules_.erase(found);
2975 void BufferParams::readIncludeonly(Lexer & lex)
2977 if (!lex.eatLine()) {
2978 lyxerr << "Error (BufferParams::readIncludeonly):"
2979 "Unexpected end of input." << endl;
2983 string child = lex.getString();
2984 if (child == "\\end_includeonly")
2986 included_children_.push_back(child);
2992 string BufferParams::paperSizeName(PapersizePurpose purpose, string const & psize) const
2994 PAPER_SIZE ppsize = psize.empty() ? papersize : papersizetranslator().find(psize);
2997 if (documentClass().pagesize() == "default")
2998 // could be anything, so don't guess
3000 return paperSizeName(purpose, documentClass().pagesize());
3001 case PAPER_CUSTOM: {
3002 if (purpose == XDVI && !paperwidth.empty() &&
3003 !paperheight.empty()) {
3004 // heightxwidth<unit>
3005 string first = paperwidth;
3006 string second = paperheight;
3007 if (orientation == ORIENTATION_LANDSCAPE)
3010 return first.erase(first.length() - 2)
3016 // dvips and dvipdfm do not know this
3017 if (purpose == DVIPS || purpose == DVIPDFM)
3021 if (purpose == DVIPS || purpose == DVIPDFM)
3025 if (purpose == DVIPS || purpose == DVIPDFM)
3035 if (purpose == DVIPS || purpose == DVIPDFM)
3039 if (purpose == DVIPS || purpose == DVIPDFM)
3043 if (purpose == DVIPS || purpose == DVIPDFM)
3047 if (purpose == DVIPS || purpose == DVIPDFM)
3051 if (purpose == DVIPS || purpose == DVIPDFM)
3055 // dvipdfm does not know this
3056 if (purpose == DVIPDFM)
3060 if (purpose == DVIPDFM)
3064 if (purpose == DVIPS || purpose == DVIPDFM)
3068 if (purpose == DVIPS || purpose == DVIPDFM)
3072 if (purpose == DVIPS || purpose == DVIPDFM)
3076 if (purpose == DVIPS || purpose == DVIPDFM)
3080 if (purpose == DVIPS || purpose == DVIPDFM)
3084 if (purpose == DVIPS || purpose == DVIPDFM)
3088 if (purpose == DVIPS || purpose == DVIPDFM)
3092 if (purpose == DVIPS || purpose == DVIPDFM)
3096 if (purpose == DVIPS || purpose == DVIPDFM)
3100 if (purpose == DVIPS || purpose == DVIPDFM)
3104 if (purpose == DVIPS || purpose == DVIPDFM)
3108 if (purpose == DVIPS || purpose == DVIPDFM)
3112 if (purpose == DVIPS || purpose == DVIPDFM)
3116 if (purpose == DVIPS || purpose == DVIPDFM)
3120 if (purpose == DVIPS || purpose == DVIPDFM)
3123 case PAPER_USEXECUTIVE:
3124 // dvipdfm does not know this
3125 if (purpose == DVIPDFM)
3130 case PAPER_USLETTER:
3132 if (purpose == XDVI)
3139 string const BufferParams::dvips_options() const
3143 // If the class loads the geometry package, we do not know which
3144 // paper size is used, since we do not set it (bug 7013).
3145 // Therefore we must not specify any argument here.
3146 // dvips gets the correct paper size via DVI specials in this case
3147 // (if the class uses the geometry package correctly).
3148 if (documentClass().provides("geometry"))
3152 && papersize == PAPER_CUSTOM
3153 && !lyxrc.print_paper_dimension_flag.empty()
3154 && !paperwidth.empty()
3155 && !paperheight.empty()) {
3156 // using a custom papersize
3157 result = lyxrc.print_paper_dimension_flag;
3158 result += ' ' + paperwidth;
3159 result += ',' + paperheight;
3161 string const paper_option = paperSizeName(DVIPS);
3162 if (!paper_option.empty() && (paper_option != "letter" ||
3163 orientation != ORIENTATION_LANDSCAPE)) {
3164 // dvips won't accept -t letter -t landscape.
3165 // In all other cases, include the paper size
3167 result = lyxrc.print_paper_flag;
3168 result += ' ' + paper_option;
3171 if (orientation == ORIENTATION_LANDSCAPE &&
3172 papersize != PAPER_CUSTOM)
3173 result += ' ' + lyxrc.print_landscape_flag;
3178 string const BufferParams::main_font_encoding() const
3180 if (font_encodings().empty()) {
3181 if (ascii_lowercase(language->fontenc(*this)) == "none")
3185 return font_encodings().back();
3189 vector<string> const BufferParams::font_encodings() const
3191 string doc_fontenc = (fontenc == "auto") ? string() : fontenc;
3193 vector<string> fontencs;
3195 // "default" means "no explicit font encoding"
3196 if (doc_fontenc != "default") {
3197 if (!doc_fontenc.empty())
3198 // If we have a custom setting, we use only that!
3199 return getVectorFromString(doc_fontenc);
3200 if (!language->fontenc(*this).empty()
3201 && ascii_lowercase(language->fontenc(*this)) != "none") {
3202 vector<string> fencs = getVectorFromString(language->fontenc(*this));
3203 for (auto & fe : fencs) {
3204 if (find(fontencs.begin(), fontencs.end(), fe) == fontencs.end())
3205 fontencs.push_back(fe);
3214 string BufferParams::babelCall(string const & lang_opts, bool const langoptions) const
3216 // suppress the babel call if there is no BabelName defined
3217 // for the document language in the lib/languages file and if no
3218 // other languages are used (lang_opts is then empty)
3219 if (lang_opts.empty())
3221 // The prefs may require the languages to
3222 // be submitted to babel itself (not the class).
3224 return "\\usepackage[" + lang_opts + "]{babel}";
3225 return "\\usepackage{babel}";
3229 docstring BufferParams::getGraphicsDriver(string const & package) const
3233 if (package == "geometry") {
3234 if (graphics_driver == "dvips"
3235 || graphics_driver == "dvipdfm"
3236 || graphics_driver == "pdftex"
3237 || graphics_driver == "vtex")
3238 result = from_ascii(graphics_driver);
3239 else if (graphics_driver == "dvipdfmx")
3240 result = from_ascii("dvipdfm");
3247 void BufferParams::writeEncodingPreamble(otexstream & os,
3248 LaTeXFeatures & features) const
3250 // With no-TeX fonts we use utf8-plain without encoding package.
3254 if (inputenc == "auto-legacy") {
3255 string const doc_encoding =
3256 language->encoding()->latexName();
3257 Encoding::Package const package =
3258 language->encoding()->package();
3260 // Create list of inputenc options:
3261 set<string> encoding_set;
3262 // luainputenc fails with more than one encoding
3263 if (features.runparams().flavor != Flavor::LuaTeX
3264 && features.runparams().flavor != Flavor::DviLuaTeX)
3265 // list all input encodings used in the document
3266 encoding_set = features.getEncodingSet(doc_encoding);
3268 // The "japanese" babel-language requires the pLaTeX engine
3269 // which conflicts with "inputenc".
3270 // See http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129680.html
3271 if ((!encoding_set.empty() || package == Encoding::inputenc)
3272 && !features.isRequired("japanese")
3273 && !features.isProvided("inputenc")) {
3274 os << "\\usepackage[";
3275 set<string>::const_iterator it = encoding_set.begin();
3276 set<string>::const_iterator const end = encoding_set.end();
3278 os << from_ascii(*it);
3281 for (; it != end; ++it)
3282 os << ',' << from_ascii(*it);
3283 if (package == Encoding::inputenc) {
3284 if (!encoding_set.empty())
3286 os << from_ascii(doc_encoding);
3288 if (features.runparams().flavor == Flavor::LuaTeX
3289 || features.runparams().flavor == Flavor::DviLuaTeX)
3290 os << "]{luainputenc}\n";
3292 os << "]{inputenc}\n";
3294 } else if (inputenc != "auto-legacy-plain") {
3295 switch (encoding().package()) {
3296 case Encoding::none:
3298 case Encoding::japanese:
3299 if (encoding().iconvName() != "UTF-8"
3300 && !features.runparams().isFullUnicode())
3301 // don't default to [utf8]{inputenc} with TeXLive >= 18
3302 os << "\\ifdefined\\UseRawInputEncoding\n"
3303 << " \\UseRawInputEncoding\\fi\n";
3305 case Encoding::inputenc:
3306 // do not load inputenc if japanese is used
3307 // or if the class provides inputenc
3308 if (features.isRequired("japanese")
3309 || features.isProvided("inputenc"))
3311 os << "\\usepackage[" << from_ascii(encoding().latexName());
3312 if (features.runparams().flavor == Flavor::LuaTeX
3313 || features.runparams().flavor == Flavor::DviLuaTeX)
3314 os << "]{luainputenc}\n";
3316 os << "]{inputenc}\n";
3320 if (inputenc == "auto-legacy-plain" || features.isRequired("japanese")) {
3321 // don't default to [utf8]{inputenc} with TeXLive >= 18
3322 os << "\\ifdefined\\UseRawInputEncoding\n";
3323 os << " \\UseRawInputEncoding\\fi\n";
3328 string const BufferParams::parseFontName(string const & name) const
3330 string mangled = name;
3331 size_t const idx = mangled.find('[');
3332 if (idx == string::npos || idx == 0)
3335 return mangled.substr(0, idx - 1);
3339 string const BufferParams::loadFonts(LaTeXFeatures & features) const
3341 if (fontsRoman() == "default" && fontsSans() == "default"
3342 && fontsTypewriter() == "default"
3343 && (fontsMath() == "default" || fontsMath() == "auto"))
3349 /* Fontspec (XeTeX, LuaTeX): we provide GUI support for oldstyle
3350 * numbers (Numbers=OldStyle) and sf/tt scaling. The Ligatures=TeX/
3351 * Mapping=tex-text option assures TeX ligatures (such as "--")
3352 * are resolved. Note that tt does not use these ligatures.
3354 * -- add more GUI options?
3355 * -- add more fonts (fonts for other scripts)
3356 * -- if there's a way to find out if a font really supports
3357 * OldStyle, enable/disable the widget accordingly.
3359 if (useNonTeXFonts && features.isAvailable("fontspec")) {
3360 // "Mapping=tex-text" and "Ligatures=TeX" are equivalent.
3361 // However, until v.2 (2010/07/11) fontspec only knew
3362 // Mapping=tex-text (for XeTeX only); then "Ligatures=TeX"
3363 // was introduced for both XeTeX and LuaTeX (LuaTeX
3364 // didn't understand "Mapping=tex-text", while XeTeX
3365 // understood both. With most recent versions, both
3366 // variants are understood by both engines. However,
3367 // we want to provide support for at least TeXLive 2009
3368 // (for XeTeX; LuaTeX is only supported as of v.2)
3369 // As of 2017/11/03, Babel has its own higher-level
3370 // interface on top of fontspec that is to be used.
3371 bool const babelfonts = features.useBabel()
3372 && features.isAvailable("babel-2017/11/03");
3373 string const texmapping =
3374 (features.runparams().flavor == Flavor::XeTeX) ?
3375 "Mapping=tex-text" : "Ligatures=TeX";
3376 if (fontsRoman() != "default") {
3378 os << "\\babelfont{rm}[";
3380 os << "\\setmainfont[";
3381 if (!font_roman_opts.empty())
3382 os << font_roman_opts << ',';
3384 if (fonts_roman_osf)
3385 os << ",Numbers=OldStyle";
3386 os << "]{" << parseFontName(fontsRoman()) << "}\n";
3388 if (fontsSans() != "default") {
3389 string const sans = parseFontName(fontsSans());
3390 if (fontsSansScale() != 100) {
3392 os << "\\babelfont{sf}";
3394 os << "\\setsansfont";
3396 << float(fontsSansScale()) / 100 << ',';
3398 os << "Numbers=OldStyle,";
3399 if (!font_sans_opts.empty())
3400 os << font_sans_opts << ',';
3401 os << texmapping << "]{"
3405 os << "\\babelfont{sf}[";
3407 os << "\\setsansfont[";
3409 os << "Numbers=OldStyle,";
3410 if (!font_sans_opts.empty())
3411 os << font_sans_opts << ',';
3412 os << texmapping << "]{"
3416 if (fontsTypewriter() != "default") {
3417 string const mono = parseFontName(fontsTypewriter());
3418 if (fontsTypewriterScale() != 100) {
3420 os << "\\babelfont{tt}";
3422 os << "\\setmonofont";
3424 << float(fontsTypewriterScale()) / 100;
3425 if (fonts_typewriter_osf)
3426 os << ",Numbers=OldStyle";
3427 if (!font_typewriter_opts.empty())
3428 os << ',' << font_typewriter_opts;
3433 os << "\\babelfont{tt}";
3435 os << "\\setmonofont";
3436 if (!font_typewriter_opts.empty() || fonts_typewriter_osf) {
3438 if (fonts_typewriter_osf)
3439 os << "Numbers=OldStyle";
3440 if (!font_typewriter_opts.empty()) {
3441 if (fonts_typewriter_osf)
3443 os << font_typewriter_opts;
3447 os << '{' << mono << "}\n";
3454 bool const ot1 = (main_font_encoding() == "default" || main_font_encoding() == "OT1");
3455 bool const dryrun = features.runparams().dryrun;
3456 bool const complete = (fontsSans() == "default" && fontsTypewriter() == "default");
3457 bool const nomath = (fontsMath() != "auto");
3460 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsRoman())).getLaTeXCode(
3461 dryrun, ot1, complete, fonts_expert_sc, fonts_roman_osf,
3462 nomath, font_roman_opts);
3465 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsSans())).getLaTeXCode(
3466 dryrun, ot1, complete, fonts_expert_sc, fonts_sans_osf,
3467 nomath, font_sans_opts, fontsSansScale());
3469 // MONOSPACED/TYPEWRITER
3470 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsTypewriter())).getLaTeXCode(
3471 dryrun, ot1, complete, fonts_expert_sc, fonts_typewriter_osf,
3472 nomath, font_typewriter_opts, fontsTypewriterScale());
3475 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsMath())).getLaTeXCode(
3476 dryrun, ot1, complete, fonts_expert_sc, fonts_roman_osf,
3483 Encoding const & BufferParams::encoding() const
3485 // Main encoding for LaTeX output.
3487 return *(encodings.fromLyXName("utf8-plain"));
3488 if (inputenc == "auto-legacy" || inputenc == "auto-legacy-plain")
3489 return *language->encoding();
3490 if (inputenc == "utf8" && language->lang() == "japanese")
3491 return *(encodings.fromLyXName("utf8-platex"));
3492 Encoding const * const enc = encodings.fromLyXName(inputenc);
3495 LYXERR0("Unknown inputenc value `" << inputenc
3496 << "'. Using `auto' instead.");
3497 return *language->encoding();
3501 string const & BufferParams::defaultBiblioStyle() const
3503 if (!biblio_style.empty())
3504 return biblio_style;
3506 map<string, string> const & bs = documentClass().defaultBiblioStyle();
3507 auto cit = bs.find(theCiteEnginesList.getTypeAsString(citeEngineType()));
3508 if (cit != bs.end())
3511 return empty_string();
3515 bool BufferParams::fullAuthorList() const
3517 return documentClass().fullAuthorList();
3521 string BufferParams::getCiteAlias(string const & s) const
3523 vector<string> commands =
3524 documentClass().citeCommands(citeEngineType());
3525 // If it is a real command, don't treat it as an alias
3526 if (find(commands.begin(), commands.end(), s) != commands.end())
3528 map<string,string> aliases = documentClass().citeCommandAliases();
3529 if (aliases.find(s) != aliases.end())
3535 vector<string> BufferParams::citeCommands() const
3537 static CitationStyle const default_style;
3538 vector<string> commands =
3539 documentClass().citeCommands(citeEngineType());
3540 if (commands.empty())
3541 commands.push_back(default_style.name);
3546 vector<CitationStyle> BufferParams::citeStyles() const
3548 static CitationStyle const default_style;
3549 vector<CitationStyle> styles =
3550 documentClass().citeStyles(citeEngineType());
3552 styles.push_back(default_style);
3557 string const BufferParams::bibtexCommand() const
3559 // Return document-specific setting if available
3560 if (bibtex_command != "default")
3561 return bibtex_command;
3563 // If we have "default" in document settings, consult the prefs
3564 // 1. Japanese (uses a specific processor)
3565 if (encoding().package() == Encoding::japanese) {
3566 if (lyxrc.jbibtex_command != "automatic")
3567 // Return the specified program, if "automatic" is not set
3568 return lyxrc.jbibtex_command;
3569 else if (!useBiblatex()) {
3570 // With classic BibTeX, return pbibtex, jbibtex, bibtex
3571 if (lyxrc.jbibtex_alternatives.find("pbibtex") != lyxrc.jbibtex_alternatives.end())
3573 if (lyxrc.jbibtex_alternatives.find("jbibtex") != lyxrc.jbibtex_alternatives.end())
3578 // 2. All other languages
3579 else if (lyxrc.bibtex_command != "automatic")
3580 // Return the specified program, if "automatic" is not set
3581 return lyxrc.bibtex_command;
3583 // 3. Automatic: find the most suitable for the current cite framework
3584 if (useBiblatex()) {
3585 // For Biblatex, we prefer biber (also for Japanese)
3586 // and fall back to bibtex8 and, as last resort, bibtex
3587 if (lyxrc.bibtex_alternatives.find("biber") != lyxrc.bibtex_alternatives.end())
3589 else if (lyxrc.bibtex_alternatives.find("bibtex8") != lyxrc.bibtex_alternatives.end())
3596 bool BufferParams::useBiblatex() const
3598 return theCiteEnginesList[citeEngine()]->getCiteFramework() == "biblatex";
3602 void BufferParams::invalidateConverterCache() const
3604 pimpl_->isExportCacheValid = false;
3605 pimpl_->isViewCacheValid = false;
3609 // We shouldn't need to reset the params here, since anything
3610 // we need will be recopied.
3611 void BufferParams::copyForAdvFR(const BufferParams & bp)
3613 string const & lang = bp.language->lang();
3615 layout_modules_ = bp.layout_modules_;
3616 string const & doc_class = bp.documentClass().name();
3617 setBaseClass(doc_class);
3621 void BufferParams::setBibFileEncoding(string const & file, string const & enc)
3623 bib_encodings[file] = enc;
3627 string const BufferParams::bibFileEncoding(string const & file) const
3629 if (bib_encodings.find(file) == bib_encodings.end())
3631 return bib_encodings.find(file)->second;