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 IgnoreList 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 typedef std::vector<WordLangTuple> IgnoreList;
608 IgnoreList & BufferParams::spellignore()
610 return pimpl_->spellignore;
614 IgnoreList const & BufferParams::spellignore() const
616 return pimpl_->spellignore;
620 bool BufferParams::spellignored(WordLangTuple const & wl) const
622 bool has_item = false;
623 vector<WordLangTuple> il = spellignore();
624 vector<WordLangTuple>::const_iterator it = il.begin();
625 for (; it != il.end(); ++it) {
626 if (it->lang()->code() != wl.lang()->code())
628 if (it->word() == wl.word()) {
637 Bullet & BufferParams::temp_bullet(lyx::size_type const index)
639 LASSERT(index < 4, return pimpl_->temp_bullets[0]);
640 return pimpl_->temp_bullets[index];
644 Bullet const & BufferParams::temp_bullet(lyx::size_type const index) const
646 LASSERT(index < 4, return pimpl_->temp_bullets[0]);
647 return pimpl_->temp_bullets[index];
651 Bullet & BufferParams::user_defined_bullet(lyx::size_type const index)
653 LASSERT(index < 4, return pimpl_->temp_bullets[0]);
654 return pimpl_->user_defined_bullets[index];
658 Bullet const & BufferParams::user_defined_bullet(lyx::size_type const index) const
660 LASSERT(index < 4, return pimpl_->temp_bullets[0]);
661 return pimpl_->user_defined_bullets[index];
665 Spacing & BufferParams::spacing()
667 return pimpl_->spacing;
671 Spacing const & BufferParams::spacing() const
673 return pimpl_->spacing;
677 PDFOptions & BufferParams::pdfoptions()
679 return pimpl_->pdfoptions;
683 PDFOptions const & BufferParams::pdfoptions() const
685 return pimpl_->pdfoptions;
689 Length const & BufferParams::getMathIndent() const
691 return pimpl_->mathindent;
695 void BufferParams::setMathIndent(Length const & indent)
697 pimpl_->mathindent = indent;
701 Length const & BufferParams::getParIndent() const
703 return pimpl_->parindent;
707 void BufferParams::setParIndent(Length const & indent)
709 pimpl_->parindent = indent;
713 VSpace const & BufferParams::getDefSkip() const
715 return pimpl_->defskip;
719 void BufferParams::setDefSkip(VSpace const & vs)
721 // DEFSKIP will cause an infinite loop
722 LASSERT(vs.kind() != VSpace::DEFSKIP, return);
723 pimpl_->defskip = vs;
727 BufferParams::MathNumber BufferParams::getMathNumber() const
729 if (math_numbering_side != DEFAULT)
730 return math_numbering_side;
731 // FIXME: do not hardcode language here
732 else if (language->lang() == "arabic_arabi"
733 || documentClass().provides("leqno"))
740 string BufferParams::readToken(Lexer & lex, string const & token,
741 FileName const & filename)
744 FileName const & filepath = filename.onlyPath();
746 if (token == "\\textclass") {
748 string const classname = lex.getString();
749 // if there exists a local layout file, ignore the system one
750 // NOTE: in this case, the textclass (.cls file) is assumed to
753 LayoutFileList & bcl = LayoutFileList::get();
754 if (!filepath.empty()) {
755 // If classname is an absolute path, the document is
756 // using a local layout file which could not be accessed
757 // by a relative path. In this case the path is correct
758 // even if the document was moved to a different
759 // location. However, we will have a problem if the
760 // document was generated on a different platform.
761 bool isabsolute = FileName::isAbsolute(classname);
762 string const classpath = onlyPath(classname);
763 string const path = isabsolute ? classpath
764 : FileName(addPath(filepath.absFileName(),
765 classpath)).realPath();
766 string const oldpath = isabsolute ? string()
767 : FileName(addPath(origin, classpath)).realPath();
768 tcp = bcl.addLocalLayout(onlyFileName(classname), path, oldpath);
770 // that returns non-empty if a "local" layout file is found.
772 result = to_utf8(makeRelPath(from_utf8(onlyPath(tcp)),
773 from_utf8(filepath.absFileName())));
776 setBaseClass(onlyFileName(tcp));
778 setBaseClass(onlyFileName(classname));
779 // We assume that a tex class exists for local or unknown
780 // layouts so this warning, will only be given for system layouts.
781 if (!baseClass()->isTeXClassAvailable()) {
782 docstring const desc =
783 translateIfPossible(from_utf8(baseClass()->description()));
784 docstring const prereqs =
785 from_utf8(baseClass()->prerequisites());
786 docstring const msg =
787 bformat(_("The selected document class\n"
789 "requires external files that are not available.\n"
790 "The document class can still be used, but the\n"
791 "document cannot be compiled until the following\n"
792 "prerequisites are installed:\n"
794 "See section 3.1.2.2 (Class Availability) of the\n"
795 "User's Guide for more information."), desc, prereqs);
796 frontend::Alert::warning(_("Document class not available"),
799 } else if (token == "\\save_transient_properties") {
800 lex >> save_transient_properties;
801 } else if (token == "\\origin") {
803 origin = lex.getString();
804 string const sysdirprefix = "/systemlyxdir/";
805 if (prefixIs(origin, sysdirprefix)) {
807 if (inSystemDir(filepath, docsys))
808 origin.replace(0, sysdirprefix.length() - 1, docsys);
810 origin.replace(0, sysdirprefix.length() - 1,
811 package().system_support().absFileName());
813 } else if (token == "\\begin_preamble") {
815 } else if (token == "\\begin_local_layout") {
816 readLocalLayout(lex, false);
817 } else if (token == "\\begin_forced_local_layout") {
818 readLocalLayout(lex, true);
819 } else if (token == "\\begin_modules") {
821 } else if (token == "\\begin_removed_modules") {
822 readRemovedModules(lex);
823 } else if (token == "\\begin_includeonly") {
824 readIncludeonly(lex);
825 } else if (token == "\\maintain_unincluded_children") {
829 maintain_unincluded_children = CM_None;
830 else if (tmp == "mostly")
831 maintain_unincluded_children = CM_Mostly;
832 else if (tmp == "strict")
833 maintain_unincluded_children = CM_Strict;
834 } else if (token == "\\options") {
836 options = lex.getString();
837 } else if (token == "\\use_default_options") {
838 lex >> use_default_options;
839 } else if (token == "\\master") {
841 master = lex.getString();
842 if (!filepath.empty() && FileName::isAbsolute(origin)) {
843 bool const isabs = FileName::isAbsolute(master);
844 FileName const abspath(isabs ? master : origin + master);
845 bool const moved = filepath != FileName(origin);
846 if (moved && abspath.exists()) {
847 docstring const path = isabs
849 : from_utf8(abspath.realPath());
850 docstring const refpath =
851 from_utf8(filepath.absFileName());
852 master = to_utf8(makeRelPath(path, refpath));
855 } else if (token == "\\suppress_date") {
856 lex >> suppress_date;
857 } else if (token == "\\justification") {
858 lex >> justification;
859 } else if (token == "\\language") {
861 } else if (token == "\\language_package") {
863 lang_package = lex.getString();
864 } else if (token == "\\inputencoding") {
866 } else if (token == "\\graphics") {
867 readGraphicsDriver(lex);
868 } else if (token == "\\default_output_format") {
869 lex >> default_output_format;
870 } else if (token == "\\bibtex_command") {
872 bibtex_command = lex.getString();
873 } else if (token == "\\index_command") {
875 index_command = lex.getString();
876 } else if (token == "\\fontencoding") {
878 fontenc = lex.getString();
879 } else if (token == "\\font_roman") {
880 lex >> fonts_roman[0];
881 lex >> fonts_roman[1];
882 } else if (token == "\\font_sans") {
883 lex >> fonts_sans[0];
884 lex >> fonts_sans[1];
885 } else if (token == "\\font_typewriter") {
886 lex >> fonts_typewriter[0];
887 lex >> fonts_typewriter[1];
888 } else if (token == "\\font_math") {
889 lex >> fonts_math[0];
890 lex >> fonts_math[1];
891 } else if (token == "\\font_default_family") {
892 lex >> fonts_default_family;
893 } else if (token == "\\use_non_tex_fonts") {
894 lex >> useNonTeXFonts;
895 } else if (token == "\\font_sc") {
896 lex >> fonts_expert_sc;
897 } else if (token == "\\font_roman_osf") {
898 lex >> fonts_roman_osf;
899 } else if (token == "\\font_sans_osf") {
900 lex >> fonts_sans_osf;
901 } else if (token == "\\font_typewriter_osf") {
902 lex >> fonts_typewriter_osf;
903 } else if (token == "\\font_roman_opts") {
904 lex >> font_roman_opts;
905 } else if (token == "\\font_sf_scale") {
906 lex >> fonts_sans_scale[0];
907 lex >> fonts_sans_scale[1];
908 } else if (token == "\\font_sans_opts") {
909 lex >> font_sans_opts;
910 } else if (token == "\\font_tt_scale") {
911 lex >> fonts_typewriter_scale[0];
912 lex >> fonts_typewriter_scale[1];
913 } else if (token == "\\font_typewriter_opts") {
914 lex >> font_typewriter_opts;
915 } else if (token == "\\font_cjk") {
917 } else if (token == "\\use_microtype") {
918 lex >> use_microtype;
919 } else if (token == "\\use_dash_ligatures") {
920 lex >> use_dash_ligatures;
921 } else if (token == "\\paragraph_separation") {
924 paragraph_separation = parseptranslator().find(parsep);
925 } else if (token == "\\paragraph_indentation") {
927 string parindent = lex.getString();
928 if (parindent == "default")
929 pimpl_->parindent = Length();
931 pimpl_->parindent = Length(parindent);
932 } else if (token == "\\defskip") {
934 string const defskip = lex.getString();
935 pimpl_->defskip = VSpace(defskip);
936 if (pimpl_->defskip.kind() == VSpace::DEFSKIP)
938 pimpl_->defskip = VSpace(VSpace::MEDSKIP);
939 } else if (token == "\\is_math_indent") {
940 lex >> is_math_indent;
941 } else if (token == "\\math_indentation") {
943 string mathindent = lex.getString();
944 if (mathindent == "default")
945 pimpl_->mathindent = Length();
947 pimpl_->mathindent = Length(mathindent);
948 } else if (token == "\\math_numbering_side") {
952 math_numbering_side = LEFT;
953 else if (tmp == "right")
954 math_numbering_side = RIGHT;
956 math_numbering_side = DEFAULT;
957 } else if (token == "\\quotes_style") {
960 quotes_style = quotesstyletranslator().find(qstyle);
961 } else if (token == "\\dynamic_quotes") {
962 lex >> dynamic_quotes;
963 } else if (token == "\\papersize") {
966 papersize = papersizetranslator().find(ppsize);
967 } else if (token == "\\use_geometry") {
969 } else if (token == "\\use_package") {
974 use_package(package, packagetranslator().find(use));
975 } else if (token == "\\cite_engine") {
977 cite_engine_ = lex.getString();
978 } else if (token == "\\cite_engine_type") {
981 cite_engine_type_ = theCiteEnginesList.getType(engine_type);
982 } else if (token == "\\biblio_style") {
984 biblio_style = lex.getString();
985 } else if (token == "\\biblio_options") {
987 biblio_opts = trim(lex.getString());
988 } else if (token == "\\biblatex_bibstyle") {
990 biblatex_bibstyle = trim(lex.getString());
991 } else if (token == "\\biblatex_citestyle") {
993 biblatex_citestyle = trim(lex.getString());
994 } else if (token == "\\use_bibtopic") {
996 } else if (token == "\\multibib") {
998 } else if (token == "\\use_indices") {
1000 } else if (token == "\\tracking_changes") {
1001 lex >> track_changes;
1002 } else if (token == "\\output_changes") {
1003 lex >> output_changes;
1004 } else if (token == "\\change_bars") {
1006 } else if (token == "\\postpone_fragile_content") {
1007 lex >> postpone_fragile_content;
1008 } else if (token == "\\branch") {
1010 docstring branch = lex.getDocString();
1011 branchlist().add(branch);
1014 string const tok = lex.getString();
1015 if (tok == "\\end_branch")
1017 Branch * branch_ptr = branchlist().find(branch);
1018 if (tok == "\\selected") {
1021 branch_ptr->setSelected(lex.getInteger());
1023 if (tok == "\\filename_suffix") {
1026 branch_ptr->setFileNameSuffix(lex.getInteger());
1028 if (tok == "\\color") {
1030 vector<string> const colors = getVectorFromString(lex.getString(), " ");
1031 string const lmcolor = colors.front();
1033 if (colors.size() > 1)
1034 dmcolor = colors.back();
1036 branch_ptr->setColors(lmcolor, dmcolor);
1039 } else if (token == "\\index") {
1041 docstring index = lex.getDocString();
1043 indiceslist().add(index);
1046 string const tok = lex.getString();
1047 if (tok == "\\end_index")
1049 Index * index_ptr = indiceslist().find(index);
1050 if (tok == "\\shortcut") {
1052 shortcut = lex.getDocString();
1054 index_ptr->setShortcut(shortcut);
1056 if (tok == "\\color") {
1058 string color = lex.getString();
1060 index_ptr->setColor(color);
1061 // Update also the Color table:
1062 if (color == "none")
1063 color = lcolor.getX11HexName(Color_background);
1065 if (!shortcut.empty())
1066 lcolor.setColor(to_utf8(shortcut)+ "@" + filename.absFileName(), color);
1069 } else if (token == "\\spellchecker_ignore") {
1071 docstring wl = lex.getDocString();
1073 docstring word = split(wl, language, ' ');
1074 Language const * lang = languages.getLanguage(to_ascii(language));
1076 spellignore().push_back(WordLangTuple(word, lang));
1077 } else if (token == "\\author") {
1079 istringstream ss(lex.getString());
1083 } else if (token == "\\paperorientation") {
1086 orientation = paperorientationtranslator().find(orient);
1087 } else if (token == "\\backgroundcolor") {
1089 backgroundcolor = lyx::rgbFromHexName(lex.getString());
1090 isbackgroundcolor = true;
1091 } else if (token == "\\fontcolor") {
1093 fontcolor = lyx::rgbFromHexName(lex.getString());
1095 } else if (token == "\\notefontcolor") {
1097 string color = lex.getString();
1098 notefontcolor = lyx::rgbFromHexName(color);
1099 lcolor.setColor("notefontcolor", color);
1100 lcolor.setLaTeXName("notefontcolor", "note_fontcolor");
1101 lcolor.setGUIName("notefontcolor", N_("greyedout inset text"));
1102 // set a local name for the painter
1103 lcolor.setColor("notefontcolor@" + filename.absFileName(), color);
1104 isnotefontcolor = true;
1105 } else if (token == "\\boxbgcolor") {
1107 string color = lex.getString();
1108 boxbgcolor = lyx::rgbFromHexName(color);
1109 lcolor.setColor("boxbgcolor@" + filename.absFileName(), color);
1110 isboxbgcolor = true;
1111 } else if (token == "\\paperwidth") {
1113 } else if (token == "\\paperheight") {
1115 } else if (token == "\\leftmargin") {
1117 } else if (token == "\\topmargin") {
1119 } else if (token == "\\rightmargin") {
1121 } else if (token == "\\bottommargin") {
1122 lex >> bottommargin;
1123 } else if (token == "\\headheight") {
1125 } else if (token == "\\headsep") {
1127 } else if (token == "\\footskip") {
1129 } else if (token == "\\columnsep") {
1131 } else if (token == "\\paperfontsize") {
1133 } else if (token == "\\papercolumns") {
1135 } else if (token == "\\listings_params") {
1138 listings_params = InsetListingsParams(par).params();
1139 } else if (token == "\\papersides") {
1142 sides = sidestranslator().find(psides);
1143 } else if (token == "\\paperpagestyle") {
1145 } else if (token == "\\tablestyle") {
1147 } else if (token == "\\bullet") {
1149 } else if (token == "\\bulletLaTeX") {
1150 readBulletsLaTeX(lex);
1151 } else if (token == "\\secnumdepth") {
1153 } else if (token == "\\tocdepth") {
1155 } else if (token == "\\spacing") {
1159 if (nspacing == "other") {
1162 spacing().set(spacetranslator().find(nspacing), tmp_val);
1163 } else if (token == "\\float_placement") {
1164 lex >> float_placement;
1165 } else if (token == "\\float_alignment") {
1166 lex >> float_alignment;
1168 } else if (prefixIs(token, "\\pdf_") || token == "\\use_hyperref") {
1169 string toktmp = pdfoptions().readToken(lex, token);
1170 if (!toktmp.empty()) {
1171 lyxerr << "PDFOptions::readToken(): Unknown token: " <<
1175 } else if (token == "\\html_math_output") {
1178 html_math_output = static_cast<MathOutput>(temp);
1179 } else if (token == "\\html_be_strict") {
1180 lex >> html_be_strict;
1181 } else if (token == "\\html_css_as_file") {
1182 lex >> html_css_as_file;
1183 } else if (token == "\\html_math_img_scale") {
1184 lex >> html_math_img_scale;
1185 } else if (token == "\\html_latex_start") {
1187 html_latex_start = lex.getString();
1188 } else if (token == "\\html_latex_end") {
1190 html_latex_end = lex.getString();
1191 } else if (token == "\\docbook_table_output") {
1194 docbook_table_output = static_cast<TableOutput>(temp);
1195 } else if (token == "\\docbook_mathml_prefix") {
1198 docbook_mathml_prefix = static_cast<MathMLNameSpacePrefix>(temp);
1199 } else if (token == "\\output_sync") {
1201 } else if (token == "\\output_sync_macro") {
1202 lex >> output_sync_macro;
1203 } else if (token == "\\use_refstyle") {
1204 lex >> use_refstyle;
1205 } else if (token == "\\use_minted") {
1207 } else if (token == "\\use_lineno") {
1209 } else if (token == "\\lineno_options") {
1211 lineno_opts = trim(lex.getString());
1213 lyxerr << "BufferParams::readToken(): Unknown token: " <<
1223 // Quote argument if it contains spaces
1224 string quoteIfNeeded(string const & str) {
1225 if (contains(str, ' '))
1226 return "\"" + str + "\"";
1232 void BufferParams::writeFile(ostream & os, Buffer const * buf) const
1234 // The top of the file is written by the buffer.
1235 // Prints out the buffer info into the .lyx file given by file
1237 os << "\\save_transient_properties "
1238 << convert<string>(save_transient_properties) << '\n';
1240 // the document directory (must end with a path separator)
1241 // realPath() is used to resolve symlinks, while addPath(..., "")
1242 // ensures a trailing path separator.
1244 string filepath = addPath(buf->fileName().onlyPath().realPath(), "");
1245 string const sysdir = inSystemDir(FileName(filepath), docsys) ? docsys
1246 : addPath(package().system_support().realPath(), "");
1247 string const relpath =
1248 to_utf8(makeRelPath(from_utf8(filepath), from_utf8(sysdir)));
1249 if (!prefixIs(relpath, "../") && !FileName::isAbsolute(relpath))
1250 filepath = addPath("/systemlyxdir", relpath);
1251 else if (!save_transient_properties || !lyxrc.save_origin)
1252 filepath = "unavailable";
1253 os << "\\origin " << quoteIfNeeded(filepath) << '\n';
1256 os << "\\textclass "
1257 << quoteIfNeeded(buf->includedFilePath(addName(buf->layoutPos(),
1258 baseClass()->name()), "layout"))
1261 // then the preamble
1262 if (!preamble.empty()) {
1263 // remove '\n' from the end of preamble
1264 docstring const tmppreamble = rtrim(preamble, "\n");
1265 os << "\\begin_preamble\n"
1266 << to_utf8(tmppreamble)
1267 << "\n\\end_preamble\n";
1271 if (!options.empty()) {
1272 os << "\\options " << options << '\n';
1275 // use the class options defined in the layout?
1276 os << "\\use_default_options "
1277 << convert<string>(use_default_options) << "\n";
1279 // the master document
1280 if (!master.empty()) {
1281 os << "\\master " << master << '\n';
1285 if (!removed_modules_.empty()) {
1286 os << "\\begin_removed_modules" << '\n';
1287 for (auto const & mod : removed_modules_)
1289 os << "\\end_removed_modules" << '\n';
1293 if (!layout_modules_.empty()) {
1294 os << "\\begin_modules" << '\n';
1295 for (auto const & mod : layout_modules_)
1297 os << "\\end_modules" << '\n';
1301 if (!included_children_.empty()) {
1302 os << "\\begin_includeonly" << '\n';
1303 for (auto const & c : included_children_)
1305 os << "\\end_includeonly" << '\n';
1308 switch (maintain_unincluded_children) {
1319 os << "\\maintain_unincluded_children " << muc << '\n';
1321 // local layout information
1322 docstring const local_layout = getLocalLayout(false);
1323 if (!local_layout.empty()) {
1324 // remove '\n' from the end
1325 docstring const tmplocal = rtrim(local_layout, "\n");
1326 os << "\\begin_local_layout\n"
1327 << to_utf8(tmplocal)
1328 << "\n\\end_local_layout\n";
1330 docstring const forced_local_layout = getLocalLayout(true);
1331 if (!forced_local_layout.empty()) {
1332 // remove '\n' from the end
1333 docstring const tmplocal = rtrim(forced_local_layout, "\n");
1334 os << "\\begin_forced_local_layout\n"
1335 << to_utf8(tmplocal)
1336 << "\n\\end_forced_local_layout\n";
1339 // then the text parameters
1340 if (language != ignore_language)
1341 os << "\\language " << language->lang() << '\n';
1342 os << "\\language_package " << lang_package
1343 << "\n\\inputencoding " << inputenc
1344 << "\n\\fontencoding " << fontenc
1345 << "\n\\font_roman \"" << fonts_roman[0]
1346 << "\" \"" << fonts_roman[1] << '"'
1347 << "\n\\font_sans \"" << fonts_sans[0]
1348 << "\" \"" << fonts_sans[1] << '"'
1349 << "\n\\font_typewriter \"" << fonts_typewriter[0]
1350 << "\" \"" << fonts_typewriter[1] << '"'
1351 << "\n\\font_math \"" << fonts_math[0]
1352 << "\" \"" << fonts_math[1] << '"'
1353 << "\n\\font_default_family " << fonts_default_family
1354 << "\n\\use_non_tex_fonts " << convert<string>(useNonTeXFonts)
1355 << "\n\\font_sc " << convert<string>(fonts_expert_sc)
1356 << "\n\\font_roman_osf " << convert<string>(fonts_roman_osf)
1357 << "\n\\font_sans_osf " << convert<string>(fonts_sans_osf)
1358 << "\n\\font_typewriter_osf " << convert<string>(fonts_typewriter_osf);
1359 if (!font_roman_opts.empty())
1360 os << "\n\\font_roman_opts \"" << font_roman_opts << "\"";
1361 os << "\n\\font_sf_scale " << fonts_sans_scale[0]
1362 << ' ' << fonts_sans_scale[1];
1363 if (!font_sans_opts.empty())
1364 os << "\n\\font_sans_opts \"" << font_sans_opts << "\"";
1365 os << "\n\\font_tt_scale " << fonts_typewriter_scale[0]
1366 << ' ' << fonts_typewriter_scale[1];
1367 if (!font_typewriter_opts.empty())
1368 os << "\n\\font_typewriter_opts \"" << font_typewriter_opts << "\"";
1370 if (!fonts_cjk.empty())
1371 os << "\\font_cjk " << fonts_cjk << '\n';
1372 os << "\\use_microtype " << convert<string>(use_microtype) << '\n';
1373 os << "\\use_dash_ligatures " << convert<string>(use_dash_ligatures) << '\n';
1374 os << "\\graphics " << graphics_driver << '\n';
1375 os << "\\default_output_format " << default_output_format << '\n';
1376 os << "\\output_sync " << output_sync << '\n';
1377 if (!output_sync_macro.empty())
1378 os << "\\output_sync_macro \"" << output_sync_macro << "\"\n";
1379 os << "\\bibtex_command " << bibtex_command << '\n';
1380 os << "\\index_command " << index_command << '\n';
1382 if (!float_placement.empty())
1383 os << "\\float_placement " << float_placement << '\n';
1384 if (!float_alignment.empty())
1385 os << "\\float_alignment " << float_alignment << '\n';
1386 os << "\\paperfontsize " << fontsize << '\n';
1388 spacing().writeFile(os);
1389 pdfoptions().writeFile(os);
1391 os << "\\papersize " << string_papersize[papersize]
1392 << "\n\\use_geometry " << convert<string>(use_geometry);
1393 map<string, string> const & packages = auto_packages();
1394 for (auto const & pack : packages)
1395 os << "\n\\use_package " << pack.first << ' '
1396 << use_package(pack.first);
1398 os << "\n\\cite_engine ";
1400 if (!cite_engine_.empty())
1405 os << "\n\\cite_engine_type " << theCiteEnginesList.getTypeAsString(cite_engine_type_);
1407 if (!biblio_style.empty())
1408 os << "\n\\biblio_style " << biblio_style;
1409 if (!biblio_opts.empty())
1410 os << "\n\\biblio_options " << biblio_opts;
1411 if (!biblatex_bibstyle.empty())
1412 os << "\n\\biblatex_bibstyle " << biblatex_bibstyle;
1413 if (!biblatex_citestyle.empty())
1414 os << "\n\\biblatex_citestyle " << biblatex_citestyle;
1415 if (!multibib.empty())
1416 os << "\n\\multibib " << multibib;
1418 os << "\n\\use_bibtopic " << convert<string>(use_bibtopic)
1419 << "\n\\use_indices " << convert<string>(use_indices)
1420 << "\n\\paperorientation " << string_orientation[orientation]
1421 << "\n\\suppress_date " << convert<string>(suppress_date)
1422 << "\n\\justification " << convert<string>(justification)
1423 << "\n\\use_refstyle " << use_refstyle
1424 << "\n\\use_minted " << use_minted
1425 << "\n\\use_lineno " << use_lineno
1428 if (!lineno_opts.empty())
1429 os << "\\lineno_options " << lineno_opts << '\n';
1431 if (isbackgroundcolor)
1432 os << "\\backgroundcolor " << lyx::X11hexname(backgroundcolor) << '\n';
1434 os << "\\fontcolor " << lyx::X11hexname(fontcolor) << '\n';
1435 if (isnotefontcolor)
1436 os << "\\notefontcolor " << lyx::X11hexname(notefontcolor) << '\n';
1438 os << "\\boxbgcolor " << lyx::X11hexname(boxbgcolor) << '\n';
1440 for (auto const & br : branchlist()) {
1441 os << "\\branch " << to_utf8(br.branch())
1442 << "\n\\selected " << br.isSelected()
1443 << "\n\\filename_suffix " << br.hasFileNameSuffix()
1444 << "\n\\color " << br.lightModeColor() << " " << br.darkModeColor()
1449 for (auto const & id : indiceslist()) {
1450 os << "\\index " << to_utf8(id.index())
1451 << "\n\\shortcut " << to_utf8(id.shortcut())
1452 << "\n\\color " << lyx::X11hexname(id.color())
1457 for (auto const & si : spellignore()) {
1458 os << "\\spellchecker_ignore " << si.lang()->lang()
1459 << " " << to_utf8(si.word())
1463 if (!paperwidth.empty())
1464 os << "\\paperwidth "
1465 << VSpace(paperwidth).asLyXCommand() << '\n';
1466 if (!paperheight.empty())
1467 os << "\\paperheight "
1468 << VSpace(paperheight).asLyXCommand() << '\n';
1469 if (!leftmargin.empty())
1470 os << "\\leftmargin "
1471 << VSpace(leftmargin).asLyXCommand() << '\n';
1472 if (!topmargin.empty())
1473 os << "\\topmargin "
1474 << VSpace(topmargin).asLyXCommand() << '\n';
1475 if (!rightmargin.empty())
1476 os << "\\rightmargin "
1477 << VSpace(rightmargin).asLyXCommand() << '\n';
1478 if (!bottommargin.empty())
1479 os << "\\bottommargin "
1480 << VSpace(bottommargin).asLyXCommand() << '\n';
1481 if (!headheight.empty())
1482 os << "\\headheight "
1483 << VSpace(headheight).asLyXCommand() << '\n';
1484 if (!headsep.empty())
1486 << VSpace(headsep).asLyXCommand() << '\n';
1487 if (!footskip.empty())
1489 << VSpace(footskip).asLyXCommand() << '\n';
1490 if (!columnsep.empty())
1491 os << "\\columnsep "
1492 << VSpace(columnsep).asLyXCommand() << '\n';
1493 os << "\\secnumdepth " << secnumdepth
1494 << "\n\\tocdepth " << tocdepth
1495 << "\n\\paragraph_separation "
1496 << string_paragraph_separation[paragraph_separation];
1497 if (!paragraph_separation)
1498 os << "\n\\paragraph_indentation "
1499 << (getParIndent().empty() ? "default" : getParIndent().asString());
1501 os << "\n\\defskip " << getDefSkip().asLyXCommand();
1502 os << "\n\\is_math_indent " << is_math_indent;
1504 os << "\n\\math_indentation "
1505 << (getMathIndent().empty() ? "default" : getMathIndent().asString());
1506 os << "\n\\math_numbering_side ";
1507 switch(math_numbering_side) {
1517 os << "\n\\quotes_style "
1518 << string_quotes_style[static_cast<int>(quotes_style)]
1519 << "\n\\dynamic_quotes " << dynamic_quotes
1520 << "\n\\papercolumns " << columns
1521 << "\n\\papersides " << sides
1522 << "\n\\paperpagestyle " << pagestyle
1523 << "\n\\tablestyle " << tablestyle << '\n';
1524 if (!listings_params.empty())
1525 os << "\\listings_params \"" <<
1526 InsetListingsParams(listings_params).encodedString() << "\"\n";
1527 for (int i = 0; i < 4; ++i) {
1528 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
1529 if (user_defined_bullet(i).getFont() != -1) {
1530 os << "\\bullet " << i << " "
1531 << user_defined_bullet(i).getFont() << " "
1532 << user_defined_bullet(i).getCharacter() << " "
1533 << user_defined_bullet(i).getSize() << "\n";
1537 os << "\\bulletLaTeX " << i << " \""
1538 << lyx::to_ascii(user_defined_bullet(i).getText())
1544 os << "\\tracking_changes "
1545 << (save_transient_properties ? convert<string>(track_changes) : "false")
1548 os << "\\output_changes "
1549 << (save_transient_properties ? convert<string>(output_changes) : "false")
1552 os << "\\change_bars "
1553 << (save_transient_properties ? convert<string>(change_bars) : "false")
1556 os << "\\postpone_fragile_content " << convert<string>(postpone_fragile_content) << '\n';
1558 os << "\\html_math_output " << html_math_output << '\n'
1559 << "\\html_css_as_file " << html_css_as_file << '\n'
1560 << "\\html_be_strict " << convert<string>(html_be_strict) << '\n';
1562 os << "\\docbook_table_output " << docbook_table_output << '\n';
1563 os << "\\docbook_mathml_prefix " << docbook_mathml_prefix << '\n';
1565 if (html_math_img_scale != 1.0)
1566 os << "\\html_math_img_scale " << convert<string>(html_math_img_scale) << '\n';
1567 if (!html_latex_start.empty())
1568 os << "\\html_latex_start " << html_latex_start << '\n';
1569 if (!html_latex_end.empty())
1570 os << "\\html_latex_end " << html_latex_end << '\n';
1572 os << pimpl_->authorlist;
1576 void BufferParams::validate(LaTeXFeatures & features) const
1578 features.require(documentClass().required());
1580 if (columns > 1 && language->rightToLeft())
1581 features.require("rtloutputdblcol");
1583 if (output_changes) {
1584 bool xcolorulem = LaTeXFeatures::isAvailable("ulem") &&
1585 LaTeXFeatures::isAvailable("xcolor");
1587 switch (features.runparams().flavor) {
1589 case Flavor::DviLuaTeX:
1591 features.require("ct-xcolor-ulem");
1592 features.require("ulem");
1593 features.require("xcolor");
1595 features.require("ct-none");
1598 case Flavor::LuaTeX:
1599 case Flavor::PdfLaTeX:
1602 features.require("ct-xcolor-ulem");
1603 features.require("ulem");
1604 features.require("xcolor");
1605 // improves color handling in PDF output
1606 features.require("pdfcolmk");
1608 features.require("ct-none");
1615 features.require("changebar");
1618 // Floats with 'Here definitely' as default setting.
1619 if (float_placement.find('H') != string::npos)
1620 features.require("float");
1622 for (auto const & pm : use_packages) {
1623 if (pm.first == "amsmath") {
1624 // AMS Style is at document level
1625 if (pm.second == package_on ||
1626 features.isProvided("amsmath"))
1627 features.require(pm.first);
1628 } else if (pm.second == package_on)
1629 features.require(pm.first);
1632 // Document-level line spacing
1633 if (spacing().getSpace() != Spacing::Single && !spacing().isDefault())
1634 features.require("setspace");
1636 // the bullet shapes are buffer level not paragraph level
1637 // so they are tested here
1638 for (int i = 0; i < 4; ++i) {
1639 if (user_defined_bullet(i) == ITEMIZE_DEFAULTS[i])
1641 int const font = user_defined_bullet(i).getFont();
1643 int const c = user_defined_bullet(i).getCharacter();
1649 features.require("latexsym");
1651 } else if (font == 1) {
1652 features.require("amssymb");
1653 } else if (font >= 2 && font <= 5) {
1654 features.require("pifont");
1658 if (pdfoptions().use_hyperref) {
1659 features.require("hyperref");
1660 // due to interferences with babel and hyperref, the color package has to
1661 // be loaded after hyperref when hyperref is used with the colorlinks
1662 // option, see http://www.lyx.org/trac/ticket/5291
1663 if (pdfoptions().colorlinks)
1664 features.require("color");
1666 if (!listings_params.empty()) {
1667 // do not test validity because listings_params is
1668 // supposed to be valid
1670 InsetListingsParams(listings_params).separatedParams(true);
1671 // we can't support all packages, but we should load the color package
1672 if (par.find("\\color", 0) != string::npos)
1673 features.require("color");
1676 // some languages are only available via polyglossia
1677 if (features.hasPolyglossiaExclusiveLanguages())
1678 features.require("polyglossia");
1680 if (useNonTeXFonts && fontsMath() != "auto")
1681 features.require("unicode-math");
1684 features.require("microtype");
1686 if (!language->required().empty())
1687 features.require(language->required());
1691 bool BufferParams::writeLaTeX(otexstream & os, LaTeXFeatures & features,
1692 FileName const & filepath) const
1694 // http://www.tug.org/texmf-dist/doc/latex/base/fixltx2e.pdf
1695 // !! To use the Fix-cm package, load it before \documentclass, and use the command
1696 // \RequirePackage to do so, rather than the normal \usepackage
1697 // Do not try to load any other package before the document class, unless you
1698 // have a thorough understanding of the LATEX internals and know exactly what you
1700 if (features.mustProvide("fix-cm"))
1701 os << "\\RequirePackage{fix-cm}\n";
1702 // Likewise for fixltx2e. If other packages conflict with this policy,
1703 // treat it as a package bug (and report it!)
1704 // See http://www.latex-project.org/cgi-bin/ltxbugs2html?pr=latex/4407
1705 if (features.mustProvide("fixltx2e"))
1706 os << "\\RequirePackage{fixltx2e}\n";
1708 os << "\\documentclass";
1710 DocumentClass const & tclass = documentClass();
1712 ostringstream clsoptions; // the document class options.
1714 if (tokenPos(tclass.opt_fontsize(),
1715 '|', fontsize) >= 0) {
1716 // only write if existing in list (and not default)
1717 clsoptions << subst(tclass.fontsizeformat(), "$$s", fontsize) << ",";
1720 // paper sizes not supported by the class itself need the
1722 vector<string> classpsizes = getVectorFromString(tclass.opt_pagesize(), "|");
1723 bool class_supported_papersize = papersize == PAPER_DEFAULT
1724 || find(classpsizes.begin(), classpsizes.end(), string_papersize[papersize]) != classpsizes.end();
1726 if ((!use_geometry || features.isProvided("geometry-light"))
1727 && class_supported_papersize && papersize != PAPER_DEFAULT)
1728 clsoptions << subst(tclass.pagesizeformat(), "$$s", string_papersize[papersize]) << ",";
1731 if (sides != tclass.sides()) {
1734 clsoptions << "oneside,";
1737 clsoptions << "twoside,";
1743 if (columns != tclass.columns()) {
1745 clsoptions << "twocolumn,";
1747 clsoptions << "onecolumn,";
1751 && orientation == ORIENTATION_LANDSCAPE)
1752 clsoptions << "landscape,";
1755 clsoptions << "fleqn,";
1757 switch(math_numbering_side) {
1759 clsoptions << "leqno,";
1762 clsoptions << "reqno,";
1763 features.require("amsmath");
1769 // language should be a parameter to \documentclass
1770 if (language->babel() == "hebrew"
1771 && default_language->babel() != "hebrew")
1772 // This seems necessary
1773 features.useLanguage(default_language);
1775 ostringstream language_options;
1776 bool const use_babel = features.useBabel() && !features.isProvided("babel");
1777 bool const use_polyglossia = features.usePolyglossia();
1778 bool const global = lyxrc.language_global_options;
1779 if (features.useBabel() || (use_polyglossia && global)) {
1780 language_options << features.getBabelLanguages();
1781 if (!language->babel().empty()) {
1782 if (!language_options.str().empty())
1783 language_options << ',';
1784 language_options << language->babel();
1786 if (global && !language_options.str().empty())
1787 clsoptions << language_options.str() << ',';
1790 // the predefined options from the layout
1791 if (use_default_options && !tclass.options().empty())
1792 clsoptions << tclass.options() << ',';
1794 // the user-defined options
1795 if (!options.empty()) {
1796 clsoptions << options << ',';
1799 docstring const strOptions = from_utf8(clsoptions.str());
1800 if (!strOptions.empty()) {
1801 // Check if class options contain uncodable glyphs
1802 docstring uncodable_glyphs;
1803 docstring options_encodable;
1804 Encoding const * const enc = features.runparams().encoding;
1806 for (char_type c : strOptions) {
1807 if (!enc->encodable(c)) {
1808 docstring const glyph(1, c);
1809 LYXERR0("Uncodable character '"
1811 << "' in class options!");
1812 uncodable_glyphs += glyph;
1813 if (features.runparams().dryrun) {
1814 options_encodable += "<" + _("LyX Warning: ")
1815 + _("uncodable character") + " '";
1816 options_encodable += c;
1817 options_encodable += "'>";
1820 options_encodable += c;
1823 options_encodable = strOptions;
1825 // On BUFFER_VIEW|UPDATE, warn user if we found uncodable glyphs
1826 if (!features.runparams().dryrun && !uncodable_glyphs.empty()) {
1827 frontend::Alert::warning(
1828 _("Uncodable character in class options"),
1830 _("The class options of your document contain glyphs "
1831 "that are unknown in the current document encoding "
1832 "(namely %1$s).\nThese glyphs are omitted "
1833 " from the output, which may result in "
1834 "incomplete output."
1835 "\n\nPlease select an appropriate "
1836 "document encoding\n"
1837 "(such as utf8) or change the "
1838 "class options accordingly."),
1841 options_encodable = rtrim(options_encodable, ",");
1842 os << '[' << options_encodable << ']';
1845 os << '{' << from_ascii(tclass.latexname()) << "}\n";
1846 // end of \documentclass defs
1848 // The package options (via \PassOptionsToPackage)
1849 os << from_ascii(features.getPackageOptions());
1851 // if we use fontspec or newtxmath, we have to load the AMS packages here
1852 string const ams = features.loadAMSPackages();
1853 bool const ot1 = (main_font_encoding() == "default" || main_font_encoding() == "OT1");
1854 bool const use_newtxmath =
1855 theLaTeXFonts().getLaTeXFont(from_ascii(fontsMath())).getUsedPackage(
1856 ot1, false, false) == "newtxmath";
1857 if ((useNonTeXFonts || use_newtxmath) && !ams.empty())
1858 os << from_ascii(ams);
1860 if (useNonTeXFonts) {
1861 // Babel (as of 2017/11/03) loads fontspec itself
1862 if (!features.isProvided("fontspec")
1863 && !(features.useBabel() && features.isAvailable("babel-2017/11/03")))
1864 os << "\\usepackage{fontspec}\n";
1865 if (features.mustProvide("unicode-math")
1866 && features.isAvailable("unicode-math"))
1867 os << "\\usepackage{unicode-math}\n";
1870 // load CJK support package before font selection
1871 // (see autotests/export/latex/CJK/micro-sign_utf8-cjk-libertine.lyx)
1872 if (!useNonTeXFonts && encoding().package() != Encoding::none && inputenc != "utf8x"
1873 && (encoding().package() == Encoding::CJK || features.mustProvide("CJK"))) {
1874 if (inputenc == "utf8-cjk" || inputenc == "utf8")
1875 os << "\\usepackage{CJKutf8}\n";
1877 os << "\\usepackage[encapsulated]{CJK}\n";
1880 // font selection must be done before loading fontenc.sty
1881 // but after babel with non-TeX fonts
1882 string const fonts = loadFonts(features);
1883 if (!fonts.empty() && (!features.useBabel() || !useNonTeXFonts))
1884 os << from_utf8(fonts);
1886 if (fonts_default_family != "default")
1887 os << "\\renewcommand{\\familydefault}{\\"
1888 << from_ascii(fonts_default_family) << "}\n";
1890 // set font encoding
1891 // non-TeX fonts use font encoding TU (set by fontspec)
1892 if (!useNonTeXFonts && !features.isProvided("fontenc")
1893 && main_font_encoding() != "default") {
1894 // get main font encodings
1895 vector<string> fontencs = font_encodings();
1896 // get font encodings of secondary languages
1897 // FIXME: some languages (hebrew, ...) assume a standard font encoding as last
1898 // option (for text in other languages).
1899 features.getFontEncodings(fontencs);
1900 if (!fontencs.empty()) {
1901 os << "\\usepackage["
1902 << from_ascii(getStringFromVector(fontencs))
1907 // Load textcomp and pmboxdraw before (lua)inputenc (#11454)
1908 if (features.mustProvide("textcomp"))
1909 os << "\\usepackage{textcomp}\n";
1910 if (features.mustProvide("pmboxdraw"))
1911 os << "\\usepackage{pmboxdraw}\n";
1913 // handle inputenc etc.
1914 // (In documents containing text in Thai language,
1915 // we must load inputenc after babel, see lib/languages).
1916 if (!contains(features.getBabelPostsettings(), from_ascii("thai.ldf")))
1917 writeEncodingPreamble(os, features);
1920 if (!features.runparams().includeall && !included_children_.empty()) {
1921 os << "\\includeonly{";
1923 for (auto incfile : included_children_) {
1924 FileName inc = makeAbsPath(incfile, filepath.absFileName());
1925 string mangled = DocFileName(changeExtension(inc.absFileName(), ".tex")).
1927 if (!features.runparams().nice)
1929 // \includeonly doesn't want an extension
1930 incfile = changeExtension(incfile, string());
1931 incfile = support::latex_path(incfile);
1932 if (!incfile.empty()) {
1935 os << from_utf8(incfile);
1942 if (!features.isProvided("geometry")
1943 && (use_geometry || !class_supported_papersize)) {
1944 odocstringstream ods;
1945 if (!getGraphicsDriver("geometry").empty())
1946 ods << getGraphicsDriver("geometry");
1947 if (orientation == ORIENTATION_LANDSCAPE)
1948 ods << ",landscape";
1949 switch (papersize) {
1951 if (!paperwidth.empty())
1952 ods << ",paperwidth="
1953 << from_ascii(paperwidth);
1954 if (!paperheight.empty())
1955 ods << ",paperheight="
1956 << from_ascii(paperheight);
1958 case PAPER_USLETTER:
1960 case PAPER_USEXECUTIVE:
1989 ods << "," << from_ascii(string_papersize_geometry[papersize]);
1994 docstring g_options = trim(ods.str(), ",");
1995 os << "\\usepackage";
1996 // geometry-light means that the class works with geometry, but overwrites
1997 // the package options and paper sizes (memoir does this).
1998 // In this case, all options need to go to \geometry
1999 // and the standard paper sizes need to go to the class options.
2000 if (!g_options.empty() && !features.isProvided("geometry-light")) {
2001 os << '[' << g_options << ']';
2004 os << "{geometry}\n";
2005 if (use_geometry || features.isProvided("geometry-light")) {
2006 os << "\\geometry{verbose";
2007 if (!g_options.empty())
2008 // Output general options here with "geometry light".
2009 os << "," << g_options;
2010 // output this only if use_geometry is true
2012 if (!topmargin.empty())
2013 os << ",tmargin=" << from_ascii(Length(topmargin).asLatexString());
2014 if (!bottommargin.empty())
2015 os << ",bmargin=" << from_ascii(Length(bottommargin).asLatexString());
2016 if (!leftmargin.empty())
2017 os << ",lmargin=" << from_ascii(Length(leftmargin).asLatexString());
2018 if (!rightmargin.empty())
2019 os << ",rmargin=" << from_ascii(Length(rightmargin).asLatexString());
2020 if (!headheight.empty())
2021 os << ",headheight=" << from_ascii(Length(headheight).asLatexString());
2022 if (!headsep.empty())
2023 os << ",headsep=" << from_ascii(Length(headsep).asLatexString());
2024 if (!footskip.empty())
2025 os << ",footskip=" << from_ascii(Length(footskip).asLatexString());
2026 if (!columnsep.empty())
2027 os << ",columnsep=" << from_ascii(Length(columnsep).asLatexString());
2031 } else if (orientation == ORIENTATION_LANDSCAPE
2032 || papersize != PAPER_DEFAULT) {
2033 features.require("papersize");
2036 if (tokenPos(tclass.opt_pagestyle(), '|', pagestyle) >= 0) {
2037 if (pagestyle == "fancy")
2038 os << "\\usepackage{fancyhdr}\n";
2039 os << "\\pagestyle{" << from_ascii(pagestyle) << "}\n";
2042 // only output when the background color is not default
2043 if (isbackgroundcolor) {
2044 // only require color here, the background color will be defined
2045 // in LaTeXFeatures.cpp to avoid interferences with the LaTeX
2047 features.require("color");
2048 features.require("pagecolor");
2051 // only output when the font color is not default
2053 // only require color here, the font color will be defined
2054 // in LaTeXFeatures.cpp to avoid interferences with the LaTeX
2056 features.require("color");
2057 features.require("fontcolor");
2060 // Only if class has a ToC hierarchy
2061 if (tclass.hasTocLevels()) {
2062 if (secnumdepth != tclass.secnumdepth()) {
2063 os << "\\setcounter{secnumdepth}{"
2067 if (tocdepth != tclass.tocdepth()) {
2068 os << "\\setcounter{tocdepth}{"
2074 if (paragraph_separation) {
2075 // when skip separation
2077 switch (getDefSkip().kind()) {
2078 case VSpace::SMALLSKIP:
2079 psopt = "\\smallskipamount";
2081 case VSpace::MEDSKIP:
2082 psopt = "\\medskipamount";
2084 case VSpace::BIGSKIP:
2085 psopt = "\\bigskipamount";
2087 case VSpace::HALFLINE:
2088 // default (no option)
2090 case VSpace::FULLLINE:
2091 psopt = "\\baselineskip";
2093 case VSpace::LENGTH:
2094 psopt = getDefSkip().length().asLatexString();
2099 if (!features.isProvided("parskip")) {
2101 psopt = "[skip=" + psopt + "]";
2102 os << "\\usepackage" + psopt + "{parskip}\n";
2104 os << "\\setlength{\\parskip}{" + psopt + "}\n";
2107 // when separation by indentation
2108 // only output something when a width is given
2109 if (!getParIndent().empty()) {
2110 os << "\\setlength{\\parindent}{"
2111 << from_utf8(getParIndent().asLatexString())
2116 if (is_math_indent) {
2117 // when formula indentation
2118 // only output something when it is not the default
2119 if (!getMathIndent().empty()) {
2120 os << "\\setlength{\\mathindent}{"
2121 << from_utf8(getMathIndent().asString())
2126 // Now insert the LyX specific LaTeX commands...
2127 features.resolveAlternatives();
2128 features.expandMultiples();
2131 if (!output_sync_macro.empty())
2132 os << from_utf8(output_sync_macro) +"\n";
2133 else if (features.runparams().flavor == Flavor::LaTeX)
2134 os << "\\usepackage[active]{srcltx}\n";
2135 else if (features.runparams().flavor == Flavor::PdfLaTeX)
2136 os << "\\synctex=-1\n";
2139 // due to interferences with babel and hyperref, the color package has to
2140 // be loaded (when it is not already loaded) before babel when hyperref
2141 // is used with the colorlinks option, see
2142 // http://www.lyx.org/trac/ticket/5291
2143 // we decided therefore to load color always before babel, see
2144 // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg144349.html
2145 os << from_ascii(features.getColorOptions());
2147 // If we use hyperref, jurabib, japanese or varioref,
2148 // we have to call babel before
2150 && (features.isRequired("jurabib")
2151 || features.isRequired("hyperref")
2152 || features.isRequired("varioref")
2153 || features.isRequired("japanese"))) {
2154 os << features.getBabelPresettings();
2156 os << from_utf8(babelCall(language_options.str(),
2157 !lyxrc.language_global_options)) + '\n';
2158 os << features.getBabelPostsettings();
2161 // The optional packages;
2162 os << from_ascii(features.getPackages());
2164 // Additional Indices
2165 if (features.isRequired("splitidx")) {
2166 for (auto const & idx : indiceslist()) {
2167 os << "\\newindex{";
2168 os << escape(idx.shortcut());
2174 os << from_utf8(spacing().writePreamble(features.isProvided("SetSpace")));
2177 // * Hyperref manual: "Make sure it comes last of your loaded
2178 // packages, to give it a fighting chance of not being over-written,
2179 // since its job is to redefine many LaTeX commands."
2180 // * Email from Heiko Oberdiek: "It is usually better to load babel
2181 // before hyperref. Then hyperref has a chance to detect babel.
2182 // * Has to be loaded before the "LyX specific LaTeX commands" to
2183 // avoid errors with algorithm floats.
2184 // use hyperref explicitly if it is required
2185 if (features.isRequired("hyperref")) {
2186 OutputParams tmp_params = features.runparams();
2187 pdfoptions().writeLaTeX(tmp_params, os,
2188 features.isProvided("hyperref"));
2189 // correctly break URLs with hyperref and dvi/ps output
2190 if (features.runparams().hyperref_driver == "dvips"
2191 && features.isAvailable("breakurl"))
2192 os << "\\usepackage{breakurl}\n";
2193 } else if (features.isRequired("nameref"))
2194 // hyperref loads this automatically
2195 os << "\\usepackage{nameref}\n";
2198 os << "\\usepackage";
2199 if (!lineno_opts.empty())
2200 os << "[" << lineno_opts << "]";
2202 os << "\\linenumbers\n";
2205 // bibtopic needs to be loaded after hyperref.
2206 // the dot provides the aux file naming which LyX can detect.
2207 if (features.mustProvide("bibtopic"))
2208 os << "\\usepackage[dot]{bibtopic}\n";
2210 // Will be surrounded by \makeatletter and \makeatother when not empty
2211 otexstringstream atlyxpreamble;
2213 // Some macros LyX will need
2215 TexString tmppreamble = features.getMacros();
2216 if (!tmppreamble.str.empty())
2217 atlyxpreamble << "\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
2218 "LyX specific LaTeX commands.\n"
2219 << move(tmppreamble)
2222 // the text class specific preamble
2224 docstring tmppreamble = features.getTClassPreamble();
2225 if (!tmppreamble.empty())
2226 atlyxpreamble << "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
2227 "Textclass specific LaTeX commands.\n"
2231 // suppress date if selected
2232 // use \@ifundefined because we cannot be sure that every document class
2233 // has a \date command
2235 atlyxpreamble << "\\@ifundefined{date}{}{\\date{}}\n";
2237 /* the user-defined preamble */
2238 if (!containsOnly(preamble, " \n\t")) {
2240 atlyxpreamble << "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
2241 "User specified LaTeX commands.\n";
2243 // Check if the user preamble contains uncodable glyphs
2244 odocstringstream user_preamble;
2245 docstring uncodable_glyphs;
2246 Encoding const * const enc = features.runparams().encoding;
2248 for (char_type c : preamble) {
2249 if (!enc->encodable(c)) {
2250 docstring const glyph(1, c);
2251 LYXERR0("Uncodable character '"
2253 << "' in user preamble!");
2254 uncodable_glyphs += glyph;
2255 if (features.runparams().dryrun) {
2256 user_preamble << "<" << _("LyX Warning: ")
2257 << _("uncodable character") << " '";
2258 user_preamble.put(c);
2259 user_preamble << "'>";
2262 user_preamble.put(c);
2265 user_preamble << preamble;
2267 // On BUFFER_VIEW|UPDATE, warn user if we found uncodable glyphs
2268 if (!features.runparams().dryrun && !uncodable_glyphs.empty()) {
2269 frontend::Alert::warning(
2270 _("Uncodable character in user preamble"),
2272 _("The user preamble of your document contains glyphs "
2273 "that are unknown in the current document encoding "
2274 "(namely %1$s).\nThese glyphs are omitted "
2275 " from the output, which may result in "
2276 "incomplete output."
2277 "\n\nPlease select an appropriate "
2278 "document encoding\n"
2279 "(such as utf8) or change the "
2280 "preamble code accordingly."),
2283 atlyxpreamble << user_preamble.str() << '\n';
2286 // footmisc must be loaded after setspace
2287 // Load it here to avoid clashes with footmisc loaded in the user
2288 // preamble. For that reason we also pass the options via
2289 // \PassOptionsToPackage in getPreamble() and not here.
2290 if (features.mustProvide("footmisc"))
2291 atlyxpreamble << "\\usepackage{footmisc}\n";
2293 // subfig loads internally the LaTeX package "caption". As
2294 // caption is a very popular package, users will load it in
2295 // the preamble. Therefore we must load subfig behind the
2296 // user-defined preamble and check if the caption package was
2297 // loaded or not. For the case that caption is loaded before
2298 // subfig, there is the subfig option "caption=false". This
2299 // option also works when a koma-script class is used and
2300 // koma's own caption commands are used instead of caption. We
2301 // use \PassOptionsToPackage here because the user could have
2302 // already loaded subfig in the preamble.
2303 if (features.mustProvide("subfig"))
2304 atlyxpreamble << "\\ifdefined\\showcaptionsetup\n"
2305 " % Caption package is used. Advise subfig not to load it again.\n"
2306 " \\PassOptionsToPackage{caption=false}{subfig}\n"
2308 "\\usepackage{subfig}\n";
2310 // Itemize bullet settings need to be last in case the user
2311 // defines their own bullets that use a package included
2312 // in the user-defined preamble -- ARRae
2313 // Actually it has to be done much later than that
2314 // since some packages like frenchb make modifications
2315 // at \begin{document} time -- JMarc
2316 docstring bullets_def;
2317 for (int i = 0; i < 4; ++i) {
2318 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
2319 if (bullets_def.empty())
2320 bullets_def += "\\AtBeginDocument{\n";
2321 bullets_def += " \\def\\labelitemi";
2323 // `i' is one less than the item to modify
2330 bullets_def += "ii";
2336 bullets_def += '{' +
2337 user_defined_bullet(i).getText()
2342 if (!bullets_def.empty())
2343 atlyxpreamble << bullets_def << "}\n\n";
2345 if (!atlyxpreamble.empty())
2346 os << "\n\\makeatletter\n"
2347 << atlyxpreamble.release()
2348 << "\\makeatother\n\n";
2350 // We try to load babel late, in case it interferes with other packages.
2351 // Jurabib, hyperref, varioref, bicaption, menukeys and listings (bug 8995)
2352 // have to be called after babel, though.
2353 if (use_babel && !features.isRequired("jurabib")
2354 && !features.isRequired("hyperref")
2355 && !features.isRequired("varioref")
2356 && !features.isRequired("japanese")) {
2357 os << features.getBabelPresettings();
2359 os << from_utf8(babelCall(language_options.str(),
2360 !lyxrc.language_global_options)) + '\n';
2361 os << features.getBabelPostsettings();
2363 // In documents containing text in Thai language,
2364 // we must load inputenc after babel (see lib/languages).
2365 if (contains(features.getBabelPostsettings(), from_ascii("thai.ldf")))
2366 writeEncodingPreamble(os, features);
2368 // font selection must be done after babel with non-TeX fonts
2369 if (!fonts.empty() && features.useBabel() && useNonTeXFonts)
2370 os << from_utf8(fonts);
2372 if (features.isRequired("bicaption"))
2373 os << "\\usepackage{bicaption}\n";
2374 if (!listings_params.empty()
2375 || features.mustProvide("listings")
2376 || features.mustProvide("minted")) {
2378 os << "\\usepackage{minted}\n";
2380 os << "\\usepackage{listings}\n";
2382 string lst_params = listings_params;
2383 // If minted, do not output the language option (bug 11203)
2384 if (use_minted && contains(lst_params, "language=")) {
2385 vector<string> opts =
2386 getVectorFromString(lst_params, ",", false);
2387 for (size_t i = 0; i < opts.size(); ++i) {
2388 if (prefixIs(opts[i], "language="))
2389 opts.erase(opts.begin() + i--);
2391 lst_params = getStringFromVector(opts, ",");
2393 if (!lst_params.empty()) {
2395 os << "\\setminted{";
2398 // do not test validity because listings_params is
2399 // supposed to be valid
2401 InsetListingsParams(lst_params).separatedParams(true);
2402 os << from_utf8(par);
2406 // xunicode only needs to be loaded if tipa is used
2407 // (the rest is obsoleted by the new TU encoding).
2408 // It needs to be loaded at least after amsmath, amssymb,
2409 // esint and the other packages that provide special glyphs
2410 if (features.mustProvide("tipa") && useNonTeXFonts
2411 && !features.isProvided("xunicode")) {
2412 // The `xunicode` package officially only supports XeTeX,
2413 // but also works with LuaTeX. We work around its XeTeX test.
2414 if (features.runparams().flavor != Flavor::XeTeX) {
2415 os << "% Pretend to xunicode that we are XeTeX\n"
2416 << "\\def\\XeTeXpicfile{}\n";
2418 os << "\\usepackage{xunicode}\n";
2421 // covington must be loaded after beamerarticle
2422 if (features.isRequired("covington"))
2423 os << "\\usepackage{covington}\n";
2425 // Polyglossia must be loaded last ...
2426 if (use_polyglossia) {
2428 os << "\\usepackage{polyglossia}\n";
2429 // set the main language
2430 os << "\\setdefaultlanguage";
2431 if (!language->polyglossiaOpts().empty())
2432 os << "[" << from_ascii(language->polyglossiaOpts()) << "]";
2433 os << "{" << from_ascii(language->polyglossia()) << "}\n";
2434 // now setup the other languages
2435 set<string> const polylangs =
2436 features.getPolyglossiaLanguages();
2437 for (auto const & pl : polylangs) {
2438 // We do not output the options here; they are output in
2439 // the language switch commands. This is safer if multiple
2440 // varieties are used.
2441 if (pl == language->polyglossia())
2443 os << "\\setotherlanguage";
2444 os << "{" << from_ascii(pl) << "}\n";
2448 // ... but before biblatex (see #7065)
2449 if ((features.mustProvide("biblatex")
2450 || features.isRequired("biblatex-chicago"))
2451 && !features.isProvided("biblatex-chicago")
2452 && !features.isProvided("biblatex-natbib")
2453 && !features.isProvided("natbib-internal")
2454 && !features.isProvided("natbib")
2455 && !features.isProvided("jurabib")) {
2456 // The biblatex-chicago package has a differing interface
2457 // it uses a wrapper package and loads styles via fixed options
2458 bool const chicago = features.isRequired("biblatex-chicago");
2461 os << "\\usepackage";
2462 if (!biblatex_bibstyle.empty()
2463 && (biblatex_bibstyle == biblatex_citestyle)
2465 opts = "style=" + biblatex_bibstyle;
2467 } else if (!chicago) {
2468 if (!biblatex_bibstyle.empty()) {
2469 opts = "bibstyle=" + biblatex_bibstyle;
2472 if (!biblatex_citestyle.empty()) {
2473 opts += delim + "citestyle=" + biblatex_citestyle;
2477 if (!multibib.empty() && multibib != "child") {
2478 opts += delim + "refsection=" + multibib;
2481 if (bibtexCommand() == "bibtex8"
2482 || prefixIs(bibtexCommand(), "bibtex8 ")) {
2483 opts += delim + "backend=bibtex8";
2485 } else if (bibtexCommand() == "bibtex"
2486 || prefixIs(bibtexCommand(), "bibtex ")) {
2487 opts += delim + "backend=bibtex";
2490 if (!bib_encoding.empty() && encodings.fromLyXName(bib_encoding)) {
2491 opts += delim + "bibencoding="
2492 + encodings.fromLyXName(bib_encoding)->latexName();
2495 if (!biblio_opts.empty())
2496 opts += delim + biblio_opts;
2498 os << "[" << opts << "]";
2500 os << "{biblatex-chicago}\n";
2502 os << "{biblatex}\n";
2506 // Load custom language package here
2507 if (features.langPackage() == LaTeXFeatures::LANG_PACK_CUSTOM) {
2508 if (lang_package == "default")
2509 os << from_utf8(lyxrc.language_custom_package);
2511 os << from_utf8(lang_package);
2515 // Since menukeys uses catoptions, which does some heavy changes on key-value options,
2516 // it is recommended to load menukeys as the last package (even after hyperref)
2517 if (features.isRequired("menukeys"))
2518 os << "\\usepackage{menukeys}\n";
2520 docstring const i18npreamble =
2521 features.getTClassI18nPreamble(use_babel, use_polyglossia,
2523 if (!i18npreamble.empty())
2524 os << i18npreamble + '\n';
2530 void BufferParams::useClassDefaults()
2532 DocumentClass const & tclass = documentClass();
2534 sides = tclass.sides();
2535 columns = tclass.columns();
2536 pagestyle = tclass.pagestyle();
2537 tablestyle = tclass.tablestyle();
2538 use_default_options = true;
2539 // Only if class has a ToC hierarchy
2540 if (tclass.hasTocLevels()) {
2541 secnumdepth = tclass.secnumdepth();
2542 tocdepth = tclass.tocdepth();
2547 bool BufferParams::hasClassDefaults() const
2549 DocumentClass const & tclass = documentClass();
2551 return sides == tclass.sides()
2552 && columns == tclass.columns()
2553 && pagestyle == tclass.pagestyle()
2554 && tablestyle == tclass.tablestyle()
2555 && use_default_options
2556 && secnumdepth == tclass.secnumdepth()
2557 && tocdepth == tclass.tocdepth();
2561 DocumentClass const & BufferParams::documentClass() const
2567 DocumentClassConstPtr BufferParams::documentClassPtr() const
2573 void BufferParams::setDocumentClass(DocumentClassConstPtr tc)
2575 // evil, but this function is evil
2576 doc_class_ = const_pointer_cast<DocumentClass>(tc);
2577 invalidateConverterCache();
2581 bool BufferParams::setBaseClass(string const & classname, string const & path)
2583 LYXERR(Debug::TCLASS, "setBaseClass: " << classname);
2584 LayoutFileList & bcl = LayoutFileList::get();
2585 if (!bcl.haveClass(classname)) {
2587 bformat(_("The layout file:\n"
2589 "could not be found. A default textclass with default\n"
2590 "layouts will be used. LyX will not be able to produce\n"
2592 from_utf8(classname));
2593 frontend::Alert::error(_("Document class not found"), s);
2594 bcl.addEmptyClass(classname);
2597 bool const success = bcl[classname].load(path);
2600 bformat(_("Due to some error in it, the layout file:\n"
2602 "could not be loaded. A default textclass with default\n"
2603 "layouts will be used. LyX will not be able to produce\n"
2605 from_utf8(classname));
2606 frontend::Alert::error(_("Could not load class"), s);
2607 bcl.addEmptyClass(classname);
2610 pimpl_->baseClass_ = classname;
2611 layout_modules_.adaptToBaseClass(baseClass(), removed_modules_);
2616 LayoutFile const * BufferParams::baseClass() const
2618 if (LayoutFileList::get().haveClass(pimpl_->baseClass_))
2619 return &(LayoutFileList::get()[pimpl_->baseClass_]);
2625 LayoutFileIndex const & BufferParams::baseClassID() const
2627 return pimpl_->baseClass_;
2631 void BufferParams::makeDocumentClass(bool clone, bool internal)
2636 invalidateConverterCache();
2637 LayoutModuleList mods;
2638 for (auto const & mod : layout_modules_)
2639 mods.push_back(mod);
2641 doc_class_ = getDocumentClass(*baseClass(), mods, cite_engine_, clone, internal);
2643 TextClass::ReturnValues success = TextClass::OK;
2644 if (!forced_local_layout_.empty())
2645 success = doc_class_->read(to_utf8(forced_local_layout_),
2647 if (!local_layout_.empty() &&
2648 (success == TextClass::OK || success == TextClass::OK_OLDFORMAT))
2649 success = doc_class_->read(to_utf8(local_layout_), TextClass::MODULE);
2650 if (success != TextClass::OK && success != TextClass::OK_OLDFORMAT) {
2651 docstring const msg = _("Error reading internal layout information");
2652 frontend::Alert::warning(_("Read Error"), msg);
2657 bool BufferParams::layoutModuleCanBeAdded(string const & modName) const
2659 return layout_modules_.moduleCanBeAdded(modName, baseClass());
2663 docstring BufferParams::getLocalLayout(bool forced) const
2666 return from_utf8(doc_class_->forcedLayouts());
2668 return local_layout_;
2672 void BufferParams::setLocalLayout(docstring const & layout, bool forced)
2675 forced_local_layout_ = layout;
2677 local_layout_ = layout;
2681 bool BufferParams::addLayoutModule(string const & modName)
2683 for (auto const & mod : layout_modules_)
2686 layout_modules_.push_back(modName);
2691 string BufferParams::bufferFormat() const
2693 return documentClass().outputFormat();
2697 bool BufferParams::isExportable(string const & format, bool need_viewable) const
2699 FormatList const & formats = exportableFormats(need_viewable);
2700 for (auto const & fmt : formats) {
2701 if (fmt->name() == format)
2708 FormatList const & BufferParams::exportableFormats(bool only_viewable) const
2710 FormatList & cached = only_viewable ?
2711 pimpl_->viewableFormatList : pimpl_->exportableFormatList;
2712 bool & valid = only_viewable ?
2713 pimpl_->isViewCacheValid : pimpl_->isExportCacheValid;
2717 vector<string> const backs = backends();
2718 set<string> excludes;
2719 if (useNonTeXFonts) {
2720 excludes.insert("latex");
2721 excludes.insert("pdflatex");
2722 } else if (inputenc != "ascii" && inputenc != "utf8-plain") {
2723 // XeTeX with TeX fonts requires input encoding ascii (#10600).
2724 excludes.insert("xetex");
2728 theConverters().getReachable(backs[0], only_viewable, true, excludes);
2729 vector<string>::const_iterator it = backs.begin() + 1;
2730 for (; it != backs.end(); ++it) {
2731 FormatList r = theConverters().getReachable(*it, only_viewable,
2733 result.insert(result.end(), r.begin(), r.end());
2735 sort(result.begin(), result.end(), Format::formatSorter);
2742 vector<string> BufferParams::backends() const
2745 string const buffmt = bufferFormat();
2747 // FIXME: Don't hardcode format names here, but use a flag
2748 if (buffmt == "latex") {
2749 if (encoding().package() == Encoding::japanese)
2750 v.push_back("platex");
2752 if (!useNonTeXFonts) {
2753 v.push_back("pdflatex");
2754 v.push_back("latex");
2757 || inputenc == "ascii" || inputenc == "utf8-plain")
2758 v.push_back("xetex");
2759 v.push_back("luatex");
2760 v.push_back("dviluatex");
2763 string rbuffmt = buffmt;
2764 // If we use an OutputFormat in Japanese docs,
2765 // we need special format in order to get the path
2766 // via pLaTeX (#8823)
2767 if (documentClass().hasOutputFormat()
2768 && encoding().package() == Encoding::japanese)
2770 v.push_back(rbuffmt);
2773 v.push_back("xhtml");
2774 v.push_back("docbook5");
2775 v.push_back("text");
2781 Flavor BufferParams::getOutputFlavor(string const & format) const
2783 string const dformat = (format.empty() || format == "default") ?
2784 getDefaultOutputFormat() : format;
2785 DefaultFlavorCache::const_iterator it =
2786 default_flavors_.find(dformat);
2788 if (it != default_flavors_.end())
2791 Flavor result = Flavor::LaTeX;
2793 // FIXME It'd be better not to hardcode this, but to do
2794 // something with formats.
2795 if (dformat == "xhtml")
2796 result = Flavor::Html;
2797 else if (dformat == "docbook5")
2798 result = Flavor::DocBook5;
2799 else if (dformat == "text")
2800 result = Flavor::Text;
2801 else if (dformat == "lyx")
2802 result = Flavor::LyX;
2803 else if (dformat == "pdflatex")
2804 result = Flavor::PdfLaTeX;
2805 else if (dformat == "xetex")
2806 result = Flavor::XeTeX;
2807 else if (dformat == "luatex")
2808 result = Flavor::LuaTeX;
2809 else if (dformat == "dviluatex")
2810 result = Flavor::DviLuaTeX;
2812 // Try to determine flavor of default output format
2813 vector<string> backs = backends();
2814 if (find(backs.begin(), backs.end(), dformat) == backs.end()) {
2815 // Get shortest path to format
2816 Graph::EdgePath path;
2817 for (auto const & bvar : backs) {
2818 Graph::EdgePath p = theConverters().getPath(bvar, dformat);
2819 if (!p.empty() && (path.empty() || p.size() < path.size())) {
2824 result = theConverters().getFlavor(path);
2827 // cache this flavor
2828 default_flavors_[dformat] = result;
2833 string BufferParams::getDefaultOutputFormat() const
2835 if (!default_output_format.empty()
2836 && default_output_format != "default")
2837 return default_output_format;
2838 if (encoding().package() == Encoding::japanese)
2839 return lyxrc.default_platex_view_format;
2841 return lyxrc.default_otf_view_format;
2842 return lyxrc.default_view_format;
2845 Font const BufferParams::getFont() const
2847 FontInfo f = documentClass().defaultfont();
2848 if (fonts_default_family == "rmdefault")
2849 f.setFamily(ROMAN_FAMILY);
2850 else if (fonts_default_family == "sfdefault")
2851 f.setFamily(SANS_FAMILY);
2852 else if (fonts_default_family == "ttdefault")
2853 f.setFamily(TYPEWRITER_FAMILY);
2854 return Font(f, language);
2858 QuoteStyle BufferParams::getQuoteStyle(string const & qs) const
2860 return quotesstyletranslator().find(qs);
2864 bool BufferParams::isLatex() const
2866 return documentClass().outputType() == LATEX;
2870 bool BufferParams::isLiterate() const
2872 return documentClass().outputType() == LITERATE;
2876 void BufferParams::readPreamble(Lexer & lex)
2878 if (lex.getString() != "\\begin_preamble")
2879 lyxerr << "Error (BufferParams::readPreamble):"
2880 "consistency check failed." << endl;
2882 preamble = lex.getLongString(from_ascii("\\end_preamble"));
2886 void BufferParams::readLocalLayout(Lexer & lex, bool forced)
2888 string const expected = forced ? "\\begin_forced_local_layout" :
2889 "\\begin_local_layout";
2890 if (lex.getString() != expected)
2891 lyxerr << "Error (BufferParams::readLocalLayout):"
2892 "consistency check failed." << endl;
2895 forced_local_layout_ =
2896 lex.getLongString(from_ascii("\\end_forced_local_layout"));
2898 local_layout_ = lex.getLongString(from_ascii("\\end_local_layout"));
2902 bool BufferParams::setLanguage(string const & lang)
2904 Language const *new_language = languages.getLanguage(lang);
2905 if (!new_language) {
2906 // Language lang was not found
2909 language = new_language;
2914 void BufferParams::readLanguage(Lexer & lex)
2916 if (!lex.next()) return;
2918 string const tmptok = lex.getString();
2920 // check if tmptok is part of tex_babel in tex-defs.h
2921 if (!setLanguage(tmptok)) {
2922 // Language tmptok was not found
2923 language = default_language;
2924 lyxerr << "Warning: Setting language `"
2925 << tmptok << "' to `" << language->lang()
2931 void BufferParams::readGraphicsDriver(Lexer & lex)
2936 string const tmptok = lex.getString();
2937 // check if tmptok is part of tex_graphics in tex_defs.h
2940 string const test = tex_graphics[n++];
2942 if (test == tmptok) {
2943 graphics_driver = tmptok;
2948 "Warning: graphics driver `$$Token' not recognized!\n"
2949 " Setting graphics driver to `default'.\n");
2950 graphics_driver = "default";
2957 void BufferParams::readBullets(Lexer & lex)
2962 int const index = lex.getInteger();
2964 int temp_int = lex.getInteger();
2965 user_defined_bullet(index).setFont(temp_int);
2966 temp_bullet(index).setFont(temp_int);
2968 user_defined_bullet(index).setCharacter(temp_int);
2969 temp_bullet(index).setCharacter(temp_int);
2971 user_defined_bullet(index).setSize(temp_int);
2972 temp_bullet(index).setSize(temp_int);
2976 void BufferParams::readBulletsLaTeX(Lexer & lex)
2978 // The bullet class should be able to read this.
2981 int const index = lex.getInteger();
2983 docstring const temp_str = lex.getDocString();
2985 user_defined_bullet(index).setText(temp_str);
2986 temp_bullet(index).setText(temp_str);
2990 void BufferParams::readModules(Lexer & lex)
2992 if (!lex.eatLine()) {
2993 lyxerr << "Error (BufferParams::readModules):"
2994 "Unexpected end of input." << endl;
2998 string mod = lex.getString();
2999 if (mod == "\\end_modules")
3001 addLayoutModule(mod);
3007 void BufferParams::readRemovedModules(Lexer & lex)
3009 if (!lex.eatLine()) {
3010 lyxerr << "Error (BufferParams::readRemovedModules):"
3011 "Unexpected end of input." << endl;
3015 string mod = lex.getString();
3016 if (mod == "\\end_removed_modules")
3018 removed_modules_.push_back(mod);
3021 // now we want to remove any removed modules that were previously
3022 // added. normally, that will be because default modules were added in
3023 // setBaseClass(), which gets called when \textclass is read at the
3024 // start of the read.
3025 for (auto const & rm : removed_modules_) {
3026 LayoutModuleList::iterator const mit = layout_modules_.begin();
3027 LayoutModuleList::iterator const men = layout_modules_.end();
3028 LayoutModuleList::iterator found = find(mit, men, rm);
3031 layout_modules_.erase(found);
3036 void BufferParams::readIncludeonly(Lexer & lex)
3038 if (!lex.eatLine()) {
3039 lyxerr << "Error (BufferParams::readIncludeonly):"
3040 "Unexpected end of input." << endl;
3044 string child = lex.getString();
3045 if (child == "\\end_includeonly")
3047 included_children_.push_back(child);
3053 string BufferParams::paperSizeName(PapersizePurpose purpose, string const & psize) const
3055 PAPER_SIZE ppsize = psize.empty() ? papersize : papersizetranslator().find(psize);
3058 if (documentClass().pagesize() == "default")
3059 // could be anything, so don't guess
3061 return paperSizeName(purpose, documentClass().pagesize());
3062 case PAPER_CUSTOM: {
3063 if (purpose == XDVI && !paperwidth.empty() &&
3064 !paperheight.empty()) {
3065 // heightxwidth<unit>
3066 string first = paperwidth;
3067 string second = paperheight;
3068 if (orientation == ORIENTATION_LANDSCAPE)
3071 return first.erase(first.length() - 2)
3077 // dvips and dvipdfm do not know this
3078 if (purpose == DVIPS || purpose == DVIPDFM)
3082 if (purpose == DVIPS || purpose == DVIPDFM)
3086 if (purpose == DVIPS || purpose == DVIPDFM)
3096 if (purpose == DVIPS || purpose == DVIPDFM)
3100 if (purpose == DVIPS || purpose == DVIPDFM)
3104 if (purpose == DVIPS || purpose == DVIPDFM)
3108 if (purpose == DVIPS || purpose == DVIPDFM)
3112 if (purpose == DVIPS || purpose == DVIPDFM)
3116 // dvipdfm does not know this
3117 if (purpose == DVIPDFM)
3121 if (purpose == DVIPDFM)
3125 if (purpose == DVIPS || purpose == DVIPDFM)
3129 if (purpose == DVIPS || purpose == DVIPDFM)
3133 if (purpose == DVIPS || purpose == DVIPDFM)
3137 if (purpose == DVIPS || purpose == DVIPDFM)
3141 if (purpose == DVIPS || purpose == DVIPDFM)
3145 if (purpose == DVIPS || purpose == DVIPDFM)
3149 if (purpose == DVIPS || purpose == DVIPDFM)
3153 if (purpose == DVIPS || purpose == DVIPDFM)
3157 if (purpose == DVIPS || purpose == DVIPDFM)
3161 if (purpose == DVIPS || purpose == DVIPDFM)
3165 if (purpose == DVIPS || purpose == DVIPDFM)
3169 if (purpose == DVIPS || purpose == DVIPDFM)
3173 if (purpose == DVIPS || purpose == DVIPDFM)
3177 if (purpose == DVIPS || purpose == DVIPDFM)
3181 if (purpose == DVIPS || purpose == DVIPDFM)
3184 case PAPER_USEXECUTIVE:
3185 // dvipdfm does not know this
3186 if (purpose == DVIPDFM)
3191 case PAPER_USLETTER:
3193 if (purpose == XDVI)
3200 string const BufferParams::dvips_options() const
3204 // If the class loads the geometry package, we do not know which
3205 // paper size is used, since we do not set it (bug 7013).
3206 // Therefore we must not specify any argument here.
3207 // dvips gets the correct paper size via DVI specials in this case
3208 // (if the class uses the geometry package correctly).
3209 if (documentClass().provides("geometry"))
3213 && papersize == PAPER_CUSTOM
3214 && !lyxrc.print_paper_dimension_flag.empty()
3215 && !paperwidth.empty()
3216 && !paperheight.empty()) {
3217 // using a custom papersize
3218 result = lyxrc.print_paper_dimension_flag;
3219 result += ' ' + paperwidth;
3220 result += ',' + paperheight;
3222 string const paper_option = paperSizeName(DVIPS);
3223 if (!paper_option.empty() && (paper_option != "letter" ||
3224 orientation != ORIENTATION_LANDSCAPE)) {
3225 // dvips won't accept -t letter -t landscape.
3226 // In all other cases, include the paper size
3228 result = lyxrc.print_paper_flag;
3229 result += ' ' + paper_option;
3232 if (orientation == ORIENTATION_LANDSCAPE &&
3233 papersize != PAPER_CUSTOM)
3234 result += ' ' + lyxrc.print_landscape_flag;
3239 string const BufferParams::main_font_encoding() const
3241 if (font_encodings().empty()) {
3242 if (ascii_lowercase(language->fontenc(*this)) == "none")
3246 return font_encodings().back();
3250 vector<string> const BufferParams::font_encodings() const
3252 string doc_fontenc = (fontenc == "auto") ? string() : fontenc;
3254 vector<string> fontencs;
3256 // "default" means "no explicit font encoding"
3257 if (doc_fontenc != "default") {
3258 if (!doc_fontenc.empty())
3259 // If we have a custom setting, we use only that!
3260 return getVectorFromString(doc_fontenc);
3261 if (!language->fontenc(*this).empty()
3262 && ascii_lowercase(language->fontenc(*this)) != "none") {
3263 vector<string> fencs = getVectorFromString(language->fontenc(*this));
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 = (main_font_encoding() == "default" || main_font_encoding() == "OT1");
3516 bool const dryrun = features.runparams().dryrun;
3517 bool const complete = (fontsSans() == "default" && fontsTypewriter() == "default");
3518 bool const nomath = (fontsMath() != "auto");
3521 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsRoman())).getLaTeXCode(
3522 dryrun, ot1, complete, fonts_expert_sc, fonts_roman_osf,
3523 nomath, font_roman_opts);
3526 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsSans())).getLaTeXCode(
3527 dryrun, ot1, complete, fonts_expert_sc, fonts_sans_osf,
3528 nomath, font_sans_opts, fontsSansScale());
3530 // MONOSPACED/TYPEWRITER
3531 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsTypewriter())).getLaTeXCode(
3532 dryrun, ot1, complete, fonts_expert_sc, fonts_typewriter_osf,
3533 nomath, font_typewriter_opts, fontsTypewriterScale());
3536 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsMath())).getLaTeXCode(
3537 dryrun, ot1, complete, fonts_expert_sc, fonts_roman_osf,
3544 Encoding const & BufferParams::encoding() const
3546 // Main encoding for LaTeX output.
3548 return *(encodings.fromLyXName("utf8-plain"));
3549 if (inputenc == "auto-legacy" || inputenc == "auto-legacy-plain")
3550 return *language->encoding();
3551 if (inputenc == "utf8" && language->lang() == "japanese")
3552 return *(encodings.fromLyXName("utf8-platex"));
3553 Encoding const * const enc = encodings.fromLyXName(inputenc);
3556 LYXERR0("Unknown inputenc value `" << inputenc
3557 << "'. Using `auto' instead.");
3558 return *language->encoding();
3562 string const & BufferParams::defaultBiblioStyle() const
3564 if (!biblio_style.empty())
3565 return biblio_style;
3567 map<string, string> const & bs = documentClass().defaultBiblioStyle();
3568 auto cit = bs.find(theCiteEnginesList.getTypeAsString(citeEngineType()));
3569 if (cit != bs.end())
3572 return empty_string();
3576 bool BufferParams::fullAuthorList() const
3578 return documentClass().fullAuthorList();
3582 string BufferParams::getCiteAlias(string const & s) const
3584 vector<string> commands =
3585 documentClass().citeCommands(citeEngineType());
3586 // If it is a real command, don't treat it as an alias
3587 if (find(commands.begin(), commands.end(), s) != commands.end())
3589 map<string,string> aliases = documentClass().citeCommandAliases();
3590 if (aliases.find(s) != aliases.end())
3596 vector<string> BufferParams::citeCommands() const
3598 static CitationStyle const default_style;
3599 vector<string> commands =
3600 documentClass().citeCommands(citeEngineType());
3601 if (commands.empty())
3602 commands.push_back(default_style.name);
3607 vector<CitationStyle> BufferParams::citeStyles() const
3609 static CitationStyle const default_style;
3610 vector<CitationStyle> styles =
3611 documentClass().citeStyles(citeEngineType());
3613 styles.push_back(default_style);
3618 string const BufferParams::bibtexCommand() const
3620 // Return document-specific setting if available
3621 if (bibtex_command != "default")
3622 return bibtex_command;
3624 // If we have "default" in document settings, consult the prefs
3625 // 1. Japanese (uses a specific processor)
3626 if (encoding().package() == Encoding::japanese) {
3627 if (lyxrc.jbibtex_command != "automatic")
3628 // Return the specified program, if "automatic" is not set
3629 return lyxrc.jbibtex_command;
3630 else if (!useBiblatex()) {
3631 // With classic BibTeX, return pbibtex, jbibtex, bibtex
3632 if (lyxrc.jbibtex_alternatives.find("pbibtex") != lyxrc.jbibtex_alternatives.end())
3634 if (lyxrc.jbibtex_alternatives.find("jbibtex") != lyxrc.jbibtex_alternatives.end())
3639 // 2. All other languages
3640 else if (lyxrc.bibtex_command != "automatic")
3641 // Return the specified program, if "automatic" is not set
3642 return lyxrc.bibtex_command;
3644 // 3. Automatic: find the most suitable for the current cite framework
3645 if (useBiblatex()) {
3646 // For Biblatex, we prefer biber (also for Japanese)
3647 // and fall back to bibtex8 and, as last resort, bibtex
3648 if (lyxrc.bibtex_alternatives.find("biber") != lyxrc.bibtex_alternatives.end())
3650 else if (lyxrc.bibtex_alternatives.find("bibtex8") != lyxrc.bibtex_alternatives.end())
3657 bool BufferParams::useBiblatex() const
3659 return theCiteEnginesList[citeEngine()]->getCiteFramework() == "biblatex";
3663 void BufferParams::invalidateConverterCache() const
3665 pimpl_->isExportCacheValid = false;
3666 pimpl_->isViewCacheValid = false;
3670 // We shouldn't need to reset the params here, since anything
3671 // we need will be recopied.
3672 void BufferParams::copyForAdvFR(const BufferParams & bp)
3674 string const & lang = bp.language->lang();
3676 layout_modules_ = bp.layout_modules_;
3677 string const & doc_class = bp.documentClass().name();
3678 setBaseClass(doc_class);
3682 void BufferParams::setBibFileEncoding(string const & file, string const & enc)
3684 bib_encodings[file] = enc;
3688 string const BufferParams::bibFileEncoding(string const & file) const
3690 if (bib_encodings.find(file) == bib_encodings.end())
3692 return bib_encodings.find(file)->second;