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 isnotefontcolor = false;
465 notefontcolor = lyx::rgbFromHexName("#cccccc");
466 boxbgcolor = lyx::rgbFromHexName("#ff0000");
467 compressed = lyxrc.save_compressed;
468 for (int iter = 0; iter < 4; ++iter) {
469 user_defined_bullet(iter) = ITEMIZE_DEFAULTS[iter];
470 temp_bullet(iter) = ITEMIZE_DEFAULTS[iter];
473 indiceslist().addDefault(B_("Index"));
474 html_be_strict = false;
475 html_math_output = MathML;
476 html_math_img_scale = 1.0;
477 html_css_as_file = false;
478 docbook_table_output = HTMLTable;
479 display_pixel_ratio = 1.0;
481 shell_escape = false;
487 // map current author
488 author_map_[pimpl_->authorlist.get(0).bufferId()] = 0;
492 docstring BufferParams::B_(string const & l10n) const
494 LASSERT(language, return from_utf8(l10n));
495 return getMessages(language->code()).get(l10n);
499 BufferParams::Package BufferParams::use_package(std::string const & p) const
501 PackageMap::const_iterator it = use_packages.find(p);
502 if (it == use_packages.end())
508 void BufferParams::use_package(std::string const & p, BufferParams::Package u)
514 map<string, string> const & BufferParams::auto_packages()
516 static map<string, string> packages;
517 if (packages.empty()) {
518 // We could have a race condition here that two threads
519 // discover an empty map at the same time and want to fill
520 // it, but that is no problem, since the same contents is
521 // filled in twice then. Having the locker inside the
522 // packages.empty() condition has the advantage that we
523 // don't need the mutex overhead for simple reading.
525 Mutex::Locker locker(&mutex);
526 // adding a package here implies a file format change!
527 packages["amsmath"] =
528 N_("The LaTeX package amsmath is only used if AMS formula types or symbols from the AMS math toolbars are inserted into formulas");
529 packages["amssymb"] =
530 N_("The LaTeX package amssymb is only used if symbols from the AMS math toolbars are inserted into formulas");
532 N_("The LaTeX package cancel is only used if \\cancel commands are used in formulas");
534 N_("The LaTeX package esint is only used if special integral symbols are inserted into formulas");
535 packages["mathdots"] =
536 N_("The LaTeX package mathdots is only used if the command \\iddots is inserted into formulas");
537 packages["mathtools"] =
538 N_("The LaTeX package mathtools is only used if some mathematical relations are inserted into formulas");
540 N_("The LaTeX package mhchem is only used if either the command \\ce or \\cf is inserted into formulas");
541 packages["stackrel"] =
542 N_("The LaTeX package stackrel is only used if the command \\stackrel with subscript is inserted into formulas");
543 packages["stmaryrd"] =
544 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");
545 packages["undertilde"] =
546 N_("The LaTeX package undertilde is only used if you use the math frame decoration 'utilde'");
552 bool BufferParams::useBibtopic() const
556 return (use_bibtopic || (!multibib.empty() && multibib != "child"));
560 AuthorList & BufferParams::authors()
562 return pimpl_->authorlist;
566 AuthorList const & BufferParams::authors() const
568 return pimpl_->authorlist;
572 void BufferParams::addAuthor(Author const & a)
574 author_map_[a.bufferId()] = pimpl_->authorlist.record(a);
578 BranchList & BufferParams::branchlist()
580 return pimpl_->branchlist;
584 BranchList const & BufferParams::branchlist() const
586 return pimpl_->branchlist;
590 IndicesList & BufferParams::indiceslist()
592 return pimpl_->indiceslist;
596 IndicesList const & BufferParams::indiceslist() const
598 return pimpl_->indiceslist;
602 Bullet & BufferParams::temp_bullet(lyx::size_type const index)
604 LASSERT(index < 4, return pimpl_->temp_bullets[0]);
605 return pimpl_->temp_bullets[index];
609 Bullet const & BufferParams::temp_bullet(lyx::size_type const index) const
611 LASSERT(index < 4, return pimpl_->temp_bullets[0]);
612 return pimpl_->temp_bullets[index];
616 Bullet & BufferParams::user_defined_bullet(lyx::size_type const index)
618 LASSERT(index < 4, return pimpl_->temp_bullets[0]);
619 return pimpl_->user_defined_bullets[index];
623 Bullet const & BufferParams::user_defined_bullet(lyx::size_type const index) const
625 LASSERT(index < 4, return pimpl_->temp_bullets[0]);
626 return pimpl_->user_defined_bullets[index];
630 Spacing & BufferParams::spacing()
632 return pimpl_->spacing;
636 Spacing const & BufferParams::spacing() const
638 return pimpl_->spacing;
642 PDFOptions & BufferParams::pdfoptions()
644 return pimpl_->pdfoptions;
648 PDFOptions const & BufferParams::pdfoptions() const
650 return pimpl_->pdfoptions;
654 Length const & BufferParams::getMathIndent() const
656 return pimpl_->mathindent;
660 void BufferParams::setMathIndent(Length const & indent)
662 pimpl_->mathindent = indent;
666 Length const & BufferParams::getParIndent() const
668 return pimpl_->parindent;
672 void BufferParams::setParIndent(Length const & indent)
674 pimpl_->parindent = indent;
678 VSpace const & BufferParams::getDefSkip() const
680 return pimpl_->defskip;
684 void BufferParams::setDefSkip(VSpace const & vs)
686 // DEFSKIP will cause an infinite loop
687 LASSERT(vs.kind() != VSpace::DEFSKIP, return);
688 pimpl_->defskip = vs;
692 BufferParams::MathNumber BufferParams::getMathNumber() const
694 if (math_numbering_side != DEFAULT)
695 return math_numbering_side;
696 // FIXME: do not hardcode language here
697 else if (language->lang() == "arabic_arabi"
698 || documentClass().provides("leqno"))
705 string BufferParams::readToken(Lexer & lex, string const & token,
706 FileName const & filepath)
710 if (token == "\\textclass") {
712 string const classname = lex.getString();
713 // if there exists a local layout file, ignore the system one
714 // NOTE: in this case, the textclass (.cls file) is assumed to
717 LayoutFileList & bcl = LayoutFileList::get();
718 if (!filepath.empty()) {
719 // If classname is an absolute path, the document is
720 // using a local layout file which could not be accessed
721 // by a relative path. In this case the path is correct
722 // even if the document was moved to a different
723 // location. However, we will have a problem if the
724 // document was generated on a different platform.
725 bool isabsolute = FileName::isAbsolute(classname);
726 string const classpath = onlyPath(classname);
727 string const path = isabsolute ? classpath
728 : FileName(addPath(filepath.absFileName(),
729 classpath)).realPath();
730 string const oldpath = isabsolute ? string()
731 : FileName(addPath(origin, classpath)).realPath();
732 tcp = bcl.addLocalLayout(onlyFileName(classname), path, oldpath);
734 // that returns non-empty if a "local" layout file is found.
736 result = to_utf8(makeRelPath(from_utf8(onlyPath(tcp)),
737 from_utf8(filepath.absFileName())));
740 setBaseClass(onlyFileName(tcp));
742 setBaseClass(onlyFileName(classname));
743 // We assume that a tex class exists for local or unknown
744 // layouts so this warning, will only be given for system layouts.
745 if (!baseClass()->isTeXClassAvailable()) {
746 docstring const desc =
747 translateIfPossible(from_utf8(baseClass()->description()));
748 docstring const prereqs =
749 from_utf8(baseClass()->prerequisites());
750 docstring const msg =
751 bformat(_("The selected document class\n"
753 "requires external files that are not available.\n"
754 "The document class can still be used, but the\n"
755 "document cannot be compiled until the following\n"
756 "prerequisites are installed:\n"
758 "See section 3.1.2.2 (Class Availability) of the\n"
759 "User's Guide for more information."), desc, prereqs);
760 frontend::Alert::warning(_("Document class not available"),
763 } else if (token == "\\save_transient_properties") {
764 lex >> save_transient_properties;
765 } else if (token == "\\origin") {
767 origin = lex.getString();
768 string const sysdirprefix = "/systemlyxdir/";
769 if (prefixIs(origin, sysdirprefix)) {
771 if (inSystemDir(filepath, docsys))
772 origin.replace(0, sysdirprefix.length() - 1, docsys);
774 origin.replace(0, sysdirprefix.length() - 1,
775 package().system_support().absFileName());
777 } else if (token == "\\begin_preamble") {
779 } else if (token == "\\begin_local_layout") {
780 readLocalLayout(lex, false);
781 } else if (token == "\\begin_forced_local_layout") {
782 readLocalLayout(lex, true);
783 } else if (token == "\\begin_modules") {
785 } else if (token == "\\begin_removed_modules") {
786 readRemovedModules(lex);
787 } else if (token == "\\begin_includeonly") {
788 readIncludeonly(lex);
789 } else if (token == "\\maintain_unincluded_children") {
793 maintain_unincluded_children = CM_None;
794 else if (tmp == "mostly")
795 maintain_unincluded_children = CM_Mostly;
796 else if (tmp == "strict")
797 maintain_unincluded_children = CM_Strict;
798 } else if (token == "\\options") {
800 options = lex.getString();
801 } else if (token == "\\use_default_options") {
802 lex >> use_default_options;
803 } else if (token == "\\master") {
805 master = lex.getString();
806 if (!filepath.empty() && FileName::isAbsolute(origin)) {
807 bool const isabs = FileName::isAbsolute(master);
808 FileName const abspath(isabs ? master : origin + master);
809 bool const moved = filepath != FileName(origin);
810 if (moved && abspath.exists()) {
811 docstring const path = isabs
813 : from_utf8(abspath.realPath());
814 docstring const refpath =
815 from_utf8(filepath.absFileName());
816 master = to_utf8(makeRelPath(path, refpath));
819 } else if (token == "\\suppress_date") {
820 lex >> suppress_date;
821 } else if (token == "\\justification") {
822 lex >> justification;
823 } else if (token == "\\language") {
825 } else if (token == "\\language_package") {
827 lang_package = lex.getString();
828 } else if (token == "\\inputencoding") {
830 } else if (token == "\\graphics") {
831 readGraphicsDriver(lex);
832 } else if (token == "\\default_output_format") {
833 lex >> default_output_format;
834 } else if (token == "\\bibtex_command") {
836 bibtex_command = lex.getString();
837 } else if (token == "\\index_command") {
839 index_command = lex.getString();
840 } else if (token == "\\fontencoding") {
842 fontenc = lex.getString();
843 } else if (token == "\\font_roman") {
844 lex >> fonts_roman[0];
845 lex >> fonts_roman[1];
846 } else if (token == "\\font_sans") {
847 lex >> fonts_sans[0];
848 lex >> fonts_sans[1];
849 } else if (token == "\\font_typewriter") {
850 lex >> fonts_typewriter[0];
851 lex >> fonts_typewriter[1];
852 } else if (token == "\\font_math") {
853 lex >> fonts_math[0];
854 lex >> fonts_math[1];
855 } else if (token == "\\font_default_family") {
856 lex >> fonts_default_family;
857 } else if (token == "\\use_non_tex_fonts") {
858 lex >> useNonTeXFonts;
859 } else if (token == "\\font_sc") {
860 lex >> fonts_expert_sc;
861 } else if (token == "\\font_roman_osf") {
862 lex >> fonts_roman_osf;
863 } else if (token == "\\font_sans_osf") {
864 lex >> fonts_sans_osf;
865 } else if (token == "\\font_typewriter_osf") {
866 lex >> fonts_typewriter_osf;
867 } else if (token == "\\font_roman_opts") {
868 lex >> font_roman_opts;
869 } else if (token == "\\font_sf_scale") {
870 lex >> fonts_sans_scale[0];
871 lex >> fonts_sans_scale[1];
872 } else if (token == "\\font_sans_opts") {
873 lex >> font_sans_opts;
874 } else if (token == "\\font_tt_scale") {
875 lex >> fonts_typewriter_scale[0];
876 lex >> fonts_typewriter_scale[1];
877 } else if (token == "\\font_typewriter_opts") {
878 lex >> font_typewriter_opts;
879 } else if (token == "\\font_cjk") {
881 } else if (token == "\\use_microtype") {
882 lex >> use_microtype;
883 } else if (token == "\\use_dash_ligatures") {
884 lex >> use_dash_ligatures;
885 } else if (token == "\\paragraph_separation") {
888 paragraph_separation = parseptranslator().find(parsep);
889 } else if (token == "\\paragraph_indentation") {
891 string parindent = lex.getString();
892 if (parindent == "default")
893 pimpl_->parindent = Length();
895 pimpl_->parindent = Length(parindent);
896 } else if (token == "\\defskip") {
898 string const defskip = lex.getString();
899 pimpl_->defskip = VSpace(defskip);
900 if (pimpl_->defskip.kind() == VSpace::DEFSKIP)
902 pimpl_->defskip = VSpace(VSpace::MEDSKIP);
903 } else if (token == "\\is_math_indent") {
904 lex >> is_math_indent;
905 } else if (token == "\\math_indentation") {
907 string mathindent = lex.getString();
908 if (mathindent == "default")
909 pimpl_->mathindent = Length();
911 pimpl_->mathindent = Length(mathindent);
912 } else if (token == "\\math_numbering_side") {
916 math_numbering_side = LEFT;
917 else if (tmp == "right")
918 math_numbering_side = RIGHT;
920 math_numbering_side = DEFAULT;
921 } else if (token == "\\quotes_style") {
924 quotes_style = quotesstyletranslator().find(qstyle);
925 } else if (token == "\\dynamic_quotes") {
926 lex >> dynamic_quotes;
927 } else if (token == "\\papersize") {
930 papersize = papersizetranslator().find(ppsize);
931 } else if (token == "\\use_geometry") {
933 } else if (token == "\\use_package") {
938 use_package(package, packagetranslator().find(use));
939 } else if (token == "\\cite_engine") {
941 cite_engine_ = lex.getString();
942 } else if (token == "\\cite_engine_type") {
945 cite_engine_type_ = theCiteEnginesList.getType(engine_type);
946 } else if (token == "\\biblio_style") {
948 biblio_style = lex.getString();
949 } else if (token == "\\biblio_options") {
951 biblio_opts = trim(lex.getString());
952 } else if (token == "\\biblatex_bibstyle") {
954 biblatex_bibstyle = trim(lex.getString());
955 } else if (token == "\\biblatex_citestyle") {
957 biblatex_citestyle = trim(lex.getString());
958 } else if (token == "\\use_bibtopic") {
960 } else if (token == "\\multibib") {
962 } else if (token == "\\use_indices") {
964 } else if (token == "\\tracking_changes") {
965 lex >> track_changes;
966 } else if (token == "\\output_changes") {
967 lex >> output_changes;
968 } else if (token == "\\change_bars") {
970 } else if (token == "\\postpone_fragile_content") {
971 lex >> postpone_fragile_content;
972 } else if (token == "\\branch") {
974 docstring branch = lex.getDocString();
975 branchlist().add(branch);
978 string const tok = lex.getString();
979 if (tok == "\\end_branch")
981 Branch * branch_ptr = branchlist().find(branch);
982 if (tok == "\\selected") {
985 branch_ptr->setSelected(lex.getInteger());
987 if (tok == "\\filename_suffix") {
990 branch_ptr->setFileNameSuffix(lex.getInteger());
992 if (tok == "\\color") {
994 vector<string> const colors = getVectorFromString(lex.getString(), " ");
995 string const lmcolor = colors.front();
997 if (colors.size() > 1)
998 dmcolor = colors.back();
1000 branch_ptr->setColors(lmcolor, dmcolor);
1003 } else if (token == "\\index") {
1005 docstring index = lex.getDocString();
1007 indiceslist().add(index);
1010 string const tok = lex.getString();
1011 if (tok == "\\end_index")
1013 Index * index_ptr = indiceslist().find(index);
1014 if (tok == "\\shortcut") {
1016 shortcut = lex.getDocString();
1018 index_ptr->setShortcut(shortcut);
1020 if (tok == "\\color") {
1022 string color = lex.getString();
1024 index_ptr->setColor(color);
1025 // Update also the Color table:
1026 if (color == "none")
1027 color = lcolor.getX11HexName(Color_background);
1029 if (!shortcut.empty())
1030 lcolor.setColor(to_utf8(shortcut), color);
1033 } else if (token == "\\author") {
1035 istringstream ss(lex.getString());
1039 } else if (token == "\\paperorientation") {
1042 orientation = paperorientationtranslator().find(orient);
1043 } else if (token == "\\backgroundcolor") {
1045 backgroundcolor = lyx::rgbFromHexName(lex.getString());
1046 isbackgroundcolor = true;
1047 } else if (token == "\\fontcolor") {
1049 fontcolor = lyx::rgbFromHexName(lex.getString());
1051 } else if (token == "\\notefontcolor") {
1053 string color = lex.getString();
1054 notefontcolor = lyx::rgbFromHexName(color);
1055 lcolor.setColor("notefontcolor", color);
1056 lcolor.setLaTeXName("notefontcolor", "note_fontcolor");
1057 isnotefontcolor = true;
1058 } else if (token == "\\boxbgcolor") {
1060 string color = lex.getString();
1061 boxbgcolor = lyx::rgbFromHexName(color);
1062 lcolor.setColor("boxbgcolor", color);
1063 } else if (token == "\\paperwidth") {
1065 } else if (token == "\\paperheight") {
1067 } else if (token == "\\leftmargin") {
1069 } else if (token == "\\topmargin") {
1071 } else if (token == "\\rightmargin") {
1073 } else if (token == "\\bottommargin") {
1074 lex >> bottommargin;
1075 } else if (token == "\\headheight") {
1077 } else if (token == "\\headsep") {
1079 } else if (token == "\\footskip") {
1081 } else if (token == "\\columnsep") {
1083 } else if (token == "\\paperfontsize") {
1085 } else if (token == "\\papercolumns") {
1087 } else if (token == "\\listings_params") {
1090 listings_params = InsetListingsParams(par).params();
1091 } else if (token == "\\papersides") {
1094 sides = sidestranslator().find(psides);
1095 } else if (token == "\\paperpagestyle") {
1097 } else if (token == "\\tablestyle") {
1099 } else if (token == "\\bullet") {
1101 } else if (token == "\\bulletLaTeX") {
1102 readBulletsLaTeX(lex);
1103 } else if (token == "\\secnumdepth") {
1105 } else if (token == "\\tocdepth") {
1107 } else if (token == "\\spacing") {
1111 if (nspacing == "other") {
1114 spacing().set(spacetranslator().find(nspacing), tmp_val);
1115 } else if (token == "\\float_placement") {
1116 lex >> float_placement;
1117 } else if (token == "\\float_alignment") {
1118 lex >> float_alignment;
1120 } else if (prefixIs(token, "\\pdf_") || token == "\\use_hyperref") {
1121 string toktmp = pdfoptions().readToken(lex, token);
1122 if (!toktmp.empty()) {
1123 lyxerr << "PDFOptions::readToken(): Unknown token: " <<
1127 } else if (token == "\\html_math_output") {
1130 html_math_output = static_cast<MathOutput>(temp);
1131 } else if (token == "\\html_be_strict") {
1132 lex >> html_be_strict;
1133 } else if (token == "\\html_css_as_file") {
1134 lex >> html_css_as_file;
1135 } else if (token == "\\html_math_img_scale") {
1136 lex >> html_math_img_scale;
1137 } else if (token == "\\html_latex_start") {
1139 html_latex_start = lex.getString();
1140 } else if (token == "\\html_latex_end") {
1142 html_latex_end = lex.getString();
1143 } else if (token == "\\docbook_table_output") {
1146 docbook_table_output = static_cast<TableOutput>(temp);
1147 } else if (token == "\\output_sync") {
1149 } else if (token == "\\output_sync_macro") {
1150 lex >> output_sync_macro;
1151 } else if (token == "\\use_refstyle") {
1152 lex >> use_refstyle;
1153 } else if (token == "\\use_minted") {
1155 } else if (token == "\\use_lineno") {
1157 } else if (token == "\\lineno_options") {
1159 lineno_opts = trim(lex.getString());
1161 lyxerr << "BufferParams::readToken(): Unknown token: " <<
1171 // Quote argument if it contains spaces
1172 string quoteIfNeeded(string const & str) {
1173 if (contains(str, ' '))
1174 return "\"" + str + "\"";
1180 void BufferParams::writeFile(ostream & os, Buffer const * buf) const
1182 // The top of the file is written by the buffer.
1183 // Prints out the buffer info into the .lyx file given by file
1185 os << "\\save_transient_properties "
1186 << convert<string>(save_transient_properties) << '\n';
1188 // the document directory (must end with a path separator)
1189 // realPath() is used to resolve symlinks, while addPath(..., "")
1190 // ensures a trailing path separator.
1192 string filepath = addPath(buf->fileName().onlyPath().realPath(), "");
1193 string const sysdir = inSystemDir(FileName(filepath), docsys) ? docsys
1194 : addPath(package().system_support().realPath(), "");
1195 string const relpath =
1196 to_utf8(makeRelPath(from_utf8(filepath), from_utf8(sysdir)));
1197 if (!prefixIs(relpath, "../") && !FileName::isAbsolute(relpath))
1198 filepath = addPath("/systemlyxdir", relpath);
1199 else if (!save_transient_properties || !lyxrc.save_origin)
1200 filepath = "unavailable";
1201 os << "\\origin " << quoteIfNeeded(filepath) << '\n';
1204 os << "\\textclass "
1205 << quoteIfNeeded(buf->includedFilePath(addName(buf->layoutPos(),
1206 baseClass()->name()), "layout"))
1209 // then the preamble
1210 if (!preamble.empty()) {
1211 // remove '\n' from the end of preamble
1212 docstring const tmppreamble = rtrim(preamble, "\n");
1213 os << "\\begin_preamble\n"
1214 << to_utf8(tmppreamble)
1215 << "\n\\end_preamble\n";
1219 if (!options.empty()) {
1220 os << "\\options " << options << '\n';
1223 // use the class options defined in the layout?
1224 os << "\\use_default_options "
1225 << convert<string>(use_default_options) << "\n";
1227 // the master document
1228 if (!master.empty()) {
1229 os << "\\master " << master << '\n';
1233 if (!removed_modules_.empty()) {
1234 os << "\\begin_removed_modules" << '\n';
1235 for (auto const & mod : removed_modules_)
1237 os << "\\end_removed_modules" << '\n';
1241 if (!layout_modules_.empty()) {
1242 os << "\\begin_modules" << '\n';
1243 for (auto const & mod : layout_modules_)
1245 os << "\\end_modules" << '\n';
1249 if (!included_children_.empty()) {
1250 os << "\\begin_includeonly" << '\n';
1251 for (auto const & c : included_children_)
1253 os << "\\end_includeonly" << '\n';
1256 switch (maintain_unincluded_children) {
1267 os << "\\maintain_unincluded_children " << muc << '\n';
1269 // local layout information
1270 docstring const local_layout = getLocalLayout(false);
1271 if (!local_layout.empty()) {
1272 // remove '\n' from the end
1273 docstring const tmplocal = rtrim(local_layout, "\n");
1274 os << "\\begin_local_layout\n"
1275 << to_utf8(tmplocal)
1276 << "\n\\end_local_layout\n";
1278 docstring const forced_local_layout = getLocalLayout(true);
1279 if (!forced_local_layout.empty()) {
1280 // remove '\n' from the end
1281 docstring const tmplocal = rtrim(forced_local_layout, "\n");
1282 os << "\\begin_forced_local_layout\n"
1283 << to_utf8(tmplocal)
1284 << "\n\\end_forced_local_layout\n";
1287 // then the text parameters
1288 if (language != ignore_language)
1289 os << "\\language " << language->lang() << '\n';
1290 os << "\\language_package " << lang_package
1291 << "\n\\inputencoding " << inputenc
1292 << "\n\\fontencoding " << fontenc
1293 << "\n\\font_roman \"" << fonts_roman[0]
1294 << "\" \"" << fonts_roman[1] << '"'
1295 << "\n\\font_sans \"" << fonts_sans[0]
1296 << "\" \"" << fonts_sans[1] << '"'
1297 << "\n\\font_typewriter \"" << fonts_typewriter[0]
1298 << "\" \"" << fonts_typewriter[1] << '"'
1299 << "\n\\font_math \"" << fonts_math[0]
1300 << "\" \"" << fonts_math[1] << '"'
1301 << "\n\\font_default_family " << fonts_default_family
1302 << "\n\\use_non_tex_fonts " << convert<string>(useNonTeXFonts)
1303 << "\n\\font_sc " << convert<string>(fonts_expert_sc)
1304 << "\n\\font_roman_osf " << convert<string>(fonts_roman_osf)
1305 << "\n\\font_sans_osf " << convert<string>(fonts_sans_osf)
1306 << "\n\\font_typewriter_osf " << convert<string>(fonts_typewriter_osf);
1307 if (!font_roman_opts.empty())
1308 os << "\n\\font_roman_opts \"" << font_roman_opts << "\"";
1309 os << "\n\\font_sf_scale " << fonts_sans_scale[0]
1310 << ' ' << fonts_sans_scale[1];
1311 if (!font_sans_opts.empty())
1312 os << "\n\\font_sans_opts \"" << font_sans_opts << "\"";
1313 os << "\n\\font_tt_scale " << fonts_typewriter_scale[0]
1314 << ' ' << fonts_typewriter_scale[1];
1315 if (!font_typewriter_opts.empty())
1316 os << "\n\\font_typewriter_opts \"" << font_typewriter_opts << "\"";
1318 if (!fonts_cjk.empty())
1319 os << "\\font_cjk " << fonts_cjk << '\n';
1320 os << "\\use_microtype " << convert<string>(use_microtype) << '\n';
1321 os << "\\use_dash_ligatures " << convert<string>(use_dash_ligatures) << '\n';
1322 os << "\\graphics " << graphics_driver << '\n';
1323 os << "\\default_output_format " << default_output_format << '\n';
1324 os << "\\output_sync " << output_sync << '\n';
1325 if (!output_sync_macro.empty())
1326 os << "\\output_sync_macro \"" << output_sync_macro << "\"\n";
1327 os << "\\bibtex_command " << bibtex_command << '\n';
1328 os << "\\index_command " << index_command << '\n';
1330 if (!float_placement.empty())
1331 os << "\\float_placement " << float_placement << '\n';
1332 if (!float_alignment.empty())
1333 os << "\\float_alignment " << float_alignment << '\n';
1334 os << "\\paperfontsize " << fontsize << '\n';
1336 spacing().writeFile(os);
1337 pdfoptions().writeFile(os);
1339 os << "\\papersize " << string_papersize[papersize]
1340 << "\n\\use_geometry " << convert<string>(use_geometry);
1341 map<string, string> const & packages = auto_packages();
1342 for (auto const & pack : packages)
1343 os << "\n\\use_package " << pack.first << ' '
1344 << use_package(pack.first);
1346 os << "\n\\cite_engine ";
1348 if (!cite_engine_.empty())
1353 os << "\n\\cite_engine_type " << theCiteEnginesList.getTypeAsString(cite_engine_type_);
1355 if (!biblio_style.empty())
1356 os << "\n\\biblio_style " << biblio_style;
1357 if (!biblio_opts.empty())
1358 os << "\n\\biblio_options " << biblio_opts;
1359 if (!biblatex_bibstyle.empty())
1360 os << "\n\\biblatex_bibstyle " << biblatex_bibstyle;
1361 if (!biblatex_citestyle.empty())
1362 os << "\n\\biblatex_citestyle " << biblatex_citestyle;
1363 if (!multibib.empty())
1364 os << "\n\\multibib " << multibib;
1366 os << "\n\\use_bibtopic " << convert<string>(use_bibtopic)
1367 << "\n\\use_indices " << convert<string>(use_indices)
1368 << "\n\\paperorientation " << string_orientation[orientation]
1369 << "\n\\suppress_date " << convert<string>(suppress_date)
1370 << "\n\\justification " << convert<string>(justification)
1371 << "\n\\use_refstyle " << use_refstyle
1372 << "\n\\use_minted " << use_minted
1373 << "\n\\use_lineno " << use_lineno
1376 if (!lineno_opts.empty())
1377 os << "\\lineno_options " << lineno_opts << '\n';
1379 if (isbackgroundcolor)
1380 os << "\\backgroundcolor " << lyx::X11hexname(backgroundcolor) << '\n';
1382 os << "\\fontcolor " << lyx::X11hexname(fontcolor) << '\n';
1383 if (isnotefontcolor)
1384 os << "\\notefontcolor " << lyx::X11hexname(notefontcolor) << '\n';
1385 if (boxbgcolor != lyx::rgbFromHexName("#ff0000"))
1386 os << "\\boxbgcolor " << lyx::X11hexname(boxbgcolor) << '\n';
1388 for (auto const & br : branchlist()) {
1389 os << "\\branch " << to_utf8(br.branch())
1390 << "\n\\selected " << br.isSelected()
1391 << "\n\\filename_suffix " << br.hasFileNameSuffix()
1392 << "\n\\color " << br.lightModeColor() << " " << br.darkModeColor()
1397 for (auto const & id : indiceslist()) {
1398 os << "\\index " << to_utf8(id.index())
1399 << "\n\\shortcut " << to_utf8(id.shortcut())
1400 << "\n\\color " << lyx::X11hexname(id.color())
1405 if (!paperwidth.empty())
1406 os << "\\paperwidth "
1407 << VSpace(paperwidth).asLyXCommand() << '\n';
1408 if (!paperheight.empty())
1409 os << "\\paperheight "
1410 << VSpace(paperheight).asLyXCommand() << '\n';
1411 if (!leftmargin.empty())
1412 os << "\\leftmargin "
1413 << VSpace(leftmargin).asLyXCommand() << '\n';
1414 if (!topmargin.empty())
1415 os << "\\topmargin "
1416 << VSpace(topmargin).asLyXCommand() << '\n';
1417 if (!rightmargin.empty())
1418 os << "\\rightmargin "
1419 << VSpace(rightmargin).asLyXCommand() << '\n';
1420 if (!bottommargin.empty())
1421 os << "\\bottommargin "
1422 << VSpace(bottommargin).asLyXCommand() << '\n';
1423 if (!headheight.empty())
1424 os << "\\headheight "
1425 << VSpace(headheight).asLyXCommand() << '\n';
1426 if (!headsep.empty())
1428 << VSpace(headsep).asLyXCommand() << '\n';
1429 if (!footskip.empty())
1431 << VSpace(footskip).asLyXCommand() << '\n';
1432 if (!columnsep.empty())
1433 os << "\\columnsep "
1434 << VSpace(columnsep).asLyXCommand() << '\n';
1435 os << "\\secnumdepth " << secnumdepth
1436 << "\n\\tocdepth " << tocdepth
1437 << "\n\\paragraph_separation "
1438 << string_paragraph_separation[paragraph_separation];
1439 if (!paragraph_separation)
1440 os << "\n\\paragraph_indentation "
1441 << (getParIndent().empty() ? "default" : getParIndent().asString());
1443 os << "\n\\defskip " << getDefSkip().asLyXCommand();
1444 os << "\n\\is_math_indent " << is_math_indent;
1446 os << "\n\\math_indentation "
1447 << (getMathIndent().empty() ? "default" : getMathIndent().asString());
1448 os << "\n\\math_numbering_side ";
1449 switch(math_numbering_side) {
1459 os << "\n\\quotes_style "
1460 << string_quotes_style[static_cast<int>(quotes_style)]
1461 << "\n\\dynamic_quotes " << dynamic_quotes
1462 << "\n\\papercolumns " << columns
1463 << "\n\\papersides " << sides
1464 << "\n\\paperpagestyle " << pagestyle
1465 << "\n\\tablestyle " << tablestyle << '\n';
1466 if (!listings_params.empty())
1467 os << "\\listings_params \"" <<
1468 InsetListingsParams(listings_params).encodedString() << "\"\n";
1469 for (int i = 0; i < 4; ++i) {
1470 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
1471 if (user_defined_bullet(i).getFont() != -1) {
1472 os << "\\bullet " << i << " "
1473 << user_defined_bullet(i).getFont() << " "
1474 << user_defined_bullet(i).getCharacter() << " "
1475 << user_defined_bullet(i).getSize() << "\n";
1479 os << "\\bulletLaTeX " << i << " \""
1480 << lyx::to_ascii(user_defined_bullet(i).getText())
1486 os << "\\tracking_changes "
1487 << (save_transient_properties ? convert<string>(track_changes) : "false")
1490 os << "\\output_changes "
1491 << (save_transient_properties ? convert<string>(output_changes) : "false")
1494 os << "\\change_bars "
1495 << (save_transient_properties ? convert<string>(change_bars) : "false")
1498 os << "\\postpone_fragile_content " << convert<string>(postpone_fragile_content) << '\n';
1500 os << "\\html_math_output " << html_math_output << '\n'
1501 << "\\html_css_as_file " << html_css_as_file << '\n'
1502 << "\\html_be_strict " << convert<string>(html_be_strict) << '\n';
1504 os << "\\docbook_table_output " << docbook_table_output << '\n';
1506 if (html_math_img_scale != 1.0)
1507 os << "\\html_math_img_scale " << convert<string>(html_math_img_scale) << '\n';
1508 if (!html_latex_start.empty())
1509 os << "\\html_latex_start " << html_latex_start << '\n';
1510 if (!html_latex_end.empty())
1511 os << "\\html_latex_end " << html_latex_end << '\n';
1513 os << pimpl_->authorlist;
1517 void BufferParams::validate(LaTeXFeatures & features) const
1519 features.require(documentClass().required());
1521 if (columns > 1 && language->rightToLeft())
1522 features.require("rtloutputdblcol");
1524 if (output_changes) {
1525 bool xcolorulem = LaTeXFeatures::isAvailable("ulem") &&
1526 LaTeXFeatures::isAvailable("xcolor");
1528 switch (features.runparams().flavor) {
1530 case Flavor::DviLuaTeX:
1532 features.require("ct-xcolor-ulem");
1533 features.require("ulem");
1534 features.require("xcolor");
1536 features.require("ct-none");
1539 case Flavor::LuaTeX:
1540 case Flavor::PdfLaTeX:
1543 features.require("ct-xcolor-ulem");
1544 features.require("ulem");
1545 features.require("xcolor");
1546 // improves color handling in PDF output
1547 features.require("pdfcolmk");
1549 features.require("ct-none");
1556 features.require("changebar");
1559 // Floats with 'Here definitely' as default setting.
1560 if (float_placement.find('H') != string::npos)
1561 features.require("float");
1563 for (auto const & pm : use_packages) {
1564 if (pm.first == "amsmath") {
1565 // AMS Style is at document level
1566 if (pm.second == package_on ||
1567 features.isProvided("amsmath"))
1568 features.require(pm.first);
1569 } else if (pm.second == package_on)
1570 features.require(pm.first);
1573 // Document-level line spacing
1574 if (spacing().getSpace() != Spacing::Single && !spacing().isDefault())
1575 features.require("setspace");
1577 // the bullet shapes are buffer level not paragraph level
1578 // so they are tested here
1579 for (int i = 0; i < 4; ++i) {
1580 if (user_defined_bullet(i) == ITEMIZE_DEFAULTS[i])
1582 int const font = user_defined_bullet(i).getFont();
1584 int const c = user_defined_bullet(i).getCharacter();
1590 features.require("latexsym");
1592 } else if (font == 1) {
1593 features.require("amssymb");
1594 } else if (font >= 2 && font <= 5) {
1595 features.require("pifont");
1599 if (pdfoptions().use_hyperref) {
1600 features.require("hyperref");
1601 // due to interferences with babel and hyperref, the color package has to
1602 // be loaded after hyperref when hyperref is used with the colorlinks
1603 // option, see http://www.lyx.org/trac/ticket/5291
1604 if (pdfoptions().colorlinks)
1605 features.require("color");
1607 if (!listings_params.empty()) {
1608 // do not test validity because listings_params is
1609 // supposed to be valid
1611 InsetListingsParams(listings_params).separatedParams(true);
1612 // we can't support all packages, but we should load the color package
1613 if (par.find("\\color", 0) != string::npos)
1614 features.require("color");
1617 // some languages are only available via polyglossia
1618 if (features.hasPolyglossiaExclusiveLanguages())
1619 features.require("polyglossia");
1621 if (useNonTeXFonts && fontsMath() != "auto")
1622 features.require("unicode-math");
1625 features.require("microtype");
1627 if (!language->required().empty())
1628 features.require(language->required());
1632 bool BufferParams::writeLaTeX(otexstream & os, LaTeXFeatures & features,
1633 FileName const & filepath) const
1635 // http://www.tug.org/texmf-dist/doc/latex/base/fixltx2e.pdf
1636 // !! To use the Fix-cm package, load it before \documentclass, and use the command
1637 // \RequirePackage to do so, rather than the normal \usepackage
1638 // Do not try to load any other package before the document class, unless you
1639 // have a thorough understanding of the LATEX internals and know exactly what you
1641 if (features.mustProvide("fix-cm"))
1642 os << "\\RequirePackage{fix-cm}\n";
1643 // Likewise for fixltx2e. If other packages conflict with this policy,
1644 // treat it as a package bug (and report it!)
1645 // See http://www.latex-project.org/cgi-bin/ltxbugs2html?pr=latex/4407
1646 if (features.mustProvide("fixltx2e"))
1647 os << "\\RequirePackage{fixltx2e}\n";
1649 os << "\\documentclass";
1651 DocumentClass const & tclass = documentClass();
1653 ostringstream clsoptions; // the document class options.
1655 if (tokenPos(tclass.opt_fontsize(),
1656 '|', fontsize) >= 0) {
1657 // only write if existing in list (and not default)
1658 clsoptions << subst(tclass.fontsizeformat(), "$$s", fontsize) << ",";
1661 // paper sizes not supported by the class itself need the
1663 vector<string> classpsizes = getVectorFromString(tclass.opt_pagesize(), "|");
1664 bool class_supported_papersize = papersize == PAPER_DEFAULT
1665 || find(classpsizes.begin(), classpsizes.end(), string_papersize[papersize]) != classpsizes.end();
1667 if ((!use_geometry || features.isProvided("geometry-light"))
1668 && class_supported_papersize && papersize != PAPER_DEFAULT)
1669 clsoptions << subst(tclass.pagesizeformat(), "$$s", string_papersize[papersize]) << ",";
1672 if (sides != tclass.sides()) {
1675 clsoptions << "oneside,";
1678 clsoptions << "twoside,";
1684 if (columns != tclass.columns()) {
1686 clsoptions << "twocolumn,";
1688 clsoptions << "onecolumn,";
1692 && orientation == ORIENTATION_LANDSCAPE)
1693 clsoptions << "landscape,";
1696 clsoptions << "fleqn,";
1698 switch(math_numbering_side) {
1700 clsoptions << "leqno,";
1703 clsoptions << "reqno,";
1704 features.require("amsmath");
1710 // language should be a parameter to \documentclass
1711 if (language->babel() == "hebrew"
1712 && default_language->babel() != "hebrew")
1713 // This seems necessary
1714 features.useLanguage(default_language);
1716 ostringstream language_options;
1717 bool const use_babel = features.useBabel() && !features.isProvided("babel");
1718 bool const use_polyglossia = features.usePolyglossia();
1719 bool const global = lyxrc.language_global_options;
1720 if (features.useBabel() || (use_polyglossia && global)) {
1721 language_options << features.getBabelLanguages();
1722 if (!language->babel().empty()) {
1723 if (!language_options.str().empty())
1724 language_options << ',';
1725 language_options << language->babel();
1727 if (global && !language_options.str().empty())
1728 clsoptions << language_options.str() << ',';
1731 // the predefined options from the layout
1732 if (use_default_options && !tclass.options().empty())
1733 clsoptions << tclass.options() << ',';
1735 // the user-defined options
1736 if (!options.empty()) {
1737 clsoptions << options << ',';
1740 docstring const strOptions = from_utf8(clsoptions.str());
1741 if (!strOptions.empty()) {
1742 // Check if class options contain uncodable glyphs
1743 docstring uncodable_glyphs;
1744 docstring options_encodable;
1745 Encoding const * const enc = features.runparams().encoding;
1747 for (char_type c : strOptions) {
1748 if (!enc->encodable(c)) {
1749 docstring const glyph(1, c);
1750 LYXERR0("Uncodable character '"
1752 << "' in class options!");
1753 uncodable_glyphs += glyph;
1754 if (features.runparams().dryrun) {
1755 options_encodable += "<" + _("LyX Warning: ")
1756 + _("uncodable character") + " '";
1757 options_encodable += c;
1758 options_encodable += "'>";
1761 options_encodable += c;
1764 options_encodable = strOptions;
1766 // On BUFFER_VIEW|UPDATE, warn user if we found uncodable glyphs
1767 if (!features.runparams().dryrun && !uncodable_glyphs.empty()) {
1768 frontend::Alert::warning(
1769 _("Uncodable character in class options"),
1771 _("The class options of your document contain glyphs "
1772 "that are unknown in the current document encoding "
1773 "(namely %1$s).\nThese glyphs are omitted "
1774 " from the output, which may result in "
1775 "incomplete output."
1776 "\n\nPlease select an appropriate "
1777 "document encoding\n"
1778 "(such as utf8) or change the "
1779 "class options accordingly."),
1782 options_encodable = rtrim(options_encodable, ",");
1783 os << '[' << options_encodable << ']';
1786 os << '{' << from_ascii(tclass.latexname()) << "}\n";
1787 // end of \documentclass defs
1789 // The package options (via \PassOptionsToPackage)
1790 os << from_ascii(features.getPackageOptions());
1792 // if we use fontspec or newtxmath, we have to load the AMS packages here
1793 string const ams = features.loadAMSPackages();
1794 bool const ot1 = (main_font_encoding() == "default" || main_font_encoding() == "OT1");
1795 bool const use_newtxmath =
1796 theLaTeXFonts().getLaTeXFont(from_ascii(fontsMath())).getUsedPackage(
1797 ot1, false, false) == "newtxmath";
1798 if ((useNonTeXFonts || use_newtxmath) && !ams.empty())
1799 os << from_ascii(ams);
1801 if (useNonTeXFonts) {
1802 // Babel (as of 2017/11/03) loads fontspec itself
1803 if (!features.isProvided("fontspec")
1804 && !(features.useBabel() && features.isAvailable("babel-2017/11/03")))
1805 os << "\\usepackage{fontspec}\n";
1806 if (features.mustProvide("unicode-math")
1807 && features.isAvailable("unicode-math"))
1808 os << "\\usepackage{unicode-math}\n";
1811 // load CJK support package before font selection
1812 // (see autotests/export/latex/CJK/micro-sign_utf8-cjk-libertine.lyx)
1813 if (!useNonTeXFonts && encoding().package() != Encoding::none && inputenc != "utf8x"
1814 && (encoding().package() == Encoding::CJK || features.mustProvide("CJK"))) {
1815 if (inputenc == "utf8-cjk" || inputenc == "utf8")
1816 os << "\\usepackage{CJKutf8}\n";
1818 os << "\\usepackage[encapsulated]{CJK}\n";
1821 // font selection must be done before loading fontenc.sty
1822 // but after babel with non-TeX fonts
1823 string const fonts = loadFonts(features);
1824 if (!fonts.empty() && (!features.useBabel() || !useNonTeXFonts))
1825 os << from_utf8(fonts);
1827 if (fonts_default_family != "default")
1828 os << "\\renewcommand{\\familydefault}{\\"
1829 << from_ascii(fonts_default_family) << "}\n";
1831 // set font encoding
1832 // non-TeX fonts use font encoding TU (set by fontspec)
1833 if (!useNonTeXFonts && !features.isProvided("fontenc")
1834 && main_font_encoding() != "default") {
1835 // get main font encodings
1836 vector<string> fontencs = font_encodings();
1837 // get font encodings of secondary languages
1838 // FIXME: some languages (hebrew, ...) assume a standard font encoding as last
1839 // option (for text in other languages).
1840 features.getFontEncodings(fontencs);
1841 if (!fontencs.empty()) {
1842 os << "\\usepackage["
1843 << from_ascii(getStringFromVector(fontencs))
1848 // Load textcomp and pmboxdraw before (lua)inputenc (#11454)
1849 if (features.mustProvide("textcomp"))
1850 os << "\\usepackage{textcomp}\n";
1851 if (features.mustProvide("pmboxdraw"))
1852 os << "\\usepackage{pmboxdraw}\n";
1854 // handle inputenc etc.
1855 // (In documents containing text in Thai language,
1856 // we must load inputenc after babel, see lib/languages).
1857 if (!contains(features.getBabelPostsettings(), from_ascii("thai.ldf")))
1858 writeEncodingPreamble(os, features);
1861 if (!features.runparams().includeall && !included_children_.empty()) {
1862 os << "\\includeonly{";
1864 for (auto incfile : included_children_) {
1865 FileName inc = makeAbsPath(incfile, filepath.absFileName());
1866 string mangled = DocFileName(changeExtension(inc.absFileName(), ".tex")).
1868 if (!features.runparams().nice)
1870 // \includeonly doesn't want an extension
1871 incfile = changeExtension(incfile, string());
1872 incfile = support::latex_path(incfile);
1873 if (!incfile.empty()) {
1876 os << from_utf8(incfile);
1883 if (!features.isProvided("geometry")
1884 && (use_geometry || !class_supported_papersize)) {
1885 odocstringstream ods;
1886 if (!getGraphicsDriver("geometry").empty())
1887 ods << getGraphicsDriver("geometry");
1888 if (orientation == ORIENTATION_LANDSCAPE)
1889 ods << ",landscape";
1890 switch (papersize) {
1892 if (!paperwidth.empty())
1893 ods << ",paperwidth="
1894 << from_ascii(paperwidth);
1895 if (!paperheight.empty())
1896 ods << ",paperheight="
1897 << from_ascii(paperheight);
1899 case PAPER_USLETTER:
1901 case PAPER_USEXECUTIVE:
1930 ods << "," << from_ascii(string_papersize_geometry[papersize]);
1935 docstring g_options = trim(ods.str(), ",");
1936 os << "\\usepackage";
1937 // geometry-light means that the class works with geometry, but overwrites
1938 // the package options and paper sizes (memoir does this).
1939 // In this case, all options need to go to \geometry
1940 // and the standard paper sizes need to go to the class options.
1941 if (!g_options.empty() && !features.isProvided("geometry-light")) {
1942 os << '[' << g_options << ']';
1945 os << "{geometry}\n";
1946 if (use_geometry || features.isProvided("geometry-light")) {
1947 os << "\\geometry{verbose";
1948 if (!g_options.empty())
1949 // Output general options here with "geometry light".
1950 os << "," << g_options;
1951 // output this only if use_geometry is true
1953 if (!topmargin.empty())
1954 os << ",tmargin=" << from_ascii(Length(topmargin).asLatexString());
1955 if (!bottommargin.empty())
1956 os << ",bmargin=" << from_ascii(Length(bottommargin).asLatexString());
1957 if (!leftmargin.empty())
1958 os << ",lmargin=" << from_ascii(Length(leftmargin).asLatexString());
1959 if (!rightmargin.empty())
1960 os << ",rmargin=" << from_ascii(Length(rightmargin).asLatexString());
1961 if (!headheight.empty())
1962 os << ",headheight=" << from_ascii(Length(headheight).asLatexString());
1963 if (!headsep.empty())
1964 os << ",headsep=" << from_ascii(Length(headsep).asLatexString());
1965 if (!footskip.empty())
1966 os << ",footskip=" << from_ascii(Length(footskip).asLatexString());
1967 if (!columnsep.empty())
1968 os << ",columnsep=" << from_ascii(Length(columnsep).asLatexString());
1972 } else if (orientation == ORIENTATION_LANDSCAPE
1973 || papersize != PAPER_DEFAULT) {
1974 features.require("papersize");
1977 if (tokenPos(tclass.opt_pagestyle(), '|', pagestyle) >= 0) {
1978 if (pagestyle == "fancy")
1979 os << "\\usepackage{fancyhdr}\n";
1980 os << "\\pagestyle{" << from_ascii(pagestyle) << "}\n";
1983 // only output when the background color is not default
1984 if (isbackgroundcolor) {
1985 // only require color here, the background color will be defined
1986 // in LaTeXFeatures.cpp to avoid interferences with the LaTeX
1988 features.require("color");
1989 features.require("pagecolor");
1992 // only output when the font color is not default
1994 // only require color here, the font color will be defined
1995 // in LaTeXFeatures.cpp to avoid interferences with the LaTeX
1997 features.require("color");
1998 features.require("fontcolor");
2001 // Only if class has a ToC hierarchy
2002 if (tclass.hasTocLevels()) {
2003 if (secnumdepth != tclass.secnumdepth()) {
2004 os << "\\setcounter{secnumdepth}{"
2008 if (tocdepth != tclass.tocdepth()) {
2009 os << "\\setcounter{tocdepth}{"
2015 if (paragraph_separation) {
2016 // when skip separation
2018 switch (getDefSkip().kind()) {
2019 case VSpace::SMALLSKIP:
2020 psopt = "\\smallskipamount";
2022 case VSpace::MEDSKIP:
2023 psopt = "\\medskipamount";
2025 case VSpace::BIGSKIP:
2026 psopt = "\\bigskipamount";
2028 case VSpace::HALFLINE:
2029 // default (no option)
2031 case VSpace::FULLLINE:
2032 psopt = "\\baselineskip";
2034 case VSpace::LENGTH:
2035 psopt = getDefSkip().length().asLatexString();
2040 if (!features.isProvided("parskip")) {
2042 psopt = "[skip=" + psopt + "]";
2043 os << "\\usepackage" + psopt + "{parskip}\n";
2045 os << "\\setlength{\\parskip}{" + psopt + "}\n";
2048 // when separation by indentation
2049 // only output something when a width is given
2050 if (!getParIndent().empty()) {
2051 os << "\\setlength{\\parindent}{"
2052 << from_utf8(getParIndent().asLatexString())
2057 if (is_math_indent) {
2058 // when formula indentation
2059 // only output something when it is not the default
2060 if (!getMathIndent().empty()) {
2061 os << "\\setlength{\\mathindent}{"
2062 << from_utf8(getMathIndent().asString())
2067 // Now insert the LyX specific LaTeX commands...
2068 features.resolveAlternatives();
2069 features.expandMultiples();
2072 if (!output_sync_macro.empty())
2073 os << from_utf8(output_sync_macro) +"\n";
2074 else if (features.runparams().flavor == Flavor::LaTeX)
2075 os << "\\usepackage[active]{srcltx}\n";
2076 else if (features.runparams().flavor == Flavor::PdfLaTeX)
2077 os << "\\synctex=-1\n";
2080 // due to interferences with babel and hyperref, the color package has to
2081 // be loaded (when it is not already loaded) before babel when hyperref
2082 // is used with the colorlinks option, see
2083 // http://www.lyx.org/trac/ticket/5291
2084 // we decided therefore to load color always before babel, see
2085 // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg144349.html
2086 os << from_ascii(features.getColorOptions());
2088 // If we use hyperref, jurabib, japanese or varioref,
2089 // we have to call babel before
2091 && (features.isRequired("jurabib")
2092 || features.isRequired("hyperref")
2093 || features.isRequired("varioref")
2094 || features.isRequired("japanese"))) {
2095 os << features.getBabelPresettings();
2097 os << from_utf8(babelCall(language_options.str(),
2098 !lyxrc.language_global_options)) + '\n';
2099 os << features.getBabelPostsettings();
2102 // The optional packages;
2103 os << from_ascii(features.getPackages());
2105 // Additional Indices
2106 if (features.isRequired("splitidx")) {
2107 for (auto const & idx : indiceslist()) {
2108 os << "\\newindex{";
2109 os << escape(idx.shortcut());
2115 os << from_utf8(spacing().writePreamble(features.isProvided("SetSpace")));
2118 // * Hyperref manual: "Make sure it comes last of your loaded
2119 // packages, to give it a fighting chance of not being over-written,
2120 // since its job is to redefine many LaTeX commands."
2121 // * Email from Heiko Oberdiek: "It is usually better to load babel
2122 // before hyperref. Then hyperref has a chance to detect babel.
2123 // * Has to be loaded before the "LyX specific LaTeX commands" to
2124 // avoid errors with algorithm floats.
2125 // use hyperref explicitly if it is required
2126 if (features.isRequired("hyperref")) {
2127 OutputParams tmp_params = features.runparams();
2128 pdfoptions().writeLaTeX(tmp_params, os,
2129 features.isProvided("hyperref"));
2130 // correctly break URLs with hyperref and dvi/ps output
2131 if (features.runparams().hyperref_driver == "dvips"
2132 && features.isAvailable("breakurl"))
2133 os << "\\usepackage{breakurl}\n";
2134 } else if (features.isRequired("nameref"))
2135 // hyperref loads this automatically
2136 os << "\\usepackage{nameref}\n";
2139 os << "\\usepackage";
2140 if (!lineno_opts.empty())
2141 os << "[" << lineno_opts << "]";
2143 os << "\\linenumbers\n";
2146 // bibtopic needs to be loaded after hyperref.
2147 // the dot provides the aux file naming which LyX can detect.
2148 if (features.mustProvide("bibtopic"))
2149 os << "\\usepackage[dot]{bibtopic}\n";
2151 // Will be surrounded by \makeatletter and \makeatother when not empty
2152 otexstringstream atlyxpreamble;
2154 // Some macros LyX will need
2156 TexString tmppreamble = features.getMacros();
2157 if (!tmppreamble.str.empty())
2158 atlyxpreamble << "\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
2159 "LyX specific LaTeX commands.\n"
2160 << move(tmppreamble)
2163 // the text class specific preamble
2165 docstring tmppreamble = features.getTClassPreamble();
2166 if (!tmppreamble.empty())
2167 atlyxpreamble << "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
2168 "Textclass specific LaTeX commands.\n"
2172 // suppress date if selected
2173 // use \@ifundefined because we cannot be sure that every document class
2174 // has a \date command
2176 atlyxpreamble << "\\@ifundefined{date}{}{\\date{}}\n";
2178 /* the user-defined preamble */
2179 if (!containsOnly(preamble, " \n\t")) {
2181 atlyxpreamble << "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
2182 "User specified LaTeX commands.\n";
2184 // Check if the user preamble contains uncodable glyphs
2185 odocstringstream user_preamble;
2186 docstring uncodable_glyphs;
2187 Encoding const * const enc = features.runparams().encoding;
2189 for (char_type c : preamble) {
2190 if (!enc->encodable(c)) {
2191 docstring const glyph(1, c);
2192 LYXERR0("Uncodable character '"
2194 << "' in user preamble!");
2195 uncodable_glyphs += glyph;
2196 if (features.runparams().dryrun) {
2197 user_preamble << "<" << _("LyX Warning: ")
2198 << _("uncodable character") << " '";
2199 user_preamble.put(c);
2200 user_preamble << "'>";
2203 user_preamble.put(c);
2206 user_preamble << preamble;
2208 // On BUFFER_VIEW|UPDATE, warn user if we found uncodable glyphs
2209 if (!features.runparams().dryrun && !uncodable_glyphs.empty()) {
2210 frontend::Alert::warning(
2211 _("Uncodable character in user preamble"),
2213 _("The user preamble of your document contains glyphs "
2214 "that are unknown in the current document encoding "
2215 "(namely %1$s).\nThese glyphs are omitted "
2216 " from the output, which may result in "
2217 "incomplete output."
2218 "\n\nPlease select an appropriate "
2219 "document encoding\n"
2220 "(such as utf8) or change the "
2221 "preamble code accordingly."),
2224 atlyxpreamble << user_preamble.str() << '\n';
2227 // footmisc must be loaded after setspace
2228 // Load it here to avoid clashes with footmisc loaded in the user
2229 // preamble. For that reason we also pass the options via
2230 // \PassOptionsToPackage in getPreamble() and not here.
2231 if (features.mustProvide("footmisc"))
2232 atlyxpreamble << "\\usepackage{footmisc}\n";
2234 // subfig loads internally the LaTeX package "caption". As
2235 // caption is a very popular package, users will load it in
2236 // the preamble. Therefore we must load subfig behind the
2237 // user-defined preamble and check if the caption package was
2238 // loaded or not. For the case that caption is loaded before
2239 // subfig, there is the subfig option "caption=false". This
2240 // option also works when a koma-script class is used and
2241 // koma's own caption commands are used instead of caption. We
2242 // use \PassOptionsToPackage here because the user could have
2243 // already loaded subfig in the preamble.
2244 if (features.mustProvide("subfig"))
2245 atlyxpreamble << "\\ifdefined\\showcaptionsetup\n"
2246 " % Caption package is used. Advise subfig not to load it again.\n"
2247 " \\PassOptionsToPackage{caption=false}{subfig}\n"
2249 "\\usepackage{subfig}\n";
2251 // Itemize bullet settings need to be last in case the user
2252 // defines their own bullets that use a package included
2253 // in the user-defined preamble -- ARRae
2254 // Actually it has to be done much later than that
2255 // since some packages like frenchb make modifications
2256 // at \begin{document} time -- JMarc
2257 docstring bullets_def;
2258 for (int i = 0; i < 4; ++i) {
2259 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
2260 if (bullets_def.empty())
2261 bullets_def += "\\AtBeginDocument{\n";
2262 bullets_def += " \\def\\labelitemi";
2264 // `i' is one less than the item to modify
2271 bullets_def += "ii";
2277 bullets_def += '{' +
2278 user_defined_bullet(i).getText()
2283 if (!bullets_def.empty())
2284 atlyxpreamble << bullets_def << "}\n\n";
2286 if (!atlyxpreamble.empty())
2287 os << "\n\\makeatletter\n"
2288 << atlyxpreamble.release()
2289 << "\\makeatother\n\n";
2291 // We try to load babel late, in case it interferes with other packages.
2292 // Jurabib, hyperref, varioref, bicaption, menukeys and listings (bug 8995)
2293 // have to be called after babel, though.
2294 if (use_babel && !features.isRequired("jurabib")
2295 && !features.isRequired("hyperref")
2296 && !features.isRequired("varioref")
2297 && !features.isRequired("japanese")) {
2298 os << features.getBabelPresettings();
2300 os << from_utf8(babelCall(language_options.str(),
2301 !lyxrc.language_global_options)) + '\n';
2302 os << features.getBabelPostsettings();
2304 // In documents containing text in Thai language,
2305 // we must load inputenc after babel (see lib/languages).
2306 if (contains(features.getBabelPostsettings(), from_ascii("thai.ldf")))
2307 writeEncodingPreamble(os, features);
2309 // font selection must be done after babel with non-TeX fonts
2310 if (!fonts.empty() && features.useBabel() && useNonTeXFonts)
2311 os << from_utf8(fonts);
2313 if (features.isRequired("bicaption"))
2314 os << "\\usepackage{bicaption}\n";
2315 if (!listings_params.empty()
2316 || features.mustProvide("listings")
2317 || features.mustProvide("minted")) {
2319 os << "\\usepackage{minted}\n";
2321 os << "\\usepackage{listings}\n";
2323 string lst_params = listings_params;
2324 // If minted, do not output the language option (bug 11203)
2325 if (use_minted && contains(lst_params, "language=")) {
2326 vector<string> opts =
2327 getVectorFromString(lst_params, ",", false);
2328 for (size_t i = 0; i < opts.size(); ++i) {
2329 if (prefixIs(opts[i], "language="))
2330 opts.erase(opts.begin() + i--);
2332 lst_params = getStringFromVector(opts, ",");
2334 if (!lst_params.empty()) {
2336 os << "\\setminted{";
2339 // do not test validity because listings_params is
2340 // supposed to be valid
2342 InsetListingsParams(lst_params).separatedParams(true);
2343 os << from_utf8(par);
2347 // xunicode only needs to be loaded if tipa is used
2348 // (the rest is obsoleted by the new TU encoding).
2349 // It needs to be loaded at least after amsmath, amssymb,
2350 // esint and the other packages that provide special glyphs
2351 if (features.mustProvide("tipa") && useNonTeXFonts
2352 && !features.isProvided("xunicode")) {
2353 // The `xunicode` package officially only supports XeTeX,
2354 // but also works with LuaTeX. We work around its XeTeX test.
2355 if (features.runparams().flavor != Flavor::XeTeX) {
2356 os << "% Pretend to xunicode that we are XeTeX\n"
2357 << "\\def\\XeTeXpicfile{}\n";
2359 os << "\\usepackage{xunicode}\n";
2362 // covington must be loaded after beamerarticle
2363 if (features.isRequired("covington"))
2364 os << "\\usepackage{covington}\n";
2366 // Polyglossia must be loaded last ...
2367 if (use_polyglossia) {
2369 os << "\\usepackage{polyglossia}\n";
2370 // set the main language
2371 os << "\\setdefaultlanguage";
2372 if (!language->polyglossiaOpts().empty())
2373 os << "[" << from_ascii(language->polyglossiaOpts()) << "]";
2374 os << "{" << from_ascii(language->polyglossia()) << "}\n";
2375 // now setup the other languages
2376 set<string> const polylangs =
2377 features.getPolyglossiaLanguages();
2378 for (auto const & pl : polylangs) {
2379 // We do not output the options here; they are output in
2380 // the language switch commands. This is safer if multiple
2381 // varieties are used.
2382 if (pl == language->polyglossia())
2384 os << "\\setotherlanguage";
2385 os << "{" << from_ascii(pl) << "}\n";
2389 // ... but before biblatex (see #7065)
2390 if ((features.mustProvide("biblatex")
2391 || features.isRequired("biblatex-chicago"))
2392 && !features.isProvided("biblatex-chicago")
2393 && !features.isProvided("biblatex-natbib")
2394 && !features.isProvided("natbib-internal")
2395 && !features.isProvided("natbib")
2396 && !features.isProvided("jurabib")) {
2397 // The biblatex-chicago package has a differing interface
2398 // it uses a wrapper package and loads styles via fixed options
2399 bool const chicago = features.isRequired("biblatex-chicago");
2402 os << "\\usepackage";
2403 if (!biblatex_bibstyle.empty()
2404 && (biblatex_bibstyle == biblatex_citestyle)
2406 opts = "style=" + biblatex_bibstyle;
2408 } else if (!chicago) {
2409 if (!biblatex_bibstyle.empty()) {
2410 opts = "bibstyle=" + biblatex_bibstyle;
2413 if (!biblatex_citestyle.empty()) {
2414 opts += delim + "citestyle=" + biblatex_citestyle;
2418 if (!multibib.empty() && multibib != "child") {
2419 opts += delim + "refsection=" + multibib;
2422 if (bibtexCommand() == "bibtex8"
2423 || prefixIs(bibtexCommand(), "bibtex8 ")) {
2424 opts += delim + "backend=bibtex8";
2426 } else if (bibtexCommand() == "bibtex"
2427 || prefixIs(bibtexCommand(), "bibtex ")) {
2428 opts += delim + "backend=bibtex";
2431 if (!bib_encoding.empty() && encodings.fromLyXName(bib_encoding)) {
2432 opts += delim + "bibencoding="
2433 + encodings.fromLyXName(bib_encoding)->latexName();
2436 if (!biblio_opts.empty())
2437 opts += delim + biblio_opts;
2439 os << "[" << opts << "]";
2441 os << "{biblatex-chicago}\n";
2443 os << "{biblatex}\n";
2447 // Load custom language package here
2448 if (features.langPackage() == LaTeXFeatures::LANG_PACK_CUSTOM) {
2449 if (lang_package == "default")
2450 os << from_utf8(lyxrc.language_custom_package);
2452 os << from_utf8(lang_package);
2456 // Since menukeys uses catoptions, which does some heavy changes on key-value options,
2457 // it is recommended to load menukeys as the last package (even after hyperref)
2458 if (features.isRequired("menukeys"))
2459 os << "\\usepackage{menukeys}\n";
2461 docstring const i18npreamble =
2462 features.getTClassI18nPreamble(use_babel, use_polyglossia,
2464 if (!i18npreamble.empty())
2465 os << i18npreamble + '\n';
2471 void BufferParams::useClassDefaults()
2473 DocumentClass const & tclass = documentClass();
2475 sides = tclass.sides();
2476 columns = tclass.columns();
2477 pagestyle = tclass.pagestyle();
2478 tablestyle = tclass.tablestyle();
2479 use_default_options = true;
2480 // Only if class has a ToC hierarchy
2481 if (tclass.hasTocLevels()) {
2482 secnumdepth = tclass.secnumdepth();
2483 tocdepth = tclass.tocdepth();
2488 bool BufferParams::hasClassDefaults() const
2490 DocumentClass const & tclass = documentClass();
2492 return sides == tclass.sides()
2493 && columns == tclass.columns()
2494 && pagestyle == tclass.pagestyle()
2495 && tablestyle == tclass.tablestyle()
2496 && use_default_options
2497 && secnumdepth == tclass.secnumdepth()
2498 && tocdepth == tclass.tocdepth();
2502 DocumentClass const & BufferParams::documentClass() const
2508 DocumentClassConstPtr BufferParams::documentClassPtr() const
2514 void BufferParams::setDocumentClass(DocumentClassConstPtr tc)
2516 // evil, but this function is evil
2517 doc_class_ = const_pointer_cast<DocumentClass>(tc);
2518 invalidateConverterCache();
2522 bool BufferParams::setBaseClass(string const & classname, string const & path)
2524 LYXERR(Debug::TCLASS, "setBaseClass: " << classname);
2525 LayoutFileList & bcl = LayoutFileList::get();
2526 if (!bcl.haveClass(classname)) {
2528 bformat(_("The layout file:\n"
2530 "could not be found. A default textclass with default\n"
2531 "layouts will be used. LyX will not be able to produce\n"
2533 from_utf8(classname));
2534 frontend::Alert::error(_("Document class not found"), s);
2535 bcl.addEmptyClass(classname);
2538 bool const success = bcl[classname].load(path);
2541 bformat(_("Due to some error in it, the layout file:\n"
2543 "could not be loaded. A default textclass with default\n"
2544 "layouts will be used. LyX will not be able to produce\n"
2546 from_utf8(classname));
2547 frontend::Alert::error(_("Could not load class"), s);
2548 bcl.addEmptyClass(classname);
2551 pimpl_->baseClass_ = classname;
2552 layout_modules_.adaptToBaseClass(baseClass(), removed_modules_);
2557 LayoutFile const * BufferParams::baseClass() const
2559 if (LayoutFileList::get().haveClass(pimpl_->baseClass_))
2560 return &(LayoutFileList::get()[pimpl_->baseClass_]);
2566 LayoutFileIndex const & BufferParams::baseClassID() const
2568 return pimpl_->baseClass_;
2572 void BufferParams::makeDocumentClass(bool clone, bool internal)
2577 invalidateConverterCache();
2578 LayoutModuleList mods;
2579 for (auto const & mod : layout_modules_)
2580 mods.push_back(mod);
2582 doc_class_ = getDocumentClass(*baseClass(), mods, cite_engine_, clone, internal);
2584 TextClass::ReturnValues success = TextClass::OK;
2585 if (!forced_local_layout_.empty())
2586 success = doc_class_->read(to_utf8(forced_local_layout_),
2588 if (!local_layout_.empty() &&
2589 (success == TextClass::OK || success == TextClass::OK_OLDFORMAT))
2590 success = doc_class_->read(to_utf8(local_layout_), TextClass::MODULE);
2591 if (success != TextClass::OK && success != TextClass::OK_OLDFORMAT) {
2592 docstring const msg = _("Error reading internal layout information");
2593 frontend::Alert::warning(_("Read Error"), msg);
2598 bool BufferParams::layoutModuleCanBeAdded(string const & modName) const
2600 return layout_modules_.moduleCanBeAdded(modName, baseClass());
2604 docstring BufferParams::getLocalLayout(bool forced) const
2607 return from_utf8(doc_class_->forcedLayouts());
2609 return local_layout_;
2613 void BufferParams::setLocalLayout(docstring const & layout, bool forced)
2616 forced_local_layout_ = layout;
2618 local_layout_ = layout;
2622 bool BufferParams::addLayoutModule(string const & modName)
2624 for (auto const & mod : layout_modules_)
2627 layout_modules_.push_back(modName);
2632 string BufferParams::bufferFormat() const
2634 return documentClass().outputFormat();
2638 bool BufferParams::isExportable(string const & format, bool need_viewable) const
2640 FormatList const & formats = exportableFormats(need_viewable);
2641 for (auto const & fmt : formats) {
2642 if (fmt->name() == format)
2649 FormatList const & BufferParams::exportableFormats(bool only_viewable) const
2651 FormatList & cached = only_viewable ?
2652 pimpl_->viewableFormatList : pimpl_->exportableFormatList;
2653 bool & valid = only_viewable ?
2654 pimpl_->isViewCacheValid : pimpl_->isExportCacheValid;
2658 vector<string> const backs = backends();
2659 set<string> excludes;
2660 if (useNonTeXFonts) {
2661 excludes.insert("latex");
2662 excludes.insert("pdflatex");
2663 } else if (inputenc != "ascii" && inputenc != "utf8-plain") {
2664 // XeTeX with TeX fonts requires input encoding ascii (#10600).
2665 excludes.insert("xetex");
2669 theConverters().getReachable(backs[0], only_viewable, true, excludes);
2670 vector<string>::const_iterator it = backs.begin() + 1;
2671 for (; it != backs.end(); ++it) {
2672 FormatList r = theConverters().getReachable(*it, only_viewable,
2674 result.insert(result.end(), r.begin(), r.end());
2676 sort(result.begin(), result.end(), Format::formatSorter);
2683 vector<string> BufferParams::backends() const
2686 string const buffmt = bufferFormat();
2688 // FIXME: Don't hardcode format names here, but use a flag
2689 if (buffmt == "latex") {
2690 if (encoding().package() == Encoding::japanese)
2691 v.push_back("platex");
2693 if (!useNonTeXFonts) {
2694 v.push_back("pdflatex");
2695 v.push_back("latex");
2698 || inputenc == "ascii" || inputenc == "utf8-plain")
2699 v.push_back("xetex");
2700 v.push_back("luatex");
2701 v.push_back("dviluatex");
2704 string rbuffmt = buffmt;
2705 // If we use an OutputFormat in Japanese docs,
2706 // we need special format in order to get the path
2707 // via pLaTeX (#8823)
2708 if (documentClass().hasOutputFormat()
2709 && encoding().package() == Encoding::japanese)
2711 v.push_back(rbuffmt);
2714 v.push_back("xhtml");
2715 v.push_back("docbook5");
2716 v.push_back("text");
2722 Flavor BufferParams::getOutputFlavor(string const & format) const
2724 string const dformat = (format.empty() || format == "default") ?
2725 getDefaultOutputFormat() : format;
2726 DefaultFlavorCache::const_iterator it =
2727 default_flavors_.find(dformat);
2729 if (it != default_flavors_.end())
2732 Flavor result = Flavor::LaTeX;
2734 // FIXME It'd be better not to hardcode this, but to do
2735 // something with formats.
2736 if (dformat == "xhtml")
2737 result = Flavor::Html;
2738 else if (dformat == "docbook5")
2739 result = Flavor::DocBook5;
2740 else if (dformat == "text")
2741 result = Flavor::Text;
2742 else if (dformat == "lyx")
2743 result = Flavor::LyX;
2744 else if (dformat == "pdflatex")
2745 result = Flavor::PdfLaTeX;
2746 else if (dformat == "xetex")
2747 result = Flavor::XeTeX;
2748 else if (dformat == "luatex")
2749 result = Flavor::LuaTeX;
2750 else if (dformat == "dviluatex")
2751 result = Flavor::DviLuaTeX;
2753 // Try to determine flavor of default output format
2754 vector<string> backs = backends();
2755 if (find(backs.begin(), backs.end(), dformat) == backs.end()) {
2756 // Get shortest path to format
2757 Graph::EdgePath path;
2758 for (auto const & bvar : backs) {
2759 Graph::EdgePath p = theConverters().getPath(bvar, dformat);
2760 if (!p.empty() && (path.empty() || p.size() < path.size())) {
2765 result = theConverters().getFlavor(path);
2768 // cache this flavor
2769 default_flavors_[dformat] = result;
2774 string BufferParams::getDefaultOutputFormat() const
2776 if (!default_output_format.empty()
2777 && default_output_format != "default")
2778 return default_output_format;
2779 if (encoding().package() == Encoding::japanese)
2780 return lyxrc.default_platex_view_format;
2782 return lyxrc.default_otf_view_format;
2783 return lyxrc.default_view_format;
2786 Font const BufferParams::getFont() const
2788 FontInfo f = documentClass().defaultfont();
2789 if (fonts_default_family == "rmdefault")
2790 f.setFamily(ROMAN_FAMILY);
2791 else if (fonts_default_family == "sfdefault")
2792 f.setFamily(SANS_FAMILY);
2793 else if (fonts_default_family == "ttdefault")
2794 f.setFamily(TYPEWRITER_FAMILY);
2795 return Font(f, language);
2799 QuoteStyle BufferParams::getQuoteStyle(string const & qs) const
2801 return quotesstyletranslator().find(qs);
2805 bool BufferParams::isLatex() const
2807 return documentClass().outputType() == LATEX;
2811 bool BufferParams::isLiterate() const
2813 return documentClass().outputType() == LITERATE;
2817 void BufferParams::readPreamble(Lexer & lex)
2819 if (lex.getString() != "\\begin_preamble")
2820 lyxerr << "Error (BufferParams::readPreamble):"
2821 "consistency check failed." << endl;
2823 preamble = lex.getLongString(from_ascii("\\end_preamble"));
2827 void BufferParams::readLocalLayout(Lexer & lex, bool forced)
2829 string const expected = forced ? "\\begin_forced_local_layout" :
2830 "\\begin_local_layout";
2831 if (lex.getString() != expected)
2832 lyxerr << "Error (BufferParams::readLocalLayout):"
2833 "consistency check failed." << endl;
2836 forced_local_layout_ =
2837 lex.getLongString(from_ascii("\\end_forced_local_layout"));
2839 local_layout_ = lex.getLongString(from_ascii("\\end_local_layout"));
2843 bool BufferParams::setLanguage(string const & lang)
2845 Language const *new_language = languages.getLanguage(lang);
2846 if (!new_language) {
2847 // Language lang was not found
2850 language = new_language;
2855 void BufferParams::readLanguage(Lexer & lex)
2857 if (!lex.next()) return;
2859 string const tmptok = lex.getString();
2861 // check if tmptok is part of tex_babel in tex-defs.h
2862 if (!setLanguage(tmptok)) {
2863 // Language tmptok was not found
2864 language = default_language;
2865 lyxerr << "Warning: Setting language `"
2866 << tmptok << "' to `" << language->lang()
2872 void BufferParams::readGraphicsDriver(Lexer & lex)
2877 string const tmptok = lex.getString();
2878 // check if tmptok is part of tex_graphics in tex_defs.h
2881 string const test = tex_graphics[n++];
2883 if (test == tmptok) {
2884 graphics_driver = tmptok;
2889 "Warning: graphics driver `$$Token' not recognized!\n"
2890 " Setting graphics driver to `default'.\n");
2891 graphics_driver = "default";
2898 void BufferParams::readBullets(Lexer & lex)
2903 int const index = lex.getInteger();
2905 int temp_int = lex.getInteger();
2906 user_defined_bullet(index).setFont(temp_int);
2907 temp_bullet(index).setFont(temp_int);
2909 user_defined_bullet(index).setCharacter(temp_int);
2910 temp_bullet(index).setCharacter(temp_int);
2912 user_defined_bullet(index).setSize(temp_int);
2913 temp_bullet(index).setSize(temp_int);
2917 void BufferParams::readBulletsLaTeX(Lexer & lex)
2919 // The bullet class should be able to read this.
2922 int const index = lex.getInteger();
2924 docstring const temp_str = lex.getDocString();
2926 user_defined_bullet(index).setText(temp_str);
2927 temp_bullet(index).setText(temp_str);
2931 void BufferParams::readModules(Lexer & lex)
2933 if (!lex.eatLine()) {
2934 lyxerr << "Error (BufferParams::readModules):"
2935 "Unexpected end of input." << endl;
2939 string mod = lex.getString();
2940 if (mod == "\\end_modules")
2942 addLayoutModule(mod);
2948 void BufferParams::readRemovedModules(Lexer & lex)
2950 if (!lex.eatLine()) {
2951 lyxerr << "Error (BufferParams::readRemovedModules):"
2952 "Unexpected end of input." << endl;
2956 string mod = lex.getString();
2957 if (mod == "\\end_removed_modules")
2959 removed_modules_.push_back(mod);
2962 // now we want to remove any removed modules that were previously
2963 // added. normally, that will be because default modules were added in
2964 // setBaseClass(), which gets called when \textclass is read at the
2965 // start of the read.
2966 for (auto const & rm : removed_modules_) {
2967 LayoutModuleList::iterator const mit = layout_modules_.begin();
2968 LayoutModuleList::iterator const men = layout_modules_.end();
2969 LayoutModuleList::iterator found = find(mit, men, rm);
2972 layout_modules_.erase(found);
2977 void BufferParams::readIncludeonly(Lexer & lex)
2979 if (!lex.eatLine()) {
2980 lyxerr << "Error (BufferParams::readIncludeonly):"
2981 "Unexpected end of input." << endl;
2985 string child = lex.getString();
2986 if (child == "\\end_includeonly")
2988 included_children_.push_back(child);
2994 string BufferParams::paperSizeName(PapersizePurpose purpose, string const & psize) const
2996 PAPER_SIZE ppsize = psize.empty() ? papersize : papersizetranslator().find(psize);
2999 if (documentClass().pagesize() == "default")
3000 // could be anything, so don't guess
3002 return paperSizeName(purpose, documentClass().pagesize());
3003 case PAPER_CUSTOM: {
3004 if (purpose == XDVI && !paperwidth.empty() &&
3005 !paperheight.empty()) {
3006 // heightxwidth<unit>
3007 string first = paperwidth;
3008 string second = paperheight;
3009 if (orientation == ORIENTATION_LANDSCAPE)
3012 return first.erase(first.length() - 2)
3018 // dvips and dvipdfm do not know this
3019 if (purpose == DVIPS || purpose == DVIPDFM)
3023 if (purpose == DVIPS || purpose == DVIPDFM)
3027 if (purpose == DVIPS || purpose == DVIPDFM)
3037 if (purpose == DVIPS || purpose == DVIPDFM)
3041 if (purpose == DVIPS || purpose == DVIPDFM)
3045 if (purpose == DVIPS || purpose == DVIPDFM)
3049 if (purpose == DVIPS || purpose == DVIPDFM)
3053 if (purpose == DVIPS || purpose == DVIPDFM)
3057 // dvipdfm does not know this
3058 if (purpose == DVIPDFM)
3062 if (purpose == DVIPDFM)
3066 if (purpose == DVIPS || purpose == DVIPDFM)
3070 if (purpose == DVIPS || purpose == DVIPDFM)
3074 if (purpose == DVIPS || purpose == DVIPDFM)
3078 if (purpose == DVIPS || purpose == DVIPDFM)
3082 if (purpose == DVIPS || purpose == DVIPDFM)
3086 if (purpose == DVIPS || purpose == DVIPDFM)
3090 if (purpose == DVIPS || purpose == DVIPDFM)
3094 if (purpose == DVIPS || purpose == DVIPDFM)
3098 if (purpose == DVIPS || purpose == DVIPDFM)
3102 if (purpose == DVIPS || purpose == DVIPDFM)
3106 if (purpose == DVIPS || purpose == DVIPDFM)
3110 if (purpose == DVIPS || purpose == DVIPDFM)
3114 if (purpose == DVIPS || purpose == DVIPDFM)
3118 if (purpose == DVIPS || purpose == DVIPDFM)
3122 if (purpose == DVIPS || purpose == DVIPDFM)
3125 case PAPER_USEXECUTIVE:
3126 // dvipdfm does not know this
3127 if (purpose == DVIPDFM)
3132 case PAPER_USLETTER:
3134 if (purpose == XDVI)
3141 string const BufferParams::dvips_options() const
3145 // If the class loads the geometry package, we do not know which
3146 // paper size is used, since we do not set it (bug 7013).
3147 // Therefore we must not specify any argument here.
3148 // dvips gets the correct paper size via DVI specials in this case
3149 // (if the class uses the geometry package correctly).
3150 if (documentClass().provides("geometry"))
3154 && papersize == PAPER_CUSTOM
3155 && !lyxrc.print_paper_dimension_flag.empty()
3156 && !paperwidth.empty()
3157 && !paperheight.empty()) {
3158 // using a custom papersize
3159 result = lyxrc.print_paper_dimension_flag;
3160 result += ' ' + paperwidth;
3161 result += ',' + paperheight;
3163 string const paper_option = paperSizeName(DVIPS);
3164 if (!paper_option.empty() && (paper_option != "letter" ||
3165 orientation != ORIENTATION_LANDSCAPE)) {
3166 // dvips won't accept -t letter -t landscape.
3167 // In all other cases, include the paper size
3169 result = lyxrc.print_paper_flag;
3170 result += ' ' + paper_option;
3173 if (orientation == ORIENTATION_LANDSCAPE &&
3174 papersize != PAPER_CUSTOM)
3175 result += ' ' + lyxrc.print_landscape_flag;
3180 string const BufferParams::main_font_encoding() const
3182 if (font_encodings().empty()) {
3183 if (ascii_lowercase(language->fontenc(*this)) == "none")
3187 return font_encodings().back();
3191 vector<string> const BufferParams::font_encodings() const
3193 string doc_fontenc = (fontenc == "auto") ? string() : fontenc;
3195 vector<string> fontencs;
3197 // "default" means "no explicit font encoding"
3198 if (doc_fontenc != "default") {
3199 if (!doc_fontenc.empty())
3200 // If we have a custom setting, we use only that!
3201 return getVectorFromString(doc_fontenc);
3202 if (!language->fontenc(*this).empty()
3203 && ascii_lowercase(language->fontenc(*this)) != "none") {
3204 vector<string> fencs = getVectorFromString(language->fontenc(*this));
3205 for (auto & fe : fencs) {
3206 if (find(fontencs.begin(), fontencs.end(), fe) == fontencs.end())
3207 fontencs.push_back(fe);
3216 string BufferParams::babelCall(string const & lang_opts, bool const langoptions) const
3218 // suppress the babel call if there is no BabelName defined
3219 // for the document language in the lib/languages file and if no
3220 // other languages are used (lang_opts is then empty)
3221 if (lang_opts.empty())
3223 // The prefs may require the languages to
3224 // be submitted to babel itself (not the class).
3226 return "\\usepackage[" + lang_opts + "]{babel}";
3227 return "\\usepackage{babel}";
3231 docstring BufferParams::getGraphicsDriver(string const & package) const
3235 if (package == "geometry") {
3236 if (graphics_driver == "dvips"
3237 || graphics_driver == "dvipdfm"
3238 || graphics_driver == "pdftex"
3239 || graphics_driver == "vtex")
3240 result = from_ascii(graphics_driver);
3241 else if (graphics_driver == "dvipdfmx")
3242 result = from_ascii("dvipdfm");
3249 void BufferParams::writeEncodingPreamble(otexstream & os,
3250 LaTeXFeatures & features) const
3252 // With no-TeX fonts we use utf8-plain without encoding package.
3256 if (inputenc == "auto-legacy") {
3257 string const doc_encoding =
3258 language->encoding()->latexName();
3259 Encoding::Package const package =
3260 language->encoding()->package();
3262 // Create list of inputenc options:
3263 set<string> encoding_set;
3264 // luainputenc fails with more than one encoding
3265 if (features.runparams().flavor != Flavor::LuaTeX
3266 && features.runparams().flavor != Flavor::DviLuaTeX)
3267 // list all input encodings used in the document
3268 encoding_set = features.getEncodingSet(doc_encoding);
3270 // The "japanese" babel-language requires the pLaTeX engine
3271 // which conflicts with "inputenc".
3272 // See http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129680.html
3273 if ((!encoding_set.empty() || package == Encoding::inputenc)
3274 && !features.isRequired("japanese")
3275 && !features.isProvided("inputenc")) {
3276 os << "\\usepackage[";
3277 set<string>::const_iterator it = encoding_set.begin();
3278 set<string>::const_iterator const end = encoding_set.end();
3280 os << from_ascii(*it);
3283 for (; it != end; ++it)
3284 os << ',' << from_ascii(*it);
3285 if (package == Encoding::inputenc) {
3286 if (!encoding_set.empty())
3288 os << from_ascii(doc_encoding);
3290 if (features.runparams().flavor == Flavor::LuaTeX
3291 || features.runparams().flavor == Flavor::DviLuaTeX)
3292 os << "]{luainputenc}\n";
3294 os << "]{inputenc}\n";
3296 } else if (inputenc != "auto-legacy-plain") {
3297 switch (encoding().package()) {
3298 case Encoding::none:
3300 case Encoding::japanese:
3301 if (encoding().iconvName() != "UTF-8"
3302 && !features.runparams().isFullUnicode())
3303 // don't default to [utf8]{inputenc} with TeXLive >= 18
3304 os << "\\ifdefined\\UseRawInputEncoding\n"
3305 << " \\UseRawInputEncoding\\fi\n";
3307 case Encoding::inputenc:
3308 // do not load inputenc if japanese is used
3309 // or if the class provides inputenc
3310 if (features.isRequired("japanese")
3311 || features.isProvided("inputenc"))
3313 os << "\\usepackage[" << from_ascii(encoding().latexName());
3314 if (features.runparams().flavor == Flavor::LuaTeX
3315 || features.runparams().flavor == Flavor::DviLuaTeX)
3316 os << "]{luainputenc}\n";
3318 os << "]{inputenc}\n";
3322 if (inputenc == "auto-legacy-plain" || features.isRequired("japanese")) {
3323 // don't default to [utf8]{inputenc} with TeXLive >= 18
3324 os << "\\ifdefined\\UseRawInputEncoding\n";
3325 os << " \\UseRawInputEncoding\\fi\n";
3330 string const BufferParams::parseFontName(string const & name) const
3332 string mangled = name;
3333 size_t const idx = mangled.find('[');
3334 if (idx == string::npos || idx == 0)
3337 return mangled.substr(0, idx - 1);
3341 string const BufferParams::loadFonts(LaTeXFeatures & features) const
3343 if (fontsRoman() == "default" && fontsSans() == "default"
3344 && fontsTypewriter() == "default"
3345 && (fontsMath() == "default" || fontsMath() == "auto"))
3351 /* Fontspec (XeTeX, LuaTeX): we provide GUI support for oldstyle
3352 * numbers (Numbers=OldStyle) and sf/tt scaling. The Ligatures=TeX/
3353 * Mapping=tex-text option assures TeX ligatures (such as "--")
3354 * are resolved. Note that tt does not use these ligatures.
3356 * -- add more GUI options?
3357 * -- add more fonts (fonts for other scripts)
3358 * -- if there's a way to find out if a font really supports
3359 * OldStyle, enable/disable the widget accordingly.
3361 if (useNonTeXFonts && features.isAvailable("fontspec")) {
3362 // "Mapping=tex-text" and "Ligatures=TeX" are equivalent.
3363 // However, until v.2 (2010/07/11) fontspec only knew
3364 // Mapping=tex-text (for XeTeX only); then "Ligatures=TeX"
3365 // was introduced for both XeTeX and LuaTeX (LuaTeX
3366 // didn't understand "Mapping=tex-text", while XeTeX
3367 // understood both. With most recent versions, both
3368 // variants are understood by both engines. However,
3369 // we want to provide support for at least TeXLive 2009
3370 // (for XeTeX; LuaTeX is only supported as of v.2)
3371 // As of 2017/11/03, Babel has its own higher-level
3372 // interface on top of fontspec that is to be used.
3373 bool const babelfonts = features.useBabel()
3374 && features.isAvailable("babel-2017/11/03");
3375 string const texmapping =
3376 (features.runparams().flavor == Flavor::XeTeX) ?
3377 "Mapping=tex-text" : "Ligatures=TeX";
3378 if (fontsRoman() != "default") {
3380 os << "\\babelfont{rm}[";
3382 os << "\\setmainfont[";
3383 if (!font_roman_opts.empty())
3384 os << font_roman_opts << ',';
3386 if (fonts_roman_osf)
3387 os << ",Numbers=OldStyle";
3388 os << "]{" << parseFontName(fontsRoman()) << "}\n";
3390 if (fontsSans() != "default") {
3391 string const sans = parseFontName(fontsSans());
3392 if (fontsSansScale() != 100) {
3394 os << "\\babelfont{sf}";
3396 os << "\\setsansfont";
3398 << float(fontsSansScale()) / 100 << ',';
3400 os << "Numbers=OldStyle,";
3401 if (!font_sans_opts.empty())
3402 os << font_sans_opts << ',';
3403 os << texmapping << "]{"
3407 os << "\\babelfont{sf}[";
3409 os << "\\setsansfont[";
3411 os << "Numbers=OldStyle,";
3412 if (!font_sans_opts.empty())
3413 os << font_sans_opts << ',';
3414 os << texmapping << "]{"
3418 if (fontsTypewriter() != "default") {
3419 string const mono = parseFontName(fontsTypewriter());
3420 if (fontsTypewriterScale() != 100) {
3422 os << "\\babelfont{tt}";
3424 os << "\\setmonofont";
3426 << float(fontsTypewriterScale()) / 100;
3427 if (fonts_typewriter_osf)
3428 os << ",Numbers=OldStyle";
3429 if (!font_typewriter_opts.empty())
3430 os << ',' << font_typewriter_opts;
3435 os << "\\babelfont{tt}";
3437 os << "\\setmonofont";
3438 if (!font_typewriter_opts.empty() || fonts_typewriter_osf) {
3440 if (fonts_typewriter_osf)
3441 os << "Numbers=OldStyle";
3442 if (!font_typewriter_opts.empty()) {
3443 if (fonts_typewriter_osf)
3445 os << font_typewriter_opts;
3449 os << '{' << mono << "}\n";
3456 bool const ot1 = (main_font_encoding() == "default" || main_font_encoding() == "OT1");
3457 bool const dryrun = features.runparams().dryrun;
3458 bool const complete = (fontsSans() == "default" && fontsTypewriter() == "default");
3459 bool const nomath = (fontsMath() != "auto");
3462 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsRoman())).getLaTeXCode(
3463 dryrun, ot1, complete, fonts_expert_sc, fonts_roman_osf,
3464 nomath, font_roman_opts);
3467 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsSans())).getLaTeXCode(
3468 dryrun, ot1, complete, fonts_expert_sc, fonts_sans_osf,
3469 nomath, font_sans_opts, fontsSansScale());
3471 // MONOSPACED/TYPEWRITER
3472 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsTypewriter())).getLaTeXCode(
3473 dryrun, ot1, complete, fonts_expert_sc, fonts_typewriter_osf,
3474 nomath, font_typewriter_opts, fontsTypewriterScale());
3477 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsMath())).getLaTeXCode(
3478 dryrun, ot1, complete, fonts_expert_sc, fonts_roman_osf,
3485 Encoding const & BufferParams::encoding() const
3487 // Main encoding for LaTeX output.
3489 return *(encodings.fromLyXName("utf8-plain"));
3490 if (inputenc == "auto-legacy" || inputenc == "auto-legacy-plain")
3491 return *language->encoding();
3492 if (inputenc == "utf8" && language->lang() == "japanese")
3493 return *(encodings.fromLyXName("utf8-platex"));
3494 Encoding const * const enc = encodings.fromLyXName(inputenc);
3497 LYXERR0("Unknown inputenc value `" << inputenc
3498 << "'. Using `auto' instead.");
3499 return *language->encoding();
3503 string const & BufferParams::defaultBiblioStyle() const
3505 if (!biblio_style.empty())
3506 return biblio_style;
3508 map<string, string> const & bs = documentClass().defaultBiblioStyle();
3509 auto cit = bs.find(theCiteEnginesList.getTypeAsString(citeEngineType()));
3510 if (cit != bs.end())
3513 return empty_string();
3517 bool BufferParams::fullAuthorList() const
3519 return documentClass().fullAuthorList();
3523 string BufferParams::getCiteAlias(string const & s) const
3525 vector<string> commands =
3526 documentClass().citeCommands(citeEngineType());
3527 // If it is a real command, don't treat it as an alias
3528 if (find(commands.begin(), commands.end(), s) != commands.end())
3530 map<string,string> aliases = documentClass().citeCommandAliases();
3531 if (aliases.find(s) != aliases.end())
3537 vector<string> BufferParams::citeCommands() const
3539 static CitationStyle const default_style;
3540 vector<string> commands =
3541 documentClass().citeCommands(citeEngineType());
3542 if (commands.empty())
3543 commands.push_back(default_style.name);
3548 vector<CitationStyle> BufferParams::citeStyles() const
3550 static CitationStyle const default_style;
3551 vector<CitationStyle> styles =
3552 documentClass().citeStyles(citeEngineType());
3554 styles.push_back(default_style);
3559 string const BufferParams::bibtexCommand() const
3561 // Return document-specific setting if available
3562 if (bibtex_command != "default")
3563 return bibtex_command;
3565 // If we have "default" in document settings, consult the prefs
3566 // 1. Japanese (uses a specific processor)
3567 if (encoding().package() == Encoding::japanese) {
3568 if (lyxrc.jbibtex_command != "automatic")
3569 // Return the specified program, if "automatic" is not set
3570 return lyxrc.jbibtex_command;
3571 else if (!useBiblatex()) {
3572 // With classic BibTeX, return pbibtex, jbibtex, bibtex
3573 if (lyxrc.jbibtex_alternatives.find("pbibtex") != lyxrc.jbibtex_alternatives.end())
3575 if (lyxrc.jbibtex_alternatives.find("jbibtex") != lyxrc.jbibtex_alternatives.end())
3580 // 2. All other languages
3581 else if (lyxrc.bibtex_command != "automatic")
3582 // Return the specified program, if "automatic" is not set
3583 return lyxrc.bibtex_command;
3585 // 3. Automatic: find the most suitable for the current cite framework
3586 if (useBiblatex()) {
3587 // For Biblatex, we prefer biber (also for Japanese)
3588 // and fall back to bibtex8 and, as last resort, bibtex
3589 if (lyxrc.bibtex_alternatives.find("biber") != lyxrc.bibtex_alternatives.end())
3591 else if (lyxrc.bibtex_alternatives.find("bibtex8") != lyxrc.bibtex_alternatives.end())
3598 bool BufferParams::useBiblatex() const
3600 return theCiteEnginesList[citeEngine()]->getCiteFramework() == "biblatex";
3604 void BufferParams::invalidateConverterCache() const
3606 pimpl_->isExportCacheValid = false;
3607 pimpl_->isViewCacheValid = false;
3611 // We shouldn't need to reset the params here, since anything
3612 // we need will be recopied.
3613 void BufferParams::copyForAdvFR(const BufferParams & bp)
3615 string const & lang = bp.language->lang();
3617 layout_modules_ = bp.layout_modules_;
3618 string const & doc_class = bp.documentClass().name();
3619 setBaseClass(doc_class);
3623 void BufferParams::setBibFileEncoding(string const & file, string const & enc)
3625 bib_encodings[file] = enc;
3629 string const BufferParams::bibFileEncoding(string const & file) const
3631 if (bib_encodings.find(file) == bib_encodings.end())
3633 return bib_encodings.find(file)->second;