2 * \file BufferParams.cpp
3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
6 * \author Alfredo Braunstein
7 * \author Lars Gullik Bjønnes
8 * \author Jean-Marc Lasgouttes
10 * \author André Pönitz
11 * \author Martin Vermeer
13 * Full author contact details are available in file CREDITS.
18 #include "BufferParams.h"
21 #include "LayoutFile.h"
22 #include "BranchList.h"
25 #include "CiteEnginesList.h"
28 #include "Converter.h"
31 #include "IndicesList.h"
33 #include "LaTeXFeatures.h"
34 #include "LaTeXFonts.h"
38 #include "OutputParams.h"
40 #include "texstream.h"
43 #include "PDFOptions.h"
45 #include "frontends/alert.h"
47 #include "insets/InsetListingsParams.h"
48 #include "insets/InsetQuotes.h"
50 #include "support/convert.h"
51 #include "support/debug.h"
52 #include "support/FileName.h"
53 #include "support/filetools.h"
54 #include "support/gettext.h"
55 #include "support/Length.h"
56 #include "support/Messages.h"
57 #include "support/mutex.h"
58 #include "support/Package.h"
59 #include "support/Translator.h"
60 #include "support/lstrings.h"
66 using namespace lyx::support;
69 static char const * const string_paragraph_separation[] = {
74 static char const * const string_quotes_style[] = {
75 "english", "swedish", "german", "polish", "swiss", "danish", "plain",
76 "british", "swedishg", "french", "frenchin", "russian", "cjk", "cjkangle",
81 static char const * const string_papersize[] = {
82 "default", "custom", "letter", "legal", "executive",
83 "a0", "a1", "a2", "a3", "a4", "a5", "a6",
84 "b0", "b1", "b2", "b3", "b4", "b5", "b6",
85 "c0", "c1", "c2", "c3", "c4", "c5", "c6",
86 "b0j", "b1j", "b2j", "b3j", "b4j", "b5j", "b6j", ""
90 static char const * const string_papersize_geometry[] = {
91 "default", "custom", "letterpaper", "legalpaper", "executivepaper",
92 "a0paper", "a1paper", "a2paper", "a3paper", "a4paper", "a5paper", "a6paper",
93 "b0paper", "b1paper", "b2paper", "b3paper", "b4paper", "b5paper", "b6paper",
94 "c0paper", "c1paper", "c2paper", "c3paper", "c4paper", "c5paper", "c6paper",
95 "b0j", "b1j", "b2j", "b3j", "b4j", "b5j", "b6j", ""
99 static char const * const string_orientation[] = {
100 "portrait", "landscape", ""
104 static char const * const tex_graphics[] = {
105 "default", "dvialw", "dvilaser", "dvipdf", "dvipdfm", "dvipdfmx",
106 "dvips", "dvipsone", "dvitops", "dviwin", "dviwindo", "dvi2ps", "emtex",
107 "ln", "oztex", "pctexhp", "pctexps", "pctexwin", "pctex32", "pdftex",
108 "psprint", "pubps", "tcidvi", "textures", "truetex", "vtex", "xdvi",
118 // Paragraph separation
119 typedef Translator<string, BufferParams::ParagraphSeparation> ParSepTranslator;
122 ParSepTranslator const init_parseptranslator()
124 ParSepTranslator translator
125 (string_paragraph_separation[0], BufferParams::ParagraphIndentSeparation);
126 translator.addPair(string_paragraph_separation[1], BufferParams::ParagraphSkipSeparation);
131 ParSepTranslator const & parseptranslator()
133 static ParSepTranslator const translator =
134 init_parseptranslator();
140 typedef Translator<string, QuoteStyle> QuotesStyleTranslator;
143 QuotesStyleTranslator const init_quotesstyletranslator()
145 QuotesStyleTranslator translator
146 (string_quotes_style[0], QuoteStyle::English);
147 translator.addPair(string_quotes_style[1], QuoteStyle::Swedish);
148 translator.addPair(string_quotes_style[2], QuoteStyle::German);
149 translator.addPair(string_quotes_style[3], QuoteStyle::Polish);
150 translator.addPair(string_quotes_style[4], QuoteStyle::Swiss);
151 translator.addPair(string_quotes_style[5], QuoteStyle::Danish);
152 translator.addPair(string_quotes_style[6], QuoteStyle::Plain);
153 translator.addPair(string_quotes_style[7], QuoteStyle::British);
154 translator.addPair(string_quotes_style[8], QuoteStyle::SwedishG);
155 translator.addPair(string_quotes_style[9], QuoteStyle::French);
156 translator.addPair(string_quotes_style[10], QuoteStyle::FrenchIN);
157 translator.addPair(string_quotes_style[11], QuoteStyle::Russian);
158 translator.addPair(string_quotes_style[12], QuoteStyle::CJK);
159 translator.addPair(string_quotes_style[13], QuoteStyle::CJKAngle);
160 translator.addPair(string_quotes_style[14], QuoteStyle::Hungarian);
165 QuotesStyleTranslator const & quotesstyletranslator()
167 static QuotesStyleTranslator const translator =
168 init_quotesstyletranslator();
174 typedef Translator<string, PAPER_SIZE> PaperSizeTranslator;
177 static PaperSizeTranslator initPaperSizeTranslator()
179 PaperSizeTranslator translator(string_papersize[0], PAPER_DEFAULT);
180 translator.addPair(string_papersize[1], PAPER_CUSTOM);
181 translator.addPair(string_papersize[2], PAPER_USLETTER);
182 translator.addPair(string_papersize[3], PAPER_USLEGAL);
183 translator.addPair(string_papersize[4], PAPER_USEXECUTIVE);
184 translator.addPair(string_papersize[5], PAPER_A0);
185 translator.addPair(string_papersize[6], PAPER_A1);
186 translator.addPair(string_papersize[7], PAPER_A2);
187 translator.addPair(string_papersize[8], PAPER_A3);
188 translator.addPair(string_papersize[9], PAPER_A4);
189 translator.addPair(string_papersize[10], PAPER_A5);
190 translator.addPair(string_papersize[11], PAPER_A6);
191 translator.addPair(string_papersize[12], PAPER_B0);
192 translator.addPair(string_papersize[13], PAPER_B1);
193 translator.addPair(string_papersize[14], PAPER_B2);
194 translator.addPair(string_papersize[15], PAPER_B3);
195 translator.addPair(string_papersize[16], PAPER_B4);
196 translator.addPair(string_papersize[17], PAPER_B5);
197 translator.addPair(string_papersize[18], PAPER_B6);
198 translator.addPair(string_papersize[19], PAPER_C0);
199 translator.addPair(string_papersize[20], PAPER_C1);
200 translator.addPair(string_papersize[21], PAPER_C2);
201 translator.addPair(string_papersize[22], PAPER_C3);
202 translator.addPair(string_papersize[23], PAPER_C4);
203 translator.addPair(string_papersize[24], PAPER_C5);
204 translator.addPair(string_papersize[25], PAPER_C6);
205 translator.addPair(string_papersize[26], PAPER_JISB0);
206 translator.addPair(string_papersize[27], PAPER_JISB1);
207 translator.addPair(string_papersize[28], PAPER_JISB2);
208 translator.addPair(string_papersize[29], PAPER_JISB3);
209 translator.addPair(string_papersize[30], PAPER_JISB4);
210 translator.addPair(string_papersize[31], PAPER_JISB5);
211 translator.addPair(string_papersize[32], PAPER_JISB6);
216 PaperSizeTranslator const & papersizetranslator()
218 static PaperSizeTranslator const translator =
219 initPaperSizeTranslator();
225 typedef Translator<string, PAPER_ORIENTATION> PaperOrientationTranslator;
228 PaperOrientationTranslator const init_paperorientationtranslator()
230 PaperOrientationTranslator translator(string_orientation[0], ORIENTATION_PORTRAIT);
231 translator.addPair(string_orientation[1], ORIENTATION_LANDSCAPE);
236 PaperOrientationTranslator const & paperorientationtranslator()
238 static PaperOrientationTranslator const translator =
239 init_paperorientationtranslator();
245 typedef Translator<int, PageSides> SidesTranslator;
248 SidesTranslator const init_sidestranslator()
250 SidesTranslator translator(1, OneSide);
251 translator.addPair(2, TwoSides);
256 SidesTranslator const & sidestranslator()
258 static SidesTranslator const translator = init_sidestranslator();
264 typedef Translator<int, BufferParams::Package> PackageTranslator;
267 PackageTranslator const init_packagetranslator()
269 PackageTranslator translator(0, BufferParams::package_off);
270 translator.addPair(1, BufferParams::package_auto);
271 translator.addPair(2, BufferParams::package_on);
276 PackageTranslator const & packagetranslator()
278 static PackageTranslator const translator =
279 init_packagetranslator();
285 typedef Translator<string, Spacing::Space> SpaceTranslator;
288 SpaceTranslator const init_spacetranslator()
290 SpaceTranslator translator("default", Spacing::Default);
291 translator.addPair("single", Spacing::Single);
292 translator.addPair("onehalf", Spacing::Onehalf);
293 translator.addPair("double", Spacing::Double);
294 translator.addPair("other", Spacing::Other);
299 SpaceTranslator const & spacetranslator()
301 static SpaceTranslator const translator = init_spacetranslator();
306 bool inSystemDir(FileName const & document_dir, string & system_dir)
308 // A document is assumed to be in a system LyX directory (not
309 // necessarily the system directory of the running instance)
310 // if both "configure.py" and "chkconfig.ltx" are found in
311 // either document_dir/../ or document_dir/../../.
312 // If true, the system directory path is returned in system_dir
313 // with a trailing path separator.
315 string const msg = "Checking whether document is in a system dir...";
317 string dir = document_dir.absFileName();
319 for (int i = 0; i < 3; ++i) {
320 dir = addPath(dir, "..");
321 if (!fileSearch(dir, "configure.py").empty() &&
322 !fileSearch(dir, "chkconfig.ltx").empty()) {
323 LYXERR(Debug::FILES, msg << " yes");
324 system_dir = addPath(FileName(dir).realPath(), "");
329 LYXERR(Debug::FILES, msg << " no");
330 system_dir = string();
337 class BufferParams::Impl
342 AuthorList authorlist;
343 BranchList branchlist;
344 Bullet temp_bullets[4];
345 Bullet user_defined_bullets[4];
346 IndicesList indiceslist;
350 /** This is the amount of space used for paragraph_separation "skip",
351 * and for detached paragraphs in "indented" documents.
354 PDFOptions pdfoptions;
355 LayoutFileIndex baseClass_;
356 FormatList exportableFormatList;
357 FormatList viewableFormatList;
358 bool isViewCacheValid;
359 bool isExportCacheValid;
363 BufferParams::Impl::Impl()
364 : defskip(VSpace::MEDSKIP), baseClass_(string("")),
365 isViewCacheValid(false), isExportCacheValid(false)
367 // set initial author
369 authorlist.record(Author(from_utf8(lyxrc.user_name),
370 from_utf8(lyxrc.user_email),
371 from_utf8(lyxrc.user_initials)));
376 BufferParams::MemoryTraits::clone(BufferParams::Impl const * ptr)
379 return new BufferParams::Impl(*ptr);
383 void BufferParams::MemoryTraits::destroy(BufferParams::Impl * ptr)
389 BufferParams::BufferParams()
392 setBaseClass(defaultBaseclass());
393 cite_engine_ = "basic";
394 cite_engine_type_ = ENGINE_TYPE_DEFAULT;
396 paragraph_separation = ParagraphIndentSeparation;
397 is_math_indent = false;
398 math_numbering_side = DEFAULT;
399 quotes_style = QuoteStyle::English;
400 dynamic_quotes = false;
401 fontsize = "default";
404 papersize = PAPER_DEFAULT;
405 orientation = ORIENTATION_PORTRAIT;
406 use_geometry = false;
407 biblio_style = string();
408 use_bibtopic = false;
411 save_transient_properties = true;
412 track_changes = false;
413 output_changes = false;
415 postpone_fragile_content = true;
416 use_default_options = true;
417 maintain_unincluded_children = CM_None;
420 language = default_language;
422 fonts_roman[0] = "default";
423 fonts_roman[1] = "default";
424 fonts_sans[0] = "default";
425 fonts_sans[1] = "default";
426 fonts_typewriter[0] = "default";
427 fonts_typewriter[1] = "default";
428 fonts_math[0] = "auto";
429 fonts_math[1] = "auto";
430 fonts_default_family = "default";
431 useNonTeXFonts = false;
432 use_microtype = false;
433 use_dash_ligatures = true;
434 fonts_expert_sc = false;
435 fonts_roman_osf = false;
436 fonts_sans_osf = false;
437 fonts_typewriter_osf = false;
438 fonts_sans_scale[0] = 100;
439 fonts_sans_scale[1] = 100;
440 fonts_typewriter_scale[0] = 100;
441 fonts_typewriter_scale[1] = 100;
443 lang_package = "default";
444 graphics_driver = "default";
445 default_output_format = "default";
446 bibtex_command = "default";
447 index_command = "default";
450 listings_params = string();
451 pagestyle = "default";
452 tablestyle = "default";
453 float_alignment = "class";
454 float_placement = "class";
455 suppress_date = false;
456 justification = true;
457 // no color is the default (white)
458 backgroundcolor = lyx::rgbFromHexName("#ffffff");
459 isbackgroundcolor = false;
460 // no color is the default (black)
461 fontcolor = lyx::rgbFromHexName("#000000");
463 // light gray is the default font color for greyed-out notes
464 notefontcolor = lyx::rgbFromHexName("#cccccc");
465 isnotefontcolor = false;
466 boxbgcolor = lyx::rgbFromHexName("#ff0000");
467 isboxbgcolor = false;
468 compressed = lyxrc.save_compressed;
469 for (int iter = 0; iter < 4; ++iter) {
470 user_defined_bullet(iter) = ITEMIZE_DEFAULTS[iter];
471 temp_bullet(iter) = ITEMIZE_DEFAULTS[iter];
474 indiceslist().addDefault(B_("Index"));
475 html_be_strict = false;
476 html_math_output = MathML;
477 html_math_img_scale = 1.0;
478 html_css_as_file = false;
479 docbook_table_output = HTMLTable;
480 display_pixel_ratio = 1.0;
482 shell_escape = false;
488 // map current author
489 author_map_[pimpl_->authorlist.get(0).bufferId()] = 0;
493 docstring BufferParams::B_(string const & l10n) const
495 LASSERT(language, return from_utf8(l10n));
496 return getMessages(language->code()).get(l10n);
500 BufferParams::Package BufferParams::use_package(std::string const & p) const
502 PackageMap::const_iterator it = use_packages.find(p);
503 if (it == use_packages.end())
509 void BufferParams::use_package(std::string const & p, BufferParams::Package u)
515 map<string, string> const & BufferParams::auto_packages()
517 static map<string, string> packages;
518 if (packages.empty()) {
519 // We could have a race condition here that two threads
520 // discover an empty map at the same time and want to fill
521 // it, but that is no problem, since the same contents is
522 // filled in twice then. Having the locker inside the
523 // packages.empty() condition has the advantage that we
524 // don't need the mutex overhead for simple reading.
526 Mutex::Locker locker(&mutex);
527 // adding a package here implies a file format change!
528 packages["amsmath"] =
529 N_("The LaTeX package amsmath is only used if AMS formula types or symbols from the AMS math toolbars are inserted into formulas");
530 packages["amssymb"] =
531 N_("The LaTeX package amssymb is only used if symbols from the AMS math toolbars are inserted into formulas");
533 N_("The LaTeX package cancel is only used if \\cancel commands are used in formulas");
535 N_("The LaTeX package esint is only used if special integral symbols are inserted into formulas");
536 packages["mathdots"] =
537 N_("The LaTeX package mathdots is only used if the command \\iddots is inserted into formulas");
538 packages["mathtools"] =
539 N_("The LaTeX package mathtools is only used if some mathematical relations are inserted into formulas");
541 N_("The LaTeX package mhchem is only used if either the command \\ce or \\cf is inserted into formulas");
542 packages["stackrel"] =
543 N_("The LaTeX package stackrel is only used if the command \\stackrel with subscript is inserted into formulas");
544 packages["stmaryrd"] =
545 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");
546 packages["undertilde"] =
547 N_("The LaTeX package undertilde is only used if you use the math frame decoration 'utilde'");
553 bool BufferParams::useBibtopic() const
557 return (use_bibtopic || (!multibib.empty() && multibib != "child"));
561 AuthorList & BufferParams::authors()
563 return pimpl_->authorlist;
567 AuthorList const & BufferParams::authors() const
569 return pimpl_->authorlist;
573 void BufferParams::addAuthor(Author const & a)
575 author_map_[a.bufferId()] = pimpl_->authorlist.record(a);
579 BranchList & BufferParams::branchlist()
581 return pimpl_->branchlist;
585 BranchList const & BufferParams::branchlist() const
587 return pimpl_->branchlist;
591 IndicesList & BufferParams::indiceslist()
593 return pimpl_->indiceslist;
597 IndicesList const & BufferParams::indiceslist() const
599 return pimpl_->indiceslist;
603 Bullet & BufferParams::temp_bullet(lyx::size_type const index)
605 LASSERT(index < 4, return pimpl_->temp_bullets[0]);
606 return pimpl_->temp_bullets[index];
610 Bullet const & BufferParams::temp_bullet(lyx::size_type const index) const
612 LASSERT(index < 4, return pimpl_->temp_bullets[0]);
613 return pimpl_->temp_bullets[index];
617 Bullet & BufferParams::user_defined_bullet(lyx::size_type const index)
619 LASSERT(index < 4, return pimpl_->temp_bullets[0]);
620 return pimpl_->user_defined_bullets[index];
624 Bullet const & BufferParams::user_defined_bullet(lyx::size_type const index) const
626 LASSERT(index < 4, return pimpl_->temp_bullets[0]);
627 return pimpl_->user_defined_bullets[index];
631 Spacing & BufferParams::spacing()
633 return pimpl_->spacing;
637 Spacing const & BufferParams::spacing() const
639 return pimpl_->spacing;
643 PDFOptions & BufferParams::pdfoptions()
645 return pimpl_->pdfoptions;
649 PDFOptions const & BufferParams::pdfoptions() const
651 return pimpl_->pdfoptions;
655 Length const & BufferParams::getMathIndent() const
657 return pimpl_->mathindent;
661 void BufferParams::setMathIndent(Length const & indent)
663 pimpl_->mathindent = indent;
667 Length const & BufferParams::getParIndent() const
669 return pimpl_->parindent;
673 void BufferParams::setParIndent(Length const & indent)
675 pimpl_->parindent = indent;
679 VSpace const & BufferParams::getDefSkip() const
681 return pimpl_->defskip;
685 void BufferParams::setDefSkip(VSpace const & vs)
687 // DEFSKIP will cause an infinite loop
688 LASSERT(vs.kind() != VSpace::DEFSKIP, return);
689 pimpl_->defskip = vs;
693 BufferParams::MathNumber BufferParams::getMathNumber() const
695 if (math_numbering_side != DEFAULT)
696 return math_numbering_side;
697 // FIXME: do not hardcode language here
698 else if (language->lang() == "arabic_arabi"
699 || documentClass().provides("leqno"))
706 string BufferParams::readToken(Lexer & lex, string const & token,
707 FileName const & filename)
710 FileName const & filepath = filename.onlyPath();
712 if (token == "\\textclass") {
714 string const classname = lex.getString();
715 // if there exists a local layout file, ignore the system one
716 // NOTE: in this case, the textclass (.cls file) is assumed to
719 LayoutFileList & bcl = LayoutFileList::get();
720 if (!filepath.empty()) {
721 // If classname is an absolute path, the document is
722 // using a local layout file which could not be accessed
723 // by a relative path. In this case the path is correct
724 // even if the document was moved to a different
725 // location. However, we will have a problem if the
726 // document was generated on a different platform.
727 bool isabsolute = FileName::isAbsolute(classname);
728 string const classpath = onlyPath(classname);
729 string const path = isabsolute ? classpath
730 : FileName(addPath(filepath.absFileName(),
731 classpath)).realPath();
732 string const oldpath = isabsolute ? string()
733 : FileName(addPath(origin, classpath)).realPath();
734 tcp = bcl.addLocalLayout(onlyFileName(classname), path, oldpath);
736 // that returns non-empty if a "local" layout file is found.
738 result = to_utf8(makeRelPath(from_utf8(onlyPath(tcp)),
739 from_utf8(filepath.absFileName())));
742 setBaseClass(onlyFileName(tcp));
744 setBaseClass(onlyFileName(classname));
745 // We assume that a tex class exists for local or unknown
746 // layouts so this warning, will only be given for system layouts.
747 if (!baseClass()->isTeXClassAvailable()) {
748 docstring const desc =
749 translateIfPossible(from_utf8(baseClass()->description()));
750 docstring const prereqs =
751 from_utf8(baseClass()->prerequisites());
752 docstring const msg =
753 bformat(_("The selected document class\n"
755 "requires external files that are not available.\n"
756 "The document class can still be used, but the\n"
757 "document cannot be compiled until the following\n"
758 "prerequisites are installed:\n"
760 "See section 3.1.2.2 (Class Availability) of the\n"
761 "User's Guide for more information."), desc, prereqs);
762 frontend::Alert::warning(_("Document class not available"),
765 } else if (token == "\\save_transient_properties") {
766 lex >> save_transient_properties;
767 } else if (token == "\\origin") {
769 origin = lex.getString();
770 string const sysdirprefix = "/systemlyxdir/";
771 if (prefixIs(origin, sysdirprefix)) {
773 if (inSystemDir(filepath, docsys))
774 origin.replace(0, sysdirprefix.length() - 1, docsys);
776 origin.replace(0, sysdirprefix.length() - 1,
777 package().system_support().absFileName());
779 } else if (token == "\\begin_preamble") {
781 } else if (token == "\\begin_local_layout") {
782 readLocalLayout(lex, false);
783 } else if (token == "\\begin_forced_local_layout") {
784 readLocalLayout(lex, true);
785 } else if (token == "\\begin_modules") {
787 } else if (token == "\\begin_removed_modules") {
788 readRemovedModules(lex);
789 } else if (token == "\\begin_includeonly") {
790 readIncludeonly(lex);
791 } else if (token == "\\maintain_unincluded_children") {
795 maintain_unincluded_children = CM_None;
796 else if (tmp == "mostly")
797 maintain_unincluded_children = CM_Mostly;
798 else if (tmp == "strict")
799 maintain_unincluded_children = CM_Strict;
800 } else if (token == "\\options") {
802 options = lex.getString();
803 } else if (token == "\\use_default_options") {
804 lex >> use_default_options;
805 } else if (token == "\\master") {
807 master = lex.getString();
808 if (!filepath.empty() && FileName::isAbsolute(origin)) {
809 bool const isabs = FileName::isAbsolute(master);
810 FileName const abspath(isabs ? master : origin + master);
811 bool const moved = filepath != FileName(origin);
812 if (moved && abspath.exists()) {
813 docstring const path = isabs
815 : from_utf8(abspath.realPath());
816 docstring const refpath =
817 from_utf8(filepath.absFileName());
818 master = to_utf8(makeRelPath(path, refpath));
821 } else if (token == "\\suppress_date") {
822 lex >> suppress_date;
823 } else if (token == "\\justification") {
824 lex >> justification;
825 } else if (token == "\\language") {
827 } else if (token == "\\language_package") {
829 lang_package = lex.getString();
830 } else if (token == "\\inputencoding") {
832 } else if (token == "\\graphics") {
833 readGraphicsDriver(lex);
834 } else if (token == "\\default_output_format") {
835 lex >> default_output_format;
836 } else if (token == "\\bibtex_command") {
838 bibtex_command = lex.getString();
839 } else if (token == "\\index_command") {
841 index_command = lex.getString();
842 } else if (token == "\\fontencoding") {
844 fontenc = lex.getString();
845 } else if (token == "\\font_roman") {
846 lex >> fonts_roman[0];
847 lex >> fonts_roman[1];
848 } else if (token == "\\font_sans") {
849 lex >> fonts_sans[0];
850 lex >> fonts_sans[1];
851 } else if (token == "\\font_typewriter") {
852 lex >> fonts_typewriter[0];
853 lex >> fonts_typewriter[1];
854 } else if (token == "\\font_math") {
855 lex >> fonts_math[0];
856 lex >> fonts_math[1];
857 } else if (token == "\\font_default_family") {
858 lex >> fonts_default_family;
859 } else if (token == "\\use_non_tex_fonts") {
860 lex >> useNonTeXFonts;
861 } else if (token == "\\font_sc") {
862 lex >> fonts_expert_sc;
863 } else if (token == "\\font_roman_osf") {
864 lex >> fonts_roman_osf;
865 } else if (token == "\\font_sans_osf") {
866 lex >> fonts_sans_osf;
867 } else if (token == "\\font_typewriter_osf") {
868 lex >> fonts_typewriter_osf;
869 } else if (token == "\\font_roman_opts") {
870 lex >> font_roman_opts;
871 } else if (token == "\\font_sf_scale") {
872 lex >> fonts_sans_scale[0];
873 lex >> fonts_sans_scale[1];
874 } else if (token == "\\font_sans_opts") {
875 lex >> font_sans_opts;
876 } else if (token == "\\font_tt_scale") {
877 lex >> fonts_typewriter_scale[0];
878 lex >> fonts_typewriter_scale[1];
879 } else if (token == "\\font_typewriter_opts") {
880 lex >> font_typewriter_opts;
881 } else if (token == "\\font_cjk") {
883 } else if (token == "\\use_microtype") {
884 lex >> use_microtype;
885 } else if (token == "\\use_dash_ligatures") {
886 lex >> use_dash_ligatures;
887 } else if (token == "\\paragraph_separation") {
890 paragraph_separation = parseptranslator().find(parsep);
891 } else if (token == "\\paragraph_indentation") {
893 string parindent = lex.getString();
894 if (parindent == "default")
895 pimpl_->parindent = Length();
897 pimpl_->parindent = Length(parindent);
898 } else if (token == "\\defskip") {
900 string const defskip = lex.getString();
901 pimpl_->defskip = VSpace(defskip);
902 if (pimpl_->defskip.kind() == VSpace::DEFSKIP)
904 pimpl_->defskip = VSpace(VSpace::MEDSKIP);
905 } else if (token == "\\is_math_indent") {
906 lex >> is_math_indent;
907 } else if (token == "\\math_indentation") {
909 string mathindent = lex.getString();
910 if (mathindent == "default")
911 pimpl_->mathindent = Length();
913 pimpl_->mathindent = Length(mathindent);
914 } else if (token == "\\math_numbering_side") {
918 math_numbering_side = LEFT;
919 else if (tmp == "right")
920 math_numbering_side = RIGHT;
922 math_numbering_side = DEFAULT;
923 } else if (token == "\\quotes_style") {
926 quotes_style = quotesstyletranslator().find(qstyle);
927 } else if (token == "\\dynamic_quotes") {
928 lex >> dynamic_quotes;
929 } else if (token == "\\papersize") {
932 papersize = papersizetranslator().find(ppsize);
933 } else if (token == "\\use_geometry") {
935 } else if (token == "\\use_package") {
940 use_package(package, packagetranslator().find(use));
941 } else if (token == "\\cite_engine") {
943 cite_engine_ = lex.getString();
944 } else if (token == "\\cite_engine_type") {
947 cite_engine_type_ = theCiteEnginesList.getType(engine_type);
948 } else if (token == "\\biblio_style") {
950 biblio_style = lex.getString();
951 } else if (token == "\\biblio_options") {
953 biblio_opts = trim(lex.getString());
954 } else if (token == "\\biblatex_bibstyle") {
956 biblatex_bibstyle = trim(lex.getString());
957 } else if (token == "\\biblatex_citestyle") {
959 biblatex_citestyle = trim(lex.getString());
960 } else if (token == "\\use_bibtopic") {
962 } else if (token == "\\multibib") {
964 } else if (token == "\\use_indices") {
966 } else if (token == "\\tracking_changes") {
967 lex >> track_changes;
968 } else if (token == "\\output_changes") {
969 lex >> output_changes;
970 } else if (token == "\\change_bars") {
972 } else if (token == "\\postpone_fragile_content") {
973 lex >> postpone_fragile_content;
974 } else if (token == "\\branch") {
976 docstring branch = lex.getDocString();
977 branchlist().add(branch);
980 string const tok = lex.getString();
981 if (tok == "\\end_branch")
983 Branch * branch_ptr = branchlist().find(branch);
984 if (tok == "\\selected") {
987 branch_ptr->setSelected(lex.getInteger());
989 if (tok == "\\filename_suffix") {
992 branch_ptr->setFileNameSuffix(lex.getInteger());
994 if (tok == "\\color") {
996 vector<string> const colors = getVectorFromString(lex.getString(), " ");
997 string const lmcolor = colors.front();
999 if (colors.size() > 1)
1000 dmcolor = colors.back();
1002 branch_ptr->setColors(lmcolor, dmcolor);
1005 } else if (token == "\\index") {
1007 docstring index = lex.getDocString();
1009 indiceslist().add(index);
1012 string const tok = lex.getString();
1013 if (tok == "\\end_index")
1015 Index * index_ptr = indiceslist().find(index);
1016 if (tok == "\\shortcut") {
1018 shortcut = lex.getDocString();
1020 index_ptr->setShortcut(shortcut);
1022 if (tok == "\\color") {
1024 string color = lex.getString();
1026 index_ptr->setColor(color);
1027 // Update also the Color table:
1028 if (color == "none")
1029 color = lcolor.getX11HexName(Color_background);
1031 if (!shortcut.empty())
1032 lcolor.setColor(to_utf8(shortcut)+ "@" + filename.absFileName(), color);
1035 } else if (token == "\\author") {
1037 istringstream ss(lex.getString());
1041 } else if (token == "\\paperorientation") {
1044 orientation = paperorientationtranslator().find(orient);
1045 } else if (token == "\\backgroundcolor") {
1047 backgroundcolor = lyx::rgbFromHexName(lex.getString());
1048 isbackgroundcolor = true;
1049 } else if (token == "\\fontcolor") {
1051 fontcolor = lyx::rgbFromHexName(lex.getString());
1053 } else if (token == "\\notefontcolor") {
1055 string color = lex.getString();
1056 notefontcolor = lyx::rgbFromHexName(color);
1057 lcolor.setColor("notefontcolor", color);
1058 lcolor.setLaTeXName("notefontcolor", "note_fontcolor");
1059 lcolor.setGUIName("notefontcolor", N_("greyedout inset text"));
1060 // set a local name for the painter
1061 lcolor.setColor("notefontcolor@" + filename.absFileName(), color);
1062 isnotefontcolor = true;
1063 } else if (token == "\\boxbgcolor") {
1065 string color = lex.getString();
1066 boxbgcolor = lyx::rgbFromHexName(color);
1067 lcolor.setColor("boxbgcolor@" + filename.absFileName(), color);
1068 isboxbgcolor = true;
1069 } else if (token == "\\paperwidth") {
1071 } else if (token == "\\paperheight") {
1073 } else if (token == "\\leftmargin") {
1075 } else if (token == "\\topmargin") {
1077 } else if (token == "\\rightmargin") {
1079 } else if (token == "\\bottommargin") {
1080 lex >> bottommargin;
1081 } else if (token == "\\headheight") {
1083 } else if (token == "\\headsep") {
1085 } else if (token == "\\footskip") {
1087 } else if (token == "\\columnsep") {
1089 } else if (token == "\\paperfontsize") {
1091 } else if (token == "\\papercolumns") {
1093 } else if (token == "\\listings_params") {
1096 listings_params = InsetListingsParams(par).params();
1097 } else if (token == "\\papersides") {
1100 sides = sidestranslator().find(psides);
1101 } else if (token == "\\paperpagestyle") {
1103 } else if (token == "\\tablestyle") {
1105 } else if (token == "\\bullet") {
1107 } else if (token == "\\bulletLaTeX") {
1108 readBulletsLaTeX(lex);
1109 } else if (token == "\\secnumdepth") {
1111 } else if (token == "\\tocdepth") {
1113 } else if (token == "\\spacing") {
1117 if (nspacing == "other") {
1120 spacing().set(spacetranslator().find(nspacing), tmp_val);
1121 } else if (token == "\\float_placement") {
1122 lex >> float_placement;
1123 } else if (token == "\\float_alignment") {
1124 lex >> float_alignment;
1126 } else if (prefixIs(token, "\\pdf_") || token == "\\use_hyperref") {
1127 string toktmp = pdfoptions().readToken(lex, token);
1128 if (!toktmp.empty()) {
1129 lyxerr << "PDFOptions::readToken(): Unknown token: " <<
1133 } else if (token == "\\html_math_output") {
1136 html_math_output = static_cast<MathOutput>(temp);
1137 } else if (token == "\\html_be_strict") {
1138 lex >> html_be_strict;
1139 } else if (token == "\\html_css_as_file") {
1140 lex >> html_css_as_file;
1141 } else if (token == "\\html_math_img_scale") {
1142 lex >> html_math_img_scale;
1143 } else if (token == "\\html_latex_start") {
1145 html_latex_start = lex.getString();
1146 } else if (token == "\\html_latex_end") {
1148 html_latex_end = lex.getString();
1149 } else if (token == "\\docbook_table_output") {
1152 docbook_table_output = static_cast<TableOutput>(temp);
1153 } else if (token == "\\output_sync") {
1155 } else if (token == "\\output_sync_macro") {
1156 lex >> output_sync_macro;
1157 } else if (token == "\\use_refstyle") {
1158 lex >> use_refstyle;
1159 } else if (token == "\\use_minted") {
1161 } else if (token == "\\use_lineno") {
1163 } else if (token == "\\lineno_options") {
1165 lineno_opts = trim(lex.getString());
1167 lyxerr << "BufferParams::readToken(): Unknown token: " <<
1177 // Quote argument if it contains spaces
1178 string quoteIfNeeded(string const & str) {
1179 if (contains(str, ' '))
1180 return "\"" + str + "\"";
1186 void BufferParams::writeFile(ostream & os, Buffer const * buf) const
1188 // The top of the file is written by the buffer.
1189 // Prints out the buffer info into the .lyx file given by file
1191 os << "\\save_transient_properties "
1192 << convert<string>(save_transient_properties) << '\n';
1194 // the document directory (must end with a path separator)
1195 // realPath() is used to resolve symlinks, while addPath(..., "")
1196 // ensures a trailing path separator.
1198 string filepath = addPath(buf->fileName().onlyPath().realPath(), "");
1199 string const sysdir = inSystemDir(FileName(filepath), docsys) ? docsys
1200 : addPath(package().system_support().realPath(), "");
1201 string const relpath =
1202 to_utf8(makeRelPath(from_utf8(filepath), from_utf8(sysdir)));
1203 if (!prefixIs(relpath, "../") && !FileName::isAbsolute(relpath))
1204 filepath = addPath("/systemlyxdir", relpath);
1205 else if (!save_transient_properties || !lyxrc.save_origin)
1206 filepath = "unavailable";
1207 os << "\\origin " << quoteIfNeeded(filepath) << '\n';
1210 os << "\\textclass "
1211 << quoteIfNeeded(buf->includedFilePath(addName(buf->layoutPos(),
1212 baseClass()->name()), "layout"))
1215 // then the preamble
1216 if (!preamble.empty()) {
1217 // remove '\n' from the end of preamble
1218 docstring const tmppreamble = rtrim(preamble, "\n");
1219 os << "\\begin_preamble\n"
1220 << to_utf8(tmppreamble)
1221 << "\n\\end_preamble\n";
1225 if (!options.empty()) {
1226 os << "\\options " << options << '\n';
1229 // use the class options defined in the layout?
1230 os << "\\use_default_options "
1231 << convert<string>(use_default_options) << "\n";
1233 // the master document
1234 if (!master.empty()) {
1235 os << "\\master " << master << '\n';
1239 if (!removed_modules_.empty()) {
1240 os << "\\begin_removed_modules" << '\n';
1241 for (auto const & mod : removed_modules_)
1243 os << "\\end_removed_modules" << '\n';
1247 if (!layout_modules_.empty()) {
1248 os << "\\begin_modules" << '\n';
1249 for (auto const & mod : layout_modules_)
1251 os << "\\end_modules" << '\n';
1255 if (!included_children_.empty()) {
1256 os << "\\begin_includeonly" << '\n';
1257 for (auto const & c : included_children_)
1259 os << "\\end_includeonly" << '\n';
1262 switch (maintain_unincluded_children) {
1273 os << "\\maintain_unincluded_children " << muc << '\n';
1275 // local layout information
1276 docstring const local_layout = getLocalLayout(false);
1277 if (!local_layout.empty()) {
1278 // remove '\n' from the end
1279 docstring const tmplocal = rtrim(local_layout, "\n");
1280 os << "\\begin_local_layout\n"
1281 << to_utf8(tmplocal)
1282 << "\n\\end_local_layout\n";
1284 docstring const forced_local_layout = getLocalLayout(true);
1285 if (!forced_local_layout.empty()) {
1286 // remove '\n' from the end
1287 docstring const tmplocal = rtrim(forced_local_layout, "\n");
1288 os << "\\begin_forced_local_layout\n"
1289 << to_utf8(tmplocal)
1290 << "\n\\end_forced_local_layout\n";
1293 // then the text parameters
1294 if (language != ignore_language)
1295 os << "\\language " << language->lang() << '\n';
1296 os << "\\language_package " << lang_package
1297 << "\n\\inputencoding " << inputenc
1298 << "\n\\fontencoding " << fontenc
1299 << "\n\\font_roman \"" << fonts_roman[0]
1300 << "\" \"" << fonts_roman[1] << '"'
1301 << "\n\\font_sans \"" << fonts_sans[0]
1302 << "\" \"" << fonts_sans[1] << '"'
1303 << "\n\\font_typewriter \"" << fonts_typewriter[0]
1304 << "\" \"" << fonts_typewriter[1] << '"'
1305 << "\n\\font_math \"" << fonts_math[0]
1306 << "\" \"" << fonts_math[1] << '"'
1307 << "\n\\font_default_family " << fonts_default_family
1308 << "\n\\use_non_tex_fonts " << convert<string>(useNonTeXFonts)
1309 << "\n\\font_sc " << convert<string>(fonts_expert_sc)
1310 << "\n\\font_roman_osf " << convert<string>(fonts_roman_osf)
1311 << "\n\\font_sans_osf " << convert<string>(fonts_sans_osf)
1312 << "\n\\font_typewriter_osf " << convert<string>(fonts_typewriter_osf);
1313 if (!font_roman_opts.empty())
1314 os << "\n\\font_roman_opts \"" << font_roman_opts << "\"";
1315 os << "\n\\font_sf_scale " << fonts_sans_scale[0]
1316 << ' ' << fonts_sans_scale[1];
1317 if (!font_sans_opts.empty())
1318 os << "\n\\font_sans_opts \"" << font_sans_opts << "\"";
1319 os << "\n\\font_tt_scale " << fonts_typewriter_scale[0]
1320 << ' ' << fonts_typewriter_scale[1];
1321 if (!font_typewriter_opts.empty())
1322 os << "\n\\font_typewriter_opts \"" << font_typewriter_opts << "\"";
1324 if (!fonts_cjk.empty())
1325 os << "\\font_cjk " << fonts_cjk << '\n';
1326 os << "\\use_microtype " << convert<string>(use_microtype) << '\n';
1327 os << "\\use_dash_ligatures " << convert<string>(use_dash_ligatures) << '\n';
1328 os << "\\graphics " << graphics_driver << '\n';
1329 os << "\\default_output_format " << default_output_format << '\n';
1330 os << "\\output_sync " << output_sync << '\n';
1331 if (!output_sync_macro.empty())
1332 os << "\\output_sync_macro \"" << output_sync_macro << "\"\n";
1333 os << "\\bibtex_command " << bibtex_command << '\n';
1334 os << "\\index_command " << index_command << '\n';
1336 if (!float_placement.empty())
1337 os << "\\float_placement " << float_placement << '\n';
1338 if (!float_alignment.empty())
1339 os << "\\float_alignment " << float_alignment << '\n';
1340 os << "\\paperfontsize " << fontsize << '\n';
1342 spacing().writeFile(os);
1343 pdfoptions().writeFile(os);
1345 os << "\\papersize " << string_papersize[papersize]
1346 << "\n\\use_geometry " << convert<string>(use_geometry);
1347 map<string, string> const & packages = auto_packages();
1348 for (auto const & pack : packages)
1349 os << "\n\\use_package " << pack.first << ' '
1350 << use_package(pack.first);
1352 os << "\n\\cite_engine ";
1354 if (!cite_engine_.empty())
1359 os << "\n\\cite_engine_type " << theCiteEnginesList.getTypeAsString(cite_engine_type_);
1361 if (!biblio_style.empty())
1362 os << "\n\\biblio_style " << biblio_style;
1363 if (!biblio_opts.empty())
1364 os << "\n\\biblio_options " << biblio_opts;
1365 if (!biblatex_bibstyle.empty())
1366 os << "\n\\biblatex_bibstyle " << biblatex_bibstyle;
1367 if (!biblatex_citestyle.empty())
1368 os << "\n\\biblatex_citestyle " << biblatex_citestyle;
1369 if (!multibib.empty())
1370 os << "\n\\multibib " << multibib;
1372 os << "\n\\use_bibtopic " << convert<string>(use_bibtopic)
1373 << "\n\\use_indices " << convert<string>(use_indices)
1374 << "\n\\paperorientation " << string_orientation[orientation]
1375 << "\n\\suppress_date " << convert<string>(suppress_date)
1376 << "\n\\justification " << convert<string>(justification)
1377 << "\n\\use_refstyle " << use_refstyle
1378 << "\n\\use_minted " << use_minted
1379 << "\n\\use_lineno " << use_lineno
1382 if (!lineno_opts.empty())
1383 os << "\\lineno_options " << lineno_opts << '\n';
1385 if (isbackgroundcolor)
1386 os << "\\backgroundcolor " << lyx::X11hexname(backgroundcolor) << '\n';
1388 os << "\\fontcolor " << lyx::X11hexname(fontcolor) << '\n';
1389 if (isnotefontcolor)
1390 os << "\\notefontcolor " << lyx::X11hexname(notefontcolor) << '\n';
1392 os << "\\boxbgcolor " << lyx::X11hexname(boxbgcolor) << '\n';
1394 for (auto const & br : branchlist()) {
1395 os << "\\branch " << to_utf8(br.branch())
1396 << "\n\\selected " << br.isSelected()
1397 << "\n\\filename_suffix " << br.hasFileNameSuffix()
1398 << "\n\\color " << br.lightModeColor() << " " << br.darkModeColor()
1403 for (auto const & id : indiceslist()) {
1404 os << "\\index " << to_utf8(id.index())
1405 << "\n\\shortcut " << to_utf8(id.shortcut())
1406 << "\n\\color " << lyx::X11hexname(id.color())
1411 if (!paperwidth.empty())
1412 os << "\\paperwidth "
1413 << VSpace(paperwidth).asLyXCommand() << '\n';
1414 if (!paperheight.empty())
1415 os << "\\paperheight "
1416 << VSpace(paperheight).asLyXCommand() << '\n';
1417 if (!leftmargin.empty())
1418 os << "\\leftmargin "
1419 << VSpace(leftmargin).asLyXCommand() << '\n';
1420 if (!topmargin.empty())
1421 os << "\\topmargin "
1422 << VSpace(topmargin).asLyXCommand() << '\n';
1423 if (!rightmargin.empty())
1424 os << "\\rightmargin "
1425 << VSpace(rightmargin).asLyXCommand() << '\n';
1426 if (!bottommargin.empty())
1427 os << "\\bottommargin "
1428 << VSpace(bottommargin).asLyXCommand() << '\n';
1429 if (!headheight.empty())
1430 os << "\\headheight "
1431 << VSpace(headheight).asLyXCommand() << '\n';
1432 if (!headsep.empty())
1434 << VSpace(headsep).asLyXCommand() << '\n';
1435 if (!footskip.empty())
1437 << VSpace(footskip).asLyXCommand() << '\n';
1438 if (!columnsep.empty())
1439 os << "\\columnsep "
1440 << VSpace(columnsep).asLyXCommand() << '\n';
1441 os << "\\secnumdepth " << secnumdepth
1442 << "\n\\tocdepth " << tocdepth
1443 << "\n\\paragraph_separation "
1444 << string_paragraph_separation[paragraph_separation];
1445 if (!paragraph_separation)
1446 os << "\n\\paragraph_indentation "
1447 << (getParIndent().empty() ? "default" : getParIndent().asString());
1449 os << "\n\\defskip " << getDefSkip().asLyXCommand();
1450 os << "\n\\is_math_indent " << is_math_indent;
1452 os << "\n\\math_indentation "
1453 << (getMathIndent().empty() ? "default" : getMathIndent().asString());
1454 os << "\n\\math_numbering_side ";
1455 switch(math_numbering_side) {
1465 os << "\n\\quotes_style "
1466 << string_quotes_style[static_cast<int>(quotes_style)]
1467 << "\n\\dynamic_quotes " << dynamic_quotes
1468 << "\n\\papercolumns " << columns
1469 << "\n\\papersides " << sides
1470 << "\n\\paperpagestyle " << pagestyle
1471 << "\n\\tablestyle " << tablestyle << '\n';
1472 if (!listings_params.empty())
1473 os << "\\listings_params \"" <<
1474 InsetListingsParams(listings_params).encodedString() << "\"\n";
1475 for (int i = 0; i < 4; ++i) {
1476 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
1477 if (user_defined_bullet(i).getFont() != -1) {
1478 os << "\\bullet " << i << " "
1479 << user_defined_bullet(i).getFont() << " "
1480 << user_defined_bullet(i).getCharacter() << " "
1481 << user_defined_bullet(i).getSize() << "\n";
1485 os << "\\bulletLaTeX " << i << " \""
1486 << lyx::to_ascii(user_defined_bullet(i).getText())
1492 os << "\\tracking_changes "
1493 << (save_transient_properties ? convert<string>(track_changes) : "false")
1496 os << "\\output_changes "
1497 << (save_transient_properties ? convert<string>(output_changes) : "false")
1500 os << "\\change_bars "
1501 << (save_transient_properties ? convert<string>(change_bars) : "false")
1504 os << "\\postpone_fragile_content " << convert<string>(postpone_fragile_content) << '\n';
1506 os << "\\html_math_output " << html_math_output << '\n'
1507 << "\\html_css_as_file " << html_css_as_file << '\n'
1508 << "\\html_be_strict " << convert<string>(html_be_strict) << '\n';
1510 os << "\\docbook_table_output " << docbook_table_output << '\n';
1512 if (html_math_img_scale != 1.0)
1513 os << "\\html_math_img_scale " << convert<string>(html_math_img_scale) << '\n';
1514 if (!html_latex_start.empty())
1515 os << "\\html_latex_start " << html_latex_start << '\n';
1516 if (!html_latex_end.empty())
1517 os << "\\html_latex_end " << html_latex_end << '\n';
1519 os << pimpl_->authorlist;
1523 void BufferParams::validate(LaTeXFeatures & features) const
1525 features.require(documentClass().required());
1527 if (columns > 1 && language->rightToLeft())
1528 features.require("rtloutputdblcol");
1530 if (output_changes) {
1531 bool xcolorulem = LaTeXFeatures::isAvailable("ulem") &&
1532 LaTeXFeatures::isAvailable("xcolor");
1534 switch (features.runparams().flavor) {
1536 case Flavor::DviLuaTeX:
1538 features.require("ct-xcolor-ulem");
1539 features.require("ulem");
1540 features.require("xcolor");
1542 features.require("ct-none");
1545 case Flavor::LuaTeX:
1546 case Flavor::PdfLaTeX:
1549 features.require("ct-xcolor-ulem");
1550 features.require("ulem");
1551 features.require("xcolor");
1552 // improves color handling in PDF output
1553 features.require("pdfcolmk");
1555 features.require("ct-none");
1562 features.require("changebar");
1565 // Floats with 'Here definitely' as default setting.
1566 if (float_placement.find('H') != string::npos)
1567 features.require("float");
1569 for (auto const & pm : use_packages) {
1570 if (pm.first == "amsmath") {
1571 // AMS Style is at document level
1572 if (pm.second == package_on ||
1573 features.isProvided("amsmath"))
1574 features.require(pm.first);
1575 } else if (pm.second == package_on)
1576 features.require(pm.first);
1579 // Document-level line spacing
1580 if (spacing().getSpace() != Spacing::Single && !spacing().isDefault())
1581 features.require("setspace");
1583 // the bullet shapes are buffer level not paragraph level
1584 // so they are tested here
1585 for (int i = 0; i < 4; ++i) {
1586 if (user_defined_bullet(i) == ITEMIZE_DEFAULTS[i])
1588 int const font = user_defined_bullet(i).getFont();
1590 int const c = user_defined_bullet(i).getCharacter();
1596 features.require("latexsym");
1598 } else if (font == 1) {
1599 features.require("amssymb");
1600 } else if (font >= 2 && font <= 5) {
1601 features.require("pifont");
1605 if (pdfoptions().use_hyperref) {
1606 features.require("hyperref");
1607 // due to interferences with babel and hyperref, the color package has to
1608 // be loaded after hyperref when hyperref is used with the colorlinks
1609 // option, see http://www.lyx.org/trac/ticket/5291
1610 if (pdfoptions().colorlinks)
1611 features.require("color");
1613 if (!listings_params.empty()) {
1614 // do not test validity because listings_params is
1615 // supposed to be valid
1617 InsetListingsParams(listings_params).separatedParams(true);
1618 // we can't support all packages, but we should load the color package
1619 if (par.find("\\color", 0) != string::npos)
1620 features.require("color");
1623 // some languages are only available via polyglossia
1624 if (features.hasPolyglossiaExclusiveLanguages())
1625 features.require("polyglossia");
1627 if (useNonTeXFonts && fontsMath() != "auto")
1628 features.require("unicode-math");
1631 features.require("microtype");
1633 if (!language->required().empty())
1634 features.require(language->required());
1638 bool BufferParams::writeLaTeX(otexstream & os, LaTeXFeatures & features,
1639 FileName const & filepath) const
1641 // http://www.tug.org/texmf-dist/doc/latex/base/fixltx2e.pdf
1642 // !! To use the Fix-cm package, load it before \documentclass, and use the command
1643 // \RequirePackage to do so, rather than the normal \usepackage
1644 // Do not try to load any other package before the document class, unless you
1645 // have a thorough understanding of the LATEX internals and know exactly what you
1647 if (features.mustProvide("fix-cm"))
1648 os << "\\RequirePackage{fix-cm}\n";
1649 // Likewise for fixltx2e. If other packages conflict with this policy,
1650 // treat it as a package bug (and report it!)
1651 // See http://www.latex-project.org/cgi-bin/ltxbugs2html?pr=latex/4407
1652 if (features.mustProvide("fixltx2e"))
1653 os << "\\RequirePackage{fixltx2e}\n";
1655 os << "\\documentclass";
1657 DocumentClass const & tclass = documentClass();
1659 ostringstream clsoptions; // the document class options.
1661 if (tokenPos(tclass.opt_fontsize(),
1662 '|', fontsize) >= 0) {
1663 // only write if existing in list (and not default)
1664 clsoptions << subst(tclass.fontsizeformat(), "$$s", fontsize) << ",";
1667 // paper sizes not supported by the class itself need the
1669 vector<string> classpsizes = getVectorFromString(tclass.opt_pagesize(), "|");
1670 bool class_supported_papersize = papersize == PAPER_DEFAULT
1671 || find(classpsizes.begin(), classpsizes.end(), string_papersize[papersize]) != classpsizes.end();
1673 if ((!use_geometry || features.isProvided("geometry-light"))
1674 && class_supported_papersize && papersize != PAPER_DEFAULT)
1675 clsoptions << subst(tclass.pagesizeformat(), "$$s", string_papersize[papersize]) << ",";
1678 if (sides != tclass.sides()) {
1681 clsoptions << "oneside,";
1684 clsoptions << "twoside,";
1690 if (columns != tclass.columns()) {
1692 clsoptions << "twocolumn,";
1694 clsoptions << "onecolumn,";
1698 && orientation == ORIENTATION_LANDSCAPE)
1699 clsoptions << "landscape,";
1702 clsoptions << "fleqn,";
1704 switch(math_numbering_side) {
1706 clsoptions << "leqno,";
1709 clsoptions << "reqno,";
1710 features.require("amsmath");
1716 // language should be a parameter to \documentclass
1717 if (language->babel() == "hebrew"
1718 && default_language->babel() != "hebrew")
1719 // This seems necessary
1720 features.useLanguage(default_language);
1722 ostringstream language_options;
1723 bool const use_babel = features.useBabel() && !features.isProvided("babel");
1724 bool const use_polyglossia = features.usePolyglossia();
1725 bool const global = lyxrc.language_global_options;
1726 if (features.useBabel() || (use_polyglossia && global)) {
1727 language_options << features.getBabelLanguages();
1728 if (!language->babel().empty()) {
1729 if (!language_options.str().empty())
1730 language_options << ',';
1731 language_options << language->babel();
1733 if (global && !language_options.str().empty())
1734 clsoptions << language_options.str() << ',';
1737 // the predefined options from the layout
1738 if (use_default_options && !tclass.options().empty())
1739 clsoptions << tclass.options() << ',';
1741 // the user-defined options
1742 if (!options.empty()) {
1743 clsoptions << options << ',';
1746 docstring const strOptions = from_utf8(clsoptions.str());
1747 if (!strOptions.empty()) {
1748 // Check if class options contain uncodable glyphs
1749 docstring uncodable_glyphs;
1750 docstring options_encodable;
1751 Encoding const * const enc = features.runparams().encoding;
1753 for (char_type c : strOptions) {
1754 if (!enc->encodable(c)) {
1755 docstring const glyph(1, c);
1756 LYXERR0("Uncodable character '"
1758 << "' in class options!");
1759 uncodable_glyphs += glyph;
1760 if (features.runparams().dryrun) {
1761 options_encodable += "<" + _("LyX Warning: ")
1762 + _("uncodable character") + " '";
1763 options_encodable += c;
1764 options_encodable += "'>";
1767 options_encodable += c;
1770 options_encodable = strOptions;
1772 // On BUFFER_VIEW|UPDATE, warn user if we found uncodable glyphs
1773 if (!features.runparams().dryrun && !uncodable_glyphs.empty()) {
1774 frontend::Alert::warning(
1775 _("Uncodable character in class options"),
1777 _("The class options of your document contain glyphs "
1778 "that are unknown in the current document encoding "
1779 "(namely %1$s).\nThese glyphs are omitted "
1780 " from the output, which may result in "
1781 "incomplete output."
1782 "\n\nPlease select an appropriate "
1783 "document encoding\n"
1784 "(such as utf8) or change the "
1785 "class options accordingly."),
1788 options_encodable = rtrim(options_encodable, ",");
1789 os << '[' << options_encodable << ']';
1792 os << '{' << from_ascii(tclass.latexname()) << "}\n";
1793 // end of \documentclass defs
1795 // The package options (via \PassOptionsToPackage)
1796 os << from_ascii(features.getPackageOptions());
1798 // if we use fontspec or newtxmath, we have to load the AMS packages here
1799 string const ams = features.loadAMSPackages();
1800 bool const ot1 = (main_font_encoding() == "default" || main_font_encoding() == "OT1");
1801 bool const use_newtxmath =
1802 theLaTeXFonts().getLaTeXFont(from_ascii(fontsMath())).getUsedPackage(
1803 ot1, false, false) == "newtxmath";
1804 if ((useNonTeXFonts || use_newtxmath) && !ams.empty())
1805 os << from_ascii(ams);
1807 if (useNonTeXFonts) {
1808 // Babel (as of 2017/11/03) loads fontspec itself
1809 if (!features.isProvided("fontspec")
1810 && !(features.useBabel() && features.isAvailable("babel-2017/11/03")))
1811 os << "\\usepackage{fontspec}\n";
1812 if (features.mustProvide("unicode-math")
1813 && features.isAvailable("unicode-math"))
1814 os << "\\usepackage{unicode-math}\n";
1817 // load CJK support package before font selection
1818 // (see autotests/export/latex/CJK/micro-sign_utf8-cjk-libertine.lyx)
1819 if (!useNonTeXFonts && encoding().package() != Encoding::none && inputenc != "utf8x"
1820 && (encoding().package() == Encoding::CJK || features.mustProvide("CJK"))) {
1821 if (inputenc == "utf8-cjk" || inputenc == "utf8")
1822 os << "\\usepackage{CJKutf8}\n";
1824 os << "\\usepackage[encapsulated]{CJK}\n";
1827 // font selection must be done before loading fontenc.sty
1828 // but after babel with non-TeX fonts
1829 string const fonts = loadFonts(features);
1830 if (!fonts.empty() && (!features.useBabel() || !useNonTeXFonts))
1831 os << from_utf8(fonts);
1833 if (fonts_default_family != "default")
1834 os << "\\renewcommand{\\familydefault}{\\"
1835 << from_ascii(fonts_default_family) << "}\n";
1837 // set font encoding
1838 // non-TeX fonts use font encoding TU (set by fontspec)
1839 if (!useNonTeXFonts && !features.isProvided("fontenc")
1840 && main_font_encoding() != "default") {
1841 // get main font encodings
1842 vector<string> fontencs = font_encodings();
1843 // get font encodings of secondary languages
1844 // FIXME: some languages (hebrew, ...) assume a standard font encoding as last
1845 // option (for text in other languages).
1846 features.getFontEncodings(fontencs);
1847 if (!fontencs.empty()) {
1848 os << "\\usepackage["
1849 << from_ascii(getStringFromVector(fontencs))
1854 // Load textcomp and pmboxdraw before (lua)inputenc (#11454)
1855 if (features.mustProvide("textcomp"))
1856 os << "\\usepackage{textcomp}\n";
1857 if (features.mustProvide("pmboxdraw"))
1858 os << "\\usepackage{pmboxdraw}\n";
1860 // handle inputenc etc.
1861 // (In documents containing text in Thai language,
1862 // we must load inputenc after babel, see lib/languages).
1863 if (!contains(features.getBabelPostsettings(), from_ascii("thai.ldf")))
1864 writeEncodingPreamble(os, features);
1867 if (!features.runparams().includeall && !included_children_.empty()) {
1868 os << "\\includeonly{";
1870 for (auto incfile : included_children_) {
1871 FileName inc = makeAbsPath(incfile, filepath.absFileName());
1872 string mangled = DocFileName(changeExtension(inc.absFileName(), ".tex")).
1874 if (!features.runparams().nice)
1876 // \includeonly doesn't want an extension
1877 incfile = changeExtension(incfile, string());
1878 incfile = support::latex_path(incfile);
1879 if (!incfile.empty()) {
1882 os << from_utf8(incfile);
1889 if (!features.isProvided("geometry")
1890 && (use_geometry || !class_supported_papersize)) {
1891 odocstringstream ods;
1892 if (!getGraphicsDriver("geometry").empty())
1893 ods << getGraphicsDriver("geometry");
1894 if (orientation == ORIENTATION_LANDSCAPE)
1895 ods << ",landscape";
1896 switch (papersize) {
1898 if (!paperwidth.empty())
1899 ods << ",paperwidth="
1900 << from_ascii(paperwidth);
1901 if (!paperheight.empty())
1902 ods << ",paperheight="
1903 << from_ascii(paperheight);
1905 case PAPER_USLETTER:
1907 case PAPER_USEXECUTIVE:
1936 ods << "," << from_ascii(string_papersize_geometry[papersize]);
1941 docstring g_options = trim(ods.str(), ",");
1942 os << "\\usepackage";
1943 // geometry-light means that the class works with geometry, but overwrites
1944 // the package options and paper sizes (memoir does this).
1945 // In this case, all options need to go to \geometry
1946 // and the standard paper sizes need to go to the class options.
1947 if (!g_options.empty() && !features.isProvided("geometry-light")) {
1948 os << '[' << g_options << ']';
1951 os << "{geometry}\n";
1952 if (use_geometry || features.isProvided("geometry-light")) {
1953 os << "\\geometry{verbose";
1954 if (!g_options.empty())
1955 // Output general options here with "geometry light".
1956 os << "," << g_options;
1957 // output this only if use_geometry is true
1959 if (!topmargin.empty())
1960 os << ",tmargin=" << from_ascii(Length(topmargin).asLatexString());
1961 if (!bottommargin.empty())
1962 os << ",bmargin=" << from_ascii(Length(bottommargin).asLatexString());
1963 if (!leftmargin.empty())
1964 os << ",lmargin=" << from_ascii(Length(leftmargin).asLatexString());
1965 if (!rightmargin.empty())
1966 os << ",rmargin=" << from_ascii(Length(rightmargin).asLatexString());
1967 if (!headheight.empty())
1968 os << ",headheight=" << from_ascii(Length(headheight).asLatexString());
1969 if (!headsep.empty())
1970 os << ",headsep=" << from_ascii(Length(headsep).asLatexString());
1971 if (!footskip.empty())
1972 os << ",footskip=" << from_ascii(Length(footskip).asLatexString());
1973 if (!columnsep.empty())
1974 os << ",columnsep=" << from_ascii(Length(columnsep).asLatexString());
1978 } else if (orientation == ORIENTATION_LANDSCAPE
1979 || papersize != PAPER_DEFAULT) {
1980 features.require("papersize");
1983 if (tokenPos(tclass.opt_pagestyle(), '|', pagestyle) >= 0) {
1984 if (pagestyle == "fancy")
1985 os << "\\usepackage{fancyhdr}\n";
1986 os << "\\pagestyle{" << from_ascii(pagestyle) << "}\n";
1989 // only output when the background color is not default
1990 if (isbackgroundcolor) {
1991 // only require color here, the background color will be defined
1992 // in LaTeXFeatures.cpp to avoid interferences with the LaTeX
1994 features.require("color");
1995 features.require("pagecolor");
1998 // only output when the font color is not default
2000 // only require color here, the font color will be defined
2001 // in LaTeXFeatures.cpp to avoid interferences with the LaTeX
2003 features.require("color");
2004 features.require("fontcolor");
2007 // Only if class has a ToC hierarchy
2008 if (tclass.hasTocLevels()) {
2009 if (secnumdepth != tclass.secnumdepth()) {
2010 os << "\\setcounter{secnumdepth}{"
2014 if (tocdepth != tclass.tocdepth()) {
2015 os << "\\setcounter{tocdepth}{"
2021 if (paragraph_separation) {
2022 // when skip separation
2024 switch (getDefSkip().kind()) {
2025 case VSpace::SMALLSKIP:
2026 psopt = "\\smallskipamount";
2028 case VSpace::MEDSKIP:
2029 psopt = "\\medskipamount";
2031 case VSpace::BIGSKIP:
2032 psopt = "\\bigskipamount";
2034 case VSpace::HALFLINE:
2035 // default (no option)
2037 case VSpace::FULLLINE:
2038 psopt = "\\baselineskip";
2040 case VSpace::LENGTH:
2041 psopt = getDefSkip().length().asLatexString();
2046 if (!features.isProvided("parskip")) {
2048 psopt = "[skip=" + psopt + "]";
2049 os << "\\usepackage" + psopt + "{parskip}\n";
2051 os << "\\setlength{\\parskip}{" + psopt + "}\n";
2054 // when separation by indentation
2055 // only output something when a width is given
2056 if (!getParIndent().empty()) {
2057 os << "\\setlength{\\parindent}{"
2058 << from_utf8(getParIndent().asLatexString())
2063 if (is_math_indent) {
2064 // when formula indentation
2065 // only output something when it is not the default
2066 if (!getMathIndent().empty()) {
2067 os << "\\setlength{\\mathindent}{"
2068 << from_utf8(getMathIndent().asString())
2073 // Now insert the LyX specific LaTeX commands...
2074 features.resolveAlternatives();
2075 features.expandMultiples();
2078 if (!output_sync_macro.empty())
2079 os << from_utf8(output_sync_macro) +"\n";
2080 else if (features.runparams().flavor == Flavor::LaTeX)
2081 os << "\\usepackage[active]{srcltx}\n";
2082 else if (features.runparams().flavor == Flavor::PdfLaTeX)
2083 os << "\\synctex=-1\n";
2086 // due to interferences with babel and hyperref, the color package has to
2087 // be loaded (when it is not already loaded) before babel when hyperref
2088 // is used with the colorlinks option, see
2089 // http://www.lyx.org/trac/ticket/5291
2090 // we decided therefore to load color always before babel, see
2091 // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg144349.html
2092 os << from_ascii(features.getColorOptions());
2094 // If we use hyperref, jurabib, japanese or varioref,
2095 // we have to call babel before
2097 && (features.isRequired("jurabib")
2098 || features.isRequired("hyperref")
2099 || features.isRequired("varioref")
2100 || features.isRequired("japanese"))) {
2101 os << features.getBabelPresettings();
2103 os << from_utf8(babelCall(language_options.str(),
2104 !lyxrc.language_global_options)) + '\n';
2105 os << features.getBabelPostsettings();
2108 // The optional packages;
2109 os << from_ascii(features.getPackages());
2111 // Additional Indices
2112 if (features.isRequired("splitidx")) {
2113 for (auto const & idx : indiceslist()) {
2114 os << "\\newindex{";
2115 os << escape(idx.shortcut());
2121 os << from_utf8(spacing().writePreamble(features.isProvided("SetSpace")));
2124 // * Hyperref manual: "Make sure it comes last of your loaded
2125 // packages, to give it a fighting chance of not being over-written,
2126 // since its job is to redefine many LaTeX commands."
2127 // * Email from Heiko Oberdiek: "It is usually better to load babel
2128 // before hyperref. Then hyperref has a chance to detect babel.
2129 // * Has to be loaded before the "LyX specific LaTeX commands" to
2130 // avoid errors with algorithm floats.
2131 // use hyperref explicitly if it is required
2132 if (features.isRequired("hyperref")) {
2133 OutputParams tmp_params = features.runparams();
2134 pdfoptions().writeLaTeX(tmp_params, os,
2135 features.isProvided("hyperref"));
2136 // correctly break URLs with hyperref and dvi/ps output
2137 if (features.runparams().hyperref_driver == "dvips"
2138 && features.isAvailable("breakurl"))
2139 os << "\\usepackage{breakurl}\n";
2140 } else if (features.isRequired("nameref"))
2141 // hyperref loads this automatically
2142 os << "\\usepackage{nameref}\n";
2145 os << "\\usepackage";
2146 if (!lineno_opts.empty())
2147 os << "[" << lineno_opts << "]";
2149 os << "\\linenumbers\n";
2152 // bibtopic needs to be loaded after hyperref.
2153 // the dot provides the aux file naming which LyX can detect.
2154 if (features.mustProvide("bibtopic"))
2155 os << "\\usepackage[dot]{bibtopic}\n";
2157 // Will be surrounded by \makeatletter and \makeatother when not empty
2158 otexstringstream atlyxpreamble;
2160 // Some macros LyX will need
2162 TexString tmppreamble = features.getMacros();
2163 if (!tmppreamble.str.empty())
2164 atlyxpreamble << "\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
2165 "LyX specific LaTeX commands.\n"
2166 << move(tmppreamble)
2169 // the text class specific preamble
2171 docstring tmppreamble = features.getTClassPreamble();
2172 if (!tmppreamble.empty())
2173 atlyxpreamble << "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
2174 "Textclass specific LaTeX commands.\n"
2178 // suppress date if selected
2179 // use \@ifundefined because we cannot be sure that every document class
2180 // has a \date command
2182 atlyxpreamble << "\\@ifundefined{date}{}{\\date{}}\n";
2184 /* the user-defined preamble */
2185 if (!containsOnly(preamble, " \n\t")) {
2187 atlyxpreamble << "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
2188 "User specified LaTeX commands.\n";
2190 // Check if the user preamble contains uncodable glyphs
2191 odocstringstream user_preamble;
2192 docstring uncodable_glyphs;
2193 Encoding const * const enc = features.runparams().encoding;
2195 for (char_type c : preamble) {
2196 if (!enc->encodable(c)) {
2197 docstring const glyph(1, c);
2198 LYXERR0("Uncodable character '"
2200 << "' in user preamble!");
2201 uncodable_glyphs += glyph;
2202 if (features.runparams().dryrun) {
2203 user_preamble << "<" << _("LyX Warning: ")
2204 << _("uncodable character") << " '";
2205 user_preamble.put(c);
2206 user_preamble << "'>";
2209 user_preamble.put(c);
2212 user_preamble << preamble;
2214 // On BUFFER_VIEW|UPDATE, warn user if we found uncodable glyphs
2215 if (!features.runparams().dryrun && !uncodable_glyphs.empty()) {
2216 frontend::Alert::warning(
2217 _("Uncodable character in user preamble"),
2219 _("The user preamble of your document contains glyphs "
2220 "that are unknown in the current document encoding "
2221 "(namely %1$s).\nThese glyphs are omitted "
2222 " from the output, which may result in "
2223 "incomplete output."
2224 "\n\nPlease select an appropriate "
2225 "document encoding\n"
2226 "(such as utf8) or change the "
2227 "preamble code accordingly."),
2230 atlyxpreamble << user_preamble.str() << '\n';
2233 // footmisc must be loaded after setspace
2234 // Load it here to avoid clashes with footmisc loaded in the user
2235 // preamble. For that reason we also pass the options via
2236 // \PassOptionsToPackage in getPreamble() and not here.
2237 if (features.mustProvide("footmisc"))
2238 atlyxpreamble << "\\usepackage{footmisc}\n";
2240 // subfig loads internally the LaTeX package "caption". As
2241 // caption is a very popular package, users will load it in
2242 // the preamble. Therefore we must load subfig behind the
2243 // user-defined preamble and check if the caption package was
2244 // loaded or not. For the case that caption is loaded before
2245 // subfig, there is the subfig option "caption=false". This
2246 // option also works when a koma-script class is used and
2247 // koma's own caption commands are used instead of caption. We
2248 // use \PassOptionsToPackage here because the user could have
2249 // already loaded subfig in the preamble.
2250 if (features.mustProvide("subfig"))
2251 atlyxpreamble << "\\ifdefined\\showcaptionsetup\n"
2252 " % Caption package is used. Advise subfig not to load it again.\n"
2253 " \\PassOptionsToPackage{caption=false}{subfig}\n"
2255 "\\usepackage{subfig}\n";
2257 // Itemize bullet settings need to be last in case the user
2258 // defines their own bullets that use a package included
2259 // in the user-defined preamble -- ARRae
2260 // Actually it has to be done much later than that
2261 // since some packages like frenchb make modifications
2262 // at \begin{document} time -- JMarc
2263 docstring bullets_def;
2264 for (int i = 0; i < 4; ++i) {
2265 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
2266 if (bullets_def.empty())
2267 bullets_def += "\\AtBeginDocument{\n";
2268 bullets_def += " \\def\\labelitemi";
2270 // `i' is one less than the item to modify
2277 bullets_def += "ii";
2283 bullets_def += '{' +
2284 user_defined_bullet(i).getText()
2289 if (!bullets_def.empty())
2290 atlyxpreamble << bullets_def << "}\n\n";
2292 if (!atlyxpreamble.empty())
2293 os << "\n\\makeatletter\n"
2294 << atlyxpreamble.release()
2295 << "\\makeatother\n\n";
2297 // We try to load babel late, in case it interferes with other packages.
2298 // Jurabib, hyperref, varioref, bicaption, menukeys and listings (bug 8995)
2299 // have to be called after babel, though.
2300 if (use_babel && !features.isRequired("jurabib")
2301 && !features.isRequired("hyperref")
2302 && !features.isRequired("varioref")
2303 && !features.isRequired("japanese")) {
2304 os << features.getBabelPresettings();
2306 os << from_utf8(babelCall(language_options.str(),
2307 !lyxrc.language_global_options)) + '\n';
2308 os << features.getBabelPostsettings();
2310 // In documents containing text in Thai language,
2311 // we must load inputenc after babel (see lib/languages).
2312 if (contains(features.getBabelPostsettings(), from_ascii("thai.ldf")))
2313 writeEncodingPreamble(os, features);
2315 // font selection must be done after babel with non-TeX fonts
2316 if (!fonts.empty() && features.useBabel() && useNonTeXFonts)
2317 os << from_utf8(fonts);
2319 if (features.isRequired("bicaption"))
2320 os << "\\usepackage{bicaption}\n";
2321 if (!listings_params.empty()
2322 || features.mustProvide("listings")
2323 || features.mustProvide("minted")) {
2325 os << "\\usepackage{minted}\n";
2327 os << "\\usepackage{listings}\n";
2329 string lst_params = listings_params;
2330 // If minted, do not output the language option (bug 11203)
2331 if (use_minted && contains(lst_params, "language=")) {
2332 vector<string> opts =
2333 getVectorFromString(lst_params, ",", false);
2334 for (size_t i = 0; i < opts.size(); ++i) {
2335 if (prefixIs(opts[i], "language="))
2336 opts.erase(opts.begin() + i--);
2338 lst_params = getStringFromVector(opts, ",");
2340 if (!lst_params.empty()) {
2342 os << "\\setminted{";
2345 // do not test validity because listings_params is
2346 // supposed to be valid
2348 InsetListingsParams(lst_params).separatedParams(true);
2349 os << from_utf8(par);
2353 // xunicode only needs to be loaded if tipa is used
2354 // (the rest is obsoleted by the new TU encoding).
2355 // It needs to be loaded at least after amsmath, amssymb,
2356 // esint and the other packages that provide special glyphs
2357 if (features.mustProvide("tipa") && useNonTeXFonts
2358 && !features.isProvided("xunicode")) {
2359 // The `xunicode` package officially only supports XeTeX,
2360 // but also works with LuaTeX. We work around its XeTeX test.
2361 if (features.runparams().flavor != Flavor::XeTeX) {
2362 os << "% Pretend to xunicode that we are XeTeX\n"
2363 << "\\def\\XeTeXpicfile{}\n";
2365 os << "\\usepackage{xunicode}\n";
2368 // covington must be loaded after beamerarticle
2369 if (features.isRequired("covington"))
2370 os << "\\usepackage{covington}\n";
2372 // Polyglossia must be loaded last ...
2373 if (use_polyglossia) {
2375 os << "\\usepackage{polyglossia}\n";
2376 // set the main language
2377 os << "\\setdefaultlanguage";
2378 if (!language->polyglossiaOpts().empty())
2379 os << "[" << from_ascii(language->polyglossiaOpts()) << "]";
2380 os << "{" << from_ascii(language->polyglossia()) << "}\n";
2381 // now setup the other languages
2382 set<string> const polylangs =
2383 features.getPolyglossiaLanguages();
2384 for (auto const & pl : polylangs) {
2385 // We do not output the options here; they are output in
2386 // the language switch commands. This is safer if multiple
2387 // varieties are used.
2388 if (pl == language->polyglossia())
2390 os << "\\setotherlanguage";
2391 os << "{" << from_ascii(pl) << "}\n";
2395 // ... but before biblatex (see #7065)
2396 if ((features.mustProvide("biblatex")
2397 || features.isRequired("biblatex-chicago"))
2398 && !features.isProvided("biblatex-chicago")
2399 && !features.isProvided("biblatex-natbib")
2400 && !features.isProvided("natbib-internal")
2401 && !features.isProvided("natbib")
2402 && !features.isProvided("jurabib")) {
2403 // The biblatex-chicago package has a differing interface
2404 // it uses a wrapper package and loads styles via fixed options
2405 bool const chicago = features.isRequired("biblatex-chicago");
2408 os << "\\usepackage";
2409 if (!biblatex_bibstyle.empty()
2410 && (biblatex_bibstyle == biblatex_citestyle)
2412 opts = "style=" + biblatex_bibstyle;
2414 } else if (!chicago) {
2415 if (!biblatex_bibstyle.empty()) {
2416 opts = "bibstyle=" + biblatex_bibstyle;
2419 if (!biblatex_citestyle.empty()) {
2420 opts += delim + "citestyle=" + biblatex_citestyle;
2424 if (!multibib.empty() && multibib != "child") {
2425 opts += delim + "refsection=" + multibib;
2428 if (bibtexCommand() == "bibtex8"
2429 || prefixIs(bibtexCommand(), "bibtex8 ")) {
2430 opts += delim + "backend=bibtex8";
2432 } else if (bibtexCommand() == "bibtex"
2433 || prefixIs(bibtexCommand(), "bibtex ")) {
2434 opts += delim + "backend=bibtex";
2437 if (!bib_encoding.empty() && encodings.fromLyXName(bib_encoding)) {
2438 opts += delim + "bibencoding="
2439 + encodings.fromLyXName(bib_encoding)->latexName();
2442 if (!biblio_opts.empty())
2443 opts += delim + biblio_opts;
2445 os << "[" << opts << "]";
2447 os << "{biblatex-chicago}\n";
2449 os << "{biblatex}\n";
2453 // Load custom language package here
2454 if (features.langPackage() == LaTeXFeatures::LANG_PACK_CUSTOM) {
2455 if (lang_package == "default")
2456 os << from_utf8(lyxrc.language_custom_package);
2458 os << from_utf8(lang_package);
2462 // Since menukeys uses catoptions, which does some heavy changes on key-value options,
2463 // it is recommended to load menukeys as the last package (even after hyperref)
2464 if (features.isRequired("menukeys"))
2465 os << "\\usepackage{menukeys}\n";
2467 docstring const i18npreamble =
2468 features.getTClassI18nPreamble(use_babel, use_polyglossia,
2470 if (!i18npreamble.empty())
2471 os << i18npreamble + '\n';
2477 void BufferParams::useClassDefaults()
2479 DocumentClass const & tclass = documentClass();
2481 sides = tclass.sides();
2482 columns = tclass.columns();
2483 pagestyle = tclass.pagestyle();
2484 tablestyle = tclass.tablestyle();
2485 use_default_options = true;
2486 // Only if class has a ToC hierarchy
2487 if (tclass.hasTocLevels()) {
2488 secnumdepth = tclass.secnumdepth();
2489 tocdepth = tclass.tocdepth();
2494 bool BufferParams::hasClassDefaults() const
2496 DocumentClass const & tclass = documentClass();
2498 return sides == tclass.sides()
2499 && columns == tclass.columns()
2500 && pagestyle == tclass.pagestyle()
2501 && tablestyle == tclass.tablestyle()
2502 && use_default_options
2503 && secnumdepth == tclass.secnumdepth()
2504 && tocdepth == tclass.tocdepth();
2508 DocumentClass const & BufferParams::documentClass() const
2514 DocumentClassConstPtr BufferParams::documentClassPtr() const
2520 void BufferParams::setDocumentClass(DocumentClassConstPtr tc)
2522 // evil, but this function is evil
2523 doc_class_ = const_pointer_cast<DocumentClass>(tc);
2524 invalidateConverterCache();
2528 bool BufferParams::setBaseClass(string const & classname, string const & path)
2530 LYXERR(Debug::TCLASS, "setBaseClass: " << classname);
2531 LayoutFileList & bcl = LayoutFileList::get();
2532 if (!bcl.haveClass(classname)) {
2534 bformat(_("The layout file:\n"
2536 "could not be found. A default textclass with default\n"
2537 "layouts will be used. LyX will not be able to produce\n"
2539 from_utf8(classname));
2540 frontend::Alert::error(_("Document class not found"), s);
2541 bcl.addEmptyClass(classname);
2544 bool const success = bcl[classname].load(path);
2547 bformat(_("Due to some error in it, the layout file:\n"
2549 "could not be loaded. A default textclass with default\n"
2550 "layouts will be used. LyX will not be able to produce\n"
2552 from_utf8(classname));
2553 frontend::Alert::error(_("Could not load class"), s);
2554 bcl.addEmptyClass(classname);
2557 pimpl_->baseClass_ = classname;
2558 layout_modules_.adaptToBaseClass(baseClass(), removed_modules_);
2563 LayoutFile const * BufferParams::baseClass() const
2565 if (LayoutFileList::get().haveClass(pimpl_->baseClass_))
2566 return &(LayoutFileList::get()[pimpl_->baseClass_]);
2572 LayoutFileIndex const & BufferParams::baseClassID() const
2574 return pimpl_->baseClass_;
2578 void BufferParams::makeDocumentClass(bool clone, bool internal)
2583 invalidateConverterCache();
2584 LayoutModuleList mods;
2585 for (auto const & mod : layout_modules_)
2586 mods.push_back(mod);
2588 doc_class_ = getDocumentClass(*baseClass(), mods, cite_engine_, clone, internal);
2590 TextClass::ReturnValues success = TextClass::OK;
2591 if (!forced_local_layout_.empty())
2592 success = doc_class_->read(to_utf8(forced_local_layout_),
2594 if (!local_layout_.empty() &&
2595 (success == TextClass::OK || success == TextClass::OK_OLDFORMAT))
2596 success = doc_class_->read(to_utf8(local_layout_), TextClass::MODULE);
2597 if (success != TextClass::OK && success != TextClass::OK_OLDFORMAT) {
2598 docstring const msg = _("Error reading internal layout information");
2599 frontend::Alert::warning(_("Read Error"), msg);
2604 bool BufferParams::layoutModuleCanBeAdded(string const & modName) const
2606 return layout_modules_.moduleCanBeAdded(modName, baseClass());
2610 docstring BufferParams::getLocalLayout(bool forced) const
2613 return from_utf8(doc_class_->forcedLayouts());
2615 return local_layout_;
2619 void BufferParams::setLocalLayout(docstring const & layout, bool forced)
2622 forced_local_layout_ = layout;
2624 local_layout_ = layout;
2628 bool BufferParams::addLayoutModule(string const & modName)
2630 for (auto const & mod : layout_modules_)
2633 layout_modules_.push_back(modName);
2638 string BufferParams::bufferFormat() const
2640 return documentClass().outputFormat();
2644 bool BufferParams::isExportable(string const & format, bool need_viewable) const
2646 FormatList const & formats = exportableFormats(need_viewable);
2647 for (auto const & fmt : formats) {
2648 if (fmt->name() == format)
2655 FormatList const & BufferParams::exportableFormats(bool only_viewable) const
2657 FormatList & cached = only_viewable ?
2658 pimpl_->viewableFormatList : pimpl_->exportableFormatList;
2659 bool & valid = only_viewable ?
2660 pimpl_->isViewCacheValid : pimpl_->isExportCacheValid;
2664 vector<string> const backs = backends();
2665 set<string> excludes;
2666 if (useNonTeXFonts) {
2667 excludes.insert("latex");
2668 excludes.insert("pdflatex");
2669 } else if (inputenc != "ascii" && inputenc != "utf8-plain") {
2670 // XeTeX with TeX fonts requires input encoding ascii (#10600).
2671 excludes.insert("xetex");
2675 theConverters().getReachable(backs[0], only_viewable, true, excludes);
2676 vector<string>::const_iterator it = backs.begin() + 1;
2677 for (; it != backs.end(); ++it) {
2678 FormatList r = theConverters().getReachable(*it, only_viewable,
2680 result.insert(result.end(), r.begin(), r.end());
2682 sort(result.begin(), result.end(), Format::formatSorter);
2689 vector<string> BufferParams::backends() const
2692 string const buffmt = bufferFormat();
2694 // FIXME: Don't hardcode format names here, but use a flag
2695 if (buffmt == "latex") {
2696 if (encoding().package() == Encoding::japanese)
2697 v.push_back("platex");
2699 if (!useNonTeXFonts) {
2700 v.push_back("pdflatex");
2701 v.push_back("latex");
2704 || inputenc == "ascii" || inputenc == "utf8-plain")
2705 v.push_back("xetex");
2706 v.push_back("luatex");
2707 v.push_back("dviluatex");
2710 string rbuffmt = buffmt;
2711 // If we use an OutputFormat in Japanese docs,
2712 // we need special format in order to get the path
2713 // via pLaTeX (#8823)
2714 if (documentClass().hasOutputFormat()
2715 && encoding().package() == Encoding::japanese)
2717 v.push_back(rbuffmt);
2720 v.push_back("xhtml");
2721 v.push_back("docbook5");
2722 v.push_back("text");
2728 Flavor BufferParams::getOutputFlavor(string const & format) const
2730 string const dformat = (format.empty() || format == "default") ?
2731 getDefaultOutputFormat() : format;
2732 DefaultFlavorCache::const_iterator it =
2733 default_flavors_.find(dformat);
2735 if (it != default_flavors_.end())
2738 Flavor result = Flavor::LaTeX;
2740 // FIXME It'd be better not to hardcode this, but to do
2741 // something with formats.
2742 if (dformat == "xhtml")
2743 result = Flavor::Html;
2744 else if (dformat == "docbook5")
2745 result = Flavor::DocBook5;
2746 else if (dformat == "text")
2747 result = Flavor::Text;
2748 else if (dformat == "lyx")
2749 result = Flavor::LyX;
2750 else if (dformat == "pdflatex")
2751 result = Flavor::PdfLaTeX;
2752 else if (dformat == "xetex")
2753 result = Flavor::XeTeX;
2754 else if (dformat == "luatex")
2755 result = Flavor::LuaTeX;
2756 else if (dformat == "dviluatex")
2757 result = Flavor::DviLuaTeX;
2759 // Try to determine flavor of default output format
2760 vector<string> backs = backends();
2761 if (find(backs.begin(), backs.end(), dformat) == backs.end()) {
2762 // Get shortest path to format
2763 Graph::EdgePath path;
2764 for (auto const & bvar : backs) {
2765 Graph::EdgePath p = theConverters().getPath(bvar, dformat);
2766 if (!p.empty() && (path.empty() || p.size() < path.size())) {
2771 result = theConverters().getFlavor(path);
2774 // cache this flavor
2775 default_flavors_[dformat] = result;
2780 string BufferParams::getDefaultOutputFormat() const
2782 if (!default_output_format.empty()
2783 && default_output_format != "default")
2784 return default_output_format;
2785 if (encoding().package() == Encoding::japanese)
2786 return lyxrc.default_platex_view_format;
2788 return lyxrc.default_otf_view_format;
2789 return lyxrc.default_view_format;
2792 Font const BufferParams::getFont() const
2794 FontInfo f = documentClass().defaultfont();
2795 if (fonts_default_family == "rmdefault")
2796 f.setFamily(ROMAN_FAMILY);
2797 else if (fonts_default_family == "sfdefault")
2798 f.setFamily(SANS_FAMILY);
2799 else if (fonts_default_family == "ttdefault")
2800 f.setFamily(TYPEWRITER_FAMILY);
2801 return Font(f, language);
2805 QuoteStyle BufferParams::getQuoteStyle(string const & qs) const
2807 return quotesstyletranslator().find(qs);
2811 bool BufferParams::isLatex() const
2813 return documentClass().outputType() == LATEX;
2817 bool BufferParams::isLiterate() const
2819 return documentClass().outputType() == LITERATE;
2823 void BufferParams::readPreamble(Lexer & lex)
2825 if (lex.getString() != "\\begin_preamble")
2826 lyxerr << "Error (BufferParams::readPreamble):"
2827 "consistency check failed." << endl;
2829 preamble = lex.getLongString(from_ascii("\\end_preamble"));
2833 void BufferParams::readLocalLayout(Lexer & lex, bool forced)
2835 string const expected = forced ? "\\begin_forced_local_layout" :
2836 "\\begin_local_layout";
2837 if (lex.getString() != expected)
2838 lyxerr << "Error (BufferParams::readLocalLayout):"
2839 "consistency check failed." << endl;
2842 forced_local_layout_ =
2843 lex.getLongString(from_ascii("\\end_forced_local_layout"));
2845 local_layout_ = lex.getLongString(from_ascii("\\end_local_layout"));
2849 bool BufferParams::setLanguage(string const & lang)
2851 Language const *new_language = languages.getLanguage(lang);
2852 if (!new_language) {
2853 // Language lang was not found
2856 language = new_language;
2861 void BufferParams::readLanguage(Lexer & lex)
2863 if (!lex.next()) return;
2865 string const tmptok = lex.getString();
2867 // check if tmptok is part of tex_babel in tex-defs.h
2868 if (!setLanguage(tmptok)) {
2869 // Language tmptok was not found
2870 language = default_language;
2871 lyxerr << "Warning: Setting language `"
2872 << tmptok << "' to `" << language->lang()
2878 void BufferParams::readGraphicsDriver(Lexer & lex)
2883 string const tmptok = lex.getString();
2884 // check if tmptok is part of tex_graphics in tex_defs.h
2887 string const test = tex_graphics[n++];
2889 if (test == tmptok) {
2890 graphics_driver = tmptok;
2895 "Warning: graphics driver `$$Token' not recognized!\n"
2896 " Setting graphics driver to `default'.\n");
2897 graphics_driver = "default";
2904 void BufferParams::readBullets(Lexer & lex)
2909 int const index = lex.getInteger();
2911 int temp_int = lex.getInteger();
2912 user_defined_bullet(index).setFont(temp_int);
2913 temp_bullet(index).setFont(temp_int);
2915 user_defined_bullet(index).setCharacter(temp_int);
2916 temp_bullet(index).setCharacter(temp_int);
2918 user_defined_bullet(index).setSize(temp_int);
2919 temp_bullet(index).setSize(temp_int);
2923 void BufferParams::readBulletsLaTeX(Lexer & lex)
2925 // The bullet class should be able to read this.
2928 int const index = lex.getInteger();
2930 docstring const temp_str = lex.getDocString();
2932 user_defined_bullet(index).setText(temp_str);
2933 temp_bullet(index).setText(temp_str);
2937 void BufferParams::readModules(Lexer & lex)
2939 if (!lex.eatLine()) {
2940 lyxerr << "Error (BufferParams::readModules):"
2941 "Unexpected end of input." << endl;
2945 string mod = lex.getString();
2946 if (mod == "\\end_modules")
2948 addLayoutModule(mod);
2954 void BufferParams::readRemovedModules(Lexer & lex)
2956 if (!lex.eatLine()) {
2957 lyxerr << "Error (BufferParams::readRemovedModules):"
2958 "Unexpected end of input." << endl;
2962 string mod = lex.getString();
2963 if (mod == "\\end_removed_modules")
2965 removed_modules_.push_back(mod);
2968 // now we want to remove any removed modules that were previously
2969 // added. normally, that will be because default modules were added in
2970 // setBaseClass(), which gets called when \textclass is read at the
2971 // start of the read.
2972 for (auto const & rm : removed_modules_) {
2973 LayoutModuleList::iterator const mit = layout_modules_.begin();
2974 LayoutModuleList::iterator const men = layout_modules_.end();
2975 LayoutModuleList::iterator found = find(mit, men, rm);
2978 layout_modules_.erase(found);
2983 void BufferParams::readIncludeonly(Lexer & lex)
2985 if (!lex.eatLine()) {
2986 lyxerr << "Error (BufferParams::readIncludeonly):"
2987 "Unexpected end of input." << endl;
2991 string child = lex.getString();
2992 if (child == "\\end_includeonly")
2994 included_children_.push_back(child);
3000 string BufferParams::paperSizeName(PapersizePurpose purpose, string const & psize) const
3002 PAPER_SIZE ppsize = psize.empty() ? papersize : papersizetranslator().find(psize);
3005 if (documentClass().pagesize() == "default")
3006 // could be anything, so don't guess
3008 return paperSizeName(purpose, documentClass().pagesize());
3009 case PAPER_CUSTOM: {
3010 if (purpose == XDVI && !paperwidth.empty() &&
3011 !paperheight.empty()) {
3012 // heightxwidth<unit>
3013 string first = paperwidth;
3014 string second = paperheight;
3015 if (orientation == ORIENTATION_LANDSCAPE)
3018 return first.erase(first.length() - 2)
3024 // dvips and dvipdfm do not know this
3025 if (purpose == DVIPS || purpose == DVIPDFM)
3029 if (purpose == DVIPS || purpose == DVIPDFM)
3033 if (purpose == DVIPS || purpose == DVIPDFM)
3043 if (purpose == DVIPS || purpose == DVIPDFM)
3047 if (purpose == DVIPS || purpose == DVIPDFM)
3051 if (purpose == DVIPS || purpose == DVIPDFM)
3055 if (purpose == DVIPS || purpose == DVIPDFM)
3059 if (purpose == DVIPS || purpose == DVIPDFM)
3063 // dvipdfm does not know this
3064 if (purpose == DVIPDFM)
3068 if (purpose == DVIPDFM)
3072 if (purpose == DVIPS || purpose == DVIPDFM)
3076 if (purpose == DVIPS || purpose == DVIPDFM)
3080 if (purpose == DVIPS || purpose == DVIPDFM)
3084 if (purpose == DVIPS || purpose == DVIPDFM)
3088 if (purpose == DVIPS || purpose == DVIPDFM)
3092 if (purpose == DVIPS || purpose == DVIPDFM)
3096 if (purpose == DVIPS || purpose == DVIPDFM)
3100 if (purpose == DVIPS || purpose == DVIPDFM)
3104 if (purpose == DVIPS || purpose == DVIPDFM)
3108 if (purpose == DVIPS || purpose == DVIPDFM)
3112 if (purpose == DVIPS || purpose == DVIPDFM)
3116 if (purpose == DVIPS || purpose == DVIPDFM)
3120 if (purpose == DVIPS || purpose == DVIPDFM)
3124 if (purpose == DVIPS || purpose == DVIPDFM)
3128 if (purpose == DVIPS || purpose == DVIPDFM)
3131 case PAPER_USEXECUTIVE:
3132 // dvipdfm does not know this
3133 if (purpose == DVIPDFM)
3138 case PAPER_USLETTER:
3140 if (purpose == XDVI)
3147 string const BufferParams::dvips_options() const
3151 // If the class loads the geometry package, we do not know which
3152 // paper size is used, since we do not set it (bug 7013).
3153 // Therefore we must not specify any argument here.
3154 // dvips gets the correct paper size via DVI specials in this case
3155 // (if the class uses the geometry package correctly).
3156 if (documentClass().provides("geometry"))
3160 && papersize == PAPER_CUSTOM
3161 && !lyxrc.print_paper_dimension_flag.empty()
3162 && !paperwidth.empty()
3163 && !paperheight.empty()) {
3164 // using a custom papersize
3165 result = lyxrc.print_paper_dimension_flag;
3166 result += ' ' + paperwidth;
3167 result += ',' + paperheight;
3169 string const paper_option = paperSizeName(DVIPS);
3170 if (!paper_option.empty() && (paper_option != "letter" ||
3171 orientation != ORIENTATION_LANDSCAPE)) {
3172 // dvips won't accept -t letter -t landscape.
3173 // In all other cases, include the paper size
3175 result = lyxrc.print_paper_flag;
3176 result += ' ' + paper_option;
3179 if (orientation == ORIENTATION_LANDSCAPE &&
3180 papersize != PAPER_CUSTOM)
3181 result += ' ' + lyxrc.print_landscape_flag;
3186 string const BufferParams::main_font_encoding() const
3188 if (font_encodings().empty()) {
3189 if (ascii_lowercase(language->fontenc(*this)) == "none")
3193 return font_encodings().back();
3197 vector<string> const BufferParams::font_encodings() const
3199 string doc_fontenc = (fontenc == "auto") ? string() : fontenc;
3201 vector<string> fontencs;
3203 // "default" means "no explicit font encoding"
3204 if (doc_fontenc != "default") {
3205 if (!doc_fontenc.empty())
3206 // If we have a custom setting, we use only that!
3207 return getVectorFromString(doc_fontenc);
3208 if (!language->fontenc(*this).empty()
3209 && ascii_lowercase(language->fontenc(*this)) != "none") {
3210 vector<string> fencs = getVectorFromString(language->fontenc(*this));
3211 for (auto & fe : fencs) {
3212 if (find(fontencs.begin(), fontencs.end(), fe) == fontencs.end())
3213 fontencs.push_back(fe);
3222 string BufferParams::babelCall(string const & lang_opts, bool const langoptions) const
3224 // suppress the babel call if there is no BabelName defined
3225 // for the document language in the lib/languages file and if no
3226 // other languages are used (lang_opts is then empty)
3227 if (lang_opts.empty())
3229 // The prefs may require the languages to
3230 // be submitted to babel itself (not the class).
3232 return "\\usepackage[" + lang_opts + "]{babel}";
3233 return "\\usepackage{babel}";
3237 docstring BufferParams::getGraphicsDriver(string const & package) const
3241 if (package == "geometry") {
3242 if (graphics_driver == "dvips"
3243 || graphics_driver == "dvipdfm"
3244 || graphics_driver == "pdftex"
3245 || graphics_driver == "vtex")
3246 result = from_ascii(graphics_driver);
3247 else if (graphics_driver == "dvipdfmx")
3248 result = from_ascii("dvipdfm");
3255 void BufferParams::writeEncodingPreamble(otexstream & os,
3256 LaTeXFeatures & features) const
3258 // With no-TeX fonts we use utf8-plain without encoding package.
3262 if (inputenc == "auto-legacy") {
3263 string const doc_encoding =
3264 language->encoding()->latexName();
3265 Encoding::Package const package =
3266 language->encoding()->package();
3268 // Create list of inputenc options:
3269 set<string> encoding_set;
3270 // luainputenc fails with more than one encoding
3271 if (features.runparams().flavor != Flavor::LuaTeX
3272 && features.runparams().flavor != Flavor::DviLuaTeX)
3273 // list all input encodings used in the document
3274 encoding_set = features.getEncodingSet(doc_encoding);
3276 // The "japanese" babel-language requires the pLaTeX engine
3277 // which conflicts with "inputenc".
3278 // See http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129680.html
3279 if ((!encoding_set.empty() || package == Encoding::inputenc)
3280 && !features.isRequired("japanese")
3281 && !features.isProvided("inputenc")) {
3282 os << "\\usepackage[";
3283 set<string>::const_iterator it = encoding_set.begin();
3284 set<string>::const_iterator const end = encoding_set.end();
3286 os << from_ascii(*it);
3289 for (; it != end; ++it)
3290 os << ',' << from_ascii(*it);
3291 if (package == Encoding::inputenc) {
3292 if (!encoding_set.empty())
3294 os << from_ascii(doc_encoding);
3296 if (features.runparams().flavor == Flavor::LuaTeX
3297 || features.runparams().flavor == Flavor::DviLuaTeX)
3298 os << "]{luainputenc}\n";
3300 os << "]{inputenc}\n";
3302 } else if (inputenc != "auto-legacy-plain") {
3303 switch (encoding().package()) {
3304 case Encoding::none:
3306 case Encoding::japanese:
3307 if (encoding().iconvName() != "UTF-8"
3308 && !features.runparams().isFullUnicode())
3309 // don't default to [utf8]{inputenc} with TeXLive >= 18
3310 os << "\\ifdefined\\UseRawInputEncoding\n"
3311 << " \\UseRawInputEncoding\\fi\n";
3313 case Encoding::inputenc:
3314 // do not load inputenc if japanese is used
3315 // or if the class provides inputenc
3316 if (features.isRequired("japanese")
3317 || features.isProvided("inputenc"))
3319 os << "\\usepackage[" << from_ascii(encoding().latexName());
3320 if (features.runparams().flavor == Flavor::LuaTeX
3321 || features.runparams().flavor == Flavor::DviLuaTeX)
3322 os << "]{luainputenc}\n";
3324 os << "]{inputenc}\n";
3328 if (inputenc == "auto-legacy-plain" || features.isRequired("japanese")) {
3329 // don't default to [utf8]{inputenc} with TeXLive >= 18
3330 os << "\\ifdefined\\UseRawInputEncoding\n";
3331 os << " \\UseRawInputEncoding\\fi\n";
3336 string const BufferParams::parseFontName(string const & name) const
3338 string mangled = name;
3339 size_t const idx = mangled.find('[');
3340 if (idx == string::npos || idx == 0)
3343 return mangled.substr(0, idx - 1);
3347 string const BufferParams::loadFonts(LaTeXFeatures & features) const
3349 if (fontsRoman() == "default" && fontsSans() == "default"
3350 && fontsTypewriter() == "default"
3351 && (fontsMath() == "default" || fontsMath() == "auto"))
3357 /* Fontspec (XeTeX, LuaTeX): we provide GUI support for oldstyle
3358 * numbers (Numbers=OldStyle) and sf/tt scaling. The Ligatures=TeX/
3359 * Mapping=tex-text option assures TeX ligatures (such as "--")
3360 * are resolved. Note that tt does not use these ligatures.
3362 * -- add more GUI options?
3363 * -- add more fonts (fonts for other scripts)
3364 * -- if there's a way to find out if a font really supports
3365 * OldStyle, enable/disable the widget accordingly.
3367 if (useNonTeXFonts && features.isAvailable("fontspec")) {
3368 // "Mapping=tex-text" and "Ligatures=TeX" are equivalent.
3369 // However, until v.2 (2010/07/11) fontspec only knew
3370 // Mapping=tex-text (for XeTeX only); then "Ligatures=TeX"
3371 // was introduced for both XeTeX and LuaTeX (LuaTeX
3372 // didn't understand "Mapping=tex-text", while XeTeX
3373 // understood both. With most recent versions, both
3374 // variants are understood by both engines. However,
3375 // we want to provide support for at least TeXLive 2009
3376 // (for XeTeX; LuaTeX is only supported as of v.2)
3377 // As of 2017/11/03, Babel has its own higher-level
3378 // interface on top of fontspec that is to be used.
3379 bool const babelfonts = features.useBabel()
3380 && features.isAvailable("babel-2017/11/03");
3381 string const texmapping =
3382 (features.runparams().flavor == Flavor::XeTeX) ?
3383 "Mapping=tex-text" : "Ligatures=TeX";
3384 if (fontsRoman() != "default") {
3386 os << "\\babelfont{rm}[";
3388 os << "\\setmainfont[";
3389 if (!font_roman_opts.empty())
3390 os << font_roman_opts << ',';
3392 if (fonts_roman_osf)
3393 os << ",Numbers=OldStyle";
3394 os << "]{" << parseFontName(fontsRoman()) << "}\n";
3396 if (fontsSans() != "default") {
3397 string const sans = parseFontName(fontsSans());
3398 if (fontsSansScale() != 100) {
3400 os << "\\babelfont{sf}";
3402 os << "\\setsansfont";
3404 << float(fontsSansScale()) / 100 << ',';
3406 os << "Numbers=OldStyle,";
3407 if (!font_sans_opts.empty())
3408 os << font_sans_opts << ',';
3409 os << texmapping << "]{"
3413 os << "\\babelfont{sf}[";
3415 os << "\\setsansfont[";
3417 os << "Numbers=OldStyle,";
3418 if (!font_sans_opts.empty())
3419 os << font_sans_opts << ',';
3420 os << texmapping << "]{"
3424 if (fontsTypewriter() != "default") {
3425 string const mono = parseFontName(fontsTypewriter());
3426 if (fontsTypewriterScale() != 100) {
3428 os << "\\babelfont{tt}";
3430 os << "\\setmonofont";
3432 << float(fontsTypewriterScale()) / 100;
3433 if (fonts_typewriter_osf)
3434 os << ",Numbers=OldStyle";
3435 if (!font_typewriter_opts.empty())
3436 os << ',' << font_typewriter_opts;
3441 os << "\\babelfont{tt}";
3443 os << "\\setmonofont";
3444 if (!font_typewriter_opts.empty() || fonts_typewriter_osf) {
3446 if (fonts_typewriter_osf)
3447 os << "Numbers=OldStyle";
3448 if (!font_typewriter_opts.empty()) {
3449 if (fonts_typewriter_osf)
3451 os << font_typewriter_opts;
3455 os << '{' << mono << "}\n";
3462 bool const ot1 = (main_font_encoding() == "default" || main_font_encoding() == "OT1");
3463 bool const dryrun = features.runparams().dryrun;
3464 bool const complete = (fontsSans() == "default" && fontsTypewriter() == "default");
3465 bool const nomath = (fontsMath() != "auto");
3468 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsRoman())).getLaTeXCode(
3469 dryrun, ot1, complete, fonts_expert_sc, fonts_roman_osf,
3470 nomath, font_roman_opts);
3473 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsSans())).getLaTeXCode(
3474 dryrun, ot1, complete, fonts_expert_sc, fonts_sans_osf,
3475 nomath, font_sans_opts, fontsSansScale());
3477 // MONOSPACED/TYPEWRITER
3478 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsTypewriter())).getLaTeXCode(
3479 dryrun, ot1, complete, fonts_expert_sc, fonts_typewriter_osf,
3480 nomath, font_typewriter_opts, fontsTypewriterScale());
3483 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsMath())).getLaTeXCode(
3484 dryrun, ot1, complete, fonts_expert_sc, fonts_roman_osf,
3491 Encoding const & BufferParams::encoding() const
3493 // Main encoding for LaTeX output.
3495 return *(encodings.fromLyXName("utf8-plain"));
3496 if (inputenc == "auto-legacy" || inputenc == "auto-legacy-plain")
3497 return *language->encoding();
3498 if (inputenc == "utf8" && language->lang() == "japanese")
3499 return *(encodings.fromLyXName("utf8-platex"));
3500 Encoding const * const enc = encodings.fromLyXName(inputenc);
3503 LYXERR0("Unknown inputenc value `" << inputenc
3504 << "'. Using `auto' instead.");
3505 return *language->encoding();
3509 string const & BufferParams::defaultBiblioStyle() const
3511 if (!biblio_style.empty())
3512 return biblio_style;
3514 map<string, string> const & bs = documentClass().defaultBiblioStyle();
3515 auto cit = bs.find(theCiteEnginesList.getTypeAsString(citeEngineType()));
3516 if (cit != bs.end())
3519 return empty_string();
3523 bool BufferParams::fullAuthorList() const
3525 return documentClass().fullAuthorList();
3529 string BufferParams::getCiteAlias(string const & s) const
3531 vector<string> commands =
3532 documentClass().citeCommands(citeEngineType());
3533 // If it is a real command, don't treat it as an alias
3534 if (find(commands.begin(), commands.end(), s) != commands.end())
3536 map<string,string> aliases = documentClass().citeCommandAliases();
3537 if (aliases.find(s) != aliases.end())
3543 vector<string> BufferParams::citeCommands() const
3545 static CitationStyle const default_style;
3546 vector<string> commands =
3547 documentClass().citeCommands(citeEngineType());
3548 if (commands.empty())
3549 commands.push_back(default_style.name);
3554 vector<CitationStyle> BufferParams::citeStyles() const
3556 static CitationStyle const default_style;
3557 vector<CitationStyle> styles =
3558 documentClass().citeStyles(citeEngineType());
3560 styles.push_back(default_style);
3565 string const BufferParams::bibtexCommand() const
3567 // Return document-specific setting if available
3568 if (bibtex_command != "default")
3569 return bibtex_command;
3571 // If we have "default" in document settings, consult the prefs
3572 // 1. Japanese (uses a specific processor)
3573 if (encoding().package() == Encoding::japanese) {
3574 if (lyxrc.jbibtex_command != "automatic")
3575 // Return the specified program, if "automatic" is not set
3576 return lyxrc.jbibtex_command;
3577 else if (!useBiblatex()) {
3578 // With classic BibTeX, return pbibtex, jbibtex, bibtex
3579 if (lyxrc.jbibtex_alternatives.find("pbibtex") != lyxrc.jbibtex_alternatives.end())
3581 if (lyxrc.jbibtex_alternatives.find("jbibtex") != lyxrc.jbibtex_alternatives.end())
3586 // 2. All other languages
3587 else if (lyxrc.bibtex_command != "automatic")
3588 // Return the specified program, if "automatic" is not set
3589 return lyxrc.bibtex_command;
3591 // 3. Automatic: find the most suitable for the current cite framework
3592 if (useBiblatex()) {
3593 // For Biblatex, we prefer biber (also for Japanese)
3594 // and fall back to bibtex8 and, as last resort, bibtex
3595 if (lyxrc.bibtex_alternatives.find("biber") != lyxrc.bibtex_alternatives.end())
3597 else if (lyxrc.bibtex_alternatives.find("bibtex8") != lyxrc.bibtex_alternatives.end())
3604 bool BufferParams::useBiblatex() const
3606 return theCiteEnginesList[citeEngine()]->getCiteFramework() == "biblatex";
3610 void BufferParams::invalidateConverterCache() const
3612 pimpl_->isExportCacheValid = false;
3613 pimpl_->isViewCacheValid = false;
3617 // We shouldn't need to reset the params here, since anything
3618 // we need will be recopied.
3619 void BufferParams::copyForAdvFR(const BufferParams & bp)
3621 string const & lang = bp.language->lang();
3623 layout_modules_ = bp.layout_modules_;
3624 string const & doc_class = bp.documentClass().name();
3625 setBaseClass(doc_class);
3629 void BufferParams::setBibFileEncoding(string const & file, string const & enc)
3631 bib_encodings[file] = enc;
3635 string const BufferParams::bibFileEncoding(string const & file) const
3637 if (bib_encodings.find(file) == bib_encodings.end())
3639 return bib_encodings.find(file)->second;