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 isnotefontcolor = false;
466 boxbgcolor = lyx::rgbFromHexName("#ff0000");
467 isboxbgcolor = false;
468 compressed = lyxrc.save_compressed;
469 for (int iter = 0; iter < 4; ++iter) {
470 user_defined_bullet(iter) = ITEMIZE_DEFAULTS[iter];
471 temp_bullet(iter) = ITEMIZE_DEFAULTS[iter];
474 indiceslist().addDefault(B_("Index"));
475 html_be_strict = false;
476 html_math_output = MathML;
477 html_math_img_scale = 1.0;
478 html_css_as_file = false;
479 docbook_table_output = HTMLTable;
480 display_pixel_ratio = 1.0;
482 shell_escape = false;
488 // map current author
489 author_map_[pimpl_->authorlist.get(0).bufferId()] = 0;
493 docstring BufferParams::B_(string const & l10n) const
495 LASSERT(language, return from_utf8(l10n));
496 return getMessages(language->code()).get(l10n);
500 BufferParams::Package BufferParams::use_package(std::string const & p) const
502 PackageMap::const_iterator it = use_packages.find(p);
503 if (it == use_packages.end())
509 void BufferParams::use_package(std::string const & p, BufferParams::Package u)
515 map<string, string> const & BufferParams::auto_packages()
517 static map<string, string> packages;
518 if (packages.empty()) {
519 // We could have a race condition here that two threads
520 // discover an empty map at the same time and want to fill
521 // it, but that is no problem, since the same contents is
522 // filled in twice then. Having the locker inside the
523 // packages.empty() condition has the advantage that we
524 // don't need the mutex overhead for simple reading.
526 Mutex::Locker locker(&mutex);
527 // adding a package here implies a file format change!
528 packages["amsmath"] =
529 N_("The LaTeX package amsmath is only used if AMS formula types or symbols from the AMS math toolbars are inserted into formulas");
530 packages["amssymb"] =
531 N_("The LaTeX package amssymb is only used if symbols from the AMS math toolbars are inserted into formulas");
533 N_("The LaTeX package cancel is only used if \\cancel commands are used in formulas");
535 N_("The LaTeX package esint is only used if special integral symbols are inserted into formulas");
536 packages["mathdots"] =
537 N_("The LaTeX package mathdots is only used if the command \\iddots is inserted into formulas");
538 packages["mathtools"] =
539 N_("The LaTeX package mathtools is only used if some mathematical relations are inserted into formulas");
541 N_("The LaTeX package mhchem is only used if either the command \\ce or \\cf is inserted into formulas");
542 packages["stackrel"] =
543 N_("The LaTeX package stackrel is only used if the command \\stackrel with subscript is inserted into formulas");
544 packages["stmaryrd"] =
545 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");
546 packages["undertilde"] =
547 N_("The LaTeX package undertilde is only used if you use the math frame decoration 'utilde'");
553 bool BufferParams::useBibtopic() const
557 return (use_bibtopic || (!multibib.empty() && multibib != "child"));
561 AuthorList & BufferParams::authors()
563 return pimpl_->authorlist;
567 AuthorList const & BufferParams::authors() const
569 return pimpl_->authorlist;
573 void BufferParams::addAuthor(Author const & a)
575 author_map_[a.bufferId()] = pimpl_->authorlist.record(a);
579 BranchList & BufferParams::branchlist()
581 return pimpl_->branchlist;
585 BranchList const & BufferParams::branchlist() const
587 return pimpl_->branchlist;
591 IndicesList & BufferParams::indiceslist()
593 return pimpl_->indiceslist;
597 IndicesList const & BufferParams::indiceslist() const
599 return pimpl_->indiceslist;
603 Bullet & BufferParams::temp_bullet(lyx::size_type const index)
605 LASSERT(index < 4, return pimpl_->temp_bullets[0]);
606 return pimpl_->temp_bullets[index];
610 Bullet const & BufferParams::temp_bullet(lyx::size_type const index) const
612 LASSERT(index < 4, return pimpl_->temp_bullets[0]);
613 return pimpl_->temp_bullets[index];
617 Bullet & BufferParams::user_defined_bullet(lyx::size_type const index)
619 LASSERT(index < 4, return pimpl_->temp_bullets[0]);
620 return pimpl_->user_defined_bullets[index];
624 Bullet const & BufferParams::user_defined_bullet(lyx::size_type const index) const
626 LASSERT(index < 4, return pimpl_->temp_bullets[0]);
627 return pimpl_->user_defined_bullets[index];
631 Spacing & BufferParams::spacing()
633 return pimpl_->spacing;
637 Spacing const & BufferParams::spacing() const
639 return pimpl_->spacing;
643 PDFOptions & BufferParams::pdfoptions()
645 return pimpl_->pdfoptions;
649 PDFOptions const & BufferParams::pdfoptions() const
651 return pimpl_->pdfoptions;
655 Length const & BufferParams::getMathIndent() const
657 return pimpl_->mathindent;
661 void BufferParams::setMathIndent(Length const & indent)
663 pimpl_->mathindent = indent;
667 Length const & BufferParams::getParIndent() const
669 return pimpl_->parindent;
673 void BufferParams::setParIndent(Length const & indent)
675 pimpl_->parindent = indent;
679 VSpace const & BufferParams::getDefSkip() const
681 return pimpl_->defskip;
685 void BufferParams::setDefSkip(VSpace const & vs)
687 // DEFSKIP will cause an infinite loop
688 LASSERT(vs.kind() != VSpace::DEFSKIP, return);
689 pimpl_->defskip = vs;
693 BufferParams::MathNumber BufferParams::getMathNumber() const
695 if (math_numbering_side != DEFAULT)
696 return math_numbering_side;
697 // FIXME: do not hardcode language here
698 else if (language->lang() == "arabic_arabi"
699 || documentClass().provides("leqno"))
706 string BufferParams::readToken(Lexer & lex, string const & token,
707 FileName const & filepath)
711 if (token == "\\textclass") {
713 string const classname = lex.getString();
714 // if there exists a local layout file, ignore the system one
715 // NOTE: in this case, the textclass (.cls file) is assumed to
718 LayoutFileList & bcl = LayoutFileList::get();
719 if (!filepath.empty()) {
720 // If classname is an absolute path, the document is
721 // using a local layout file which could not be accessed
722 // by a relative path. In this case the path is correct
723 // even if the document was moved to a different
724 // location. However, we will have a problem if the
725 // document was generated on a different platform.
726 bool isabsolute = FileName::isAbsolute(classname);
727 string const classpath = onlyPath(classname);
728 string const path = isabsolute ? classpath
729 : FileName(addPath(filepath.absFileName(),
730 classpath)).realPath();
731 string const oldpath = isabsolute ? string()
732 : FileName(addPath(origin, classpath)).realPath();
733 tcp = bcl.addLocalLayout(onlyFileName(classname), path, oldpath);
735 // that returns non-empty if a "local" layout file is found.
737 result = to_utf8(makeRelPath(from_utf8(onlyPath(tcp)),
738 from_utf8(filepath.absFileName())));
741 setBaseClass(onlyFileName(tcp));
743 setBaseClass(onlyFileName(classname));
744 // We assume that a tex class exists for local or unknown
745 // layouts so this warning, will only be given for system layouts.
746 if (!baseClass()->isTeXClassAvailable()) {
747 docstring const desc =
748 translateIfPossible(from_utf8(baseClass()->description()));
749 docstring const prereqs =
750 from_utf8(baseClass()->prerequisites());
751 docstring const msg =
752 bformat(_("The selected document class\n"
754 "requires external files that are not available.\n"
755 "The document class can still be used, but the\n"
756 "document cannot be compiled until the following\n"
757 "prerequisites are installed:\n"
759 "See section 3.1.2.2 (Class Availability) of the\n"
760 "User's Guide for more information."), desc, prereqs);
761 frontend::Alert::warning(_("Document class not available"),
764 } else if (token == "\\save_transient_properties") {
765 lex >> save_transient_properties;
766 } else if (token == "\\origin") {
768 origin = lex.getString();
769 string const sysdirprefix = "/systemlyxdir/";
770 if (prefixIs(origin, sysdirprefix)) {
772 if (inSystemDir(filepath, docsys))
773 origin.replace(0, sysdirprefix.length() - 1, docsys);
775 origin.replace(0, sysdirprefix.length() - 1,
776 package().system_support().absFileName());
778 } else if (token == "\\begin_preamble") {
780 } else if (token == "\\begin_local_layout") {
781 readLocalLayout(lex, false);
782 } else if (token == "\\begin_forced_local_layout") {
783 readLocalLayout(lex, true);
784 } else if (token == "\\begin_modules") {
786 } else if (token == "\\begin_removed_modules") {
787 readRemovedModules(lex);
788 } else if (token == "\\begin_includeonly") {
789 readIncludeonly(lex);
790 } else if (token == "\\maintain_unincluded_children") {
794 maintain_unincluded_children = CM_None;
795 else if (tmp == "mostly")
796 maintain_unincluded_children = CM_Mostly;
797 else if (tmp == "strict")
798 maintain_unincluded_children = CM_Strict;
799 } else if (token == "\\options") {
801 options = lex.getString();
802 } else if (token == "\\use_default_options") {
803 lex >> use_default_options;
804 } else if (token == "\\master") {
806 master = lex.getString();
807 if (!filepath.empty() && FileName::isAbsolute(origin)) {
808 bool const isabs = FileName::isAbsolute(master);
809 FileName const abspath(isabs ? master : origin + master);
810 bool const moved = filepath != FileName(origin);
811 if (moved && abspath.exists()) {
812 docstring const path = isabs
814 : from_utf8(abspath.realPath());
815 docstring const refpath =
816 from_utf8(filepath.absFileName());
817 master = to_utf8(makeRelPath(path, refpath));
820 } else if (token == "\\suppress_date") {
821 lex >> suppress_date;
822 } else if (token == "\\justification") {
823 lex >> justification;
824 } else if (token == "\\language") {
826 } else if (token == "\\language_package") {
828 lang_package = lex.getString();
829 } else if (token == "\\inputencoding") {
831 } else if (token == "\\graphics") {
832 readGraphicsDriver(lex);
833 } else if (token == "\\default_output_format") {
834 lex >> default_output_format;
835 } else if (token == "\\bibtex_command") {
837 bibtex_command = lex.getString();
838 } else if (token == "\\index_command") {
840 index_command = lex.getString();
841 } else if (token == "\\fontencoding") {
843 fontenc = lex.getString();
844 } else if (token == "\\font_roman") {
845 lex >> fonts_roman[0];
846 lex >> fonts_roman[1];
847 } else if (token == "\\font_sans") {
848 lex >> fonts_sans[0];
849 lex >> fonts_sans[1];
850 } else if (token == "\\font_typewriter") {
851 lex >> fonts_typewriter[0];
852 lex >> fonts_typewriter[1];
853 } else if (token == "\\font_math") {
854 lex >> fonts_math[0];
855 lex >> fonts_math[1];
856 } else if (token == "\\font_default_family") {
857 lex >> fonts_default_family;
858 } else if (token == "\\use_non_tex_fonts") {
859 lex >> useNonTeXFonts;
860 } else if (token == "\\font_sc") {
861 lex >> fonts_expert_sc;
862 } else if (token == "\\font_roman_osf") {
863 lex >> fonts_roman_osf;
864 } else if (token == "\\font_sans_osf") {
865 lex >> fonts_sans_osf;
866 } else if (token == "\\font_typewriter_osf") {
867 lex >> fonts_typewriter_osf;
868 } else if (token == "\\font_roman_opts") {
869 lex >> font_roman_opts;
870 } else if (token == "\\font_sf_scale") {
871 lex >> fonts_sans_scale[0];
872 lex >> fonts_sans_scale[1];
873 } else if (token == "\\font_sans_opts") {
874 lex >> font_sans_opts;
875 } else if (token == "\\font_tt_scale") {
876 lex >> fonts_typewriter_scale[0];
877 lex >> fonts_typewriter_scale[1];
878 } else if (token == "\\font_typewriter_opts") {
879 lex >> font_typewriter_opts;
880 } else if (token == "\\font_cjk") {
882 } else if (token == "\\use_microtype") {
883 lex >> use_microtype;
884 } else if (token == "\\use_dash_ligatures") {
885 lex >> use_dash_ligatures;
886 } else if (token == "\\paragraph_separation") {
889 paragraph_separation = parseptranslator().find(parsep);
890 } else if (token == "\\paragraph_indentation") {
892 string parindent = lex.getString();
893 if (parindent == "default")
894 pimpl_->parindent = Length();
896 pimpl_->parindent = Length(parindent);
897 } else if (token == "\\defskip") {
899 string const defskip = lex.getString();
900 pimpl_->defskip = VSpace(defskip);
901 if (pimpl_->defskip.kind() == VSpace::DEFSKIP)
903 pimpl_->defskip = VSpace(VSpace::MEDSKIP);
904 } else if (token == "\\is_math_indent") {
905 lex >> is_math_indent;
906 } else if (token == "\\math_indentation") {
908 string mathindent = lex.getString();
909 if (mathindent == "default")
910 pimpl_->mathindent = Length();
912 pimpl_->mathindent = Length(mathindent);
913 } else if (token == "\\math_numbering_side") {
917 math_numbering_side = LEFT;
918 else if (tmp == "right")
919 math_numbering_side = RIGHT;
921 math_numbering_side = DEFAULT;
922 } else if (token == "\\quotes_style") {
925 quotes_style = quotesstyletranslator().find(qstyle);
926 } else if (token == "\\dynamic_quotes") {
927 lex >> dynamic_quotes;
928 } else if (token == "\\papersize") {
931 papersize = papersizetranslator().find(ppsize);
932 } else if (token == "\\use_geometry") {
934 } else if (token == "\\use_package") {
939 use_package(package, packagetranslator().find(use));
940 } else if (token == "\\cite_engine") {
942 cite_engine_ = lex.getString();
943 } else if (token == "\\cite_engine_type") {
946 cite_engine_type_ = theCiteEnginesList.getType(engine_type);
947 } else if (token == "\\biblio_style") {
949 biblio_style = lex.getString();
950 } else if (token == "\\biblio_options") {
952 biblio_opts = trim(lex.getString());
953 } else if (token == "\\biblatex_bibstyle") {
955 biblatex_bibstyle = trim(lex.getString());
956 } else if (token == "\\biblatex_citestyle") {
958 biblatex_citestyle = trim(lex.getString());
959 } else if (token == "\\use_bibtopic") {
961 } else if (token == "\\multibib") {
963 } else if (token == "\\use_indices") {
965 } else if (token == "\\tracking_changes") {
966 lex >> track_changes;
967 } else if (token == "\\output_changes") {
968 lex >> output_changes;
969 } else if (token == "\\change_bars") {
971 } else if (token == "\\postpone_fragile_content") {
972 lex >> postpone_fragile_content;
973 } else if (token == "\\branch") {
975 docstring branch = lex.getDocString();
976 branchlist().add(branch);
979 string const tok = lex.getString();
980 if (tok == "\\end_branch")
982 Branch * branch_ptr = branchlist().find(branch);
983 if (tok == "\\selected") {
986 branch_ptr->setSelected(lex.getInteger());
988 if (tok == "\\filename_suffix") {
991 branch_ptr->setFileNameSuffix(lex.getInteger());
993 if (tok == "\\color") {
995 vector<string> const colors = getVectorFromString(lex.getString(), " ");
996 string const lmcolor = colors.front();
998 if (colors.size() > 1)
999 dmcolor = colors.back();
1001 branch_ptr->setColors(lmcolor, dmcolor);
1004 } else if (token == "\\index") {
1006 docstring index = lex.getDocString();
1008 indiceslist().add(index);
1011 string const tok = lex.getString();
1012 if (tok == "\\end_index")
1014 Index * index_ptr = indiceslist().find(index);
1015 if (tok == "\\shortcut") {
1017 shortcut = lex.getDocString();
1019 index_ptr->setShortcut(shortcut);
1021 if (tok == "\\color") {
1023 string color = lex.getString();
1025 index_ptr->setColor(color);
1026 // Update also the Color table:
1027 if (color == "none")
1028 color = lcolor.getX11HexName(Color_background);
1030 if (!shortcut.empty())
1031 lcolor.setColor(to_utf8(shortcut), color);
1034 } else if (token == "\\author") {
1036 istringstream ss(lex.getString());
1040 } else if (token == "\\paperorientation") {
1043 orientation = paperorientationtranslator().find(orient);
1044 } else if (token == "\\backgroundcolor") {
1046 backgroundcolor = lyx::rgbFromHexName(lex.getString());
1047 isbackgroundcolor = true;
1048 } else if (token == "\\fontcolor") {
1050 fontcolor = lyx::rgbFromHexName(lex.getString());
1052 } else if (token == "\\notefontcolor") {
1054 string color = lex.getString();
1055 notefontcolor = lyx::rgbFromHexName(color);
1056 lcolor.setColor("notefontcolor", color);
1057 lcolor.setLaTeXName("notefontcolor", "note_fontcolor");
1058 isnotefontcolor = true;
1059 } else if (token == "\\boxbgcolor") {
1061 string color = lex.getString();
1062 boxbgcolor = lyx::rgbFromHexName(color);
1063 lcolor.setColor("boxbgcolor", color);
1064 isboxbgcolor = true;
1065 } else if (token == "\\paperwidth") {
1067 } else if (token == "\\paperheight") {
1069 } else if (token == "\\leftmargin") {
1071 } else if (token == "\\topmargin") {
1073 } else if (token == "\\rightmargin") {
1075 } else if (token == "\\bottommargin") {
1076 lex >> bottommargin;
1077 } else if (token == "\\headheight") {
1079 } else if (token == "\\headsep") {
1081 } else if (token == "\\footskip") {
1083 } else if (token == "\\columnsep") {
1085 } else if (token == "\\paperfontsize") {
1087 } else if (token == "\\papercolumns") {
1089 } else if (token == "\\listings_params") {
1092 listings_params = InsetListingsParams(par).params();
1093 } else if (token == "\\papersides") {
1096 sides = sidestranslator().find(psides);
1097 } else if (token == "\\paperpagestyle") {
1099 } else if (token == "\\tablestyle") {
1101 } else if (token == "\\bullet") {
1103 } else if (token == "\\bulletLaTeX") {
1104 readBulletsLaTeX(lex);
1105 } else if (token == "\\secnumdepth") {
1107 } else if (token == "\\tocdepth") {
1109 } else if (token == "\\spacing") {
1113 if (nspacing == "other") {
1116 spacing().set(spacetranslator().find(nspacing), tmp_val);
1117 } else if (token == "\\float_placement") {
1118 lex >> float_placement;
1119 } else if (token == "\\float_alignment") {
1120 lex >> float_alignment;
1122 } else if (prefixIs(token, "\\pdf_") || token == "\\use_hyperref") {
1123 string toktmp = pdfoptions().readToken(lex, token);
1124 if (!toktmp.empty()) {
1125 lyxerr << "PDFOptions::readToken(): Unknown token: " <<
1129 } else if (token == "\\html_math_output") {
1132 html_math_output = static_cast<MathOutput>(temp);
1133 } else if (token == "\\html_be_strict") {
1134 lex >> html_be_strict;
1135 } else if (token == "\\html_css_as_file") {
1136 lex >> html_css_as_file;
1137 } else if (token == "\\html_math_img_scale") {
1138 lex >> html_math_img_scale;
1139 } else if (token == "\\html_latex_start") {
1141 html_latex_start = lex.getString();
1142 } else if (token == "\\html_latex_end") {
1144 html_latex_end = lex.getString();
1145 } else if (token == "\\docbook_table_output") {
1148 docbook_table_output = static_cast<TableOutput>(temp);
1149 } else if (token == "\\output_sync") {
1151 } else if (token == "\\output_sync_macro") {
1152 lex >> output_sync_macro;
1153 } else if (token == "\\use_refstyle") {
1154 lex >> use_refstyle;
1155 } else if (token == "\\use_minted") {
1157 } else if (token == "\\use_lineno") {
1159 } else if (token == "\\lineno_options") {
1161 lineno_opts = trim(lex.getString());
1163 lyxerr << "BufferParams::readToken(): Unknown token: " <<
1173 // Quote argument if it contains spaces
1174 string quoteIfNeeded(string const & str) {
1175 if (contains(str, ' '))
1176 return "\"" + str + "\"";
1182 void BufferParams::writeFile(ostream & os, Buffer const * buf) const
1184 // The top of the file is written by the buffer.
1185 // Prints out the buffer info into the .lyx file given by file
1187 os << "\\save_transient_properties "
1188 << convert<string>(save_transient_properties) << '\n';
1190 // the document directory (must end with a path separator)
1191 // realPath() is used to resolve symlinks, while addPath(..., "")
1192 // ensures a trailing path separator.
1194 string filepath = addPath(buf->fileName().onlyPath().realPath(), "");
1195 string const sysdir = inSystemDir(FileName(filepath), docsys) ? docsys
1196 : addPath(package().system_support().realPath(), "");
1197 string const relpath =
1198 to_utf8(makeRelPath(from_utf8(filepath), from_utf8(sysdir)));
1199 if (!prefixIs(relpath, "../") && !FileName::isAbsolute(relpath))
1200 filepath = addPath("/systemlyxdir", relpath);
1201 else if (!save_transient_properties || !lyxrc.save_origin)
1202 filepath = "unavailable";
1203 os << "\\origin " << quoteIfNeeded(filepath) << '\n';
1206 os << "\\textclass "
1207 << quoteIfNeeded(buf->includedFilePath(addName(buf->layoutPos(),
1208 baseClass()->name()), "layout"))
1211 // then the preamble
1212 if (!preamble.empty()) {
1213 // remove '\n' from the end of preamble
1214 docstring const tmppreamble = rtrim(preamble, "\n");
1215 os << "\\begin_preamble\n"
1216 << to_utf8(tmppreamble)
1217 << "\n\\end_preamble\n";
1221 if (!options.empty()) {
1222 os << "\\options " << options << '\n';
1225 // use the class options defined in the layout?
1226 os << "\\use_default_options "
1227 << convert<string>(use_default_options) << "\n";
1229 // the master document
1230 if (!master.empty()) {
1231 os << "\\master " << master << '\n';
1235 if (!removed_modules_.empty()) {
1236 os << "\\begin_removed_modules" << '\n';
1237 for (auto const & mod : removed_modules_)
1239 os << "\\end_removed_modules" << '\n';
1243 if (!layout_modules_.empty()) {
1244 os << "\\begin_modules" << '\n';
1245 for (auto const & mod : layout_modules_)
1247 os << "\\end_modules" << '\n';
1251 if (!included_children_.empty()) {
1252 os << "\\begin_includeonly" << '\n';
1253 for (auto const & c : included_children_)
1255 os << "\\end_includeonly" << '\n';
1258 switch (maintain_unincluded_children) {
1269 os << "\\maintain_unincluded_children " << muc << '\n';
1271 // local layout information
1272 docstring const local_layout = getLocalLayout(false);
1273 if (!local_layout.empty()) {
1274 // remove '\n' from the end
1275 docstring const tmplocal = rtrim(local_layout, "\n");
1276 os << "\\begin_local_layout\n"
1277 << to_utf8(tmplocal)
1278 << "\n\\end_local_layout\n";
1280 docstring const forced_local_layout = getLocalLayout(true);
1281 if (!forced_local_layout.empty()) {
1282 // remove '\n' from the end
1283 docstring const tmplocal = rtrim(forced_local_layout, "\n");
1284 os << "\\begin_forced_local_layout\n"
1285 << to_utf8(tmplocal)
1286 << "\n\\end_forced_local_layout\n";
1289 // then the text parameters
1290 if (language != ignore_language)
1291 os << "\\language " << language->lang() << '\n';
1292 os << "\\language_package " << lang_package
1293 << "\n\\inputencoding " << inputenc
1294 << "\n\\fontencoding " << fontenc
1295 << "\n\\font_roman \"" << fonts_roman[0]
1296 << "\" \"" << fonts_roman[1] << '"'
1297 << "\n\\font_sans \"" << fonts_sans[0]
1298 << "\" \"" << fonts_sans[1] << '"'
1299 << "\n\\font_typewriter \"" << fonts_typewriter[0]
1300 << "\" \"" << fonts_typewriter[1] << '"'
1301 << "\n\\font_math \"" << fonts_math[0]
1302 << "\" \"" << fonts_math[1] << '"'
1303 << "\n\\font_default_family " << fonts_default_family
1304 << "\n\\use_non_tex_fonts " << convert<string>(useNonTeXFonts)
1305 << "\n\\font_sc " << convert<string>(fonts_expert_sc)
1306 << "\n\\font_roman_osf " << convert<string>(fonts_roman_osf)
1307 << "\n\\font_sans_osf " << convert<string>(fonts_sans_osf)
1308 << "\n\\font_typewriter_osf " << convert<string>(fonts_typewriter_osf);
1309 if (!font_roman_opts.empty())
1310 os << "\n\\font_roman_opts \"" << font_roman_opts << "\"";
1311 os << "\n\\font_sf_scale " << fonts_sans_scale[0]
1312 << ' ' << fonts_sans_scale[1];
1313 if (!font_sans_opts.empty())
1314 os << "\n\\font_sans_opts \"" << font_sans_opts << "\"";
1315 os << "\n\\font_tt_scale " << fonts_typewriter_scale[0]
1316 << ' ' << fonts_typewriter_scale[1];
1317 if (!font_typewriter_opts.empty())
1318 os << "\n\\font_typewriter_opts \"" << font_typewriter_opts << "\"";
1320 if (!fonts_cjk.empty())
1321 os << "\\font_cjk " << fonts_cjk << '\n';
1322 os << "\\use_microtype " << convert<string>(use_microtype) << '\n';
1323 os << "\\use_dash_ligatures " << convert<string>(use_dash_ligatures) << '\n';
1324 os << "\\graphics " << graphics_driver << '\n';
1325 os << "\\default_output_format " << default_output_format << '\n';
1326 os << "\\output_sync " << output_sync << '\n';
1327 if (!output_sync_macro.empty())
1328 os << "\\output_sync_macro \"" << output_sync_macro << "\"\n";
1329 os << "\\bibtex_command " << bibtex_command << '\n';
1330 os << "\\index_command " << index_command << '\n';
1332 if (!float_placement.empty())
1333 os << "\\float_placement " << float_placement << '\n';
1334 if (!float_alignment.empty())
1335 os << "\\float_alignment " << float_alignment << '\n';
1336 os << "\\paperfontsize " << fontsize << '\n';
1338 spacing().writeFile(os);
1339 pdfoptions().writeFile(os);
1341 os << "\\papersize " << string_papersize[papersize]
1342 << "\n\\use_geometry " << convert<string>(use_geometry);
1343 map<string, string> const & packages = auto_packages();
1344 for (auto const & pack : packages)
1345 os << "\n\\use_package " << pack.first << ' '
1346 << use_package(pack.first);
1348 os << "\n\\cite_engine ";
1350 if (!cite_engine_.empty())
1355 os << "\n\\cite_engine_type " << theCiteEnginesList.getTypeAsString(cite_engine_type_);
1357 if (!biblio_style.empty())
1358 os << "\n\\biblio_style " << biblio_style;
1359 if (!biblio_opts.empty())
1360 os << "\n\\biblio_options " << biblio_opts;
1361 if (!biblatex_bibstyle.empty())
1362 os << "\n\\biblatex_bibstyle " << biblatex_bibstyle;
1363 if (!biblatex_citestyle.empty())
1364 os << "\n\\biblatex_citestyle " << biblatex_citestyle;
1365 if (!multibib.empty())
1366 os << "\n\\multibib " << multibib;
1368 os << "\n\\use_bibtopic " << convert<string>(use_bibtopic)
1369 << "\n\\use_indices " << convert<string>(use_indices)
1370 << "\n\\paperorientation " << string_orientation[orientation]
1371 << "\n\\suppress_date " << convert<string>(suppress_date)
1372 << "\n\\justification " << convert<string>(justification)
1373 << "\n\\use_refstyle " << use_refstyle
1374 << "\n\\use_minted " << use_minted
1375 << "\n\\use_lineno " << use_lineno
1378 if (!lineno_opts.empty())
1379 os << "\\lineno_options " << lineno_opts << '\n';
1381 if (isbackgroundcolor)
1382 os << "\\backgroundcolor " << lyx::X11hexname(backgroundcolor) << '\n';
1384 os << "\\fontcolor " << lyx::X11hexname(fontcolor) << '\n';
1385 if (isnotefontcolor)
1386 os << "\\notefontcolor " << lyx::X11hexname(notefontcolor) << '\n';
1388 os << "\\boxbgcolor " << lyx::X11hexname(boxbgcolor) << '\n';
1390 for (auto const & br : branchlist()) {
1391 os << "\\branch " << to_utf8(br.branch())
1392 << "\n\\selected " << br.isSelected()
1393 << "\n\\filename_suffix " << br.hasFileNameSuffix()
1394 << "\n\\color " << br.lightModeColor() << " " << br.darkModeColor()
1399 for (auto const & id : indiceslist()) {
1400 os << "\\index " << to_utf8(id.index())
1401 << "\n\\shortcut " << to_utf8(id.shortcut())
1402 << "\n\\color " << lyx::X11hexname(id.color())
1407 if (!paperwidth.empty())
1408 os << "\\paperwidth "
1409 << VSpace(paperwidth).asLyXCommand() << '\n';
1410 if (!paperheight.empty())
1411 os << "\\paperheight "
1412 << VSpace(paperheight).asLyXCommand() << '\n';
1413 if (!leftmargin.empty())
1414 os << "\\leftmargin "
1415 << VSpace(leftmargin).asLyXCommand() << '\n';
1416 if (!topmargin.empty())
1417 os << "\\topmargin "
1418 << VSpace(topmargin).asLyXCommand() << '\n';
1419 if (!rightmargin.empty())
1420 os << "\\rightmargin "
1421 << VSpace(rightmargin).asLyXCommand() << '\n';
1422 if (!bottommargin.empty())
1423 os << "\\bottommargin "
1424 << VSpace(bottommargin).asLyXCommand() << '\n';
1425 if (!headheight.empty())
1426 os << "\\headheight "
1427 << VSpace(headheight).asLyXCommand() << '\n';
1428 if (!headsep.empty())
1430 << VSpace(headsep).asLyXCommand() << '\n';
1431 if (!footskip.empty())
1433 << VSpace(footskip).asLyXCommand() << '\n';
1434 if (!columnsep.empty())
1435 os << "\\columnsep "
1436 << VSpace(columnsep).asLyXCommand() << '\n';
1437 os << "\\secnumdepth " << secnumdepth
1438 << "\n\\tocdepth " << tocdepth
1439 << "\n\\paragraph_separation "
1440 << string_paragraph_separation[paragraph_separation];
1441 if (!paragraph_separation)
1442 os << "\n\\paragraph_indentation "
1443 << (getParIndent().empty() ? "default" : getParIndent().asString());
1445 os << "\n\\defskip " << getDefSkip().asLyXCommand();
1446 os << "\n\\is_math_indent " << is_math_indent;
1448 os << "\n\\math_indentation "
1449 << (getMathIndent().empty() ? "default" : getMathIndent().asString());
1450 os << "\n\\math_numbering_side ";
1451 switch(math_numbering_side) {
1461 os << "\n\\quotes_style "
1462 << string_quotes_style[static_cast<int>(quotes_style)]
1463 << "\n\\dynamic_quotes " << dynamic_quotes
1464 << "\n\\papercolumns " << columns
1465 << "\n\\papersides " << sides
1466 << "\n\\paperpagestyle " << pagestyle
1467 << "\n\\tablestyle " << tablestyle << '\n';
1468 if (!listings_params.empty())
1469 os << "\\listings_params \"" <<
1470 InsetListingsParams(listings_params).encodedString() << "\"\n";
1471 for (int i = 0; i < 4; ++i) {
1472 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
1473 if (user_defined_bullet(i).getFont() != -1) {
1474 os << "\\bullet " << i << " "
1475 << user_defined_bullet(i).getFont() << " "
1476 << user_defined_bullet(i).getCharacter() << " "
1477 << user_defined_bullet(i).getSize() << "\n";
1481 os << "\\bulletLaTeX " << i << " \""
1482 << lyx::to_ascii(user_defined_bullet(i).getText())
1488 os << "\\tracking_changes "
1489 << (save_transient_properties ? convert<string>(track_changes) : "false")
1492 os << "\\output_changes "
1493 << (save_transient_properties ? convert<string>(output_changes) : "false")
1496 os << "\\change_bars "
1497 << (save_transient_properties ? convert<string>(change_bars) : "false")
1500 os << "\\postpone_fragile_content " << convert<string>(postpone_fragile_content) << '\n';
1502 os << "\\html_math_output " << html_math_output << '\n'
1503 << "\\html_css_as_file " << html_css_as_file << '\n'
1504 << "\\html_be_strict " << convert<string>(html_be_strict) << '\n';
1506 os << "\\docbook_table_output " << docbook_table_output << '\n';
1508 if (html_math_img_scale != 1.0)
1509 os << "\\html_math_img_scale " << convert<string>(html_math_img_scale) << '\n';
1510 if (!html_latex_start.empty())
1511 os << "\\html_latex_start " << html_latex_start << '\n';
1512 if (!html_latex_end.empty())
1513 os << "\\html_latex_end " << html_latex_end << '\n';
1515 os << pimpl_->authorlist;
1519 void BufferParams::validate(LaTeXFeatures & features) const
1521 features.require(documentClass().required());
1523 if (columns > 1 && language->rightToLeft())
1524 features.require("rtloutputdblcol");
1526 if (output_changes) {
1527 bool xcolorulem = LaTeXFeatures::isAvailable("ulem") &&
1528 LaTeXFeatures::isAvailable("xcolor");
1530 switch (features.runparams().flavor) {
1532 case Flavor::DviLuaTeX:
1534 features.require("ct-xcolor-ulem");
1535 features.require("ulem");
1536 features.require("xcolor");
1538 features.require("ct-none");
1541 case Flavor::LuaTeX:
1542 case Flavor::PdfLaTeX:
1545 features.require("ct-xcolor-ulem");
1546 features.require("ulem");
1547 features.require("xcolor");
1548 // improves color handling in PDF output
1549 features.require("pdfcolmk");
1551 features.require("ct-none");
1558 features.require("changebar");
1561 // Floats with 'Here definitely' as default setting.
1562 if (float_placement.find('H') != string::npos)
1563 features.require("float");
1565 for (auto const & pm : use_packages) {
1566 if (pm.first == "amsmath") {
1567 // AMS Style is at document level
1568 if (pm.second == package_on ||
1569 features.isProvided("amsmath"))
1570 features.require(pm.first);
1571 } else if (pm.second == package_on)
1572 features.require(pm.first);
1575 // Document-level line spacing
1576 if (spacing().getSpace() != Spacing::Single && !spacing().isDefault())
1577 features.require("setspace");
1579 // the bullet shapes are buffer level not paragraph level
1580 // so they are tested here
1581 for (int i = 0; i < 4; ++i) {
1582 if (user_defined_bullet(i) == ITEMIZE_DEFAULTS[i])
1584 int const font = user_defined_bullet(i).getFont();
1586 int const c = user_defined_bullet(i).getCharacter();
1592 features.require("latexsym");
1594 } else if (font == 1) {
1595 features.require("amssymb");
1596 } else if (font >= 2 && font <= 5) {
1597 features.require("pifont");
1601 if (pdfoptions().use_hyperref) {
1602 features.require("hyperref");
1603 // due to interferences with babel and hyperref, the color package has to
1604 // be loaded after hyperref when hyperref is used with the colorlinks
1605 // option, see http://www.lyx.org/trac/ticket/5291
1606 if (pdfoptions().colorlinks)
1607 features.require("color");
1609 if (!listings_params.empty()) {
1610 // do not test validity because listings_params is
1611 // supposed to be valid
1613 InsetListingsParams(listings_params).separatedParams(true);
1614 // we can't support all packages, but we should load the color package
1615 if (par.find("\\color", 0) != string::npos)
1616 features.require("color");
1619 // some languages are only available via polyglossia
1620 if (features.hasPolyglossiaExclusiveLanguages())
1621 features.require("polyglossia");
1623 if (useNonTeXFonts && fontsMath() != "auto")
1624 features.require("unicode-math");
1627 features.require("microtype");
1629 if (!language->required().empty())
1630 features.require(language->required());
1634 bool BufferParams::writeLaTeX(otexstream & os, LaTeXFeatures & features,
1635 FileName const & filepath) const
1637 // http://www.tug.org/texmf-dist/doc/latex/base/fixltx2e.pdf
1638 // !! To use the Fix-cm package, load it before \documentclass, and use the command
1639 // \RequirePackage to do so, rather than the normal \usepackage
1640 // Do not try to load any other package before the document class, unless you
1641 // have a thorough understanding of the LATEX internals and know exactly what you
1643 if (features.mustProvide("fix-cm"))
1644 os << "\\RequirePackage{fix-cm}\n";
1645 // Likewise for fixltx2e. If other packages conflict with this policy,
1646 // treat it as a package bug (and report it!)
1647 // See http://www.latex-project.org/cgi-bin/ltxbugs2html?pr=latex/4407
1648 if (features.mustProvide("fixltx2e"))
1649 os << "\\RequirePackage{fixltx2e}\n";
1651 os << "\\documentclass";
1653 DocumentClass const & tclass = documentClass();
1655 ostringstream clsoptions; // the document class options.
1657 if (tokenPos(tclass.opt_fontsize(),
1658 '|', fontsize) >= 0) {
1659 // only write if existing in list (and not default)
1660 clsoptions << subst(tclass.fontsizeformat(), "$$s", fontsize) << ",";
1663 // paper sizes not supported by the class itself need the
1665 vector<string> classpsizes = getVectorFromString(tclass.opt_pagesize(), "|");
1666 bool class_supported_papersize = papersize == PAPER_DEFAULT
1667 || find(classpsizes.begin(), classpsizes.end(), string_papersize[papersize]) != classpsizes.end();
1669 if ((!use_geometry || features.isProvided("geometry-light"))
1670 && class_supported_papersize && papersize != PAPER_DEFAULT)
1671 clsoptions << subst(tclass.pagesizeformat(), "$$s", string_papersize[papersize]) << ",";
1674 if (sides != tclass.sides()) {
1677 clsoptions << "oneside,";
1680 clsoptions << "twoside,";
1686 if (columns != tclass.columns()) {
1688 clsoptions << "twocolumn,";
1690 clsoptions << "onecolumn,";
1694 && orientation == ORIENTATION_LANDSCAPE)
1695 clsoptions << "landscape,";
1698 clsoptions << "fleqn,";
1700 switch(math_numbering_side) {
1702 clsoptions << "leqno,";
1705 clsoptions << "reqno,";
1706 features.require("amsmath");
1712 // language should be a parameter to \documentclass
1713 if (language->babel() == "hebrew"
1714 && default_language->babel() != "hebrew")
1715 // This seems necessary
1716 features.useLanguage(default_language);
1718 ostringstream language_options;
1719 bool const use_babel = features.useBabel() && !features.isProvided("babel");
1720 bool const use_polyglossia = features.usePolyglossia();
1721 bool const global = lyxrc.language_global_options;
1722 if (features.useBabel() || (use_polyglossia && global)) {
1723 language_options << features.getBabelLanguages();
1724 if (!language->babel().empty()) {
1725 if (!language_options.str().empty())
1726 language_options << ',';
1727 language_options << language->babel();
1729 if (global && !language_options.str().empty())
1730 clsoptions << language_options.str() << ',';
1733 // the predefined options from the layout
1734 if (use_default_options && !tclass.options().empty())
1735 clsoptions << tclass.options() << ',';
1737 // the user-defined options
1738 if (!options.empty()) {
1739 clsoptions << options << ',';
1742 docstring const strOptions = from_utf8(clsoptions.str());
1743 if (!strOptions.empty()) {
1744 // Check if class options contain uncodable glyphs
1745 docstring uncodable_glyphs;
1746 docstring options_encodable;
1747 Encoding const * const enc = features.runparams().encoding;
1749 for (char_type c : strOptions) {
1750 if (!enc->encodable(c)) {
1751 docstring const glyph(1, c);
1752 LYXERR0("Uncodable character '"
1754 << "' in class options!");
1755 uncodable_glyphs += glyph;
1756 if (features.runparams().dryrun) {
1757 options_encodable += "<" + _("LyX Warning: ")
1758 + _("uncodable character") + " '";
1759 options_encodable += c;
1760 options_encodable += "'>";
1763 options_encodable += c;
1766 options_encodable = strOptions;
1768 // On BUFFER_VIEW|UPDATE, warn user if we found uncodable glyphs
1769 if (!features.runparams().dryrun && !uncodable_glyphs.empty()) {
1770 frontend::Alert::warning(
1771 _("Uncodable character in class options"),
1773 _("The class options of your document contain glyphs "
1774 "that are unknown in the current document encoding "
1775 "(namely %1$s).\nThese glyphs are omitted "
1776 " from the output, which may result in "
1777 "incomplete output."
1778 "\n\nPlease select an appropriate "
1779 "document encoding\n"
1780 "(such as utf8) or change the "
1781 "class options accordingly."),
1784 options_encodable = rtrim(options_encodable, ",");
1785 os << '[' << options_encodable << ']';
1788 os << '{' << from_ascii(tclass.latexname()) << "}\n";
1789 // end of \documentclass defs
1791 // The package options (via \PassOptionsToPackage)
1792 os << from_ascii(features.getPackageOptions());
1794 // if we use fontspec or newtxmath, we have to load the AMS packages here
1795 string const ams = features.loadAMSPackages();
1796 bool const ot1 = (main_font_encoding() == "default" || main_font_encoding() == "OT1");
1797 bool const use_newtxmath =
1798 theLaTeXFonts().getLaTeXFont(from_ascii(fontsMath())).getUsedPackage(
1799 ot1, false, false) == "newtxmath";
1800 if ((useNonTeXFonts || use_newtxmath) && !ams.empty())
1801 os << from_ascii(ams);
1803 if (useNonTeXFonts) {
1804 // Babel (as of 2017/11/03) loads fontspec itself
1805 if (!features.isProvided("fontspec")
1806 && !(features.useBabel() && features.isAvailable("babel-2017/11/03")))
1807 os << "\\usepackage{fontspec}\n";
1808 if (features.mustProvide("unicode-math")
1809 && features.isAvailable("unicode-math"))
1810 os << "\\usepackage{unicode-math}\n";
1813 // load CJK support package before font selection
1814 // (see autotests/export/latex/CJK/micro-sign_utf8-cjk-libertine.lyx)
1815 if (!useNonTeXFonts && encoding().package() != Encoding::none && inputenc != "utf8x"
1816 && (encoding().package() == Encoding::CJK || features.mustProvide("CJK"))) {
1817 if (inputenc == "utf8-cjk" || inputenc == "utf8")
1818 os << "\\usepackage{CJKutf8}\n";
1820 os << "\\usepackage[encapsulated]{CJK}\n";
1823 // font selection must be done before loading fontenc.sty
1824 // but after babel with non-TeX fonts
1825 string const fonts = loadFonts(features);
1826 if (!fonts.empty() && (!features.useBabel() || !useNonTeXFonts))
1827 os << from_utf8(fonts);
1829 if (fonts_default_family != "default")
1830 os << "\\renewcommand{\\familydefault}{\\"
1831 << from_ascii(fonts_default_family) << "}\n";
1833 // set font encoding
1834 // non-TeX fonts use font encoding TU (set by fontspec)
1835 if (!useNonTeXFonts && !features.isProvided("fontenc")
1836 && main_font_encoding() != "default") {
1837 // get main font encodings
1838 vector<string> fontencs = font_encodings();
1839 // get font encodings of secondary languages
1840 // FIXME: some languages (hebrew, ...) assume a standard font encoding as last
1841 // option (for text in other languages).
1842 features.getFontEncodings(fontencs);
1843 if (!fontencs.empty()) {
1844 os << "\\usepackage["
1845 << from_ascii(getStringFromVector(fontencs))
1850 // Load textcomp and pmboxdraw before (lua)inputenc (#11454)
1851 if (features.mustProvide("textcomp"))
1852 os << "\\usepackage{textcomp}\n";
1853 if (features.mustProvide("pmboxdraw"))
1854 os << "\\usepackage{pmboxdraw}\n";
1856 // handle inputenc etc.
1857 // (In documents containing text in Thai language,
1858 // we must load inputenc after babel, see lib/languages).
1859 if (!contains(features.getBabelPostsettings(), from_ascii("thai.ldf")))
1860 writeEncodingPreamble(os, features);
1863 if (!features.runparams().includeall && !included_children_.empty()) {
1864 os << "\\includeonly{";
1866 for (auto incfile : included_children_) {
1867 FileName inc = makeAbsPath(incfile, filepath.absFileName());
1868 string mangled = DocFileName(changeExtension(inc.absFileName(), ".tex")).
1870 if (!features.runparams().nice)
1872 // \includeonly doesn't want an extension
1873 incfile = changeExtension(incfile, string());
1874 incfile = support::latex_path(incfile);
1875 if (!incfile.empty()) {
1878 os << from_utf8(incfile);
1885 if (!features.isProvided("geometry")
1886 && (use_geometry || !class_supported_papersize)) {
1887 odocstringstream ods;
1888 if (!getGraphicsDriver("geometry").empty())
1889 ods << getGraphicsDriver("geometry");
1890 if (orientation == ORIENTATION_LANDSCAPE)
1891 ods << ",landscape";
1892 switch (papersize) {
1894 if (!paperwidth.empty())
1895 ods << ",paperwidth="
1896 << from_ascii(paperwidth);
1897 if (!paperheight.empty())
1898 ods << ",paperheight="
1899 << from_ascii(paperheight);
1901 case PAPER_USLETTER:
1903 case PAPER_USEXECUTIVE:
1932 ods << "," << from_ascii(string_papersize_geometry[papersize]);
1937 docstring g_options = trim(ods.str(), ",");
1938 os << "\\usepackage";
1939 // geometry-light means that the class works with geometry, but overwrites
1940 // the package options and paper sizes (memoir does this).
1941 // In this case, all options need to go to \geometry
1942 // and the standard paper sizes need to go to the class options.
1943 if (!g_options.empty() && !features.isProvided("geometry-light")) {
1944 os << '[' << g_options << ']';
1947 os << "{geometry}\n";
1948 if (use_geometry || features.isProvided("geometry-light")) {
1949 os << "\\geometry{verbose";
1950 if (!g_options.empty())
1951 // Output general options here with "geometry light".
1952 os << "," << g_options;
1953 // output this only if use_geometry is true
1955 if (!topmargin.empty())
1956 os << ",tmargin=" << from_ascii(Length(topmargin).asLatexString());
1957 if (!bottommargin.empty())
1958 os << ",bmargin=" << from_ascii(Length(bottommargin).asLatexString());
1959 if (!leftmargin.empty())
1960 os << ",lmargin=" << from_ascii(Length(leftmargin).asLatexString());
1961 if (!rightmargin.empty())
1962 os << ",rmargin=" << from_ascii(Length(rightmargin).asLatexString());
1963 if (!headheight.empty())
1964 os << ",headheight=" << from_ascii(Length(headheight).asLatexString());
1965 if (!headsep.empty())
1966 os << ",headsep=" << from_ascii(Length(headsep).asLatexString());
1967 if (!footskip.empty())
1968 os << ",footskip=" << from_ascii(Length(footskip).asLatexString());
1969 if (!columnsep.empty())
1970 os << ",columnsep=" << from_ascii(Length(columnsep).asLatexString());
1974 } else if (orientation == ORIENTATION_LANDSCAPE
1975 || papersize != PAPER_DEFAULT) {
1976 features.require("papersize");
1979 if (tokenPos(tclass.opt_pagestyle(), '|', pagestyle) >= 0) {
1980 if (pagestyle == "fancy")
1981 os << "\\usepackage{fancyhdr}\n";
1982 os << "\\pagestyle{" << from_ascii(pagestyle) << "}\n";
1985 // only output when the background color is not default
1986 if (isbackgroundcolor) {
1987 // only require color here, the background color will be defined
1988 // in LaTeXFeatures.cpp to avoid interferences with the LaTeX
1990 features.require("color");
1991 features.require("pagecolor");
1994 // only output when the font color is not default
1996 // only require color here, the font color will be defined
1997 // in LaTeXFeatures.cpp to avoid interferences with the LaTeX
1999 features.require("color");
2000 features.require("fontcolor");
2003 // Only if class has a ToC hierarchy
2004 if (tclass.hasTocLevels()) {
2005 if (secnumdepth != tclass.secnumdepth()) {
2006 os << "\\setcounter{secnumdepth}{"
2010 if (tocdepth != tclass.tocdepth()) {
2011 os << "\\setcounter{tocdepth}{"
2017 if (paragraph_separation) {
2018 // when skip separation
2020 switch (getDefSkip().kind()) {
2021 case VSpace::SMALLSKIP:
2022 psopt = "\\smallskipamount";
2024 case VSpace::MEDSKIP:
2025 psopt = "\\medskipamount";
2027 case VSpace::BIGSKIP:
2028 psopt = "\\bigskipamount";
2030 case VSpace::HALFLINE:
2031 // default (no option)
2033 case VSpace::FULLLINE:
2034 psopt = "\\baselineskip";
2036 case VSpace::LENGTH:
2037 psopt = getDefSkip().length().asLatexString();
2042 if (!features.isProvided("parskip")) {
2044 psopt = "[skip=" + psopt + "]";
2045 os << "\\usepackage" + psopt + "{parskip}\n";
2047 os << "\\setlength{\\parskip}{" + psopt + "}\n";
2050 // when separation by indentation
2051 // only output something when a width is given
2052 if (!getParIndent().empty()) {
2053 os << "\\setlength{\\parindent}{"
2054 << from_utf8(getParIndent().asLatexString())
2059 if (is_math_indent) {
2060 // when formula indentation
2061 // only output something when it is not the default
2062 if (!getMathIndent().empty()) {
2063 os << "\\setlength{\\mathindent}{"
2064 << from_utf8(getMathIndent().asString())
2069 // Now insert the LyX specific LaTeX commands...
2070 features.resolveAlternatives();
2071 features.expandMultiples();
2074 if (!output_sync_macro.empty())
2075 os << from_utf8(output_sync_macro) +"\n";
2076 else if (features.runparams().flavor == Flavor::LaTeX)
2077 os << "\\usepackage[active]{srcltx}\n";
2078 else if (features.runparams().flavor == Flavor::PdfLaTeX)
2079 os << "\\synctex=-1\n";
2082 // due to interferences with babel and hyperref, the color package has to
2083 // be loaded (when it is not already loaded) before babel when hyperref
2084 // is used with the colorlinks option, see
2085 // http://www.lyx.org/trac/ticket/5291
2086 // we decided therefore to load color always before babel, see
2087 // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg144349.html
2088 os << from_ascii(features.getColorOptions());
2090 // If we use hyperref, jurabib, japanese or varioref,
2091 // we have to call babel before
2093 && (features.isRequired("jurabib")
2094 || features.isRequired("hyperref")
2095 || features.isRequired("varioref")
2096 || features.isRequired("japanese"))) {
2097 os << features.getBabelPresettings();
2099 os << from_utf8(babelCall(language_options.str(),
2100 !lyxrc.language_global_options)) + '\n';
2101 os << features.getBabelPostsettings();
2104 // The optional packages;
2105 os << from_ascii(features.getPackages());
2107 // Additional Indices
2108 if (features.isRequired("splitidx")) {
2109 for (auto const & idx : indiceslist()) {
2110 os << "\\newindex{";
2111 os << escape(idx.shortcut());
2117 os << from_utf8(spacing().writePreamble(features.isProvided("SetSpace")));
2120 // * Hyperref manual: "Make sure it comes last of your loaded
2121 // packages, to give it a fighting chance of not being over-written,
2122 // since its job is to redefine many LaTeX commands."
2123 // * Email from Heiko Oberdiek: "It is usually better to load babel
2124 // before hyperref. Then hyperref has a chance to detect babel.
2125 // * Has to be loaded before the "LyX specific LaTeX commands" to
2126 // avoid errors with algorithm floats.
2127 // use hyperref explicitly if it is required
2128 if (features.isRequired("hyperref")) {
2129 OutputParams tmp_params = features.runparams();
2130 pdfoptions().writeLaTeX(tmp_params, os,
2131 features.isProvided("hyperref"));
2132 // correctly break URLs with hyperref and dvi/ps output
2133 if (features.runparams().hyperref_driver == "dvips"
2134 && features.isAvailable("breakurl"))
2135 os << "\\usepackage{breakurl}\n";
2136 } else if (features.isRequired("nameref"))
2137 // hyperref loads this automatically
2138 os << "\\usepackage{nameref}\n";
2141 os << "\\usepackage";
2142 if (!lineno_opts.empty())
2143 os << "[" << lineno_opts << "]";
2145 os << "\\linenumbers\n";
2148 // bibtopic needs to be loaded after hyperref.
2149 // the dot provides the aux file naming which LyX can detect.
2150 if (features.mustProvide("bibtopic"))
2151 os << "\\usepackage[dot]{bibtopic}\n";
2153 // Will be surrounded by \makeatletter and \makeatother when not empty
2154 otexstringstream atlyxpreamble;
2156 // Some macros LyX will need
2158 TexString tmppreamble = features.getMacros();
2159 if (!tmppreamble.str.empty())
2160 atlyxpreamble << "\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
2161 "LyX specific LaTeX commands.\n"
2162 << move(tmppreamble)
2165 // the text class specific preamble
2167 docstring tmppreamble = features.getTClassPreamble();
2168 if (!tmppreamble.empty())
2169 atlyxpreamble << "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
2170 "Textclass specific LaTeX commands.\n"
2174 // suppress date if selected
2175 // use \@ifundefined because we cannot be sure that every document class
2176 // has a \date command
2178 atlyxpreamble << "\\@ifundefined{date}{}{\\date{}}\n";
2180 /* the user-defined preamble */
2181 if (!containsOnly(preamble, " \n\t")) {
2183 atlyxpreamble << "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
2184 "User specified LaTeX commands.\n";
2186 // Check if the user preamble contains uncodable glyphs
2187 odocstringstream user_preamble;
2188 docstring uncodable_glyphs;
2189 Encoding const * const enc = features.runparams().encoding;
2191 for (char_type c : preamble) {
2192 if (!enc->encodable(c)) {
2193 docstring const glyph(1, c);
2194 LYXERR0("Uncodable character '"
2196 << "' in user preamble!");
2197 uncodable_glyphs += glyph;
2198 if (features.runparams().dryrun) {
2199 user_preamble << "<" << _("LyX Warning: ")
2200 << _("uncodable character") << " '";
2201 user_preamble.put(c);
2202 user_preamble << "'>";
2205 user_preamble.put(c);
2208 user_preamble << preamble;
2210 // On BUFFER_VIEW|UPDATE, warn user if we found uncodable glyphs
2211 if (!features.runparams().dryrun && !uncodable_glyphs.empty()) {
2212 frontend::Alert::warning(
2213 _("Uncodable character in user preamble"),
2215 _("The user preamble of your document contains glyphs "
2216 "that are unknown in the current document encoding "
2217 "(namely %1$s).\nThese glyphs are omitted "
2218 " from the output, which may result in "
2219 "incomplete output."
2220 "\n\nPlease select an appropriate "
2221 "document encoding\n"
2222 "(such as utf8) or change the "
2223 "preamble code accordingly."),
2226 atlyxpreamble << user_preamble.str() << '\n';
2229 // footmisc must be loaded after setspace
2230 // Load it here to avoid clashes with footmisc loaded in the user
2231 // preamble. For that reason we also pass the options via
2232 // \PassOptionsToPackage in getPreamble() and not here.
2233 if (features.mustProvide("footmisc"))
2234 atlyxpreamble << "\\usepackage{footmisc}\n";
2236 // subfig loads internally the LaTeX package "caption". As
2237 // caption is a very popular package, users will load it in
2238 // the preamble. Therefore we must load subfig behind the
2239 // user-defined preamble and check if the caption package was
2240 // loaded or not. For the case that caption is loaded before
2241 // subfig, there is the subfig option "caption=false". This
2242 // option also works when a koma-script class is used and
2243 // koma's own caption commands are used instead of caption. We
2244 // use \PassOptionsToPackage here because the user could have
2245 // already loaded subfig in the preamble.
2246 if (features.mustProvide("subfig"))
2247 atlyxpreamble << "\\ifdefined\\showcaptionsetup\n"
2248 " % Caption package is used. Advise subfig not to load it again.\n"
2249 " \\PassOptionsToPackage{caption=false}{subfig}\n"
2251 "\\usepackage{subfig}\n";
2253 // Itemize bullet settings need to be last in case the user
2254 // defines their own bullets that use a package included
2255 // in the user-defined preamble -- ARRae
2256 // Actually it has to be done much later than that
2257 // since some packages like frenchb make modifications
2258 // at \begin{document} time -- JMarc
2259 docstring bullets_def;
2260 for (int i = 0; i < 4; ++i) {
2261 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
2262 if (bullets_def.empty())
2263 bullets_def += "\\AtBeginDocument{\n";
2264 bullets_def += " \\def\\labelitemi";
2266 // `i' is one less than the item to modify
2273 bullets_def += "ii";
2279 bullets_def += '{' +
2280 user_defined_bullet(i).getText()
2285 if (!bullets_def.empty())
2286 atlyxpreamble << bullets_def << "}\n\n";
2288 if (!atlyxpreamble.empty())
2289 os << "\n\\makeatletter\n"
2290 << atlyxpreamble.release()
2291 << "\\makeatother\n\n";
2293 // We try to load babel late, in case it interferes with other packages.
2294 // Jurabib, hyperref, varioref, bicaption, menukeys and listings (bug 8995)
2295 // have to be called after babel, though.
2296 if (use_babel && !features.isRequired("jurabib")
2297 && !features.isRequired("hyperref")
2298 && !features.isRequired("varioref")
2299 && !features.isRequired("japanese")) {
2300 os << features.getBabelPresettings();
2302 os << from_utf8(babelCall(language_options.str(),
2303 !lyxrc.language_global_options)) + '\n';
2304 os << features.getBabelPostsettings();
2306 // In documents containing text in Thai language,
2307 // we must load inputenc after babel (see lib/languages).
2308 if (contains(features.getBabelPostsettings(), from_ascii("thai.ldf")))
2309 writeEncodingPreamble(os, features);
2311 // font selection must be done after babel with non-TeX fonts
2312 if (!fonts.empty() && features.useBabel() && useNonTeXFonts)
2313 os << from_utf8(fonts);
2315 if (features.isRequired("bicaption"))
2316 os << "\\usepackage{bicaption}\n";
2317 if (!listings_params.empty()
2318 || features.mustProvide("listings")
2319 || features.mustProvide("minted")) {
2321 os << "\\usepackage{minted}\n";
2323 os << "\\usepackage{listings}\n";
2325 string lst_params = listings_params;
2326 // If minted, do not output the language option (bug 11203)
2327 if (use_minted && contains(lst_params, "language=")) {
2328 vector<string> opts =
2329 getVectorFromString(lst_params, ",", false);
2330 for (size_t i = 0; i < opts.size(); ++i) {
2331 if (prefixIs(opts[i], "language="))
2332 opts.erase(opts.begin() + i--);
2334 lst_params = getStringFromVector(opts, ",");
2336 if (!lst_params.empty()) {
2338 os << "\\setminted{";
2341 // do not test validity because listings_params is
2342 // supposed to be valid
2344 InsetListingsParams(lst_params).separatedParams(true);
2345 os << from_utf8(par);
2349 // xunicode only needs to be loaded if tipa is used
2350 // (the rest is obsoleted by the new TU encoding).
2351 // It needs to be loaded at least after amsmath, amssymb,
2352 // esint and the other packages that provide special glyphs
2353 if (features.mustProvide("tipa") && useNonTeXFonts
2354 && !features.isProvided("xunicode")) {
2355 // The `xunicode` package officially only supports XeTeX,
2356 // but also works with LuaTeX. We work around its XeTeX test.
2357 if (features.runparams().flavor != Flavor::XeTeX) {
2358 os << "% Pretend to xunicode that we are XeTeX\n"
2359 << "\\def\\XeTeXpicfile{}\n";
2361 os << "\\usepackage{xunicode}\n";
2364 // covington must be loaded after beamerarticle
2365 if (features.isRequired("covington"))
2366 os << "\\usepackage{covington}\n";
2368 // Polyglossia must be loaded last ...
2369 if (use_polyglossia) {
2371 os << "\\usepackage{polyglossia}\n";
2372 // set the main language
2373 os << "\\setdefaultlanguage";
2374 if (!language->polyglossiaOpts().empty())
2375 os << "[" << from_ascii(language->polyglossiaOpts()) << "]";
2376 os << "{" << from_ascii(language->polyglossia()) << "}\n";
2377 // now setup the other languages
2378 set<string> const polylangs =
2379 features.getPolyglossiaLanguages();
2380 for (auto const & pl : polylangs) {
2381 // We do not output the options here; they are output in
2382 // the language switch commands. This is safer if multiple
2383 // varieties are used.
2384 if (pl == language->polyglossia())
2386 os << "\\setotherlanguage";
2387 os << "{" << from_ascii(pl) << "}\n";
2391 // ... but before biblatex (see #7065)
2392 if ((features.mustProvide("biblatex")
2393 || features.isRequired("biblatex-chicago"))
2394 && !features.isProvided("biblatex-chicago")
2395 && !features.isProvided("biblatex-natbib")
2396 && !features.isProvided("natbib-internal")
2397 && !features.isProvided("natbib")
2398 && !features.isProvided("jurabib")) {
2399 // The biblatex-chicago package has a differing interface
2400 // it uses a wrapper package and loads styles via fixed options
2401 bool const chicago = features.isRequired("biblatex-chicago");
2404 os << "\\usepackage";
2405 if (!biblatex_bibstyle.empty()
2406 && (biblatex_bibstyle == biblatex_citestyle)
2408 opts = "style=" + biblatex_bibstyle;
2410 } else if (!chicago) {
2411 if (!biblatex_bibstyle.empty()) {
2412 opts = "bibstyle=" + biblatex_bibstyle;
2415 if (!biblatex_citestyle.empty()) {
2416 opts += delim + "citestyle=" + biblatex_citestyle;
2420 if (!multibib.empty() && multibib != "child") {
2421 opts += delim + "refsection=" + multibib;
2424 if (bibtexCommand() == "bibtex8"
2425 || prefixIs(bibtexCommand(), "bibtex8 ")) {
2426 opts += delim + "backend=bibtex8";
2428 } else if (bibtexCommand() == "bibtex"
2429 || prefixIs(bibtexCommand(), "bibtex ")) {
2430 opts += delim + "backend=bibtex";
2433 if (!bib_encoding.empty() && encodings.fromLyXName(bib_encoding)) {
2434 opts += delim + "bibencoding="
2435 + encodings.fromLyXName(bib_encoding)->latexName();
2438 if (!biblio_opts.empty())
2439 opts += delim + biblio_opts;
2441 os << "[" << opts << "]";
2443 os << "{biblatex-chicago}\n";
2445 os << "{biblatex}\n";
2449 // Load custom language package here
2450 if (features.langPackage() == LaTeXFeatures::LANG_PACK_CUSTOM) {
2451 if (lang_package == "default")
2452 os << from_utf8(lyxrc.language_custom_package);
2454 os << from_utf8(lang_package);
2458 // Since menukeys uses catoptions, which does some heavy changes on key-value options,
2459 // it is recommended to load menukeys as the last package (even after hyperref)
2460 if (features.isRequired("menukeys"))
2461 os << "\\usepackage{menukeys}\n";
2463 docstring const i18npreamble =
2464 features.getTClassI18nPreamble(use_babel, use_polyglossia,
2466 if (!i18npreamble.empty())
2467 os << i18npreamble + '\n';
2473 void BufferParams::useClassDefaults()
2475 DocumentClass const & tclass = documentClass();
2477 sides = tclass.sides();
2478 columns = tclass.columns();
2479 pagestyle = tclass.pagestyle();
2480 tablestyle = tclass.tablestyle();
2481 use_default_options = true;
2482 // Only if class has a ToC hierarchy
2483 if (tclass.hasTocLevels()) {
2484 secnumdepth = tclass.secnumdepth();
2485 tocdepth = tclass.tocdepth();
2490 bool BufferParams::hasClassDefaults() const
2492 DocumentClass const & tclass = documentClass();
2494 return sides == tclass.sides()
2495 && columns == tclass.columns()
2496 && pagestyle == tclass.pagestyle()
2497 && tablestyle == tclass.tablestyle()
2498 && use_default_options
2499 && secnumdepth == tclass.secnumdepth()
2500 && tocdepth == tclass.tocdepth();
2504 DocumentClass const & BufferParams::documentClass() const
2510 DocumentClassConstPtr BufferParams::documentClassPtr() const
2516 void BufferParams::setDocumentClass(DocumentClassConstPtr tc)
2518 // evil, but this function is evil
2519 doc_class_ = const_pointer_cast<DocumentClass>(tc);
2520 invalidateConverterCache();
2524 bool BufferParams::setBaseClass(string const & classname, string const & path)
2526 LYXERR(Debug::TCLASS, "setBaseClass: " << classname);
2527 LayoutFileList & bcl = LayoutFileList::get();
2528 if (!bcl.haveClass(classname)) {
2530 bformat(_("The layout file:\n"
2532 "could not be found. A default textclass with default\n"
2533 "layouts will be used. LyX will not be able to produce\n"
2535 from_utf8(classname));
2536 frontend::Alert::error(_("Document class not found"), s);
2537 bcl.addEmptyClass(classname);
2540 bool const success = bcl[classname].load(path);
2543 bformat(_("Due to some error in it, the layout file:\n"
2545 "could not be loaded. A default textclass with default\n"
2546 "layouts will be used. LyX will not be able to produce\n"
2548 from_utf8(classname));
2549 frontend::Alert::error(_("Could not load class"), s);
2550 bcl.addEmptyClass(classname);
2553 pimpl_->baseClass_ = classname;
2554 layout_modules_.adaptToBaseClass(baseClass(), removed_modules_);
2559 LayoutFile const * BufferParams::baseClass() const
2561 if (LayoutFileList::get().haveClass(pimpl_->baseClass_))
2562 return &(LayoutFileList::get()[pimpl_->baseClass_]);
2568 LayoutFileIndex const & BufferParams::baseClassID() const
2570 return pimpl_->baseClass_;
2574 void BufferParams::makeDocumentClass(bool clone, bool internal)
2579 invalidateConverterCache();
2580 LayoutModuleList mods;
2581 for (auto const & mod : layout_modules_)
2582 mods.push_back(mod);
2584 doc_class_ = getDocumentClass(*baseClass(), mods, cite_engine_, clone, internal);
2586 TextClass::ReturnValues success = TextClass::OK;
2587 if (!forced_local_layout_.empty())
2588 success = doc_class_->read(to_utf8(forced_local_layout_),
2590 if (!local_layout_.empty() &&
2591 (success == TextClass::OK || success == TextClass::OK_OLDFORMAT))
2592 success = doc_class_->read(to_utf8(local_layout_), TextClass::MODULE);
2593 if (success != TextClass::OK && success != TextClass::OK_OLDFORMAT) {
2594 docstring const msg = _("Error reading internal layout information");
2595 frontend::Alert::warning(_("Read Error"), msg);
2600 bool BufferParams::layoutModuleCanBeAdded(string const & modName) const
2602 return layout_modules_.moduleCanBeAdded(modName, baseClass());
2606 docstring BufferParams::getLocalLayout(bool forced) const
2609 return from_utf8(doc_class_->forcedLayouts());
2611 return local_layout_;
2615 void BufferParams::setLocalLayout(docstring const & layout, bool forced)
2618 forced_local_layout_ = layout;
2620 local_layout_ = layout;
2624 bool BufferParams::addLayoutModule(string const & modName)
2626 for (auto const & mod : layout_modules_)
2629 layout_modules_.push_back(modName);
2634 string BufferParams::bufferFormat() const
2636 return documentClass().outputFormat();
2640 bool BufferParams::isExportable(string const & format, bool need_viewable) const
2642 FormatList const & formats = exportableFormats(need_viewable);
2643 for (auto const & fmt : formats) {
2644 if (fmt->name() == format)
2651 FormatList const & BufferParams::exportableFormats(bool only_viewable) const
2653 FormatList & cached = only_viewable ?
2654 pimpl_->viewableFormatList : pimpl_->exportableFormatList;
2655 bool & valid = only_viewable ?
2656 pimpl_->isViewCacheValid : pimpl_->isExportCacheValid;
2660 vector<string> const backs = backends();
2661 set<string> excludes;
2662 if (useNonTeXFonts) {
2663 excludes.insert("latex");
2664 excludes.insert("pdflatex");
2665 } else if (inputenc != "ascii" && inputenc != "utf8-plain") {
2666 // XeTeX with TeX fonts requires input encoding ascii (#10600).
2667 excludes.insert("xetex");
2671 theConverters().getReachable(backs[0], only_viewable, true, excludes);
2672 vector<string>::const_iterator it = backs.begin() + 1;
2673 for (; it != backs.end(); ++it) {
2674 FormatList r = theConverters().getReachable(*it, only_viewable,
2676 result.insert(result.end(), r.begin(), r.end());
2678 sort(result.begin(), result.end(), Format::formatSorter);
2685 vector<string> BufferParams::backends() const
2688 string const buffmt = bufferFormat();
2690 // FIXME: Don't hardcode format names here, but use a flag
2691 if (buffmt == "latex") {
2692 if (encoding().package() == Encoding::japanese)
2693 v.push_back("platex");
2695 if (!useNonTeXFonts) {
2696 v.push_back("pdflatex");
2697 v.push_back("latex");
2700 || inputenc == "ascii" || inputenc == "utf8-plain")
2701 v.push_back("xetex");
2702 v.push_back("luatex");
2703 v.push_back("dviluatex");
2706 string rbuffmt = buffmt;
2707 // If we use an OutputFormat in Japanese docs,
2708 // we need special format in order to get the path
2709 // via pLaTeX (#8823)
2710 if (documentClass().hasOutputFormat()
2711 && encoding().package() == Encoding::japanese)
2713 v.push_back(rbuffmt);
2716 v.push_back("xhtml");
2717 v.push_back("docbook5");
2718 v.push_back("text");
2724 Flavor BufferParams::getOutputFlavor(string const & format) const
2726 string const dformat = (format.empty() || format == "default") ?
2727 getDefaultOutputFormat() : format;
2728 DefaultFlavorCache::const_iterator it =
2729 default_flavors_.find(dformat);
2731 if (it != default_flavors_.end())
2734 Flavor result = Flavor::LaTeX;
2736 // FIXME It'd be better not to hardcode this, but to do
2737 // something with formats.
2738 if (dformat == "xhtml")
2739 result = Flavor::Html;
2740 else if (dformat == "docbook5")
2741 result = Flavor::DocBook5;
2742 else if (dformat == "text")
2743 result = Flavor::Text;
2744 else if (dformat == "lyx")
2745 result = Flavor::LyX;
2746 else if (dformat == "pdflatex")
2747 result = Flavor::PdfLaTeX;
2748 else if (dformat == "xetex")
2749 result = Flavor::XeTeX;
2750 else if (dformat == "luatex")
2751 result = Flavor::LuaTeX;
2752 else if (dformat == "dviluatex")
2753 result = Flavor::DviLuaTeX;
2755 // Try to determine flavor of default output format
2756 vector<string> backs = backends();
2757 if (find(backs.begin(), backs.end(), dformat) == backs.end()) {
2758 // Get shortest path to format
2759 Graph::EdgePath path;
2760 for (auto const & bvar : backs) {
2761 Graph::EdgePath p = theConverters().getPath(bvar, dformat);
2762 if (!p.empty() && (path.empty() || p.size() < path.size())) {
2767 result = theConverters().getFlavor(path);
2770 // cache this flavor
2771 default_flavors_[dformat] = result;
2776 string BufferParams::getDefaultOutputFormat() const
2778 if (!default_output_format.empty()
2779 && default_output_format != "default")
2780 return default_output_format;
2781 if (encoding().package() == Encoding::japanese)
2782 return lyxrc.default_platex_view_format;
2784 return lyxrc.default_otf_view_format;
2785 return lyxrc.default_view_format;
2788 Font const BufferParams::getFont() const
2790 FontInfo f = documentClass().defaultfont();
2791 if (fonts_default_family == "rmdefault")
2792 f.setFamily(ROMAN_FAMILY);
2793 else if (fonts_default_family == "sfdefault")
2794 f.setFamily(SANS_FAMILY);
2795 else if (fonts_default_family == "ttdefault")
2796 f.setFamily(TYPEWRITER_FAMILY);
2797 return Font(f, language);
2801 QuoteStyle BufferParams::getQuoteStyle(string const & qs) const
2803 return quotesstyletranslator().find(qs);
2807 bool BufferParams::isLatex() const
2809 return documentClass().outputType() == LATEX;
2813 bool BufferParams::isLiterate() const
2815 return documentClass().outputType() == LITERATE;
2819 void BufferParams::readPreamble(Lexer & lex)
2821 if (lex.getString() != "\\begin_preamble")
2822 lyxerr << "Error (BufferParams::readPreamble):"
2823 "consistency check failed." << endl;
2825 preamble = lex.getLongString(from_ascii("\\end_preamble"));
2829 void BufferParams::readLocalLayout(Lexer & lex, bool forced)
2831 string const expected = forced ? "\\begin_forced_local_layout" :
2832 "\\begin_local_layout";
2833 if (lex.getString() != expected)
2834 lyxerr << "Error (BufferParams::readLocalLayout):"
2835 "consistency check failed." << endl;
2838 forced_local_layout_ =
2839 lex.getLongString(from_ascii("\\end_forced_local_layout"));
2841 local_layout_ = lex.getLongString(from_ascii("\\end_local_layout"));
2845 bool BufferParams::setLanguage(string const & lang)
2847 Language const *new_language = languages.getLanguage(lang);
2848 if (!new_language) {
2849 // Language lang was not found
2852 language = new_language;
2857 void BufferParams::readLanguage(Lexer & lex)
2859 if (!lex.next()) return;
2861 string const tmptok = lex.getString();
2863 // check if tmptok is part of tex_babel in tex-defs.h
2864 if (!setLanguage(tmptok)) {
2865 // Language tmptok was not found
2866 language = default_language;
2867 lyxerr << "Warning: Setting language `"
2868 << tmptok << "' to `" << language->lang()
2874 void BufferParams::readGraphicsDriver(Lexer & lex)
2879 string const tmptok = lex.getString();
2880 // check if tmptok is part of tex_graphics in tex_defs.h
2883 string const test = tex_graphics[n++];
2885 if (test == tmptok) {
2886 graphics_driver = tmptok;
2891 "Warning: graphics driver `$$Token' not recognized!\n"
2892 " Setting graphics driver to `default'.\n");
2893 graphics_driver = "default";
2900 void BufferParams::readBullets(Lexer & lex)
2905 int const index = lex.getInteger();
2907 int temp_int = lex.getInteger();
2908 user_defined_bullet(index).setFont(temp_int);
2909 temp_bullet(index).setFont(temp_int);
2911 user_defined_bullet(index).setCharacter(temp_int);
2912 temp_bullet(index).setCharacter(temp_int);
2914 user_defined_bullet(index).setSize(temp_int);
2915 temp_bullet(index).setSize(temp_int);
2919 void BufferParams::readBulletsLaTeX(Lexer & lex)
2921 // The bullet class should be able to read this.
2924 int const index = lex.getInteger();
2926 docstring const temp_str = lex.getDocString();
2928 user_defined_bullet(index).setText(temp_str);
2929 temp_bullet(index).setText(temp_str);
2933 void BufferParams::readModules(Lexer & lex)
2935 if (!lex.eatLine()) {
2936 lyxerr << "Error (BufferParams::readModules):"
2937 "Unexpected end of input." << endl;
2941 string mod = lex.getString();
2942 if (mod == "\\end_modules")
2944 addLayoutModule(mod);
2950 void BufferParams::readRemovedModules(Lexer & lex)
2952 if (!lex.eatLine()) {
2953 lyxerr << "Error (BufferParams::readRemovedModules):"
2954 "Unexpected end of input." << endl;
2958 string mod = lex.getString();
2959 if (mod == "\\end_removed_modules")
2961 removed_modules_.push_back(mod);
2964 // now we want to remove any removed modules that were previously
2965 // added. normally, that will be because default modules were added in
2966 // setBaseClass(), which gets called when \textclass is read at the
2967 // start of the read.
2968 for (auto const & rm : removed_modules_) {
2969 LayoutModuleList::iterator const mit = layout_modules_.begin();
2970 LayoutModuleList::iterator const men = layout_modules_.end();
2971 LayoutModuleList::iterator found = find(mit, men, rm);
2974 layout_modules_.erase(found);
2979 void BufferParams::readIncludeonly(Lexer & lex)
2981 if (!lex.eatLine()) {
2982 lyxerr << "Error (BufferParams::readIncludeonly):"
2983 "Unexpected end of input." << endl;
2987 string child = lex.getString();
2988 if (child == "\\end_includeonly")
2990 included_children_.push_back(child);
2996 string BufferParams::paperSizeName(PapersizePurpose purpose, string const & psize) const
2998 PAPER_SIZE ppsize = psize.empty() ? papersize : papersizetranslator().find(psize);
3001 if (documentClass().pagesize() == "default")
3002 // could be anything, so don't guess
3004 return paperSizeName(purpose, documentClass().pagesize());
3005 case PAPER_CUSTOM: {
3006 if (purpose == XDVI && !paperwidth.empty() &&
3007 !paperheight.empty()) {
3008 // heightxwidth<unit>
3009 string first = paperwidth;
3010 string second = paperheight;
3011 if (orientation == ORIENTATION_LANDSCAPE)
3014 return first.erase(first.length() - 2)
3020 // dvips and dvipdfm do not know this
3021 if (purpose == DVIPS || purpose == DVIPDFM)
3025 if (purpose == DVIPS || purpose == DVIPDFM)
3029 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 if (purpose == DVIPS || purpose == DVIPDFM)
3059 // dvipdfm does not know this
3060 if (purpose == DVIPDFM)
3064 if (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)
3124 if (purpose == DVIPS || purpose == DVIPDFM)
3127 case PAPER_USEXECUTIVE:
3128 // dvipdfm does not know this
3129 if (purpose == DVIPDFM)
3134 case PAPER_USLETTER:
3136 if (purpose == XDVI)
3143 string const BufferParams::dvips_options() const
3147 // If the class loads the geometry package, we do not know which
3148 // paper size is used, since we do not set it (bug 7013).
3149 // Therefore we must not specify any argument here.
3150 // dvips gets the correct paper size via DVI specials in this case
3151 // (if the class uses the geometry package correctly).
3152 if (documentClass().provides("geometry"))
3156 && papersize == PAPER_CUSTOM
3157 && !lyxrc.print_paper_dimension_flag.empty()
3158 && !paperwidth.empty()
3159 && !paperheight.empty()) {
3160 // using a custom papersize
3161 result = lyxrc.print_paper_dimension_flag;
3162 result += ' ' + paperwidth;
3163 result += ',' + paperheight;
3165 string const paper_option = paperSizeName(DVIPS);
3166 if (!paper_option.empty() && (paper_option != "letter" ||
3167 orientation != ORIENTATION_LANDSCAPE)) {
3168 // dvips won't accept -t letter -t landscape.
3169 // In all other cases, include the paper size
3171 result = lyxrc.print_paper_flag;
3172 result += ' ' + paper_option;
3175 if (orientation == ORIENTATION_LANDSCAPE &&
3176 papersize != PAPER_CUSTOM)
3177 result += ' ' + lyxrc.print_landscape_flag;
3182 string const BufferParams::main_font_encoding() const
3184 if (font_encodings().empty()) {
3185 if (ascii_lowercase(language->fontenc(*this)) == "none")
3189 return font_encodings().back();
3193 vector<string> const BufferParams::font_encodings() const
3195 string doc_fontenc = (fontenc == "auto") ? string() : fontenc;
3197 vector<string> fontencs;
3199 // "default" means "no explicit font encoding"
3200 if (doc_fontenc != "default") {
3201 if (!doc_fontenc.empty())
3202 // If we have a custom setting, we use only that!
3203 return getVectorFromString(doc_fontenc);
3204 if (!language->fontenc(*this).empty()
3205 && ascii_lowercase(language->fontenc(*this)) != "none") {
3206 vector<string> fencs = getVectorFromString(language->fontenc(*this));
3207 for (auto & fe : fencs) {
3208 if (find(fontencs.begin(), fontencs.end(), fe) == fontencs.end())
3209 fontencs.push_back(fe);
3218 string BufferParams::babelCall(string const & lang_opts, bool const langoptions) const
3220 // suppress the babel call if there is no BabelName defined
3221 // for the document language in the lib/languages file and if no
3222 // other languages are used (lang_opts is then empty)
3223 if (lang_opts.empty())
3225 // The prefs may require the languages to
3226 // be submitted to babel itself (not the class).
3228 return "\\usepackage[" + lang_opts + "]{babel}";
3229 return "\\usepackage{babel}";
3233 docstring BufferParams::getGraphicsDriver(string const & package) const
3237 if (package == "geometry") {
3238 if (graphics_driver == "dvips"
3239 || graphics_driver == "dvipdfm"
3240 || graphics_driver == "pdftex"
3241 || graphics_driver == "vtex")
3242 result = from_ascii(graphics_driver);
3243 else if (graphics_driver == "dvipdfmx")
3244 result = from_ascii("dvipdfm");
3251 void BufferParams::writeEncodingPreamble(otexstream & os,
3252 LaTeXFeatures & features) const
3254 // With no-TeX fonts we use utf8-plain without encoding package.
3258 if (inputenc == "auto-legacy") {
3259 string const doc_encoding =
3260 language->encoding()->latexName();
3261 Encoding::Package const package =
3262 language->encoding()->package();
3264 // Create list of inputenc options:
3265 set<string> encoding_set;
3266 // luainputenc fails with more than one encoding
3267 if (features.runparams().flavor != Flavor::LuaTeX
3268 && features.runparams().flavor != Flavor::DviLuaTeX)
3269 // list all input encodings used in the document
3270 encoding_set = features.getEncodingSet(doc_encoding);
3272 // The "japanese" babel-language requires the pLaTeX engine
3273 // which conflicts with "inputenc".
3274 // See http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129680.html
3275 if ((!encoding_set.empty() || package == Encoding::inputenc)
3276 && !features.isRequired("japanese")
3277 && !features.isProvided("inputenc")) {
3278 os << "\\usepackage[";
3279 set<string>::const_iterator it = encoding_set.begin();
3280 set<string>::const_iterator const end = encoding_set.end();
3282 os << from_ascii(*it);
3285 for (; it != end; ++it)
3286 os << ',' << from_ascii(*it);
3287 if (package == Encoding::inputenc) {
3288 if (!encoding_set.empty())
3290 os << from_ascii(doc_encoding);
3292 if (features.runparams().flavor == Flavor::LuaTeX
3293 || features.runparams().flavor == Flavor::DviLuaTeX)
3294 os << "]{luainputenc}\n";
3296 os << "]{inputenc}\n";
3298 } else if (inputenc != "auto-legacy-plain") {
3299 switch (encoding().package()) {
3300 case Encoding::none:
3302 case Encoding::japanese:
3303 if (encoding().iconvName() != "UTF-8"
3304 && !features.runparams().isFullUnicode())
3305 // don't default to [utf8]{inputenc} with TeXLive >= 18
3306 os << "\\ifdefined\\UseRawInputEncoding\n"
3307 << " \\UseRawInputEncoding\\fi\n";
3309 case Encoding::inputenc:
3310 // do not load inputenc if japanese is used
3311 // or if the class provides inputenc
3312 if (features.isRequired("japanese")
3313 || features.isProvided("inputenc"))
3315 os << "\\usepackage[" << from_ascii(encoding().latexName());
3316 if (features.runparams().flavor == Flavor::LuaTeX
3317 || features.runparams().flavor == Flavor::DviLuaTeX)
3318 os << "]{luainputenc}\n";
3320 os << "]{inputenc}\n";
3324 if (inputenc == "auto-legacy-plain" || features.isRequired("japanese")) {
3325 // don't default to [utf8]{inputenc} with TeXLive >= 18
3326 os << "\\ifdefined\\UseRawInputEncoding\n";
3327 os << " \\UseRawInputEncoding\\fi\n";
3332 string const BufferParams::parseFontName(string const & name) const
3334 string mangled = name;
3335 size_t const idx = mangled.find('[');
3336 if (idx == string::npos || idx == 0)
3339 return mangled.substr(0, idx - 1);
3343 string const BufferParams::loadFonts(LaTeXFeatures & features) const
3345 if (fontsRoman() == "default" && fontsSans() == "default"
3346 && fontsTypewriter() == "default"
3347 && (fontsMath() == "default" || fontsMath() == "auto"))
3353 /* Fontspec (XeTeX, LuaTeX): we provide GUI support for oldstyle
3354 * numbers (Numbers=OldStyle) and sf/tt scaling. The Ligatures=TeX/
3355 * Mapping=tex-text option assures TeX ligatures (such as "--")
3356 * are resolved. Note that tt does not use these ligatures.
3358 * -- add more GUI options?
3359 * -- add more fonts (fonts for other scripts)
3360 * -- if there's a way to find out if a font really supports
3361 * OldStyle, enable/disable the widget accordingly.
3363 if (useNonTeXFonts && features.isAvailable("fontspec")) {
3364 // "Mapping=tex-text" and "Ligatures=TeX" are equivalent.
3365 // However, until v.2 (2010/07/11) fontspec only knew
3366 // Mapping=tex-text (for XeTeX only); then "Ligatures=TeX"
3367 // was introduced for both XeTeX and LuaTeX (LuaTeX
3368 // didn't understand "Mapping=tex-text", while XeTeX
3369 // understood both. With most recent versions, both
3370 // variants are understood by both engines. However,
3371 // we want to provide support for at least TeXLive 2009
3372 // (for XeTeX; LuaTeX is only supported as of v.2)
3373 // As of 2017/11/03, Babel has its own higher-level
3374 // interface on top of fontspec that is to be used.
3375 bool const babelfonts = features.useBabel()
3376 && features.isAvailable("babel-2017/11/03");
3377 string const texmapping =
3378 (features.runparams().flavor == Flavor::XeTeX) ?
3379 "Mapping=tex-text" : "Ligatures=TeX";
3380 if (fontsRoman() != "default") {
3382 os << "\\babelfont{rm}[";
3384 os << "\\setmainfont[";
3385 if (!font_roman_opts.empty())
3386 os << font_roman_opts << ',';
3388 if (fonts_roman_osf)
3389 os << ",Numbers=OldStyle";
3390 os << "]{" << parseFontName(fontsRoman()) << "}\n";
3392 if (fontsSans() != "default") {
3393 string const sans = parseFontName(fontsSans());
3394 if (fontsSansScale() != 100) {
3396 os << "\\babelfont{sf}";
3398 os << "\\setsansfont";
3400 << float(fontsSansScale()) / 100 << ',';
3402 os << "Numbers=OldStyle,";
3403 if (!font_sans_opts.empty())
3404 os << font_sans_opts << ',';
3405 os << texmapping << "]{"
3409 os << "\\babelfont{sf}[";
3411 os << "\\setsansfont[";
3413 os << "Numbers=OldStyle,";
3414 if (!font_sans_opts.empty())
3415 os << font_sans_opts << ',';
3416 os << texmapping << "]{"
3420 if (fontsTypewriter() != "default") {
3421 string const mono = parseFontName(fontsTypewriter());
3422 if (fontsTypewriterScale() != 100) {
3424 os << "\\babelfont{tt}";
3426 os << "\\setmonofont";
3428 << float(fontsTypewriterScale()) / 100;
3429 if (fonts_typewriter_osf)
3430 os << ",Numbers=OldStyle";
3431 if (!font_typewriter_opts.empty())
3432 os << ',' << font_typewriter_opts;
3437 os << "\\babelfont{tt}";
3439 os << "\\setmonofont";
3440 if (!font_typewriter_opts.empty() || fonts_typewriter_osf) {
3442 if (fonts_typewriter_osf)
3443 os << "Numbers=OldStyle";
3444 if (!font_typewriter_opts.empty()) {
3445 if (fonts_typewriter_osf)
3447 os << font_typewriter_opts;
3451 os << '{' << mono << "}\n";
3458 bool const ot1 = (main_font_encoding() == "default" || main_font_encoding() == "OT1");
3459 bool const dryrun = features.runparams().dryrun;
3460 bool const complete = (fontsSans() == "default" && fontsTypewriter() == "default");
3461 bool const nomath = (fontsMath() != "auto");
3464 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsRoman())).getLaTeXCode(
3465 dryrun, ot1, complete, fonts_expert_sc, fonts_roman_osf,
3466 nomath, font_roman_opts);
3469 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsSans())).getLaTeXCode(
3470 dryrun, ot1, complete, fonts_expert_sc, fonts_sans_osf,
3471 nomath, font_sans_opts, fontsSansScale());
3473 // MONOSPACED/TYPEWRITER
3474 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsTypewriter())).getLaTeXCode(
3475 dryrun, ot1, complete, fonts_expert_sc, fonts_typewriter_osf,
3476 nomath, font_typewriter_opts, fontsTypewriterScale());
3479 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsMath())).getLaTeXCode(
3480 dryrun, ot1, complete, fonts_expert_sc, fonts_roman_osf,
3487 Encoding const & BufferParams::encoding() const
3489 // Main encoding for LaTeX output.
3491 return *(encodings.fromLyXName("utf8-plain"));
3492 if (inputenc == "auto-legacy" || inputenc == "auto-legacy-plain")
3493 return *language->encoding();
3494 if (inputenc == "utf8" && language->lang() == "japanese")
3495 return *(encodings.fromLyXName("utf8-platex"));
3496 Encoding const * const enc = encodings.fromLyXName(inputenc);
3499 LYXERR0("Unknown inputenc value `" << inputenc
3500 << "'. Using `auto' instead.");
3501 return *language->encoding();
3505 string const & BufferParams::defaultBiblioStyle() const
3507 if (!biblio_style.empty())
3508 return biblio_style;
3510 map<string, string> const & bs = documentClass().defaultBiblioStyle();
3511 auto cit = bs.find(theCiteEnginesList.getTypeAsString(citeEngineType()));
3512 if (cit != bs.end())
3515 return empty_string();
3519 bool BufferParams::fullAuthorList() const
3521 return documentClass().fullAuthorList();
3525 string BufferParams::getCiteAlias(string const & s) const
3527 vector<string> commands =
3528 documentClass().citeCommands(citeEngineType());
3529 // If it is a real command, don't treat it as an alias
3530 if (find(commands.begin(), commands.end(), s) != commands.end())
3532 map<string,string> aliases = documentClass().citeCommandAliases();
3533 if (aliases.find(s) != aliases.end())
3539 vector<string> BufferParams::citeCommands() const
3541 static CitationStyle const default_style;
3542 vector<string> commands =
3543 documentClass().citeCommands(citeEngineType());
3544 if (commands.empty())
3545 commands.push_back(default_style.name);
3550 vector<CitationStyle> BufferParams::citeStyles() const
3552 static CitationStyle const default_style;
3553 vector<CitationStyle> styles =
3554 documentClass().citeStyles(citeEngineType());
3556 styles.push_back(default_style);
3561 string const BufferParams::bibtexCommand() const
3563 // Return document-specific setting if available
3564 if (bibtex_command != "default")
3565 return bibtex_command;
3567 // If we have "default" in document settings, consult the prefs
3568 // 1. Japanese (uses a specific processor)
3569 if (encoding().package() == Encoding::japanese) {
3570 if (lyxrc.jbibtex_command != "automatic")
3571 // Return the specified program, if "automatic" is not set
3572 return lyxrc.jbibtex_command;
3573 else if (!useBiblatex()) {
3574 // With classic BibTeX, return pbibtex, jbibtex, bibtex
3575 if (lyxrc.jbibtex_alternatives.find("pbibtex") != lyxrc.jbibtex_alternatives.end())
3577 if (lyxrc.jbibtex_alternatives.find("jbibtex") != lyxrc.jbibtex_alternatives.end())
3582 // 2. All other languages
3583 else if (lyxrc.bibtex_command != "automatic")
3584 // Return the specified program, if "automatic" is not set
3585 return lyxrc.bibtex_command;
3587 // 3. Automatic: find the most suitable for the current cite framework
3588 if (useBiblatex()) {
3589 // For Biblatex, we prefer biber (also for Japanese)
3590 // and fall back to bibtex8 and, as last resort, bibtex
3591 if (lyxrc.bibtex_alternatives.find("biber") != lyxrc.bibtex_alternatives.end())
3593 else if (lyxrc.bibtex_alternatives.find("bibtex8") != lyxrc.bibtex_alternatives.end())
3600 bool BufferParams::useBiblatex() const
3602 return theCiteEnginesList[citeEngine()]->getCiteFramework() == "biblatex";
3606 void BufferParams::invalidateConverterCache() const
3608 pimpl_->isExportCacheValid = false;
3609 pimpl_->isViewCacheValid = false;
3613 // We shouldn't need to reset the params here, since anything
3614 // we need will be recopied.
3615 void BufferParams::copyForAdvFR(const BufferParams & bp)
3617 string const & lang = bp.language->lang();
3619 layout_modules_ = bp.layout_modules_;
3620 string const & doc_class = bp.documentClass().name();
3621 setBaseClass(doc_class);
3625 void BufferParams::setBibFileEncoding(string const & file, string const & enc)
3627 bib_encodings[file] = enc;
3631 string const BufferParams::bibFileEncoding(string const & file) const
3633 if (bib_encodings.find(file) == bib_encodings.end())
3635 return bib_encodings.find(file)->second;