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", ""
80 static char const * const string_papersize[] = {
81 "default", "custom", "letter", "legal", "executive",
82 "a0", "a1", "a2", "a3", "a4", "a5", "a6",
83 "b0", "b1", "b2", "b3", "b4", "b5", "b6",
84 "c0", "c1", "c2", "c3", "c4", "c5", "c6",
85 "b0j", "b1j", "b2j", "b3j", "b4j", "b5j", "b6j", ""
89 static char const * const string_papersize_geometry[] = {
90 "default", "custom", "letterpaper", "legalpaper", "executivepaper",
91 "a0paper", "a1paper", "a2paper", "a3paper", "a4paper", "a5paper", "a6paper",
92 "b0paper", "b1paper", "b2paper", "b3paper", "b4paper", "b5paper", "b6paper",
93 "c0paper", "c1paper", "c2paper", "c3paper", "c4paper", "c5paper", "c6paper",
94 "b0j", "b1j", "b2j", "b3j", "b4j", "b5j", "b6j", ""
98 static char const * const string_orientation[] = {
99 "portrait", "landscape", ""
103 static char const * const tex_graphics[] = {
104 "default", "dvialw", "dvilaser", "dvipdf", "dvipdfm", "dvipdfmx",
105 "dvips", "dvipsone", "dvitops", "dviwin", "dviwindo", "dvi2ps", "emtex",
106 "ln", "oztex", "pctexhp", "pctexps", "pctexwin", "pctex32", "pdftex",
107 "psprint", "pubps", "tcidvi", "textures", "truetex", "vtex", "xdvi",
117 // Paragraph separation
118 typedef Translator<string, BufferParams::ParagraphSeparation> ParSepTranslator;
121 ParSepTranslator const init_parseptranslator()
123 ParSepTranslator translator
124 (string_paragraph_separation[0], BufferParams::ParagraphIndentSeparation);
125 translator.addPair(string_paragraph_separation[1], BufferParams::ParagraphSkipSeparation);
130 ParSepTranslator const & parseptranslator()
132 static ParSepTranslator const translator =
133 init_parseptranslator();
139 typedef Translator<string, QuoteStyle> QuotesStyleTranslator;
142 QuotesStyleTranslator const init_quotesstyletranslator()
144 QuotesStyleTranslator translator
145 (string_quotes_style[0], QuoteStyle::EnglishQuotes);
146 translator.addPair(string_quotes_style[1], QuoteStyle::SwedishQuotes);
147 translator.addPair(string_quotes_style[2], QuoteStyle::GermanQuotes);
148 translator.addPair(string_quotes_style[3], QuoteStyle::PolishQuotes);
149 translator.addPair(string_quotes_style[4], QuoteStyle::SwissQuotes);
150 translator.addPair(string_quotes_style[5], QuoteStyle::DanishQuotes);
151 translator.addPair(string_quotes_style[6], QuoteStyle::PlainQuotes);
152 translator.addPair(string_quotes_style[7], QuoteStyle::BritishQuotes);
153 translator.addPair(string_quotes_style[8], QuoteStyle::SwedishGQuotes);
154 translator.addPair(string_quotes_style[9], QuoteStyle::FrenchQuotes);
155 translator.addPair(string_quotes_style[10], QuoteStyle::FrenchINQuotes);
156 translator.addPair(string_quotes_style[11], QuoteStyle::RussianQuotes);
157 translator.addPair(string_quotes_style[12], QuoteStyle::CJKQuotes);
158 translator.addPair(string_quotes_style[13], QuoteStyle::CJKAngleQuotes);
163 QuotesStyleTranslator const & quotesstyletranslator()
165 static QuotesStyleTranslator const translator =
166 init_quotesstyletranslator();
172 typedef Translator<string, PAPER_SIZE> PaperSizeTranslator;
175 static PaperSizeTranslator initPaperSizeTranslator()
177 PaperSizeTranslator translator(string_papersize[0], PAPER_DEFAULT);
178 translator.addPair(string_papersize[1], PAPER_CUSTOM);
179 translator.addPair(string_papersize[2], PAPER_USLETTER);
180 translator.addPair(string_papersize[3], PAPER_USLEGAL);
181 translator.addPair(string_papersize[4], PAPER_USEXECUTIVE);
182 translator.addPair(string_papersize[5], PAPER_A0);
183 translator.addPair(string_papersize[6], PAPER_A1);
184 translator.addPair(string_papersize[7], PAPER_A2);
185 translator.addPair(string_papersize[8], PAPER_A3);
186 translator.addPair(string_papersize[9], PAPER_A4);
187 translator.addPair(string_papersize[10], PAPER_A5);
188 translator.addPair(string_papersize[11], PAPER_A6);
189 translator.addPair(string_papersize[12], PAPER_B0);
190 translator.addPair(string_papersize[13], PAPER_B1);
191 translator.addPair(string_papersize[14], PAPER_B2);
192 translator.addPair(string_papersize[15], PAPER_B3);
193 translator.addPair(string_papersize[16], PAPER_B4);
194 translator.addPair(string_papersize[17], PAPER_B5);
195 translator.addPair(string_papersize[18], PAPER_B6);
196 translator.addPair(string_papersize[19], PAPER_C0);
197 translator.addPair(string_papersize[20], PAPER_C1);
198 translator.addPair(string_papersize[21], PAPER_C2);
199 translator.addPair(string_papersize[22], PAPER_C3);
200 translator.addPair(string_papersize[23], PAPER_C4);
201 translator.addPair(string_papersize[24], PAPER_C5);
202 translator.addPair(string_papersize[25], PAPER_C6);
203 translator.addPair(string_papersize[26], PAPER_JISB0);
204 translator.addPair(string_papersize[27], PAPER_JISB1);
205 translator.addPair(string_papersize[28], PAPER_JISB2);
206 translator.addPair(string_papersize[29], PAPER_JISB3);
207 translator.addPair(string_papersize[30], PAPER_JISB4);
208 translator.addPair(string_papersize[31], PAPER_JISB5);
209 translator.addPair(string_papersize[32], PAPER_JISB6);
214 PaperSizeTranslator const & papersizetranslator()
216 static PaperSizeTranslator const translator =
217 initPaperSizeTranslator();
223 typedef Translator<string, PAPER_ORIENTATION> PaperOrientationTranslator;
226 PaperOrientationTranslator const init_paperorientationtranslator()
228 PaperOrientationTranslator translator(string_orientation[0], ORIENTATION_PORTRAIT);
229 translator.addPair(string_orientation[1], ORIENTATION_LANDSCAPE);
234 PaperOrientationTranslator const & paperorientationtranslator()
236 static PaperOrientationTranslator const translator =
237 init_paperorientationtranslator();
243 typedef Translator<int, PageSides> SidesTranslator;
246 SidesTranslator const init_sidestranslator()
248 SidesTranslator translator(1, OneSide);
249 translator.addPair(2, TwoSides);
254 SidesTranslator const & sidestranslator()
256 static SidesTranslator const translator = init_sidestranslator();
262 typedef Translator<int, BufferParams::Package> PackageTranslator;
265 PackageTranslator const init_packagetranslator()
267 PackageTranslator translator(0, BufferParams::package_off);
268 translator.addPair(1, BufferParams::package_auto);
269 translator.addPair(2, BufferParams::package_on);
274 PackageTranslator const & packagetranslator()
276 static PackageTranslator const translator =
277 init_packagetranslator();
283 typedef Translator<string, Spacing::Space> SpaceTranslator;
286 SpaceTranslator const init_spacetranslator()
288 SpaceTranslator translator("default", Spacing::Default);
289 translator.addPair("single", Spacing::Single);
290 translator.addPair("onehalf", Spacing::Onehalf);
291 translator.addPair("double", Spacing::Double);
292 translator.addPair("other", Spacing::Other);
297 SpaceTranslator const & spacetranslator()
299 static SpaceTranslator const translator = init_spacetranslator();
304 bool inSystemDir(FileName const & document_dir, string & system_dir)
306 // A document is assumed to be in a system LyX directory (not
307 // necessarily the system directory of the running instance)
308 // if both "configure.py" and "chkconfig.ltx" are found in
309 // either document_dir/../ or document_dir/../../.
310 // If true, the system directory path is returned in system_dir
311 // with a trailing path separator.
313 string const msg = "Checking whether document is in a system dir...";
315 string dir = document_dir.absFileName();
317 for (int i = 0; i < 3; ++i) {
318 dir = addPath(dir, "..");
319 if (!fileSearch(dir, "configure.py").empty() &&
320 !fileSearch(dir, "chkconfig.ltx").empty()) {
321 LYXERR(Debug::FILES, msg << " yes");
322 system_dir = addPath(FileName(dir).realPath(), "");
327 LYXERR(Debug::FILES, msg << " no");
328 system_dir = string();
335 class BufferParams::Impl
340 AuthorList authorlist;
341 BranchList branchlist;
342 Bullet temp_bullets[4];
343 Bullet user_defined_bullets[4];
344 IndicesList indiceslist;
348 /** This is the amount of space used for paragraph_separation "skip",
349 * and for detached paragraphs in "indented" documents.
352 PDFOptions pdfoptions;
353 LayoutFileIndex baseClass_;
354 FormatList exportableFormatList;
355 FormatList viewableFormatList;
356 bool isViewCacheValid;
357 bool isExportCacheValid;
361 BufferParams::Impl::Impl()
362 : defskip(VSpace::MEDSKIP), baseClass_(string("")),
363 isViewCacheValid(false), isExportCacheValid(false)
365 // set initial author
367 authorlist.record(Author(from_utf8(lyxrc.user_name),
368 from_utf8(lyxrc.user_email),
369 from_utf8(lyxrc.user_initials)));
374 BufferParams::MemoryTraits::clone(BufferParams::Impl const * ptr)
377 return new BufferParams::Impl(*ptr);
381 void BufferParams::MemoryTraits::destroy(BufferParams::Impl * ptr)
387 BufferParams::BufferParams()
390 setBaseClass(defaultBaseclass());
391 cite_engine_ = "basic";
392 cite_engine_type_ = ENGINE_TYPE_DEFAULT;
394 paragraph_separation = ParagraphIndentSeparation;
395 is_math_indent = false;
396 math_numbering_side = DEFAULT;
397 quotes_style = QuoteStyle::EnglishQuotes;
398 dynamic_quotes = false;
399 fontsize = "default";
402 papersize = PAPER_DEFAULT;
403 orientation = ORIENTATION_PORTRAIT;
404 use_geometry = false;
405 biblio_style = string();
406 use_bibtopic = false;
409 save_transient_properties = true;
410 track_changes = false;
411 output_changes = false;
413 postpone_fragile_content = true;
414 use_default_options = true;
415 maintain_unincluded_children = CM_None;
418 language = default_language;
420 fonts_roman[0] = "default";
421 fonts_roman[1] = "default";
422 fonts_sans[0] = "default";
423 fonts_sans[1] = "default";
424 fonts_typewriter[0] = "default";
425 fonts_typewriter[1] = "default";
426 fonts_math[0] = "auto";
427 fonts_math[1] = "auto";
428 fonts_default_family = "default";
429 useNonTeXFonts = false;
430 use_microtype = false;
431 use_dash_ligatures = true;
432 fonts_expert_sc = false;
433 fonts_roman_osf = false;
434 fonts_sans_osf = false;
435 fonts_typewriter_osf = false;
436 fonts_sans_scale[0] = 100;
437 fonts_sans_scale[1] = 100;
438 fonts_typewriter_scale[0] = 100;
439 fonts_typewriter_scale[1] = 100;
441 lang_package = "default";
442 graphics_driver = "default";
443 default_output_format = "default";
444 bibtex_command = "default";
445 index_command = "default";
448 listings_params = string();
449 pagestyle = "default";
450 tablestyle = "default";
451 float_alignment = "class";
452 float_placement = "class";
453 suppress_date = false;
454 justification = true;
455 // no color is the default (white)
456 backgroundcolor = lyx::rgbFromHexName("#ffffff");
457 isbackgroundcolor = false;
458 // no color is the default (black)
459 fontcolor = lyx::rgbFromHexName("#000000");
461 // light gray is the default font color for greyed-out notes
462 notefontcolor = lyx::rgbFromHexName("#cccccc");
463 boxbgcolor = lyx::rgbFromHexName("#ff0000");
464 compressed = lyxrc.save_compressed;
465 for (int iter = 0; iter < 4; ++iter) {
466 user_defined_bullet(iter) = ITEMIZE_DEFAULTS[iter];
467 temp_bullet(iter) = ITEMIZE_DEFAULTS[iter];
470 indiceslist().addDefault(B_("Index"));
471 html_be_strict = false;
472 html_math_output = MathML;
473 html_math_img_scale = 1.0;
474 html_css_as_file = false;
475 docbook_table_output = HTMLTable;
476 display_pixel_ratio = 1.0;
478 shell_escape = false;
484 // map current author
485 author_map_[pimpl_->authorlist.get(0).bufferId()] = 0;
489 docstring BufferParams::B_(string const & l10n) const
491 LASSERT(language, return from_utf8(l10n));
492 return getMessages(language->code()).get(l10n);
496 BufferParams::Package BufferParams::use_package(std::string const & p) const
498 PackageMap::const_iterator it = use_packages.find(p);
499 if (it == use_packages.end())
505 void BufferParams::use_package(std::string const & p, BufferParams::Package u)
511 map<string, string> const & BufferParams::auto_packages()
513 static map<string, string> packages;
514 if (packages.empty()) {
515 // We could have a race condition here that two threads
516 // discover an empty map at the same time and want to fill
517 // it, but that is no problem, since the same contents is
518 // filled in twice then. Having the locker inside the
519 // packages.empty() condition has the advantage that we
520 // don't need the mutex overhead for simple reading.
522 Mutex::Locker locker(&mutex);
523 // adding a package here implies a file format change!
524 packages["amsmath"] =
525 N_("The LaTeX package amsmath is only used if AMS formula types or symbols from the AMS math toolbars are inserted into formulas");
526 packages["amssymb"] =
527 N_("The LaTeX package amssymb is only used if symbols from the AMS math toolbars are inserted into formulas");
529 N_("The LaTeX package cancel is only used if \\cancel commands are used in formulas");
531 N_("The LaTeX package esint is only used if special integral symbols are inserted into formulas");
532 packages["mathdots"] =
533 N_("The LaTeX package mathdots is only used if the command \\iddots is inserted into formulas");
534 packages["mathtools"] =
535 N_("The LaTeX package mathtools is only used if some mathematical relations are inserted into formulas");
537 N_("The LaTeX package mhchem is only used if either the command \\ce or \\cf is inserted into formulas");
538 packages["stackrel"] =
539 N_("The LaTeX package stackrel is only used if the command \\stackrel with subscript is inserted into formulas");
540 packages["stmaryrd"] =
541 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");
542 packages["undertilde"] =
543 N_("The LaTeX package undertilde is only used if you use the math frame decoration 'utilde'");
549 bool BufferParams::useBibtopic() const
553 return (use_bibtopic || (!multibib.empty() && multibib != "child"));
557 AuthorList & BufferParams::authors()
559 return pimpl_->authorlist;
563 AuthorList const & BufferParams::authors() const
565 return pimpl_->authorlist;
569 void BufferParams::addAuthor(Author const & a)
571 author_map_[a.bufferId()] = pimpl_->authorlist.record(a);
575 BranchList & BufferParams::branchlist()
577 return pimpl_->branchlist;
581 BranchList const & BufferParams::branchlist() const
583 return pimpl_->branchlist;
587 IndicesList & BufferParams::indiceslist()
589 return pimpl_->indiceslist;
593 IndicesList const & BufferParams::indiceslist() const
595 return pimpl_->indiceslist;
599 Bullet & BufferParams::temp_bullet(lyx::size_type const index)
601 LASSERT(index < 4, return pimpl_->temp_bullets[0]);
602 return pimpl_->temp_bullets[index];
606 Bullet const & BufferParams::temp_bullet(lyx::size_type const index) const
608 LASSERT(index < 4, return pimpl_->temp_bullets[0]);
609 return pimpl_->temp_bullets[index];
613 Bullet & BufferParams::user_defined_bullet(lyx::size_type const index)
615 LASSERT(index < 4, return pimpl_->temp_bullets[0]);
616 return pimpl_->user_defined_bullets[index];
620 Bullet const & BufferParams::user_defined_bullet(lyx::size_type const index) const
622 LASSERT(index < 4, return pimpl_->temp_bullets[0]);
623 return pimpl_->user_defined_bullets[index];
627 Spacing & BufferParams::spacing()
629 return pimpl_->spacing;
633 Spacing const & BufferParams::spacing() const
635 return pimpl_->spacing;
639 PDFOptions & BufferParams::pdfoptions()
641 return pimpl_->pdfoptions;
645 PDFOptions const & BufferParams::pdfoptions() const
647 return pimpl_->pdfoptions;
651 Length const & BufferParams::getMathIndent() const
653 return pimpl_->mathindent;
657 void BufferParams::setMathIndent(Length const & indent)
659 pimpl_->mathindent = indent;
663 Length const & BufferParams::getParIndent() const
665 return pimpl_->parindent;
669 void BufferParams::setParIndent(Length const & indent)
671 pimpl_->parindent = indent;
675 VSpace const & BufferParams::getDefSkip() const
677 return pimpl_->defskip;
681 void BufferParams::setDefSkip(VSpace const & vs)
683 // DEFSKIP will cause an infinite loop
684 LASSERT(vs.kind() != VSpace::DEFSKIP, return);
685 pimpl_->defskip = vs;
689 BufferParams::MathNumber BufferParams::getMathNumber() const
691 if (math_numbering_side != DEFAULT)
692 return math_numbering_side;
693 // FIXME: do not hardcode language here
694 else if (language->lang() == "arabic_arabi"
695 || documentClass().provides("leqno"))
702 string BufferParams::readToken(Lexer & lex, string const & token,
703 FileName const & filepath)
707 if (token == "\\textclass") {
709 string const classname = lex.getString();
710 // if there exists a local layout file, ignore the system one
711 // NOTE: in this case, the textclass (.cls file) is assumed to
714 LayoutFileList & bcl = LayoutFileList::get();
715 if (!filepath.empty()) {
716 // If classname is an absolute path, the document is
717 // using a local layout file which could not be accessed
718 // by a relative path. In this case the path is correct
719 // even if the document was moved to a different
720 // location. However, we will have a problem if the
721 // document was generated on a different platform.
722 bool isabsolute = FileName::isAbsolute(classname);
723 string const classpath = onlyPath(classname);
724 string const path = isabsolute ? classpath
725 : FileName(addPath(filepath.absFileName(),
726 classpath)).realPath();
727 string const oldpath = isabsolute ? string()
728 : FileName(addPath(origin, classpath)).realPath();
729 tcp = bcl.addLocalLayout(onlyFileName(classname), path, oldpath);
731 // that returns non-empty if a "local" layout file is found.
733 result = to_utf8(makeRelPath(from_utf8(onlyPath(tcp)),
734 from_utf8(filepath.absFileName())));
737 setBaseClass(onlyFileName(tcp));
739 setBaseClass(onlyFileName(classname));
740 // We assume that a tex class exists for local or unknown
741 // layouts so this warning, will only be given for system layouts.
742 if (!baseClass()->isTeXClassAvailable()) {
743 docstring const desc =
744 translateIfPossible(from_utf8(baseClass()->description()));
745 docstring const prereqs =
746 from_utf8(baseClass()->prerequisites());
747 docstring const msg =
748 bformat(_("The selected document class\n"
750 "requires external files that are not available.\n"
751 "The document class can still be used, but the\n"
752 "document cannot be compiled until the following\n"
753 "prerequisites are installed:\n"
755 "See section 3.1.2.2 (Class Availability) of the\n"
756 "User's Guide for more information."), desc, prereqs);
757 frontend::Alert::warning(_("Document class not available"),
760 } else if (token == "\\save_transient_properties") {
761 lex >> save_transient_properties;
762 } else if (token == "\\origin") {
764 origin = lex.getString();
765 string const sysdirprefix = "/systemlyxdir/";
766 if (prefixIs(origin, sysdirprefix)) {
768 if (inSystemDir(filepath, docsys))
769 origin.replace(0, sysdirprefix.length() - 1, docsys);
771 origin.replace(0, sysdirprefix.length() - 1,
772 package().system_support().absFileName());
774 } else if (token == "\\begin_preamble") {
776 } else if (token == "\\begin_local_layout") {
777 readLocalLayout(lex, false);
778 } else if (token == "\\begin_forced_local_layout") {
779 readLocalLayout(lex, true);
780 } else if (token == "\\begin_modules") {
782 } else if (token == "\\begin_removed_modules") {
783 readRemovedModules(lex);
784 } else if (token == "\\begin_includeonly") {
785 readIncludeonly(lex);
786 } else if (token == "\\maintain_unincluded_children") {
790 maintain_unincluded_children = CM_None;
791 else if (tmp == "mostly")
792 maintain_unincluded_children = CM_Mostly;
793 else if (tmp == "strict")
794 maintain_unincluded_children = CM_Strict;
795 } else if (token == "\\options") {
797 options = lex.getString();
798 } else if (token == "\\use_default_options") {
799 lex >> use_default_options;
800 } else if (token == "\\master") {
802 master = lex.getString();
803 if (!filepath.empty() && FileName::isAbsolute(origin)) {
804 bool const isabs = FileName::isAbsolute(master);
805 FileName const abspath(isabs ? master : origin + master);
806 bool const moved = filepath != FileName(origin);
807 if (moved && abspath.exists()) {
808 docstring const path = isabs
810 : from_utf8(abspath.realPath());
811 docstring const refpath =
812 from_utf8(filepath.absFileName());
813 master = to_utf8(makeRelPath(path, refpath));
816 } else if (token == "\\suppress_date") {
817 lex >> suppress_date;
818 } else if (token == "\\justification") {
819 lex >> justification;
820 } else if (token == "\\language") {
822 } else if (token == "\\language_package") {
824 lang_package = lex.getString();
825 } else if (token == "\\inputencoding") {
827 } else if (token == "\\graphics") {
828 readGraphicsDriver(lex);
829 } else if (token == "\\default_output_format") {
830 lex >> default_output_format;
831 } else if (token == "\\bibtex_command") {
833 bibtex_command = lex.getString();
834 } else if (token == "\\index_command") {
836 index_command = lex.getString();
837 } else if (token == "\\fontencoding") {
839 fontenc = lex.getString();
840 } else if (token == "\\font_roman") {
841 lex >> fonts_roman[0];
842 lex >> fonts_roman[1];
843 } else if (token == "\\font_sans") {
844 lex >> fonts_sans[0];
845 lex >> fonts_sans[1];
846 } else if (token == "\\font_typewriter") {
847 lex >> fonts_typewriter[0];
848 lex >> fonts_typewriter[1];
849 } else if (token == "\\font_math") {
850 lex >> fonts_math[0];
851 lex >> fonts_math[1];
852 } else if (token == "\\font_default_family") {
853 lex >> fonts_default_family;
854 } else if (token == "\\use_non_tex_fonts") {
855 lex >> useNonTeXFonts;
856 } else if (token == "\\font_sc") {
857 lex >> fonts_expert_sc;
858 } else if (token == "\\font_roman_osf") {
859 lex >> fonts_roman_osf;
860 } else if (token == "\\font_sans_osf") {
861 lex >> fonts_sans_osf;
862 } else if (token == "\\font_typewriter_osf") {
863 lex >> fonts_typewriter_osf;
864 } else if (token == "\\font_roman_opts") {
865 lex >> font_roman_opts;
866 } else if (token == "\\font_sf_scale") {
867 lex >> fonts_sans_scale[0];
868 lex >> fonts_sans_scale[1];
869 } else if (token == "\\font_sans_opts") {
870 lex >> font_sans_opts;
871 } else if (token == "\\font_tt_scale") {
872 lex >> fonts_typewriter_scale[0];
873 lex >> fonts_typewriter_scale[1];
874 } else if (token == "\\font_typewriter_opts") {
875 lex >> font_typewriter_opts;
876 } else if (token == "\\font_cjk") {
878 } else if (token == "\\use_microtype") {
879 lex >> use_microtype;
880 } else if (token == "\\use_dash_ligatures") {
881 lex >> use_dash_ligatures;
882 } else if (token == "\\paragraph_separation") {
885 paragraph_separation = parseptranslator().find(parsep);
886 } else if (token == "\\paragraph_indentation") {
888 string parindent = lex.getString();
889 if (parindent == "default")
890 pimpl_->parindent = Length();
892 pimpl_->parindent = Length(parindent);
893 } else if (token == "\\defskip") {
895 string const defskip = lex.getString();
896 pimpl_->defskip = VSpace(defskip);
897 if (pimpl_->defskip.kind() == VSpace::DEFSKIP)
899 pimpl_->defskip = VSpace(VSpace::MEDSKIP);
900 } else if (token == "\\is_math_indent") {
901 lex >> is_math_indent;
902 } else if (token == "\\math_indentation") {
904 string mathindent = lex.getString();
905 if (mathindent == "default")
906 pimpl_->mathindent = Length();
908 pimpl_->mathindent = Length(mathindent);
909 } else if (token == "\\math_numbering_side") {
913 math_numbering_side = LEFT;
914 else if (tmp == "right")
915 math_numbering_side = RIGHT;
917 math_numbering_side = DEFAULT;
918 } else if (token == "\\quotes_style") {
921 quotes_style = quotesstyletranslator().find(qstyle);
922 } else if (token == "\\dynamic_quotes") {
923 lex >> dynamic_quotes;
924 } else if (token == "\\papersize") {
927 papersize = papersizetranslator().find(ppsize);
928 } else if (token == "\\use_geometry") {
930 } else if (token == "\\use_package") {
935 use_package(package, packagetranslator().find(use));
936 } else if (token == "\\cite_engine") {
938 cite_engine_ = lex.getString();
939 } else if (token == "\\cite_engine_type") {
942 cite_engine_type_ = theCiteEnginesList.getType(engine_type);
943 } else if (token == "\\biblio_style") {
945 biblio_style = lex.getString();
946 } else if (token == "\\biblio_options") {
948 biblio_opts = trim(lex.getString());
949 } else if (token == "\\biblatex_bibstyle") {
951 biblatex_bibstyle = trim(lex.getString());
952 } else if (token == "\\biblatex_citestyle") {
954 biblatex_citestyle = trim(lex.getString());
955 } else if (token == "\\use_bibtopic") {
957 } else if (token == "\\multibib") {
959 } else if (token == "\\use_indices") {
961 } else if (token == "\\tracking_changes") {
962 lex >> track_changes;
963 } else if (token == "\\output_changes") {
964 lex >> output_changes;
965 } else if (token == "\\change_bars") {
967 } else if (token == "\\postpone_fragile_content") {
968 lex >> postpone_fragile_content;
969 } else if (token == "\\branch") {
971 docstring branch = lex.getDocString();
972 branchlist().add(branch);
975 string const tok = lex.getString();
976 if (tok == "\\end_branch")
978 Branch * branch_ptr = branchlist().find(branch);
979 if (tok == "\\selected") {
982 branch_ptr->setSelected(lex.getInteger());
984 if (tok == "\\filename_suffix") {
987 branch_ptr->setFileNameSuffix(lex.getInteger());
989 if (tok == "\\color") {
991 string color = lex.getString();
993 branch_ptr->setColor(color);
994 // Update also the Color table:
996 color = lcolor.getX11HexName(Color_background);
998 lcolor.setColor(to_utf8(branch), color);
1001 } else if (token == "\\index") {
1003 docstring index = lex.getDocString();
1005 indiceslist().add(index);
1008 string const tok = lex.getString();
1009 if (tok == "\\end_index")
1011 Index * index_ptr = indiceslist().find(index);
1012 if (tok == "\\shortcut") {
1014 shortcut = lex.getDocString();
1016 index_ptr->setShortcut(shortcut);
1018 if (tok == "\\color") {
1020 string color = lex.getString();
1022 index_ptr->setColor(color);
1023 // Update also the Color table:
1024 if (color == "none")
1025 color = lcolor.getX11HexName(Color_background);
1027 if (!shortcut.empty())
1028 lcolor.setColor(to_utf8(shortcut), color);
1031 } else if (token == "\\author") {
1033 istringstream ss(lex.getString());
1037 } else if (token == "\\paperorientation") {
1040 orientation = paperorientationtranslator().find(orient);
1041 } else if (token == "\\backgroundcolor") {
1043 backgroundcolor = lyx::rgbFromHexName(lex.getString());
1044 isbackgroundcolor = true;
1045 } else if (token == "\\fontcolor") {
1047 fontcolor = lyx::rgbFromHexName(lex.getString());
1049 } else if (token == "\\notefontcolor") {
1051 string color = lex.getString();
1052 notefontcolor = lyx::rgbFromHexName(color);
1053 lcolor.setColor("notefontcolor", color);
1054 } else if (token == "\\boxbgcolor") {
1056 string color = lex.getString();
1057 boxbgcolor = lyx::rgbFromHexName(color);
1058 lcolor.setColor("boxbgcolor", color);
1059 } else if (token == "\\paperwidth") {
1061 } else if (token == "\\paperheight") {
1063 } else if (token == "\\leftmargin") {
1065 } else if (token == "\\topmargin") {
1067 } else if (token == "\\rightmargin") {
1069 } else if (token == "\\bottommargin") {
1070 lex >> bottommargin;
1071 } else if (token == "\\headheight") {
1073 } else if (token == "\\headsep") {
1075 } else if (token == "\\footskip") {
1077 } else if (token == "\\columnsep") {
1079 } else if (token == "\\paperfontsize") {
1081 } else if (token == "\\papercolumns") {
1083 } else if (token == "\\listings_params") {
1086 listings_params = InsetListingsParams(par).params();
1087 } else if (token == "\\papersides") {
1090 sides = sidestranslator().find(psides);
1091 } else if (token == "\\paperpagestyle") {
1093 } else if (token == "\\tablestyle") {
1095 } else if (token == "\\bullet") {
1097 } else if (token == "\\bulletLaTeX") {
1098 readBulletsLaTeX(lex);
1099 } else if (token == "\\secnumdepth") {
1101 } else if (token == "\\tocdepth") {
1103 } else if (token == "\\spacing") {
1107 if (nspacing == "other") {
1110 spacing().set(spacetranslator().find(nspacing), tmp_val);
1111 } else if (token == "\\float_placement") {
1112 lex >> float_placement;
1113 } else if (token == "\\float_alignment") {
1114 lex >> float_alignment;
1116 } else if (prefixIs(token, "\\pdf_") || token == "\\use_hyperref") {
1117 string toktmp = pdfoptions().readToken(lex, token);
1118 if (!toktmp.empty()) {
1119 lyxerr << "PDFOptions::readToken(): Unknown token: " <<
1123 } else if (token == "\\html_math_output") {
1126 html_math_output = static_cast<MathOutput>(temp);
1127 } else if (token == "\\html_be_strict") {
1128 lex >> html_be_strict;
1129 } else if (token == "\\html_css_as_file") {
1130 lex >> html_css_as_file;
1131 } else if (token == "\\html_math_img_scale") {
1132 lex >> html_math_img_scale;
1133 } else if (token == "\\html_latex_start") {
1135 html_latex_start = lex.getString();
1136 } else if (token == "\\html_latex_end") {
1138 html_latex_end = lex.getString();
1139 } else if (token == "\\docbook_table_output") {
1142 docbook_table_output = static_cast<TableOutput>(temp);
1143 } else if (token == "\\output_sync") {
1145 } else if (token == "\\output_sync_macro") {
1146 lex >> output_sync_macro;
1147 } else if (token == "\\use_refstyle") {
1148 lex >> use_refstyle;
1149 } else if (token == "\\use_minted") {
1151 } else if (token == "\\use_lineno") {
1153 } else if (token == "\\lineno_options") {
1155 lineno_opts = trim(lex.getString());
1157 lyxerr << "BufferParams::readToken(): Unknown token: " <<
1167 // Quote argument if it contains spaces
1168 string quoteIfNeeded(string const & str) {
1169 if (contains(str, ' '))
1170 return "\"" + str + "\"";
1176 void BufferParams::writeFile(ostream & os, Buffer const * buf) const
1178 // The top of the file is written by the buffer.
1179 // Prints out the buffer info into the .lyx file given by file
1181 os << "\\save_transient_properties "
1182 << convert<string>(save_transient_properties) << '\n';
1184 // the document directory (must end with a path separator)
1185 // realPath() is used to resolve symlinks, while addPath(..., "")
1186 // ensures a trailing path separator.
1188 string filepath = addPath(buf->fileName().onlyPath().realPath(), "");
1189 string const sysdir = inSystemDir(FileName(filepath), docsys) ? docsys
1190 : addPath(package().system_support().realPath(), "");
1191 string const relpath =
1192 to_utf8(makeRelPath(from_utf8(filepath), from_utf8(sysdir)));
1193 if (!prefixIs(relpath, "../") && !FileName::isAbsolute(relpath))
1194 filepath = addPath("/systemlyxdir", relpath);
1195 else if (!save_transient_properties || !lyxrc.save_origin)
1196 filepath = "unavailable";
1197 os << "\\origin " << quoteIfNeeded(filepath) << '\n';
1200 os << "\\textclass "
1201 << quoteIfNeeded(buf->includedFilePath(addName(buf->layoutPos(),
1202 baseClass()->name()), "layout"))
1205 // then the preamble
1206 if (!preamble.empty()) {
1207 // remove '\n' from the end of preamble
1208 docstring const tmppreamble = rtrim(preamble, "\n");
1209 os << "\\begin_preamble\n"
1210 << to_utf8(tmppreamble)
1211 << "\n\\end_preamble\n";
1215 if (!options.empty()) {
1216 os << "\\options " << options << '\n';
1219 // use the class options defined in the layout?
1220 os << "\\use_default_options "
1221 << convert<string>(use_default_options) << "\n";
1223 // the master document
1224 if (!master.empty()) {
1225 os << "\\master " << master << '\n';
1229 if (!removed_modules_.empty()) {
1230 os << "\\begin_removed_modules" << '\n';
1231 for (auto const & mod : removed_modules_)
1233 os << "\\end_removed_modules" << '\n';
1237 if (!layout_modules_.empty()) {
1238 os << "\\begin_modules" << '\n';
1239 for (auto const & mod : layout_modules_)
1241 os << "\\end_modules" << '\n';
1245 if (!included_children_.empty()) {
1246 os << "\\begin_includeonly" << '\n';
1247 for (auto const & c : included_children_)
1249 os << "\\end_includeonly" << '\n';
1252 switch (maintain_unincluded_children) {
1263 os << "\\maintain_unincluded_children " << muc << '\n';
1265 // local layout information
1266 docstring const local_layout = getLocalLayout(false);
1267 if (!local_layout.empty()) {
1268 // remove '\n' from the end
1269 docstring const tmplocal = rtrim(local_layout, "\n");
1270 os << "\\begin_local_layout\n"
1271 << to_utf8(tmplocal)
1272 << "\n\\end_local_layout\n";
1274 docstring const forced_local_layout = getLocalLayout(true);
1275 if (!forced_local_layout.empty()) {
1276 // remove '\n' from the end
1277 docstring const tmplocal = rtrim(forced_local_layout, "\n");
1278 os << "\\begin_forced_local_layout\n"
1279 << to_utf8(tmplocal)
1280 << "\n\\end_forced_local_layout\n";
1283 // then the text parameters
1284 if (language != ignore_language)
1285 os << "\\language " << language->lang() << '\n';
1286 os << "\\language_package " << lang_package
1287 << "\n\\inputencoding " << inputenc
1288 << "\n\\fontencoding " << fontenc
1289 << "\n\\font_roman \"" << fonts_roman[0]
1290 << "\" \"" << fonts_roman[1] << '"'
1291 << "\n\\font_sans \"" << fonts_sans[0]
1292 << "\" \"" << fonts_sans[1] << '"'
1293 << "\n\\font_typewriter \"" << fonts_typewriter[0]
1294 << "\" \"" << fonts_typewriter[1] << '"'
1295 << "\n\\font_math \"" << fonts_math[0]
1296 << "\" \"" << fonts_math[1] << '"'
1297 << "\n\\font_default_family " << fonts_default_family
1298 << "\n\\use_non_tex_fonts " << convert<string>(useNonTeXFonts)
1299 << "\n\\font_sc " << convert<string>(fonts_expert_sc)
1300 << "\n\\font_roman_osf " << convert<string>(fonts_roman_osf)
1301 << "\n\\font_sans_osf " << convert<string>(fonts_sans_osf)
1302 << "\n\\font_typewriter_osf " << convert<string>(fonts_typewriter_osf);
1303 if (!font_roman_opts.empty())
1304 os << "\n\\font_roman_opts \"" << font_roman_opts << "\"";
1305 os << "\n\\font_sf_scale " << fonts_sans_scale[0]
1306 << ' ' << fonts_sans_scale[1];
1307 if (!font_sans_opts.empty())
1308 os << "\n\\font_sans_opts \"" << font_sans_opts << "\"";
1309 os << "\n\\font_tt_scale " << fonts_typewriter_scale[0]
1310 << ' ' << fonts_typewriter_scale[1];
1311 if (!font_typewriter_opts.empty())
1312 os << "\n\\font_typewriter_opts \"" << font_typewriter_opts << "\"";
1314 if (!fonts_cjk.empty())
1315 os << "\\font_cjk " << fonts_cjk << '\n';
1316 os << "\\use_microtype " << convert<string>(use_microtype) << '\n';
1317 os << "\\use_dash_ligatures " << convert<string>(use_dash_ligatures) << '\n';
1318 os << "\\graphics " << graphics_driver << '\n';
1319 os << "\\default_output_format " << default_output_format << '\n';
1320 os << "\\output_sync " << output_sync << '\n';
1321 if (!output_sync_macro.empty())
1322 os << "\\output_sync_macro \"" << output_sync_macro << "\"\n";
1323 os << "\\bibtex_command " << bibtex_command << '\n';
1324 os << "\\index_command " << index_command << '\n';
1326 if (!float_placement.empty())
1327 os << "\\float_placement " << float_placement << '\n';
1328 if (!float_alignment.empty())
1329 os << "\\float_alignment " << float_alignment << '\n';
1330 os << "\\paperfontsize " << fontsize << '\n';
1332 spacing().writeFile(os);
1333 pdfoptions().writeFile(os);
1335 os << "\\papersize " << string_papersize[papersize]
1336 << "\n\\use_geometry " << convert<string>(use_geometry);
1337 map<string, string> const & packages = auto_packages();
1338 for (auto const & pack : packages)
1339 os << "\n\\use_package " << pack.first << ' '
1340 << use_package(pack.first);
1342 os << "\n\\cite_engine ";
1344 if (!cite_engine_.empty())
1349 os << "\n\\cite_engine_type " << theCiteEnginesList.getTypeAsString(cite_engine_type_);
1351 if (!biblio_style.empty())
1352 os << "\n\\biblio_style " << biblio_style;
1353 if (!biblio_opts.empty())
1354 os << "\n\\biblio_options " << biblio_opts;
1355 if (!biblatex_bibstyle.empty())
1356 os << "\n\\biblatex_bibstyle " << biblatex_bibstyle;
1357 if (!biblatex_citestyle.empty())
1358 os << "\n\\biblatex_citestyle " << biblatex_citestyle;
1359 if (!multibib.empty())
1360 os << "\n\\multibib " << multibib;
1362 os << "\n\\use_bibtopic " << convert<string>(use_bibtopic)
1363 << "\n\\use_indices " << convert<string>(use_indices)
1364 << "\n\\paperorientation " << string_orientation[orientation]
1365 << "\n\\suppress_date " << convert<string>(suppress_date)
1366 << "\n\\justification " << convert<string>(justification)
1367 << "\n\\use_refstyle " << use_refstyle
1368 << "\n\\use_minted " << use_minted
1369 << "\n\\use_lineno " << use_lineno
1372 if (!lineno_opts.empty())
1373 os << "\\lineno_options " << lineno_opts << '\n';
1375 if (isbackgroundcolor)
1376 os << "\\backgroundcolor " << lyx::X11hexname(backgroundcolor) << '\n';
1378 os << "\\fontcolor " << lyx::X11hexname(fontcolor) << '\n';
1379 if (notefontcolor != lyx::rgbFromHexName("#cccccc"))
1380 os << "\\notefontcolor " << lyx::X11hexname(notefontcolor) << '\n';
1381 if (boxbgcolor != lyx::rgbFromHexName("#ff0000"))
1382 os << "\\boxbgcolor " << lyx::X11hexname(boxbgcolor) << '\n';
1384 for (auto const & br : branchlist()) {
1385 os << "\\branch " << to_utf8(br.branch())
1386 << "\n\\selected " << br.isSelected()
1387 << "\n\\filename_suffix " << br.hasFileNameSuffix()
1388 << "\n\\color " << lyx::X11hexname(br.color())
1393 for (auto const & id : indiceslist()) {
1394 os << "\\index " << to_utf8(id.index())
1395 << "\n\\shortcut " << to_utf8(id.shortcut())
1396 << "\n\\color " << lyx::X11hexname(id.color())
1401 if (!paperwidth.empty())
1402 os << "\\paperwidth "
1403 << VSpace(paperwidth).asLyXCommand() << '\n';
1404 if (!paperheight.empty())
1405 os << "\\paperheight "
1406 << VSpace(paperheight).asLyXCommand() << '\n';
1407 if (!leftmargin.empty())
1408 os << "\\leftmargin "
1409 << VSpace(leftmargin).asLyXCommand() << '\n';
1410 if (!topmargin.empty())
1411 os << "\\topmargin "
1412 << VSpace(topmargin).asLyXCommand() << '\n';
1413 if (!rightmargin.empty())
1414 os << "\\rightmargin "
1415 << VSpace(rightmargin).asLyXCommand() << '\n';
1416 if (!bottommargin.empty())
1417 os << "\\bottommargin "
1418 << VSpace(bottommargin).asLyXCommand() << '\n';
1419 if (!headheight.empty())
1420 os << "\\headheight "
1421 << VSpace(headheight).asLyXCommand() << '\n';
1422 if (!headsep.empty())
1424 << VSpace(headsep).asLyXCommand() << '\n';
1425 if (!footskip.empty())
1427 << VSpace(footskip).asLyXCommand() << '\n';
1428 if (!columnsep.empty())
1429 os << "\\columnsep "
1430 << VSpace(columnsep).asLyXCommand() << '\n';
1431 os << "\\secnumdepth " << secnumdepth
1432 << "\n\\tocdepth " << tocdepth
1433 << "\n\\paragraph_separation "
1434 << string_paragraph_separation[paragraph_separation];
1435 if (!paragraph_separation)
1436 os << "\n\\paragraph_indentation "
1437 << (getParIndent().empty() ? "default" : getParIndent().asString());
1439 os << "\n\\defskip " << getDefSkip().asLyXCommand();
1440 os << "\n\\is_math_indent " << is_math_indent;
1442 os << "\n\\math_indentation "
1443 << (getMathIndent().empty() ? "default" : getMathIndent().asString());
1444 os << "\n\\math_numbering_side ";
1445 switch(math_numbering_side) {
1455 os << "\n\\quotes_style "
1456 << string_quotes_style[static_cast<int>(quotes_style)]
1457 << "\n\\dynamic_quotes " << dynamic_quotes
1458 << "\n\\papercolumns " << columns
1459 << "\n\\papersides " << sides
1460 << "\n\\paperpagestyle " << pagestyle
1461 << "\n\\tablestyle " << tablestyle << '\n';
1462 if (!listings_params.empty())
1463 os << "\\listings_params \"" <<
1464 InsetListingsParams(listings_params).encodedString() << "\"\n";
1465 for (int i = 0; i < 4; ++i) {
1466 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
1467 if (user_defined_bullet(i).getFont() != -1) {
1468 os << "\\bullet " << i << " "
1469 << user_defined_bullet(i).getFont() << " "
1470 << user_defined_bullet(i).getCharacter() << " "
1471 << user_defined_bullet(i).getSize() << "\n";
1475 os << "\\bulletLaTeX " << i << " \""
1476 << lyx::to_ascii(user_defined_bullet(i).getText())
1482 os << "\\tracking_changes "
1483 << (save_transient_properties ? convert<string>(track_changes) : "false")
1486 os << "\\output_changes "
1487 << (save_transient_properties ? convert<string>(output_changes) : "false")
1490 os << "\\change_bars "
1491 << (save_transient_properties ? convert<string>(change_bars) : "false")
1494 os << "\\postpone_fragile_content " << convert<string>(postpone_fragile_content) << '\n';
1496 os << "\\html_math_output " << html_math_output << '\n'
1497 << "\\html_css_as_file " << html_css_as_file << '\n'
1498 << "\\html_be_strict " << convert<string>(html_be_strict) << '\n';
1500 os << "\\docbook_table_output " << docbook_table_output << '\n';
1502 if (html_math_img_scale != 1.0)
1503 os << "\\html_math_img_scale " << convert<string>(html_math_img_scale) << '\n';
1504 if (!html_latex_start.empty())
1505 os << "\\html_latex_start " << html_latex_start << '\n';
1506 if (!html_latex_end.empty())
1507 os << "\\html_latex_end " << html_latex_end << '\n';
1509 os << pimpl_->authorlist;
1513 void BufferParams::validate(LaTeXFeatures & features) const
1515 features.require(documentClass().required());
1517 if (columns > 1 && language->rightToLeft())
1518 features.require("rtloutputdblcol");
1520 if (output_changes) {
1521 bool xcolorulem = LaTeXFeatures::isAvailable("ulem") &&
1522 LaTeXFeatures::isAvailable("xcolor");
1524 switch (features.runparams().flavor) {
1526 case FLAVOR::DVILUATEX:
1528 features.require("ct-xcolor-ulem");
1529 features.require("ulem");
1530 features.require("xcolor");
1532 features.require("ct-none");
1535 case FLAVOR::LUATEX:
1536 case FLAVOR::PDFLATEX:
1539 features.require("ct-xcolor-ulem");
1540 features.require("ulem");
1541 features.require("xcolor");
1542 // improves color handling in PDF output
1543 features.require("pdfcolmk");
1545 features.require("ct-none");
1552 features.require("changebar");
1555 // Floats with 'Here definitely' as default setting.
1556 if (float_placement.find('H') != string::npos)
1557 features.require("float");
1559 for (auto const & pm : use_packages) {
1560 if (pm.first == "amsmath") {
1561 // AMS Style is at document level
1562 if (pm.second == package_on ||
1563 features.isProvided("amsmath"))
1564 features.require(pm.first);
1565 } else if (pm.second == package_on)
1566 features.require(pm.first);
1569 // Document-level line spacing
1570 if (spacing().getSpace() != Spacing::Single && !spacing().isDefault())
1571 features.require("setspace");
1573 // the bullet shapes are buffer level not paragraph level
1574 // so they are tested here
1575 for (int i = 0; i < 4; ++i) {
1576 if (user_defined_bullet(i) == ITEMIZE_DEFAULTS[i])
1578 int const font = user_defined_bullet(i).getFont();
1580 int const c = user_defined_bullet(i).getCharacter();
1586 features.require("latexsym");
1588 } else if (font == 1) {
1589 features.require("amssymb");
1590 } else if (font >= 2 && font <= 5) {
1591 features.require("pifont");
1595 if (pdfoptions().use_hyperref) {
1596 features.require("hyperref");
1597 // due to interferences with babel and hyperref, the color package has to
1598 // be loaded after hyperref when hyperref is used with the colorlinks
1599 // option, see http://www.lyx.org/trac/ticket/5291
1600 if (pdfoptions().colorlinks)
1601 features.require("color");
1603 if (!listings_params.empty()) {
1604 // do not test validity because listings_params is
1605 // supposed to be valid
1607 InsetListingsParams(listings_params).separatedParams(true);
1608 // we can't support all packages, but we should load the color package
1609 if (par.find("\\color", 0) != string::npos)
1610 features.require("color");
1613 // some languages are only available via polyglossia
1614 if (features.hasPolyglossiaExclusiveLanguages())
1615 features.require("polyglossia");
1617 if (useNonTeXFonts && fontsMath() != "auto")
1618 features.require("unicode-math");
1621 features.require("microtype");
1623 if (!language->required().empty())
1624 features.require(language->required());
1628 bool BufferParams::writeLaTeX(otexstream & os, LaTeXFeatures & features,
1629 FileName const & filepath) const
1631 // http://www.tug.org/texmf-dist/doc/latex/base/fixltx2e.pdf
1632 // !! To use the Fix-cm package, load it before \documentclass, and use the command
1633 // \RequirePackage to do so, rather than the normal \usepackage
1634 // Do not try to load any other package before the document class, unless you
1635 // have a thorough understanding of the LATEX internals and know exactly what you
1637 if (features.mustProvide("fix-cm"))
1638 os << "\\RequirePackage{fix-cm}\n";
1639 // Likewise for fixltx2e. If other packages conflict with this policy,
1640 // treat it as a package bug (and report it!)
1641 // See http://www.latex-project.org/cgi-bin/ltxbugs2html?pr=latex/4407
1642 if (features.mustProvide("fixltx2e"))
1643 os << "\\RequirePackage{fixltx2e}\n";
1645 os << "\\documentclass";
1647 DocumentClass const & tclass = documentClass();
1649 ostringstream clsoptions; // the document class options.
1651 if (tokenPos(tclass.opt_fontsize(),
1652 '|', fontsize) >= 0) {
1653 // only write if existing in list (and not default)
1654 clsoptions << subst(tclass.fontsizeformat(), "$$s", fontsize) << ",";
1657 // paper sizes not supported by the class itself need the
1659 vector<string> classpsizes = getVectorFromString(tclass.opt_pagesize(), "|");
1660 bool class_supported_papersize = papersize == PAPER_DEFAULT
1661 || find(classpsizes.begin(), classpsizes.end(), string_papersize[papersize]) != classpsizes.end();
1663 if ((!use_geometry || features.isProvided("geometry-light"))
1664 && class_supported_papersize && papersize != PAPER_DEFAULT)
1665 clsoptions << subst(tclass.pagesizeformat(), "$$s", string_papersize[papersize]) << ",";
1668 if (sides != tclass.sides()) {
1671 clsoptions << "oneside,";
1674 clsoptions << "twoside,";
1680 if (columns != tclass.columns()) {
1682 clsoptions << "twocolumn,";
1684 clsoptions << "onecolumn,";
1688 && orientation == ORIENTATION_LANDSCAPE)
1689 clsoptions << "landscape,";
1692 clsoptions << "fleqn,";
1694 switch(math_numbering_side) {
1696 clsoptions << "leqno,";
1699 clsoptions << "reqno,";
1700 features.require("amsmath");
1706 // language should be a parameter to \documentclass
1707 if (language->babel() == "hebrew"
1708 && default_language->babel() != "hebrew")
1709 // This seems necessary
1710 features.useLanguage(default_language);
1712 ostringstream language_options;
1713 bool const use_babel = features.useBabel() && !features.isProvided("babel");
1714 bool const use_polyglossia = features.usePolyglossia();
1715 bool const global = lyxrc.language_global_options;
1716 if (features.useBabel() || (use_polyglossia && global)) {
1717 language_options << features.getBabelLanguages();
1718 if (!language->babel().empty()) {
1719 if (!language_options.str().empty())
1720 language_options << ',';
1721 language_options << language->babel();
1723 if (global && !language_options.str().empty())
1724 clsoptions << language_options.str() << ',';
1727 // the predefined options from the layout
1728 if (use_default_options && !tclass.options().empty())
1729 clsoptions << tclass.options() << ',';
1731 // the user-defined options
1732 if (!options.empty()) {
1733 clsoptions << options << ',';
1736 docstring const strOptions = from_utf8(clsoptions.str());
1737 if (!strOptions.empty()) {
1738 // Check if class options contain uncodable glyphs
1739 docstring uncodable_glyphs;
1740 docstring options_encodable;
1741 Encoding const * const enc = features.runparams().encoding;
1743 for (char_type c : strOptions) {
1744 if (!enc->encodable(c)) {
1745 docstring const glyph(1, c);
1746 LYXERR0("Uncodable character '"
1748 << "' in class options!");
1749 uncodable_glyphs += glyph;
1750 if (features.runparams().dryrun) {
1751 options_encodable += "<" + _("LyX Warning: ")
1752 + _("uncodable character") + " '";
1753 options_encodable += c;
1754 options_encodable += "'>";
1757 options_encodable += c;
1760 options_encodable = strOptions;
1762 // On BUFFER_VIEW|UPDATE, warn user if we found uncodable glyphs
1763 if (!features.runparams().dryrun && !uncodable_glyphs.empty()) {
1764 frontend::Alert::warning(
1765 _("Uncodable character in class options"),
1767 _("The class options of your document contain glyphs "
1768 "that are unknown in the current document encoding "
1769 "(namely %1$s).\nThese glyphs are omitted "
1770 " from the output, which may result in "
1771 "incomplete output."
1772 "\n\nPlease select an appropriate "
1773 "document encoding\n"
1774 "(such as utf8) or change the "
1775 "class options accordingly."),
1778 options_encodable = rtrim(options_encodable, ",");
1779 os << '[' << options_encodable << ']';
1782 os << '{' << from_ascii(tclass.latexname()) << "}\n";
1783 // end of \documentclass defs
1785 // The package options (via \PassOptionsToPackage)
1786 os << from_ascii(features.getPackageOptions());
1788 // if we use fontspec or newtxmath, we have to load the AMS packages here
1789 string const ams = features.loadAMSPackages();
1790 bool const ot1 = (main_font_encoding() == "default" || main_font_encoding() == "OT1");
1791 bool const use_newtxmath =
1792 theLaTeXFonts().getLaTeXFont(from_ascii(fontsMath())).getUsedPackage(
1793 ot1, false, false) == "newtxmath";
1794 if ((useNonTeXFonts || use_newtxmath) && !ams.empty())
1795 os << from_ascii(ams);
1797 if (useNonTeXFonts) {
1798 // Babel (as of 2017/11/03) loads fontspec itself
1799 if (!features.isProvided("fontspec")
1800 && !(features.useBabel() && features.isAvailable("babel-2017/11/03")))
1801 os << "\\usepackage{fontspec}\n";
1802 if (features.mustProvide("unicode-math")
1803 && features.isAvailable("unicode-math"))
1804 os << "\\usepackage{unicode-math}\n";
1807 // load CJK support package before font selection
1808 // (see autotests/export/latex/CJK/micro-sign_utf8-cjk-libertine.lyx)
1809 if (!useNonTeXFonts && encoding().package() != Encoding::none && inputenc != "utf8x"
1810 && (encoding().package() == Encoding::CJK || features.mustProvide("CJK"))) {
1811 if (inputenc == "utf8-cjk" || inputenc == "utf8")
1812 os << "\\usepackage{CJKutf8}\n";
1814 os << "\\usepackage[encapsulated]{CJK}\n";
1817 // font selection must be done before loading fontenc.sty
1818 // but after babel with non-TeX fonts
1819 string const fonts = loadFonts(features);
1820 if (!fonts.empty() && (!features.useBabel() || !useNonTeXFonts))
1821 os << from_utf8(fonts);
1823 if (fonts_default_family != "default")
1824 os << "\\renewcommand{\\familydefault}{\\"
1825 << from_ascii(fonts_default_family) << "}\n";
1827 // set font encoding
1828 // non-TeX fonts use font encoding TU (set by fontspec)
1829 if (!useNonTeXFonts && !features.isProvided("fontenc")
1830 && main_font_encoding() != "default") {
1831 // get main font encodings
1832 vector<string> fontencs = font_encodings();
1833 // get font encodings of secondary languages
1834 // FIXME: some languages (hebrew, ...) assume a standard font encoding as last
1835 // option (for text in other languages).
1836 features.getFontEncodings(fontencs);
1837 if (!fontencs.empty()) {
1838 os << "\\usepackage["
1839 << from_ascii(getStringFromVector(fontencs))
1844 // Load textcomp and pmboxdraw before (lua)inputenc (#11454)
1845 if (features.mustProvide("textcomp"))
1846 os << "\\usepackage{textcomp}\n";
1847 if (features.mustProvide("pmboxdraw"))
1848 os << "\\usepackage{pmboxdraw}\n";
1850 // handle inputenc etc.
1851 // (In documents containing text in Thai language,
1852 // we must load inputenc after babel, see lib/languages).
1853 if (!contains(features.getBabelPostsettings(), from_ascii("thai.ldf")))
1854 writeEncodingPreamble(os, features);
1857 if (!features.runparams().includeall && !included_children_.empty()) {
1858 os << "\\includeonly{";
1860 for (auto incfile : included_children_) {
1861 FileName inc = makeAbsPath(incfile, filepath.absFileName());
1862 string mangled = DocFileName(changeExtension(inc.absFileName(), ".tex")).
1864 if (!features.runparams().nice)
1866 // \includeonly doesn't want an extension
1867 incfile = changeExtension(incfile, string());
1868 incfile = support::latex_path(incfile);
1869 if (!incfile.empty()) {
1872 os << from_utf8(incfile);
1879 if (!features.isProvided("geometry")
1880 && (use_geometry || !class_supported_papersize)) {
1881 odocstringstream ods;
1882 if (!getGraphicsDriver("geometry").empty())
1883 ods << getGraphicsDriver("geometry");
1884 if (orientation == ORIENTATION_LANDSCAPE)
1885 ods << ",landscape";
1886 switch (papersize) {
1888 if (!paperwidth.empty())
1889 ods << ",paperwidth="
1890 << from_ascii(paperwidth);
1891 if (!paperheight.empty())
1892 ods << ",paperheight="
1893 << from_ascii(paperheight);
1895 case PAPER_USLETTER:
1897 case PAPER_USEXECUTIVE:
1926 ods << "," << from_ascii(string_papersize_geometry[papersize]);
1931 docstring g_options = trim(ods.str(), ",");
1932 os << "\\usepackage";
1933 // geometry-light means that the class works with geometry, but overwrites
1934 // the package options and paper sizes (memoir does this).
1935 // In this case, all options need to go to \geometry
1936 // and the standard paper sizes need to go to the class options.
1937 if (!g_options.empty() && !features.isProvided("geometry-light")) {
1938 os << '[' << g_options << ']';
1941 os << "{geometry}\n";
1942 if (use_geometry || features.isProvided("geometry-light")) {
1943 os << "\\geometry{verbose";
1944 if (!g_options.empty())
1945 // Output general options here with "geometry light".
1946 os << "," << g_options;
1947 // output this only if use_geometry is true
1949 if (!topmargin.empty())
1950 os << ",tmargin=" << from_ascii(Length(topmargin).asLatexString());
1951 if (!bottommargin.empty())
1952 os << ",bmargin=" << from_ascii(Length(bottommargin).asLatexString());
1953 if (!leftmargin.empty())
1954 os << ",lmargin=" << from_ascii(Length(leftmargin).asLatexString());
1955 if (!rightmargin.empty())
1956 os << ",rmargin=" << from_ascii(Length(rightmargin).asLatexString());
1957 if (!headheight.empty())
1958 os << ",headheight=" << from_ascii(Length(headheight).asLatexString());
1959 if (!headsep.empty())
1960 os << ",headsep=" << from_ascii(Length(headsep).asLatexString());
1961 if (!footskip.empty())
1962 os << ",footskip=" << from_ascii(Length(footskip).asLatexString());
1963 if (!columnsep.empty())
1964 os << ",columnsep=" << from_ascii(Length(columnsep).asLatexString());
1968 } else if (orientation == ORIENTATION_LANDSCAPE
1969 || papersize != PAPER_DEFAULT) {
1970 features.require("papersize");
1973 if (tokenPos(tclass.opt_pagestyle(), '|', pagestyle) >= 0) {
1974 if (pagestyle == "fancy")
1975 os << "\\usepackage{fancyhdr}\n";
1976 os << "\\pagestyle{" << from_ascii(pagestyle) << "}\n";
1979 // only output when the background color is not default
1980 if (isbackgroundcolor) {
1981 // only require color here, the background color will be defined
1982 // in LaTeXFeatures.cpp to avoid interferences with the LaTeX
1984 features.require("color");
1985 features.require("pagecolor");
1988 // only output when the font color is not default
1990 // only require color here, the font color will be defined
1991 // in LaTeXFeatures.cpp to avoid interferences with the LaTeX
1993 features.require("color");
1994 features.require("fontcolor");
1997 // Only if class has a ToC hierarchy
1998 if (tclass.hasTocLevels()) {
1999 if (secnumdepth != tclass.secnumdepth()) {
2000 os << "\\setcounter{secnumdepth}{"
2004 if (tocdepth != tclass.tocdepth()) {
2005 os << "\\setcounter{tocdepth}{"
2011 if (paragraph_separation) {
2012 // when skip separation
2014 switch (getDefSkip().kind()) {
2015 case VSpace::SMALLSKIP:
2016 psopt = "\\smallskipamount";
2018 case VSpace::MEDSKIP:
2019 psopt = "\\medskipamount";
2021 case VSpace::BIGSKIP:
2022 psopt = "\\bigskipamount";
2024 case VSpace::HALFLINE:
2025 // default (no option)
2027 case VSpace::FULLLINE:
2028 psopt = "\\baselineskip";
2030 case VSpace::LENGTH:
2031 psopt = getDefSkip().length().asLatexString();
2036 if (!features.isProvided("parskip")) {
2038 psopt = "[skip=" + psopt + "]";
2039 os << "\\usepackage" + psopt + "{parskip}\n";
2041 os << "\\setlength{\\parskip}{" + psopt + "}\n";
2044 // when separation by indentation
2045 // only output something when a width is given
2046 if (!getParIndent().empty()) {
2047 os << "\\setlength{\\parindent}{"
2048 << from_utf8(getParIndent().asLatexString())
2053 if (is_math_indent) {
2054 // when formula indentation
2055 // only output something when it is not the default
2056 if (!getMathIndent().empty()) {
2057 os << "\\setlength{\\mathindent}{"
2058 << from_utf8(getMathIndent().asString())
2063 // Now insert the LyX specific LaTeX commands...
2064 features.resolveAlternatives();
2065 features.expandMultiples();
2068 if (!output_sync_macro.empty())
2069 os << from_utf8(output_sync_macro) +"\n";
2070 else if (features.runparams().flavor == FLAVOR::LATEX)
2071 os << "\\usepackage[active]{srcltx}\n";
2072 else if (features.runparams().flavor == FLAVOR::PDFLATEX)
2073 os << "\\synctex=-1\n";
2076 // due to interferences with babel and hyperref, the color package has to
2077 // be loaded (when it is not already loaded) before babel when hyperref
2078 // is used with the colorlinks option, see
2079 // http://www.lyx.org/trac/ticket/5291
2080 // we decided therefore to load color always before babel, see
2081 // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg144349.html
2082 os << from_ascii(features.getColorOptions());
2084 // If we use hyperref, jurabib, japanese or varioref,
2085 // we have to call babel before
2087 && (features.isRequired("jurabib")
2088 || features.isRequired("hyperref")
2089 || features.isRequired("varioref")
2090 || features.isRequired("japanese"))) {
2091 os << features.getBabelPresettings();
2093 os << from_utf8(babelCall(language_options.str(),
2094 !lyxrc.language_global_options)) + '\n';
2095 os << features.getBabelPostsettings();
2098 // The optional packages;
2099 os << from_ascii(features.getPackages());
2101 // Additional Indices
2102 if (features.isRequired("splitidx")) {
2103 for (auto const & idx : indiceslist()) {
2104 os << "\\newindex{";
2105 os << escape(idx.shortcut());
2111 os << from_utf8(spacing().writePreamble(features.isProvided("SetSpace")));
2114 // * Hyperref manual: "Make sure it comes last of your loaded
2115 // packages, to give it a fighting chance of not being over-written,
2116 // since its job is to redefine many LaTeX commands."
2117 // * Email from Heiko Oberdiek: "It is usually better to load babel
2118 // before hyperref. Then hyperref has a chance to detect babel.
2119 // * Has to be loaded before the "LyX specific LaTeX commands" to
2120 // avoid errors with algorithm floats.
2121 // use hyperref explicitly if it is required
2122 if (features.isRequired("hyperref")) {
2123 OutputParams tmp_params = features.runparams();
2124 pdfoptions().writeLaTeX(tmp_params, os,
2125 features.isProvided("hyperref"));
2126 // correctly break URLs with hyperref and dvi/ps output
2127 if (features.runparams().hyperref_driver == "dvips"
2128 && features.isAvailable("breakurl"))
2129 os << "\\usepackage{breakurl}\n";
2130 } else if (features.isRequired("nameref"))
2131 // hyperref loads this automatically
2132 os << "\\usepackage{nameref}\n";
2135 os << "\\usepackage";
2136 if (!lineno_opts.empty())
2137 os << "[" << lineno_opts << "]";
2139 os << "\\linenumbers\n";
2142 // bibtopic needs to be loaded after hyperref.
2143 // the dot provides the aux file naming which LyX can detect.
2144 if (features.mustProvide("bibtopic"))
2145 os << "\\usepackage[dot]{bibtopic}\n";
2147 // Will be surrounded by \makeatletter and \makeatother when not empty
2148 otexstringstream atlyxpreamble;
2150 // Some macros LyX will need
2152 TexString tmppreamble = features.getMacros();
2153 if (!tmppreamble.str.empty())
2154 atlyxpreamble << "\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
2155 "LyX specific LaTeX commands.\n"
2156 << move(tmppreamble)
2159 // the text class specific preamble
2161 docstring tmppreamble = features.getTClassPreamble();
2162 if (!tmppreamble.empty())
2163 atlyxpreamble << "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
2164 "Textclass specific LaTeX commands.\n"
2168 // suppress date if selected
2169 // use \@ifundefined because we cannot be sure that every document class
2170 // has a \date command
2172 atlyxpreamble << "\\@ifundefined{date}{}{\\date{}}\n";
2174 /* the user-defined preamble */
2175 if (!containsOnly(preamble, " \n\t")) {
2177 atlyxpreamble << "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
2178 "User specified LaTeX commands.\n";
2180 // Check if the user preamble contains uncodable glyphs
2181 odocstringstream user_preamble;
2182 docstring uncodable_glyphs;
2183 Encoding const * const enc = features.runparams().encoding;
2185 for (char_type c : preamble) {
2186 if (!enc->encodable(c)) {
2187 docstring const glyph(1, c);
2188 LYXERR0("Uncodable character '"
2190 << "' in user preamble!");
2191 uncodable_glyphs += glyph;
2192 if (features.runparams().dryrun) {
2193 user_preamble << "<" << _("LyX Warning: ")
2194 << _("uncodable character") << " '";
2195 user_preamble.put(c);
2196 user_preamble << "'>";
2199 user_preamble.put(c);
2202 user_preamble << preamble;
2204 // On BUFFER_VIEW|UPDATE, warn user if we found uncodable glyphs
2205 if (!features.runparams().dryrun && !uncodable_glyphs.empty()) {
2206 frontend::Alert::warning(
2207 _("Uncodable character in user preamble"),
2209 _("The user preamble of your document contains glyphs "
2210 "that are unknown in the current document encoding "
2211 "(namely %1$s).\nThese glyphs are omitted "
2212 " from the output, which may result in "
2213 "incomplete output."
2214 "\n\nPlease select an appropriate "
2215 "document encoding\n"
2216 "(such as utf8) or change the "
2217 "preamble code accordingly."),
2220 atlyxpreamble << user_preamble.str() << '\n';
2223 // footmisc must be loaded after setspace
2224 // Load it here to avoid clashes with footmisc loaded in the user
2225 // preamble. For that reason we also pass the options via
2226 // \PassOptionsToPackage in getPreamble() and not here.
2227 if (features.mustProvide("footmisc"))
2228 atlyxpreamble << "\\usepackage{footmisc}\n";
2230 // subfig loads internally the LaTeX package "caption". As
2231 // caption is a very popular package, users will load it in
2232 // the preamble. Therefore we must load subfig behind the
2233 // user-defined preamble and check if the caption package was
2234 // loaded or not. For the case that caption is loaded before
2235 // subfig, there is the subfig option "caption=false". This
2236 // option also works when a koma-script class is used and
2237 // koma's own caption commands are used instead of caption. We
2238 // use \PassOptionsToPackage here because the user could have
2239 // already loaded subfig in the preamble.
2240 if (features.mustProvide("subfig"))
2241 atlyxpreamble << "\\@ifundefined{showcaptionsetup}{}{%\n"
2242 " \\PassOptionsToPackage{caption=false}{subfig}}\n"
2243 "\\usepackage{subfig}\n";
2245 // Itemize bullet settings need to be last in case the user
2246 // defines their own bullets that use a package included
2247 // in the user-defined preamble -- ARRae
2248 // Actually it has to be done much later than that
2249 // since some packages like frenchb make modifications
2250 // at \begin{document} time -- JMarc
2251 docstring bullets_def;
2252 for (int i = 0; i < 4; ++i) {
2253 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
2254 if (bullets_def.empty())
2255 bullets_def += "\\AtBeginDocument{\n";
2256 bullets_def += " \\def\\labelitemi";
2258 // `i' is one less than the item to modify
2265 bullets_def += "ii";
2271 bullets_def += '{' +
2272 user_defined_bullet(i).getText()
2277 if (!bullets_def.empty())
2278 atlyxpreamble << bullets_def << "}\n\n";
2280 if (!atlyxpreamble.empty())
2281 os << "\n\\makeatletter\n"
2282 << atlyxpreamble.release()
2283 << "\\makeatother\n\n";
2285 // We try to load babel late, in case it interferes with other packages.
2286 // Jurabib, hyperref, varioref, bicaption, menukeys and listings (bug 8995)
2287 // have to be called after babel, though.
2288 if (use_babel && !features.isRequired("jurabib")
2289 && !features.isRequired("hyperref")
2290 && !features.isRequired("varioref")
2291 && !features.isRequired("japanese")) {
2292 os << features.getBabelPresettings();
2294 os << from_utf8(babelCall(language_options.str(),
2295 !lyxrc.language_global_options)) + '\n';
2296 os << features.getBabelPostsettings();
2298 // In documents containing text in Thai language,
2299 // we must load inputenc after babel (see lib/languages).
2300 if (contains(features.getBabelPostsettings(), from_ascii("thai.ldf")))
2301 writeEncodingPreamble(os, features);
2303 // font selection must be done after babel with non-TeX fonts
2304 if (!fonts.empty() && features.useBabel() && useNonTeXFonts)
2305 os << from_utf8(fonts);
2307 if (features.isRequired("bicaption"))
2308 os << "\\usepackage{bicaption}\n";
2309 if (!listings_params.empty()
2310 || features.mustProvide("listings")
2311 || features.mustProvide("minted")) {
2313 os << "\\usepackage{minted}\n";
2315 os << "\\usepackage{listings}\n";
2317 string lst_params = listings_params;
2318 // If minted, do not output the language option (bug 11203)
2319 if (use_minted && contains(lst_params, "language=")) {
2320 vector<string> opts =
2321 getVectorFromString(lst_params, ",", false);
2322 for (size_t i = 0; i < opts.size(); ++i) {
2323 if (prefixIs(opts[i], "language="))
2324 opts.erase(opts.begin() + i--);
2326 lst_params = getStringFromVector(opts, ",");
2328 if (!lst_params.empty()) {
2330 os << "\\setminted{";
2333 // do not test validity because listings_params is
2334 // supposed to be valid
2336 InsetListingsParams(lst_params).separatedParams(true);
2337 os << from_utf8(par);
2341 // xunicode only needs to be loaded if tipa is used
2342 // (the rest is obsoleted by the new TU encoding).
2343 // It needs to be loaded at least after amsmath, amssymb,
2344 // esint and the other packages that provide special glyphs
2345 if (features.mustProvide("tipa") && useNonTeXFonts
2346 && !features.isProvided("xunicode")) {
2347 // The `xunicode` package officially only supports XeTeX,
2348 // but also works with LuaTeX. We work around its XeTeX test.
2349 if (features.runparams().flavor != FLAVOR::XETEX) {
2350 os << "% Pretend to xunicode that we are XeTeX\n"
2351 << "\\def\\XeTeXpicfile{}\n";
2353 os << "\\usepackage{xunicode}\n";
2356 // covington must be loaded after beamerarticle
2357 if (features.isRequired("covington"))
2358 os << "\\usepackage{covington}\n";
2360 // Polyglossia must be loaded last ...
2361 if (use_polyglossia) {
2363 os << "\\usepackage{polyglossia}\n";
2364 // set the main language
2365 os << "\\setdefaultlanguage";
2366 if (!language->polyglossiaOpts().empty())
2367 os << "[" << from_ascii(language->polyglossiaOpts()) << "]";
2368 os << "{" << from_ascii(language->polyglossia()) << "}\n";
2369 // now setup the other languages
2370 set<string> const polylangs =
2371 features.getPolyglossiaLanguages();
2372 for (auto const & pl : polylangs) {
2373 // We do not output the options here; they are output in
2374 // the language switch commands. This is safer if multiple
2375 // varieties are used.
2376 if (pl == language->polyglossia())
2378 os << "\\setotherlanguage";
2379 os << "{" << from_ascii(pl) << "}\n";
2383 // ... but before biblatex (see #7065)
2384 if ((features.mustProvide("biblatex")
2385 || features.isRequired("biblatex-chicago"))
2386 && !features.isProvided("biblatex-chicago")
2387 && !features.isProvided("biblatex-natbib")
2388 && !features.isProvided("natbib-internal")
2389 && !features.isProvided("natbib")
2390 && !features.isProvided("jurabib")) {
2391 // The biblatex-chicago package has a differing interface
2392 // it uses a wrapper package and loads styles via fixed options
2393 bool const chicago = features.isRequired("biblatex-chicago");
2396 os << "\\usepackage";
2397 if (!biblatex_bibstyle.empty()
2398 && (biblatex_bibstyle == biblatex_citestyle)
2400 opts = "style=" + biblatex_bibstyle;
2402 } else if (!chicago) {
2403 if (!biblatex_bibstyle.empty()) {
2404 opts = "bibstyle=" + biblatex_bibstyle;
2407 if (!biblatex_citestyle.empty()) {
2408 opts += delim + "citestyle=" + biblatex_citestyle;
2412 if (!multibib.empty() && multibib != "child") {
2413 opts += delim + "refsection=" + multibib;
2416 if (bibtexCommand() == "bibtex8"
2417 || prefixIs(bibtexCommand(), "bibtex8 ")) {
2418 opts += delim + "backend=bibtex8";
2420 } else if (bibtexCommand() == "bibtex"
2421 || prefixIs(bibtexCommand(), "bibtex ")) {
2422 opts += delim + "backend=bibtex";
2425 if (!bib_encoding.empty() && encodings.fromLyXName(bib_encoding)) {
2426 opts += delim + "bibencoding="
2427 + encodings.fromLyXName(bib_encoding)->latexName();
2430 if (!biblio_opts.empty())
2431 opts += delim + biblio_opts;
2433 os << "[" << opts << "]";
2435 os << "{biblatex-chicago}\n";
2437 os << "{biblatex}\n";
2441 // Load custom language package here
2442 if (features.langPackage() == LaTeXFeatures::LANG_PACK_CUSTOM) {
2443 if (lang_package == "default")
2444 os << from_utf8(lyxrc.language_custom_package);
2446 os << from_utf8(lang_package);
2450 // Since menukeys uses catoptions, which does some heavy changes on key-value options,
2451 // it is recommended to load menukeys as the last package (even after hyperref)
2452 if (features.isRequired("menukeys"))
2453 os << "\\usepackage{menukeys}\n";
2455 docstring const i18npreamble =
2456 features.getTClassI18nPreamble(use_babel, use_polyglossia,
2458 if (!i18npreamble.empty())
2459 os << i18npreamble + '\n';
2465 void BufferParams::useClassDefaults()
2467 DocumentClass const & tclass = documentClass();
2469 sides = tclass.sides();
2470 columns = tclass.columns();
2471 pagestyle = tclass.pagestyle();
2472 tablestyle = tclass.tablestyle();
2473 use_default_options = true;
2474 // Only if class has a ToC hierarchy
2475 if (tclass.hasTocLevels()) {
2476 secnumdepth = tclass.secnumdepth();
2477 tocdepth = tclass.tocdepth();
2482 bool BufferParams::hasClassDefaults() const
2484 DocumentClass const & tclass = documentClass();
2486 return sides == tclass.sides()
2487 && columns == tclass.columns()
2488 && pagestyle == tclass.pagestyle()
2489 && tablestyle == tclass.tablestyle()
2490 && use_default_options
2491 && secnumdepth == tclass.secnumdepth()
2492 && tocdepth == tclass.tocdepth();
2496 DocumentClass const & BufferParams::documentClass() const
2502 DocumentClassConstPtr BufferParams::documentClassPtr() const
2508 void BufferParams::setDocumentClass(DocumentClassConstPtr tc)
2510 // evil, but this function is evil
2511 doc_class_ = const_pointer_cast<DocumentClass>(tc);
2512 invalidateConverterCache();
2516 bool BufferParams::setBaseClass(string const & classname, string const & path)
2518 LYXERR(Debug::TCLASS, "setBaseClass: " << classname);
2519 LayoutFileList & bcl = LayoutFileList::get();
2520 if (!bcl.haveClass(classname)) {
2522 bformat(_("The layout file:\n"
2524 "could not be found. A default textclass with default\n"
2525 "layouts will be used. LyX will not be able to produce\n"
2527 from_utf8(classname));
2528 frontend::Alert::error(_("Document class not found"), s);
2529 bcl.addEmptyClass(classname);
2532 bool const success = bcl[classname].load(path);
2535 bformat(_("Due to some error in it, the layout file:\n"
2537 "could not be loaded. A default textclass with default\n"
2538 "layouts will be used. LyX will not be able to produce\n"
2540 from_utf8(classname));
2541 frontend::Alert::error(_("Could not load class"), s);
2542 bcl.addEmptyClass(classname);
2545 pimpl_->baseClass_ = classname;
2546 layout_modules_.adaptToBaseClass(baseClass(), removed_modules_);
2551 LayoutFile const * BufferParams::baseClass() const
2553 if (LayoutFileList::get().haveClass(pimpl_->baseClass_))
2554 return &(LayoutFileList::get()[pimpl_->baseClass_]);
2560 LayoutFileIndex const & BufferParams::baseClassID() const
2562 return pimpl_->baseClass_;
2566 void BufferParams::makeDocumentClass(bool const clone)
2571 invalidateConverterCache();
2572 LayoutModuleList mods;
2573 for (auto const & mod : layout_modules_)
2574 mods.push_back(mod);
2576 doc_class_ = getDocumentClass(*baseClass(), mods, cite_engine_, clone);
2578 TextClass::ReturnValues success = TextClass::OK;
2579 if (!forced_local_layout_.empty())
2580 success = doc_class_->read(to_utf8(forced_local_layout_),
2582 if (!local_layout_.empty() &&
2583 (success == TextClass::OK || success == TextClass::OK_OLDFORMAT))
2584 success = doc_class_->read(to_utf8(local_layout_), TextClass::MODULE);
2585 if (success != TextClass::OK && success != TextClass::OK_OLDFORMAT) {
2586 docstring const msg = _("Error reading internal layout information");
2587 frontend::Alert::warning(_("Read Error"), msg);
2592 bool BufferParams::layoutModuleCanBeAdded(string const & modName) const
2594 return layout_modules_.moduleCanBeAdded(modName, baseClass());
2598 docstring BufferParams::getLocalLayout(bool forced) const
2601 return from_utf8(doc_class_->forcedLayouts());
2603 return local_layout_;
2607 void BufferParams::setLocalLayout(docstring const & layout, bool forced)
2610 forced_local_layout_ = layout;
2612 local_layout_ = layout;
2616 bool BufferParams::addLayoutModule(string const & modName)
2618 for (auto const & mod : layout_modules_)
2621 layout_modules_.push_back(modName);
2626 string BufferParams::bufferFormat() const
2628 return documentClass().outputFormat();
2632 bool BufferParams::isExportable(string const & format, bool need_viewable) const
2634 FormatList const & formats = exportableFormats(need_viewable);
2635 for (auto const & fmt : formats) {
2636 if (fmt->name() == format)
2643 FormatList const & BufferParams::exportableFormats(bool only_viewable) const
2645 FormatList & cached = only_viewable ?
2646 pimpl_->viewableFormatList : pimpl_->exportableFormatList;
2647 bool & valid = only_viewable ?
2648 pimpl_->isViewCacheValid : pimpl_->isExportCacheValid;
2652 vector<string> const backs = backends();
2653 set<string> excludes;
2654 if (useNonTeXFonts) {
2655 excludes.insert("latex");
2656 excludes.insert("pdflatex");
2657 } else if (inputenc != "ascii" && inputenc != "utf8-plain") {
2658 // XeTeX with TeX fonts requires input encoding ascii (#10600).
2659 excludes.insert("xetex");
2663 theConverters().getReachable(backs[0], only_viewable, true, excludes);
2664 vector<string>::const_iterator it = backs.begin() + 1;
2665 for (; it != backs.end(); ++it) {
2666 FormatList r = theConverters().getReachable(*it, only_viewable,
2668 result.insert(result.end(), r.begin(), r.end());
2670 sort(result.begin(), result.end(), Format::formatSorter);
2677 vector<string> BufferParams::backends() const
2680 string const buffmt = bufferFormat();
2682 // FIXME: Don't hardcode format names here, but use a flag
2683 if (buffmt == "latex") {
2684 if (encoding().package() == Encoding::japanese)
2685 v.push_back("platex");
2687 if (!useNonTeXFonts) {
2688 v.push_back("pdflatex");
2689 v.push_back("latex");
2692 || inputenc == "ascii" || inputenc == "utf8-plain")
2693 v.push_back("xetex");
2694 v.push_back("luatex");
2695 v.push_back("dviluatex");
2698 string rbuffmt = buffmt;
2699 // If we use an OutputFormat in Japanese docs,
2700 // we need special format in order to get the path
2701 // via pLaTeX (#8823)
2702 if (documentClass().hasOutputFormat()
2703 && encoding().package() == Encoding::japanese)
2705 v.push_back(rbuffmt);
2708 v.push_back("xhtml");
2709 v.push_back("docbook5");
2710 v.push_back("text");
2716 FLAVOR BufferParams::getOutputFlavor(string const & format) const
2718 string const dformat = (format.empty() || format == "default") ?
2719 getDefaultOutputFormat() : format;
2720 DefaultFlavorCache::const_iterator it =
2721 default_flavors_.find(dformat);
2723 if (it != default_flavors_.end())
2726 FLAVOR result = FLAVOR::LATEX;
2728 // FIXME It'd be better not to hardcode this, but to do
2729 // something with formats.
2730 if (dformat == "xhtml")
2731 result = FLAVOR::HTML;
2732 else if (dformat == "docbook5")
2733 result = FLAVOR::DOCBOOK5;
2734 else if (dformat == "text")
2735 result = FLAVOR::TEXT;
2736 else if (dformat == "lyx")
2737 result = FLAVOR::LYX;
2738 else if (dformat == "pdflatex")
2739 result = FLAVOR::PDFLATEX;
2740 else if (dformat == "xetex")
2741 result = FLAVOR::XETEX;
2742 else if (dformat == "luatex")
2743 result = FLAVOR::LUATEX;
2744 else if (dformat == "dviluatex")
2745 result = FLAVOR::DVILUATEX;
2747 // Try to determine flavor of default output format
2748 vector<string> backs = backends();
2749 if (find(backs.begin(), backs.end(), dformat) == backs.end()) {
2750 // Get shortest path to format
2751 Graph::EdgePath path;
2752 for (auto const & bvar : backs) {
2753 Graph::EdgePath p = theConverters().getPath(bvar, dformat);
2754 if (!p.empty() && (path.empty() || p.size() < path.size())) {
2759 result = theConverters().getFlavor(path);
2762 // cache this flavor
2763 default_flavors_[dformat] = result;
2768 string BufferParams::getDefaultOutputFormat() const
2770 if (!default_output_format.empty()
2771 && default_output_format != "default")
2772 return default_output_format;
2773 if (encoding().package() == Encoding::japanese)
2774 return lyxrc.default_platex_view_format;
2776 return lyxrc.default_otf_view_format;
2777 return lyxrc.default_view_format;
2780 Font const BufferParams::getFont() const
2782 FontInfo f = documentClass().defaultfont();
2783 if (fonts_default_family == "rmdefault")
2784 f.setFamily(ROMAN_FAMILY);
2785 else if (fonts_default_family == "sfdefault")
2786 f.setFamily(SANS_FAMILY);
2787 else if (fonts_default_family == "ttdefault")
2788 f.setFamily(TYPEWRITER_FAMILY);
2789 return Font(f, language);
2793 QuoteStyle BufferParams::getQuoteStyle(string const & qs) const
2795 return quotesstyletranslator().find(qs);
2799 bool BufferParams::isLatex() const
2801 return documentClass().outputType() == LATEX;
2805 bool BufferParams::isLiterate() const
2807 return documentClass().outputType() == LITERATE;
2811 void BufferParams::readPreamble(Lexer & lex)
2813 if (lex.getString() != "\\begin_preamble")
2814 lyxerr << "Error (BufferParams::readPreamble):"
2815 "consistency check failed." << endl;
2817 preamble = lex.getLongString(from_ascii("\\end_preamble"));
2821 void BufferParams::readLocalLayout(Lexer & lex, bool forced)
2823 string const expected = forced ? "\\begin_forced_local_layout" :
2824 "\\begin_local_layout";
2825 if (lex.getString() != expected)
2826 lyxerr << "Error (BufferParams::readLocalLayout):"
2827 "consistency check failed." << endl;
2830 forced_local_layout_ =
2831 lex.getLongString(from_ascii("\\end_forced_local_layout"));
2833 local_layout_ = lex.getLongString(from_ascii("\\end_local_layout"));
2837 bool BufferParams::setLanguage(string const & lang)
2839 Language const *new_language = languages.getLanguage(lang);
2840 if (!new_language) {
2841 // Language lang was not found
2844 language = new_language;
2849 void BufferParams::readLanguage(Lexer & lex)
2851 if (!lex.next()) return;
2853 string const tmptok = lex.getString();
2855 // check if tmptok is part of tex_babel in tex-defs.h
2856 if (!setLanguage(tmptok)) {
2857 // Language tmptok was not found
2858 language = default_language;
2859 lyxerr << "Warning: Setting language `"
2860 << tmptok << "' to `" << language->lang()
2866 void BufferParams::readGraphicsDriver(Lexer & lex)
2871 string const tmptok = lex.getString();
2872 // check if tmptok is part of tex_graphics in tex_defs.h
2875 string const test = tex_graphics[n++];
2877 if (test == tmptok) {
2878 graphics_driver = tmptok;
2883 "Warning: graphics driver `$$Token' not recognized!\n"
2884 " Setting graphics driver to `default'.\n");
2885 graphics_driver = "default";
2892 void BufferParams::readBullets(Lexer & lex)
2897 int const index = lex.getInteger();
2899 int temp_int = lex.getInteger();
2900 user_defined_bullet(index).setFont(temp_int);
2901 temp_bullet(index).setFont(temp_int);
2903 user_defined_bullet(index).setCharacter(temp_int);
2904 temp_bullet(index).setCharacter(temp_int);
2906 user_defined_bullet(index).setSize(temp_int);
2907 temp_bullet(index).setSize(temp_int);
2911 void BufferParams::readBulletsLaTeX(Lexer & lex)
2913 // The bullet class should be able to read this.
2916 int const index = lex.getInteger();
2918 docstring const temp_str = lex.getDocString();
2920 user_defined_bullet(index).setText(temp_str);
2921 temp_bullet(index).setText(temp_str);
2925 void BufferParams::readModules(Lexer & lex)
2927 if (!lex.eatLine()) {
2928 lyxerr << "Error (BufferParams::readModules):"
2929 "Unexpected end of input." << endl;
2933 string mod = lex.getString();
2934 if (mod == "\\end_modules")
2936 addLayoutModule(mod);
2942 void BufferParams::readRemovedModules(Lexer & lex)
2944 if (!lex.eatLine()) {
2945 lyxerr << "Error (BufferParams::readRemovedModules):"
2946 "Unexpected end of input." << endl;
2950 string mod = lex.getString();
2951 if (mod == "\\end_removed_modules")
2953 removed_modules_.push_back(mod);
2956 // now we want to remove any removed modules that were previously
2957 // added. normally, that will be because default modules were added in
2958 // setBaseClass(), which gets called when \textclass is read at the
2959 // start of the read.
2960 for (auto const & rm : removed_modules_) {
2961 LayoutModuleList::iterator const mit = layout_modules_.begin();
2962 LayoutModuleList::iterator const men = layout_modules_.end();
2963 LayoutModuleList::iterator found = find(mit, men, rm);
2966 layout_modules_.erase(found);
2971 void BufferParams::readIncludeonly(Lexer & lex)
2973 if (!lex.eatLine()) {
2974 lyxerr << "Error (BufferParams::readIncludeonly):"
2975 "Unexpected end of input." << endl;
2979 string child = lex.getString();
2980 if (child == "\\end_includeonly")
2982 included_children_.push_back(child);
2988 string BufferParams::paperSizeName(PapersizePurpose purpose, string const & psize) const
2990 PAPER_SIZE ppsize = psize.empty() ? papersize : papersizetranslator().find(psize);
2993 if (documentClass().pagesize() == "default")
2994 // could be anything, so don't guess
2996 return paperSizeName(purpose, documentClass().pagesize());
2997 case PAPER_CUSTOM: {
2998 if (purpose == XDVI && !paperwidth.empty() &&
2999 !paperheight.empty()) {
3000 // heightxwidth<unit>
3001 string first = paperwidth;
3002 string second = paperheight;
3003 if (orientation == ORIENTATION_LANDSCAPE)
3006 return first.erase(first.length() - 2)
3012 // dvips and dvipdfm do not know this
3013 if (purpose == DVIPS || purpose == DVIPDFM)
3017 if (purpose == DVIPS || purpose == DVIPDFM)
3021 if (purpose == DVIPS || purpose == DVIPDFM)
3031 if (purpose == DVIPS || purpose == DVIPDFM)
3035 if (purpose == DVIPS || purpose == DVIPDFM)
3039 if (purpose == DVIPS || purpose == DVIPDFM)
3043 if (purpose == DVIPS || purpose == DVIPDFM)
3047 if (purpose == DVIPS || purpose == DVIPDFM)
3051 // dvipdfm does not know this
3052 if (purpose == DVIPDFM)
3056 if (purpose == DVIPDFM)
3060 if (purpose == DVIPS || purpose == DVIPDFM)
3064 if (purpose == DVIPS || purpose == DVIPDFM)
3068 if (purpose == DVIPS || purpose == DVIPDFM)
3072 if (purpose == DVIPS || purpose == DVIPDFM)
3076 if (purpose == DVIPS || purpose == DVIPDFM)
3080 if (purpose == DVIPS || purpose == DVIPDFM)
3084 if (purpose == DVIPS || purpose == DVIPDFM)
3088 if (purpose == DVIPS || purpose == DVIPDFM)
3092 if (purpose == DVIPS || purpose == DVIPDFM)
3096 if (purpose == DVIPS || purpose == DVIPDFM)
3100 if (purpose == DVIPS || purpose == DVIPDFM)
3104 if (purpose == DVIPS || purpose == DVIPDFM)
3108 if (purpose == DVIPS || purpose == DVIPDFM)
3112 if (purpose == DVIPS || purpose == DVIPDFM)
3116 if (purpose == DVIPS || purpose == DVIPDFM)
3119 case PAPER_USEXECUTIVE:
3120 // dvipdfm does not know this
3121 if (purpose == DVIPDFM)
3126 case PAPER_USLETTER:
3128 if (purpose == XDVI)
3135 string const BufferParams::dvips_options() const
3139 // If the class loads the geometry package, we do not know which
3140 // paper size is used, since we do not set it (bug 7013).
3141 // Therefore we must not specify any argument here.
3142 // dvips gets the correct paper size via DVI specials in this case
3143 // (if the class uses the geometry package correctly).
3144 if (documentClass().provides("geometry"))
3148 && papersize == PAPER_CUSTOM
3149 && !lyxrc.print_paper_dimension_flag.empty()
3150 && !paperwidth.empty()
3151 && !paperheight.empty()) {
3152 // using a custom papersize
3153 result = lyxrc.print_paper_dimension_flag;
3154 result += ' ' + paperwidth;
3155 result += ',' + paperheight;
3157 string const paper_option = paperSizeName(DVIPS);
3158 if (!paper_option.empty() && (paper_option != "letter" ||
3159 orientation != ORIENTATION_LANDSCAPE)) {
3160 // dvips won't accept -t letter -t landscape.
3161 // In all other cases, include the paper size
3163 result = lyxrc.print_paper_flag;
3164 result += ' ' + paper_option;
3167 if (orientation == ORIENTATION_LANDSCAPE &&
3168 papersize != PAPER_CUSTOM)
3169 result += ' ' + lyxrc.print_landscape_flag;
3174 string const BufferParams::main_font_encoding() const
3176 if (font_encodings().empty()) {
3177 if (ascii_lowercase(language->fontenc(*this)) == "none")
3181 return font_encodings().back();
3185 vector<string> const BufferParams::font_encodings() const
3187 string doc_fontenc = (fontenc == "auto") ? string() : fontenc;
3189 vector<string> fontencs;
3191 // "default" means "no explicit font encoding"
3192 if (doc_fontenc != "default") {
3193 if (!doc_fontenc.empty())
3194 // If we have a custom setting, we use only that!
3195 return getVectorFromString(doc_fontenc);
3196 if (!language->fontenc(*this).empty()
3197 && ascii_lowercase(language->fontenc(*this)) != "none") {
3198 vector<string> fencs = getVectorFromString(language->fontenc(*this));
3199 for (auto & fe : fencs) {
3200 if (find(fontencs.begin(), fontencs.end(), fe) == fontencs.end())
3201 fontencs.push_back(fe);
3210 string BufferParams::babelCall(string const & lang_opts, bool const langoptions) const
3212 // suppress the babel call if there is no BabelName defined
3213 // for the document language in the lib/languages file and if no
3214 // other languages are used (lang_opts is then empty)
3215 if (lang_opts.empty())
3217 // The prefs may require the languages to
3218 // be submitted to babel itself (not the class).
3220 return "\\usepackage[" + lang_opts + "]{babel}";
3221 return "\\usepackage{babel}";
3225 docstring BufferParams::getGraphicsDriver(string const & package) const
3229 if (package == "geometry") {
3230 if (graphics_driver == "dvips"
3231 || graphics_driver == "dvipdfm"
3232 || graphics_driver == "pdftex"
3233 || graphics_driver == "vtex")
3234 result = from_ascii(graphics_driver);
3235 else if (graphics_driver == "dvipdfmx")
3236 result = from_ascii("dvipdfm");
3243 void BufferParams::writeEncodingPreamble(otexstream & os,
3244 LaTeXFeatures & features) const
3246 // With no-TeX fonts we use utf8-plain without encoding package.
3250 if (inputenc == "auto-legacy") {
3251 string const doc_encoding =
3252 language->encoding()->latexName();
3253 Encoding::Package const package =
3254 language->encoding()->package();
3256 // Create list of inputenc options:
3257 set<string> encoding_set;
3258 // luainputenc fails with more than one encoding
3259 if (features.runparams().flavor != FLAVOR::LUATEX
3260 && features.runparams().flavor != FLAVOR::DVILUATEX)
3261 // list all input encodings used in the document
3262 encoding_set = features.getEncodingSet(doc_encoding);
3264 // The "japanese" babel-language requires the pLaTeX engine
3265 // which conflicts with "inputenc".
3266 // See http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129680.html
3267 if ((!encoding_set.empty() || package == Encoding::inputenc)
3268 && !features.isRequired("japanese")
3269 && !features.isProvided("inputenc")) {
3270 os << "\\usepackage[";
3271 set<string>::const_iterator it = encoding_set.begin();
3272 set<string>::const_iterator const end = encoding_set.end();
3274 os << from_ascii(*it);
3277 for (; it != end; ++it)
3278 os << ',' << from_ascii(*it);
3279 if (package == Encoding::inputenc) {
3280 if (!encoding_set.empty())
3282 os << from_ascii(doc_encoding);
3284 if (features.runparams().flavor == FLAVOR::LUATEX
3285 || features.runparams().flavor == FLAVOR::DVILUATEX)
3286 os << "]{luainputenc}\n";
3288 os << "]{inputenc}\n";
3290 } else if (inputenc != "auto-legacy-plain") {
3291 switch (encoding().package()) {
3292 case Encoding::none:
3294 case Encoding::japanese:
3295 if (encoding().iconvName() != "UTF-8"
3296 && !features.runparams().isFullUnicode())
3297 // don't default to [utf8]{inputenc} with TeXLive >= 18
3298 os << "\\ifdefined\\UseRawInputEncoding\n"
3299 << " \\UseRawInputEncoding\\fi\n";
3301 case Encoding::inputenc:
3302 // do not load inputenc if japanese is used
3303 // or if the class provides inputenc
3304 if (features.isRequired("japanese")
3305 || features.isProvided("inputenc"))
3307 os << "\\usepackage[" << from_ascii(encoding().latexName());
3308 if (features.runparams().flavor == FLAVOR::LUATEX
3309 || features.runparams().flavor == FLAVOR::DVILUATEX)
3310 os << "]{luainputenc}\n";
3312 os << "]{inputenc}\n";
3316 if (inputenc == "auto-legacy-plain" || features.isRequired("japanese")) {
3317 // don't default to [utf8]{inputenc} with TeXLive >= 18
3318 os << "\\ifdefined\\UseRawInputEncoding\n";
3319 os << " \\UseRawInputEncoding\\fi\n";
3324 string const BufferParams::parseFontName(string const & name) const
3326 string mangled = name;
3327 size_t const idx = mangled.find('[');
3328 if (idx == string::npos || idx == 0)
3331 return mangled.substr(0, idx - 1);
3335 string const BufferParams::loadFonts(LaTeXFeatures & features) const
3337 if (fontsRoman() == "default" && fontsSans() == "default"
3338 && fontsTypewriter() == "default"
3339 && (fontsMath() == "default" || fontsMath() == "auto"))
3345 /* Fontspec (XeTeX, LuaTeX): we provide GUI support for oldstyle
3346 * numbers (Numbers=OldStyle) and sf/tt scaling. The Ligatures=TeX/
3347 * Mapping=tex-text option assures TeX ligatures (such as "--")
3348 * are resolved. Note that tt does not use these ligatures.
3350 * -- add more GUI options?
3351 * -- add more fonts (fonts for other scripts)
3352 * -- if there's a way to find out if a font really supports
3353 * OldStyle, enable/disable the widget accordingly.
3355 if (useNonTeXFonts && features.isAvailable("fontspec")) {
3356 // "Mapping=tex-text" and "Ligatures=TeX" are equivalent.
3357 // However, until v.2 (2010/07/11) fontspec only knew
3358 // Mapping=tex-text (for XeTeX only); then "Ligatures=TeX"
3359 // was introduced for both XeTeX and LuaTeX (LuaTeX
3360 // didn't understand "Mapping=tex-text", while XeTeX
3361 // understood both. With most recent versions, both
3362 // variants are understood by both engines. However,
3363 // we want to provide support for at least TeXLive 2009
3364 // (for XeTeX; LuaTeX is only supported as of v.2)
3365 // As of 2017/11/03, Babel has its own higher-level
3366 // interface on top of fontspec that is to be used.
3367 bool const babelfonts = features.useBabel()
3368 && features.isAvailable("babel-2017/11/03");
3369 string const texmapping =
3370 (features.runparams().flavor == FLAVOR::XETEX) ?
3371 "Mapping=tex-text" : "Ligatures=TeX";
3372 if (fontsRoman() != "default") {
3374 os << "\\babelfont{rm}[";
3376 os << "\\setmainfont[";
3377 if (!font_roman_opts.empty())
3378 os << font_roman_opts << ',';
3380 if (fonts_roman_osf)
3381 os << ",Numbers=OldStyle";
3382 os << "]{" << parseFontName(fontsRoman()) << "}\n";
3384 if (fontsSans() != "default") {
3385 string const sans = parseFontName(fontsSans());
3386 if (fontsSansScale() != 100) {
3388 os << "\\babelfont{sf}";
3390 os << "\\setsansfont";
3392 << float(fontsSansScale()) / 100 << ',';
3394 os << "Numbers=OldStyle,";
3395 if (!font_sans_opts.empty())
3396 os << font_sans_opts << ',';
3397 os << texmapping << "]{"
3401 os << "\\babelfont{sf}[";
3403 os << "\\setsansfont[";
3405 os << "Numbers=OldStyle,";
3406 if (!font_sans_opts.empty())
3407 os << font_sans_opts << ',';
3408 os << texmapping << "]{"
3412 if (fontsTypewriter() != "default") {
3413 string const mono = parseFontName(fontsTypewriter());
3414 if (fontsTypewriterScale() != 100) {
3416 os << "\\babelfont{tt}";
3418 os << "\\setmonofont";
3420 << float(fontsTypewriterScale()) / 100;
3421 if (fonts_typewriter_osf)
3422 os << ",Numbers=OldStyle";
3423 if (!font_typewriter_opts.empty())
3424 os << ',' << font_typewriter_opts;
3429 os << "\\babelfont{tt}";
3431 os << "\\setmonofont";
3432 if (!font_typewriter_opts.empty() || fonts_typewriter_osf) {
3434 if (fonts_typewriter_osf)
3435 os << "Numbers=OldStyle";
3436 if (!font_typewriter_opts.empty()) {
3437 if (fonts_typewriter_osf)
3439 os << font_typewriter_opts;
3443 os << '{' << mono << "}\n";
3450 bool const ot1 = (main_font_encoding() == "default" || main_font_encoding() == "OT1");
3451 bool const dryrun = features.runparams().dryrun;
3452 bool const complete = (fontsSans() == "default" && fontsTypewriter() == "default");
3453 bool const nomath = (fontsMath() == "default");
3456 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsRoman())).getLaTeXCode(
3457 dryrun, ot1, complete, fonts_expert_sc, fonts_roman_osf,
3458 nomath, font_roman_opts);
3461 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsSans())).getLaTeXCode(
3462 dryrun, ot1, complete, fonts_expert_sc, fonts_sans_osf,
3463 nomath, font_sans_opts, fontsSansScale());
3465 // MONOSPACED/TYPEWRITER
3466 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsTypewriter())).getLaTeXCode(
3467 dryrun, ot1, complete, fonts_expert_sc, fonts_typewriter_osf,
3468 nomath, font_typewriter_opts, fontsTypewriterScale());
3471 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsMath())).getLaTeXCode(
3472 dryrun, ot1, complete, fonts_expert_sc, fonts_roman_osf,
3479 Encoding const & BufferParams::encoding() const
3481 // Main encoding for LaTeX output.
3483 return *(encodings.fromLyXName("utf8-plain"));
3484 if (inputenc == "auto-legacy" || inputenc == "auto-legacy-plain")
3485 return *language->encoding();
3486 if (inputenc == "utf8" && language->lang() == "japanese")
3487 return *(encodings.fromLyXName("utf8-platex"));
3488 Encoding const * const enc = encodings.fromLyXName(inputenc);
3491 LYXERR0("Unknown inputenc value `" << inputenc
3492 << "'. Using `auto' instead.");
3493 return *language->encoding();
3497 string const & BufferParams::defaultBiblioStyle() const
3499 if (!biblio_style.empty())
3500 return biblio_style;
3502 map<string, string> const & bs = documentClass().defaultBiblioStyle();
3503 auto cit = bs.find(theCiteEnginesList.getTypeAsString(citeEngineType()));
3504 if (cit != bs.end())
3507 return empty_string();
3511 bool BufferParams::fullAuthorList() const
3513 return documentClass().fullAuthorList();
3517 string BufferParams::getCiteAlias(string const & s) const
3519 vector<string> commands =
3520 documentClass().citeCommands(citeEngineType());
3521 // If it is a real command, don't treat it as an alias
3522 if (find(commands.begin(), commands.end(), s) != commands.end())
3524 map<string,string> aliases = documentClass().citeCommandAliases();
3525 if (aliases.find(s) != aliases.end())
3531 vector<string> BufferParams::citeCommands() const
3533 static CitationStyle const default_style;
3534 vector<string> commands =
3535 documentClass().citeCommands(citeEngineType());
3536 if (commands.empty())
3537 commands.push_back(default_style.name);
3542 vector<CitationStyle> BufferParams::citeStyles() const
3544 static CitationStyle const default_style;
3545 vector<CitationStyle> styles =
3546 documentClass().citeStyles(citeEngineType());
3548 styles.push_back(default_style);
3553 string const BufferParams::bibtexCommand() const
3555 // Return document-specific setting if available
3556 if (bibtex_command != "default")
3557 return bibtex_command;
3559 // If we have "default" in document settings, consult the prefs
3560 // 1. Japanese (uses a specific processor)
3561 if (encoding().package() == Encoding::japanese) {
3562 if (lyxrc.jbibtex_command != "automatic")
3563 // Return the specified program, if "automatic" is not set
3564 return lyxrc.jbibtex_command;
3565 else if (!useBiblatex()) {
3566 // With classic BibTeX, return pbibtex, jbibtex, bibtex
3567 if (lyxrc.jbibtex_alternatives.find("pbibtex") != lyxrc.jbibtex_alternatives.end())
3569 if (lyxrc.jbibtex_alternatives.find("jbibtex") != lyxrc.jbibtex_alternatives.end())
3574 // 2. All other languages
3575 else if (lyxrc.bibtex_command != "automatic")
3576 // Return the specified program, if "automatic" is not set
3577 return lyxrc.bibtex_command;
3579 // 3. Automatic: find the most suitable for the current cite framework
3580 if (useBiblatex()) {
3581 // For Biblatex, we prefer biber (also for Japanese)
3582 // and fall back to bibtex8 and, as last resort, bibtex
3583 if (lyxrc.bibtex_alternatives.find("biber") != lyxrc.bibtex_alternatives.end())
3585 else if (lyxrc.bibtex_alternatives.find("bibtex8") != lyxrc.bibtex_alternatives.end())
3592 bool BufferParams::useBiblatex() const
3594 return theCiteEnginesList[citeEngine()]->getCiteFramework() == "biblatex";
3598 void BufferParams::invalidateConverterCache() const
3600 pimpl_->isExportCacheValid = false;
3601 pimpl_->isViewCacheValid = false;
3605 // We shouldn't need to reset the params here, since anything
3606 // we need will be recopied.
3607 void BufferParams::copyForAdvFR(const BufferParams & bp)
3609 string const & lang = bp.language->lang();
3611 layout_modules_ = bp.layout_modules_;
3612 string const & doc_class = bp.documentClass().name();
3613 setBaseClass(doc_class);
3617 void BufferParams::setBibFileEncoding(string const & file, string const & enc)
3619 bib_encodings[file] = enc;
3623 string const BufferParams::bibFileEncoding(string const & file) const
3625 if (bib_encodings.find(file) == bib_encodings.end())
3627 return bib_encodings.find(file)->second;