2 * \file BufferParams.cpp
3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
6 * \author Alfredo Braunstein
7 * \author Lars Gullik Bjønnes
8 * \author Jean-Marc Lasgouttes
10 * \author André Pönitz
11 * \author Martin Vermeer
13 * Full author contact details are available in file CREDITS.
18 #include "BufferParams.h"
21 #include "LayoutFile.h"
22 #include "BranchList.h"
25 #include "CiteEnginesList.h"
28 #include "Converter.h"
31 #include "IndicesList.h"
33 #include "LaTeXFeatures.h"
34 #include "LaTeXFonts.h"
38 #include "OutputParams.h"
40 #include "texstream.h"
43 #include "PDFOptions.h"
45 #include "frontends/alert.h"
47 #include "insets/InsetListingsParams.h"
48 #include "insets/InsetQuotes.h"
50 #include "support/convert.h"
51 #include "support/debug.h"
52 #include "support/FileName.h"
53 #include "support/filetools.h"
54 #include "support/gettext.h"
55 #include "support/Length.h"
56 #include "support/Messages.h"
57 #include "support/mutex.h"
58 #include "support/Package.h"
59 #include "support/Translator.h"
60 #include "support/lstrings.h"
66 using namespace lyx::support;
69 static char const * const string_paragraph_separation[] = {
74 static char const * const string_quotes_style[] = {
75 "english", "swedish", "german", "polish", "swiss", "danish", "plain",
76 "british", "swedishg", "french", "frenchin", "russian", "cjk", "cjkangle",
81 static char const * const string_papersize[] = {
82 "default", "custom", "letter", "legal", "executive",
83 "a0", "a1", "a2", "a3", "a4", "a5", "a6",
84 "b0", "b1", "b2", "b3", "b4", "b5", "b6",
85 "c0", "c1", "c2", "c3", "c4", "c5", "c6",
86 "b0j", "b1j", "b2j", "b3j", "b4j", "b5j", "b6j", ""
90 static char const * const string_papersize_geometry[] = {
91 "default", "custom", "letterpaper", "legalpaper", "executivepaper",
92 "a0paper", "a1paper", "a2paper", "a3paper", "a4paper", "a5paper", "a6paper",
93 "b0paper", "b1paper", "b2paper", "b3paper", "b4paper", "b5paper", "b6paper",
94 "c0paper", "c1paper", "c2paper", "c3paper", "c4paper", "c5paper", "c6paper",
95 "b0j", "b1j", "b2j", "b3j", "b4j", "b5j", "b6j", ""
99 static char const * const string_orientation[] = {
100 "portrait", "landscape", ""
104 static char const * const tex_graphics[] = {
105 "default", "dvialw", "dvilaser", "dvipdf", "dvipdfm", "dvipdfmx",
106 "dvips", "dvipsone", "dvitops", "dviwin", "dviwindo", "dvi2ps", "emtex",
107 "ln", "oztex", "pctexhp", "pctexps", "pctexwin", "pctex32", "pdftex",
108 "psprint", "pubps", "tcidvi", "textures", "truetex", "vtex", "xdvi",
118 // Paragraph separation
119 typedef Translator<string, BufferParams::ParagraphSeparation> ParSepTranslator;
122 ParSepTranslator const init_parseptranslator()
124 ParSepTranslator translator
125 (string_paragraph_separation[0], BufferParams::ParagraphIndentSeparation);
126 translator.addPair(string_paragraph_separation[1], BufferParams::ParagraphSkipSeparation);
131 ParSepTranslator const & parseptranslator()
133 static ParSepTranslator const translator =
134 init_parseptranslator();
140 typedef Translator<string, QuoteStyle> QuotesStyleTranslator;
143 QuotesStyleTranslator const init_quotesstyletranslator()
145 QuotesStyleTranslator translator
146 (string_quotes_style[0], QuoteStyle::English);
147 translator.addPair(string_quotes_style[1], QuoteStyle::Swedish);
148 translator.addPair(string_quotes_style[2], QuoteStyle::German);
149 translator.addPair(string_quotes_style[3], QuoteStyle::Polish);
150 translator.addPair(string_quotes_style[4], QuoteStyle::Swiss);
151 translator.addPair(string_quotes_style[5], QuoteStyle::Danish);
152 translator.addPair(string_quotes_style[6], QuoteStyle::Plain);
153 translator.addPair(string_quotes_style[7], QuoteStyle::British);
154 translator.addPair(string_quotes_style[8], QuoteStyle::SwedishG);
155 translator.addPair(string_quotes_style[9], QuoteStyle::French);
156 translator.addPair(string_quotes_style[10], QuoteStyle::FrenchIN);
157 translator.addPair(string_quotes_style[11], QuoteStyle::Russian);
158 translator.addPair(string_quotes_style[12], QuoteStyle::CJK);
159 translator.addPair(string_quotes_style[13], QuoteStyle::CJKAngle);
160 translator.addPair(string_quotes_style[14], QuoteStyle::Hungarian);
165 QuotesStyleTranslator const & quotesstyletranslator()
167 static QuotesStyleTranslator const translator =
168 init_quotesstyletranslator();
174 typedef Translator<string, PAPER_SIZE> PaperSizeTranslator;
177 static PaperSizeTranslator initPaperSizeTranslator()
179 PaperSizeTranslator translator(string_papersize[0], PAPER_DEFAULT);
180 translator.addPair(string_papersize[1], PAPER_CUSTOM);
181 translator.addPair(string_papersize[2], PAPER_USLETTER);
182 translator.addPair(string_papersize[3], PAPER_USLEGAL);
183 translator.addPair(string_papersize[4], PAPER_USEXECUTIVE);
184 translator.addPair(string_papersize[5], PAPER_A0);
185 translator.addPair(string_papersize[6], PAPER_A1);
186 translator.addPair(string_papersize[7], PAPER_A2);
187 translator.addPair(string_papersize[8], PAPER_A3);
188 translator.addPair(string_papersize[9], PAPER_A4);
189 translator.addPair(string_papersize[10], PAPER_A5);
190 translator.addPair(string_papersize[11], PAPER_A6);
191 translator.addPair(string_papersize[12], PAPER_B0);
192 translator.addPair(string_papersize[13], PAPER_B1);
193 translator.addPair(string_papersize[14], PAPER_B2);
194 translator.addPair(string_papersize[15], PAPER_B3);
195 translator.addPair(string_papersize[16], PAPER_B4);
196 translator.addPair(string_papersize[17], PAPER_B5);
197 translator.addPair(string_papersize[18], PAPER_B6);
198 translator.addPair(string_papersize[19], PAPER_C0);
199 translator.addPair(string_papersize[20], PAPER_C1);
200 translator.addPair(string_papersize[21], PAPER_C2);
201 translator.addPair(string_papersize[22], PAPER_C3);
202 translator.addPair(string_papersize[23], PAPER_C4);
203 translator.addPair(string_papersize[24], PAPER_C5);
204 translator.addPair(string_papersize[25], PAPER_C6);
205 translator.addPair(string_papersize[26], PAPER_JISB0);
206 translator.addPair(string_papersize[27], PAPER_JISB1);
207 translator.addPair(string_papersize[28], PAPER_JISB2);
208 translator.addPair(string_papersize[29], PAPER_JISB3);
209 translator.addPair(string_papersize[30], PAPER_JISB4);
210 translator.addPair(string_papersize[31], PAPER_JISB5);
211 translator.addPair(string_papersize[32], PAPER_JISB6);
216 PaperSizeTranslator const & papersizetranslator()
218 static PaperSizeTranslator const translator =
219 initPaperSizeTranslator();
225 typedef Translator<string, PAPER_ORIENTATION> PaperOrientationTranslator;
228 PaperOrientationTranslator const init_paperorientationtranslator()
230 PaperOrientationTranslator translator(string_orientation[0], ORIENTATION_PORTRAIT);
231 translator.addPair(string_orientation[1], ORIENTATION_LANDSCAPE);
236 PaperOrientationTranslator const & paperorientationtranslator()
238 static PaperOrientationTranslator const translator =
239 init_paperorientationtranslator();
245 typedef Translator<int, PageSides> SidesTranslator;
248 SidesTranslator const init_sidestranslator()
250 SidesTranslator translator(1, OneSide);
251 translator.addPair(2, TwoSides);
256 SidesTranslator const & sidestranslator()
258 static SidesTranslator const translator = init_sidestranslator();
264 typedef Translator<int, BufferParams::Package> PackageTranslator;
267 PackageTranslator const init_packagetranslator()
269 PackageTranslator translator(0, BufferParams::package_off);
270 translator.addPair(1, BufferParams::package_auto);
271 translator.addPair(2, BufferParams::package_on);
276 PackageTranslator const & packagetranslator()
278 static PackageTranslator const translator =
279 init_packagetranslator();
285 typedef Translator<string, Spacing::Space> SpaceTranslator;
288 SpaceTranslator const init_spacetranslator()
290 SpaceTranslator translator("default", Spacing::Default);
291 translator.addPair("single", Spacing::Single);
292 translator.addPair("onehalf", Spacing::Onehalf);
293 translator.addPair("double", Spacing::Double);
294 translator.addPair("other", Spacing::Other);
299 SpaceTranslator const & spacetranslator()
301 static SpaceTranslator const translator = init_spacetranslator();
306 bool inSystemDir(FileName const & document_dir, string & system_dir)
308 // A document is assumed to be in a system LyX directory (not
309 // necessarily the system directory of the running instance)
310 // if both "configure.py" and "chkconfig.ltx" are found in
311 // either document_dir/../ or document_dir/../../.
312 // If true, the system directory path is returned in system_dir
313 // with a trailing path separator.
315 string const msg = "Checking whether document is in a system dir...";
317 string dir = document_dir.absFileName();
319 for (int i = 0; i < 3; ++i) {
320 dir = addPath(dir, "..");
321 if (!fileSearch(dir, "configure.py").empty() &&
322 !fileSearch(dir, "chkconfig.ltx").empty()) {
323 LYXERR(Debug::FILES, msg << " yes");
324 system_dir = addPath(FileName(dir).realPath(), "");
329 LYXERR(Debug::FILES, msg << " no");
330 system_dir = string();
337 class BufferParams::Impl
342 AuthorList authorlist;
343 BranchList branchlist;
344 WordLangTable spellignore;
345 Bullet temp_bullets[4];
346 Bullet user_defined_bullets[4];
347 IndicesList indiceslist;
351 /** This is the amount of space used for paragraph_separation "skip",
352 * and for detached paragraphs in "indented" documents.
355 PDFOptions pdfoptions;
356 LayoutFileIndex baseClass_;
357 FormatList exportableFormatList;
358 FormatList viewableFormatList;
359 bool isViewCacheValid;
360 bool isExportCacheValid;
364 BufferParams::Impl::Impl()
365 : defskip(VSpace::MEDSKIP), baseClass_(string("")),
366 isViewCacheValid(false), isExportCacheValid(false)
368 // set initial author
370 authorlist.record(Author(from_utf8(lyxrc.user_name),
371 from_utf8(lyxrc.user_email),
372 from_utf8(lyxrc.user_initials)));
377 BufferParams::MemoryTraits::clone(BufferParams::Impl const * ptr)
380 return new BufferParams::Impl(*ptr);
384 void BufferParams::MemoryTraits::destroy(BufferParams::Impl * ptr)
390 BufferParams::BufferParams()
393 setBaseClass(defaultBaseclass());
394 cite_engine_ = "basic";
395 cite_engine_type_ = ENGINE_TYPE_DEFAULT;
397 paragraph_separation = ParagraphIndentSeparation;
398 is_math_indent = false;
399 math_numbering_side = DEFAULT;
400 quotes_style = QuoteStyle::English;
401 dynamic_quotes = false;
402 fontsize = "default";
405 papersize = PAPER_DEFAULT;
406 orientation = ORIENTATION_PORTRAIT;
407 use_geometry = false;
408 biblio_style = string();
409 use_bibtopic = false;
412 save_transient_properties = true;
413 track_changes = false;
414 output_changes = false;
416 postpone_fragile_content = true;
417 use_default_options = true;
418 maintain_unincluded_children = CM_None;
421 language = default_language;
423 fonts_roman[0] = "default";
424 fonts_roman[1] = "default";
425 fonts_sans[0] = "default";
426 fonts_sans[1] = "default";
427 fonts_typewriter[0] = "default";
428 fonts_typewriter[1] = "default";
429 fonts_math[0] = "auto";
430 fonts_math[1] = "auto";
431 fonts_default_family = "default";
432 useNonTeXFonts = false;
433 use_microtype = false;
434 use_dash_ligatures = true;
435 fonts_expert_sc = false;
436 fonts_roman_osf = false;
437 fonts_sans_osf = false;
438 fonts_typewriter_osf = false;
439 fonts_sans_scale[0] = 100;
440 fonts_sans_scale[1] = 100;
441 fonts_typewriter_scale[0] = 100;
442 fonts_typewriter_scale[1] = 100;
444 lang_package = "default";
445 graphics_driver = "default";
446 default_output_format = "default";
447 bibtex_command = "default";
448 index_command = "default";
451 listings_params = string();
452 pagestyle = "default";
453 tablestyle = "default";
454 float_alignment = "class";
455 float_placement = "class";
456 suppress_date = false;
457 justification = true;
458 // no color is the default (white)
459 backgroundcolor = lyx::rgbFromHexName("#ffffff");
460 isbackgroundcolor = false;
461 // no color is the default (black)
462 fontcolor = lyx::rgbFromHexName("#000000");
464 // light gray is the default font color for greyed-out notes
465 notefontcolor = lyx::rgbFromHexName("#cccccc");
466 isnotefontcolor = false;
467 boxbgcolor = lyx::rgbFromHexName("#ff0000");
468 isboxbgcolor = false;
469 compressed = lyxrc.save_compressed;
470 for (int iter = 0; iter < 4; ++iter) {
471 user_defined_bullet(iter) = ITEMIZE_DEFAULTS[iter];
472 temp_bullet(iter) = ITEMIZE_DEFAULTS[iter];
475 indiceslist().addDefault(B_("Index"));
476 html_be_strict = false;
477 html_math_output = MathML;
478 html_math_img_scale = 1.0;
479 html_css_as_file = false;
480 docbook_table_output = HTMLTable;
481 docbook_mathml_prefix = MPrefix;
482 display_pixel_ratio = 1.0;
484 shell_escape = false;
490 // map current author
491 author_map_[pimpl_->authorlist.get(0).bufferId()] = 0;
495 docstring BufferParams::B_(string const & l10n) const
497 LASSERT(language, return from_utf8(l10n));
498 return getMessages(language->code()).get(l10n);
502 BufferParams::Package BufferParams::use_package(std::string const & p) const
504 PackageMap::const_iterator it = use_packages.find(p);
505 if (it == use_packages.end())
511 void BufferParams::use_package(std::string const & p, BufferParams::Package u)
517 map<string, string> const & BufferParams::auto_packages()
519 static map<string, string> packages;
520 if (packages.empty()) {
521 // We could have a race condition here that two threads
522 // discover an empty map at the same time and want to fill
523 // it, but that is no problem, since the same contents is
524 // filled in twice then. Having the locker inside the
525 // packages.empty() condition has the advantage that we
526 // don't need the mutex overhead for simple reading.
528 Mutex::Locker locker(&mutex);
529 // adding a package here implies a file format change!
530 packages["amsmath"] =
531 N_("The LaTeX package amsmath is only used if AMS formula types or symbols from the AMS math toolbars are inserted into formulas");
532 packages["amssymb"] =
533 N_("The LaTeX package amssymb is only used if symbols from the AMS math toolbars are inserted into formulas");
535 N_("The LaTeX package cancel is only used if \\cancel commands are used in formulas");
537 N_("The LaTeX package esint is only used if special integral symbols are inserted into formulas");
538 packages["mathdots"] =
539 N_("The LaTeX package mathdots is only used if the command \\iddots is inserted into formulas");
540 packages["mathtools"] =
541 N_("The LaTeX package mathtools is only used if some mathematical relations are inserted into formulas");
543 N_("The LaTeX package mhchem is only used if either the command \\ce or \\cf is inserted into formulas");
544 packages["stackrel"] =
545 N_("The LaTeX package stackrel is only used if the command \\stackrel with subscript is inserted into formulas");
546 packages["stmaryrd"] =
547 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");
548 packages["undertilde"] =
549 N_("The LaTeX package undertilde is only used if you use the math frame decoration 'utilde'");
555 bool BufferParams::useBibtopic() const
559 return (use_bibtopic || (!multibib.empty() && multibib != "child"));
563 AuthorList & BufferParams::authors()
565 return pimpl_->authorlist;
569 AuthorList const & BufferParams::authors() const
571 return pimpl_->authorlist;
575 void BufferParams::addAuthor(Author const & a)
577 author_map_[a.bufferId()] = pimpl_->authorlist.record(a);
581 BranchList & BufferParams::branchlist()
583 return pimpl_->branchlist;
587 BranchList const & BufferParams::branchlist() const
589 return pimpl_->branchlist;
593 IndicesList & BufferParams::indiceslist()
595 return pimpl_->indiceslist;
599 IndicesList const & BufferParams::indiceslist() const
601 return pimpl_->indiceslist;
605 WordLangTable & BufferParams::spellignore()
607 return pimpl_->spellignore;
611 WordLangTable const & BufferParams::spellignore() const
613 return pimpl_->spellignore;
617 bool BufferParams::spellignored(WordLangTuple const & wl) const
619 bool has_item = false;
620 vector<WordLangTuple> il = spellignore();
621 vector<WordLangTuple>::const_iterator it = il.begin();
622 for (; it != il.end(); ++it) {
623 if (it->lang()->code() != wl.lang()->code())
625 if (it->word() == wl.word()) {
634 Bullet & BufferParams::temp_bullet(lyx::size_type const index)
636 LASSERT(index < 4, return pimpl_->temp_bullets[0]);
637 return pimpl_->temp_bullets[index];
641 Bullet const & BufferParams::temp_bullet(lyx::size_type const index) const
643 LASSERT(index < 4, return pimpl_->temp_bullets[0]);
644 return pimpl_->temp_bullets[index];
648 Bullet & BufferParams::user_defined_bullet(lyx::size_type const index)
650 LASSERT(index < 4, return pimpl_->temp_bullets[0]);
651 return pimpl_->user_defined_bullets[index];
655 Bullet const & BufferParams::user_defined_bullet(lyx::size_type const index) const
657 LASSERT(index < 4, return pimpl_->temp_bullets[0]);
658 return pimpl_->user_defined_bullets[index];
662 Spacing & BufferParams::spacing()
664 return pimpl_->spacing;
668 Spacing const & BufferParams::spacing() const
670 return pimpl_->spacing;
674 PDFOptions & BufferParams::pdfoptions()
676 return pimpl_->pdfoptions;
680 PDFOptions const & BufferParams::pdfoptions() const
682 return pimpl_->pdfoptions;
686 Length const & BufferParams::getMathIndent() const
688 return pimpl_->mathindent;
692 void BufferParams::setMathIndent(Length const & indent)
694 pimpl_->mathindent = indent;
698 Length const & BufferParams::getParIndent() const
700 return pimpl_->parindent;
704 void BufferParams::setParIndent(Length const & indent)
706 pimpl_->parindent = indent;
710 VSpace const & BufferParams::getDefSkip() const
712 return pimpl_->defskip;
716 void BufferParams::setDefSkip(VSpace const & vs)
718 // DEFSKIP will cause an infinite loop
719 LASSERT(vs.kind() != VSpace::DEFSKIP, return);
720 pimpl_->defskip = vs;
724 BufferParams::MathNumber BufferParams::getMathNumber() const
726 if (math_numbering_side != DEFAULT)
727 return math_numbering_side;
728 // FIXME: do not hardcode language here
729 else if (language->lang() == "arabic_arabi"
730 || documentClass().provides("leqno"))
737 string BufferParams::readToken(Lexer & lex, string const & token,
738 FileName const & filename)
741 FileName const & filepath = filename.onlyPath();
743 if (token == "\\textclass") {
745 string const classname = lex.getString();
746 // if there exists a local layout file, ignore the system one
747 // NOTE: in this case, the textclass (.cls file) is assumed to
750 LayoutFileList & bcl = LayoutFileList::get();
751 if (!filepath.empty()) {
752 // If classname is an absolute path, the document is
753 // using a local layout file which could not be accessed
754 // by a relative path. In this case the path is correct
755 // even if the document was moved to a different
756 // location. However, we will have a problem if the
757 // document was generated on a different platform.
758 bool isabsolute = FileName::isAbsolute(classname);
759 string const classpath = onlyPath(classname);
760 string const path = isabsolute ? classpath
761 : FileName(addPath(filepath.absFileName(),
762 classpath)).realPath();
763 string const oldpath = isabsolute ? string()
764 : FileName(addPath(origin, classpath)).realPath();
765 tcp = bcl.addLocalLayout(onlyFileName(classname), path, oldpath);
767 // that returns non-empty if a "local" layout file is found.
769 result = to_utf8(makeRelPath(from_utf8(onlyPath(tcp)),
770 from_utf8(filepath.absFileName())));
773 setBaseClass(onlyFileName(tcp));
775 setBaseClass(onlyFileName(classname));
776 // We assume that a tex class exists for local or unknown
777 // layouts so this warning, will only be given for system layouts.
778 if (!baseClass()->isTeXClassAvailable()) {
779 docstring const desc =
780 translateIfPossible(from_utf8(baseClass()->description()));
781 docstring const prereqs =
782 from_utf8(baseClass()->prerequisites());
783 docstring const msg =
784 bformat(_("The selected document class\n"
786 "requires external files that are not available.\n"
787 "The document class can still be used, but the\n"
788 "document cannot be compiled until the following\n"
789 "prerequisites are installed:\n"
791 "See section 3.1.2.2 (Class Availability) of the\n"
792 "User's Guide for more information."), desc, prereqs);
793 frontend::Alert::warning(_("Document class not available"),
796 } else if (token == "\\save_transient_properties") {
797 lex >> save_transient_properties;
798 } else if (token == "\\origin") {
800 origin = lex.getString();
801 string const sysdirprefix = "/systemlyxdir/";
802 if (prefixIs(origin, sysdirprefix)) {
804 if (inSystemDir(filepath, docsys))
805 origin.replace(0, sysdirprefix.length() - 1, docsys);
807 origin.replace(0, sysdirprefix.length() - 1,
808 package().system_support().absFileName());
810 } else if (token == "\\begin_preamble") {
812 } else if (token == "\\begin_local_layout") {
813 readLocalLayout(lex, false);
814 } else if (token == "\\begin_forced_local_layout") {
815 readLocalLayout(lex, true);
816 } else if (token == "\\begin_modules") {
818 } else if (token == "\\begin_removed_modules") {
819 readRemovedModules(lex);
820 } else if (token == "\\begin_includeonly") {
821 readIncludeonly(lex);
822 } else if (token == "\\maintain_unincluded_children") {
826 maintain_unincluded_children = CM_None;
827 else if (tmp == "mostly")
828 maintain_unincluded_children = CM_Mostly;
829 else if (tmp == "strict")
830 maintain_unincluded_children = CM_Strict;
831 } else if (token == "\\options") {
833 options = lex.getString();
834 } else if (token == "\\use_default_options") {
835 lex >> use_default_options;
836 } else if (token == "\\master") {
838 master = lex.getString();
839 if (!filepath.empty() && FileName::isAbsolute(origin)) {
840 bool const isabs = FileName::isAbsolute(master);
841 FileName const abspath(isabs ? master : origin + master);
842 bool const moved = filepath != FileName(origin);
843 if (moved && abspath.exists()) {
844 docstring const path = isabs
846 : from_utf8(abspath.realPath());
847 docstring const refpath =
848 from_utf8(filepath.absFileName());
849 master = to_utf8(makeRelPath(path, refpath));
852 } else if (token == "\\suppress_date") {
853 lex >> suppress_date;
854 } else if (token == "\\justification") {
855 lex >> justification;
856 } else if (token == "\\language") {
858 } else if (token == "\\language_package") {
860 lang_package = lex.getString();
861 } else if (token == "\\inputencoding") {
863 } else if (token == "\\graphics") {
864 readGraphicsDriver(lex);
865 } else if (token == "\\default_output_format") {
866 lex >> default_output_format;
867 } else if (token == "\\bibtex_command") {
869 bibtex_command = lex.getString();
870 } else if (token == "\\index_command") {
872 index_command = lex.getString();
873 } else if (token == "\\fontencoding") {
875 fontenc = lex.getString();
876 } else if (token == "\\font_roman") {
877 lex >> fonts_roman[0];
878 lex >> fonts_roman[1];
879 } else if (token == "\\font_sans") {
880 lex >> fonts_sans[0];
881 lex >> fonts_sans[1];
882 } else if (token == "\\font_typewriter") {
883 lex >> fonts_typewriter[0];
884 lex >> fonts_typewriter[1];
885 } else if (token == "\\font_math") {
886 lex >> fonts_math[0];
887 lex >> fonts_math[1];
888 } else if (token == "\\font_default_family") {
889 lex >> fonts_default_family;
890 } else if (token == "\\use_non_tex_fonts") {
891 lex >> useNonTeXFonts;
892 } else if (token == "\\font_sc") {
893 lex >> fonts_expert_sc;
894 } else if (token == "\\font_roman_osf") {
895 lex >> fonts_roman_osf;
896 } else if (token == "\\font_sans_osf") {
897 lex >> fonts_sans_osf;
898 } else if (token == "\\font_typewriter_osf") {
899 lex >> fonts_typewriter_osf;
900 } else if (token == "\\font_roman_opts") {
901 lex >> font_roman_opts;
902 } else if (token == "\\font_sf_scale") {
903 lex >> fonts_sans_scale[0];
904 lex >> fonts_sans_scale[1];
905 } else if (token == "\\font_sans_opts") {
906 lex >> font_sans_opts;
907 } else if (token == "\\font_tt_scale") {
908 lex >> fonts_typewriter_scale[0];
909 lex >> fonts_typewriter_scale[1];
910 } else if (token == "\\font_typewriter_opts") {
911 lex >> font_typewriter_opts;
912 } else if (token == "\\font_cjk") {
914 } else if (token == "\\use_microtype") {
915 lex >> use_microtype;
916 } else if (token == "\\use_dash_ligatures") {
917 lex >> use_dash_ligatures;
918 } else if (token == "\\paragraph_separation") {
921 paragraph_separation = parseptranslator().find(parsep);
922 } else if (token == "\\paragraph_indentation") {
924 string parindent = lex.getString();
925 if (parindent == "default")
926 pimpl_->parindent = Length();
928 pimpl_->parindent = Length(parindent);
929 } else if (token == "\\defskip") {
931 string const defskip = lex.getString();
932 pimpl_->defskip = VSpace(defskip);
933 if (pimpl_->defskip.kind() == VSpace::DEFSKIP)
935 pimpl_->defskip = VSpace(VSpace::MEDSKIP);
936 } else if (token == "\\is_math_indent") {
937 lex >> is_math_indent;
938 } else if (token == "\\math_indentation") {
940 string mathindent = lex.getString();
941 if (mathindent == "default")
942 pimpl_->mathindent = Length();
944 pimpl_->mathindent = Length(mathindent);
945 } else if (token == "\\math_numbering_side") {
949 math_numbering_side = LEFT;
950 else if (tmp == "right")
951 math_numbering_side = RIGHT;
953 math_numbering_side = DEFAULT;
954 } else if (token == "\\quotes_style") {
957 quotes_style = quotesstyletranslator().find(qstyle);
958 } else if (token == "\\dynamic_quotes") {
959 lex >> dynamic_quotes;
960 } else if (token == "\\papersize") {
963 papersize = papersizetranslator().find(ppsize);
964 } else if (token == "\\use_geometry") {
966 } else if (token == "\\use_package") {
971 use_package(package, packagetranslator().find(use));
972 } else if (token == "\\cite_engine") {
974 cite_engine_ = lex.getString();
975 } else if (token == "\\cite_engine_type") {
978 cite_engine_type_ = theCiteEnginesList.getType(engine_type);
979 } else if (token == "\\biblio_style") {
981 biblio_style = lex.getString();
982 } else if (token == "\\biblio_options") {
984 biblio_opts = trim(lex.getString());
985 } else if (token == "\\biblatex_bibstyle") {
987 biblatex_bibstyle = trim(lex.getString());
988 } else if (token == "\\biblatex_citestyle") {
990 biblatex_citestyle = trim(lex.getString());
991 } else if (token == "\\use_bibtopic") {
993 } else if (token == "\\multibib") {
995 } else if (token == "\\use_indices") {
997 } else if (token == "\\tracking_changes") {
998 lex >> track_changes;
999 } else if (token == "\\output_changes") {
1000 lex >> output_changes;
1001 } else if (token == "\\change_bars") {
1003 } else if (token == "\\postpone_fragile_content") {
1004 lex >> postpone_fragile_content;
1005 } else if (token == "\\branch") {
1007 docstring branch = lex.getDocString();
1008 branchlist().add(branch);
1011 string const tok = lex.getString();
1012 if (tok == "\\end_branch")
1014 Branch * branch_ptr = branchlist().find(branch);
1015 if (tok == "\\selected") {
1018 branch_ptr->setSelected(lex.getInteger());
1020 if (tok == "\\filename_suffix") {
1023 branch_ptr->setFileNameSuffix(lex.getInteger());
1025 if (tok == "\\color") {
1027 vector<string> const colors = getVectorFromString(lex.getString(), " ");
1028 string const lmcolor = colors.front();
1030 if (colors.size() > 1)
1031 dmcolor = colors.back();
1033 branch_ptr->setColors(lmcolor, dmcolor);
1036 } else if (token == "\\index") {
1038 docstring index = lex.getDocString();
1040 indiceslist().add(index);
1043 string const tok = lex.getString();
1044 if (tok == "\\end_index")
1046 Index * index_ptr = indiceslist().find(index);
1047 if (tok == "\\shortcut") {
1049 shortcut = lex.getDocString();
1051 index_ptr->setShortcut(shortcut);
1053 if (tok == "\\color") {
1055 string color = lex.getString();
1057 index_ptr->setColor(color);
1058 // Update also the Color table:
1059 if (color == "none")
1060 color = lcolor.getX11HexName(Color_background);
1062 if (!shortcut.empty())
1063 lcolor.setColor(to_utf8(shortcut)+ "@" + filename.absFileName(), color);
1066 } else if (token == "\\spellchecker_ignore") {
1068 docstring wl = lex.getDocString();
1070 docstring word = split(wl, language, ' ');
1071 Language const * lang = languages.getLanguage(to_ascii(language));
1073 spellignore().push_back(WordLangTuple(word, lang));
1074 } else if (token == "\\author") {
1076 istringstream ss(lex.getString());
1080 } else if (token == "\\paperorientation") {
1083 orientation = paperorientationtranslator().find(orient);
1084 } else if (token == "\\backgroundcolor") {
1086 backgroundcolor = lyx::rgbFromHexName(lex.getString());
1087 isbackgroundcolor = true;
1088 } else if (token == "\\fontcolor") {
1090 fontcolor = lyx::rgbFromHexName(lex.getString());
1092 } else if (token == "\\notefontcolor") {
1094 string color = lex.getString();
1095 notefontcolor = lyx::rgbFromHexName(color);
1096 lcolor.setColor("notefontcolor", color);
1097 lcolor.setLaTeXName("notefontcolor", "note_fontcolor");
1098 lcolor.setGUIName("notefontcolor", N_("greyedout inset text"));
1099 // set a local name for the painter
1100 lcolor.setColor("notefontcolor@" + filename.absFileName(), color);
1101 isnotefontcolor = true;
1102 } else if (token == "\\boxbgcolor") {
1104 string color = lex.getString();
1105 boxbgcolor = lyx::rgbFromHexName(color);
1106 lcolor.setColor("boxbgcolor@" + filename.absFileName(), color);
1107 isboxbgcolor = true;
1108 } else if (token == "\\paperwidth") {
1110 } else if (token == "\\paperheight") {
1112 } else if (token == "\\leftmargin") {
1114 } else if (token == "\\topmargin") {
1116 } else if (token == "\\rightmargin") {
1118 } else if (token == "\\bottommargin") {
1119 lex >> bottommargin;
1120 } else if (token == "\\headheight") {
1122 } else if (token == "\\headsep") {
1124 } else if (token == "\\footskip") {
1126 } else if (token == "\\columnsep") {
1128 } else if (token == "\\paperfontsize") {
1130 } else if (token == "\\papercolumns") {
1132 } else if (token == "\\listings_params") {
1135 listings_params = InsetListingsParams(par).params();
1136 } else if (token == "\\papersides") {
1139 sides = sidestranslator().find(psides);
1140 } else if (token == "\\paperpagestyle") {
1142 } else if (token == "\\tablestyle") {
1144 } else if (token == "\\bullet") {
1146 } else if (token == "\\bulletLaTeX") {
1147 readBulletsLaTeX(lex);
1148 } else if (token == "\\secnumdepth") {
1150 } else if (token == "\\tocdepth") {
1152 } else if (token == "\\spacing") {
1156 if (nspacing == "other") {
1159 spacing().set(spacetranslator().find(nspacing), tmp_val);
1160 } else if (token == "\\float_placement") {
1161 lex >> float_placement;
1162 } else if (token == "\\float_alignment") {
1163 lex >> float_alignment;
1165 } else if (prefixIs(token, "\\pdf_") || token == "\\use_hyperref") {
1166 string toktmp = pdfoptions().readToken(lex, token);
1167 if (!toktmp.empty()) {
1168 lyxerr << "PDFOptions::readToken(): Unknown token: " <<
1172 } else if (token == "\\html_math_output") {
1175 html_math_output = static_cast<MathOutput>(temp);
1176 } else if (token == "\\html_be_strict") {
1177 lex >> html_be_strict;
1178 } else if (token == "\\html_css_as_file") {
1179 lex >> html_css_as_file;
1180 } else if (token == "\\html_math_img_scale") {
1181 lex >> html_math_img_scale;
1182 } else if (token == "\\html_latex_start") {
1184 html_latex_start = lex.getString();
1185 } else if (token == "\\html_latex_end") {
1187 html_latex_end = lex.getString();
1188 } else if (token == "\\docbook_table_output") {
1191 docbook_table_output = static_cast<TableOutput>(temp);
1192 } else if (token == "\\docbook_mathml_prefix") {
1195 docbook_mathml_prefix = static_cast<MathMLNameSpacePrefix>(temp);
1196 } else if (token == "\\output_sync") {
1198 } else if (token == "\\output_sync_macro") {
1199 lex >> output_sync_macro;
1200 } else if (token == "\\use_refstyle") {
1201 lex >> use_refstyle;
1202 } else if (token == "\\use_minted") {
1204 } else if (token == "\\use_lineno") {
1206 } else if (token == "\\lineno_options") {
1208 lineno_opts = trim(lex.getString());
1210 lyxerr << "BufferParams::readToken(): Unknown token: " <<
1220 // Quote argument if it contains spaces
1221 string quoteIfNeeded(string const & str) {
1222 if (contains(str, ' '))
1223 return "\"" + str + "\"";
1229 void BufferParams::writeFile(ostream & os, Buffer const * buf) const
1231 // The top of the file is written by the buffer.
1232 // Prints out the buffer info into the .lyx file given by file
1234 os << "\\save_transient_properties "
1235 << convert<string>(save_transient_properties) << '\n';
1237 // the document directory (must end with a path separator)
1238 // realPath() is used to resolve symlinks, while addPath(..., "")
1239 // ensures a trailing path separator.
1241 string filepath = addPath(buf->fileName().onlyPath().realPath(), "");
1242 string const sysdir = inSystemDir(FileName(filepath), docsys) ? docsys
1243 : addPath(package().system_support().realPath(), "");
1244 string const relpath =
1245 to_utf8(makeRelPath(from_utf8(filepath), from_utf8(sysdir)));
1246 if (!prefixIs(relpath, "../") && !FileName::isAbsolute(relpath))
1247 filepath = addPath("/systemlyxdir", relpath);
1248 else if (!save_transient_properties || !lyxrc.save_origin)
1249 filepath = "unavailable";
1250 os << "\\origin " << quoteIfNeeded(filepath) << '\n';
1253 os << "\\textclass "
1254 << quoteIfNeeded(buf->includedFilePath(addName(buf->layoutPos(),
1255 baseClass()->name()), "layout"))
1258 // then the preamble
1259 if (!preamble.empty()) {
1260 // remove '\n' from the end of preamble
1261 docstring const tmppreamble = rtrim(preamble, "\n");
1262 os << "\\begin_preamble\n"
1263 << to_utf8(tmppreamble)
1264 << "\n\\end_preamble\n";
1268 if (!options.empty()) {
1269 os << "\\options " << options << '\n';
1272 // use the class options defined in the layout?
1273 os << "\\use_default_options "
1274 << convert<string>(use_default_options) << "\n";
1276 // the master document
1277 if (!master.empty()) {
1278 os << "\\master " << master << '\n';
1282 if (!removed_modules_.empty()) {
1283 os << "\\begin_removed_modules" << '\n';
1284 for (auto const & mod : removed_modules_)
1286 os << "\\end_removed_modules" << '\n';
1290 if (!layout_modules_.empty()) {
1291 os << "\\begin_modules" << '\n';
1292 for (auto const & mod : layout_modules_)
1294 os << "\\end_modules" << '\n';
1298 if (!included_children_.empty()) {
1299 os << "\\begin_includeonly" << '\n';
1300 for (auto const & c : included_children_)
1302 os << "\\end_includeonly" << '\n';
1305 switch (maintain_unincluded_children) {
1316 os << "\\maintain_unincluded_children " << muc << '\n';
1318 // local layout information
1319 docstring const local_layout = getLocalLayout(false);
1320 if (!local_layout.empty()) {
1321 // remove '\n' from the end
1322 docstring const tmplocal = rtrim(local_layout, "\n");
1323 os << "\\begin_local_layout\n"
1324 << to_utf8(tmplocal)
1325 << "\n\\end_local_layout\n";
1327 docstring const forced_local_layout = getLocalLayout(true);
1328 if (!forced_local_layout.empty()) {
1329 // remove '\n' from the end
1330 docstring const tmplocal = rtrim(forced_local_layout, "\n");
1331 os << "\\begin_forced_local_layout\n"
1332 << to_utf8(tmplocal)
1333 << "\n\\end_forced_local_layout\n";
1336 // then the text parameters
1337 if (language != ignore_language)
1338 os << "\\language " << language->lang() << '\n';
1339 os << "\\language_package " << lang_package
1340 << "\n\\inputencoding " << inputenc
1341 << "\n\\fontencoding " << fontenc
1342 << "\n\\font_roman \"" << fonts_roman[0]
1343 << "\" \"" << fonts_roman[1] << '"'
1344 << "\n\\font_sans \"" << fonts_sans[0]
1345 << "\" \"" << fonts_sans[1] << '"'
1346 << "\n\\font_typewriter \"" << fonts_typewriter[0]
1347 << "\" \"" << fonts_typewriter[1] << '"'
1348 << "\n\\font_math \"" << fonts_math[0]
1349 << "\" \"" << fonts_math[1] << '"'
1350 << "\n\\font_default_family " << fonts_default_family
1351 << "\n\\use_non_tex_fonts " << convert<string>(useNonTeXFonts)
1352 << "\n\\font_sc " << convert<string>(fonts_expert_sc)
1353 << "\n\\font_roman_osf " << convert<string>(fonts_roman_osf)
1354 << "\n\\font_sans_osf " << convert<string>(fonts_sans_osf)
1355 << "\n\\font_typewriter_osf " << convert<string>(fonts_typewriter_osf);
1356 if (!font_roman_opts.empty())
1357 os << "\n\\font_roman_opts \"" << font_roman_opts << "\"";
1358 os << "\n\\font_sf_scale " << fonts_sans_scale[0]
1359 << ' ' << fonts_sans_scale[1];
1360 if (!font_sans_opts.empty())
1361 os << "\n\\font_sans_opts \"" << font_sans_opts << "\"";
1362 os << "\n\\font_tt_scale " << fonts_typewriter_scale[0]
1363 << ' ' << fonts_typewriter_scale[1];
1364 if (!font_typewriter_opts.empty())
1365 os << "\n\\font_typewriter_opts \"" << font_typewriter_opts << "\"";
1367 if (!fonts_cjk.empty())
1368 os << "\\font_cjk " << fonts_cjk << '\n';
1369 os << "\\use_microtype " << convert<string>(use_microtype) << '\n';
1370 os << "\\use_dash_ligatures " << convert<string>(use_dash_ligatures) << '\n';
1371 os << "\\graphics " << graphics_driver << '\n';
1372 os << "\\default_output_format " << default_output_format << '\n';
1373 os << "\\output_sync " << output_sync << '\n';
1374 if (!output_sync_macro.empty())
1375 os << "\\output_sync_macro \"" << output_sync_macro << "\"\n";
1376 os << "\\bibtex_command " << bibtex_command << '\n';
1377 os << "\\index_command " << index_command << '\n';
1379 if (!float_placement.empty())
1380 os << "\\float_placement " << float_placement << '\n';
1381 if (!float_alignment.empty())
1382 os << "\\float_alignment " << float_alignment << '\n';
1383 os << "\\paperfontsize " << fontsize << '\n';
1385 spacing().writeFile(os);
1386 pdfoptions().writeFile(os);
1388 os << "\\papersize " << string_papersize[papersize]
1389 << "\n\\use_geometry " << convert<string>(use_geometry);
1390 map<string, string> const & packages = auto_packages();
1391 for (auto const & pack : packages)
1392 os << "\n\\use_package " << pack.first << ' '
1393 << use_package(pack.first);
1395 os << "\n\\cite_engine ";
1397 if (!cite_engine_.empty())
1402 os << "\n\\cite_engine_type " << theCiteEnginesList.getTypeAsString(cite_engine_type_);
1404 if (!biblio_style.empty())
1405 os << "\n\\biblio_style " << biblio_style;
1406 if (!biblio_opts.empty())
1407 os << "\n\\biblio_options " << biblio_opts;
1408 if (!biblatex_bibstyle.empty())
1409 os << "\n\\biblatex_bibstyle " << biblatex_bibstyle;
1410 if (!biblatex_citestyle.empty())
1411 os << "\n\\biblatex_citestyle " << biblatex_citestyle;
1412 if (!multibib.empty())
1413 os << "\n\\multibib " << multibib;
1415 os << "\n\\use_bibtopic " << convert<string>(use_bibtopic)
1416 << "\n\\use_indices " << convert<string>(use_indices)
1417 << "\n\\paperorientation " << string_orientation[orientation]
1418 << "\n\\suppress_date " << convert<string>(suppress_date)
1419 << "\n\\justification " << convert<string>(justification)
1420 << "\n\\use_refstyle " << use_refstyle
1421 << "\n\\use_minted " << use_minted
1422 << "\n\\use_lineno " << use_lineno
1425 if (!lineno_opts.empty())
1426 os << "\\lineno_options " << lineno_opts << '\n';
1428 if (isbackgroundcolor)
1429 os << "\\backgroundcolor " << lyx::X11hexname(backgroundcolor) << '\n';
1431 os << "\\fontcolor " << lyx::X11hexname(fontcolor) << '\n';
1432 if (isnotefontcolor)
1433 os << "\\notefontcolor " << lyx::X11hexname(notefontcolor) << '\n';
1435 os << "\\boxbgcolor " << lyx::X11hexname(boxbgcolor) << '\n';
1437 for (auto const & br : branchlist()) {
1438 os << "\\branch " << to_utf8(br.branch())
1439 << "\n\\selected " << br.isSelected()
1440 << "\n\\filename_suffix " << br.hasFileNameSuffix()
1441 << "\n\\color " << br.lightModeColor() << " " << br.darkModeColor()
1446 for (auto const & id : indiceslist()) {
1447 os << "\\index " << to_utf8(id.index())
1448 << "\n\\shortcut " << to_utf8(id.shortcut())
1449 << "\n\\color " << lyx::X11hexname(id.color())
1454 for (auto const & si : spellignore()) {
1455 os << "\\spellchecker_ignore " << si.lang()->lang()
1456 << " " << to_utf8(si.word())
1460 if (!paperwidth.empty())
1461 os << "\\paperwidth "
1462 << VSpace(paperwidth).asLyXCommand() << '\n';
1463 if (!paperheight.empty())
1464 os << "\\paperheight "
1465 << VSpace(paperheight).asLyXCommand() << '\n';
1466 if (!leftmargin.empty())
1467 os << "\\leftmargin "
1468 << VSpace(leftmargin).asLyXCommand() << '\n';
1469 if (!topmargin.empty())
1470 os << "\\topmargin "
1471 << VSpace(topmargin).asLyXCommand() << '\n';
1472 if (!rightmargin.empty())
1473 os << "\\rightmargin "
1474 << VSpace(rightmargin).asLyXCommand() << '\n';
1475 if (!bottommargin.empty())
1476 os << "\\bottommargin "
1477 << VSpace(bottommargin).asLyXCommand() << '\n';
1478 if (!headheight.empty())
1479 os << "\\headheight "
1480 << VSpace(headheight).asLyXCommand() << '\n';
1481 if (!headsep.empty())
1483 << VSpace(headsep).asLyXCommand() << '\n';
1484 if (!footskip.empty())
1486 << VSpace(footskip).asLyXCommand() << '\n';
1487 if (!columnsep.empty())
1488 os << "\\columnsep "
1489 << VSpace(columnsep).asLyXCommand() << '\n';
1490 os << "\\secnumdepth " << secnumdepth
1491 << "\n\\tocdepth " << tocdepth
1492 << "\n\\paragraph_separation "
1493 << string_paragraph_separation[paragraph_separation];
1494 if (!paragraph_separation)
1495 os << "\n\\paragraph_indentation "
1496 << (getParIndent().empty() ? "default" : getParIndent().asString());
1498 os << "\n\\defskip " << getDefSkip().asLyXCommand();
1499 os << "\n\\is_math_indent " << is_math_indent;
1501 os << "\n\\math_indentation "
1502 << (getMathIndent().empty() ? "default" : getMathIndent().asString());
1503 os << "\n\\math_numbering_side ";
1504 switch(math_numbering_side) {
1514 os << "\n\\quotes_style "
1515 << string_quotes_style[static_cast<int>(quotes_style)]
1516 << "\n\\dynamic_quotes " << dynamic_quotes
1517 << "\n\\papercolumns " << columns
1518 << "\n\\papersides " << sides
1519 << "\n\\paperpagestyle " << pagestyle
1520 << "\n\\tablestyle " << tablestyle << '\n';
1521 if (!listings_params.empty())
1522 os << "\\listings_params \"" <<
1523 InsetListingsParams(listings_params).encodedString() << "\"\n";
1524 for (int i = 0; i < 4; ++i) {
1525 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
1526 if (user_defined_bullet(i).getFont() != -1) {
1527 os << "\\bullet " << i << " "
1528 << user_defined_bullet(i).getFont() << " "
1529 << user_defined_bullet(i).getCharacter() << " "
1530 << user_defined_bullet(i).getSize() << "\n";
1534 os << "\\bulletLaTeX " << i << " \""
1535 << lyx::to_ascii(user_defined_bullet(i).getText())
1541 os << "\\tracking_changes "
1542 << (save_transient_properties ? convert<string>(track_changes) : "false")
1545 os << "\\output_changes "
1546 << (save_transient_properties ? convert<string>(output_changes) : "false")
1549 os << "\\change_bars "
1550 << (save_transient_properties ? convert<string>(change_bars) : "false")
1553 os << "\\postpone_fragile_content " << convert<string>(postpone_fragile_content) << '\n';
1555 os << "\\html_math_output " << html_math_output << '\n'
1556 << "\\html_css_as_file " << html_css_as_file << '\n'
1557 << "\\html_be_strict " << convert<string>(html_be_strict) << '\n';
1559 os << "\\docbook_table_output " << docbook_table_output << '\n';
1560 os << "\\docbook_mathml_prefix " << docbook_mathml_prefix << '\n';
1562 if (html_math_img_scale != 1.0)
1563 os << "\\html_math_img_scale " << convert<string>(html_math_img_scale) << '\n';
1564 if (!html_latex_start.empty())
1565 os << "\\html_latex_start " << html_latex_start << '\n';
1566 if (!html_latex_end.empty())
1567 os << "\\html_latex_end " << html_latex_end << '\n';
1569 os << pimpl_->authorlist;
1573 void BufferParams::validate(LaTeXFeatures & features) const
1575 features.require(documentClass().required());
1577 if (columns > 1 && language->rightToLeft())
1578 features.require("rtloutputdblcol");
1580 if (output_changes) {
1581 bool xcolorulem = LaTeXFeatures::isAvailable("ulem") &&
1582 LaTeXFeatures::isAvailable("xcolor");
1584 switch (features.runparams().flavor) {
1586 case Flavor::DviLuaTeX:
1588 features.require("ct-xcolor-ulem");
1589 features.require("ulem");
1590 features.require("xcolor");
1592 features.require("ct-none");
1595 case Flavor::LuaTeX:
1596 case Flavor::PdfLaTeX:
1599 features.require("ct-xcolor-ulem");
1600 features.require("ulem");
1601 features.require("xcolor");
1602 // improves color handling in PDF output
1603 features.require("pdfcolmk");
1605 features.require("ct-none");
1612 features.require("changebar");
1615 // Floats with 'Here definitely' as default setting.
1616 if (float_placement.find('H') != string::npos)
1617 features.require("float");
1619 for (auto const & pm : use_packages) {
1620 if (pm.first == "amsmath") {
1621 // AMS Style is at document level
1622 if (pm.second == package_on ||
1623 features.isProvided("amsmath"))
1624 features.require(pm.first);
1625 } else if (pm.second == package_on)
1626 features.require(pm.first);
1629 // Document-level line spacing
1630 if (spacing().getSpace() != Spacing::Single && !spacing().isDefault())
1631 features.require("setspace");
1633 // the bullet shapes are buffer level not paragraph level
1634 // so they are tested here
1635 for (int i = 0; i < 4; ++i) {
1636 if (user_defined_bullet(i) == ITEMIZE_DEFAULTS[i])
1638 int const font = user_defined_bullet(i).getFont();
1640 int const c = user_defined_bullet(i).getCharacter();
1646 features.require("latexsym");
1648 } else if (font == 1) {
1649 features.require("amssymb");
1650 } else if (font >= 2 && font <= 5) {
1651 features.require("pifont");
1655 if (pdfoptions().use_hyperref) {
1656 features.require("hyperref");
1657 // due to interferences with babel and hyperref, the color package has to
1658 // be loaded after hyperref when hyperref is used with the colorlinks
1659 // option, see http://www.lyx.org/trac/ticket/5291
1660 if (pdfoptions().colorlinks)
1661 features.require("color");
1663 if (!listings_params.empty()) {
1664 // do not test validity because listings_params is
1665 // supposed to be valid
1667 InsetListingsParams(listings_params).separatedParams(true);
1668 // we can't support all packages, but we should load the color package
1669 if (par.find("\\color", 0) != string::npos)
1670 features.require("color");
1673 // some languages are only available via polyglossia
1674 if (features.hasPolyglossiaExclusiveLanguages())
1675 features.require("polyglossia");
1677 if (useNonTeXFonts && fontsMath() != "auto")
1678 features.require("unicode-math");
1681 features.require("microtype");
1683 if (!language->required().empty())
1684 features.require(language->required());
1688 bool BufferParams::writeLaTeX(otexstream & os, LaTeXFeatures & features,
1689 FileName const & filepath) const
1691 // http://www.tug.org/texmf-dist/doc/latex/base/fixltx2e.pdf
1692 // !! To use the Fix-cm package, load it before \documentclass, and use the command
1693 // \RequirePackage to do so, rather than the normal \usepackage
1694 // Do not try to load any other package before the document class, unless you
1695 // have a thorough understanding of the LATEX internals and know exactly what you
1697 if (features.mustProvide("fix-cm"))
1698 os << "\\RequirePackage{fix-cm}\n";
1699 // Likewise for fixltx2e. If other packages conflict with this policy,
1700 // treat it as a package bug (and report it!)
1701 // See http://www.latex-project.org/cgi-bin/ltxbugs2html?pr=latex/4407
1702 if (features.mustProvide("fixltx2e"))
1703 os << "\\RequirePackage{fixltx2e}\n";
1705 os << "\\documentclass";
1707 DocumentClass const & tclass = documentClass();
1709 ostringstream clsoptions; // the document class options.
1711 if (tokenPos(tclass.opt_fontsize(),
1712 '|', fontsize) >= 0) {
1713 // only write if existing in list (and not default)
1714 clsoptions << subst(tclass.fontsizeformat(), "$$s", fontsize) << ",";
1717 // paper sizes not supported by the class itself need the
1719 vector<string> classpsizes = getVectorFromString(tclass.opt_pagesize(), "|");
1720 bool class_supported_papersize = papersize == PAPER_DEFAULT
1721 || find(classpsizes.begin(), classpsizes.end(), string_papersize[papersize]) != classpsizes.end();
1723 if ((!use_geometry || features.isProvided("geometry-light"))
1724 && class_supported_papersize && papersize != PAPER_DEFAULT)
1725 clsoptions << subst(tclass.pagesizeformat(), "$$s", string_papersize[papersize]) << ",";
1728 if (sides != tclass.sides()) {
1731 clsoptions << "oneside,";
1734 clsoptions << "twoside,";
1740 if (columns != tclass.columns()) {
1742 clsoptions << "twocolumn,";
1744 clsoptions << "onecolumn,";
1748 && orientation == ORIENTATION_LANDSCAPE)
1749 clsoptions << "landscape,";
1752 clsoptions << "fleqn,";
1754 switch(math_numbering_side) {
1756 clsoptions << "leqno,";
1759 clsoptions << "reqno,";
1760 features.require("amsmath");
1766 // language should be a parameter to \documentclass
1767 if (language->babel() == "hebrew"
1768 && default_language->babel() != "hebrew")
1769 // This seems necessary
1770 features.useLanguage(default_language);
1772 ostringstream language_options;
1773 bool const use_babel = features.useBabel() && !features.isProvided("babel");
1774 bool const use_polyglossia = features.usePolyglossia();
1775 bool const global = lyxrc.language_global_options;
1776 if (features.useBabel() || (use_polyglossia && global)) {
1777 language_options << features.getBabelLanguages();
1778 if (!language->babel().empty()) {
1779 if (!language_options.str().empty())
1780 language_options << ',';
1781 language_options << language->babel();
1783 if (global && !language_options.str().empty())
1784 clsoptions << language_options.str() << ',';
1787 // the predefined options from the layout
1788 if (use_default_options && !tclass.options().empty())
1789 clsoptions << tclass.options() << ',';
1791 // the user-defined options
1792 if (!options.empty()) {
1793 clsoptions << options << ',';
1796 docstring const strOptions = from_utf8(clsoptions.str());
1797 if (!strOptions.empty()) {
1798 // Check if class options contain uncodable glyphs
1799 docstring uncodable_glyphs;
1800 docstring options_encodable;
1801 Encoding const * const enc = features.runparams().encoding;
1803 for (char_type c : strOptions) {
1804 if (!enc->encodable(c)) {
1805 docstring const glyph(1, c);
1806 LYXERR0("Uncodable character '"
1808 << "' in class options!");
1809 uncodable_glyphs += glyph;
1810 if (features.runparams().dryrun) {
1811 options_encodable += "<" + _("LyX Warning: ")
1812 + _("uncodable character") + " '";
1813 options_encodable += c;
1814 options_encodable += "'>";
1817 options_encodable += c;
1820 options_encodable = strOptions;
1822 // On BUFFER_VIEW|UPDATE, warn user if we found uncodable glyphs
1823 if (!features.runparams().dryrun && !uncodable_glyphs.empty()) {
1824 frontend::Alert::warning(
1825 _("Uncodable character in class options"),
1827 _("The class options of your document contain glyphs "
1828 "that are unknown in the current document encoding "
1829 "(namely %1$s).\nThese glyphs are omitted "
1830 " from the output, which may result in "
1831 "incomplete output."
1832 "\n\nPlease select an appropriate "
1833 "document encoding\n"
1834 "(such as utf8) or change the "
1835 "class options accordingly."),
1838 options_encodable = rtrim(options_encodable, ",");
1839 os << '[' << options_encodable << ']';
1842 os << '{' << from_ascii(tclass.latexname()) << "}\n";
1843 // end of \documentclass defs
1845 // The package options (via \PassOptionsToPackage)
1846 os << from_ascii(features.getPackageOptions());
1848 // if we use fontspec or newtxmath, we have to load the AMS packages here
1849 string const ams = features.loadAMSPackages();
1850 bool const ot1 = (main_font_encoding() == "default" || main_font_encoding() == "OT1");
1851 bool const use_newtxmath =
1852 theLaTeXFonts().getLaTeXFont(from_ascii(fontsMath())).getUsedPackage(
1853 ot1, false, false) == "newtxmath";
1854 if ((useNonTeXFonts || use_newtxmath) && !ams.empty())
1855 os << from_ascii(ams);
1857 if (useNonTeXFonts) {
1858 // Babel (as of 2017/11/03) loads fontspec itself
1859 if (!features.isProvided("fontspec")
1860 && !(features.useBabel() && features.isAvailable("babel-2017/11/03")))
1861 os << "\\usepackage{fontspec}\n";
1862 if (features.mustProvide("unicode-math")
1863 && features.isAvailable("unicode-math"))
1864 os << "\\usepackage{unicode-math}\n";
1867 // load CJK support package before font selection
1868 // (see autotests/export/latex/CJK/micro-sign_utf8-cjk-libertine.lyx)
1869 if (!useNonTeXFonts && encoding().package() != Encoding::none && inputenc != "utf8x"
1870 && (encoding().package() == Encoding::CJK || features.mustProvide("CJK"))) {
1871 if (inputenc == "utf8-cjk" || inputenc == "utf8")
1872 os << "\\usepackage{CJKutf8}\n";
1874 os << "\\usepackage[encapsulated]{CJK}\n";
1877 // font selection must be done before loading fontenc.sty
1878 // but after babel with non-TeX fonts
1879 string const fonts = loadFonts(features);
1880 if (!fonts.empty() && (!features.useBabel() || !useNonTeXFonts))
1881 os << from_utf8(fonts);
1883 if (fonts_default_family != "default")
1884 os << "\\renewcommand{\\familydefault}{\\"
1885 << from_ascii(fonts_default_family) << "}\n";
1887 // set font encoding
1888 // non-TeX fonts use font encoding TU (set by fontspec)
1889 if (!useNonTeXFonts && !features.isProvided("fontenc")
1890 && main_font_encoding() != "default") {
1891 // get main font encodings
1892 vector<string> fontencs = font_encodings();
1893 // get font encodings of secondary languages
1894 // FIXME: some languages (hebrew, ...) assume a standard font encoding as last
1895 // option (for text in other languages).
1896 features.getFontEncodings(fontencs);
1897 if (!fontencs.empty()) {
1898 os << "\\usepackage["
1899 << from_ascii(getStringFromVector(fontencs))
1904 // Load textcomp and pmboxdraw before (lua)inputenc (#11454)
1905 if (features.mustProvide("textcomp"))
1906 os << "\\usepackage{textcomp}\n";
1907 if (features.mustProvide("pmboxdraw"))
1908 os << "\\usepackage{pmboxdraw}\n";
1910 // handle inputenc etc.
1911 // (In documents containing text in Thai language,
1912 // we must load inputenc after babel, see lib/languages).
1913 if (!contains(features.getBabelPostsettings(), from_ascii("thai.ldf")))
1914 writeEncodingPreamble(os, features);
1917 if (!features.runparams().includeall && !included_children_.empty()) {
1918 os << "\\includeonly{";
1920 for (auto incfile : included_children_) {
1921 FileName inc = makeAbsPath(incfile, filepath.absFileName());
1922 string mangled = DocFileName(changeExtension(inc.absFileName(), ".tex")).
1924 if (!features.runparams().nice)
1926 // \includeonly doesn't want an extension
1927 incfile = changeExtension(incfile, string());
1928 incfile = support::latex_path(incfile);
1929 if (!incfile.empty()) {
1932 os << from_utf8(incfile);
1939 if (!features.isProvided("geometry")
1940 && (use_geometry || !class_supported_papersize)) {
1941 odocstringstream ods;
1942 if (!getGraphicsDriver("geometry").empty())
1943 ods << getGraphicsDriver("geometry");
1944 if (orientation == ORIENTATION_LANDSCAPE)
1945 ods << ",landscape";
1946 switch (papersize) {
1948 if (!paperwidth.empty())
1949 ods << ",paperwidth="
1950 << from_ascii(paperwidth);
1951 if (!paperheight.empty())
1952 ods << ",paperheight="
1953 << from_ascii(paperheight);
1955 case PAPER_USLETTER:
1957 case PAPER_USEXECUTIVE:
1986 ods << "," << from_ascii(string_papersize_geometry[papersize]);
1991 docstring g_options = trim(ods.str(), ",");
1992 os << "\\usepackage";
1993 // geometry-light means that the class works with geometry, but overwrites
1994 // the package options and paper sizes (memoir does this).
1995 // In this case, all options need to go to \geometry
1996 // and the standard paper sizes need to go to the class options.
1997 if (!g_options.empty() && !features.isProvided("geometry-light")) {
1998 os << '[' << g_options << ']';
2001 os << "{geometry}\n";
2002 if (use_geometry || features.isProvided("geometry-light")) {
2003 os << "\\geometry{verbose";
2004 if (!g_options.empty())
2005 // Output general options here with "geometry light".
2006 os << "," << g_options;
2007 // output this only if use_geometry is true
2009 if (!topmargin.empty())
2010 os << ",tmargin=" << from_ascii(Length(topmargin).asLatexString());
2011 if (!bottommargin.empty())
2012 os << ",bmargin=" << from_ascii(Length(bottommargin).asLatexString());
2013 if (!leftmargin.empty())
2014 os << ",lmargin=" << from_ascii(Length(leftmargin).asLatexString());
2015 if (!rightmargin.empty())
2016 os << ",rmargin=" << from_ascii(Length(rightmargin).asLatexString());
2017 if (!headheight.empty())
2018 os << ",headheight=" << from_ascii(Length(headheight).asLatexString());
2019 if (!headsep.empty())
2020 os << ",headsep=" << from_ascii(Length(headsep).asLatexString());
2021 if (!footskip.empty())
2022 os << ",footskip=" << from_ascii(Length(footskip).asLatexString());
2023 if (!columnsep.empty())
2024 os << ",columnsep=" << from_ascii(Length(columnsep).asLatexString());
2028 } else if (orientation == ORIENTATION_LANDSCAPE
2029 || papersize != PAPER_DEFAULT) {
2030 features.require("papersize");
2033 if (tokenPos(tclass.opt_pagestyle(), '|', pagestyle) >= 0) {
2034 if (pagestyle == "fancy")
2035 os << "\\usepackage{fancyhdr}\n";
2036 os << "\\pagestyle{" << from_ascii(pagestyle) << "}\n";
2039 // only output when the background color is not default
2040 if (isbackgroundcolor) {
2041 // only require color here, the background color will be defined
2042 // in LaTeXFeatures.cpp to avoid interferences with the LaTeX
2044 features.require("color");
2045 features.require("pagecolor");
2048 // only output when the font color is not default
2050 // only require color here, the font color will be defined
2051 // in LaTeXFeatures.cpp to avoid interferences with the LaTeX
2053 features.require("color");
2054 features.require("fontcolor");
2057 // Only if class has a ToC hierarchy
2058 if (tclass.hasTocLevels()) {
2059 if (secnumdepth != tclass.secnumdepth()) {
2060 os << "\\setcounter{secnumdepth}{"
2064 if (tocdepth != tclass.tocdepth()) {
2065 os << "\\setcounter{tocdepth}{"
2071 if (paragraph_separation) {
2072 // when skip separation
2074 switch (getDefSkip().kind()) {
2075 case VSpace::SMALLSKIP:
2076 psopt = "\\smallskipamount";
2078 case VSpace::MEDSKIP:
2079 psopt = "\\medskipamount";
2081 case VSpace::BIGSKIP:
2082 psopt = "\\bigskipamount";
2084 case VSpace::HALFLINE:
2085 // default (no option)
2087 case VSpace::FULLLINE:
2088 psopt = "\\baselineskip";
2090 case VSpace::LENGTH:
2091 psopt = getDefSkip().length().asLatexString();
2096 if (!features.isProvided("parskip")) {
2098 psopt = "[skip=" + psopt + "]";
2099 os << "\\usepackage" + psopt + "{parskip}\n";
2101 os << "\\setlength{\\parskip}{" + psopt + "}\n";
2104 // when separation by indentation
2105 // only output something when a width is given
2106 if (!getParIndent().empty()) {
2107 os << "\\setlength{\\parindent}{"
2108 << from_utf8(getParIndent().asLatexString())
2113 if (is_math_indent) {
2114 // when formula indentation
2115 // only output something when it is not the default
2116 if (!getMathIndent().empty()) {
2117 os << "\\setlength{\\mathindent}{"
2118 << from_utf8(getMathIndent().asString())
2123 // Now insert the LyX specific LaTeX commands...
2124 features.resolveAlternatives();
2125 features.expandMultiples();
2128 if (!output_sync_macro.empty())
2129 os << from_utf8(output_sync_macro) +"\n";
2130 else if (features.runparams().flavor == Flavor::LaTeX)
2131 os << "\\usepackage[active]{srcltx}\n";
2132 else if (features.runparams().flavor == Flavor::PdfLaTeX)
2133 os << "\\synctex=-1\n";
2136 // due to interferences with babel and hyperref, the color package has to
2137 // be loaded (when it is not already loaded) before babel when hyperref
2138 // is used with the colorlinks option, see
2139 // http://www.lyx.org/trac/ticket/5291
2140 // we decided therefore to load color always before babel, see
2141 // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg144349.html
2142 os << from_ascii(features.getColorOptions());
2144 // If we use hyperref, jurabib, japanese or varioref,
2145 // we have to call babel before
2147 && (features.isRequired("jurabib")
2148 || features.isRequired("hyperref")
2149 || features.isRequired("varioref")
2150 || features.isRequired("japanese"))) {
2151 os << features.getBabelPresettings();
2153 os << from_utf8(babelCall(language_options.str(),
2154 !lyxrc.language_global_options)) + '\n';
2155 os << features.getBabelPostsettings();
2158 // The optional packages;
2159 os << from_ascii(features.getPackages());
2161 // Additional Indices
2162 if (features.isRequired("splitidx")) {
2163 for (auto const & idx : indiceslist()) {
2164 os << "\\newindex{";
2165 os << escape(idx.shortcut());
2171 os << from_utf8(spacing().writePreamble(features.isProvided("SetSpace")));
2174 // * Hyperref manual: "Make sure it comes last of your loaded
2175 // packages, to give it a fighting chance of not being over-written,
2176 // since its job is to redefine many LaTeX commands."
2177 // * Email from Heiko Oberdiek: "It is usually better to load babel
2178 // before hyperref. Then hyperref has a chance to detect babel.
2179 // * Has to be loaded before the "LyX specific LaTeX commands" to
2180 // avoid errors with algorithm floats.
2181 // use hyperref explicitly if it is required
2182 if (features.isRequired("hyperref")) {
2183 OutputParams tmp_params = features.runparams();
2184 pdfoptions().writeLaTeX(tmp_params, os,
2185 features.isProvided("hyperref"));
2186 // correctly break URLs with hyperref and dvi/ps output
2187 if (features.runparams().hyperref_driver == "dvips"
2188 && features.isAvailable("breakurl"))
2189 os << "\\usepackage{breakurl}\n";
2190 } else if (features.isRequired("nameref"))
2191 // hyperref loads this automatically
2192 os << "\\usepackage{nameref}\n";
2195 os << "\\usepackage";
2196 if (!lineno_opts.empty())
2197 os << "[" << lineno_opts << "]";
2199 os << "\\linenumbers\n";
2202 // bibtopic needs to be loaded after hyperref.
2203 // the dot provides the aux file naming which LyX can detect.
2204 if (features.mustProvide("bibtopic"))
2205 os << "\\usepackage[dot]{bibtopic}\n";
2207 // Will be surrounded by \makeatletter and \makeatother when not empty
2208 otexstringstream atlyxpreamble;
2210 // Some macros LyX will need
2212 TexString tmppreamble = features.getMacros();
2213 if (!tmppreamble.str.empty())
2214 atlyxpreamble << "\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
2215 "LyX specific LaTeX commands.\n"
2216 << move(tmppreamble)
2219 // the text class specific preamble
2221 docstring tmppreamble = features.getTClassPreamble();
2222 if (!tmppreamble.empty())
2223 atlyxpreamble << "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
2224 "Textclass specific LaTeX commands.\n"
2228 // suppress date if selected
2229 // use \@ifundefined because we cannot be sure that every document class
2230 // has a \date command
2232 atlyxpreamble << "\\@ifundefined{date}{}{\\date{}}\n";
2234 /* the user-defined preamble */
2235 if (!containsOnly(preamble, " \n\t")) {
2237 atlyxpreamble << "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
2238 "User specified LaTeX commands.\n";
2240 // Check if the user preamble contains uncodable glyphs
2241 odocstringstream user_preamble;
2242 docstring uncodable_glyphs;
2243 Encoding const * const enc = features.runparams().encoding;
2245 for (char_type c : preamble) {
2246 if (!enc->encodable(c)) {
2247 docstring const glyph(1, c);
2248 LYXERR0("Uncodable character '"
2250 << "' in user preamble!");
2251 uncodable_glyphs += glyph;
2252 if (features.runparams().dryrun) {
2253 user_preamble << "<" << _("LyX Warning: ")
2254 << _("uncodable character") << " '";
2255 user_preamble.put(c);
2256 user_preamble << "'>";
2259 user_preamble.put(c);
2262 user_preamble << preamble;
2264 // On BUFFER_VIEW|UPDATE, warn user if we found uncodable glyphs
2265 if (!features.runparams().dryrun && !uncodable_glyphs.empty()) {
2266 frontend::Alert::warning(
2267 _("Uncodable character in user preamble"),
2269 _("The user preamble of your document contains glyphs "
2270 "that are unknown in the current document encoding "
2271 "(namely %1$s).\nThese glyphs are omitted "
2272 " from the output, which may result in "
2273 "incomplete output."
2274 "\n\nPlease select an appropriate "
2275 "document encoding\n"
2276 "(such as utf8) or change the "
2277 "preamble code accordingly."),
2280 atlyxpreamble << user_preamble.str() << '\n';
2283 // footmisc must be loaded after setspace
2284 // Load it here to avoid clashes with footmisc loaded in the user
2285 // preamble. For that reason we also pass the options via
2286 // \PassOptionsToPackage in getPreamble() and not here.
2287 if (features.mustProvide("footmisc"))
2288 atlyxpreamble << "\\usepackage{footmisc}\n";
2290 // subfig loads internally the LaTeX package "caption". As
2291 // caption is a very popular package, users will load it in
2292 // the preamble. Therefore we must load subfig behind the
2293 // user-defined preamble and check if the caption package was
2294 // loaded or not. For the case that caption is loaded before
2295 // subfig, there is the subfig option "caption=false". This
2296 // option also works when a koma-script class is used and
2297 // koma's own caption commands are used instead of caption. We
2298 // use \PassOptionsToPackage here because the user could have
2299 // already loaded subfig in the preamble.
2300 if (features.mustProvide("subfig"))
2301 atlyxpreamble << "\\ifdefined\\showcaptionsetup\n"
2302 " % Caption package is used. Advise subfig not to load it again.\n"
2303 " \\PassOptionsToPackage{caption=false}{subfig}\n"
2305 "\\usepackage{subfig}\n";
2307 // Itemize bullet settings need to be last in case the user
2308 // defines their own bullets that use a package included
2309 // in the user-defined preamble -- ARRae
2310 // Actually it has to be done much later than that
2311 // since some packages like frenchb make modifications
2312 // at \begin{document} time -- JMarc
2313 docstring bullets_def;
2314 for (int i = 0; i < 4; ++i) {
2315 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
2316 if (bullets_def.empty())
2317 bullets_def += "\\AtBeginDocument{\n";
2318 bullets_def += " \\def\\labelitemi";
2320 // `i' is one less than the item to modify
2327 bullets_def += "ii";
2333 bullets_def += '{' +
2334 user_defined_bullet(i).getText()
2339 if (!bullets_def.empty())
2340 atlyxpreamble << bullets_def << "}\n\n";
2342 if (!atlyxpreamble.empty())
2343 os << "\n\\makeatletter\n"
2344 << atlyxpreamble.release()
2345 << "\\makeatother\n\n";
2347 // We try to load babel late, in case it interferes with other packages.
2348 // Jurabib, hyperref, varioref, bicaption, menukeys and listings (bug 8995)
2349 // have to be called after babel, though.
2350 if (use_babel && !features.isRequired("jurabib")
2351 && !features.isRequired("hyperref")
2352 && !features.isRequired("varioref")
2353 && !features.isRequired("japanese")) {
2354 os << features.getBabelPresettings();
2356 os << from_utf8(babelCall(language_options.str(),
2357 !lyxrc.language_global_options)) + '\n';
2358 os << features.getBabelPostsettings();
2360 // In documents containing text in Thai language,
2361 // we must load inputenc after babel (see lib/languages).
2362 if (contains(features.getBabelPostsettings(), from_ascii("thai.ldf")))
2363 writeEncodingPreamble(os, features);
2365 // font selection must be done after babel with non-TeX fonts
2366 if (!fonts.empty() && features.useBabel() && useNonTeXFonts)
2367 os << from_utf8(fonts);
2369 if (features.isRequired("bicaption"))
2370 os << "\\usepackage{bicaption}\n";
2371 if (!listings_params.empty()
2372 || features.mustProvide("listings")
2373 || features.mustProvide("minted")) {
2375 os << "\\usepackage{minted}\n";
2377 os << "\\usepackage{listings}\n";
2379 string lst_params = listings_params;
2380 // If minted, do not output the language option (bug 11203)
2381 if (use_minted && contains(lst_params, "language=")) {
2382 vector<string> opts =
2383 getVectorFromString(lst_params, ",", false);
2384 for (size_t i = 0; i < opts.size(); ++i) {
2385 if (prefixIs(opts[i], "language="))
2386 opts.erase(opts.begin() + i--);
2388 lst_params = getStringFromVector(opts, ",");
2390 if (!lst_params.empty()) {
2392 os << "\\setminted{";
2395 // do not test validity because listings_params is
2396 // supposed to be valid
2398 InsetListingsParams(lst_params).separatedParams(true);
2399 os << from_utf8(par);
2403 // xunicode only needs to be loaded if tipa is used
2404 // (the rest is obsoleted by the new TU encoding).
2405 // It needs to be loaded at least after amsmath, amssymb,
2406 // esint and the other packages that provide special glyphs
2407 if (features.mustProvide("tipa") && useNonTeXFonts
2408 && !features.isProvided("xunicode")) {
2409 // The `xunicode` package officially only supports XeTeX,
2410 // but also works with LuaTeX. We work around its XeTeX test.
2411 if (features.runparams().flavor != Flavor::XeTeX) {
2412 os << "% Pretend to xunicode that we are XeTeX\n"
2413 << "\\def\\XeTeXpicfile{}\n";
2415 os << "\\usepackage{xunicode}\n";
2418 // covington must be loaded after beamerarticle
2419 if (features.isRequired("covington"))
2420 os << "\\usepackage{covington}\n";
2422 // Polyglossia must be loaded last ...
2423 if (use_polyglossia) {
2425 os << "\\usepackage{polyglossia}\n";
2426 // set the main language
2427 os << "\\setdefaultlanguage";
2428 if (!language->polyglossiaOpts().empty())
2429 os << "[" << from_ascii(language->polyglossiaOpts()) << "]";
2430 os << "{" << from_ascii(language->polyglossia()) << "}\n";
2431 // now setup the other languages
2432 set<string> const polylangs =
2433 features.getPolyglossiaLanguages();
2434 for (auto const & pl : polylangs) {
2435 // We do not output the options here; they are output in
2436 // the language switch commands. This is safer if multiple
2437 // varieties are used.
2438 if (pl == language->polyglossia())
2440 os << "\\setotherlanguage";
2441 os << "{" << from_ascii(pl) << "}\n";
2445 // ... but before biblatex (see #7065)
2446 if ((features.mustProvide("biblatex")
2447 || features.isRequired("biblatex-chicago"))
2448 && !features.isProvided("biblatex-chicago")
2449 && !features.isProvided("biblatex-natbib")
2450 && !features.isProvided("natbib-internal")
2451 && !features.isProvided("natbib")
2452 && !features.isProvided("jurabib")) {
2453 // The biblatex-chicago package has a differing interface
2454 // it uses a wrapper package and loads styles via fixed options
2455 bool const chicago = features.isRequired("biblatex-chicago");
2458 os << "\\usepackage";
2459 if (!biblatex_bibstyle.empty()
2460 && (biblatex_bibstyle == biblatex_citestyle)
2462 opts = "style=" + biblatex_bibstyle;
2464 } else if (!chicago) {
2465 if (!biblatex_bibstyle.empty()) {
2466 opts = "bibstyle=" + biblatex_bibstyle;
2469 if (!biblatex_citestyle.empty()) {
2470 opts += delim + "citestyle=" + biblatex_citestyle;
2474 if (!multibib.empty() && multibib != "child") {
2475 opts += delim + "refsection=" + multibib;
2478 if (bibtexCommand() == "bibtex8"
2479 || prefixIs(bibtexCommand(), "bibtex8 ")) {
2480 opts += delim + "backend=bibtex8";
2482 } else if (bibtexCommand() == "bibtex"
2483 || prefixIs(bibtexCommand(), "bibtex ")) {
2484 opts += delim + "backend=bibtex";
2487 if (!bib_encoding.empty() && encodings.fromLyXName(bib_encoding)) {
2488 opts += delim + "bibencoding="
2489 + encodings.fromLyXName(bib_encoding)->latexName();
2492 if (!biblio_opts.empty())
2493 opts += delim + biblio_opts;
2495 os << "[" << opts << "]";
2497 os << "{biblatex-chicago}\n";
2499 os << "{biblatex}\n";
2503 // Load custom language package here
2504 if (features.langPackage() == LaTeXFeatures::LANG_PACK_CUSTOM) {
2505 if (lang_package == "default")
2506 os << from_utf8(lyxrc.language_custom_package);
2508 os << from_utf8(lang_package);
2512 // Since menukeys uses catoptions, which does some heavy changes on key-value options,
2513 // it is recommended to load menukeys as the last package (even after hyperref)
2514 if (features.isRequired("menukeys"))
2515 os << "\\usepackage{menukeys}\n";
2517 docstring const i18npreamble =
2518 features.getTClassI18nPreamble(use_babel, use_polyglossia,
2520 if (!i18npreamble.empty())
2521 os << i18npreamble + '\n';
2527 void BufferParams::useClassDefaults()
2529 DocumentClass const & tclass = documentClass();
2531 sides = tclass.sides();
2532 columns = tclass.columns();
2533 pagestyle = tclass.pagestyle();
2534 tablestyle = tclass.tablestyle();
2535 use_default_options = true;
2536 // Only if class has a ToC hierarchy
2537 if (tclass.hasTocLevels()) {
2538 secnumdepth = tclass.secnumdepth();
2539 tocdepth = tclass.tocdepth();
2544 bool BufferParams::hasClassDefaults() const
2546 DocumentClass const & tclass = documentClass();
2548 return sides == tclass.sides()
2549 && columns == tclass.columns()
2550 && pagestyle == tclass.pagestyle()
2551 && tablestyle == tclass.tablestyle()
2552 && use_default_options
2553 && secnumdepth == tclass.secnumdepth()
2554 && tocdepth == tclass.tocdepth();
2558 DocumentClass const & BufferParams::documentClass() const
2564 DocumentClassConstPtr BufferParams::documentClassPtr() const
2570 void BufferParams::setDocumentClass(DocumentClassConstPtr tc)
2572 // evil, but this function is evil
2573 doc_class_ = const_pointer_cast<DocumentClass>(tc);
2574 invalidateConverterCache();
2578 bool BufferParams::setBaseClass(string const & classname, string const & path)
2580 LYXERR(Debug::TCLASS, "setBaseClass: " << classname);
2581 LayoutFileList & bcl = LayoutFileList::get();
2582 if (!bcl.haveClass(classname)) {
2584 bformat(_("The layout file:\n"
2586 "could not be found. A default textclass with default\n"
2587 "layouts will be used. LyX will not be able to produce\n"
2589 from_utf8(classname));
2590 frontend::Alert::error(_("Document class not found"), s);
2591 bcl.addEmptyClass(classname);
2594 bool const success = bcl[classname].load(path);
2597 bformat(_("Due to some error in it, the layout file:\n"
2599 "could not be loaded. A default textclass with default\n"
2600 "layouts will be used. LyX will not be able to produce\n"
2602 from_utf8(classname));
2603 frontend::Alert::error(_("Could not load class"), s);
2604 bcl.addEmptyClass(classname);
2607 pimpl_->baseClass_ = classname;
2608 layout_modules_.adaptToBaseClass(baseClass(), removed_modules_);
2613 LayoutFile const * BufferParams::baseClass() const
2615 if (LayoutFileList::get().haveClass(pimpl_->baseClass_))
2616 return &(LayoutFileList::get()[pimpl_->baseClass_]);
2622 LayoutFileIndex const & BufferParams::baseClassID() const
2624 return pimpl_->baseClass_;
2628 void BufferParams::makeDocumentClass(bool clone, bool internal)
2633 invalidateConverterCache();
2634 LayoutModuleList mods;
2635 for (auto const & mod : layout_modules_)
2636 mods.push_back(mod);
2638 doc_class_ = getDocumentClass(*baseClass(), mods, cite_engine_, clone, internal);
2640 TextClass::ReturnValues success = TextClass::OK;
2641 if (!forced_local_layout_.empty())
2642 success = doc_class_->read(to_utf8(forced_local_layout_),
2644 if (!local_layout_.empty() &&
2645 (success == TextClass::OK || success == TextClass::OK_OLDFORMAT))
2646 success = doc_class_->read(to_utf8(local_layout_), TextClass::MODULE);
2647 if (success != TextClass::OK && success != TextClass::OK_OLDFORMAT) {
2648 docstring const msg = _("Error reading internal layout information");
2649 frontend::Alert::warning(_("Read Error"), msg);
2654 bool BufferParams::layoutModuleCanBeAdded(string const & modName) const
2656 return layout_modules_.moduleCanBeAdded(modName, baseClass());
2660 docstring BufferParams::getLocalLayout(bool forced) const
2663 return from_utf8(doc_class_->forcedLayouts());
2665 return local_layout_;
2669 void BufferParams::setLocalLayout(docstring const & layout, bool forced)
2672 forced_local_layout_ = layout;
2674 local_layout_ = layout;
2678 bool BufferParams::addLayoutModule(string const & modName)
2680 for (auto const & mod : layout_modules_)
2683 layout_modules_.push_back(modName);
2688 string BufferParams::bufferFormat() const
2690 return documentClass().outputFormat();
2694 bool BufferParams::isExportable(string const & format, bool need_viewable) const
2696 FormatList const & formats = exportableFormats(need_viewable);
2697 for (auto const & fmt : formats) {
2698 if (fmt->name() == format)
2705 FormatList const & BufferParams::exportableFormats(bool only_viewable) const
2707 FormatList & cached = only_viewable ?
2708 pimpl_->viewableFormatList : pimpl_->exportableFormatList;
2709 bool & valid = only_viewable ?
2710 pimpl_->isViewCacheValid : pimpl_->isExportCacheValid;
2714 vector<string> const backs = backends();
2715 set<string> excludes;
2716 if (useNonTeXFonts) {
2717 excludes.insert("latex");
2718 excludes.insert("pdflatex");
2719 } else if (inputenc != "ascii" && inputenc != "utf8-plain") {
2720 // XeTeX with TeX fonts requires input encoding ascii (#10600).
2721 excludes.insert("xetex");
2725 theConverters().getReachable(backs[0], only_viewable, true, excludes);
2726 vector<string>::const_iterator it = backs.begin() + 1;
2727 for (; it != backs.end(); ++it) {
2728 FormatList r = theConverters().getReachable(*it, only_viewable,
2730 result.insert(result.end(), r.begin(), r.end());
2732 sort(result.begin(), result.end(), Format::formatSorter);
2739 vector<string> BufferParams::backends() const
2742 string const buffmt = bufferFormat();
2744 // FIXME: Don't hardcode format names here, but use a flag
2745 if (buffmt == "latex") {
2746 if (encoding().package() == Encoding::japanese)
2747 v.push_back("platex");
2749 if (!useNonTeXFonts) {
2750 v.push_back("pdflatex");
2751 v.push_back("latex");
2754 || inputenc == "ascii" || inputenc == "utf8-plain")
2755 v.push_back("xetex");
2756 v.push_back("luatex");
2757 v.push_back("dviluatex");
2760 string rbuffmt = buffmt;
2761 // If we use an OutputFormat in Japanese docs,
2762 // we need special format in order to get the path
2763 // via pLaTeX (#8823)
2764 if (documentClass().hasOutputFormat()
2765 && encoding().package() == Encoding::japanese)
2767 v.push_back(rbuffmt);
2770 v.push_back("xhtml");
2771 v.push_back("docbook5");
2772 v.push_back("text");
2778 Flavor BufferParams::getOutputFlavor(string const & format) const
2780 string const dformat = (format.empty() || format == "default") ?
2781 getDefaultOutputFormat() : format;
2782 DefaultFlavorCache::const_iterator it =
2783 default_flavors_.find(dformat);
2785 if (it != default_flavors_.end())
2788 Flavor result = Flavor::LaTeX;
2790 // FIXME It'd be better not to hardcode this, but to do
2791 // something with formats.
2792 if (dformat == "xhtml")
2793 result = Flavor::Html;
2794 else if (dformat == "docbook5")
2795 result = Flavor::DocBook5;
2796 else if (dformat == "text")
2797 result = Flavor::Text;
2798 else if (dformat == "lyx")
2799 result = Flavor::LyX;
2800 else if (dformat == "pdflatex")
2801 result = Flavor::PdfLaTeX;
2802 else if (dformat == "xetex")
2803 result = Flavor::XeTeX;
2804 else if (dformat == "luatex")
2805 result = Flavor::LuaTeX;
2806 else if (dformat == "dviluatex")
2807 result = Flavor::DviLuaTeX;
2809 // Try to determine flavor of default output format
2810 vector<string> backs = backends();
2811 if (find(backs.begin(), backs.end(), dformat) == backs.end()) {
2812 // Get shortest path to format
2813 Graph::EdgePath path;
2814 for (auto const & bvar : backs) {
2815 Graph::EdgePath p = theConverters().getPath(bvar, dformat);
2816 if (!p.empty() && (path.empty() || p.size() < path.size())) {
2821 result = theConverters().getFlavor(path);
2824 // cache this flavor
2825 default_flavors_[dformat] = result;
2830 string BufferParams::getDefaultOutputFormat() const
2832 if (!default_output_format.empty()
2833 && default_output_format != "default")
2834 return default_output_format;
2835 if (encoding().package() == Encoding::japanese)
2836 return lyxrc.default_platex_view_format;
2838 return lyxrc.default_otf_view_format;
2839 return lyxrc.default_view_format;
2842 Font const BufferParams::getFont() const
2844 FontInfo f = documentClass().defaultfont();
2845 if (fonts_default_family == "rmdefault")
2846 f.setFamily(ROMAN_FAMILY);
2847 else if (fonts_default_family == "sfdefault")
2848 f.setFamily(SANS_FAMILY);
2849 else if (fonts_default_family == "ttdefault")
2850 f.setFamily(TYPEWRITER_FAMILY);
2851 return Font(f, language);
2855 QuoteStyle BufferParams::getQuoteStyle(string const & qs) const
2857 return quotesstyletranslator().find(qs);
2861 bool BufferParams::isLatex() const
2863 return documentClass().outputType() == LATEX;
2867 bool BufferParams::isLiterate() const
2869 return documentClass().outputType() == LITERATE;
2873 void BufferParams::readPreamble(Lexer & lex)
2875 if (lex.getString() != "\\begin_preamble")
2876 lyxerr << "Error (BufferParams::readPreamble):"
2877 "consistency check failed." << endl;
2879 preamble = lex.getLongString(from_ascii("\\end_preamble"));
2883 void BufferParams::readLocalLayout(Lexer & lex, bool forced)
2885 string const expected = forced ? "\\begin_forced_local_layout" :
2886 "\\begin_local_layout";
2887 if (lex.getString() != expected)
2888 lyxerr << "Error (BufferParams::readLocalLayout):"
2889 "consistency check failed." << endl;
2892 forced_local_layout_ =
2893 lex.getLongString(from_ascii("\\end_forced_local_layout"));
2895 local_layout_ = lex.getLongString(from_ascii("\\end_local_layout"));
2899 bool BufferParams::setLanguage(string const & lang)
2901 Language const *new_language = languages.getLanguage(lang);
2902 if (!new_language) {
2903 // Language lang was not found
2906 language = new_language;
2911 void BufferParams::readLanguage(Lexer & lex)
2913 if (!lex.next()) return;
2915 string const tmptok = lex.getString();
2917 // check if tmptok is part of tex_babel in tex-defs.h
2918 if (!setLanguage(tmptok)) {
2919 // Language tmptok was not found
2920 language = default_language;
2921 lyxerr << "Warning: Setting language `"
2922 << tmptok << "' to `" << language->lang()
2928 void BufferParams::readGraphicsDriver(Lexer & lex)
2933 string const tmptok = lex.getString();
2934 // check if tmptok is part of tex_graphics in tex_defs.h
2937 string const test = tex_graphics[n++];
2939 if (test == tmptok) {
2940 graphics_driver = tmptok;
2945 "Warning: graphics driver `$$Token' not recognized!\n"
2946 " Setting graphics driver to `default'.\n");
2947 graphics_driver = "default";
2954 void BufferParams::readBullets(Lexer & lex)
2959 int const index = lex.getInteger();
2961 int temp_int = lex.getInteger();
2962 user_defined_bullet(index).setFont(temp_int);
2963 temp_bullet(index).setFont(temp_int);
2965 user_defined_bullet(index).setCharacter(temp_int);
2966 temp_bullet(index).setCharacter(temp_int);
2968 user_defined_bullet(index).setSize(temp_int);
2969 temp_bullet(index).setSize(temp_int);
2973 void BufferParams::readBulletsLaTeX(Lexer & lex)
2975 // The bullet class should be able to read this.
2978 int const index = lex.getInteger();
2980 docstring const temp_str = lex.getDocString();
2982 user_defined_bullet(index).setText(temp_str);
2983 temp_bullet(index).setText(temp_str);
2987 void BufferParams::readModules(Lexer & lex)
2989 if (!lex.eatLine()) {
2990 lyxerr << "Error (BufferParams::readModules):"
2991 "Unexpected end of input." << endl;
2995 string mod = lex.getString();
2996 if (mod == "\\end_modules")
2998 addLayoutModule(mod);
3004 void BufferParams::readRemovedModules(Lexer & lex)
3006 if (!lex.eatLine()) {
3007 lyxerr << "Error (BufferParams::readRemovedModules):"
3008 "Unexpected end of input." << endl;
3012 string mod = lex.getString();
3013 if (mod == "\\end_removed_modules")
3015 removed_modules_.push_back(mod);
3018 // now we want to remove any removed modules that were previously
3019 // added. normally, that will be because default modules were added in
3020 // setBaseClass(), which gets called when \textclass is read at the
3021 // start of the read.
3022 for (auto const & rm : removed_modules_) {
3023 LayoutModuleList::iterator const mit = layout_modules_.begin();
3024 LayoutModuleList::iterator const men = layout_modules_.end();
3025 LayoutModuleList::iterator found = find(mit, men, rm);
3028 layout_modules_.erase(found);
3033 void BufferParams::readIncludeonly(Lexer & lex)
3035 if (!lex.eatLine()) {
3036 lyxerr << "Error (BufferParams::readIncludeonly):"
3037 "Unexpected end of input." << endl;
3041 string child = lex.getString();
3042 if (child == "\\end_includeonly")
3044 included_children_.push_back(child);
3050 string BufferParams::paperSizeName(PapersizePurpose purpose, string const & psize) const
3052 PAPER_SIZE ppsize = psize.empty() ? papersize : papersizetranslator().find(psize);
3055 if (documentClass().pagesize() == "default")
3056 // could be anything, so don't guess
3058 return paperSizeName(purpose, documentClass().pagesize());
3059 case PAPER_CUSTOM: {
3060 if (purpose == XDVI && !paperwidth.empty() &&
3061 !paperheight.empty()) {
3062 // heightxwidth<unit>
3063 string first = paperwidth;
3064 string second = paperheight;
3065 if (orientation == ORIENTATION_LANDSCAPE)
3068 return first.erase(first.length() - 2)
3074 // dvips and dvipdfm do not know this
3075 if (purpose == DVIPS || purpose == DVIPDFM)
3079 if (purpose == DVIPS || purpose == DVIPDFM)
3083 if (purpose == DVIPS || purpose == DVIPDFM)
3093 if (purpose == DVIPS || purpose == DVIPDFM)
3097 if (purpose == DVIPS || purpose == DVIPDFM)
3101 if (purpose == DVIPS || purpose == DVIPDFM)
3105 if (purpose == DVIPS || purpose == DVIPDFM)
3109 if (purpose == DVIPS || purpose == DVIPDFM)
3113 // dvipdfm does not know this
3114 if (purpose == DVIPDFM)
3118 if (purpose == DVIPDFM)
3122 if (purpose == DVIPS || purpose == DVIPDFM)
3126 if (purpose == DVIPS || purpose == DVIPDFM)
3130 if (purpose == DVIPS || purpose == DVIPDFM)
3134 if (purpose == DVIPS || purpose == DVIPDFM)
3138 if (purpose == DVIPS || purpose == DVIPDFM)
3142 if (purpose == DVIPS || purpose == DVIPDFM)
3146 if (purpose == DVIPS || purpose == DVIPDFM)
3150 if (purpose == DVIPS || purpose == DVIPDFM)
3154 if (purpose == DVIPS || purpose == DVIPDFM)
3158 if (purpose == DVIPS || purpose == DVIPDFM)
3162 if (purpose == DVIPS || purpose == DVIPDFM)
3166 if (purpose == DVIPS || purpose == DVIPDFM)
3170 if (purpose == DVIPS || purpose == DVIPDFM)
3174 if (purpose == DVIPS || purpose == DVIPDFM)
3178 if (purpose == DVIPS || purpose == DVIPDFM)
3181 case PAPER_USEXECUTIVE:
3182 // dvipdfm does not know this
3183 if (purpose == DVIPDFM)
3188 case PAPER_USLETTER:
3190 if (purpose == XDVI)
3197 string const BufferParams::dvips_options() const
3201 // If the class loads the geometry package, we do not know which
3202 // paper size is used, since we do not set it (bug 7013).
3203 // Therefore we must not specify any argument here.
3204 // dvips gets the correct paper size via DVI specials in this case
3205 // (if the class uses the geometry package correctly).
3206 if (documentClass().provides("geometry"))
3210 && papersize == PAPER_CUSTOM
3211 && !lyxrc.print_paper_dimension_flag.empty()
3212 && !paperwidth.empty()
3213 && !paperheight.empty()) {
3214 // using a custom papersize
3215 result = lyxrc.print_paper_dimension_flag;
3216 result += ' ' + paperwidth;
3217 result += ',' + paperheight;
3219 string const paper_option = paperSizeName(DVIPS);
3220 if (!paper_option.empty() && (paper_option != "letter" ||
3221 orientation != ORIENTATION_LANDSCAPE)) {
3222 // dvips won't accept -t letter -t landscape.
3223 // In all other cases, include the paper size
3225 result = lyxrc.print_paper_flag;
3226 result += ' ' + paper_option;
3229 if (orientation == ORIENTATION_LANDSCAPE &&
3230 papersize != PAPER_CUSTOM)
3231 result += ' ' + lyxrc.print_landscape_flag;
3236 string const BufferParams::main_font_encoding() const
3238 if (font_encodings().empty()) {
3239 if (ascii_lowercase(language->fontenc(*this)) == "none")
3243 return font_encodings().back();
3247 vector<string> const BufferParams::font_encodings() const
3249 string doc_fontenc = (fontenc == "auto") ? string() : fontenc;
3251 vector<string> fontencs;
3253 // "default" means "no explicit font encoding"
3254 if (doc_fontenc != "default") {
3255 if (!doc_fontenc.empty())
3256 // If we have a custom setting, we use only that!
3257 return getVectorFromString(doc_fontenc);
3258 if (!language->fontenc(*this).empty()
3259 && ascii_lowercase(language->fontenc(*this)) != "none") {
3260 vector<string> fencs = getVectorFromString(language->fontenc(*this));
3261 for (auto & fe : fencs) {
3262 if (find(fontencs.begin(), fontencs.end(), fe) == fontencs.end())
3263 fontencs.push_back(fe);
3272 string BufferParams::babelCall(string const & lang_opts, bool const langoptions) const
3274 // suppress the babel call if there is no BabelName defined
3275 // for the document language in the lib/languages file and if no
3276 // other languages are used (lang_opts is then empty)
3277 if (lang_opts.empty())
3279 // The prefs may require the languages to
3280 // be submitted to babel itself (not the class).
3282 return "\\usepackage[" + lang_opts + "]{babel}";
3283 return "\\usepackage{babel}";
3287 docstring BufferParams::getGraphicsDriver(string const & package) const
3291 if (package == "geometry") {
3292 if (graphics_driver == "dvips"
3293 || graphics_driver == "dvipdfm"
3294 || graphics_driver == "pdftex"
3295 || graphics_driver == "vtex")
3296 result = from_ascii(graphics_driver);
3297 else if (graphics_driver == "dvipdfmx")
3298 result = from_ascii("dvipdfm");
3305 void BufferParams::writeEncodingPreamble(otexstream & os,
3306 LaTeXFeatures & features) const
3308 // With no-TeX fonts we use utf8-plain without encoding package.
3312 if (inputenc == "auto-legacy") {
3313 string const doc_encoding =
3314 language->encoding()->latexName();
3315 Encoding::Package const package =
3316 language->encoding()->package();
3318 // Create list of inputenc options:
3319 set<string> encoding_set;
3320 // luainputenc fails with more than one encoding
3321 if (features.runparams().flavor != Flavor::LuaTeX
3322 && features.runparams().flavor != Flavor::DviLuaTeX)
3323 // list all input encodings used in the document
3324 encoding_set = features.getEncodingSet(doc_encoding);
3326 // The "japanese" babel-language requires the pLaTeX engine
3327 // which conflicts with "inputenc".
3328 // See http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129680.html
3329 if ((!encoding_set.empty() || package == Encoding::inputenc)
3330 && !features.isRequired("japanese")
3331 && !features.isProvided("inputenc")) {
3332 os << "\\usepackage[";
3333 set<string>::const_iterator it = encoding_set.begin();
3334 set<string>::const_iterator const end = encoding_set.end();
3336 os << from_ascii(*it);
3339 for (; it != end; ++it)
3340 os << ',' << from_ascii(*it);
3341 if (package == Encoding::inputenc) {
3342 if (!encoding_set.empty())
3344 os << from_ascii(doc_encoding);
3346 if (features.runparams().flavor == Flavor::LuaTeX
3347 || features.runparams().flavor == Flavor::DviLuaTeX)
3348 os << "]{luainputenc}\n";
3350 os << "]{inputenc}\n";
3352 } else if (inputenc != "auto-legacy-plain") {
3353 switch (encoding().package()) {
3354 case Encoding::none:
3356 case Encoding::japanese:
3357 if (encoding().iconvName() != "UTF-8"
3358 && !features.runparams().isFullUnicode())
3359 // don't default to [utf8]{inputenc} with TeXLive >= 18
3360 os << "\\ifdefined\\UseRawInputEncoding\n"
3361 << " \\UseRawInputEncoding\\fi\n";
3363 case Encoding::inputenc:
3364 // do not load inputenc if japanese is used
3365 // or if the class provides inputenc
3366 if (features.isRequired("japanese")
3367 || features.isProvided("inputenc"))
3369 os << "\\usepackage[" << from_ascii(encoding().latexName());
3370 if (features.runparams().flavor == Flavor::LuaTeX
3371 || features.runparams().flavor == Flavor::DviLuaTeX)
3372 os << "]{luainputenc}\n";
3374 os << "]{inputenc}\n";
3378 if (inputenc == "auto-legacy-plain" || features.isRequired("japanese")) {
3379 // don't default to [utf8]{inputenc} with TeXLive >= 18
3380 os << "\\ifdefined\\UseRawInputEncoding\n";
3381 os << " \\UseRawInputEncoding\\fi\n";
3386 string const BufferParams::parseFontName(string const & name) const
3388 string mangled = name;
3389 size_t const idx = mangled.find('[');
3390 if (idx == string::npos || idx == 0)
3393 return mangled.substr(0, idx - 1);
3397 string const BufferParams::loadFonts(LaTeXFeatures & features) const
3399 if (fontsRoman() == "default" && fontsSans() == "default"
3400 && fontsTypewriter() == "default"
3401 && (fontsMath() == "default" || fontsMath() == "auto"))
3407 /* Fontspec (XeTeX, LuaTeX): we provide GUI support for oldstyle
3408 * numbers (Numbers=OldStyle) and sf/tt scaling. The Ligatures=TeX/
3409 * Mapping=tex-text option assures TeX ligatures (such as "--")
3410 * are resolved. Note that tt does not use these ligatures.
3412 * -- add more GUI options?
3413 * -- add more fonts (fonts for other scripts)
3414 * -- if there's a way to find out if a font really supports
3415 * OldStyle, enable/disable the widget accordingly.
3417 if (useNonTeXFonts && features.isAvailable("fontspec")) {
3418 // "Mapping=tex-text" and "Ligatures=TeX" are equivalent.
3419 // However, until v.2 (2010/07/11) fontspec only knew
3420 // Mapping=tex-text (for XeTeX only); then "Ligatures=TeX"
3421 // was introduced for both XeTeX and LuaTeX (LuaTeX
3422 // didn't understand "Mapping=tex-text", while XeTeX
3423 // understood both. With most recent versions, both
3424 // variants are understood by both engines. However,
3425 // we want to provide support for at least TeXLive 2009
3426 // (for XeTeX; LuaTeX is only supported as of v.2)
3427 // As of 2017/11/03, Babel has its own higher-level
3428 // interface on top of fontspec that is to be used.
3429 bool const babelfonts = features.useBabel()
3430 && features.isAvailable("babel-2017/11/03");
3431 string const texmapping =
3432 (features.runparams().flavor == Flavor::XeTeX) ?
3433 "Mapping=tex-text" : "Ligatures=TeX";
3434 if (fontsRoman() != "default") {
3436 os << "\\babelfont{rm}[";
3438 os << "\\setmainfont[";
3439 if (!font_roman_opts.empty())
3440 os << font_roman_opts << ',';
3442 if (fonts_roman_osf)
3443 os << ",Numbers=OldStyle";
3444 os << "]{" << parseFontName(fontsRoman()) << "}\n";
3446 if (fontsSans() != "default") {
3447 string const sans = parseFontName(fontsSans());
3448 if (fontsSansScale() != 100) {
3450 os << "\\babelfont{sf}";
3452 os << "\\setsansfont";
3454 << float(fontsSansScale()) / 100 << ',';
3456 os << "Numbers=OldStyle,";
3457 if (!font_sans_opts.empty())
3458 os << font_sans_opts << ',';
3459 os << texmapping << "]{"
3463 os << "\\babelfont{sf}[";
3465 os << "\\setsansfont[";
3467 os << "Numbers=OldStyle,";
3468 if (!font_sans_opts.empty())
3469 os << font_sans_opts << ',';
3470 os << texmapping << "]{"
3474 if (fontsTypewriter() != "default") {
3475 string const mono = parseFontName(fontsTypewriter());
3476 if (fontsTypewriterScale() != 100) {
3478 os << "\\babelfont{tt}";
3480 os << "\\setmonofont";
3482 << float(fontsTypewriterScale()) / 100;
3483 if (fonts_typewriter_osf)
3484 os << ",Numbers=OldStyle";
3485 if (!font_typewriter_opts.empty())
3486 os << ',' << font_typewriter_opts;
3491 os << "\\babelfont{tt}";
3493 os << "\\setmonofont";
3494 if (!font_typewriter_opts.empty() || fonts_typewriter_osf) {
3496 if (fonts_typewriter_osf)
3497 os << "Numbers=OldStyle";
3498 if (!font_typewriter_opts.empty()) {
3499 if (fonts_typewriter_osf)
3501 os << font_typewriter_opts;
3505 os << '{' << mono << "}\n";
3512 bool const ot1 = (main_font_encoding() == "default" || main_font_encoding() == "OT1");
3513 bool const dryrun = features.runparams().dryrun;
3514 bool const complete = (fontsSans() == "default" && fontsTypewriter() == "default");
3515 bool const nomath = (fontsMath() != "auto");
3518 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsRoman())).getLaTeXCode(
3519 dryrun, ot1, complete, fonts_expert_sc, fonts_roman_osf,
3520 nomath, font_roman_opts);
3523 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsSans())).getLaTeXCode(
3524 dryrun, ot1, complete, fonts_expert_sc, fonts_sans_osf,
3525 nomath, font_sans_opts, fontsSansScale());
3527 // MONOSPACED/TYPEWRITER
3528 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsTypewriter())).getLaTeXCode(
3529 dryrun, ot1, complete, fonts_expert_sc, fonts_typewriter_osf,
3530 nomath, font_typewriter_opts, fontsTypewriterScale());
3533 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsMath())).getLaTeXCode(
3534 dryrun, ot1, complete, fonts_expert_sc, fonts_roman_osf,
3541 Encoding const & BufferParams::encoding() const
3543 // Main encoding for LaTeX output.
3545 return *(encodings.fromLyXName("utf8-plain"));
3546 if (inputenc == "auto-legacy" || inputenc == "auto-legacy-plain")
3547 return *language->encoding();
3548 if (inputenc == "utf8" && language->lang() == "japanese")
3549 return *(encodings.fromLyXName("utf8-platex"));
3550 Encoding const * const enc = encodings.fromLyXName(inputenc);
3553 LYXERR0("Unknown inputenc value `" << inputenc
3554 << "'. Using `auto' instead.");
3555 return *language->encoding();
3559 string const & BufferParams::defaultBiblioStyle() const
3561 if (!biblio_style.empty())
3562 return biblio_style;
3564 map<string, string> const & bs = documentClass().defaultBiblioStyle();
3565 auto cit = bs.find(theCiteEnginesList.getTypeAsString(citeEngineType()));
3566 if (cit != bs.end())
3569 return empty_string();
3573 bool BufferParams::fullAuthorList() const
3575 return documentClass().fullAuthorList();
3579 string BufferParams::getCiteAlias(string const & s) const
3581 vector<string> commands =
3582 documentClass().citeCommands(citeEngineType());
3583 // If it is a real command, don't treat it as an alias
3584 if (find(commands.begin(), commands.end(), s) != commands.end())
3586 map<string,string> aliases = documentClass().citeCommandAliases();
3587 if (aliases.find(s) != aliases.end())
3593 vector<string> BufferParams::citeCommands() const
3595 static CitationStyle const default_style;
3596 vector<string> commands =
3597 documentClass().citeCommands(citeEngineType());
3598 if (commands.empty())
3599 commands.push_back(default_style.name);
3604 vector<CitationStyle> BufferParams::citeStyles() const
3606 static CitationStyle const default_style;
3607 vector<CitationStyle> styles =
3608 documentClass().citeStyles(citeEngineType());
3610 styles.push_back(default_style);
3615 string const BufferParams::getBibtexCommand(string const cmd, bool const warn) const
3617 // split from options
3619 split(cmd, command_in, ' ');
3621 // Look if the requested command is available. If so, use that.
3622 for (auto const & alts : lyxrc.bibtex_alternatives) {
3623 string command_prov;
3624 split(alts, command_prov, ' ');
3625 if (command_in == command_prov)
3629 // If not, find the most suitable fallback for the current cite framework,
3630 // and warn. Note that we omit options in any such case.
3632 if (useBiblatex()) {
3633 // For Biblatex, we prefer biber (also for Japanese)
3634 // and try to fall back to bibtex8
3635 if (lyxrc.bibtex_alternatives.find("biber") != lyxrc.bibtex_alternatives.end())
3637 else if (lyxrc.bibtex_alternatives.find("bibtex8") != lyxrc.bibtex_alternatives.end())
3638 fallback = "bibtex8";
3640 // For classic BibTeX and as last resort for biblatex, try bibtex
3641 if (fallback.empty()) {
3642 if (lyxrc.bibtex_alternatives.find("bibtex") != lyxrc.bibtex_alternatives.end())
3643 fallback = "bibtex";
3649 if (fallback.empty()) {
3650 frontend::Alert::warning(
3651 _("No bibliography processor found!"),
3653 _("The bibliography processor requested by this document "
3654 "(%1$s) is not available and no appropriate "
3655 "alternative has been found. "
3656 "No bibliography and references will be generated.\n"
3657 "Please fix your installation!"),
3660 frontend::Alert::warning(
3661 _("Requested bibliography processor not found!"),
3663 _("The bibliography processor requested by this document "
3664 "(%1$s) is not available. "
3665 "As a fallback, '%2$s' will be used, options are omitted. "
3666 "This might result in errors or unwanted changes in "
3667 "the bibliography. Please check carefully!\n"
3668 "It is suggested to install the missing processor."),
3669 from_utf8(cmd), from_utf8(fallback)));
3675 string const BufferParams::bibtexCommand(bool const warn) const
3677 // Return document-specific setting if available
3678 if (bibtex_command != "default")
3679 return getBibtexCommand(bibtex_command, warn);
3681 // If we have "default" in document settings, consult the prefs
3682 // 1. Japanese (uses a specific processor)
3683 if (encoding().package() == Encoding::japanese) {
3684 if (lyxrc.jbibtex_command != "automatic")
3685 // Return the specified program, if "automatic" is not set
3686 return lyxrc.jbibtex_command;
3687 else if (!useBiblatex()) {
3688 // With classic BibTeX, return pbibtex, jbibtex, bibtex
3689 if (lyxrc.jbibtex_alternatives.find("pbibtex") != lyxrc.jbibtex_alternatives.end())
3691 if (lyxrc.jbibtex_alternatives.find("jbibtex") != lyxrc.jbibtex_alternatives.end())
3696 // 2. All other languages
3697 else if (lyxrc.bibtex_command != "automatic")
3698 // Return the specified program, if "automatic" is not set
3699 return getBibtexCommand(lyxrc.bibtex_command, warn);
3701 // 3. Automatic: find the most suitable for the current cite framework
3702 if (useBiblatex()) {
3703 // For Biblatex, we prefer biber (also for Japanese)
3704 // and fall back to bibtex8 and, as last resort, bibtex
3705 if (lyxrc.bibtex_alternatives.find("biber") != lyxrc.bibtex_alternatives.end())
3707 else if (lyxrc.bibtex_alternatives.find("bibtex8") != lyxrc.bibtex_alternatives.end())
3714 bool BufferParams::useBiblatex() const
3716 return theCiteEnginesList[citeEngine()]->getCiteFramework() == "biblatex";
3720 void BufferParams::invalidateConverterCache() const
3722 pimpl_->isExportCacheValid = false;
3723 pimpl_->isViewCacheValid = false;
3727 // We shouldn't need to reset the params here, since anything
3728 // we need will be recopied.
3729 void BufferParams::copyForAdvFR(const BufferParams & bp)
3731 string const & lang = bp.language->lang();
3733 layout_modules_ = bp.layout_modules_;
3734 string const & doc_class = bp.documentClass().name();
3735 setBaseClass(doc_class);
3739 void BufferParams::setBibFileEncoding(string const & file, string const & enc)
3741 bib_encodings[file] = enc;
3745 string const BufferParams::bibFileEncoding(string const & file) const
3747 if (bib_encodings.find(file) == bib_encodings.end())
3749 return bib_encodings.find(file)->second;