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 string strOptions(clsoptions.str());
1729 if (!strOptions.empty()) {
1730 strOptions = rtrim(strOptions, ",");
1732 os << '[' << from_utf8(strOptions) << ']';
1735 os << '{' << from_ascii(tclass.latexname()) << "}\n";
1736 // end of \documentclass defs
1738 // if we use fontspec or newtxmath, we have to load the AMS packages here
1739 string const ams = features.loadAMSPackages();
1740 bool const ot1 = (main_font_encoding() == "default" || main_font_encoding() == "OT1");
1741 bool const use_newtxmath =
1742 theLaTeXFonts().getLaTeXFont(from_ascii(fontsMath())).getUsedPackage(
1743 ot1, false, false) == "newtxmath";
1744 if ((useNonTeXFonts || use_newtxmath) && !ams.empty())
1745 os << from_ascii(ams);
1747 if (useNonTeXFonts) {
1748 // Babel (as of 2017/11/03) loads fontspec itself
1749 if (!features.isProvided("fontspec")
1750 && !(features.useBabel() && features.isAvailable("babel-2017/11/03")))
1751 os << "\\usepackage{fontspec}\n";
1752 if (features.mustProvide("unicode-math")
1753 && features.isAvailable("unicode-math"))
1754 os << "\\usepackage{unicode-math}\n";
1757 // load CJK support package before font selection
1758 // (see autotests/export/latex/CJK/micro-sign_utf8-cjk-libertine.lyx)
1759 if (!useNonTeXFonts && encoding().package() != Encoding::none && inputenc != "utf8x"
1760 && (encoding().package() == Encoding::CJK || features.mustProvide("CJK"))) {
1761 if (inputenc == "utf8-cjk" || inputenc == "utf8")
1762 os << "\\usepackage{CJKutf8}\n";
1764 os << "\\usepackage[encapsulated]{CJK}\n";
1767 // font selection must be done before loading fontenc.sty
1768 // but after babel with non-TeX fonts
1769 string const fonts = loadFonts(features);
1770 if (!fonts.empty() && (!features.useBabel() || !useNonTeXFonts))
1771 os << from_utf8(fonts);
1773 if (fonts_default_family != "default")
1774 os << "\\renewcommand{\\familydefault}{\\"
1775 << from_ascii(fonts_default_family) << "}\n";
1777 // set font encoding
1778 // non-TeX fonts use font encoding TU (set by fontspec)
1779 if (!useNonTeXFonts && !features.isProvided("fontenc")
1780 && main_font_encoding() != "default") {
1781 // get main font encodings
1782 vector<string> fontencs = font_encodings();
1783 // get font encodings of secondary languages
1784 // FIXME: some languages (hebrew, ...) assume a standard font encoding as last
1785 // option (for text in other languages).
1786 features.getFontEncodings(fontencs);
1787 if (!fontencs.empty()) {
1788 os << "\\usepackage["
1789 << from_ascii(getStringFromVector(fontencs))
1794 // Load textcomp and pmboxdraw before (lua)inputenc (#11454)
1795 if (features.mustProvide("textcomp"))
1796 os << "\\usepackage{textcomp}\n";
1797 if (features.mustProvide("pmboxdraw"))
1798 os << "\\usepackage{pmboxdraw}\n";
1800 // handle inputenc etc.
1801 // (In documents containing text in Thai language,
1802 // we must load inputenc after babel, see lib/languages).
1803 if (!contains(features.getBabelPostsettings(), from_ascii("thai.ldf")))
1804 writeEncodingPreamble(os, features);
1807 if (!features.runparams().includeall && !included_children_.empty()) {
1808 os << "\\includeonly{";
1810 for (auto incfile : included_children_) {
1811 FileName inc = makeAbsPath(incfile, filepath.absFileName());
1812 string mangled = DocFileName(changeExtension(inc.absFileName(), ".tex")).
1814 if (!features.runparams().nice)
1816 // \includeonly doesn't want an extension
1817 incfile = changeExtension(incfile, string());
1818 incfile = support::latex_path(incfile);
1819 if (!incfile.empty()) {
1822 os << from_utf8(incfile);
1829 if (!features.isProvided("geometry")
1830 && (use_geometry || !class_supported_papersize)) {
1831 odocstringstream ods;
1832 if (!getGraphicsDriver("geometry").empty())
1833 ods << getGraphicsDriver("geometry");
1834 if (orientation == ORIENTATION_LANDSCAPE)
1835 ods << ",landscape";
1836 switch (papersize) {
1838 if (!paperwidth.empty())
1839 ods << ",paperwidth="
1840 << from_ascii(paperwidth);
1841 if (!paperheight.empty())
1842 ods << ",paperheight="
1843 << from_ascii(paperheight);
1845 case PAPER_USLETTER:
1847 case PAPER_USEXECUTIVE:
1876 ods << "," << from_ascii(string_papersize_geometry[papersize]);
1881 docstring g_options = trim(ods.str(), ",");
1882 os << "\\usepackage";
1883 // geometry-light means that the class works with geometry, but overwrites
1884 // the package options and paper sizes (memoir does this).
1885 // In this case, all options need to go to \geometry
1886 // and the standard paper sizes need to go to the class options.
1887 if (!g_options.empty() && !features.isProvided("geometry-light")) {
1888 os << '[' << g_options << ']';
1891 os << "{geometry}\n";
1892 if (use_geometry || features.isProvided("geometry-light")) {
1893 os << "\\geometry{verbose";
1894 if (!g_options.empty())
1895 // Output general options here with "geometry light".
1896 os << "," << g_options;
1897 // output this only if use_geometry is true
1899 if (!topmargin.empty())
1900 os << ",tmargin=" << from_ascii(Length(topmargin).asLatexString());
1901 if (!bottommargin.empty())
1902 os << ",bmargin=" << from_ascii(Length(bottommargin).asLatexString());
1903 if (!leftmargin.empty())
1904 os << ",lmargin=" << from_ascii(Length(leftmargin).asLatexString());
1905 if (!rightmargin.empty())
1906 os << ",rmargin=" << from_ascii(Length(rightmargin).asLatexString());
1907 if (!headheight.empty())
1908 os << ",headheight=" << from_ascii(Length(headheight).asLatexString());
1909 if (!headsep.empty())
1910 os << ",headsep=" << from_ascii(Length(headsep).asLatexString());
1911 if (!footskip.empty())
1912 os << ",footskip=" << from_ascii(Length(footskip).asLatexString());
1913 if (!columnsep.empty())
1914 os << ",columnsep=" << from_ascii(Length(columnsep).asLatexString());
1918 } else if (orientation == ORIENTATION_LANDSCAPE
1919 || papersize != PAPER_DEFAULT) {
1920 features.require("papersize");
1923 if (tokenPos(tclass.opt_pagestyle(), '|', pagestyle) >= 0) {
1924 if (pagestyle == "fancy")
1925 os << "\\usepackage{fancyhdr}\n";
1926 os << "\\pagestyle{" << from_ascii(pagestyle) << "}\n";
1929 // only output when the background color is not default
1930 if (isbackgroundcolor == true) {
1931 // only require color here, the background color will be defined
1932 // in LaTeXFeatures.cpp to avoid interferences with the LaTeX
1934 features.require("color");
1935 features.require("pagecolor");
1938 // only output when the font color is not default
1939 if (isfontcolor == true) {
1940 // only require color here, the font color will be defined
1941 // in LaTeXFeatures.cpp to avoid interferences with the LaTeX
1943 features.require("color");
1944 features.require("fontcolor");
1947 // Only if class has a ToC hierarchy
1948 if (tclass.hasTocLevels()) {
1949 if (secnumdepth != tclass.secnumdepth()) {
1950 os << "\\setcounter{secnumdepth}{"
1954 if (tocdepth != tclass.tocdepth()) {
1955 os << "\\setcounter{tocdepth}{"
1961 if (paragraph_separation) {
1962 // when skip separation
1963 switch (getDefSkip().kind()) {
1964 case VSpace::SMALLSKIP:
1965 os << "\\setlength{\\parskip}{\\smallskipamount}\n";
1967 case VSpace::MEDSKIP:
1968 os << "\\setlength{\\parskip}{\\medskipamount}\n";
1970 case VSpace::BIGSKIP:
1971 os << "\\setlength{\\parskip}{\\bigskipamount}\n";
1973 case VSpace::LENGTH:
1974 os << "\\setlength{\\parskip}{"
1975 << from_utf8(getDefSkip().length().asLatexString())
1978 default: // should never happen // Then delete it.
1979 os << "\\setlength{\\parskip}{\\medskipamount}\n";
1982 os << "\\setlength{\\parindent}{0pt}\n";
1984 // when separation by indentation
1985 // only output something when a width is given
1986 if (!getParIndent().empty()) {
1987 os << "\\setlength{\\parindent}{"
1988 << from_utf8(getParIndent().asLatexString())
1993 if (is_math_indent) {
1994 // when formula indentation
1995 // only output something when it is not the default
1996 if (!getMathIndent().empty()) {
1997 os << "\\setlength{\\mathindent}{"
1998 << from_utf8(getMathIndent().asString())
2003 // Now insert the LyX specific LaTeX commands...
2004 features.resolveAlternatives();
2005 features.expandMultiples();
2008 if (!output_sync_macro.empty())
2009 os << from_utf8(output_sync_macro) +"\n";
2010 else if (features.runparams().flavor == OutputParams::LATEX)
2011 os << "\\usepackage[active]{srcltx}\n";
2012 else if (features.runparams().flavor == OutputParams::PDFLATEX)
2013 os << "\\synctex=-1\n";
2016 // The package options (via \PassOptionsToPackage)
2017 os << from_ascii(features.getPackageOptions());
2019 // due to interferences with babel and hyperref, the color package has to
2020 // be loaded (when it is not already loaded) before babel when hyperref
2021 // is used with the colorlinks option, see
2022 // http://www.lyx.org/trac/ticket/5291
2023 // we decided therefore to load color always before babel, see
2024 // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg144349.html
2025 os << from_ascii(features.getColorOptions());
2027 // If we use hyperref, jurabib, japanese or varioref,
2028 // we have to call babel before
2030 && (features.isRequired("jurabib")
2031 || features.isRequired("hyperref")
2032 || features.isRequired("varioref")
2033 || features.isRequired("japanese"))) {
2034 os << features.getBabelPresettings();
2036 os << from_utf8(babelCall(language_options.str(),
2037 !lyxrc.language_global_options)) + '\n';
2038 os << features.getBabelPostsettings();
2041 // The optional packages;
2042 os << from_ascii(features.getPackages());
2044 // Additional Indices
2045 if (features.isRequired("splitidx")) {
2046 for (auto const & idx : indiceslist()) {
2047 os << "\\newindex{";
2048 os << escape(idx.shortcut());
2054 os << from_utf8(spacing().writePreamble(features.isProvided("SetSpace")));
2057 // * Hyperref manual: "Make sure it comes last of your loaded
2058 // packages, to give it a fighting chance of not being over-written,
2059 // since its job is to redefine many LaTeX commands."
2060 // * Email from Heiko Oberdiek: "It is usually better to load babel
2061 // before hyperref. Then hyperref has a chance to detect babel.
2062 // * Has to be loaded before the "LyX specific LaTeX commands" to
2063 // avoid errors with algorithm floats.
2064 // use hyperref explicitly if it is required
2065 if (features.isRequired("hyperref")) {
2066 OutputParams tmp_params = features.runparams();
2067 pdfoptions().writeLaTeX(tmp_params, os,
2068 features.isProvided("hyperref"));
2069 // correctly break URLs with hyperref and dvi/ps output
2070 if (features.runparams().hyperref_driver == "dvips"
2071 && features.isAvailable("breakurl"))
2072 os << "\\usepackage{breakurl}\n";
2073 } else if (features.isRequired("nameref"))
2074 // hyperref loads this automatically
2075 os << "\\usepackage{nameref}\n";
2078 os << "\\usepackage";
2079 if (!lineno_opts.empty())
2080 os << "[" << lineno_opts << "]";
2082 os << "\\linenumbers\n";
2085 // bibtopic needs to be loaded after hyperref.
2086 // the dot provides the aux file naming which LyX can detect.
2087 if (features.mustProvide("bibtopic"))
2088 os << "\\usepackage[dot]{bibtopic}\n";
2090 // Will be surrounded by \makeatletter and \makeatother when not empty
2091 otexstringstream atlyxpreamble;
2093 // Some macros LyX will need
2095 TexString tmppreamble = features.getMacros();
2096 if (!tmppreamble.str.empty())
2097 atlyxpreamble << "\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
2098 "LyX specific LaTeX commands.\n"
2099 << move(tmppreamble)
2102 // the text class specific preamble
2104 docstring tmppreamble = features.getTClassPreamble();
2105 if (!tmppreamble.empty())
2106 atlyxpreamble << "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
2107 "Textclass specific LaTeX commands.\n"
2111 // suppress date if selected
2112 // use \@ifundefined because we cannot be sure that every document class
2113 // has a \date command
2115 atlyxpreamble << "\\@ifundefined{date}{}{\\date{}}\n";
2117 /* the user-defined preamble */
2118 if (!containsOnly(preamble, " \n\t")) {
2120 atlyxpreamble << "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
2121 "User specified LaTeX commands.\n";
2123 // Check if the user preamble contains uncodable glyphs
2124 odocstringstream user_preamble;
2125 docstring uncodable_glyphs;
2126 Encoding const * const enc = features.runparams().encoding;
2128 for (size_t n = 0; n < preamble.size(); ++n) {
2129 char_type c = preamble[n];
2130 if (!enc->encodable(c)) {
2131 docstring const glyph(1, c);
2132 LYXERR0("Uncodable character '"
2134 << "' in user preamble!");
2135 uncodable_glyphs += glyph;
2136 if (features.runparams().dryrun) {
2137 user_preamble << "<" << _("LyX Warning: ")
2138 << _("uncodable character") << " '";
2139 user_preamble.put(c);
2140 user_preamble << "'>";
2143 user_preamble.put(c);
2146 user_preamble << preamble;
2148 // On BUFFER_VIEW|UPDATE, warn user if we found uncodable glyphs
2149 if (!features.runparams().dryrun && !uncodable_glyphs.empty()) {
2150 frontend::Alert::warning(
2151 _("Uncodable character in user preamble"),
2153 _("The user preamble of your document contains glyphs "
2154 "that are unknown in the current document encoding "
2155 "(namely %1$s).\nThese glyphs are omitted "
2156 " from the output, which may result in "
2157 "incomplete output."
2158 "\n\nPlease select an appropriate "
2159 "document encoding\n"
2160 "(such as utf8) or change the "
2161 "preamble code accordingly."),
2164 atlyxpreamble << user_preamble.str() << '\n';
2167 // footmisc must be loaded after setspace
2168 // Load it here to avoid clashes with footmisc loaded in the user
2169 // preamble. For that reason we also pass the options via
2170 // \PassOptionsToPackage in getPreamble() and not here.
2171 if (features.mustProvide("footmisc"))
2172 atlyxpreamble << "\\usepackage{footmisc}\n";
2174 // subfig loads internally the LaTeX package "caption". As
2175 // caption is a very popular package, users will load it in
2176 // the preamble. Therefore we must load subfig behind the
2177 // user-defined preamble and check if the caption package was
2178 // loaded or not. For the case that caption is loaded before
2179 // subfig, there is the subfig option "caption=false". This
2180 // option also works when a koma-script class is used and
2181 // koma's own caption commands are used instead of caption. We
2182 // use \PassOptionsToPackage here because the user could have
2183 // already loaded subfig in the preamble.
2184 if (features.mustProvide("subfig"))
2185 atlyxpreamble << "\\@ifundefined{showcaptionsetup}{}{%\n"
2186 " \\PassOptionsToPackage{caption=false}{subfig}}\n"
2187 "\\usepackage{subfig}\n";
2189 // Itemize bullet settings need to be last in case the user
2190 // defines their own bullets that use a package included
2191 // in the user-defined preamble -- ARRae
2192 // Actually it has to be done much later than that
2193 // since some packages like frenchb make modifications
2194 // at \begin{document} time -- JMarc
2195 docstring bullets_def;
2196 for (int i = 0; i < 4; ++i) {
2197 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
2198 if (bullets_def.empty())
2199 bullets_def += "\\AtBeginDocument{\n";
2200 bullets_def += " \\def\\labelitemi";
2202 // `i' is one less than the item to modify
2209 bullets_def += "ii";
2215 bullets_def += '{' +
2216 user_defined_bullet(i).getText()
2221 if (!bullets_def.empty())
2222 atlyxpreamble << bullets_def << "}\n\n";
2224 if (!atlyxpreamble.empty())
2225 os << "\n\\makeatletter\n"
2226 << atlyxpreamble.release()
2227 << "\\makeatother\n\n";
2229 // We try to load babel late, in case it interferes with other packages.
2230 // Jurabib, hyperref, varioref, bicaption, menukeys and listings (bug 8995)
2231 // have to be called after babel, though.
2232 if (use_babel && !features.isRequired("jurabib")
2233 && !features.isRequired("hyperref")
2234 && !features.isRequired("varioref")
2235 && !features.isRequired("japanese")) {
2236 os << features.getBabelPresettings();
2238 os << from_utf8(babelCall(language_options.str(),
2239 !lyxrc.language_global_options)) + '\n';
2240 os << features.getBabelPostsettings();
2242 // In documents containing text in Thai language,
2243 // we must load inputenc after babel (see lib/languages).
2244 if (contains(features.getBabelPostsettings(), from_ascii("thai.ldf")))
2245 writeEncodingPreamble(os, features);
2247 // font selection must be done after babel with non-TeX fonts
2248 if (!fonts.empty() && features.useBabel() && useNonTeXFonts)
2249 os << from_utf8(fonts);
2251 if (features.isRequired("bicaption"))
2252 os << "\\usepackage{bicaption}\n";
2253 if (!listings_params.empty()
2254 || features.mustProvide("listings")
2255 || features.mustProvide("minted")) {
2257 os << "\\usepackage{minted}\n";
2259 os << "\\usepackage{listings}\n";
2261 string lst_params = listings_params;
2262 // If minted, do not output the language option (bug 11203)
2263 if (use_minted && contains(lst_params, "language=")) {
2264 vector<string> opts =
2265 getVectorFromString(lst_params, ",", false);
2266 for (size_t i = 0; i < opts.size(); ++i) {
2267 if (prefixIs(opts[i], "language="))
2268 opts.erase(opts.begin() + i--);
2270 lst_params = getStringFromVector(opts, ",");
2272 if (!lst_params.empty()) {
2274 os << "\\setminted{";
2277 // do not test validity because listings_params is
2278 // supposed to be valid
2280 InsetListingsParams(lst_params).separatedParams(true);
2281 os << from_utf8(par);
2285 // xunicode only needs to be loaded if tipa is used
2286 // (the rest is obsoleted by the new TU encoding).
2287 // It needs to be loaded at least after amsmath, amssymb,
2288 // esint and the other packages that provide special glyphs
2289 if (features.mustProvide("tipa") && useNonTeXFonts
2290 && !features.isProvided("xunicode")) {
2291 // The `xunicode` package officially only supports XeTeX,
2292 // but also works with LuaTeX. We work around its XeTeX test.
2293 if (features.runparams().flavor != OutputParams::XETEX) {
2294 os << "% Pretend to xunicode that we are XeTeX\n"
2295 << "\\def\\XeTeXpicfile{}\n";
2297 os << "\\usepackage{xunicode}\n";
2300 // covington must be loaded after beamerarticle
2301 if (features.isRequired("covington"))
2302 os << "\\usepackage{covington}\n";
2304 // Polyglossia must be loaded last ...
2305 if (use_polyglossia) {
2307 os << "\\usepackage{polyglossia}\n";
2308 // set the main language
2309 os << "\\setdefaultlanguage";
2310 if (!language->polyglossiaOpts().empty())
2311 os << "[" << from_ascii(language->polyglossiaOpts()) << "]";
2312 os << "{" << from_ascii(language->polyglossia()) << "}\n";
2313 // now setup the other languages
2314 set<string> const polylangs =
2315 features.getPolyglossiaLanguages();
2316 for (auto const & pl : polylangs) {
2317 // We do not output the options here; they are output in
2318 // the language switch commands. This is safer if multiple
2319 // varieties are used.
2320 if (pl == language->polyglossia())
2322 os << "\\setotherlanguage";
2323 os << "{" << from_ascii(pl) << "}\n";
2327 // ... but before biblatex (see #7065)
2328 if ((features.mustProvide("biblatex")
2329 || features.isRequired("biblatex-chicago"))
2330 && !features.isProvided("biblatex-chicago")
2331 && !features.isProvided("biblatex-natbib")
2332 && !features.isProvided("natbib-internal")
2333 && !features.isProvided("natbib")
2334 && !features.isProvided("jurabib")) {
2335 // The biblatex-chicago package has a differing interface
2336 // it uses a wrapper package and loads styles via fixed options
2337 bool const chicago = features.isRequired("biblatex-chicago");
2340 os << "\\usepackage";
2341 if (!biblatex_bibstyle.empty()
2342 && (biblatex_bibstyle == biblatex_citestyle)
2344 opts = "style=" + biblatex_bibstyle;
2346 } else if (!chicago) {
2347 if (!biblatex_bibstyle.empty()) {
2348 opts = "bibstyle=" + biblatex_bibstyle;
2351 if (!biblatex_citestyle.empty()) {
2352 opts += delim + "citestyle=" + biblatex_citestyle;
2356 if (!multibib.empty() && multibib != "child") {
2357 opts += delim + "refsection=" + multibib;
2360 if (bibtexCommand() == "bibtex8"
2361 || prefixIs(bibtexCommand(), "bibtex8 ")) {
2362 opts += delim + "backend=bibtex8";
2364 } else if (bibtexCommand() == "bibtex"
2365 || prefixIs(bibtexCommand(), "bibtex ")) {
2366 opts += delim + "backend=bibtex";
2369 if (!bib_encoding.empty() && encodings.fromLyXName(bib_encoding)) {
2370 opts += delim + "bibencoding="
2371 + encodings.fromLyXName(bib_encoding)->latexName();
2374 if (!biblio_opts.empty())
2375 opts += delim + biblio_opts;
2377 os << "[" << opts << "]";
2379 os << "{biblatex-chicago}\n";
2381 os << "{biblatex}\n";
2385 // Load custom language package here
2386 if (features.langPackage() == LaTeXFeatures::LANG_PACK_CUSTOM) {
2387 if (lang_package == "default")
2388 os << from_utf8(lyxrc.language_custom_package);
2390 os << from_utf8(lang_package);
2394 // Since menukeys uses catoptions, which does some heavy changes on key-value options,
2395 // it is recommended to load menukeys as the last package (even after hyperref)
2396 if (features.isRequired("menukeys"))
2397 os << "\\usepackage{menukeys}\n";
2399 docstring const i18npreamble =
2400 features.getTClassI18nPreamble(use_babel, use_polyglossia,
2402 if (!i18npreamble.empty())
2403 os << i18npreamble + '\n';
2409 void BufferParams::useClassDefaults()
2411 DocumentClass const & tclass = documentClass();
2413 sides = tclass.sides();
2414 columns = tclass.columns();
2415 pagestyle = tclass.pagestyle();
2416 tablestyle = tclass.tablestyle();
2417 use_default_options = true;
2418 // Only if class has a ToC hierarchy
2419 if (tclass.hasTocLevels()) {
2420 secnumdepth = tclass.secnumdepth();
2421 tocdepth = tclass.tocdepth();
2426 bool BufferParams::hasClassDefaults() const
2428 DocumentClass const & tclass = documentClass();
2430 return sides == tclass.sides()
2431 && columns == tclass.columns()
2432 && pagestyle == tclass.pagestyle()
2433 && tablestyle == tclass.tablestyle()
2434 && use_default_options
2435 && secnumdepth == tclass.secnumdepth()
2436 && tocdepth == tclass.tocdepth();
2440 DocumentClass const & BufferParams::documentClass() const
2446 DocumentClassConstPtr BufferParams::documentClassPtr() const
2452 void BufferParams::setDocumentClass(DocumentClassConstPtr tc)
2454 // evil, but this function is evil
2455 doc_class_ = const_pointer_cast<DocumentClass>(tc);
2456 invalidateConverterCache();
2460 bool BufferParams::setBaseClass(string const & classname, string const & path)
2462 LYXERR(Debug::TCLASS, "setBaseClass: " << classname);
2463 LayoutFileList & bcl = LayoutFileList::get();
2464 if (!bcl.haveClass(classname)) {
2466 bformat(_("The layout file:\n"
2468 "could not be found. A default textclass with default\n"
2469 "layouts will be used. LyX will not be able to produce\n"
2471 from_utf8(classname));
2472 frontend::Alert::error(_("Document class not found"), s);
2473 bcl.addEmptyClass(classname);
2476 bool const success = bcl[classname].load(path);
2479 bformat(_("Due to some error in it, the layout file:\n"
2481 "could not be loaded. A default textclass with default\n"
2482 "layouts will be used. LyX will not be able to produce\n"
2484 from_utf8(classname));
2485 frontend::Alert::error(_("Could not load class"), s);
2486 bcl.addEmptyClass(classname);
2489 pimpl_->baseClass_ = classname;
2490 layout_modules_.adaptToBaseClass(baseClass(), removed_modules_);
2495 LayoutFile const * BufferParams::baseClass() const
2497 if (LayoutFileList::get().haveClass(pimpl_->baseClass_))
2498 return &(LayoutFileList::get()[pimpl_->baseClass_]);
2504 LayoutFileIndex const & BufferParams::baseClassID() const
2506 return pimpl_->baseClass_;
2510 void BufferParams::makeDocumentClass(bool const clone)
2515 invalidateConverterCache();
2516 LayoutModuleList mods;
2517 for (auto const & mod : layout_modules_)
2518 mods.push_back(mod);
2520 doc_class_ = getDocumentClass(*baseClass(), mods, cite_engine_, clone);
2522 TextClass::ReturnValues success = TextClass::OK;
2523 if (!forced_local_layout_.empty())
2524 success = doc_class_->read(to_utf8(forced_local_layout_),
2526 if (!local_layout_.empty() &&
2527 (success == TextClass::OK || success == TextClass::OK_OLDFORMAT))
2528 success = doc_class_->read(to_utf8(local_layout_), TextClass::MODULE);
2529 if (success != TextClass::OK && success != TextClass::OK_OLDFORMAT) {
2530 docstring const msg = _("Error reading internal layout information");
2531 frontend::Alert::warning(_("Read Error"), msg);
2536 bool BufferParams::layoutModuleCanBeAdded(string const & modName) const
2538 return layout_modules_.moduleCanBeAdded(modName, baseClass());
2542 docstring BufferParams::getLocalLayout(bool forced) const
2545 return from_utf8(doc_class_->forcedLayouts());
2547 return local_layout_;
2551 void BufferParams::setLocalLayout(docstring const & layout, bool forced)
2554 forced_local_layout_ = layout;
2556 local_layout_ = layout;
2560 bool BufferParams::addLayoutModule(string const & modName)
2562 for (auto const & mod : layout_modules_)
2565 layout_modules_.push_back(modName);
2570 string BufferParams::bufferFormat() const
2572 return documentClass().outputFormat();
2576 bool BufferParams::isExportable(string const & format, bool need_viewable) const
2578 FormatList const & formats = exportableFormats(need_viewable);
2579 for (auto const & fmt : formats) {
2580 if (fmt->name() == format)
2587 FormatList const & BufferParams::exportableFormats(bool only_viewable) const
2589 FormatList & cached = only_viewable ?
2590 pimpl_->viewableFormatList : pimpl_->exportableFormatList;
2591 bool & valid = only_viewable ?
2592 pimpl_->isViewCacheValid : pimpl_->isExportCacheValid;
2596 vector<string> const backs = backends();
2597 set<string> excludes;
2598 if (useNonTeXFonts) {
2599 excludes.insert("latex");
2600 excludes.insert("pdflatex");
2601 } else if (inputenc != "ascii" && inputenc != "utf8-plain")
2602 // XeTeX with TeX fonts requires input encoding ascii (#10600).
2603 excludes.insert("xetex");
2604 FormatList result = theConverters().getReachable(backs[0], only_viewable,
2606 vector<string>::const_iterator it = backs.begin() + 1;
2607 for (; it != backs.end(); ++it) {
2608 FormatList r = theConverters().getReachable(*it, only_viewable,
2610 result.insert(result.end(), r.begin(), r.end());
2612 sort(result.begin(), result.end(), Format::formatSorter);
2619 vector<string> BufferParams::backends() const
2622 string const buffmt = bufferFormat();
2624 // FIXME: Don't hardcode format names here, but use a flag
2625 if (buffmt == "latex") {
2626 if (encoding().package() == Encoding::japanese)
2627 v.push_back("platex");
2629 if (!useNonTeXFonts) {
2630 v.push_back("pdflatex");
2631 v.push_back("latex");
2634 || inputenc == "ascii" || inputenc == "utf8-plain")
2635 v.push_back("xetex");
2636 v.push_back("luatex");
2637 v.push_back("dviluatex");
2640 string rbuffmt = buffmt;
2641 // If we use an OutputFormat in Japanese docs,
2642 // we need special format in order to get the path
2643 // via pLaTeX (#8823)
2644 if (documentClass().hasOutputFormat()
2645 && encoding().package() == Encoding::japanese)
2647 v.push_back(rbuffmt);
2650 v.push_back("xhtml");
2651 v.push_back("text");
2657 OutputParams::FLAVOR BufferParams::getOutputFlavor(string const & format) const
2659 string const dformat = (format.empty() || format == "default") ?
2660 getDefaultOutputFormat() : format;
2661 DefaultFlavorCache::const_iterator it =
2662 default_flavors_.find(dformat);
2664 if (it != default_flavors_.end())
2667 OutputParams::FLAVOR result = OutputParams::LATEX;
2669 // FIXME It'd be better not to hardcode this, but to do
2670 // something with formats.
2671 if (dformat == "xhtml")
2672 result = OutputParams::HTML;
2673 else if (dformat == "text")
2674 result = OutputParams::TEXT;
2675 else if (dformat == "lyx")
2676 result = OutputParams::LYX;
2677 else if (dformat == "pdflatex")
2678 result = OutputParams::PDFLATEX;
2679 else if (dformat == "xetex")
2680 result = OutputParams::XETEX;
2681 else if (dformat == "luatex")
2682 result = OutputParams::LUATEX;
2683 else if (dformat == "dviluatex")
2684 result = OutputParams::DVILUATEX;
2686 // Try to determine flavor of default output format
2687 vector<string> backs = backends();
2688 if (find(backs.begin(), backs.end(), dformat) == backs.end()) {
2689 // Get shortest path to format
2690 Graph::EdgePath path;
2691 for (auto const & bvar : backs) {
2692 Graph::EdgePath p = theConverters().getPath(bvar, dformat);
2693 if (!p.empty() && (path.empty() || p.size() < path.size())) {
2698 result = theConverters().getFlavor(path);
2701 // cache this flavor
2702 default_flavors_[dformat] = result;
2707 string BufferParams::getDefaultOutputFormat() const
2709 if (!default_output_format.empty()
2710 && default_output_format != "default")
2711 return default_output_format;
2713 FormatList const & formats = exportableFormats(true);
2714 if (formats.empty())
2716 // return the first we find
2717 return formats.front()->name();
2719 if (encoding().package() == Encoding::japanese)
2720 return lyxrc.default_platex_view_format;
2722 return lyxrc.default_otf_view_format;
2723 return lyxrc.default_view_format;
2726 Font const BufferParams::getFont() const
2728 FontInfo f = documentClass().defaultfont();
2729 if (fonts_default_family == "rmdefault")
2730 f.setFamily(ROMAN_FAMILY);
2731 else if (fonts_default_family == "sfdefault")
2732 f.setFamily(SANS_FAMILY);
2733 else if (fonts_default_family == "ttdefault")
2734 f.setFamily(TYPEWRITER_FAMILY);
2735 return Font(f, language);
2739 InsetQuotesParams::QuoteStyle BufferParams::getQuoteStyle(string const & qs) const
2741 return quotesstyletranslator().find(qs);
2745 bool BufferParams::isLatex() const
2747 return documentClass().outputType() == LATEX;
2751 bool BufferParams::isLiterate() const
2753 return documentClass().outputType() == LITERATE;
2757 bool BufferParams::isDocBook() const
2759 return documentClass().outputType() == DOCBOOK;
2763 void BufferParams::readPreamble(Lexer & lex)
2765 if (lex.getString() != "\\begin_preamble")
2766 lyxerr << "Error (BufferParams::readPreamble):"
2767 "consistency check failed." << endl;
2769 preamble = lex.getLongString(from_ascii("\\end_preamble"));
2773 void BufferParams::readLocalLayout(Lexer & lex, bool forced)
2775 string const expected = forced ? "\\begin_forced_local_layout" :
2776 "\\begin_local_layout";
2777 if (lex.getString() != expected)
2778 lyxerr << "Error (BufferParams::readLocalLayout):"
2779 "consistency check failed." << endl;
2782 forced_local_layout_ =
2783 lex.getLongString(from_ascii("\\end_forced_local_layout"));
2785 local_layout_ = lex.getLongString(from_ascii("\\end_local_layout"));
2789 bool BufferParams::setLanguage(string const & lang)
2791 Language const *new_language = languages.getLanguage(lang);
2792 if (!new_language) {
2793 // Language lang was not found
2796 language = new_language;
2801 void BufferParams::readLanguage(Lexer & lex)
2803 if (!lex.next()) return;
2805 string const tmptok = lex.getString();
2807 // check if tmptok is part of tex_babel in tex-defs.h
2808 if (!setLanguage(tmptok)) {
2809 // Language tmptok was not found
2810 language = default_language;
2811 lyxerr << "Warning: Setting language `"
2812 << tmptok << "' to `" << language->lang()
2818 void BufferParams::readGraphicsDriver(Lexer & lex)
2823 string const tmptok = lex.getString();
2824 // check if tmptok is part of tex_graphics in tex_defs.h
2827 string const test = tex_graphics[n++];
2829 if (test == tmptok) {
2830 graphics_driver = tmptok;
2835 "Warning: graphics driver `$$Token' not recognized!\n"
2836 " Setting graphics driver to `default'.\n");
2837 graphics_driver = "default";
2844 void BufferParams::readBullets(Lexer & lex)
2849 int const index = lex.getInteger();
2851 int temp_int = lex.getInteger();
2852 user_defined_bullet(index).setFont(temp_int);
2853 temp_bullet(index).setFont(temp_int);
2855 user_defined_bullet(index).setCharacter(temp_int);
2856 temp_bullet(index).setCharacter(temp_int);
2858 user_defined_bullet(index).setSize(temp_int);
2859 temp_bullet(index).setSize(temp_int);
2863 void BufferParams::readBulletsLaTeX(Lexer & lex)
2865 // The bullet class should be able to read this.
2868 int const index = lex.getInteger();
2870 docstring const temp_str = lex.getDocString();
2872 user_defined_bullet(index).setText(temp_str);
2873 temp_bullet(index).setText(temp_str);
2877 void BufferParams::readModules(Lexer & lex)
2879 if (!lex.eatLine()) {
2880 lyxerr << "Error (BufferParams::readModules):"
2881 "Unexpected end of input." << endl;
2885 string mod = lex.getString();
2886 if (mod == "\\end_modules")
2888 addLayoutModule(mod);
2894 void BufferParams::readRemovedModules(Lexer & lex)
2896 if (!lex.eatLine()) {
2897 lyxerr << "Error (BufferParams::readRemovedModules):"
2898 "Unexpected end of input." << endl;
2902 string mod = lex.getString();
2903 if (mod == "\\end_removed_modules")
2905 removed_modules_.push_back(mod);
2908 // now we want to remove any removed modules that were previously
2909 // added. normally, that will be because default modules were added in
2910 // setBaseClass(), which gets called when \textclass is read at the
2911 // start of the read.
2912 for (auto const & rm : removed_modules_) {
2913 LayoutModuleList::iterator const mit = layout_modules_.begin();
2914 LayoutModuleList::iterator const men = layout_modules_.end();
2915 LayoutModuleList::iterator found = find(mit, men, rm);
2918 layout_modules_.erase(found);
2923 void BufferParams::readIncludeonly(Lexer & lex)
2925 if (!lex.eatLine()) {
2926 lyxerr << "Error (BufferParams::readIncludeonly):"
2927 "Unexpected end of input." << endl;
2931 string child = lex.getString();
2932 if (child == "\\end_includeonly")
2934 included_children_.push_back(child);
2940 string BufferParams::paperSizeName(PapersizePurpose purpose, string const & psize) const
2942 PAPER_SIZE ppsize = psize.empty() ? papersize : papersizetranslator().find(psize);
2945 if (documentClass().pagesize() == "default")
2946 // could be anything, so don't guess
2948 return paperSizeName(purpose, documentClass().pagesize());
2949 case PAPER_CUSTOM: {
2950 if (purpose == XDVI && !paperwidth.empty() &&
2951 !paperheight.empty()) {
2952 // heightxwidth<unit>
2953 string first = paperwidth;
2954 string second = paperheight;
2955 if (orientation == ORIENTATION_LANDSCAPE)
2958 return first.erase(first.length() - 2)
2964 // dvips and dvipdfm do not know this
2965 if (purpose == DVIPS || purpose == DVIPDFM)
2969 if (purpose == DVIPS || purpose == DVIPDFM)
2973 if (purpose == DVIPS || purpose == DVIPDFM)
2983 if (purpose == DVIPS || purpose == DVIPDFM)
2987 if (purpose == DVIPS || purpose == DVIPDFM)
2991 if (purpose == DVIPS || purpose == DVIPDFM)
2995 if (purpose == DVIPS || purpose == DVIPDFM)
2999 if (purpose == DVIPS || purpose == DVIPDFM)
3003 // dvipdfm does not know this
3004 if (purpose == DVIPDFM)
3008 if (purpose == DVIPDFM)
3012 if (purpose == DVIPS || purpose == DVIPDFM)
3016 if (purpose == DVIPS || purpose == DVIPDFM)
3020 if (purpose == DVIPS || purpose == DVIPDFM)
3024 if (purpose == DVIPS || purpose == DVIPDFM)
3028 if (purpose == DVIPS || purpose == DVIPDFM)
3032 if (purpose == DVIPS || purpose == DVIPDFM)
3036 if (purpose == DVIPS || purpose == DVIPDFM)
3040 if (purpose == DVIPS || purpose == DVIPDFM)
3044 if (purpose == DVIPS || purpose == DVIPDFM)
3048 if (purpose == DVIPS || purpose == DVIPDFM)
3052 if (purpose == DVIPS || 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)
3071 case PAPER_USEXECUTIVE:
3072 // dvipdfm does not know this
3073 if (purpose == DVIPDFM)
3078 case PAPER_USLETTER:
3080 if (purpose == XDVI)
3087 string const BufferParams::dvips_options() const
3091 // If the class loads the geometry package, we do not know which
3092 // paper size is used, since we do not set it (bug 7013).
3093 // Therefore we must not specify any argument here.
3094 // dvips gets the correct paper size via DVI specials in this case
3095 // (if the class uses the geometry package correctly).
3096 if (documentClass().provides("geometry"))
3100 && papersize == PAPER_CUSTOM
3101 && !lyxrc.print_paper_dimension_flag.empty()
3102 && !paperwidth.empty()
3103 && !paperheight.empty()) {
3104 // using a custom papersize
3105 result = lyxrc.print_paper_dimension_flag;
3106 result += ' ' + paperwidth;
3107 result += ',' + paperheight;
3109 string const paper_option = paperSizeName(DVIPS);
3110 if (!paper_option.empty() && (paper_option != "letter" ||
3111 orientation != ORIENTATION_LANDSCAPE)) {
3112 // dvips won't accept -t letter -t landscape.
3113 // In all other cases, include the paper size
3115 result = lyxrc.print_paper_flag;
3116 result += ' ' + paper_option;
3119 if (orientation == ORIENTATION_LANDSCAPE &&
3120 papersize != PAPER_CUSTOM)
3121 result += ' ' + lyxrc.print_landscape_flag;
3126 string const BufferParams::main_font_encoding() const
3128 if (font_encodings().empty()) {
3129 if (ascii_lowercase(language->fontenc(*this)) == "none")
3133 return font_encodings().back();
3137 vector<string> const BufferParams::font_encodings() const
3139 string doc_fontenc = (fontenc == "auto") ? string() : fontenc;
3141 vector<string> fontencs;
3143 // "default" means "no explicit font encoding"
3144 if (doc_fontenc != "default") {
3145 if (!doc_fontenc.empty())
3146 // If we have a custom setting, we use only that!
3147 return getVectorFromString(doc_fontenc);
3148 if (!language->fontenc(*this).empty()
3149 && ascii_lowercase(language->fontenc(*this)) != "none") {
3150 vector<string> fencs = getVectorFromString(language->fontenc(*this));
3151 for (auto & fe : fencs) {
3152 if (find(fontencs.begin(), fontencs.end(), fe) == fontencs.end())
3153 fontencs.push_back(fe);
3162 string BufferParams::babelCall(string const & lang_opts, bool const langoptions) const
3164 // suppress the babel call if there is no BabelName defined
3165 // for the document language in the lib/languages file and if no
3166 // other languages are used (lang_opts is then empty)
3167 if (lang_opts.empty())
3169 // The prefs may require the languages to
3170 // be submitted to babel itself (not the class).
3172 return "\\usepackage[" + lang_opts + "]{babel}";
3173 return "\\usepackage{babel}";
3177 docstring BufferParams::getGraphicsDriver(string const & package) const
3181 if (package == "geometry") {
3182 if (graphics_driver == "dvips"
3183 || graphics_driver == "dvipdfm"
3184 || graphics_driver == "pdftex"
3185 || graphics_driver == "vtex")
3186 result = from_ascii(graphics_driver);
3187 else if (graphics_driver == "dvipdfmx")
3188 result = from_ascii("dvipdfm");
3195 void BufferParams::writeEncodingPreamble(otexstream & os,
3196 LaTeXFeatures & features) const
3198 // With no-TeX fonts we use utf8-plain without encoding package.
3202 if (inputenc == "auto-legacy") {
3203 string const doc_encoding =
3204 language->encoding()->latexName();
3205 Encoding::Package const package =
3206 language->encoding()->package();
3208 // Create list of inputenc options:
3209 set<string> encoding_set;
3210 // luainputenc fails with more than one encoding
3211 if (features.runparams().flavor != OutputParams::LUATEX
3212 && features.runparams().flavor != OutputParams::DVILUATEX)
3213 // list all input encodings used in the document
3214 encoding_set = features.getEncodingSet(doc_encoding);
3216 // The "japanese" babel-language requires the pLaTeX engine
3217 // which conflicts with "inputenc".
3218 // See http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129680.html
3219 if ((!encoding_set.empty() || package == Encoding::inputenc)
3220 && !features.isRequired("japanese")
3221 && !features.isProvided("inputenc")) {
3222 os << "\\usepackage[";
3223 set<string>::const_iterator it = encoding_set.begin();
3224 set<string>::const_iterator const end = encoding_set.end();
3226 os << from_ascii(*it);
3229 for (; it != end; ++it)
3230 os << ',' << from_ascii(*it);
3231 if (package == Encoding::inputenc) {
3232 if (!encoding_set.empty())
3234 os << from_ascii(doc_encoding);
3236 if (features.runparams().flavor == OutputParams::LUATEX
3237 || features.runparams().flavor == OutputParams::DVILUATEX)
3238 os << "]{luainputenc}\n";
3240 os << "]{inputenc}\n";
3242 } else if (inputenc != "auto-legacy-plain") {
3243 switch (encoding().package()) {
3244 case Encoding::none:
3246 case Encoding::japanese:
3247 if (encoding().iconvName() != "UTF-8"
3248 && !features.runparams().isFullUnicode())
3249 // don't default to [utf8]{inputenc} with TeXLive >= 18
3250 os << "\\ifdefined\\UseRawInputEncoding\n"
3251 << " \\UseRawInputEncoding\\fi\n";
3253 case Encoding::inputenc:
3254 // do not load inputenc if japanese is used
3255 // or if the class provides inputenc
3256 if (features.isRequired("japanese")
3257 || features.isProvided("inputenc"))
3259 os << "\\usepackage[" << from_ascii(encoding().latexName());
3260 if (features.runparams().flavor == OutputParams::LUATEX
3261 || features.runparams().flavor == OutputParams::DVILUATEX)
3262 os << "]{luainputenc}\n";
3264 os << "]{inputenc}\n";
3268 if (inputenc == "auto-legacy-plain" || features.isRequired("japanese")) {
3269 // don't default to [utf8]{inputenc} with TeXLive >= 18
3270 os << "\\ifdefined\\UseRawInputEncoding\n";
3271 os << " \\UseRawInputEncoding\\fi\n";
3276 string const BufferParams::parseFontName(string const & name) const
3278 string mangled = name;
3279 size_t const idx = mangled.find('[');
3280 if (idx == string::npos || idx == 0)
3283 return mangled.substr(0, idx - 1);
3287 string const BufferParams::loadFonts(LaTeXFeatures & features) const
3289 if (fontsRoman() == "default" && fontsSans() == "default"
3290 && fontsTypewriter() == "default"
3291 && (fontsMath() == "default" || fontsMath() == "auto"))
3297 /* Fontspec (XeTeX, LuaTeX): we provide GUI support for oldstyle
3298 * numbers (Numbers=OldStyle) and sf/tt scaling. The Ligatures=TeX/
3299 * Mapping=tex-text option assures TeX ligatures (such as "--")
3300 * are resolved. Note that tt does not use these ligatures.
3302 * -- add more GUI options?
3303 * -- add more fonts (fonts for other scripts)
3304 * -- if there's a way to find out if a font really supports
3305 * OldStyle, enable/disable the widget accordingly.
3307 if (useNonTeXFonts && features.isAvailable("fontspec")) {
3308 // "Mapping=tex-text" and "Ligatures=TeX" are equivalent.
3309 // However, until v.2 (2010/07/11) fontspec only knew
3310 // Mapping=tex-text (for XeTeX only); then "Ligatures=TeX"
3311 // was introduced for both XeTeX and LuaTeX (LuaTeX
3312 // didn't understand "Mapping=tex-text", while XeTeX
3313 // understood both. With most recent versions, both
3314 // variants are understood by both engines. However,
3315 // we want to provide support for at least TeXLive 2009
3316 // (for XeTeX; LuaTeX is only supported as of v.2)
3317 // As of 2017/11/03, Babel has its own higher-level
3318 // interface on top of fontspec that is to be used.
3319 bool const babelfonts = features.useBabel()
3320 && features.isAvailable("babel-2017/11/03");
3321 string const texmapping =
3322 (features.runparams().flavor == OutputParams::XETEX) ?
3323 "Mapping=tex-text" : "Ligatures=TeX";
3324 if (fontsRoman() != "default") {
3326 os << "\\babelfont{rm}[";
3328 os << "\\setmainfont[";
3329 if (!font_roman_opts.empty())
3330 os << font_roman_opts << ',';
3332 if (fonts_roman_osf)
3333 os << ",Numbers=OldStyle";
3334 os << "]{" << parseFontName(fontsRoman()) << "}\n";
3336 if (fontsSans() != "default") {
3337 string const sans = parseFontName(fontsSans());
3338 if (fontsSansScale() != 100) {
3340 os << "\\babelfont{sf}";
3342 os << "\\setsansfont";
3344 << float(fontsSansScale()) / 100 << ',';
3346 os << "Numbers=OldStyle,";
3347 if (!font_sans_opts.empty())
3348 os << font_sans_opts << ',';
3349 os << texmapping << "]{"
3353 os << "\\babelfont{sf}[";
3355 os << "\\setsansfont[";
3357 os << "Numbers=OldStyle,";
3358 if (!font_sans_opts.empty())
3359 os << font_sans_opts << ',';
3360 os << texmapping << "]{"
3364 if (fontsTypewriter() != "default") {
3365 string const mono = parseFontName(fontsTypewriter());
3366 if (fontsTypewriterScale() != 100) {
3368 os << "\\babelfont{tt}";
3370 os << "\\setmonofont";
3372 << float(fontsTypewriterScale()) / 100;
3373 if (fonts_typewriter_osf)
3374 os << ",Numbers=OldStyle";
3375 if (!font_typewriter_opts.empty())
3376 os << ',' << font_typewriter_opts;
3381 os << "\\babelfont{tt}";
3383 os << "\\setmonofont";
3384 if (!font_typewriter_opts.empty() || fonts_typewriter_osf) {
3386 if (fonts_typewriter_osf)
3387 os << "Numbers=OldStyle";
3388 if (!font_typewriter_opts.empty()) {
3389 if (fonts_typewriter_osf)
3391 os << font_typewriter_opts;
3395 os << '{' << mono << "}\n";
3402 bool const ot1 = (main_font_encoding() == "default" || main_font_encoding() == "OT1");
3403 bool const dryrun = features.runparams().dryrun;
3404 bool const complete = (fontsSans() == "default" && fontsTypewriter() == "default");
3405 bool const nomath = (fontsMath() == "default");
3408 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsRoman())).getLaTeXCode(
3409 dryrun, ot1, complete, fonts_expert_sc, fonts_roman_osf,
3410 nomath, font_roman_opts);
3413 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsSans())).getLaTeXCode(
3414 dryrun, ot1, complete, fonts_expert_sc, fonts_sans_osf,
3415 nomath, font_sans_opts, fontsSansScale());
3417 // MONOSPACED/TYPEWRITER
3418 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsTypewriter())).getLaTeXCode(
3419 dryrun, ot1, complete, fonts_expert_sc, fonts_typewriter_osf,
3420 nomath, font_typewriter_opts, fontsTypewriterScale());
3423 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsMath())).getLaTeXCode(
3424 dryrun, ot1, complete, fonts_expert_sc, fonts_roman_osf,
3431 Encoding const & BufferParams::encoding() const
3433 // Main encoding for LaTeX output.
3435 return *(encodings.fromLyXName("utf8-plain"));
3436 if (inputenc == "auto-legacy" || inputenc == "auto-legacy-plain")
3437 return *language->encoding();
3438 if (inputenc == "utf8" && language->lang() == "japanese")
3439 return *(encodings.fromLyXName("utf8-platex"));
3440 Encoding const * const enc = encodings.fromLyXName(inputenc);
3443 LYXERR0("Unknown inputenc value `" << inputenc
3444 << "'. Using `auto' instead.");
3445 return *language->encoding();
3449 string const & BufferParams::defaultBiblioStyle() const
3451 if (!biblio_style.empty())
3452 return biblio_style;
3454 map<string, string> const & bs = documentClass().defaultBiblioStyle();
3455 auto cit = bs.find(theCiteEnginesList.getTypeAsString(citeEngineType()));
3456 if (cit != bs.end())
3459 return empty_string();
3463 bool const & BufferParams::fullAuthorList() const
3465 return documentClass().fullAuthorList();
3469 string BufferParams::getCiteAlias(string const & s) const
3471 vector<string> commands =
3472 documentClass().citeCommands(citeEngineType());
3473 // If it is a real command, don't treat it as an alias
3474 if (find(commands.begin(), commands.end(), s) != commands.end())
3476 map<string,string> aliases = documentClass().citeCommandAliases();
3477 if (aliases.find(s) != aliases.end())
3483 vector<string> BufferParams::citeCommands() const
3485 static CitationStyle const default_style;
3486 vector<string> commands =
3487 documentClass().citeCommands(citeEngineType());
3488 if (commands.empty())
3489 commands.push_back(default_style.name);
3494 vector<CitationStyle> BufferParams::citeStyles() const
3496 static CitationStyle const default_style;
3497 vector<CitationStyle> styles =
3498 documentClass().citeStyles(citeEngineType());
3500 styles.push_back(default_style);
3505 string const BufferParams::bibtexCommand() const
3507 // Return document-specific setting if available
3508 if (bibtex_command != "default")
3509 return bibtex_command;
3511 // If we have "default" in document settings, consult the prefs
3512 // 1. Japanese (uses a specific processor)
3513 if (encoding().package() == Encoding::japanese) {
3514 if (lyxrc.jbibtex_command != "automatic")
3515 // Return the specified program, if "automatic" is not set
3516 return lyxrc.jbibtex_command;
3517 else if (!useBiblatex()) {
3518 // With classic BibTeX, return pbibtex, jbibtex, bibtex
3519 if (lyxrc.jbibtex_alternatives.find("pbibtex") != lyxrc.jbibtex_alternatives.end())
3521 if (lyxrc.jbibtex_alternatives.find("jbibtex") != lyxrc.jbibtex_alternatives.end())
3526 // 2. All other languages
3527 else if (lyxrc.bibtex_command != "automatic")
3528 // Return the specified program, if "automatic" is not set
3529 return lyxrc.bibtex_command;
3531 // 3. Automatic: find the most suitable for the current cite framework
3532 if (useBiblatex()) {
3533 // For Biblatex, we prefer biber (also for Japanese)
3534 // and fall back to bibtex8 and, as last resort, bibtex
3535 if (lyxrc.bibtex_alternatives.find("biber") != lyxrc.bibtex_alternatives.end())
3537 else if (lyxrc.bibtex_alternatives.find("bibtex8") != lyxrc.bibtex_alternatives.end())
3544 bool BufferParams::useBiblatex() const
3546 return theCiteEnginesList[citeEngine()]->getCiteFramework() == "biblatex";
3550 void BufferParams::invalidateConverterCache() const
3552 pimpl_->isExportCacheValid = false;
3553 pimpl_->isViewCacheValid = false;
3557 // We shouldn't need to reset the params here, since anything
3558 // we need will be recopied.
3559 void BufferParams::copyForAdvFR(const BufferParams & bp)
3561 string const & lang = bp.language->lang();
3563 layout_modules_ = bp.layout_modules_;
3564 string const & doc_class = bp.documentClass().name();
3565 setBaseClass(doc_class);
3569 void BufferParams::setBibFileEncoding(string const & file, string const & enc)
3571 bib_encodings[file] = enc;
3575 string const BufferParams::bibFileEncoding(string const & file) const
3577 if (bib_encodings.find(file) == bib_encodings.end())
3579 return bib_encodings.find(file)->second;