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 string const main_font_enc = features.runparams().main_fontenc;
1851 bool const ot1 = (main_font_enc == "default" || main_font_enc == "OT1");
1852 bool const use_newtxmath =
1853 theLaTeXFonts().getLaTeXFont(from_ascii(fontsMath())).getUsedPackage(
1854 ot1, false, false) == "newtxmath";
1855 if ((useNonTeXFonts || use_newtxmath) && !ams.empty())
1856 os << from_ascii(ams);
1858 if (useNonTeXFonts) {
1859 // Babel (as of 2017/11/03) loads fontspec itself
1860 if (!features.isProvided("fontspec")
1861 && !(features.useBabel() && features.isAvailable("babel-2017/11/03")))
1862 os << "\\usepackage{fontspec}\n";
1863 if (features.mustProvide("unicode-math")
1864 && features.isAvailable("unicode-math"))
1865 os << "\\usepackage{unicode-math}\n";
1868 // load CJK support package before font selection
1869 // (see autotests/export/latex/CJK/micro-sign_utf8-cjk-libertine.lyx)
1870 if (!useNonTeXFonts && encoding().package() != Encoding::none && inputenc != "utf8x"
1871 && (encoding().package() == Encoding::CJK || features.mustProvide("CJK"))) {
1872 if (inputenc == "utf8-cjk" || inputenc == "utf8")
1873 os << "\\usepackage{CJKutf8}\n";
1875 os << "\\usepackage[encapsulated]{CJK}\n";
1878 // font selection must be done before loading fontenc.sty
1879 // but after babel with non-TeX fonts
1880 string const fonts = loadFonts(features);
1881 if (!fonts.empty() && (!features.useBabel() || !useNonTeXFonts))
1882 os << from_utf8(fonts);
1884 if (fonts_default_family != "default")
1885 os << "\\renewcommand{\\familydefault}{\\"
1886 << from_ascii(fonts_default_family) << "}\n";
1888 // set font encoding
1889 // non-TeX fonts use font encoding TU (set by fontspec)
1890 if (!useNonTeXFonts && !features.isProvided("fontenc")
1891 && main_font_enc != "default") {
1892 // get main font encodings
1893 vector<string> fontencs = font_encodings();
1894 // get font encodings of secondary languages
1895 // FIXME: some languages (hebrew, ...) assume a standard font encoding as last
1896 // option (for text in other languages).
1897 features.getFontEncodings(fontencs);
1898 if (!fontencs.empty()) {
1899 os << "\\usepackage["
1900 << from_ascii(getStringFromVector(fontencs))
1905 // Load textcomp and pmboxdraw before (lua)inputenc (#11454)
1906 if (features.mustProvide("textcomp"))
1907 os << "\\usepackage{textcomp}\n";
1908 if (features.mustProvide("pmboxdraw"))
1909 os << "\\usepackage{pmboxdraw}\n";
1911 // handle inputenc etc.
1912 // (In documents containing text in Thai language,
1913 // we must load inputenc after babel, see lib/languages).
1914 if (!contains(features.getBabelPostsettings(), from_ascii("thai.ldf")))
1915 writeEncodingPreamble(os, features);
1918 if (!features.runparams().includeall && !included_children_.empty()) {
1919 os << "\\includeonly{";
1921 for (auto incfile : included_children_) {
1922 FileName inc = makeAbsPath(incfile, filepath.absFileName());
1923 string mangled = DocFileName(changeExtension(inc.absFileName(), ".tex")).
1925 if (!features.runparams().nice)
1927 // \includeonly doesn't want an extension
1928 incfile = changeExtension(incfile, string());
1929 incfile = support::latex_path(incfile);
1930 if (!incfile.empty()) {
1933 os << from_utf8(incfile);
1940 if (!features.isProvided("geometry")
1941 && (use_geometry || !class_supported_papersize)) {
1942 odocstringstream ods;
1943 if (!getGraphicsDriver("geometry").empty())
1944 ods << getGraphicsDriver("geometry");
1945 if (orientation == ORIENTATION_LANDSCAPE)
1946 ods << ",landscape";
1947 switch (papersize) {
1949 if (!paperwidth.empty())
1950 ods << ",paperwidth="
1951 << from_ascii(paperwidth);
1952 if (!paperheight.empty())
1953 ods << ",paperheight="
1954 << from_ascii(paperheight);
1956 case PAPER_USLETTER:
1958 case PAPER_USEXECUTIVE:
1987 ods << "," << from_ascii(string_papersize_geometry[papersize]);
1992 docstring g_options = trim(ods.str(), ",");
1993 os << "\\usepackage";
1994 // geometry-light means that the class works with geometry, but overwrites
1995 // the package options and paper sizes (memoir does this).
1996 // In this case, all options need to go to \geometry
1997 // and the standard paper sizes need to go to the class options.
1998 if (!g_options.empty() && !features.isProvided("geometry-light")) {
1999 os << '[' << g_options << ']';
2002 os << "{geometry}\n";
2003 if (use_geometry || features.isProvided("geometry-light")) {
2004 os << "\\geometry{verbose";
2005 if (!g_options.empty())
2006 // Output general options here with "geometry light".
2007 os << "," << g_options;
2008 // output this only if use_geometry is true
2010 if (!topmargin.empty())
2011 os << ",tmargin=" << from_ascii(Length(topmargin).asLatexString());
2012 if (!bottommargin.empty())
2013 os << ",bmargin=" << from_ascii(Length(bottommargin).asLatexString());
2014 if (!leftmargin.empty())
2015 os << ",lmargin=" << from_ascii(Length(leftmargin).asLatexString());
2016 if (!rightmargin.empty())
2017 os << ",rmargin=" << from_ascii(Length(rightmargin).asLatexString());
2018 if (!headheight.empty())
2019 os << ",headheight=" << from_ascii(Length(headheight).asLatexString());
2020 if (!headsep.empty())
2021 os << ",headsep=" << from_ascii(Length(headsep).asLatexString());
2022 if (!footskip.empty())
2023 os << ",footskip=" << from_ascii(Length(footskip).asLatexString());
2024 if (!columnsep.empty())
2025 os << ",columnsep=" << from_ascii(Length(columnsep).asLatexString());
2029 } else if (orientation == ORIENTATION_LANDSCAPE
2030 || papersize != PAPER_DEFAULT) {
2031 features.require("papersize");
2034 if (tokenPos(tclass.opt_pagestyle(), '|', pagestyle) >= 0) {
2035 if (pagestyle == "fancy")
2036 os << "\\usepackage{fancyhdr}\n";
2037 os << "\\pagestyle{" << from_ascii(pagestyle) << "}\n";
2040 // only output when the background color is not default
2041 if (isbackgroundcolor) {
2042 // only require color here, the background color will be defined
2043 // in LaTeXFeatures.cpp to avoid interferences with the LaTeX
2045 features.require("color");
2046 features.require("pagecolor");
2049 // only output when the font color is not default
2051 // only require color here, the font color will be defined
2052 // in LaTeXFeatures.cpp to avoid interferences with the LaTeX
2054 features.require("color");
2055 features.require("fontcolor");
2058 // Only if class has a ToC hierarchy
2059 if (tclass.hasTocLevels()) {
2060 if (secnumdepth != tclass.secnumdepth()) {
2061 os << "\\setcounter{secnumdepth}{"
2065 if (tocdepth != tclass.tocdepth()) {
2066 os << "\\setcounter{tocdepth}{"
2072 if (paragraph_separation) {
2073 // when skip separation
2075 switch (getDefSkip().kind()) {
2076 case VSpace::SMALLSKIP:
2077 psopt = "\\smallskipamount";
2079 case VSpace::MEDSKIP:
2080 psopt = "\\medskipamount";
2082 case VSpace::BIGSKIP:
2083 psopt = "\\bigskipamount";
2085 case VSpace::HALFLINE:
2086 // default (no option)
2088 case VSpace::FULLLINE:
2089 psopt = "\\baselineskip";
2091 case VSpace::LENGTH:
2092 psopt = getDefSkip().length().asLatexString();
2097 if (!features.isProvided("parskip")) {
2099 psopt = "[skip=" + psopt + "]";
2100 os << "\\usepackage" + psopt + "{parskip}\n";
2102 os << "\\setlength{\\parskip}{" + psopt + "}\n";
2105 // when separation by indentation
2106 // only output something when a width is given
2107 if (!getParIndent().empty()) {
2108 os << "\\setlength{\\parindent}{"
2109 << from_utf8(getParIndent().asLatexString())
2114 if (is_math_indent) {
2115 // when formula indentation
2116 // only output something when it is not the default
2117 if (!getMathIndent().empty()) {
2118 os << "\\setlength{\\mathindent}{"
2119 << from_utf8(getMathIndent().asString())
2124 // Now insert the LyX specific LaTeX commands...
2125 features.resolveAlternatives();
2126 features.expandMultiples();
2129 if (!output_sync_macro.empty())
2130 os << from_utf8(output_sync_macro) +"\n";
2131 else if (features.runparams().flavor == Flavor::LaTeX)
2132 os << "\\usepackage[active]{srcltx}\n";
2133 else if (features.runparams().flavor == Flavor::PdfLaTeX)
2134 os << "\\synctex=-1\n";
2137 // due to interferences with babel and hyperref, the color package has to
2138 // be loaded (when it is not already loaded) before babel when hyperref
2139 // is used with the colorlinks option, see
2140 // http://www.lyx.org/trac/ticket/5291
2141 // we decided therefore to load color always before babel, see
2142 // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg144349.html
2143 os << from_ascii(features.getColorOptions());
2145 // If we use hyperref, jurabib, japanese or varioref,
2146 // we have to call babel before
2148 && (features.isRequired("jurabib")
2149 || features.isRequired("hyperref")
2150 || features.isRequired("varioref")
2151 || features.isRequired("japanese"))) {
2152 os << features.getBabelPresettings();
2154 os << from_utf8(babelCall(language_options.str(),
2155 !lyxrc.language_global_options)) + '\n';
2156 os << features.getBabelPostsettings();
2159 // The optional packages;
2160 os << from_ascii(features.getPackages());
2162 // Additional Indices
2163 if (features.isRequired("splitidx")) {
2164 for (auto const & idx : indiceslist()) {
2165 os << "\\newindex{";
2166 os << escape(idx.shortcut());
2172 os << from_utf8(spacing().writePreamble(features.isProvided("SetSpace")));
2175 // * Hyperref manual: "Make sure it comes last of your loaded
2176 // packages, to give it a fighting chance of not being over-written,
2177 // since its job is to redefine many LaTeX commands."
2178 // * Email from Heiko Oberdiek: "It is usually better to load babel
2179 // before hyperref. Then hyperref has a chance to detect babel.
2180 // * Has to be loaded before the "LyX specific LaTeX commands" to
2181 // avoid errors with algorithm floats.
2182 // use hyperref explicitly if it is required
2183 if (features.isRequired("hyperref")) {
2184 OutputParams tmp_params = features.runparams();
2185 pdfoptions().writeLaTeX(tmp_params, os,
2186 features.isProvided("hyperref"));
2187 // correctly break URLs with hyperref and dvi/ps output
2188 if (features.runparams().hyperref_driver == "dvips"
2189 && features.isAvailable("breakurl"))
2190 os << "\\usepackage{breakurl}\n";
2191 } else if (features.isRequired("nameref"))
2192 // hyperref loads this automatically
2193 os << "\\usepackage{nameref}\n";
2196 os << "\\usepackage";
2197 if (!lineno_opts.empty())
2198 os << "[" << lineno_opts << "]";
2200 os << "\\linenumbers\n";
2203 // bibtopic needs to be loaded after hyperref.
2204 // the dot provides the aux file naming which LyX can detect.
2205 if (features.mustProvide("bibtopic"))
2206 os << "\\usepackage[dot]{bibtopic}\n";
2208 // Will be surrounded by \makeatletter and \makeatother when not empty
2209 otexstringstream atlyxpreamble;
2211 // Some macros LyX will need
2213 TexString tmppreamble = features.getMacros();
2214 if (!tmppreamble.str.empty())
2215 atlyxpreamble << "\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
2216 "LyX specific LaTeX commands.\n"
2217 << move(tmppreamble)
2220 // the text class specific preamble
2222 docstring tmppreamble = features.getTClassPreamble();
2223 if (!tmppreamble.empty())
2224 atlyxpreamble << "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
2225 "Textclass specific LaTeX commands.\n"
2229 // suppress date if selected
2230 // use \@ifundefined because we cannot be sure that every document class
2231 // has a \date command
2233 atlyxpreamble << "\\@ifundefined{date}{}{\\date{}}\n";
2235 /* the user-defined preamble */
2236 if (!containsOnly(preamble, " \n\t")) {
2238 atlyxpreamble << "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
2239 "User specified LaTeX commands.\n";
2241 // Check if the user preamble contains uncodable glyphs
2242 odocstringstream user_preamble;
2243 docstring uncodable_glyphs;
2244 Encoding const * const enc = features.runparams().encoding;
2246 for (char_type c : preamble) {
2247 if (!enc->encodable(c)) {
2248 docstring const glyph(1, c);
2249 LYXERR0("Uncodable character '"
2251 << "' in user preamble!");
2252 uncodable_glyphs += glyph;
2253 if (features.runparams().dryrun) {
2254 user_preamble << "<" << _("LyX Warning: ")
2255 << _("uncodable character") << " '";
2256 user_preamble.put(c);
2257 user_preamble << "'>";
2260 user_preamble.put(c);
2263 user_preamble << preamble;
2265 // On BUFFER_VIEW|UPDATE, warn user if we found uncodable glyphs
2266 if (!features.runparams().dryrun && !uncodable_glyphs.empty()) {
2267 frontend::Alert::warning(
2268 _("Uncodable character in user preamble"),
2270 _("The user preamble of your document contains glyphs "
2271 "that are unknown in the current document encoding "
2272 "(namely %1$s).\nThese glyphs are omitted "
2273 " from the output, which may result in "
2274 "incomplete output."
2275 "\n\nPlease select an appropriate "
2276 "document encoding\n"
2277 "(such as utf8) or change the "
2278 "preamble code accordingly."),
2281 atlyxpreamble << user_preamble.str() << '\n';
2284 // footmisc must be loaded after setspace
2285 // Load it here to avoid clashes with footmisc loaded in the user
2286 // preamble. For that reason we also pass the options via
2287 // \PassOptionsToPackage in getPreamble() and not here.
2288 if (features.mustProvide("footmisc"))
2289 atlyxpreamble << "\\usepackage{footmisc}\n";
2291 // subfig loads internally the LaTeX package "caption". As
2292 // caption is a very popular package, users will load it in
2293 // the preamble. Therefore we must load subfig behind the
2294 // user-defined preamble and check if the caption package was
2295 // loaded or not. For the case that caption is loaded before
2296 // subfig, there is the subfig option "caption=false". This
2297 // option also works when a koma-script class is used and
2298 // koma's own caption commands are used instead of caption. We
2299 // use \PassOptionsToPackage here because the user could have
2300 // already loaded subfig in the preamble.
2301 if (features.mustProvide("subfig"))
2302 atlyxpreamble << "\\ifdefined\\showcaptionsetup\n"
2303 " % Caption package is used. Advise subfig not to load it again.\n"
2304 " \\PassOptionsToPackage{caption=false}{subfig}\n"
2306 "\\usepackage{subfig}\n";
2308 // Itemize bullet settings need to be last in case the user
2309 // defines their own bullets that use a package included
2310 // in the user-defined preamble -- ARRae
2311 // Actually it has to be done much later than that
2312 // since some packages like frenchb make modifications
2313 // at \begin{document} time -- JMarc
2314 docstring bullets_def;
2315 for (int i = 0; i < 4; ++i) {
2316 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
2317 if (bullets_def.empty())
2318 bullets_def += "\\AtBeginDocument{\n";
2319 bullets_def += " \\def\\labelitemi";
2321 // `i' is one less than the item to modify
2328 bullets_def += "ii";
2334 bullets_def += '{' +
2335 user_defined_bullet(i).getText()
2340 if (!bullets_def.empty())
2341 atlyxpreamble << bullets_def << "}\n\n";
2343 if (!atlyxpreamble.empty())
2344 os << "\n\\makeatletter\n"
2345 << atlyxpreamble.release()
2346 << "\\makeatother\n\n";
2348 // We try to load babel late, in case it interferes with other packages.
2349 // Jurabib, hyperref, varioref, bicaption, menukeys and listings (bug 8995)
2350 // have to be called after babel, though.
2351 if (use_babel && !features.isRequired("jurabib")
2352 && !features.isRequired("hyperref")
2353 && !features.isRequired("varioref")
2354 && !features.isRequired("japanese")) {
2355 os << features.getBabelPresettings();
2357 os << from_utf8(babelCall(language_options.str(),
2358 !lyxrc.language_global_options)) + '\n';
2359 os << features.getBabelPostsettings();
2361 // In documents containing text in Thai language,
2362 // we must load inputenc after babel (see lib/languages).
2363 if (contains(features.getBabelPostsettings(), from_ascii("thai.ldf")))
2364 writeEncodingPreamble(os, features);
2366 // font selection must be done after babel with non-TeX fonts
2367 if (!fonts.empty() && features.useBabel() && useNonTeXFonts)
2368 os << from_utf8(fonts);
2370 if (features.isRequired("bicaption"))
2371 os << "\\usepackage{bicaption}\n";
2372 if (!listings_params.empty()
2373 || features.mustProvide("listings")
2374 || features.mustProvide("minted")) {
2376 os << "\\usepackage{minted}\n";
2378 os << "\\usepackage{listings}\n";
2380 string lst_params = listings_params;
2381 // If minted, do not output the language option (bug 11203)
2382 if (use_minted && contains(lst_params, "language=")) {
2383 vector<string> opts =
2384 getVectorFromString(lst_params, ",", false);
2385 for (size_t i = 0; i < opts.size(); ++i) {
2386 if (prefixIs(opts[i], "language="))
2387 opts.erase(opts.begin() + i--);
2389 lst_params = getStringFromVector(opts, ",");
2391 if (!lst_params.empty()) {
2393 os << "\\setminted{";
2396 // do not test validity because listings_params is
2397 // supposed to be valid
2399 InsetListingsParams(lst_params).separatedParams(true);
2400 os << from_utf8(par);
2404 // xunicode only needs to be loaded if tipa is used
2405 // (the rest is obsoleted by the new TU encoding).
2406 // It needs to be loaded at least after amsmath, amssymb,
2407 // esint and the other packages that provide special glyphs
2408 if (features.mustProvide("tipa") && useNonTeXFonts
2409 && !features.isProvided("xunicode")) {
2410 // The `xunicode` package officially only supports XeTeX,
2411 // but also works with LuaTeX. We work around its XeTeX test.
2412 if (features.runparams().flavor != Flavor::XeTeX) {
2413 os << "% Pretend to xunicode that we are XeTeX\n"
2414 << "\\def\\XeTeXpicfile{}\n";
2416 os << "\\usepackage{xunicode}\n";
2419 // covington must be loaded after beamerarticle
2420 if (features.isRequired("covington"))
2421 os << "\\usepackage{covington}\n";
2423 // Polyglossia must be loaded last ...
2424 if (use_polyglossia) {
2426 os << "\\usepackage{polyglossia}\n";
2427 // set the main language
2428 os << "\\setdefaultlanguage";
2429 if (!language->polyglossiaOpts().empty())
2430 os << "[" << from_ascii(language->polyglossiaOpts()) << "]";
2431 os << "{" << from_ascii(language->polyglossia()) << "}\n";
2432 // now setup the other languages
2433 set<string> const polylangs =
2434 features.getPolyglossiaLanguages();
2435 for (auto const & pl : polylangs) {
2436 // We do not output the options here; they are output in
2437 // the language switch commands. This is safer if multiple
2438 // varieties are used.
2439 if (pl == language->polyglossia())
2441 os << "\\setotherlanguage";
2442 os << "{" << from_ascii(pl) << "}\n";
2446 // ... but before biblatex (see #7065)
2447 if ((features.mustProvide("biblatex")
2448 || features.isRequired("biblatex-chicago"))
2449 && !features.isProvided("biblatex-chicago")
2450 && !features.isProvided("biblatex-natbib")
2451 && !features.isProvided("natbib-internal")
2452 && !features.isProvided("natbib")
2453 && !features.isProvided("jurabib")) {
2454 // The biblatex-chicago package has a differing interface
2455 // it uses a wrapper package and loads styles via fixed options
2456 bool const chicago = features.isRequired("biblatex-chicago");
2459 os << "\\usepackage";
2460 if (!biblatex_bibstyle.empty()
2461 && (biblatex_bibstyle == biblatex_citestyle)
2463 opts = "style=" + biblatex_bibstyle;
2465 } else if (!chicago) {
2466 if (!biblatex_bibstyle.empty()) {
2467 opts = "bibstyle=" + biblatex_bibstyle;
2470 if (!biblatex_citestyle.empty()) {
2471 opts += delim + "citestyle=" + biblatex_citestyle;
2475 if (!multibib.empty() && multibib != "child") {
2476 opts += delim + "refsection=" + multibib;
2479 if (bibtexCommand() == "bibtex8"
2480 || prefixIs(bibtexCommand(), "bibtex8 ")) {
2481 opts += delim + "backend=bibtex8";
2483 } else if (bibtexCommand() == "bibtex"
2484 || prefixIs(bibtexCommand(), "bibtex ")) {
2485 opts += delim + "backend=bibtex";
2488 if (!bib_encoding.empty() && encodings.fromLyXName(bib_encoding)) {
2489 opts += delim + "bibencoding="
2490 + encodings.fromLyXName(bib_encoding)->latexName();
2493 if (!biblio_opts.empty())
2494 opts += delim + biblio_opts;
2496 os << "[" << opts << "]";
2498 os << "{biblatex-chicago}\n";
2500 os << "{biblatex}\n";
2504 // Load custom language package here
2505 if (features.langPackage() == LaTeXFeatures::LANG_PACK_CUSTOM) {
2506 if (lang_package == "default")
2507 os << from_utf8(lyxrc.language_custom_package);
2509 os << from_utf8(lang_package);
2513 // Since menukeys uses catoptions, which does some heavy changes on key-value options,
2514 // it is recommended to load menukeys as the last package (even after hyperref)
2515 if (features.isRequired("menukeys"))
2516 os << "\\usepackage{menukeys}\n";
2518 docstring const i18npreamble =
2519 features.getTClassI18nPreamble(use_babel, use_polyglossia,
2521 if (!i18npreamble.empty())
2522 os << i18npreamble + '\n';
2528 void BufferParams::useClassDefaults()
2530 DocumentClass const & tclass = documentClass();
2532 sides = tclass.sides();
2533 columns = tclass.columns();
2534 pagestyle = tclass.pagestyle();
2535 tablestyle = tclass.tablestyle();
2536 use_default_options = true;
2537 // Only if class has a ToC hierarchy
2538 if (tclass.hasTocLevels()) {
2539 secnumdepth = tclass.secnumdepth();
2540 tocdepth = tclass.tocdepth();
2545 bool BufferParams::hasClassDefaults() const
2547 DocumentClass const & tclass = documentClass();
2549 return sides == tclass.sides()
2550 && columns == tclass.columns()
2551 && pagestyle == tclass.pagestyle()
2552 && tablestyle == tclass.tablestyle()
2553 && use_default_options
2554 && secnumdepth == tclass.secnumdepth()
2555 && tocdepth == tclass.tocdepth();
2559 DocumentClass const & BufferParams::documentClass() const
2565 DocumentClassConstPtr BufferParams::documentClassPtr() const
2571 void BufferParams::setDocumentClass(DocumentClassConstPtr tc)
2573 // evil, but this function is evil
2574 doc_class_ = const_pointer_cast<DocumentClass>(tc);
2575 invalidateConverterCache();
2579 bool BufferParams::setBaseClass(string const & classname, string const & path)
2581 LYXERR(Debug::TCLASS, "setBaseClass: " << classname);
2582 LayoutFileList & bcl = LayoutFileList::get();
2583 if (!bcl.haveClass(classname)) {
2585 bformat(_("The layout file:\n"
2587 "could not be found. A default textclass with default\n"
2588 "layouts will be used. LyX will not be able to produce\n"
2590 from_utf8(classname));
2591 frontend::Alert::error(_("Document class not found"), s);
2592 bcl.addEmptyClass(classname);
2595 bool const success = bcl[classname].load(path);
2598 bformat(_("Due to some error in it, the layout file:\n"
2600 "could not be loaded. A default textclass with default\n"
2601 "layouts will be used. LyX will not be able to produce\n"
2603 from_utf8(classname));
2604 frontend::Alert::error(_("Could not load class"), s);
2605 bcl.addEmptyClass(classname);
2608 pimpl_->baseClass_ = classname;
2609 layout_modules_.adaptToBaseClass(baseClass(), removed_modules_);
2614 LayoutFile const * BufferParams::baseClass() const
2616 if (LayoutFileList::get().haveClass(pimpl_->baseClass_))
2617 return &(LayoutFileList::get()[pimpl_->baseClass_]);
2623 LayoutFileIndex const & BufferParams::baseClassID() const
2625 return pimpl_->baseClass_;
2629 void BufferParams::makeDocumentClass(bool clone, bool internal)
2634 invalidateConverterCache();
2635 LayoutModuleList mods;
2636 for (auto const & mod : layout_modules_)
2637 mods.push_back(mod);
2639 doc_class_ = getDocumentClass(*baseClass(), mods, cite_engine_, clone, internal);
2641 TextClass::ReturnValues success = TextClass::OK;
2642 if (!forced_local_layout_.empty())
2643 success = doc_class_->read(to_utf8(forced_local_layout_),
2645 if (!local_layout_.empty() &&
2646 (success == TextClass::OK || success == TextClass::OK_OLDFORMAT))
2647 success = doc_class_->read(to_utf8(local_layout_), TextClass::MODULE);
2648 if (success != TextClass::OK && success != TextClass::OK_OLDFORMAT) {
2649 docstring const msg = _("Error reading internal layout information");
2650 frontend::Alert::warning(_("Read Error"), msg);
2655 bool BufferParams::layoutModuleCanBeAdded(string const & modName) const
2657 return layout_modules_.moduleCanBeAdded(modName, baseClass());
2661 docstring BufferParams::getLocalLayout(bool forced) const
2664 return from_utf8(doc_class_->forcedLayouts());
2666 return local_layout_;
2670 void BufferParams::setLocalLayout(docstring const & layout, bool forced)
2673 forced_local_layout_ = layout;
2675 local_layout_ = layout;
2679 bool BufferParams::addLayoutModule(string const & modName)
2681 for (auto const & mod : layout_modules_)
2684 layout_modules_.push_back(modName);
2689 string BufferParams::bufferFormat() const
2691 return documentClass().outputFormat();
2695 bool BufferParams::isExportable(string const & format, bool need_viewable) const
2697 FormatList const & formats = exportableFormats(need_viewable);
2698 for (auto const & fmt : formats) {
2699 if (fmt->name() == format)
2706 FormatList const & BufferParams::exportableFormats(bool only_viewable) const
2708 FormatList & cached = only_viewable ?
2709 pimpl_->viewableFormatList : pimpl_->exportableFormatList;
2710 bool & valid = only_viewable ?
2711 pimpl_->isViewCacheValid : pimpl_->isExportCacheValid;
2715 vector<string> const backs = backends();
2716 set<string> excludes;
2717 if (useNonTeXFonts) {
2718 excludes.insert("latex");
2719 excludes.insert("pdflatex");
2720 } else if (inputenc != "ascii" && inputenc != "utf8-plain") {
2721 // XeTeX with TeX fonts requires input encoding ascii (#10600).
2722 excludes.insert("xetex");
2726 theConverters().getReachable(backs[0], only_viewable, true, excludes);
2727 vector<string>::const_iterator it = backs.begin() + 1;
2728 for (; it != backs.end(); ++it) {
2729 FormatList r = theConverters().getReachable(*it, only_viewable,
2731 result.insert(result.end(), r.begin(), r.end());
2733 sort(result.begin(), result.end(), Format::formatSorter);
2740 vector<string> BufferParams::backends() const
2743 string const buffmt = bufferFormat();
2745 // FIXME: Don't hardcode format names here, but use a flag
2746 if (buffmt == "latex") {
2747 if (encoding().package() == Encoding::japanese)
2748 v.push_back("platex");
2750 if (!useNonTeXFonts) {
2751 v.push_back("pdflatex");
2752 v.push_back("latex");
2755 || inputenc == "ascii" || inputenc == "utf8-plain")
2756 v.push_back("xetex");
2757 v.push_back("luatex");
2758 v.push_back("dviluatex");
2761 string rbuffmt = buffmt;
2762 // If we use an OutputFormat in Japanese docs,
2763 // we need special format in order to get the path
2764 // via pLaTeX (#8823)
2765 if (documentClass().hasOutputFormat()
2766 && encoding().package() == Encoding::japanese)
2768 v.push_back(rbuffmt);
2771 v.push_back("xhtml");
2772 v.push_back("docbook5");
2773 v.push_back("text");
2779 Flavor BufferParams::getOutputFlavor(string const & format) const
2781 string const dformat = (format.empty() || format == "default") ?
2782 getDefaultOutputFormat() : format;
2783 DefaultFlavorCache::const_iterator it =
2784 default_flavors_.find(dformat);
2786 if (it != default_flavors_.end())
2789 Flavor result = Flavor::LaTeX;
2791 // FIXME It'd be better not to hardcode this, but to do
2792 // something with formats.
2793 if (dformat == "xhtml")
2794 result = Flavor::Html;
2795 else if (dformat == "docbook5")
2796 result = Flavor::DocBook5;
2797 else if (dformat == "text")
2798 result = Flavor::Text;
2799 else if (dformat == "lyx")
2800 result = Flavor::LyX;
2801 else if (dformat == "pdflatex")
2802 result = Flavor::PdfLaTeX;
2803 else if (dformat == "xetex")
2804 result = Flavor::XeTeX;
2805 else if (dformat == "luatex")
2806 result = Flavor::LuaTeX;
2807 else if (dformat == "dviluatex")
2808 result = Flavor::DviLuaTeX;
2810 // Try to determine flavor of default output format
2811 vector<string> backs = backends();
2812 if (find(backs.begin(), backs.end(), dformat) == backs.end()) {
2813 // Get shortest path to format
2814 Graph::EdgePath path;
2815 for (auto const & bvar : backs) {
2816 Graph::EdgePath p = theConverters().getPath(bvar, dformat);
2817 if (!p.empty() && (path.empty() || p.size() < path.size())) {
2822 result = theConverters().getFlavor(path);
2825 // cache this flavor
2826 default_flavors_[dformat] = result;
2831 string BufferParams::getDefaultOutputFormat() const
2833 if (!default_output_format.empty()
2834 && default_output_format != "default")
2835 return default_output_format;
2836 if (encoding().package() == Encoding::japanese)
2837 return lyxrc.default_platex_view_format;
2839 return lyxrc.default_otf_view_format;
2840 return lyxrc.default_view_format;
2843 Font const BufferParams::getFont() const
2845 FontInfo f = documentClass().defaultfont();
2846 if (fonts_default_family == "rmdefault")
2847 f.setFamily(ROMAN_FAMILY);
2848 else if (fonts_default_family == "sfdefault")
2849 f.setFamily(SANS_FAMILY);
2850 else if (fonts_default_family == "ttdefault")
2851 f.setFamily(TYPEWRITER_FAMILY);
2852 return Font(f, language);
2856 QuoteStyle BufferParams::getQuoteStyle(string const & qs) const
2858 return quotesstyletranslator().find(qs);
2862 bool BufferParams::isLatex() const
2864 return documentClass().outputType() == LATEX;
2868 bool BufferParams::isLiterate() const
2870 return documentClass().outputType() == LITERATE;
2874 void BufferParams::readPreamble(Lexer & lex)
2876 if (lex.getString() != "\\begin_preamble")
2877 lyxerr << "Error (BufferParams::readPreamble):"
2878 "consistency check failed." << endl;
2880 preamble = lex.getLongString(from_ascii("\\end_preamble"));
2884 void BufferParams::readLocalLayout(Lexer & lex, bool forced)
2886 string const expected = forced ? "\\begin_forced_local_layout" :
2887 "\\begin_local_layout";
2888 if (lex.getString() != expected)
2889 lyxerr << "Error (BufferParams::readLocalLayout):"
2890 "consistency check failed." << endl;
2893 forced_local_layout_ =
2894 lex.getLongString(from_ascii("\\end_forced_local_layout"));
2896 local_layout_ = lex.getLongString(from_ascii("\\end_local_layout"));
2900 bool BufferParams::setLanguage(string const & lang)
2902 Language const *new_language = languages.getLanguage(lang);
2903 if (!new_language) {
2904 // Language lang was not found
2907 language = new_language;
2912 void BufferParams::readLanguage(Lexer & lex)
2914 if (!lex.next()) return;
2916 string const tmptok = lex.getString();
2918 // check if tmptok is part of tex_babel in tex-defs.h
2919 if (!setLanguage(tmptok)) {
2920 // Language tmptok was not found
2921 language = default_language;
2922 lyxerr << "Warning: Setting language `"
2923 << tmptok << "' to `" << language->lang()
2929 void BufferParams::readGraphicsDriver(Lexer & lex)
2934 string const tmptok = lex.getString();
2935 // check if tmptok is part of tex_graphics in tex_defs.h
2938 string const test = tex_graphics[n++];
2940 if (test == tmptok) {
2941 graphics_driver = tmptok;
2946 "Warning: graphics driver `$$Token' not recognized!\n"
2947 " Setting graphics driver to `default'.\n");
2948 graphics_driver = "default";
2955 void BufferParams::readBullets(Lexer & lex)
2960 int const index = lex.getInteger();
2962 int temp_int = lex.getInteger();
2963 user_defined_bullet(index).setFont(temp_int);
2964 temp_bullet(index).setFont(temp_int);
2966 user_defined_bullet(index).setCharacter(temp_int);
2967 temp_bullet(index).setCharacter(temp_int);
2969 user_defined_bullet(index).setSize(temp_int);
2970 temp_bullet(index).setSize(temp_int);
2974 void BufferParams::readBulletsLaTeX(Lexer & lex)
2976 // The bullet class should be able to read this.
2979 int const index = lex.getInteger();
2981 docstring const temp_str = lex.getDocString();
2983 user_defined_bullet(index).setText(temp_str);
2984 temp_bullet(index).setText(temp_str);
2988 void BufferParams::readModules(Lexer & lex)
2990 if (!lex.eatLine()) {
2991 lyxerr << "Error (BufferParams::readModules):"
2992 "Unexpected end of input." << endl;
2996 string mod = lex.getString();
2997 if (mod == "\\end_modules")
2999 addLayoutModule(mod);
3005 void BufferParams::readRemovedModules(Lexer & lex)
3007 if (!lex.eatLine()) {
3008 lyxerr << "Error (BufferParams::readRemovedModules):"
3009 "Unexpected end of input." << endl;
3013 string mod = lex.getString();
3014 if (mod == "\\end_removed_modules")
3016 removed_modules_.push_back(mod);
3019 // now we want to remove any removed modules that were previously
3020 // added. normally, that will be because default modules were added in
3021 // setBaseClass(), which gets called when \textclass is read at the
3022 // start of the read.
3023 for (auto const & rm : removed_modules_) {
3024 LayoutModuleList::iterator const mit = layout_modules_.begin();
3025 LayoutModuleList::iterator const men = layout_modules_.end();
3026 LayoutModuleList::iterator found = find(mit, men, rm);
3029 layout_modules_.erase(found);
3034 void BufferParams::readIncludeonly(Lexer & lex)
3036 if (!lex.eatLine()) {
3037 lyxerr << "Error (BufferParams::readIncludeonly):"
3038 "Unexpected end of input." << endl;
3042 string child = lex.getString();
3043 if (child == "\\end_includeonly")
3045 included_children_.push_back(child);
3051 string BufferParams::paperSizeName(PapersizePurpose purpose, string const & psize) const
3053 PAPER_SIZE ppsize = psize.empty() ? papersize : papersizetranslator().find(psize);
3056 if (documentClass().pagesize() == "default")
3057 // could be anything, so don't guess
3059 return paperSizeName(purpose, documentClass().pagesize());
3060 case PAPER_CUSTOM: {
3061 if (purpose == XDVI && !paperwidth.empty() &&
3062 !paperheight.empty()) {
3063 // heightxwidth<unit>
3064 string first = paperwidth;
3065 string second = paperheight;
3066 if (orientation == ORIENTATION_LANDSCAPE)
3069 return first.erase(first.length() - 2)
3075 // dvips and dvipdfm do not know this
3076 if (purpose == DVIPS || purpose == DVIPDFM)
3080 if (purpose == DVIPS || purpose == DVIPDFM)
3084 if (purpose == DVIPS || purpose == DVIPDFM)
3094 if (purpose == DVIPS || purpose == DVIPDFM)
3098 if (purpose == DVIPS || purpose == DVIPDFM)
3102 if (purpose == DVIPS || purpose == DVIPDFM)
3106 if (purpose == DVIPS || purpose == DVIPDFM)
3110 if (purpose == DVIPS || purpose == DVIPDFM)
3114 // dvipdfm does not know this
3115 if (purpose == DVIPDFM)
3119 if (purpose == DVIPDFM)
3123 if (purpose == DVIPS || purpose == DVIPDFM)
3127 if (purpose == DVIPS || purpose == DVIPDFM)
3131 if (purpose == DVIPS || purpose == DVIPDFM)
3135 if (purpose == DVIPS || purpose == DVIPDFM)
3139 if (purpose == DVIPS || purpose == DVIPDFM)
3143 if (purpose == DVIPS || purpose == DVIPDFM)
3147 if (purpose == DVIPS || purpose == DVIPDFM)
3151 if (purpose == DVIPS || purpose == DVIPDFM)
3155 if (purpose == DVIPS || purpose == DVIPDFM)
3159 if (purpose == DVIPS || purpose == DVIPDFM)
3163 if (purpose == DVIPS || purpose == DVIPDFM)
3167 if (purpose == DVIPS || purpose == DVIPDFM)
3171 if (purpose == DVIPS || purpose == DVIPDFM)
3175 if (purpose == DVIPS || purpose == DVIPDFM)
3179 if (purpose == DVIPS || purpose == DVIPDFM)
3182 case PAPER_USEXECUTIVE:
3183 // dvipdfm does not know this
3184 if (purpose == DVIPDFM)
3189 case PAPER_USLETTER:
3191 if (purpose == XDVI)
3198 string const BufferParams::dvips_options() const
3202 // If the class loads the geometry package, we do not know which
3203 // paper size is used, since we do not set it (bug 7013).
3204 // Therefore we must not specify any argument here.
3205 // dvips gets the correct paper size via DVI specials in this case
3206 // (if the class uses the geometry package correctly).
3207 if (documentClass().provides("geometry"))
3211 && papersize == PAPER_CUSTOM
3212 && !lyxrc.print_paper_dimension_flag.empty()
3213 && !paperwidth.empty()
3214 && !paperheight.empty()) {
3215 // using a custom papersize
3216 result = lyxrc.print_paper_dimension_flag;
3217 result += ' ' + paperwidth;
3218 result += ',' + paperheight;
3220 string const paper_option = paperSizeName(DVIPS);
3221 if (!paper_option.empty() && (paper_option != "letter" ||
3222 orientation != ORIENTATION_LANDSCAPE)) {
3223 // dvips won't accept -t letter -t landscape.
3224 // In all other cases, include the paper size
3226 result = lyxrc.print_paper_flag;
3227 result += ' ' + paper_option;
3230 if (orientation == ORIENTATION_LANDSCAPE &&
3231 papersize != PAPER_CUSTOM)
3232 result += ' ' + lyxrc.print_landscape_flag;
3237 string const BufferParams::main_font_encoding() const
3239 vector<string> const fencs = font_encodings();
3240 if (fencs.empty()) {
3241 if (ascii_lowercase(language->fontenc(*this)) == "none")
3245 return fencs.back();
3249 vector<string> const BufferParams::font_encodings() const
3251 string doc_fontenc = (fontenc == "auto") ? string() : fontenc;
3253 vector<string> fontencs;
3255 // "default" means "no explicit font encoding"
3256 if (doc_fontenc != "default") {
3257 if (!doc_fontenc.empty())
3258 // If we have a custom setting, we use only that!
3259 return getVectorFromString(doc_fontenc);
3260 string const lfe = language->fontenc(*this);
3262 && ascii_lowercase(language->fontenc(*this)) != "none") {
3263 vector<string> fencs = getVectorFromString(lfe);
3264 for (auto & fe : fencs) {
3265 if (find(fontencs.begin(), fontencs.end(), fe) == fontencs.end())
3266 fontencs.push_back(fe);
3275 string BufferParams::babelCall(string const & lang_opts, bool const langoptions) const
3277 // suppress the babel call if there is no BabelName defined
3278 // for the document language in the lib/languages file and if no
3279 // other languages are used (lang_opts is then empty)
3280 if (lang_opts.empty())
3282 // The prefs may require the languages to
3283 // be submitted to babel itself (not the class).
3285 return "\\usepackage[" + lang_opts + "]{babel}";
3286 return "\\usepackage{babel}";
3290 docstring BufferParams::getGraphicsDriver(string const & package) const
3294 if (package == "geometry") {
3295 if (graphics_driver == "dvips"
3296 || graphics_driver == "dvipdfm"
3297 || graphics_driver == "pdftex"
3298 || graphics_driver == "vtex")
3299 result = from_ascii(graphics_driver);
3300 else if (graphics_driver == "dvipdfmx")
3301 result = from_ascii("dvipdfm");
3308 void BufferParams::writeEncodingPreamble(otexstream & os,
3309 LaTeXFeatures & features) const
3311 // With no-TeX fonts we use utf8-plain without encoding package.
3315 if (inputenc == "auto-legacy") {
3316 string const doc_encoding =
3317 language->encoding()->latexName();
3318 Encoding::Package const package =
3319 language->encoding()->package();
3321 // Create list of inputenc options:
3322 set<string> encoding_set;
3323 // luainputenc fails with more than one encoding
3324 if (features.runparams().flavor != Flavor::LuaTeX
3325 && features.runparams().flavor != Flavor::DviLuaTeX)
3326 // list all input encodings used in the document
3327 encoding_set = features.getEncodingSet(doc_encoding);
3329 // The "japanese" babel-language requires the pLaTeX engine
3330 // which conflicts with "inputenc".
3331 // See http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129680.html
3332 if ((!encoding_set.empty() || package == Encoding::inputenc)
3333 && !features.isRequired("japanese")
3334 && !features.isProvided("inputenc")) {
3335 os << "\\usepackage[";
3336 set<string>::const_iterator it = encoding_set.begin();
3337 set<string>::const_iterator const end = encoding_set.end();
3339 os << from_ascii(*it);
3342 for (; it != end; ++it)
3343 os << ',' << from_ascii(*it);
3344 if (package == Encoding::inputenc) {
3345 if (!encoding_set.empty())
3347 os << from_ascii(doc_encoding);
3349 if (features.runparams().flavor == Flavor::LuaTeX
3350 || features.runparams().flavor == Flavor::DviLuaTeX)
3351 os << "]{luainputenc}\n";
3353 os << "]{inputenc}\n";
3355 } else if (inputenc != "auto-legacy-plain") {
3356 switch (encoding().package()) {
3357 case Encoding::none:
3359 case Encoding::japanese:
3360 if (encoding().iconvName() != "UTF-8"
3361 && !features.runparams().isFullUnicode())
3362 // don't default to [utf8]{inputenc} with TeXLive >= 18
3363 os << "\\ifdefined\\UseRawInputEncoding\n"
3364 << " \\UseRawInputEncoding\\fi\n";
3366 case Encoding::inputenc:
3367 // do not load inputenc if japanese is used
3368 // or if the class provides inputenc
3369 if (features.isRequired("japanese")
3370 || features.isProvided("inputenc"))
3372 os << "\\usepackage[" << from_ascii(encoding().latexName());
3373 if (features.runparams().flavor == Flavor::LuaTeX
3374 || features.runparams().flavor == Flavor::DviLuaTeX)
3375 os << "]{luainputenc}\n";
3377 os << "]{inputenc}\n";
3381 if (inputenc == "auto-legacy-plain" || features.isRequired("japanese")) {
3382 // don't default to [utf8]{inputenc} with TeXLive >= 18
3383 os << "\\ifdefined\\UseRawInputEncoding\n";
3384 os << " \\UseRawInputEncoding\\fi\n";
3389 string const BufferParams::parseFontName(string const & name) const
3391 string mangled = name;
3392 size_t const idx = mangled.find('[');
3393 if (idx == string::npos || idx == 0)
3396 return mangled.substr(0, idx - 1);
3400 string const BufferParams::loadFonts(LaTeXFeatures & features) const
3402 if (fontsRoman() == "default" && fontsSans() == "default"
3403 && fontsTypewriter() == "default"
3404 && (fontsMath() == "default" || fontsMath() == "auto"))
3410 /* Fontspec (XeTeX, LuaTeX): we provide GUI support for oldstyle
3411 * numbers (Numbers=OldStyle) and sf/tt scaling. The Ligatures=TeX/
3412 * Mapping=tex-text option assures TeX ligatures (such as "--")
3413 * are resolved. Note that tt does not use these ligatures.
3415 * -- add more GUI options?
3416 * -- add more fonts (fonts for other scripts)
3417 * -- if there's a way to find out if a font really supports
3418 * OldStyle, enable/disable the widget accordingly.
3420 if (useNonTeXFonts && features.isAvailable("fontspec")) {
3421 // "Mapping=tex-text" and "Ligatures=TeX" are equivalent.
3422 // However, until v.2 (2010/07/11) fontspec only knew
3423 // Mapping=tex-text (for XeTeX only); then "Ligatures=TeX"
3424 // was introduced for both XeTeX and LuaTeX (LuaTeX
3425 // didn't understand "Mapping=tex-text", while XeTeX
3426 // understood both. With most recent versions, both
3427 // variants are understood by both engines. However,
3428 // we want to provide support for at least TeXLive 2009
3429 // (for XeTeX; LuaTeX is only supported as of v.2)
3430 // As of 2017/11/03, Babel has its own higher-level
3431 // interface on top of fontspec that is to be used.
3432 bool const babelfonts = features.useBabel()
3433 && features.isAvailable("babel-2017/11/03");
3434 string const texmapping =
3435 (features.runparams().flavor == Flavor::XeTeX) ?
3436 "Mapping=tex-text" : "Ligatures=TeX";
3437 if (fontsRoman() != "default") {
3439 os << "\\babelfont{rm}[";
3441 os << "\\setmainfont[";
3442 if (!font_roman_opts.empty())
3443 os << font_roman_opts << ',';
3445 if (fonts_roman_osf)
3446 os << ",Numbers=OldStyle";
3447 os << "]{" << parseFontName(fontsRoman()) << "}\n";
3449 if (fontsSans() != "default") {
3450 string const sans = parseFontName(fontsSans());
3451 if (fontsSansScale() != 100) {
3453 os << "\\babelfont{sf}";
3455 os << "\\setsansfont";
3457 << float(fontsSansScale()) / 100 << ',';
3459 os << "Numbers=OldStyle,";
3460 if (!font_sans_opts.empty())
3461 os << font_sans_opts << ',';
3462 os << texmapping << "]{"
3466 os << "\\babelfont{sf}[";
3468 os << "\\setsansfont[";
3470 os << "Numbers=OldStyle,";
3471 if (!font_sans_opts.empty())
3472 os << font_sans_opts << ',';
3473 os << texmapping << "]{"
3477 if (fontsTypewriter() != "default") {
3478 string const mono = parseFontName(fontsTypewriter());
3479 if (fontsTypewriterScale() != 100) {
3481 os << "\\babelfont{tt}";
3483 os << "\\setmonofont";
3485 << float(fontsTypewriterScale()) / 100;
3486 if (fonts_typewriter_osf)
3487 os << ",Numbers=OldStyle";
3488 if (!font_typewriter_opts.empty())
3489 os << ',' << font_typewriter_opts;
3494 os << "\\babelfont{tt}";
3496 os << "\\setmonofont";
3497 if (!font_typewriter_opts.empty() || fonts_typewriter_osf) {
3499 if (fonts_typewriter_osf)
3500 os << "Numbers=OldStyle";
3501 if (!font_typewriter_opts.empty()) {
3502 if (fonts_typewriter_osf)
3504 os << font_typewriter_opts;
3508 os << '{' << mono << "}\n";
3515 bool const ot1 = (features.runparams().main_fontenc == "default"
3516 || features.runparams().main_fontenc == "OT1");
3517 bool const dryrun = features.runparams().dryrun;
3518 bool const complete = (fontsSans() == "default" && fontsTypewriter() == "default");
3519 bool const nomath = (fontsMath() != "auto");
3522 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsRoman())).getLaTeXCode(
3523 dryrun, ot1, complete, fonts_expert_sc, fonts_roman_osf,
3524 nomath, font_roman_opts);
3527 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsSans())).getLaTeXCode(
3528 dryrun, ot1, complete, fonts_expert_sc, fonts_sans_osf,
3529 nomath, font_sans_opts, fontsSansScale());
3531 // MONOSPACED/TYPEWRITER
3532 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsTypewriter())).getLaTeXCode(
3533 dryrun, ot1, complete, fonts_expert_sc, fonts_typewriter_osf,
3534 nomath, font_typewriter_opts, fontsTypewriterScale());
3537 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsMath())).getLaTeXCode(
3538 dryrun, ot1, complete, fonts_expert_sc, fonts_roman_osf,
3545 Encoding const & BufferParams::encoding() const
3547 // Main encoding for LaTeX output.
3549 return *(encodings.fromLyXName("utf8-plain"));
3550 if (inputenc == "auto-legacy" || inputenc == "auto-legacy-plain")
3551 return *language->encoding();
3552 if (inputenc == "utf8" && language->lang() == "japanese")
3553 return *(encodings.fromLyXName("utf8-platex"));
3554 Encoding const * const enc = encodings.fromLyXName(inputenc);
3557 LYXERR0("Unknown inputenc value `" << inputenc
3558 << "'. Using `auto' instead.");
3559 return *language->encoding();
3563 string const & BufferParams::defaultBiblioStyle() const
3565 if (!biblio_style.empty())
3566 return biblio_style;
3568 map<string, string> const & bs = documentClass().defaultBiblioStyle();
3569 auto cit = bs.find(theCiteEnginesList.getTypeAsString(citeEngineType()));
3570 if (cit != bs.end())
3573 return empty_string();
3577 bool BufferParams::fullAuthorList() const
3579 return documentClass().fullAuthorList();
3583 string BufferParams::getCiteAlias(string const & s) const
3585 vector<string> commands =
3586 documentClass().citeCommands(citeEngineType());
3587 // If it is a real command, don't treat it as an alias
3588 if (find(commands.begin(), commands.end(), s) != commands.end())
3590 map<string,string> aliases = documentClass().citeCommandAliases();
3591 if (aliases.find(s) != aliases.end())
3597 vector<string> BufferParams::citeCommands() const
3599 static CitationStyle const default_style;
3600 vector<string> commands =
3601 documentClass().citeCommands(citeEngineType());
3602 if (commands.empty())
3603 commands.push_back(default_style.name);
3608 vector<CitationStyle> BufferParams::citeStyles() const
3610 static CitationStyle const default_style;
3611 vector<CitationStyle> styles =
3612 documentClass().citeStyles(citeEngineType());
3614 styles.push_back(default_style);
3619 string const BufferParams::getBibtexCommand(string const cmd, bool const warn) const
3621 // split from options
3623 split(cmd, command_in, ' ');
3625 // Look if the requested command is available. If so, use that.
3626 for (auto const & alts : lyxrc.bibtex_alternatives) {
3627 string command_prov;
3628 split(alts, command_prov, ' ');
3629 if (command_in == command_prov)
3633 // If not, find the most suitable fallback for the current cite framework,
3634 // and warn. Note that we omit options in any such case.
3636 if (useBiblatex()) {
3637 // For Biblatex, we prefer biber (also for Japanese)
3638 // and try to fall back to bibtex8
3639 if (lyxrc.bibtex_alternatives.find("biber") != lyxrc.bibtex_alternatives.end())
3641 else if (lyxrc.bibtex_alternatives.find("bibtex8") != lyxrc.bibtex_alternatives.end())
3642 fallback = "bibtex8";
3644 // For classic BibTeX and as last resort for biblatex, try bibtex
3645 if (fallback.empty()) {
3646 if (lyxrc.bibtex_alternatives.find("bibtex") != lyxrc.bibtex_alternatives.end())
3647 fallback = "bibtex";
3653 if (fallback.empty()) {
3654 frontend::Alert::warning(
3655 _("No bibliography processor found!"),
3657 _("The bibliography processor requested by this document "
3658 "(%1$s) is not available and no appropriate "
3659 "alternative has been found. "
3660 "No bibliography and references will be generated.\n"
3661 "Please fix your installation!"),
3664 frontend::Alert::warning(
3665 _("Requested bibliography processor not found!"),
3667 _("The bibliography processor requested by this document "
3668 "(%1$s) is not available. "
3669 "As a fallback, '%2$s' will be used, options are omitted. "
3670 "This might result in errors or unwanted changes in "
3671 "the bibliography. Please check carefully!\n"
3672 "It is suggested to install the missing processor."),
3673 from_utf8(cmd), from_utf8(fallback)));
3679 string const BufferParams::bibtexCommand(bool const warn) const
3681 // Return document-specific setting if available
3682 if (bibtex_command != "default")
3683 return getBibtexCommand(bibtex_command, warn);
3685 // If we have "default" in document settings, consult the prefs
3686 // 1. Japanese (uses a specific processor)
3687 if (encoding().package() == Encoding::japanese) {
3688 if (lyxrc.jbibtex_command != "automatic")
3689 // Return the specified program, if "automatic" is not set
3690 return lyxrc.jbibtex_command;
3691 else if (!useBiblatex()) {
3692 // With classic BibTeX, return pbibtex, jbibtex, bibtex
3693 if (lyxrc.jbibtex_alternatives.find("pbibtex") != lyxrc.jbibtex_alternatives.end())
3695 if (lyxrc.jbibtex_alternatives.find("jbibtex") != lyxrc.jbibtex_alternatives.end())
3700 // 2. All other languages
3701 else if (lyxrc.bibtex_command != "automatic")
3702 // Return the specified program, if "automatic" is not set
3703 return getBibtexCommand(lyxrc.bibtex_command, warn);
3705 // 3. Automatic: find the most suitable for the current cite framework
3706 if (useBiblatex()) {
3707 // For Biblatex, we prefer biber (also for Japanese)
3708 // and fall back to bibtex8 and, as last resort, bibtex
3709 if (lyxrc.bibtex_alternatives.find("biber") != lyxrc.bibtex_alternatives.end())
3711 else if (lyxrc.bibtex_alternatives.find("bibtex8") != lyxrc.bibtex_alternatives.end())
3718 bool BufferParams::useBiblatex() const
3720 return theCiteEnginesList[citeEngine()]->getCiteFramework() == "biblatex";
3724 void BufferParams::invalidateConverterCache() const
3726 pimpl_->isExportCacheValid = false;
3727 pimpl_->isViewCacheValid = false;
3731 // We shouldn't need to reset the params here, since anything
3732 // we need will be recopied.
3733 void BufferParams::copyForAdvFR(const BufferParams & bp)
3735 string const & lang = bp.language->lang();
3737 layout_modules_ = bp.layout_modules_;
3738 string const & doc_class = bp.documentClass().name();
3739 setBaseClass(doc_class);
3743 void BufferParams::setBibFileEncoding(string const & file, string const & enc)
3745 bib_encodings[file] = enc;
3749 string const BufferParams::bibFileEncoding(string const & file) const
3751 if (bib_encodings.find(file) == bib_encodings.end())
3753 return bib_encodings.find(file)->second;