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"
24 #include "buffer_funcs.h"
26 #include "CiteEnginesList.h"
29 #include "Converter.h"
31 #include "IndicesList.h"
33 #include "LaTeXFeatures.h"
34 #include "LaTeXFonts.h"
36 #include "ModuleList.h"
40 #include "OutputParams.h"
42 #include "texstream.h"
45 #include "PDFOptions.h"
47 #include "frontends/alert.h"
49 #include "insets/InsetListingsParams.h"
51 #include "support/convert.h"
52 #include "support/debug.h"
53 #include "support/docstream.h"
54 #include "support/FileName.h"
55 #include "support/filetools.h"
56 #include "support/gettext.h"
57 #include "support/Messages.h"
58 #include "support/mutex.h"
59 #include "support/Package.h"
60 #include "support/Translator.h"
61 #include "support/lstrings.h"
67 using namespace lyx::support;
70 static char const * const string_paragraph_separation[] = {
75 static char const * const string_quotes_style[] = {
76 "english", "swedish", "german", "polish", "swiss", "danish", "plain",
77 "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, InsetQuotesParams::QuoteStyle> QuotesStyleTranslator;
143 QuotesStyleTranslator const init_quotesstyletranslator()
145 QuotesStyleTranslator translator
146 (string_quotes_style[0], InsetQuotesParams::EnglishQuotes);
147 translator.addPair(string_quotes_style[1], InsetQuotesParams::SwedishQuotes);
148 translator.addPair(string_quotes_style[2], InsetQuotesParams::GermanQuotes);
149 translator.addPair(string_quotes_style[3], InsetQuotesParams::PolishQuotes);
150 translator.addPair(string_quotes_style[4], InsetQuotesParams::SwissQuotes);
151 translator.addPair(string_quotes_style[5], InsetQuotesParams::DanishQuotes);
152 translator.addPair(string_quotes_style[6], InsetQuotesParams::PlainQuotes);
153 translator.addPair(string_quotes_style[7], InsetQuotesParams::BritishQuotes);
154 translator.addPair(string_quotes_style[8], InsetQuotesParams::SwedishGQuotes);
155 translator.addPair(string_quotes_style[9], InsetQuotesParams::FrenchQuotes);
156 translator.addPair(string_quotes_style[10], InsetQuotesParams::FrenchINQuotes);
157 translator.addPair(string_quotes_style[11], InsetQuotesParams::RussianQuotes);
158 translator.addPair(string_quotes_style[12], InsetQuotesParams::CJKQuotes);
159 translator.addPair(string_quotes_style[13], InsetQuotesParams::CJKAngleQuotes);
164 QuotesStyleTranslator const & quotesstyletranslator()
166 static QuotesStyleTranslator const translator =
167 init_quotesstyletranslator();
173 typedef Translator<string, PAPER_SIZE> PaperSizeTranslator;
176 static PaperSizeTranslator initPaperSizeTranslator()
178 PaperSizeTranslator translator(string_papersize[0], PAPER_DEFAULT);
179 translator.addPair(string_papersize[1], PAPER_CUSTOM);
180 translator.addPair(string_papersize[2], PAPER_USLETTER);
181 translator.addPair(string_papersize[3], PAPER_USLEGAL);
182 translator.addPair(string_papersize[4], PAPER_USEXECUTIVE);
183 translator.addPair(string_papersize[5], PAPER_A0);
184 translator.addPair(string_papersize[6], PAPER_A1);
185 translator.addPair(string_papersize[7], PAPER_A2);
186 translator.addPair(string_papersize[8], PAPER_A3);
187 translator.addPair(string_papersize[9], PAPER_A4);
188 translator.addPair(string_papersize[10], PAPER_A5);
189 translator.addPair(string_papersize[11], PAPER_A6);
190 translator.addPair(string_papersize[12], PAPER_B0);
191 translator.addPair(string_papersize[13], PAPER_B1);
192 translator.addPair(string_papersize[14], PAPER_B2);
193 translator.addPair(string_papersize[15], PAPER_B3);
194 translator.addPair(string_papersize[16], PAPER_B4);
195 translator.addPair(string_papersize[17], PAPER_B5);
196 translator.addPair(string_papersize[18], PAPER_B6);
197 translator.addPair(string_papersize[19], PAPER_C0);
198 translator.addPair(string_papersize[20], PAPER_C1);
199 translator.addPair(string_papersize[21], PAPER_C2);
200 translator.addPair(string_papersize[22], PAPER_C3);
201 translator.addPair(string_papersize[23], PAPER_C4);
202 translator.addPair(string_papersize[24], PAPER_C5);
203 translator.addPair(string_papersize[25], PAPER_C6);
204 translator.addPair(string_papersize[26], PAPER_JISB0);
205 translator.addPair(string_papersize[27], PAPER_JISB1);
206 translator.addPair(string_papersize[28], PAPER_JISB2);
207 translator.addPair(string_papersize[29], PAPER_JISB3);
208 translator.addPair(string_papersize[30], PAPER_JISB4);
209 translator.addPair(string_papersize[31], PAPER_JISB5);
210 translator.addPair(string_papersize[32], PAPER_JISB6);
215 PaperSizeTranslator const & papersizetranslator()
217 static PaperSizeTranslator const translator =
218 initPaperSizeTranslator();
224 typedef Translator<string, PAPER_ORIENTATION> PaperOrientationTranslator;
227 PaperOrientationTranslator const init_paperorientationtranslator()
229 PaperOrientationTranslator translator(string_orientation[0], ORIENTATION_PORTRAIT);
230 translator.addPair(string_orientation[1], ORIENTATION_LANDSCAPE);
235 PaperOrientationTranslator const & paperorientationtranslator()
237 static PaperOrientationTranslator const translator =
238 init_paperorientationtranslator();
244 typedef Translator<int, PageSides> SidesTranslator;
247 SidesTranslator const init_sidestranslator()
249 SidesTranslator translator(1, OneSide);
250 translator.addPair(2, TwoSides);
255 SidesTranslator const & sidestranslator()
257 static SidesTranslator const translator = init_sidestranslator();
263 typedef Translator<int, BufferParams::Package> PackageTranslator;
266 PackageTranslator const init_packagetranslator()
268 PackageTranslator translator(0, BufferParams::package_off);
269 translator.addPair(1, BufferParams::package_auto);
270 translator.addPair(2, BufferParams::package_on);
275 PackageTranslator const & packagetranslator()
277 static PackageTranslator const translator =
278 init_packagetranslator();
284 typedef Translator<string, Spacing::Space> SpaceTranslator;
287 SpaceTranslator const init_spacetranslator()
289 SpaceTranslator translator("default", Spacing::Default);
290 translator.addPair("single", Spacing::Single);
291 translator.addPair("onehalf", Spacing::Onehalf);
292 translator.addPair("double", Spacing::Double);
293 translator.addPair("other", Spacing::Other);
298 SpaceTranslator const & spacetranslator()
300 static SpaceTranslator const translator = init_spacetranslator();
305 bool inSystemDir(FileName const & document_dir, string & system_dir)
307 // A document is assumed to be in a system LyX directory (not
308 // necessarily the system directory of the running instance)
309 // if both "configure.py" and "chkconfig.ltx" are found in
310 // either document_dir/../ or document_dir/../../.
311 // If true, the system directory path is returned in system_dir
312 // with a trailing path separator.
314 string const msg = "Checking whether document is in a system dir...";
316 string dir = document_dir.absFileName();
318 for (int i = 0; i < 3; ++i) {
319 dir = addPath(dir, "..");
320 if (!fileSearch(dir, "configure.py").empty() &&
321 !fileSearch(dir, "chkconfig.ltx").empty()) {
322 LYXERR(Debug::FILES, msg << " yes");
323 system_dir = addPath(FileName(dir).realPath(), "");
328 LYXERR(Debug::FILES, msg << " no");
329 system_dir = string();
336 class BufferParams::Impl
341 AuthorList authorlist;
342 BranchList branchlist;
343 Bullet temp_bullets[4];
344 Bullet user_defined_bullets[4];
345 IndicesList indiceslist;
349 /** This is the amount of space used for paragraph_separation "skip",
350 * and for detached paragraphs in "indented" documents.
353 PDFOptions pdfoptions;
354 LayoutFileIndex baseClass_;
355 FormatList exportableFormatList;
356 FormatList viewableFormatList;
357 bool isViewCacheValid;
358 bool isExportCacheValid;
362 BufferParams::Impl::Impl()
363 : defskip(VSpace::MEDSKIP), baseClass_(string("")),
364 isViewCacheValid(false), isExportCacheValid(false)
366 // set initial author
368 authorlist.record(Author(from_utf8(lyxrc.user_name),
369 from_utf8(lyxrc.user_email),
370 from_utf8(lyxrc.user_initials)));
375 BufferParams::MemoryTraits::clone(BufferParams::Impl const * ptr)
378 return new BufferParams::Impl(*ptr);
382 void BufferParams::MemoryTraits::destroy(BufferParams::Impl * ptr)
388 BufferParams::BufferParams()
391 setBaseClass(defaultBaseclass());
392 cite_engine_ = "basic";
393 cite_engine_type_ = ENGINE_TYPE_DEFAULT;
395 paragraph_separation = ParagraphIndentSeparation;
396 is_math_indent = false;
397 math_numbering_side = DEFAULT;
398 quotes_style = InsetQuotesParams::EnglishQuotes;
399 dynamic_quotes = false;
400 fontsize = "default";
403 papersize = PAPER_DEFAULT;
404 orientation = ORIENTATION_PORTRAIT;
405 use_geometry = false;
406 biblio_style = string();
407 use_bibtopic = false;
410 save_transient_properties = true;
411 track_changes = false;
412 output_changes = false;
414 postpone_fragile_content = true;
415 use_default_options = true;
416 maintain_unincluded_children = CM_None;
419 language = default_language;
421 fonts_roman[0] = "default";
422 fonts_roman[1] = "default";
423 fonts_sans[0] = "default";
424 fonts_sans[1] = "default";
425 fonts_typewriter[0] = "default";
426 fonts_typewriter[1] = "default";
427 fonts_math[0] = "auto";
428 fonts_math[1] = "auto";
429 fonts_default_family = "default";
430 useNonTeXFonts = false;
431 use_microtype = false;
432 use_dash_ligatures = true;
433 fonts_expert_sc = false;
434 fonts_roman_osf = false;
435 fonts_sans_osf = false;
436 fonts_typewriter_osf = false;
437 fonts_sans_scale[0] = 100;
438 fonts_sans_scale[1] = 100;
439 fonts_typewriter_scale[0] = 100;
440 fonts_typewriter_scale[1] = 100;
442 lang_package = "default";
443 graphics_driver = "default";
444 default_output_format = "default";
445 bibtex_command = "default";
446 index_command = "default";
449 listings_params = string();
450 pagestyle = "default";
451 tablestyle = "default";
452 suppress_date = false;
453 justification = true;
454 // no color is the default (white)
455 backgroundcolor = lyx::rgbFromHexName("#ffffff");
456 isbackgroundcolor = false;
457 // no color is the default (black)
458 fontcolor = lyx::rgbFromHexName("#000000");
460 // light gray is the default font color for greyed-out notes
461 notefontcolor = lyx::rgbFromHexName("#cccccc");
462 boxbgcolor = lyx::rgbFromHexName("#ff0000");
463 compressed = lyxrc.save_compressed;
464 for (int iter = 0; iter < 4; ++iter) {
465 user_defined_bullet(iter) = ITEMIZE_DEFAULTS[iter];
466 temp_bullet(iter) = ITEMIZE_DEFAULTS[iter];
469 indiceslist().addDefault(B_("Index"));
470 html_be_strict = false;
471 html_math_output = MathML;
472 html_math_img_scale = 1.0;
473 html_css_as_file = false;
474 display_pixel_ratio = 1.0;
476 shell_escape = false;
482 // map current author
483 author_map_[pimpl_->authorlist.get(0).bufferId()] = 0;
487 docstring BufferParams::B_(string const & l10n) const
489 LASSERT(language, return from_utf8(l10n));
490 return getMessages(language->code()).get(l10n);
494 BufferParams::Package BufferParams::use_package(std::string const & p) const
496 PackageMap::const_iterator it = use_packages.find(p);
497 if (it == use_packages.end())
503 void BufferParams::use_package(std::string const & p, BufferParams::Package u)
509 map<string, string> const & BufferParams::auto_packages()
511 static map<string, string> packages;
512 if (packages.empty()) {
513 // We could have a race condition here that two threads
514 // discover an empty map at the same time and want to fill
515 // it, but that is no problem, since the same contents is
516 // filled in twice then. Having the locker inside the
517 // packages.empty() condition has the advantage that we
518 // don't need the mutex overhead for simple reading.
520 Mutex::Locker locker(&mutex);
521 // adding a package here implies a file format change!
522 packages["amsmath"] =
523 N_("The LaTeX package amsmath is only used if AMS formula types or symbols from the AMS math toolbars are inserted into formulas");
524 packages["amssymb"] =
525 N_("The LaTeX package amssymb is only used if symbols from the AMS math toolbars are inserted into formulas");
527 N_("The LaTeX package cancel is only used if \\cancel commands are used in formulas");
529 N_("The LaTeX package esint is only used if special integral symbols are inserted into formulas");
530 packages["mathdots"] =
531 N_("The LaTeX package mathdots is only used if the command \\iddots is inserted into formulas");
532 packages["mathtools"] =
533 N_("The LaTeX package mathtools is only used if some mathematical relations are inserted into formulas");
535 N_("The LaTeX package mhchem is only used if either the command \\ce or \\cf is inserted into formulas");
536 packages["stackrel"] =
537 N_("The LaTeX package stackrel is only used if the command \\stackrel with subscript is inserted into formulas");
538 packages["stmaryrd"] =
539 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");
540 packages["undertilde"] =
541 N_("The LaTeX package undertilde is only used if you use the math frame decoration 'utilde'");
547 bool BufferParams::useBibtopic() const
551 return (use_bibtopic || (!multibib.empty() && multibib != "child"));
555 AuthorList & BufferParams::authors()
557 return pimpl_->authorlist;
561 AuthorList const & BufferParams::authors() const
563 return pimpl_->authorlist;
567 void BufferParams::addAuthor(Author a)
569 author_map_[a.bufferId()] = pimpl_->authorlist.record(a);
573 BranchList & BufferParams::branchlist()
575 return pimpl_->branchlist;
579 BranchList const & BufferParams::branchlist() const
581 return pimpl_->branchlist;
585 IndicesList & BufferParams::indiceslist()
587 return pimpl_->indiceslist;
591 IndicesList const & BufferParams::indiceslist() const
593 return pimpl_->indiceslist;
597 Bullet & BufferParams::temp_bullet(lyx::size_type const index)
599 LASSERT(index < 4, return pimpl_->temp_bullets[0]);
600 return pimpl_->temp_bullets[index];
604 Bullet const & BufferParams::temp_bullet(lyx::size_type const index) const
606 LASSERT(index < 4, return pimpl_->temp_bullets[0]);
607 return pimpl_->temp_bullets[index];
611 Bullet & BufferParams::user_defined_bullet(lyx::size_type const index)
613 LASSERT(index < 4, return pimpl_->temp_bullets[0]);
614 return pimpl_->user_defined_bullets[index];
618 Bullet const & BufferParams::user_defined_bullet(lyx::size_type const index) const
620 LASSERT(index < 4, return pimpl_->temp_bullets[0]);
621 return pimpl_->user_defined_bullets[index];
625 Spacing & BufferParams::spacing()
627 return pimpl_->spacing;
631 Spacing const & BufferParams::spacing() const
633 return pimpl_->spacing;
637 PDFOptions & BufferParams::pdfoptions()
639 return pimpl_->pdfoptions;
643 PDFOptions const & BufferParams::pdfoptions() const
645 return pimpl_->pdfoptions;
649 Length const & BufferParams::getMathIndent() const
651 return pimpl_->mathindent;
655 void BufferParams::setMathIndent(Length const & indent)
657 pimpl_->mathindent = indent;
661 Length const & BufferParams::getParIndent() const
663 return pimpl_->parindent;
667 void BufferParams::setParIndent(Length const & indent)
669 pimpl_->parindent = indent;
673 VSpace const & BufferParams::getDefSkip() const
675 return pimpl_->defskip;
679 void BufferParams::setDefSkip(VSpace const & vs)
681 // DEFSKIP will cause an infinite loop
682 LASSERT(vs.kind() != VSpace::DEFSKIP, return);
683 pimpl_->defskip = vs;
687 BufferParams::MathNumber BufferParams::getMathNumber() const
689 if (math_numbering_side != DEFAULT)
690 return math_numbering_side;
691 // FIXME: do not hardcode language here
692 else if (language->lang() == "arabic_arabi"
693 || documentClass().provides("leqno"))
700 string BufferParams::readToken(Lexer & lex, string const & token,
701 FileName const & filepath)
705 if (token == "\\textclass") {
707 string const classname = lex.getString();
708 // if there exists a local layout file, ignore the system one
709 // NOTE: in this case, the textclass (.cls file) is assumed to
712 LayoutFileList & bcl = LayoutFileList::get();
713 if (!filepath.empty()) {
714 // If classname is an absolute path, the document is
715 // using a local layout file which could not be accessed
716 // by a relative path. In this case the path is correct
717 // even if the document was moved to a different
718 // location. However, we will have a problem if the
719 // document was generated on a different platform.
720 bool isabsolute = FileName::isAbsolute(classname);
721 string const classpath = onlyPath(classname);
722 string const path = isabsolute ? classpath
723 : FileName(addPath(filepath.absFileName(),
724 classpath)).realPath();
725 string const oldpath = isabsolute ? string()
726 : FileName(addPath(origin, classpath)).realPath();
727 tcp = bcl.addLocalLayout(onlyFileName(classname), path, oldpath);
729 // that returns non-empty if a "local" layout file is found.
731 result = to_utf8(makeRelPath(from_utf8(onlyPath(tcp)),
732 from_utf8(filepath.absFileName())));
735 setBaseClass(onlyFileName(tcp));
737 setBaseClass(onlyFileName(classname));
738 // We assume that a tex class exists for local or unknown
739 // layouts so this warning, will only be given for system layouts.
740 if (!baseClass()->isTeXClassAvailable()) {
741 docstring const desc =
742 translateIfPossible(from_utf8(baseClass()->description()));
743 docstring const prereqs =
744 from_utf8(baseClass()->prerequisites());
745 docstring const msg =
746 bformat(_("The selected document class\n"
748 "requires external files that are not available.\n"
749 "The document class can still be used, but the\n"
750 "document cannot be compiled until the following\n"
751 "prerequisites are installed:\n"
753 "See section 3.1.2.2 (Class Availability) of the\n"
754 "User's Guide for more information."), desc, prereqs);
755 frontend::Alert::warning(_("Document class not available"),
758 } else if (token == "\\save_transient_properties") {
759 lex >> save_transient_properties;
760 } else if (token == "\\origin") {
762 origin = lex.getString();
763 string const sysdirprefix = "/systemlyxdir/";
764 if (prefixIs(origin, sysdirprefix)) {
766 if (inSystemDir(filepath, docsys))
767 origin.replace(0, sysdirprefix.length() - 1, docsys);
769 origin.replace(0, sysdirprefix.length() - 1,
770 package().system_support().absFileName());
772 } else if (token == "\\begin_preamble") {
774 } else if (token == "\\begin_local_layout") {
775 readLocalLayout(lex, false);
776 } else if (token == "\\begin_forced_local_layout") {
777 readLocalLayout(lex, true);
778 } else if (token == "\\begin_modules") {
780 } else if (token == "\\begin_removed_modules") {
781 readRemovedModules(lex);
782 } else if (token == "\\begin_includeonly") {
783 readIncludeonly(lex);
784 } else if (token == "\\maintain_unincluded_children") {
788 maintain_unincluded_children = CM_None;
789 else if (tmp == "mostly")
790 maintain_unincluded_children = CM_Mostly;
791 else if (tmp == "strict")
792 maintain_unincluded_children = CM_Strict;
793 } else if (token == "\\options") {
795 options = lex.getString();
796 } else if (token == "\\use_default_options") {
797 lex >> use_default_options;
798 } else if (token == "\\master") {
800 master = lex.getString();
801 if (!filepath.empty() && FileName::isAbsolute(origin)) {
802 bool const isabs = FileName::isAbsolute(master);
803 FileName const abspath(isabs ? master : origin + master);
804 bool const moved = filepath != FileName(origin);
805 if (moved && abspath.exists()) {
806 docstring const path = isabs
808 : from_utf8(abspath.realPath());
809 docstring const refpath =
810 from_utf8(filepath.absFileName());
811 master = to_utf8(makeRelPath(path, refpath));
814 } else if (token == "\\suppress_date") {
815 lex >> suppress_date;
816 } else if (token == "\\justification") {
817 lex >> justification;
818 } else if (token == "\\language") {
820 } else if (token == "\\language_package") {
822 lang_package = lex.getString();
823 } else if (token == "\\inputencoding") {
825 } else if (token == "\\graphics") {
826 readGraphicsDriver(lex);
827 } else if (token == "\\default_output_format") {
828 lex >> default_output_format;
829 } else if (token == "\\bibtex_command") {
831 bibtex_command = lex.getString();
832 } else if (token == "\\index_command") {
834 index_command = lex.getString();
835 } else if (token == "\\fontencoding") {
837 fontenc = lex.getString();
838 } else if (token == "\\font_roman") {
839 lex >> fonts_roman[0];
840 lex >> fonts_roman[1];
841 } else if (token == "\\font_sans") {
842 lex >> fonts_sans[0];
843 lex >> fonts_sans[1];
844 } else if (token == "\\font_typewriter") {
845 lex >> fonts_typewriter[0];
846 lex >> fonts_typewriter[1];
847 } else if (token == "\\font_math") {
848 lex >> fonts_math[0];
849 lex >> fonts_math[1];
850 } else if (token == "\\font_default_family") {
851 lex >> fonts_default_family;
852 } else if (token == "\\use_non_tex_fonts") {
853 lex >> useNonTeXFonts;
854 } else if (token == "\\font_sc") {
855 lex >> fonts_expert_sc;
856 } else if (token == "\\font_roman_osf") {
857 lex >> fonts_roman_osf;
858 } else if (token == "\\font_sans_osf") {
859 lex >> fonts_sans_osf;
860 } else if (token == "\\font_typewriter_osf") {
861 lex >> fonts_typewriter_osf;
862 } else if (token == "\\font_roman_opts") {
863 lex >> font_roman_opts;
864 } else if (token == "\\font_sf_scale") {
865 lex >> fonts_sans_scale[0];
866 lex >> fonts_sans_scale[1];
867 } else if (token == "\\font_sans_opts") {
868 lex >> font_sans_opts;
869 } else if (token == "\\font_tt_scale") {
870 lex >> fonts_typewriter_scale[0];
871 lex >> fonts_typewriter_scale[1];
872 } else if (token == "\\font_typewriter_opts") {
873 lex >> font_typewriter_opts;
874 } else if (token == "\\font_cjk") {
876 } else if (token == "\\use_microtype") {
877 lex >> use_microtype;
878 } else if (token == "\\use_dash_ligatures") {
879 lex >> use_dash_ligatures;
880 } else if (token == "\\paragraph_separation") {
883 paragraph_separation = parseptranslator().find(parsep);
884 } else if (token == "\\paragraph_indentation") {
886 string parindent = lex.getString();
887 if (parindent == "default")
888 pimpl_->parindent = Length();
890 pimpl_->parindent = Length(parindent);
891 } else if (token == "\\defskip") {
893 string const defskip = lex.getString();
894 pimpl_->defskip = VSpace(defskip);
895 if (pimpl_->defskip.kind() == VSpace::DEFSKIP)
897 pimpl_->defskip = VSpace(VSpace::MEDSKIP);
898 } else if (token == "\\is_math_indent") {
899 lex >> is_math_indent;
900 } else if (token == "\\math_indentation") {
902 string mathindent = lex.getString();
903 if (mathindent == "default")
904 pimpl_->mathindent = Length();
906 pimpl_->mathindent = Length(mathindent);
907 } else if (token == "\\math_numbering_side") {
911 math_numbering_side = LEFT;
912 else if (tmp == "right")
913 math_numbering_side = RIGHT;
915 math_numbering_side = DEFAULT;
916 } else if (token == "\\quotes_style") {
919 quotes_style = quotesstyletranslator().find(qstyle);
920 } else if (token == "\\dynamic_quotes") {
921 lex >> dynamic_quotes;
922 } else if (token == "\\papersize") {
925 papersize = papersizetranslator().find(ppsize);
926 } else if (token == "\\use_geometry") {
928 } else if (token == "\\use_package") {
933 use_package(package, packagetranslator().find(use));
934 } else if (token == "\\cite_engine") {
936 cite_engine_ = lex.getString();
937 } else if (token == "\\cite_engine_type") {
940 cite_engine_type_ = theCiteEnginesList.getType(engine_type);
941 } else if (token == "\\biblio_style") {
943 biblio_style = lex.getString();
944 } else if (token == "\\biblio_options") {
946 biblio_opts = trim(lex.getString());
947 } else if (token == "\\biblatex_bibstyle") {
949 biblatex_bibstyle = trim(lex.getString());
950 } else if (token == "\\biblatex_citestyle") {
952 biblatex_citestyle = trim(lex.getString());
953 } else if (token == "\\use_bibtopic") {
955 } else if (token == "\\multibib") {
957 } else if (token == "\\use_indices") {
959 } else if (token == "\\tracking_changes") {
960 lex >> track_changes;
961 } else if (token == "\\output_changes") {
962 lex >> output_changes;
963 } else if (token == "\\change_bars") {
965 } else if (token == "\\postpone_fragile_content") {
966 lex >> postpone_fragile_content;
967 } else if (token == "\\branch") {
969 docstring branch = lex.getDocString();
970 branchlist().add(branch);
973 string const tok = lex.getString();
974 if (tok == "\\end_branch")
976 Branch * branch_ptr = branchlist().find(branch);
977 if (tok == "\\selected") {
980 branch_ptr->setSelected(lex.getInteger());
982 if (tok == "\\filename_suffix") {
985 branch_ptr->setFileNameSuffix(lex.getInteger());
987 if (tok == "\\color") {
989 string color = lex.getString();
991 branch_ptr->setColor(color);
992 // Update also the Color table:
994 color = lcolor.getX11Name(Color_background);
996 lcolor.setColor(to_utf8(branch), color);
999 } else if (token == "\\index") {
1001 docstring index = lex.getDocString();
1003 indiceslist().add(index);
1006 string const tok = lex.getString();
1007 if (tok == "\\end_index")
1009 Index * index_ptr = indiceslist().find(index);
1010 if (tok == "\\shortcut") {
1012 shortcut = lex.getDocString();
1014 index_ptr->setShortcut(shortcut);
1016 if (tok == "\\color") {
1018 string color = lex.getString();
1020 index_ptr->setColor(color);
1021 // Update also the Color table:
1022 if (color == "none")
1023 color = lcolor.getX11Name(Color_background);
1025 if (!shortcut.empty())
1026 lcolor.setColor(to_utf8(shortcut), color);
1029 } else if (token == "\\author") {
1031 istringstream ss(lex.getString());
1035 } else if (token == "\\paperorientation") {
1038 orientation = paperorientationtranslator().find(orient);
1039 } else if (token == "\\backgroundcolor") {
1041 backgroundcolor = lyx::rgbFromHexName(lex.getString());
1042 isbackgroundcolor = true;
1043 } else if (token == "\\fontcolor") {
1045 fontcolor = lyx::rgbFromHexName(lex.getString());
1047 } else if (token == "\\notefontcolor") {
1049 string color = lex.getString();
1050 notefontcolor = lyx::rgbFromHexName(color);
1051 lcolor.setColor("notefontcolor", color);
1052 } else if (token == "\\boxbgcolor") {
1054 string color = lex.getString();
1055 boxbgcolor = lyx::rgbFromHexName(color);
1056 lcolor.setColor("boxbgcolor", color);
1057 } else if (token == "\\paperwidth") {
1059 } else if (token == "\\paperheight") {
1061 } else if (token == "\\leftmargin") {
1063 } else if (token == "\\topmargin") {
1065 } else if (token == "\\rightmargin") {
1067 } else if (token == "\\bottommargin") {
1068 lex >> bottommargin;
1069 } else if (token == "\\headheight") {
1071 } else if (token == "\\headsep") {
1073 } else if (token == "\\footskip") {
1075 } else if (token == "\\columnsep") {
1077 } else if (token == "\\paperfontsize") {
1079 } else if (token == "\\papercolumns") {
1081 } else if (token == "\\listings_params") {
1084 listings_params = InsetListingsParams(par).params();
1085 } else if (token == "\\papersides") {
1088 sides = sidestranslator().find(psides);
1089 } else if (token == "\\paperpagestyle") {
1091 } else if (token == "\\tablestyle") {
1093 } else if (token == "\\bullet") {
1095 } else if (token == "\\bulletLaTeX") {
1096 readBulletsLaTeX(lex);
1097 } else if (token == "\\secnumdepth") {
1099 } else if (token == "\\tocdepth") {
1101 } else if (token == "\\spacing") {
1105 if (nspacing == "other") {
1108 spacing().set(spacetranslator().find(nspacing), tmp_val);
1109 } else if (token == "\\float_placement") {
1110 lex >> float_placement;
1111 } else if (token == "\\float_alignment") {
1112 lex >> float_alignment;
1114 } else if (prefixIs(token, "\\pdf_") || token == "\\use_hyperref") {
1115 string toktmp = pdfoptions().readToken(lex, token);
1116 if (!toktmp.empty()) {
1117 lyxerr << "PDFOptions::readToken(): Unknown token: " <<
1121 } else if (token == "\\html_math_output") {
1124 html_math_output = static_cast<MathOutput>(temp);
1125 } else if (token == "\\html_be_strict") {
1126 lex >> html_be_strict;
1127 } else if (token == "\\html_css_as_file") {
1128 lex >> html_css_as_file;
1129 } else if (token == "\\html_math_img_scale") {
1130 lex >> html_math_img_scale;
1131 } else if (token == "\\html_latex_start") {
1133 html_latex_start = lex.getString();
1134 } else if (token == "\\html_latex_end") {
1136 html_latex_end = lex.getString();
1137 } else if (token == "\\output_sync") {
1139 } else if (token == "\\output_sync_macro") {
1140 lex >> output_sync_macro;
1141 } else if (token == "\\use_refstyle") {
1142 lex >> use_refstyle;
1143 } else if (token == "\\use_minted") {
1145 } else if (token == "\\use_lineno") {
1147 } else if (token == "\\lineno_options") {
1149 lineno_opts = trim(lex.getString());
1151 lyxerr << "BufferParams::readToken(): Unknown token: " <<
1161 // Quote argument if it contains spaces
1162 string quoteIfNeeded(string const & str) {
1163 if (contains(str, ' '))
1164 return "\"" + str + "\"";
1170 void BufferParams::writeFile(ostream & os, Buffer const * buf) const
1172 // The top of the file is written by the buffer.
1173 // Prints out the buffer info into the .lyx file given by file
1175 os << "\\save_transient_properties "
1176 << convert<string>(save_transient_properties) << '\n';
1178 // the document directory (must end with a path separator)
1179 // realPath() is used to resolve symlinks, while addPath(..., "")
1180 // ensures a trailing path separator.
1182 string filepath = addPath(buf->fileName().onlyPath().realPath(), "");
1183 string const sysdir = inSystemDir(FileName(filepath), docsys) ? docsys
1184 : addPath(package().system_support().realPath(), "");
1185 string const relpath =
1186 to_utf8(makeRelPath(from_utf8(filepath), from_utf8(sysdir)));
1187 if (!prefixIs(relpath, "../") && !FileName::isAbsolute(relpath))
1188 filepath = addPath("/systemlyxdir", relpath);
1189 else if (!save_transient_properties || !lyxrc.save_origin)
1190 filepath = "unavailable";
1191 os << "\\origin " << quoteIfNeeded(filepath) << '\n';
1194 os << "\\textclass "
1195 << quoteIfNeeded(buf->includedFilePath(addName(buf->layoutPos(),
1196 baseClass()->name()), "layout"))
1199 // then the preamble
1200 if (!preamble.empty()) {
1201 // remove '\n' from the end of preamble
1202 docstring const tmppreamble = rtrim(preamble, "\n");
1203 os << "\\begin_preamble\n"
1204 << to_utf8(tmppreamble)
1205 << "\n\\end_preamble\n";
1209 if (!options.empty()) {
1210 os << "\\options " << options << '\n';
1213 // use the class options defined in the layout?
1214 os << "\\use_default_options "
1215 << convert<string>(use_default_options) << "\n";
1217 // the master document
1218 if (!master.empty()) {
1219 os << "\\master " << master << '\n';
1223 if (!removed_modules_.empty()) {
1224 os << "\\begin_removed_modules" << '\n';
1225 for (auto const & mod : removed_modules_)
1227 os << "\\end_removed_modules" << '\n';
1231 if (!layout_modules_.empty()) {
1232 os << "\\begin_modules" << '\n';
1233 for (auto const & mod : layout_modules_)
1235 os << "\\end_modules" << '\n';
1239 if (!included_children_.empty()) {
1240 os << "\\begin_includeonly" << '\n';
1241 for (auto const & c : included_children_)
1243 os << "\\end_includeonly" << '\n';
1246 switch (maintain_unincluded_children) {
1257 os << "\\maintain_unincluded_children " << muc << '\n';
1259 // local layout information
1260 docstring const local_layout = getLocalLayout(false);
1261 if (!local_layout.empty()) {
1262 // remove '\n' from the end
1263 docstring const tmplocal = rtrim(local_layout, "\n");
1264 os << "\\begin_local_layout\n"
1265 << to_utf8(tmplocal)
1266 << "\n\\end_local_layout\n";
1268 docstring const forced_local_layout = getLocalLayout(true);
1269 if (!forced_local_layout.empty()) {
1270 // remove '\n' from the end
1271 docstring const tmplocal = rtrim(forced_local_layout, "\n");
1272 os << "\\begin_forced_local_layout\n"
1273 << to_utf8(tmplocal)
1274 << "\n\\end_forced_local_layout\n";
1277 // then the text parameters
1278 if (language != ignore_language)
1279 os << "\\language " << language->lang() << '\n';
1280 os << "\\language_package " << lang_package
1281 << "\n\\inputencoding " << inputenc
1282 << "\n\\fontencoding " << fontenc
1283 << "\n\\font_roman \"" << fonts_roman[0]
1284 << "\" \"" << fonts_roman[1] << '"'
1285 << "\n\\font_sans \"" << fonts_sans[0]
1286 << "\" \"" << fonts_sans[1] << '"'
1287 << "\n\\font_typewriter \"" << fonts_typewriter[0]
1288 << "\" \"" << fonts_typewriter[1] << '"'
1289 << "\n\\font_math \"" << fonts_math[0]
1290 << "\" \"" << fonts_math[1] << '"'
1291 << "\n\\font_default_family " << fonts_default_family
1292 << "\n\\use_non_tex_fonts " << convert<string>(useNonTeXFonts)
1293 << "\n\\font_sc " << convert<string>(fonts_expert_sc)
1294 << "\n\\font_roman_osf " << convert<string>(fonts_roman_osf)
1295 << "\n\\font_sans_osf " << convert<string>(fonts_sans_osf)
1296 << "\n\\font_typewriter_osf " << convert<string>(fonts_typewriter_osf);
1297 if (!font_roman_opts.empty())
1298 os << "\n\\font_roman_opts \"" << font_roman_opts << "\"";
1299 os << "\n\\font_sf_scale " << fonts_sans_scale[0]
1300 << ' ' << fonts_sans_scale[1];
1301 if (!font_sans_opts.empty())
1302 os << "\n\\font_sans_opts \"" << font_sans_opts << "\"";
1303 os << "\n\\font_tt_scale " << fonts_typewriter_scale[0]
1304 << ' ' << fonts_typewriter_scale[1];
1305 if (!font_typewriter_opts.empty())
1306 os << "\n\\font_typewriter_opts \"" << font_typewriter_opts << "\"";
1308 if (!fonts_cjk.empty())
1309 os << "\\font_cjk " << fonts_cjk << '\n';
1310 os << "\\use_microtype " << convert<string>(use_microtype) << '\n';
1311 os << "\\use_dash_ligatures " << convert<string>(use_dash_ligatures) << '\n';
1312 os << "\\graphics " << graphics_driver << '\n';
1313 os << "\\default_output_format " << default_output_format << '\n';
1314 os << "\\output_sync " << output_sync << '\n';
1315 if (!output_sync_macro.empty())
1316 os << "\\output_sync_macro \"" << output_sync_macro << "\"\n";
1317 os << "\\bibtex_command " << bibtex_command << '\n';
1318 os << "\\index_command " << index_command << '\n';
1320 if (!float_placement.empty())
1321 os << "\\float_placement " << float_placement << '\n';
1322 if (!float_alignment.empty())
1323 os << "\\float_alignment " << float_alignment << '\n';
1324 os << "\\paperfontsize " << fontsize << '\n';
1326 spacing().writeFile(os);
1327 pdfoptions().writeFile(os);
1329 os << "\\papersize " << string_papersize[papersize]
1330 << "\n\\use_geometry " << convert<string>(use_geometry);
1331 map<string, string> const & packages = auto_packages();
1332 for (auto const & pack : packages)
1333 os << "\n\\use_package " << pack.first << ' '
1334 << use_package(pack.first);
1336 os << "\n\\cite_engine ";
1338 if (!cite_engine_.empty())
1343 os << "\n\\cite_engine_type " << theCiteEnginesList.getTypeAsString(cite_engine_type_);
1345 if (!biblio_style.empty())
1346 os << "\n\\biblio_style " << biblio_style;
1347 if (!biblio_opts.empty())
1348 os << "\n\\biblio_options " << biblio_opts;
1349 if (!biblatex_bibstyle.empty())
1350 os << "\n\\biblatex_bibstyle " << biblatex_bibstyle;
1351 if (!biblatex_citestyle.empty())
1352 os << "\n\\biblatex_citestyle " << biblatex_citestyle;
1353 if (!multibib.empty())
1354 os << "\n\\multibib " << multibib;
1356 os << "\n\\use_bibtopic " << convert<string>(use_bibtopic)
1357 << "\n\\use_indices " << convert<string>(use_indices)
1358 << "\n\\paperorientation " << string_orientation[orientation]
1359 << "\n\\suppress_date " << convert<string>(suppress_date)
1360 << "\n\\justification " << convert<string>(justification)
1361 << "\n\\use_refstyle " << use_refstyle
1362 << "\n\\use_minted " << use_minted
1363 << "\n\\use_lineno " << use_lineno
1366 if (!lineno_opts.empty())
1367 os << "\\lineno_options " << lineno_opts << '\n';
1369 if (isbackgroundcolor == true)
1370 os << "\\backgroundcolor " << lyx::X11hexname(backgroundcolor) << '\n';
1371 if (isfontcolor == true)
1372 os << "\\fontcolor " << lyx::X11hexname(fontcolor) << '\n';
1373 if (notefontcolor != lyx::rgbFromHexName("#cccccc"))
1374 os << "\\notefontcolor " << lyx::X11hexname(notefontcolor) << '\n';
1375 if (boxbgcolor != lyx::rgbFromHexName("#ff0000"))
1376 os << "\\boxbgcolor " << lyx::X11hexname(boxbgcolor) << '\n';
1378 for (auto const & br : branchlist()) {
1379 os << "\\branch " << to_utf8(br.branch())
1380 << "\n\\selected " << br.isSelected()
1381 << "\n\\filename_suffix " << br.hasFileNameSuffix()
1382 << "\n\\color " << lyx::X11hexname(br.color())
1387 for (auto const & id : indiceslist()) {
1388 os << "\\index " << to_utf8(id.index())
1389 << "\n\\shortcut " << to_utf8(id.shortcut())
1390 << "\n\\color " << lyx::X11hexname(id.color())
1395 if (!paperwidth.empty())
1396 os << "\\paperwidth "
1397 << VSpace(paperwidth).asLyXCommand() << '\n';
1398 if (!paperheight.empty())
1399 os << "\\paperheight "
1400 << VSpace(paperheight).asLyXCommand() << '\n';
1401 if (!leftmargin.empty())
1402 os << "\\leftmargin "
1403 << VSpace(leftmargin).asLyXCommand() << '\n';
1404 if (!topmargin.empty())
1405 os << "\\topmargin "
1406 << VSpace(topmargin).asLyXCommand() << '\n';
1407 if (!rightmargin.empty())
1408 os << "\\rightmargin "
1409 << VSpace(rightmargin).asLyXCommand() << '\n';
1410 if (!bottommargin.empty())
1411 os << "\\bottommargin "
1412 << VSpace(bottommargin).asLyXCommand() << '\n';
1413 if (!headheight.empty())
1414 os << "\\headheight "
1415 << VSpace(headheight).asLyXCommand() << '\n';
1416 if (!headsep.empty())
1418 << VSpace(headsep).asLyXCommand() << '\n';
1419 if (!footskip.empty())
1421 << VSpace(footskip).asLyXCommand() << '\n';
1422 if (!columnsep.empty())
1423 os << "\\columnsep "
1424 << VSpace(columnsep).asLyXCommand() << '\n';
1425 os << "\\secnumdepth " << secnumdepth
1426 << "\n\\tocdepth " << tocdepth
1427 << "\n\\paragraph_separation "
1428 << string_paragraph_separation[paragraph_separation];
1429 if (!paragraph_separation)
1430 os << "\n\\paragraph_indentation "
1431 << (getParIndent().empty() ? "default" : getParIndent().asString());
1433 os << "\n\\defskip " << getDefSkip().asLyXCommand();
1434 os << "\n\\is_math_indent " << is_math_indent;
1436 os << "\n\\math_indentation "
1437 << (getMathIndent().empty() ? "default" : getMathIndent().asString());
1438 os << "\n\\math_numbering_side ";
1439 switch(math_numbering_side) {
1449 os << "\n\\quotes_style "
1450 << string_quotes_style[quotes_style]
1451 << "\n\\dynamic_quotes " << dynamic_quotes
1452 << "\n\\papercolumns " << columns
1453 << "\n\\papersides " << sides
1454 << "\n\\paperpagestyle " << pagestyle
1455 << "\n\\tablestyle " << tablestyle << '\n';
1456 if (!listings_params.empty())
1457 os << "\\listings_params \"" <<
1458 InsetListingsParams(listings_params).encodedString() << "\"\n";
1459 for (int i = 0; i < 4; ++i) {
1460 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
1461 if (user_defined_bullet(i).getFont() != -1) {
1462 os << "\\bullet " << i << " "
1463 << user_defined_bullet(i).getFont() << " "
1464 << user_defined_bullet(i).getCharacter() << " "
1465 << user_defined_bullet(i).getSize() << "\n";
1469 os << "\\bulletLaTeX " << i << " \""
1470 << lyx::to_ascii(user_defined_bullet(i).getText())
1476 os << "\\tracking_changes "
1477 << (save_transient_properties ? convert<string>(track_changes) : "false")
1480 os << "\\output_changes "
1481 << (save_transient_properties ? convert<string>(output_changes) : "false")
1484 os << "\\change_bars "
1485 << (save_transient_properties ? convert<string>(change_bars) : "false")
1488 os << "\\postpone_fragile_content " << convert<string>(postpone_fragile_content) << '\n';
1490 os << "\\html_math_output " << html_math_output << '\n'
1491 << "\\html_css_as_file " << html_css_as_file << '\n'
1492 << "\\html_be_strict " << convert<string>(html_be_strict) << '\n';
1494 if (html_math_img_scale != 1.0)
1495 os << "\\html_math_img_scale " << convert<string>(html_math_img_scale) << '\n';
1496 if (!html_latex_start.empty())
1497 os << "\\html_latex_start " << html_latex_start << '\n';
1498 if (!html_latex_end.empty())
1499 os << "\\html_latex_end " << html_latex_end << '\n';
1501 os << pimpl_->authorlist;
1505 void BufferParams::validate(LaTeXFeatures & features) const
1507 features.require(documentClass().required());
1509 if (columns > 1 && language->rightToLeft())
1510 features.require("rtloutputdblcol");
1512 if (output_changes) {
1513 bool xcolorulem = LaTeXFeatures::isAvailable("ulem") &&
1514 LaTeXFeatures::isAvailable("xcolor");
1516 switch (features.runparams().flavor) {
1517 case OutputParams::LATEX:
1518 case OutputParams::DVILUATEX:
1520 features.require("ct-xcolor-ulem");
1521 features.require("ulem");
1522 features.require("xcolor");
1524 features.require("ct-none");
1527 case OutputParams::LUATEX:
1528 case OutputParams::PDFLATEX:
1529 case OutputParams::XETEX:
1531 features.require("ct-xcolor-ulem");
1532 features.require("ulem");
1533 features.require("xcolor");
1534 // improves color handling in PDF output
1535 features.require("pdfcolmk");
1537 features.require("ct-none");
1544 features.require("changebar");
1547 // Floats with 'Here definitely' as default setting.
1548 if (float_placement.find('H') != string::npos)
1549 features.require("float");
1551 for (auto const & pm : use_packages) {
1552 if (pm.first == "amsmath") {
1553 // AMS Style is at document level
1554 if (pm.second == package_on ||
1555 features.isProvided("amsmath"))
1556 features.require(pm.first);
1557 } else if (pm.second == package_on)
1558 features.require(pm.first);
1561 // Document-level line spacing
1562 if (spacing().getSpace() != Spacing::Single && !spacing().isDefault())
1563 features.require("setspace");
1565 // the bullet shapes are buffer level not paragraph level
1566 // so they are tested here
1567 for (int i = 0; i < 4; ++i) {
1568 if (user_defined_bullet(i) == ITEMIZE_DEFAULTS[i])
1570 int const font = user_defined_bullet(i).getFont();
1572 int const c = user_defined_bullet(i).getCharacter();
1578 features.require("latexsym");
1580 } else if (font == 1) {
1581 features.require("amssymb");
1582 } else if (font >= 2 && font <= 5) {
1583 features.require("pifont");
1587 if (pdfoptions().use_hyperref) {
1588 features.require("hyperref");
1589 // due to interferences with babel and hyperref, the color package has to
1590 // be loaded after hyperref when hyperref is used with the colorlinks
1591 // option, see http://www.lyx.org/trac/ticket/5291
1592 if (pdfoptions().colorlinks)
1593 features.require("color");
1595 if (!listings_params.empty()) {
1596 // do not test validity because listings_params is
1597 // supposed to be valid
1599 InsetListingsParams(listings_params).separatedParams(true);
1600 // we can't support all packages, but we should load the color package
1601 if (par.find("\\color", 0) != string::npos)
1602 features.require("color");
1605 // some languages are only available via polyglossia
1606 if (features.hasPolyglossiaExclusiveLanguages())
1607 features.require("polyglossia");
1609 if (useNonTeXFonts && fontsMath() != "auto")
1610 features.require("unicode-math");
1613 features.require("microtype");
1615 if (!language->required().empty())
1616 features.require(language->required());
1620 bool BufferParams::writeLaTeX(otexstream & os, LaTeXFeatures & features,
1621 FileName const & filepath) const
1623 // http://www.tug.org/texmf-dist/doc/latex/base/fixltx2e.pdf
1624 // !! To use the Fix-cm package, load it before \documentclass, and use the command
1625 // \RequirePackage to do so, rather than the normal \usepackage
1626 // Do not try to load any other package before the document class, unless you
1627 // have a thorough understanding of the LATEX internals and know exactly what you
1629 if (features.mustProvide("fix-cm"))
1630 os << "\\RequirePackage{fix-cm}\n";
1631 // Likewise for fixltx2e. If other packages conflict with this policy,
1632 // treat it as a package bug (and report it!)
1633 // See http://www.latex-project.org/cgi-bin/ltxbugs2html?pr=latex/4407
1634 if (features.mustProvide("fixltx2e"))
1635 os << "\\RequirePackage{fixltx2e}\n";
1637 os << "\\documentclass";
1639 DocumentClass const & tclass = documentClass();
1641 ostringstream clsoptions; // the document class options.
1643 if (tokenPos(tclass.opt_fontsize(),
1644 '|', fontsize) >= 0) {
1645 // only write if existing in list (and not default)
1646 clsoptions << subst(tclass.fontsizeformat(), "$$s", fontsize) << ",";
1649 // paper sizes not supported by the class itself need the
1651 vector<string> classpsizes = getVectorFromString(tclass.opt_pagesize(), "|");
1652 bool class_supported_papersize = papersize == PAPER_DEFAULT
1653 || find(classpsizes.begin(), classpsizes.end(), string_papersize[papersize]) != classpsizes.end();
1655 if ((!use_geometry || features.isProvided("geometry-light"))
1656 && class_supported_papersize && papersize != PAPER_DEFAULT)
1657 clsoptions << subst(tclass.pagesizeformat(), "$$s", string_papersize[papersize]) << ",";
1660 if (sides != tclass.sides()) {
1663 clsoptions << "oneside,";
1666 clsoptions << "twoside,";
1672 if (columns != tclass.columns()) {
1674 clsoptions << "twocolumn,";
1676 clsoptions << "onecolumn,";
1680 && orientation == ORIENTATION_LANDSCAPE)
1681 clsoptions << "landscape,";
1684 clsoptions << "fleqn,";
1686 switch(math_numbering_side) {
1688 clsoptions << "leqno,";
1691 clsoptions << "reqno,";
1692 features.require("amsmath");
1698 // language should be a parameter to \documentclass
1699 if (language->babel() == "hebrew"
1700 && default_language->babel() != "hebrew")
1701 // This seems necessary
1702 features.useLanguage(default_language);
1704 ostringstream language_options;
1705 bool const use_babel = features.useBabel() && !features.isProvided("babel");
1706 bool const use_polyglossia = features.usePolyglossia();
1707 bool const global = lyxrc.language_global_options;
1708 if (features.useBabel() || (use_polyglossia && global)) {
1709 language_options << features.getBabelLanguages();
1710 if (!language->babel().empty()) {
1711 if (!language_options.str().empty())
1712 language_options << ',';
1713 language_options << language->babel();
1715 if (global && !language_options.str().empty())
1716 clsoptions << language_options.str() << ',';
1719 // the predefined options from the layout
1720 if (use_default_options && !tclass.options().empty())
1721 clsoptions << tclass.options() << ',';
1723 // the user-defined options
1724 if (!options.empty()) {
1725 clsoptions << options << ',';
1728 docstring const strOptions = from_utf8(clsoptions.str());
1729 if (!strOptions.empty()) {
1730 // Check if class options contain uncodable glyphs
1731 docstring uncodable_glyphs;
1732 docstring options_encodable;
1733 Encoding const * const enc = features.runparams().encoding;
1735 for (size_t n = 0; n < strOptions.size(); ++n) {
1736 char_type c = strOptions[n];
1737 if (!enc->encodable(c)) {
1738 docstring const glyph(1, c);
1739 LYXERR0("Uncodable character '"
1741 << "' in class options!");
1742 uncodable_glyphs += glyph;
1743 if (features.runparams().dryrun) {
1744 options_encodable += "<" + _("LyX Warning: ")
1745 + _("uncodable character") + " '";
1746 options_encodable += c;
1747 options_encodable += "'>";
1750 options_encodable += c;
1753 options_encodable = strOptions;
1755 // On BUFFER_VIEW|UPDATE, warn user if we found uncodable glyphs
1756 if (!features.runparams().dryrun && !uncodable_glyphs.empty()) {
1757 frontend::Alert::warning(
1758 _("Uncodable character in class options"),
1760 _("The class options of your document contain glyphs "
1761 "that are unknown in the current document encoding "
1762 "(namely %1$s).\nThese glyphs are omitted "
1763 " from the output, which may result in "
1764 "incomplete output."
1765 "\n\nPlease select an appropriate "
1766 "document encoding\n"
1767 "(such as utf8) or change the "
1768 "class options accordingly."),
1771 options_encodable = rtrim(options_encodable, ",");
1772 os << '[' << options_encodable << ']';
1775 os << '{' << from_ascii(tclass.latexname()) << "}\n";
1776 // end of \documentclass defs
1778 // The package options (via \PassOptionsToPackage)
1779 os << from_ascii(features.getPackageOptions());
1781 // if we use fontspec or newtxmath, we have to load the AMS packages here
1782 string const ams = features.loadAMSPackages();
1783 bool const ot1 = (main_font_encoding() == "default" || main_font_encoding() == "OT1");
1784 bool const use_newtxmath =
1785 theLaTeXFonts().getLaTeXFont(from_ascii(fontsMath())).getUsedPackage(
1786 ot1, false, false) == "newtxmath";
1787 if ((useNonTeXFonts || use_newtxmath) && !ams.empty())
1788 os << from_ascii(ams);
1790 if (useNonTeXFonts) {
1791 // Babel (as of 2017/11/03) loads fontspec itself
1792 if (!features.isProvided("fontspec")
1793 && !(features.useBabel() && features.isAvailable("babel-2017/11/03")))
1794 os << "\\usepackage{fontspec}\n";
1795 if (features.mustProvide("unicode-math")
1796 && features.isAvailable("unicode-math"))
1797 os << "\\usepackage{unicode-math}\n";
1800 // load CJK support package before font selection
1801 // (see autotests/export/latex/CJK/micro-sign_utf8-cjk-libertine.lyx)
1802 if (!useNonTeXFonts && encoding().package() != Encoding::none && inputenc != "utf8x"
1803 && (encoding().package() == Encoding::CJK || features.mustProvide("CJK"))) {
1804 if (inputenc == "utf8-cjk" || inputenc == "utf8")
1805 os << "\\usepackage{CJKutf8}\n";
1807 os << "\\usepackage[encapsulated]{CJK}\n";
1810 // font selection must be done before loading fontenc.sty
1811 // but after babel with non-TeX fonts
1812 string const fonts = loadFonts(features);
1813 if (!fonts.empty() && (!features.useBabel() || !useNonTeXFonts))
1814 os << from_utf8(fonts);
1816 if (fonts_default_family != "default")
1817 os << "\\renewcommand{\\familydefault}{\\"
1818 << from_ascii(fonts_default_family) << "}\n";
1820 // set font encoding
1821 // non-TeX fonts use font encoding TU (set by fontspec)
1822 if (!useNonTeXFonts && !features.isProvided("fontenc")
1823 && main_font_encoding() != "default") {
1824 // get main font encodings
1825 vector<string> fontencs = font_encodings();
1826 // get font encodings of secondary languages
1827 // FIXME: some languages (hebrew, ...) assume a standard font encoding as last
1828 // option (for text in other languages).
1829 features.getFontEncodings(fontencs);
1830 if (!fontencs.empty()) {
1831 os << "\\usepackage["
1832 << from_ascii(getStringFromVector(fontencs))
1837 // Load textcomp and pmboxdraw before (lua)inputenc (#11454)
1838 if (features.mustProvide("textcomp"))
1839 os << "\\usepackage{textcomp}\n";
1840 if (features.mustProvide("pmboxdraw"))
1841 os << "\\usepackage{pmboxdraw}\n";
1843 // handle inputenc etc.
1844 // (In documents containing text in Thai language,
1845 // we must load inputenc after babel, see lib/languages).
1846 if (!contains(features.getBabelPostsettings(), from_ascii("thai.ldf")))
1847 writeEncodingPreamble(os, features);
1850 if (!features.runparams().includeall && !included_children_.empty()) {
1851 os << "\\includeonly{";
1853 for (auto incfile : included_children_) {
1854 FileName inc = makeAbsPath(incfile, filepath.absFileName());
1855 string mangled = DocFileName(changeExtension(inc.absFileName(), ".tex")).
1857 if (!features.runparams().nice)
1859 // \includeonly doesn't want an extension
1860 incfile = changeExtension(incfile, string());
1861 incfile = support::latex_path(incfile);
1862 if (!incfile.empty()) {
1865 os << from_utf8(incfile);
1872 if (!features.isProvided("geometry")
1873 && (use_geometry || !class_supported_papersize)) {
1874 odocstringstream ods;
1875 if (!getGraphicsDriver("geometry").empty())
1876 ods << getGraphicsDriver("geometry");
1877 if (orientation == ORIENTATION_LANDSCAPE)
1878 ods << ",landscape";
1879 switch (papersize) {
1881 if (!paperwidth.empty())
1882 ods << ",paperwidth="
1883 << from_ascii(paperwidth);
1884 if (!paperheight.empty())
1885 ods << ",paperheight="
1886 << from_ascii(paperheight);
1888 case PAPER_USLETTER:
1890 case PAPER_USEXECUTIVE:
1919 ods << "," << from_ascii(string_papersize_geometry[papersize]);
1924 docstring g_options = trim(ods.str(), ",");
1925 os << "\\usepackage";
1926 // geometry-light means that the class works with geometry, but overwrites
1927 // the package options and paper sizes (memoir does this).
1928 // In this case, all options need to go to \geometry
1929 // and the standard paper sizes need to go to the class options.
1930 if (!g_options.empty() && !features.isProvided("geometry-light")) {
1931 os << '[' << g_options << ']';
1934 os << "{geometry}\n";
1935 if (use_geometry || features.isProvided("geometry-light")) {
1936 os << "\\geometry{verbose";
1937 if (!g_options.empty())
1938 // Output general options here with "geometry light".
1939 os << "," << g_options;
1940 // output this only if use_geometry is true
1942 if (!topmargin.empty())
1943 os << ",tmargin=" << from_ascii(Length(topmargin).asLatexString());
1944 if (!bottommargin.empty())
1945 os << ",bmargin=" << from_ascii(Length(bottommargin).asLatexString());
1946 if (!leftmargin.empty())
1947 os << ",lmargin=" << from_ascii(Length(leftmargin).asLatexString());
1948 if (!rightmargin.empty())
1949 os << ",rmargin=" << from_ascii(Length(rightmargin).asLatexString());
1950 if (!headheight.empty())
1951 os << ",headheight=" << from_ascii(Length(headheight).asLatexString());
1952 if (!headsep.empty())
1953 os << ",headsep=" << from_ascii(Length(headsep).asLatexString());
1954 if (!footskip.empty())
1955 os << ",footskip=" << from_ascii(Length(footskip).asLatexString());
1956 if (!columnsep.empty())
1957 os << ",columnsep=" << from_ascii(Length(columnsep).asLatexString());
1961 } else if (orientation == ORIENTATION_LANDSCAPE
1962 || papersize != PAPER_DEFAULT) {
1963 features.require("papersize");
1966 if (tokenPos(tclass.opt_pagestyle(), '|', pagestyle) >= 0) {
1967 if (pagestyle == "fancy")
1968 os << "\\usepackage{fancyhdr}\n";
1969 os << "\\pagestyle{" << from_ascii(pagestyle) << "}\n";
1972 // only output when the background color is not default
1973 if (isbackgroundcolor == true) {
1974 // only require color here, the background color will be defined
1975 // in LaTeXFeatures.cpp to avoid interferences with the LaTeX
1977 features.require("color");
1978 features.require("pagecolor");
1981 // only output when the font color is not default
1982 if (isfontcolor == true) {
1983 // only require color here, the font color will be defined
1984 // in LaTeXFeatures.cpp to avoid interferences with the LaTeX
1986 features.require("color");
1987 features.require("fontcolor");
1990 // Only if class has a ToC hierarchy
1991 if (tclass.hasTocLevels()) {
1992 if (secnumdepth != tclass.secnumdepth()) {
1993 os << "\\setcounter{secnumdepth}{"
1997 if (tocdepth != tclass.tocdepth()) {
1998 os << "\\setcounter{tocdepth}{"
2004 if (paragraph_separation) {
2005 // when skip separation
2007 switch (getDefSkip().kind()) {
2008 case VSpace::SMALLSKIP:
2009 psopt = "[skip=\\smallskipamount]";
2011 case VSpace::MEDSKIP:
2012 psopt = "[skip=\\medskipamount]";
2014 case VSpace::BIGSKIP:
2015 psopt = "[skip=\\bigskipamount]";
2017 case VSpace::HALFLINE:
2019 case VSpace::FULLLINE:
2020 psopt = "[skip=\\baselineskip]";
2022 case VSpace::LENGTH:
2023 psopt = "[skip={" + getDefSkip().length().asLatexString() + "}]";
2028 if (features.isAvailable("parskip"))
2029 os << "\\usepackage" + psopt + "{parskip}\n";
2031 // when separation by indentation
2032 // only output something when a width is given
2033 if (!getParIndent().empty()) {
2034 os << "\\setlength{\\parindent}{"
2035 << from_utf8(getParIndent().asLatexString())
2040 if (is_math_indent) {
2041 // when formula indentation
2042 // only output something when it is not the default
2043 if (!getMathIndent().empty()) {
2044 os << "\\setlength{\\mathindent}{"
2045 << from_utf8(getMathIndent().asString())
2050 // Now insert the LyX specific LaTeX commands...
2051 features.resolveAlternatives();
2052 features.expandMultiples();
2055 if (!output_sync_macro.empty())
2056 os << from_utf8(output_sync_macro) +"\n";
2057 else if (features.runparams().flavor == OutputParams::LATEX)
2058 os << "\\usepackage[active]{srcltx}\n";
2059 else if (features.runparams().flavor == OutputParams::PDFLATEX)
2060 os << "\\synctex=-1\n";
2063 // due to interferences with babel and hyperref, the color package has to
2064 // be loaded (when it is not already loaded) before babel when hyperref
2065 // is used with the colorlinks option, see
2066 // http://www.lyx.org/trac/ticket/5291
2067 // we decided therefore to load color always before babel, see
2068 // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg144349.html
2069 os << from_ascii(features.getColorOptions());
2071 // If we use hyperref, jurabib, japanese or varioref,
2072 // we have to call babel before
2074 && (features.isRequired("jurabib")
2075 || features.isRequired("hyperref")
2076 || features.isRequired("varioref")
2077 || features.isRequired("japanese"))) {
2078 os << features.getBabelPresettings();
2080 os << from_utf8(babelCall(language_options.str(),
2081 !lyxrc.language_global_options)) + '\n';
2082 os << features.getBabelPostsettings();
2085 // The optional packages;
2086 os << from_ascii(features.getPackages());
2088 // Additional Indices
2089 if (features.isRequired("splitidx")) {
2090 for (auto const & idx : indiceslist()) {
2091 os << "\\newindex{";
2092 os << escape(idx.shortcut());
2098 os << from_utf8(spacing().writePreamble(features.isProvided("SetSpace")));
2101 // * Hyperref manual: "Make sure it comes last of your loaded
2102 // packages, to give it a fighting chance of not being over-written,
2103 // since its job is to redefine many LaTeX commands."
2104 // * Email from Heiko Oberdiek: "It is usually better to load babel
2105 // before hyperref. Then hyperref has a chance to detect babel.
2106 // * Has to be loaded before the "LyX specific LaTeX commands" to
2107 // avoid errors with algorithm floats.
2108 // use hyperref explicitly if it is required
2109 if (features.isRequired("hyperref")) {
2110 OutputParams tmp_params = features.runparams();
2111 pdfoptions().writeLaTeX(tmp_params, os,
2112 features.isProvided("hyperref"));
2113 // correctly break URLs with hyperref and dvi/ps output
2114 if (features.runparams().hyperref_driver == "dvips"
2115 && features.isAvailable("breakurl"))
2116 os << "\\usepackage{breakurl}\n";
2117 } else if (features.isRequired("nameref"))
2118 // hyperref loads this automatically
2119 os << "\\usepackage{nameref}\n";
2122 os << "\\usepackage";
2123 if (!lineno_opts.empty())
2124 os << "[" << lineno_opts << "]";
2126 os << "\\linenumbers\n";
2129 // bibtopic needs to be loaded after hyperref.
2130 // the dot provides the aux file naming which LyX can detect.
2131 if (features.mustProvide("bibtopic"))
2132 os << "\\usepackage[dot]{bibtopic}\n";
2134 // Will be surrounded by \makeatletter and \makeatother when not empty
2135 otexstringstream atlyxpreamble;
2137 // Some macros LyX will need
2139 TexString tmppreamble = features.getMacros();
2140 if (!tmppreamble.str.empty())
2141 atlyxpreamble << "\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
2142 "LyX specific LaTeX commands.\n"
2143 << move(tmppreamble)
2146 // the text class specific preamble
2148 docstring tmppreamble = features.getTClassPreamble();
2149 if (!tmppreamble.empty())
2150 atlyxpreamble << "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
2151 "Textclass specific LaTeX commands.\n"
2155 // suppress date if selected
2156 // use \@ifundefined because we cannot be sure that every document class
2157 // has a \date command
2159 atlyxpreamble << "\\@ifundefined{date}{}{\\date{}}\n";
2161 /* the user-defined preamble */
2162 if (!containsOnly(preamble, " \n\t")) {
2164 atlyxpreamble << "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
2165 "User specified LaTeX commands.\n";
2167 // Check if the user preamble contains uncodable glyphs
2168 odocstringstream user_preamble;
2169 docstring uncodable_glyphs;
2170 Encoding const * const enc = features.runparams().encoding;
2172 for (size_t n = 0; n < preamble.size(); ++n) {
2173 char_type c = preamble[n];
2174 if (!enc->encodable(c)) {
2175 docstring const glyph(1, c);
2176 LYXERR0("Uncodable character '"
2178 << "' in user preamble!");
2179 uncodable_glyphs += glyph;
2180 if (features.runparams().dryrun) {
2181 user_preamble << "<" << _("LyX Warning: ")
2182 << _("uncodable character") << " '";
2183 user_preamble.put(c);
2184 user_preamble << "'>";
2187 user_preamble.put(c);
2190 user_preamble << preamble;
2192 // On BUFFER_VIEW|UPDATE, warn user if we found uncodable glyphs
2193 if (!features.runparams().dryrun && !uncodable_glyphs.empty()) {
2194 frontend::Alert::warning(
2195 _("Uncodable character in user preamble"),
2197 _("The user preamble of your document contains glyphs "
2198 "that are unknown in the current document encoding "
2199 "(namely %1$s).\nThese glyphs are omitted "
2200 " from the output, which may result in "
2201 "incomplete output."
2202 "\n\nPlease select an appropriate "
2203 "document encoding\n"
2204 "(such as utf8) or change the "
2205 "preamble code accordingly."),
2208 atlyxpreamble << user_preamble.str() << '\n';
2211 // footmisc must be loaded after setspace
2212 // Load it here to avoid clashes with footmisc loaded in the user
2213 // preamble. For that reason we also pass the options via
2214 // \PassOptionsToPackage in getPreamble() and not here.
2215 if (features.mustProvide("footmisc"))
2216 atlyxpreamble << "\\usepackage{footmisc}\n";
2218 // subfig loads internally the LaTeX package "caption". As
2219 // caption is a very popular package, users will load it in
2220 // the preamble. Therefore we must load subfig behind the
2221 // user-defined preamble and check if the caption package was
2222 // loaded or not. For the case that caption is loaded before
2223 // subfig, there is the subfig option "caption=false". This
2224 // option also works when a koma-script class is used and
2225 // koma's own caption commands are used instead of caption. We
2226 // use \PassOptionsToPackage here because the user could have
2227 // already loaded subfig in the preamble.
2228 if (features.mustProvide("subfig"))
2229 atlyxpreamble << "\\@ifundefined{showcaptionsetup}{}{%\n"
2230 " \\PassOptionsToPackage{caption=false}{subfig}}\n"
2231 "\\usepackage{subfig}\n";
2233 // Itemize bullet settings need to be last in case the user
2234 // defines their own bullets that use a package included
2235 // in the user-defined preamble -- ARRae
2236 // Actually it has to be done much later than that
2237 // since some packages like frenchb make modifications
2238 // at \begin{document} time -- JMarc
2239 docstring bullets_def;
2240 for (int i = 0; i < 4; ++i) {
2241 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
2242 if (bullets_def.empty())
2243 bullets_def += "\\AtBeginDocument{\n";
2244 bullets_def += " \\def\\labelitemi";
2246 // `i' is one less than the item to modify
2253 bullets_def += "ii";
2259 bullets_def += '{' +
2260 user_defined_bullet(i).getText()
2265 if (!bullets_def.empty())
2266 atlyxpreamble << bullets_def << "}\n\n";
2268 if (!atlyxpreamble.empty())
2269 os << "\n\\makeatletter\n"
2270 << atlyxpreamble.release()
2271 << "\\makeatother\n\n";
2273 // We try to load babel late, in case it interferes with other packages.
2274 // Jurabib, hyperref, varioref, bicaption, menukeys and listings (bug 8995)
2275 // have to be called after babel, though.
2276 if (use_babel && !features.isRequired("jurabib")
2277 && !features.isRequired("hyperref")
2278 && !features.isRequired("varioref")
2279 && !features.isRequired("japanese")) {
2280 os << features.getBabelPresettings();
2282 os << from_utf8(babelCall(language_options.str(),
2283 !lyxrc.language_global_options)) + '\n';
2284 os << features.getBabelPostsettings();
2286 // In documents containing text in Thai language,
2287 // we must load inputenc after babel (see lib/languages).
2288 if (contains(features.getBabelPostsettings(), from_ascii("thai.ldf")))
2289 writeEncodingPreamble(os, features);
2291 // font selection must be done after babel with non-TeX fonts
2292 if (!fonts.empty() && features.useBabel() && useNonTeXFonts)
2293 os << from_utf8(fonts);
2295 if (features.isRequired("bicaption"))
2296 os << "\\usepackage{bicaption}\n";
2297 if (!listings_params.empty()
2298 || features.mustProvide("listings")
2299 || features.mustProvide("minted")) {
2301 os << "\\usepackage{minted}\n";
2303 os << "\\usepackage{listings}\n";
2305 string lst_params = listings_params;
2306 // If minted, do not output the language option (bug 11203)
2307 if (use_minted && contains(lst_params, "language=")) {
2308 vector<string> opts =
2309 getVectorFromString(lst_params, ",", false);
2310 for (size_t i = 0; i < opts.size(); ++i) {
2311 if (prefixIs(opts[i], "language="))
2312 opts.erase(opts.begin() + i--);
2314 lst_params = getStringFromVector(opts, ",");
2316 if (!lst_params.empty()) {
2318 os << "\\setminted{";
2321 // do not test validity because listings_params is
2322 // supposed to be valid
2324 InsetListingsParams(lst_params).separatedParams(true);
2325 os << from_utf8(par);
2329 // xunicode only needs to be loaded if tipa is used
2330 // (the rest is obsoleted by the new TU encoding).
2331 // It needs to be loaded at least after amsmath, amssymb,
2332 // esint and the other packages that provide special glyphs
2333 if (features.mustProvide("tipa") && useNonTeXFonts
2334 && !features.isProvided("xunicode")) {
2335 // The `xunicode` package officially only supports XeTeX,
2336 // but also works with LuaTeX. We work around its XeTeX test.
2337 if (features.runparams().flavor != OutputParams::XETEX) {
2338 os << "% Pretend to xunicode that we are XeTeX\n"
2339 << "\\def\\XeTeXpicfile{}\n";
2341 os << "\\usepackage{xunicode}\n";
2344 // covington must be loaded after beamerarticle
2345 if (features.isRequired("covington"))
2346 os << "\\usepackage{covington}\n";
2348 // Polyglossia must be loaded last ...
2349 if (use_polyglossia) {
2351 os << "\\usepackage{polyglossia}\n";
2352 // set the main language
2353 os << "\\setdefaultlanguage";
2354 if (!language->polyglossiaOpts().empty())
2355 os << "[" << from_ascii(language->polyglossiaOpts()) << "]";
2356 os << "{" << from_ascii(language->polyglossia()) << "}\n";
2357 // now setup the other languages
2358 set<string> const polylangs =
2359 features.getPolyglossiaLanguages();
2360 for (auto const & pl : polylangs) {
2361 // We do not output the options here; they are output in
2362 // the language switch commands. This is safer if multiple
2363 // varieties are used.
2364 if (pl == language->polyglossia())
2366 os << "\\setotherlanguage";
2367 os << "{" << from_ascii(pl) << "}\n";
2371 // ... but before biblatex (see #7065)
2372 if ((features.mustProvide("biblatex")
2373 || features.isRequired("biblatex-chicago"))
2374 && !features.isProvided("biblatex-chicago")
2375 && !features.isProvided("biblatex-natbib")
2376 && !features.isProvided("natbib-internal")
2377 && !features.isProvided("natbib")
2378 && !features.isProvided("jurabib")) {
2379 // The biblatex-chicago package has a differing interface
2380 // it uses a wrapper package and loads styles via fixed options
2381 bool const chicago = features.isRequired("biblatex-chicago");
2384 os << "\\usepackage";
2385 if (!biblatex_bibstyle.empty()
2386 && (biblatex_bibstyle == biblatex_citestyle)
2388 opts = "style=" + biblatex_bibstyle;
2390 } else if (!chicago) {
2391 if (!biblatex_bibstyle.empty()) {
2392 opts = "bibstyle=" + biblatex_bibstyle;
2395 if (!biblatex_citestyle.empty()) {
2396 opts += delim + "citestyle=" + biblatex_citestyle;
2400 if (!multibib.empty() && multibib != "child") {
2401 opts += delim + "refsection=" + multibib;
2404 if (bibtexCommand() == "bibtex8"
2405 || prefixIs(bibtexCommand(), "bibtex8 ")) {
2406 opts += delim + "backend=bibtex8";
2408 } else if (bibtexCommand() == "bibtex"
2409 || prefixIs(bibtexCommand(), "bibtex ")) {
2410 opts += delim + "backend=bibtex";
2413 if (!bib_encoding.empty() && encodings.fromLyXName(bib_encoding)) {
2414 opts += delim + "bibencoding="
2415 + encodings.fromLyXName(bib_encoding)->latexName();
2418 if (!biblio_opts.empty())
2419 opts += delim + biblio_opts;
2421 os << "[" << opts << "]";
2423 os << "{biblatex-chicago}\n";
2425 os << "{biblatex}\n";
2429 // Load custom language package here
2430 if (features.langPackage() == LaTeXFeatures::LANG_PACK_CUSTOM) {
2431 if (lang_package == "default")
2432 os << from_utf8(lyxrc.language_custom_package);
2434 os << from_utf8(lang_package);
2438 // Since menukeys uses catoptions, which does some heavy changes on key-value options,
2439 // it is recommended to load menukeys as the last package (even after hyperref)
2440 if (features.isRequired("menukeys"))
2441 os << "\\usepackage{menukeys}\n";
2443 docstring const i18npreamble =
2444 features.getTClassI18nPreamble(use_babel, use_polyglossia,
2446 if (!i18npreamble.empty())
2447 os << i18npreamble + '\n';
2453 void BufferParams::useClassDefaults()
2455 DocumentClass const & tclass = documentClass();
2457 sides = tclass.sides();
2458 columns = tclass.columns();
2459 pagestyle = tclass.pagestyle();
2460 tablestyle = tclass.tablestyle();
2461 use_default_options = true;
2462 // Only if class has a ToC hierarchy
2463 if (tclass.hasTocLevels()) {
2464 secnumdepth = tclass.secnumdepth();
2465 tocdepth = tclass.tocdepth();
2470 bool BufferParams::hasClassDefaults() const
2472 DocumentClass const & tclass = documentClass();
2474 return sides == tclass.sides()
2475 && columns == tclass.columns()
2476 && pagestyle == tclass.pagestyle()
2477 && tablestyle == tclass.tablestyle()
2478 && use_default_options
2479 && secnumdepth == tclass.secnumdepth()
2480 && tocdepth == tclass.tocdepth();
2484 DocumentClass const & BufferParams::documentClass() const
2490 DocumentClassConstPtr BufferParams::documentClassPtr() const
2496 void BufferParams::setDocumentClass(DocumentClassConstPtr tc)
2498 // evil, but this function is evil
2499 doc_class_ = const_pointer_cast<DocumentClass>(tc);
2500 invalidateConverterCache();
2504 bool BufferParams::setBaseClass(string const & classname, string const & path)
2506 LYXERR(Debug::TCLASS, "setBaseClass: " << classname);
2507 LayoutFileList & bcl = LayoutFileList::get();
2508 if (!bcl.haveClass(classname)) {
2510 bformat(_("The layout file:\n"
2512 "could not be found. A default textclass with default\n"
2513 "layouts will be used. LyX will not be able to produce\n"
2515 from_utf8(classname));
2516 frontend::Alert::error(_("Document class not found"), s);
2517 bcl.addEmptyClass(classname);
2520 bool const success = bcl[classname].load(path);
2523 bformat(_("Due to some error in it, the layout file:\n"
2525 "could not be loaded. A default textclass with default\n"
2526 "layouts will be used. LyX will not be able to produce\n"
2528 from_utf8(classname));
2529 frontend::Alert::error(_("Could not load class"), s);
2530 bcl.addEmptyClass(classname);
2533 pimpl_->baseClass_ = classname;
2534 layout_modules_.adaptToBaseClass(baseClass(), removed_modules_);
2539 LayoutFile const * BufferParams::baseClass() const
2541 if (LayoutFileList::get().haveClass(pimpl_->baseClass_))
2542 return &(LayoutFileList::get()[pimpl_->baseClass_]);
2548 LayoutFileIndex const & BufferParams::baseClassID() const
2550 return pimpl_->baseClass_;
2554 void BufferParams::makeDocumentClass(bool const clone)
2559 invalidateConverterCache();
2560 LayoutModuleList mods;
2561 for (auto const & mod : layout_modules_)
2562 mods.push_back(mod);
2564 doc_class_ = getDocumentClass(*baseClass(), mods, cite_engine_, clone);
2566 TextClass::ReturnValues success = TextClass::OK;
2567 if (!forced_local_layout_.empty())
2568 success = doc_class_->read(to_utf8(forced_local_layout_),
2570 if (!local_layout_.empty() &&
2571 (success == TextClass::OK || success == TextClass::OK_OLDFORMAT))
2572 success = doc_class_->read(to_utf8(local_layout_), TextClass::MODULE);
2573 if (success != TextClass::OK && success != TextClass::OK_OLDFORMAT) {
2574 docstring const msg = _("Error reading internal layout information");
2575 frontend::Alert::warning(_("Read Error"), msg);
2580 bool BufferParams::layoutModuleCanBeAdded(string const & modName) const
2582 return layout_modules_.moduleCanBeAdded(modName, baseClass());
2586 docstring BufferParams::getLocalLayout(bool forced) const
2589 return from_utf8(doc_class_->forcedLayouts());
2591 return local_layout_;
2595 void BufferParams::setLocalLayout(docstring const & layout, bool forced)
2598 forced_local_layout_ = layout;
2600 local_layout_ = layout;
2604 bool BufferParams::addLayoutModule(string const & modName)
2606 for (auto const & mod : layout_modules_)
2609 layout_modules_.push_back(modName);
2614 string BufferParams::bufferFormat() const
2616 return documentClass().outputFormat();
2620 bool BufferParams::isExportable(string const & format, bool need_viewable) const
2622 FormatList const & formats = exportableFormats(need_viewable);
2623 for (auto const & fmt : formats) {
2624 if (fmt->name() == format)
2631 FormatList const & BufferParams::exportableFormats(bool only_viewable) const
2633 FormatList & cached = only_viewable ?
2634 pimpl_->viewableFormatList : pimpl_->exportableFormatList;
2635 bool & valid = only_viewable ?
2636 pimpl_->isViewCacheValid : pimpl_->isExportCacheValid;
2640 vector<string> const backs = backends();
2641 set<string> excludes;
2642 if (useNonTeXFonts) {
2643 excludes.insert("latex");
2644 excludes.insert("pdflatex");
2645 } else if (inputenc != "ascii" && inputenc != "utf8-plain")
2646 // XeTeX with TeX fonts requires input encoding ascii (#10600).
2647 excludes.insert("xetex");
2648 FormatList result = theConverters().getReachable(backs[0], only_viewable,
2650 vector<string>::const_iterator it = backs.begin() + 1;
2651 for (; it != backs.end(); ++it) {
2652 FormatList r = theConverters().getReachable(*it, only_viewable,
2654 result.insert(result.end(), r.begin(), r.end());
2656 sort(result.begin(), result.end(), Format::formatSorter);
2663 vector<string> BufferParams::backends() const
2666 string const buffmt = bufferFormat();
2668 // FIXME: Don't hardcode format names here, but use a flag
2669 if (buffmt == "latex") {
2670 if (encoding().package() == Encoding::japanese)
2671 v.push_back("platex");
2673 if (!useNonTeXFonts) {
2674 v.push_back("pdflatex");
2675 v.push_back("latex");
2678 || inputenc == "ascii" || inputenc == "utf8-plain")
2679 v.push_back("xetex");
2680 v.push_back("luatex");
2681 v.push_back("dviluatex");
2684 string rbuffmt = buffmt;
2685 // If we use an OutputFormat in Japanese docs,
2686 // we need special format in order to get the path
2687 // via pLaTeX (#8823)
2688 if (documentClass().hasOutputFormat()
2689 && encoding().package() == Encoding::japanese)
2691 v.push_back(rbuffmt);
2694 v.push_back("xhtml");
2695 v.push_back("text");
2701 OutputParams::FLAVOR BufferParams::getOutputFlavor(string const & format) const
2703 string const dformat = (format.empty() || format == "default") ?
2704 getDefaultOutputFormat() : format;
2705 DefaultFlavorCache::const_iterator it =
2706 default_flavors_.find(dformat);
2708 if (it != default_flavors_.end())
2711 OutputParams::FLAVOR result = OutputParams::LATEX;
2713 // FIXME It'd be better not to hardcode this, but to do
2714 // something with formats.
2715 if (dformat == "xhtml")
2716 result = OutputParams::HTML;
2717 else if (dformat == "text")
2718 result = OutputParams::TEXT;
2719 else if (dformat == "lyx")
2720 result = OutputParams::LYX;
2721 else if (dformat == "pdflatex")
2722 result = OutputParams::PDFLATEX;
2723 else if (dformat == "xetex")
2724 result = OutputParams::XETEX;
2725 else if (dformat == "luatex")
2726 result = OutputParams::LUATEX;
2727 else if (dformat == "dviluatex")
2728 result = OutputParams::DVILUATEX;
2730 // Try to determine flavor of default output format
2731 vector<string> backs = backends();
2732 if (find(backs.begin(), backs.end(), dformat) == backs.end()) {
2733 // Get shortest path to format
2734 Graph::EdgePath path;
2735 for (auto const & bvar : backs) {
2736 Graph::EdgePath p = theConverters().getPath(bvar, dformat);
2737 if (!p.empty() && (path.empty() || p.size() < path.size())) {
2742 result = theConverters().getFlavor(path);
2745 // cache this flavor
2746 default_flavors_[dformat] = result;
2751 string BufferParams::getDefaultOutputFormat() const
2753 if (!default_output_format.empty()
2754 && default_output_format != "default")
2755 return default_output_format;
2757 FormatList const & formats = exportableFormats(true);
2758 if (formats.empty())
2760 // return the first we find
2761 return formats.front()->name();
2763 if (encoding().package() == Encoding::japanese)
2764 return lyxrc.default_platex_view_format;
2766 return lyxrc.default_otf_view_format;
2767 return lyxrc.default_view_format;
2770 Font const BufferParams::getFont() const
2772 FontInfo f = documentClass().defaultfont();
2773 if (fonts_default_family == "rmdefault")
2774 f.setFamily(ROMAN_FAMILY);
2775 else if (fonts_default_family == "sfdefault")
2776 f.setFamily(SANS_FAMILY);
2777 else if (fonts_default_family == "ttdefault")
2778 f.setFamily(TYPEWRITER_FAMILY);
2779 return Font(f, language);
2783 InsetQuotesParams::QuoteStyle BufferParams::getQuoteStyle(string const & qs) const
2785 return quotesstyletranslator().find(qs);
2789 bool BufferParams::isLatex() const
2791 return documentClass().outputType() == LATEX;
2795 bool BufferParams::isLiterate() const
2797 return documentClass().outputType() == LITERATE;
2801 bool BufferParams::isDocBook() const
2803 return documentClass().outputType() == DOCBOOK;
2807 void BufferParams::readPreamble(Lexer & lex)
2809 if (lex.getString() != "\\begin_preamble")
2810 lyxerr << "Error (BufferParams::readPreamble):"
2811 "consistency check failed." << endl;
2813 preamble = lex.getLongString(from_ascii("\\end_preamble"));
2817 void BufferParams::readLocalLayout(Lexer & lex, bool forced)
2819 string const expected = forced ? "\\begin_forced_local_layout" :
2820 "\\begin_local_layout";
2821 if (lex.getString() != expected)
2822 lyxerr << "Error (BufferParams::readLocalLayout):"
2823 "consistency check failed." << endl;
2826 forced_local_layout_ =
2827 lex.getLongString(from_ascii("\\end_forced_local_layout"));
2829 local_layout_ = lex.getLongString(from_ascii("\\end_local_layout"));
2833 bool BufferParams::setLanguage(string const & lang)
2835 Language const *new_language = languages.getLanguage(lang);
2836 if (!new_language) {
2837 // Language lang was not found
2840 language = new_language;
2845 void BufferParams::readLanguage(Lexer & lex)
2847 if (!lex.next()) return;
2849 string const tmptok = lex.getString();
2851 // check if tmptok is part of tex_babel in tex-defs.h
2852 if (!setLanguage(tmptok)) {
2853 // Language tmptok was not found
2854 language = default_language;
2855 lyxerr << "Warning: Setting language `"
2856 << tmptok << "' to `" << language->lang()
2862 void BufferParams::readGraphicsDriver(Lexer & lex)
2867 string const tmptok = lex.getString();
2868 // check if tmptok is part of tex_graphics in tex_defs.h
2871 string const test = tex_graphics[n++];
2873 if (test == tmptok) {
2874 graphics_driver = tmptok;
2879 "Warning: graphics driver `$$Token' not recognized!\n"
2880 " Setting graphics driver to `default'.\n");
2881 graphics_driver = "default";
2888 void BufferParams::readBullets(Lexer & lex)
2893 int const index = lex.getInteger();
2895 int temp_int = lex.getInteger();
2896 user_defined_bullet(index).setFont(temp_int);
2897 temp_bullet(index).setFont(temp_int);
2899 user_defined_bullet(index).setCharacter(temp_int);
2900 temp_bullet(index).setCharacter(temp_int);
2902 user_defined_bullet(index).setSize(temp_int);
2903 temp_bullet(index).setSize(temp_int);
2907 void BufferParams::readBulletsLaTeX(Lexer & lex)
2909 // The bullet class should be able to read this.
2912 int const index = lex.getInteger();
2914 docstring const temp_str = lex.getDocString();
2916 user_defined_bullet(index).setText(temp_str);
2917 temp_bullet(index).setText(temp_str);
2921 void BufferParams::readModules(Lexer & lex)
2923 if (!lex.eatLine()) {
2924 lyxerr << "Error (BufferParams::readModules):"
2925 "Unexpected end of input." << endl;
2929 string mod = lex.getString();
2930 if (mod == "\\end_modules")
2932 addLayoutModule(mod);
2938 void BufferParams::readRemovedModules(Lexer & lex)
2940 if (!lex.eatLine()) {
2941 lyxerr << "Error (BufferParams::readRemovedModules):"
2942 "Unexpected end of input." << endl;
2946 string mod = lex.getString();
2947 if (mod == "\\end_removed_modules")
2949 removed_modules_.push_back(mod);
2952 // now we want to remove any removed modules that were previously
2953 // added. normally, that will be because default modules were added in
2954 // setBaseClass(), which gets called when \textclass is read at the
2955 // start of the read.
2956 for (auto const & rm : removed_modules_) {
2957 LayoutModuleList::iterator const mit = layout_modules_.begin();
2958 LayoutModuleList::iterator const men = layout_modules_.end();
2959 LayoutModuleList::iterator found = find(mit, men, rm);
2962 layout_modules_.erase(found);
2967 void BufferParams::readIncludeonly(Lexer & lex)
2969 if (!lex.eatLine()) {
2970 lyxerr << "Error (BufferParams::readIncludeonly):"
2971 "Unexpected end of input." << endl;
2975 string child = lex.getString();
2976 if (child == "\\end_includeonly")
2978 included_children_.push_back(child);
2984 string BufferParams::paperSizeName(PapersizePurpose purpose, string const & psize) const
2986 PAPER_SIZE ppsize = psize.empty() ? papersize : papersizetranslator().find(psize);
2989 if (documentClass().pagesize() == "default")
2990 // could be anything, so don't guess
2992 return paperSizeName(purpose, documentClass().pagesize());
2993 case PAPER_CUSTOM: {
2994 if (purpose == XDVI && !paperwidth.empty() &&
2995 !paperheight.empty()) {
2996 // heightxwidth<unit>
2997 string first = paperwidth;
2998 string second = paperheight;
2999 if (orientation == ORIENTATION_LANDSCAPE)
3002 return first.erase(first.length() - 2)
3008 // dvips and dvipdfm do not know this
3009 if (purpose == DVIPS || purpose == DVIPDFM)
3013 if (purpose == DVIPS || purpose == DVIPDFM)
3017 if (purpose == DVIPS || purpose == DVIPDFM)
3027 if (purpose == DVIPS || purpose == DVIPDFM)
3031 if (purpose == DVIPS || purpose == DVIPDFM)
3035 if (purpose == DVIPS || purpose == DVIPDFM)
3039 if (purpose == DVIPS || purpose == DVIPDFM)
3043 if (purpose == DVIPS || purpose == DVIPDFM)
3047 // dvipdfm does not know this
3048 if (purpose == DVIPDFM)
3052 if (purpose == DVIPDFM)
3056 if (purpose == DVIPS || purpose == DVIPDFM)
3060 if (purpose == DVIPS || purpose == DVIPDFM)
3064 if (purpose == DVIPS || purpose == DVIPDFM)
3068 if (purpose == DVIPS || purpose == DVIPDFM)
3072 if (purpose == DVIPS || purpose == DVIPDFM)
3076 if (purpose == DVIPS || purpose == DVIPDFM)
3080 if (purpose == DVIPS || purpose == DVIPDFM)
3084 if (purpose == DVIPS || purpose == DVIPDFM)
3088 if (purpose == DVIPS || purpose == DVIPDFM)
3092 if (purpose == DVIPS || purpose == DVIPDFM)
3096 if (purpose == DVIPS || purpose == DVIPDFM)
3100 if (purpose == DVIPS || purpose == DVIPDFM)
3104 if (purpose == DVIPS || purpose == DVIPDFM)
3108 if (purpose == DVIPS || purpose == DVIPDFM)
3112 if (purpose == DVIPS || purpose == DVIPDFM)
3115 case PAPER_USEXECUTIVE:
3116 // dvipdfm does not know this
3117 if (purpose == DVIPDFM)
3122 case PAPER_USLETTER:
3124 if (purpose == XDVI)
3131 string const BufferParams::dvips_options() const
3135 // If the class loads the geometry package, we do not know which
3136 // paper size is used, since we do not set it (bug 7013).
3137 // Therefore we must not specify any argument here.
3138 // dvips gets the correct paper size via DVI specials in this case
3139 // (if the class uses the geometry package correctly).
3140 if (documentClass().provides("geometry"))
3144 && papersize == PAPER_CUSTOM
3145 && !lyxrc.print_paper_dimension_flag.empty()
3146 && !paperwidth.empty()
3147 && !paperheight.empty()) {
3148 // using a custom papersize
3149 result = lyxrc.print_paper_dimension_flag;
3150 result += ' ' + paperwidth;
3151 result += ',' + paperheight;
3153 string const paper_option = paperSizeName(DVIPS);
3154 if (!paper_option.empty() && (paper_option != "letter" ||
3155 orientation != ORIENTATION_LANDSCAPE)) {
3156 // dvips won't accept -t letter -t landscape.
3157 // In all other cases, include the paper size
3159 result = lyxrc.print_paper_flag;
3160 result += ' ' + paper_option;
3163 if (orientation == ORIENTATION_LANDSCAPE &&
3164 papersize != PAPER_CUSTOM)
3165 result += ' ' + lyxrc.print_landscape_flag;
3170 string const BufferParams::main_font_encoding() const
3172 if (font_encodings().empty()) {
3173 if (ascii_lowercase(language->fontenc(*this)) == "none")
3177 return font_encodings().back();
3181 vector<string> const BufferParams::font_encodings() const
3183 string doc_fontenc = (fontenc == "auto") ? string() : fontenc;
3185 vector<string> fontencs;
3187 // "default" means "no explicit font encoding"
3188 if (doc_fontenc != "default") {
3189 if (!doc_fontenc.empty())
3190 // If we have a custom setting, we use only that!
3191 return getVectorFromString(doc_fontenc);
3192 if (!language->fontenc(*this).empty()
3193 && ascii_lowercase(language->fontenc(*this)) != "none") {
3194 vector<string> fencs = getVectorFromString(language->fontenc(*this));
3195 for (auto & fe : fencs) {
3196 if (find(fontencs.begin(), fontencs.end(), fe) == fontencs.end())
3197 fontencs.push_back(fe);
3206 string BufferParams::babelCall(string const & lang_opts, bool const langoptions) const
3208 // suppress the babel call if there is no BabelName defined
3209 // for the document language in the lib/languages file and if no
3210 // other languages are used (lang_opts is then empty)
3211 if (lang_opts.empty())
3213 // The prefs may require the languages to
3214 // be submitted to babel itself (not the class).
3216 return "\\usepackage[" + lang_opts + "]{babel}";
3217 return "\\usepackage{babel}";
3221 docstring BufferParams::getGraphicsDriver(string const & package) const
3225 if (package == "geometry") {
3226 if (graphics_driver == "dvips"
3227 || graphics_driver == "dvipdfm"
3228 || graphics_driver == "pdftex"
3229 || graphics_driver == "vtex")
3230 result = from_ascii(graphics_driver);
3231 else if (graphics_driver == "dvipdfmx")
3232 result = from_ascii("dvipdfm");
3239 void BufferParams::writeEncodingPreamble(otexstream & os,
3240 LaTeXFeatures & features) const
3242 // With no-TeX fonts we use utf8-plain without encoding package.
3246 if (inputenc == "auto-legacy") {
3247 string const doc_encoding =
3248 language->encoding()->latexName();
3249 Encoding::Package const package =
3250 language->encoding()->package();
3252 // Create list of inputenc options:
3253 set<string> encoding_set;
3254 // luainputenc fails with more than one encoding
3255 if (features.runparams().flavor != OutputParams::LUATEX
3256 && features.runparams().flavor != OutputParams::DVILUATEX)
3257 // list all input encodings used in the document
3258 encoding_set = features.getEncodingSet(doc_encoding);
3260 // The "japanese" babel-language requires the pLaTeX engine
3261 // which conflicts with "inputenc".
3262 // See http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129680.html
3263 if ((!encoding_set.empty() || package == Encoding::inputenc)
3264 && !features.isRequired("japanese")
3265 && !features.isProvided("inputenc")) {
3266 os << "\\usepackage[";
3267 set<string>::const_iterator it = encoding_set.begin();
3268 set<string>::const_iterator const end = encoding_set.end();
3270 os << from_ascii(*it);
3273 for (; it != end; ++it)
3274 os << ',' << from_ascii(*it);
3275 if (package == Encoding::inputenc) {
3276 if (!encoding_set.empty())
3278 os << from_ascii(doc_encoding);
3280 if (features.runparams().flavor == OutputParams::LUATEX
3281 || features.runparams().flavor == OutputParams::DVILUATEX)
3282 os << "]{luainputenc}\n";
3284 os << "]{inputenc}\n";
3286 } else if (inputenc != "auto-legacy-plain") {
3287 switch (encoding().package()) {
3288 case Encoding::none:
3290 case Encoding::japanese:
3291 if (encoding().iconvName() != "UTF-8"
3292 && !features.runparams().isFullUnicode())
3293 // don't default to [utf8]{inputenc} with TeXLive >= 18
3294 os << "\\ifdefined\\UseRawInputEncoding\n"
3295 << " \\UseRawInputEncoding\\fi\n";
3297 case Encoding::inputenc:
3298 // do not load inputenc if japanese is used
3299 // or if the class provides inputenc
3300 if (features.isRequired("japanese")
3301 || features.isProvided("inputenc"))
3303 os << "\\usepackage[" << from_ascii(encoding().latexName());
3304 if (features.runparams().flavor == OutputParams::LUATEX
3305 || features.runparams().flavor == OutputParams::DVILUATEX)
3306 os << "]{luainputenc}\n";
3308 os << "]{inputenc}\n";
3312 if (inputenc == "auto-legacy-plain" || features.isRequired("japanese")) {
3313 // don't default to [utf8]{inputenc} with TeXLive >= 18
3314 os << "\\ifdefined\\UseRawInputEncoding\n";
3315 os << " \\UseRawInputEncoding\\fi\n";
3320 string const BufferParams::parseFontName(string const & name) const
3322 string mangled = name;
3323 size_t const idx = mangled.find('[');
3324 if (idx == string::npos || idx == 0)
3327 return mangled.substr(0, idx - 1);
3331 string const BufferParams::loadFonts(LaTeXFeatures & features) const
3333 if (fontsRoman() == "default" && fontsSans() == "default"
3334 && fontsTypewriter() == "default"
3335 && (fontsMath() == "default" || fontsMath() == "auto"))
3341 /* Fontspec (XeTeX, LuaTeX): we provide GUI support for oldstyle
3342 * numbers (Numbers=OldStyle) and sf/tt scaling. The Ligatures=TeX/
3343 * Mapping=tex-text option assures TeX ligatures (such as "--")
3344 * are resolved. Note that tt does not use these ligatures.
3346 * -- add more GUI options?
3347 * -- add more fonts (fonts for other scripts)
3348 * -- if there's a way to find out if a font really supports
3349 * OldStyle, enable/disable the widget accordingly.
3351 if (useNonTeXFonts && features.isAvailable("fontspec")) {
3352 // "Mapping=tex-text" and "Ligatures=TeX" are equivalent.
3353 // However, until v.2 (2010/07/11) fontspec only knew
3354 // Mapping=tex-text (for XeTeX only); then "Ligatures=TeX"
3355 // was introduced for both XeTeX and LuaTeX (LuaTeX
3356 // didn't understand "Mapping=tex-text", while XeTeX
3357 // understood both. With most recent versions, both
3358 // variants are understood by both engines. However,
3359 // we want to provide support for at least TeXLive 2009
3360 // (for XeTeX; LuaTeX is only supported as of v.2)
3361 // As of 2017/11/03, Babel has its own higher-level
3362 // interface on top of fontspec that is to be used.
3363 bool const babelfonts = features.useBabel()
3364 && features.isAvailable("babel-2017/11/03");
3365 string const texmapping =
3366 (features.runparams().flavor == OutputParams::XETEX) ?
3367 "Mapping=tex-text" : "Ligatures=TeX";
3368 if (fontsRoman() != "default") {
3370 os << "\\babelfont{rm}[";
3372 os << "\\setmainfont[";
3373 if (!font_roman_opts.empty())
3374 os << font_roman_opts << ',';
3376 if (fonts_roman_osf)
3377 os << ",Numbers=OldStyle";
3378 os << "]{" << parseFontName(fontsRoman()) << "}\n";
3380 if (fontsSans() != "default") {
3381 string const sans = parseFontName(fontsSans());
3382 if (fontsSansScale() != 100) {
3384 os << "\\babelfont{sf}";
3386 os << "\\setsansfont";
3388 << float(fontsSansScale()) / 100 << ',';
3390 os << "Numbers=OldStyle,";
3391 if (!font_sans_opts.empty())
3392 os << font_sans_opts << ',';
3393 os << texmapping << "]{"
3397 os << "\\babelfont{sf}[";
3399 os << "\\setsansfont[";
3401 os << "Numbers=OldStyle,";
3402 if (!font_sans_opts.empty())
3403 os << font_sans_opts << ',';
3404 os << texmapping << "]{"
3408 if (fontsTypewriter() != "default") {
3409 string const mono = parseFontName(fontsTypewriter());
3410 if (fontsTypewriterScale() != 100) {
3412 os << "\\babelfont{tt}";
3414 os << "\\setmonofont";
3416 << float(fontsTypewriterScale()) / 100;
3417 if (fonts_typewriter_osf)
3418 os << ",Numbers=OldStyle";
3419 if (!font_typewriter_opts.empty())
3420 os << ',' << font_typewriter_opts;
3425 os << "\\babelfont{tt}";
3427 os << "\\setmonofont";
3428 if (!font_typewriter_opts.empty() || fonts_typewriter_osf) {
3430 if (fonts_typewriter_osf)
3431 os << "Numbers=OldStyle";
3432 if (!font_typewriter_opts.empty()) {
3433 if (fonts_typewriter_osf)
3435 os << font_typewriter_opts;
3439 os << '{' << mono << "}\n";
3446 bool const ot1 = (main_font_encoding() == "default" || main_font_encoding() == "OT1");
3447 bool const dryrun = features.runparams().dryrun;
3448 bool const complete = (fontsSans() == "default" && fontsTypewriter() == "default");
3449 bool const nomath = (fontsMath() == "default");
3452 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsRoman())).getLaTeXCode(
3453 dryrun, ot1, complete, fonts_expert_sc, fonts_roman_osf,
3454 nomath, font_roman_opts);
3457 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsSans())).getLaTeXCode(
3458 dryrun, ot1, complete, fonts_expert_sc, fonts_sans_osf,
3459 nomath, font_sans_opts, fontsSansScale());
3461 // MONOSPACED/TYPEWRITER
3462 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsTypewriter())).getLaTeXCode(
3463 dryrun, ot1, complete, fonts_expert_sc, fonts_typewriter_osf,
3464 nomath, font_typewriter_opts, fontsTypewriterScale());
3467 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsMath())).getLaTeXCode(
3468 dryrun, ot1, complete, fonts_expert_sc, fonts_roman_osf,
3475 Encoding const & BufferParams::encoding() const
3477 // Main encoding for LaTeX output.
3479 return *(encodings.fromLyXName("utf8-plain"));
3480 if (inputenc == "auto-legacy" || inputenc == "auto-legacy-plain")
3481 return *language->encoding();
3482 if (inputenc == "utf8" && language->lang() == "japanese")
3483 return *(encodings.fromLyXName("utf8-platex"));
3484 Encoding const * const enc = encodings.fromLyXName(inputenc);
3487 LYXERR0("Unknown inputenc value `" << inputenc
3488 << "'. Using `auto' instead.");
3489 return *language->encoding();
3493 string const & BufferParams::defaultBiblioStyle() const
3495 if (!biblio_style.empty())
3496 return biblio_style;
3498 map<string, string> const & bs = documentClass().defaultBiblioStyle();
3499 auto cit = bs.find(theCiteEnginesList.getTypeAsString(citeEngineType()));
3500 if (cit != bs.end())
3503 return empty_string();
3507 bool const & BufferParams::fullAuthorList() const
3509 return documentClass().fullAuthorList();
3513 string BufferParams::getCiteAlias(string const & s) const
3515 vector<string> commands =
3516 documentClass().citeCommands(citeEngineType());
3517 // If it is a real command, don't treat it as an alias
3518 if (find(commands.begin(), commands.end(), s) != commands.end())
3520 map<string,string> aliases = documentClass().citeCommandAliases();
3521 if (aliases.find(s) != aliases.end())
3527 vector<string> BufferParams::citeCommands() const
3529 static CitationStyle const default_style;
3530 vector<string> commands =
3531 documentClass().citeCommands(citeEngineType());
3532 if (commands.empty())
3533 commands.push_back(default_style.name);
3538 vector<CitationStyle> BufferParams::citeStyles() const
3540 static CitationStyle const default_style;
3541 vector<CitationStyle> styles =
3542 documentClass().citeStyles(citeEngineType());
3544 styles.push_back(default_style);
3549 string const BufferParams::bibtexCommand() const
3551 // Return document-specific setting if available
3552 if (bibtex_command != "default")
3553 return bibtex_command;
3555 // If we have "default" in document settings, consult the prefs
3556 // 1. Japanese (uses a specific processor)
3557 if (encoding().package() == Encoding::japanese) {
3558 if (lyxrc.jbibtex_command != "automatic")
3559 // Return the specified program, if "automatic" is not set
3560 return lyxrc.jbibtex_command;
3561 else if (!useBiblatex()) {
3562 // With classic BibTeX, return pbibtex, jbibtex, bibtex
3563 if (lyxrc.jbibtex_alternatives.find("pbibtex") != lyxrc.jbibtex_alternatives.end())
3565 if (lyxrc.jbibtex_alternatives.find("jbibtex") != lyxrc.jbibtex_alternatives.end())
3570 // 2. All other languages
3571 else if (lyxrc.bibtex_command != "automatic")
3572 // Return the specified program, if "automatic" is not set
3573 return lyxrc.bibtex_command;
3575 // 3. Automatic: find the most suitable for the current cite framework
3576 if (useBiblatex()) {
3577 // For Biblatex, we prefer biber (also for Japanese)
3578 // and fall back to bibtex8 and, as last resort, bibtex
3579 if (lyxrc.bibtex_alternatives.find("biber") != lyxrc.bibtex_alternatives.end())
3581 else if (lyxrc.bibtex_alternatives.find("bibtex8") != lyxrc.bibtex_alternatives.end())
3588 bool BufferParams::useBiblatex() const
3590 return theCiteEnginesList[citeEngine()]->getCiteFramework() == "biblatex";
3594 void BufferParams::invalidateConverterCache() const
3596 pimpl_->isExportCacheValid = false;
3597 pimpl_->isViewCacheValid = false;
3601 // We shouldn't need to reset the params here, since anything
3602 // we need will be recopied.
3603 void BufferParams::copyForAdvFR(const BufferParams & bp)
3605 string const & lang = bp.language->lang();
3607 layout_modules_ = bp.layout_modules_;
3608 string const & doc_class = bp.documentClass().name();
3609 setBaseClass(doc_class);
3613 void BufferParams::setBibFileEncoding(string const & file, string const & enc)
3615 bib_encodings[file] = enc;
3619 string const BufferParams::bibFileEncoding(string const & file) const
3621 if (bib_encodings.find(file) == bib_encodings.end())
3623 return bib_encodings.find(file)->second;