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 boxbgcolor = lyx::rgbFromHexName("#ff0000");
466 compressed = lyxrc.save_compressed;
467 for (int iter = 0; iter < 4; ++iter) {
468 user_defined_bullet(iter) = ITEMIZE_DEFAULTS[iter];
469 temp_bullet(iter) = ITEMIZE_DEFAULTS[iter];
472 indiceslist().addDefault(B_("Index"));
473 html_be_strict = false;
474 html_math_output = MathML;
475 html_math_img_scale = 1.0;
476 html_css_as_file = false;
477 docbook_table_output = HTMLTable;
478 display_pixel_ratio = 1.0;
480 shell_escape = false;
486 // map current author
487 author_map_[pimpl_->authorlist.get(0).bufferId()] = 0;
491 docstring BufferParams::B_(string const & l10n) const
493 LASSERT(language, return from_utf8(l10n));
494 return getMessages(language->code()).get(l10n);
498 BufferParams::Package BufferParams::use_package(std::string const & p) const
500 PackageMap::const_iterator it = use_packages.find(p);
501 if (it == use_packages.end())
507 void BufferParams::use_package(std::string const & p, BufferParams::Package u)
513 map<string, string> const & BufferParams::auto_packages()
515 static map<string, string> packages;
516 if (packages.empty()) {
517 // We could have a race condition here that two threads
518 // discover an empty map at the same time and want to fill
519 // it, but that is no problem, since the same contents is
520 // filled in twice then. Having the locker inside the
521 // packages.empty() condition has the advantage that we
522 // don't need the mutex overhead for simple reading.
524 Mutex::Locker locker(&mutex);
525 // adding a package here implies a file format change!
526 packages["amsmath"] =
527 N_("The LaTeX package amsmath is only used if AMS formula types or symbols from the AMS math toolbars are inserted into formulas");
528 packages["amssymb"] =
529 N_("The LaTeX package amssymb is only used if symbols from the AMS math toolbars are inserted into formulas");
531 N_("The LaTeX package cancel is only used if \\cancel commands are used in formulas");
533 N_("The LaTeX package esint is only used if special integral symbols are inserted into formulas");
534 packages["mathdots"] =
535 N_("The LaTeX package mathdots is only used if the command \\iddots is inserted into formulas");
536 packages["mathtools"] =
537 N_("The LaTeX package mathtools is only used if some mathematical relations are inserted into formulas");
539 N_("The LaTeX package mhchem is only used if either the command \\ce or \\cf is inserted into formulas");
540 packages["stackrel"] =
541 N_("The LaTeX package stackrel is only used if the command \\stackrel with subscript is inserted into formulas");
542 packages["stmaryrd"] =
543 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");
544 packages["undertilde"] =
545 N_("The LaTeX package undertilde is only used if you use the math frame decoration 'utilde'");
551 bool BufferParams::useBibtopic() const
555 return (use_bibtopic || (!multibib.empty() && multibib != "child"));
559 AuthorList & BufferParams::authors()
561 return pimpl_->authorlist;
565 AuthorList const & BufferParams::authors() const
567 return pimpl_->authorlist;
571 void BufferParams::addAuthor(Author const & a)
573 author_map_[a.bufferId()] = pimpl_->authorlist.record(a);
577 BranchList & BufferParams::branchlist()
579 return pimpl_->branchlist;
583 BranchList const & BufferParams::branchlist() const
585 return pimpl_->branchlist;
589 IndicesList & BufferParams::indiceslist()
591 return pimpl_->indiceslist;
595 IndicesList const & BufferParams::indiceslist() const
597 return pimpl_->indiceslist;
601 Bullet & BufferParams::temp_bullet(lyx::size_type const index)
603 LASSERT(index < 4, return pimpl_->temp_bullets[0]);
604 return pimpl_->temp_bullets[index];
608 Bullet const & BufferParams::temp_bullet(lyx::size_type const index) const
610 LASSERT(index < 4, return pimpl_->temp_bullets[0]);
611 return pimpl_->temp_bullets[index];
615 Bullet & BufferParams::user_defined_bullet(lyx::size_type const index)
617 LASSERT(index < 4, return pimpl_->temp_bullets[0]);
618 return pimpl_->user_defined_bullets[index];
622 Bullet const & BufferParams::user_defined_bullet(lyx::size_type const index) const
624 LASSERT(index < 4, return pimpl_->temp_bullets[0]);
625 return pimpl_->user_defined_bullets[index];
629 Spacing & BufferParams::spacing()
631 return pimpl_->spacing;
635 Spacing const & BufferParams::spacing() const
637 return pimpl_->spacing;
641 PDFOptions & BufferParams::pdfoptions()
643 return pimpl_->pdfoptions;
647 PDFOptions const & BufferParams::pdfoptions() const
649 return pimpl_->pdfoptions;
653 Length const & BufferParams::getMathIndent() const
655 return pimpl_->mathindent;
659 void BufferParams::setMathIndent(Length const & indent)
661 pimpl_->mathindent = indent;
665 Length const & BufferParams::getParIndent() const
667 return pimpl_->parindent;
671 void BufferParams::setParIndent(Length const & indent)
673 pimpl_->parindent = indent;
677 VSpace const & BufferParams::getDefSkip() const
679 return pimpl_->defskip;
683 void BufferParams::setDefSkip(VSpace const & vs)
685 // DEFSKIP will cause an infinite loop
686 LASSERT(vs.kind() != VSpace::DEFSKIP, return);
687 pimpl_->defskip = vs;
691 BufferParams::MathNumber BufferParams::getMathNumber() const
693 if (math_numbering_side != DEFAULT)
694 return math_numbering_side;
695 // FIXME: do not hardcode language here
696 else if (language->lang() == "arabic_arabi"
697 || documentClass().provides("leqno"))
704 string BufferParams::readToken(Lexer & lex, string const & token,
705 FileName const & filepath)
709 if (token == "\\textclass") {
711 string const classname = lex.getString();
712 // if there exists a local layout file, ignore the system one
713 // NOTE: in this case, the textclass (.cls file) is assumed to
716 LayoutFileList & bcl = LayoutFileList::get();
717 if (!filepath.empty()) {
718 // If classname is an absolute path, the document is
719 // using a local layout file which could not be accessed
720 // by a relative path. In this case the path is correct
721 // even if the document was moved to a different
722 // location. However, we will have a problem if the
723 // document was generated on a different platform.
724 bool isabsolute = FileName::isAbsolute(classname);
725 string const classpath = onlyPath(classname);
726 string const path = isabsolute ? classpath
727 : FileName(addPath(filepath.absFileName(),
728 classpath)).realPath();
729 string const oldpath = isabsolute ? string()
730 : FileName(addPath(origin, classpath)).realPath();
731 tcp = bcl.addLocalLayout(onlyFileName(classname), path, oldpath);
733 // that returns non-empty if a "local" layout file is found.
735 result = to_utf8(makeRelPath(from_utf8(onlyPath(tcp)),
736 from_utf8(filepath.absFileName())));
739 setBaseClass(onlyFileName(tcp));
741 setBaseClass(onlyFileName(classname));
742 // We assume that a tex class exists for local or unknown
743 // layouts so this warning, will only be given for system layouts.
744 if (!baseClass()->isTeXClassAvailable()) {
745 docstring const desc =
746 translateIfPossible(from_utf8(baseClass()->description()));
747 docstring const prereqs =
748 from_utf8(baseClass()->prerequisites());
749 docstring const msg =
750 bformat(_("The selected document class\n"
752 "requires external files that are not available.\n"
753 "The document class can still be used, but the\n"
754 "document cannot be compiled until the following\n"
755 "prerequisites are installed:\n"
757 "See section 3.1.2.2 (Class Availability) of the\n"
758 "User's Guide for more information."), desc, prereqs);
759 frontend::Alert::warning(_("Document class not available"),
762 } else if (token == "\\save_transient_properties") {
763 lex >> save_transient_properties;
764 } else if (token == "\\origin") {
766 origin = lex.getString();
767 string const sysdirprefix = "/systemlyxdir/";
768 if (prefixIs(origin, sysdirprefix)) {
770 if (inSystemDir(filepath, docsys))
771 origin.replace(0, sysdirprefix.length() - 1, docsys);
773 origin.replace(0, sysdirprefix.length() - 1,
774 package().system_support().absFileName());
776 } else if (token == "\\begin_preamble") {
778 } else if (token == "\\begin_local_layout") {
779 readLocalLayout(lex, false);
780 } else if (token == "\\begin_forced_local_layout") {
781 readLocalLayout(lex, true);
782 } else if (token == "\\begin_modules") {
784 } else if (token == "\\begin_removed_modules") {
785 readRemovedModules(lex);
786 } else if (token == "\\begin_includeonly") {
787 readIncludeonly(lex);
788 } else if (token == "\\maintain_unincluded_children") {
792 maintain_unincluded_children = CM_None;
793 else if (tmp == "mostly")
794 maintain_unincluded_children = CM_Mostly;
795 else if (tmp == "strict")
796 maintain_unincluded_children = CM_Strict;
797 } else if (token == "\\options") {
799 options = lex.getString();
800 } else if (token == "\\use_default_options") {
801 lex >> use_default_options;
802 } else if (token == "\\master") {
804 master = lex.getString();
805 if (!filepath.empty() && FileName::isAbsolute(origin)) {
806 bool const isabs = FileName::isAbsolute(master);
807 FileName const abspath(isabs ? master : origin + master);
808 bool const moved = filepath != FileName(origin);
809 if (moved && abspath.exists()) {
810 docstring const path = isabs
812 : from_utf8(abspath.realPath());
813 docstring const refpath =
814 from_utf8(filepath.absFileName());
815 master = to_utf8(makeRelPath(path, refpath));
818 } else if (token == "\\suppress_date") {
819 lex >> suppress_date;
820 } else if (token == "\\justification") {
821 lex >> justification;
822 } else if (token == "\\language") {
824 } else if (token == "\\language_package") {
826 lang_package = lex.getString();
827 } else if (token == "\\inputencoding") {
829 } else if (token == "\\graphics") {
830 readGraphicsDriver(lex);
831 } else if (token == "\\default_output_format") {
832 lex >> default_output_format;
833 } else if (token == "\\bibtex_command") {
835 bibtex_command = lex.getString();
836 } else if (token == "\\index_command") {
838 index_command = lex.getString();
839 } else if (token == "\\fontencoding") {
841 fontenc = lex.getString();
842 } else if (token == "\\font_roman") {
843 lex >> fonts_roman[0];
844 lex >> fonts_roman[1];
845 } else if (token == "\\font_sans") {
846 lex >> fonts_sans[0];
847 lex >> fonts_sans[1];
848 } else if (token == "\\font_typewriter") {
849 lex >> fonts_typewriter[0];
850 lex >> fonts_typewriter[1];
851 } else if (token == "\\font_math") {
852 lex >> fonts_math[0];
853 lex >> fonts_math[1];
854 } else if (token == "\\font_default_family") {
855 lex >> fonts_default_family;
856 } else if (token == "\\use_non_tex_fonts") {
857 lex >> useNonTeXFonts;
858 } else if (token == "\\font_sc") {
859 lex >> fonts_expert_sc;
860 } else if (token == "\\font_roman_osf") {
861 lex >> fonts_roman_osf;
862 } else if (token == "\\font_sans_osf") {
863 lex >> fonts_sans_osf;
864 } else if (token == "\\font_typewriter_osf") {
865 lex >> fonts_typewriter_osf;
866 } else if (token == "\\font_roman_opts") {
867 lex >> font_roman_opts;
868 } else if (token == "\\font_sf_scale") {
869 lex >> fonts_sans_scale[0];
870 lex >> fonts_sans_scale[1];
871 } else if (token == "\\font_sans_opts") {
872 lex >> font_sans_opts;
873 } else if (token == "\\font_tt_scale") {
874 lex >> fonts_typewriter_scale[0];
875 lex >> fonts_typewriter_scale[1];
876 } else if (token == "\\font_typewriter_opts") {
877 lex >> font_typewriter_opts;
878 } else if (token == "\\font_cjk") {
880 } else if (token == "\\use_microtype") {
881 lex >> use_microtype;
882 } else if (token == "\\use_dash_ligatures") {
883 lex >> use_dash_ligatures;
884 } else if (token == "\\paragraph_separation") {
887 paragraph_separation = parseptranslator().find(parsep);
888 } else if (token == "\\paragraph_indentation") {
890 string parindent = lex.getString();
891 if (parindent == "default")
892 pimpl_->parindent = Length();
894 pimpl_->parindent = Length(parindent);
895 } else if (token == "\\defskip") {
897 string const defskip = lex.getString();
898 pimpl_->defskip = VSpace(defskip);
899 if (pimpl_->defskip.kind() == VSpace::DEFSKIP)
901 pimpl_->defskip = VSpace(VSpace::MEDSKIP);
902 } else if (token == "\\is_math_indent") {
903 lex >> is_math_indent;
904 } else if (token == "\\math_indentation") {
906 string mathindent = lex.getString();
907 if (mathindent == "default")
908 pimpl_->mathindent = Length();
910 pimpl_->mathindent = Length(mathindent);
911 } else if (token == "\\math_numbering_side") {
915 math_numbering_side = LEFT;
916 else if (tmp == "right")
917 math_numbering_side = RIGHT;
919 math_numbering_side = DEFAULT;
920 } else if (token == "\\quotes_style") {
923 quotes_style = quotesstyletranslator().find(qstyle);
924 } else if (token == "\\dynamic_quotes") {
925 lex >> dynamic_quotes;
926 } else if (token == "\\papersize") {
929 papersize = papersizetranslator().find(ppsize);
930 } else if (token == "\\use_geometry") {
932 } else if (token == "\\use_package") {
937 use_package(package, packagetranslator().find(use));
938 } else if (token == "\\cite_engine") {
940 cite_engine_ = lex.getString();
941 } else if (token == "\\cite_engine_type") {
944 cite_engine_type_ = theCiteEnginesList.getType(engine_type);
945 } else if (token == "\\biblio_style") {
947 biblio_style = lex.getString();
948 } else if (token == "\\biblio_options") {
950 biblio_opts = trim(lex.getString());
951 } else if (token == "\\biblatex_bibstyle") {
953 biblatex_bibstyle = trim(lex.getString());
954 } else if (token == "\\biblatex_citestyle") {
956 biblatex_citestyle = trim(lex.getString());
957 } else if (token == "\\use_bibtopic") {
959 } else if (token == "\\multibib") {
961 } else if (token == "\\use_indices") {
963 } else if (token == "\\tracking_changes") {
964 lex >> track_changes;
965 } else if (token == "\\output_changes") {
966 lex >> output_changes;
967 } else if (token == "\\change_bars") {
969 } else if (token == "\\postpone_fragile_content") {
970 lex >> postpone_fragile_content;
971 } else if (token == "\\branch") {
973 docstring branch = lex.getDocString();
974 branchlist().add(branch);
977 string const tok = lex.getString();
978 if (tok == "\\end_branch")
980 Branch * branch_ptr = branchlist().find(branch);
981 if (tok == "\\selected") {
984 branch_ptr->setSelected(lex.getInteger());
986 if (tok == "\\filename_suffix") {
989 branch_ptr->setFileNameSuffix(lex.getInteger());
991 if (tok == "\\color") {
993 string color = lex.getString();
995 branch_ptr->setColor(color);
996 if (branch_ptr->color() == "none")
997 color = lcolor.getX11HexName(Color_background);
999 // Update also the Color table:
1000 if (color == "none")
1001 color = lcolor.getX11HexName(Color_background);
1002 else if (color.size() != 7 || color[0] != '#')
1003 color = lcolor.getFromLyXName(color);
1005 lcolor.setColor(to_utf8(branch), color);
1008 } else if (token == "\\index") {
1010 docstring index = lex.getDocString();
1012 indiceslist().add(index);
1015 string const tok = lex.getString();
1016 if (tok == "\\end_index")
1018 Index * index_ptr = indiceslist().find(index);
1019 if (tok == "\\shortcut") {
1021 shortcut = lex.getDocString();
1023 index_ptr->setShortcut(shortcut);
1025 if (tok == "\\color") {
1027 string color = lex.getString();
1029 index_ptr->setColor(color);
1030 // Update also the Color table:
1031 if (color == "none")
1032 color = lcolor.getX11HexName(Color_background);
1034 if (!shortcut.empty())
1035 lcolor.setColor(to_utf8(shortcut), color);
1038 } else if (token == "\\author") {
1040 istringstream ss(lex.getString());
1044 } else if (token == "\\paperorientation") {
1047 orientation = paperorientationtranslator().find(orient);
1048 } else if (token == "\\backgroundcolor") {
1050 backgroundcolor = lyx::rgbFromHexName(lex.getString());
1051 isbackgroundcolor = true;
1052 } else if (token == "\\fontcolor") {
1054 fontcolor = lyx::rgbFromHexName(lex.getString());
1056 } else if (token == "\\notefontcolor") {
1058 string color = lex.getString();
1059 notefontcolor = lyx::rgbFromHexName(color);
1060 lcolor.setColor("notefontcolor", color);
1061 } else if (token == "\\boxbgcolor") {
1063 string color = lex.getString();
1064 boxbgcolor = lyx::rgbFromHexName(color);
1065 lcolor.setColor("boxbgcolor", color);
1066 } else if (token == "\\paperwidth") {
1068 } else if (token == "\\paperheight") {
1070 } else if (token == "\\leftmargin") {
1072 } else if (token == "\\topmargin") {
1074 } else if (token == "\\rightmargin") {
1076 } else if (token == "\\bottommargin") {
1077 lex >> bottommargin;
1078 } else if (token == "\\headheight") {
1080 } else if (token == "\\headsep") {
1082 } else if (token == "\\footskip") {
1084 } else if (token == "\\columnsep") {
1086 } else if (token == "\\paperfontsize") {
1088 } else if (token == "\\papercolumns") {
1090 } else if (token == "\\listings_params") {
1093 listings_params = InsetListingsParams(par).params();
1094 } else if (token == "\\papersides") {
1097 sides = sidestranslator().find(psides);
1098 } else if (token == "\\paperpagestyle") {
1100 } else if (token == "\\tablestyle") {
1102 } else if (token == "\\bullet") {
1104 } else if (token == "\\bulletLaTeX") {
1105 readBulletsLaTeX(lex);
1106 } else if (token == "\\secnumdepth") {
1108 } else if (token == "\\tocdepth") {
1110 } else if (token == "\\spacing") {
1114 if (nspacing == "other") {
1117 spacing().set(spacetranslator().find(nspacing), tmp_val);
1118 } else if (token == "\\float_placement") {
1119 lex >> float_placement;
1120 } else if (token == "\\float_alignment") {
1121 lex >> float_alignment;
1123 } else if (prefixIs(token, "\\pdf_") || token == "\\use_hyperref") {
1124 string toktmp = pdfoptions().readToken(lex, token);
1125 if (!toktmp.empty()) {
1126 lyxerr << "PDFOptions::readToken(): Unknown token: " <<
1130 } else if (token == "\\html_math_output") {
1133 html_math_output = static_cast<MathOutput>(temp);
1134 } else if (token == "\\html_be_strict") {
1135 lex >> html_be_strict;
1136 } else if (token == "\\html_css_as_file") {
1137 lex >> html_css_as_file;
1138 } else if (token == "\\html_math_img_scale") {
1139 lex >> html_math_img_scale;
1140 } else if (token == "\\html_latex_start") {
1142 html_latex_start = lex.getString();
1143 } else if (token == "\\html_latex_end") {
1145 html_latex_end = lex.getString();
1146 } else if (token == "\\docbook_table_output") {
1149 docbook_table_output = static_cast<TableOutput>(temp);
1150 } else if (token == "\\output_sync") {
1152 } else if (token == "\\output_sync_macro") {
1153 lex >> output_sync_macro;
1154 } else if (token == "\\use_refstyle") {
1155 lex >> use_refstyle;
1156 } else if (token == "\\use_minted") {
1158 } else if (token == "\\use_lineno") {
1160 } else if (token == "\\lineno_options") {
1162 lineno_opts = trim(lex.getString());
1164 lyxerr << "BufferParams::readToken(): Unknown token: " <<
1174 // Quote argument if it contains spaces
1175 string quoteIfNeeded(string const & str) {
1176 if (contains(str, ' '))
1177 return "\"" + str + "\"";
1183 void BufferParams::writeFile(ostream & os, Buffer const * buf) const
1185 // The top of the file is written by the buffer.
1186 // Prints out the buffer info into the .lyx file given by file
1188 os << "\\save_transient_properties "
1189 << convert<string>(save_transient_properties) << '\n';
1191 // the document directory (must end with a path separator)
1192 // realPath() is used to resolve symlinks, while addPath(..., "")
1193 // ensures a trailing path separator.
1195 string filepath = addPath(buf->fileName().onlyPath().realPath(), "");
1196 string const sysdir = inSystemDir(FileName(filepath), docsys) ? docsys
1197 : addPath(package().system_support().realPath(), "");
1198 string const relpath =
1199 to_utf8(makeRelPath(from_utf8(filepath), from_utf8(sysdir)));
1200 if (!prefixIs(relpath, "../") && !FileName::isAbsolute(relpath))
1201 filepath = addPath("/systemlyxdir", relpath);
1202 else if (!save_transient_properties || !lyxrc.save_origin)
1203 filepath = "unavailable";
1204 os << "\\origin " << quoteIfNeeded(filepath) << '\n';
1207 os << "\\textclass "
1208 << quoteIfNeeded(buf->includedFilePath(addName(buf->layoutPos(),
1209 baseClass()->name()), "layout"))
1212 // then the preamble
1213 if (!preamble.empty()) {
1214 // remove '\n' from the end of preamble
1215 docstring const tmppreamble = rtrim(preamble, "\n");
1216 os << "\\begin_preamble\n"
1217 << to_utf8(tmppreamble)
1218 << "\n\\end_preamble\n";
1222 if (!options.empty()) {
1223 os << "\\options " << options << '\n';
1226 // use the class options defined in the layout?
1227 os << "\\use_default_options "
1228 << convert<string>(use_default_options) << "\n";
1230 // the master document
1231 if (!master.empty()) {
1232 os << "\\master " << master << '\n';
1236 if (!removed_modules_.empty()) {
1237 os << "\\begin_removed_modules" << '\n';
1238 for (auto const & mod : removed_modules_)
1240 os << "\\end_removed_modules" << '\n';
1244 if (!layout_modules_.empty()) {
1245 os << "\\begin_modules" << '\n';
1246 for (auto const & mod : layout_modules_)
1248 os << "\\end_modules" << '\n';
1252 if (!included_children_.empty()) {
1253 os << "\\begin_includeonly" << '\n';
1254 for (auto const & c : included_children_)
1256 os << "\\end_includeonly" << '\n';
1259 switch (maintain_unincluded_children) {
1270 os << "\\maintain_unincluded_children " << muc << '\n';
1272 // local layout information
1273 docstring const local_layout = getLocalLayout(false);
1274 if (!local_layout.empty()) {
1275 // remove '\n' from the end
1276 docstring const tmplocal = rtrim(local_layout, "\n");
1277 os << "\\begin_local_layout\n"
1278 << to_utf8(tmplocal)
1279 << "\n\\end_local_layout\n";
1281 docstring const forced_local_layout = getLocalLayout(true);
1282 if (!forced_local_layout.empty()) {
1283 // remove '\n' from the end
1284 docstring const tmplocal = rtrim(forced_local_layout, "\n");
1285 os << "\\begin_forced_local_layout\n"
1286 << to_utf8(tmplocal)
1287 << "\n\\end_forced_local_layout\n";
1290 // then the text parameters
1291 if (language != ignore_language)
1292 os << "\\language " << language->lang() << '\n';
1293 os << "\\language_package " << lang_package
1294 << "\n\\inputencoding " << inputenc
1295 << "\n\\fontencoding " << fontenc
1296 << "\n\\font_roman \"" << fonts_roman[0]
1297 << "\" \"" << fonts_roman[1] << '"'
1298 << "\n\\font_sans \"" << fonts_sans[0]
1299 << "\" \"" << fonts_sans[1] << '"'
1300 << "\n\\font_typewriter \"" << fonts_typewriter[0]
1301 << "\" \"" << fonts_typewriter[1] << '"'
1302 << "\n\\font_math \"" << fonts_math[0]
1303 << "\" \"" << fonts_math[1] << '"'
1304 << "\n\\font_default_family " << fonts_default_family
1305 << "\n\\use_non_tex_fonts " << convert<string>(useNonTeXFonts)
1306 << "\n\\font_sc " << convert<string>(fonts_expert_sc)
1307 << "\n\\font_roman_osf " << convert<string>(fonts_roman_osf)
1308 << "\n\\font_sans_osf " << convert<string>(fonts_sans_osf)
1309 << "\n\\font_typewriter_osf " << convert<string>(fonts_typewriter_osf);
1310 if (!font_roman_opts.empty())
1311 os << "\n\\font_roman_opts \"" << font_roman_opts << "\"";
1312 os << "\n\\font_sf_scale " << fonts_sans_scale[0]
1313 << ' ' << fonts_sans_scale[1];
1314 if (!font_sans_opts.empty())
1315 os << "\n\\font_sans_opts \"" << font_sans_opts << "\"";
1316 os << "\n\\font_tt_scale " << fonts_typewriter_scale[0]
1317 << ' ' << fonts_typewriter_scale[1];
1318 if (!font_typewriter_opts.empty())
1319 os << "\n\\font_typewriter_opts \"" << font_typewriter_opts << "\"";
1321 if (!fonts_cjk.empty())
1322 os << "\\font_cjk " << fonts_cjk << '\n';
1323 os << "\\use_microtype " << convert<string>(use_microtype) << '\n';
1324 os << "\\use_dash_ligatures " << convert<string>(use_dash_ligatures) << '\n';
1325 os << "\\graphics " << graphics_driver << '\n';
1326 os << "\\default_output_format " << default_output_format << '\n';
1327 os << "\\output_sync " << output_sync << '\n';
1328 if (!output_sync_macro.empty())
1329 os << "\\output_sync_macro \"" << output_sync_macro << "\"\n";
1330 os << "\\bibtex_command " << bibtex_command << '\n';
1331 os << "\\index_command " << index_command << '\n';
1333 if (!float_placement.empty())
1334 os << "\\float_placement " << float_placement << '\n';
1335 if (!float_alignment.empty())
1336 os << "\\float_alignment " << float_alignment << '\n';
1337 os << "\\paperfontsize " << fontsize << '\n';
1339 spacing().writeFile(os);
1340 pdfoptions().writeFile(os);
1342 os << "\\papersize " << string_papersize[papersize]
1343 << "\n\\use_geometry " << convert<string>(use_geometry);
1344 map<string, string> const & packages = auto_packages();
1345 for (auto const & pack : packages)
1346 os << "\n\\use_package " << pack.first << ' '
1347 << use_package(pack.first);
1349 os << "\n\\cite_engine ";
1351 if (!cite_engine_.empty())
1356 os << "\n\\cite_engine_type " << theCiteEnginesList.getTypeAsString(cite_engine_type_);
1358 if (!biblio_style.empty())
1359 os << "\n\\biblio_style " << biblio_style;
1360 if (!biblio_opts.empty())
1361 os << "\n\\biblio_options " << biblio_opts;
1362 if (!biblatex_bibstyle.empty())
1363 os << "\n\\biblatex_bibstyle " << biblatex_bibstyle;
1364 if (!biblatex_citestyle.empty())
1365 os << "\n\\biblatex_citestyle " << biblatex_citestyle;
1366 if (!multibib.empty())
1367 os << "\n\\multibib " << multibib;
1369 os << "\n\\use_bibtopic " << convert<string>(use_bibtopic)
1370 << "\n\\use_indices " << convert<string>(use_indices)
1371 << "\n\\paperorientation " << string_orientation[orientation]
1372 << "\n\\suppress_date " << convert<string>(suppress_date)
1373 << "\n\\justification " << convert<string>(justification)
1374 << "\n\\use_refstyle " << use_refstyle
1375 << "\n\\use_minted " << use_minted
1376 << "\n\\use_lineno " << use_lineno
1379 if (!lineno_opts.empty())
1380 os << "\\lineno_options " << lineno_opts << '\n';
1382 if (isbackgroundcolor)
1383 os << "\\backgroundcolor " << lyx::X11hexname(backgroundcolor) << '\n';
1385 os << "\\fontcolor " << lyx::X11hexname(fontcolor) << '\n';
1386 if (notefontcolor != lyx::rgbFromHexName("#cccccc"))
1387 os << "\\notefontcolor " << lyx::X11hexname(notefontcolor) << '\n';
1388 if (boxbgcolor != lyx::rgbFromHexName("#ff0000"))
1389 os << "\\boxbgcolor " << lyx::X11hexname(boxbgcolor) << '\n';
1391 for (auto const & br : branchlist()) {
1392 os << "\\branch " << to_utf8(br.branch())
1393 << "\n\\selected " << br.isSelected()
1394 << "\n\\filename_suffix " << br.hasFileNameSuffix()
1395 << "\n\\color " << br.color()
1400 for (auto const & id : indiceslist()) {
1401 os << "\\index " << to_utf8(id.index())
1402 << "\n\\shortcut " << to_utf8(id.shortcut())
1403 << "\n\\color " << lyx::X11hexname(id.color())
1408 if (!paperwidth.empty())
1409 os << "\\paperwidth "
1410 << VSpace(paperwidth).asLyXCommand() << '\n';
1411 if (!paperheight.empty())
1412 os << "\\paperheight "
1413 << VSpace(paperheight).asLyXCommand() << '\n';
1414 if (!leftmargin.empty())
1415 os << "\\leftmargin "
1416 << VSpace(leftmargin).asLyXCommand() << '\n';
1417 if (!topmargin.empty())
1418 os << "\\topmargin "
1419 << VSpace(topmargin).asLyXCommand() << '\n';
1420 if (!rightmargin.empty())
1421 os << "\\rightmargin "
1422 << VSpace(rightmargin).asLyXCommand() << '\n';
1423 if (!bottommargin.empty())
1424 os << "\\bottommargin "
1425 << VSpace(bottommargin).asLyXCommand() << '\n';
1426 if (!headheight.empty())
1427 os << "\\headheight "
1428 << VSpace(headheight).asLyXCommand() << '\n';
1429 if (!headsep.empty())
1431 << VSpace(headsep).asLyXCommand() << '\n';
1432 if (!footskip.empty())
1434 << VSpace(footskip).asLyXCommand() << '\n';
1435 if (!columnsep.empty())
1436 os << "\\columnsep "
1437 << VSpace(columnsep).asLyXCommand() << '\n';
1438 os << "\\secnumdepth " << secnumdepth
1439 << "\n\\tocdepth " << tocdepth
1440 << "\n\\paragraph_separation "
1441 << string_paragraph_separation[paragraph_separation];
1442 if (!paragraph_separation)
1443 os << "\n\\paragraph_indentation "
1444 << (getParIndent().empty() ? "default" : getParIndent().asString());
1446 os << "\n\\defskip " << getDefSkip().asLyXCommand();
1447 os << "\n\\is_math_indent " << is_math_indent;
1449 os << "\n\\math_indentation "
1450 << (getMathIndent().empty() ? "default" : getMathIndent().asString());
1451 os << "\n\\math_numbering_side ";
1452 switch(math_numbering_side) {
1462 os << "\n\\quotes_style "
1463 << string_quotes_style[static_cast<int>(quotes_style)]
1464 << "\n\\dynamic_quotes " << dynamic_quotes
1465 << "\n\\papercolumns " << columns
1466 << "\n\\papersides " << sides
1467 << "\n\\paperpagestyle " << pagestyle
1468 << "\n\\tablestyle " << tablestyle << '\n';
1469 if (!listings_params.empty())
1470 os << "\\listings_params \"" <<
1471 InsetListingsParams(listings_params).encodedString() << "\"\n";
1472 for (int i = 0; i < 4; ++i) {
1473 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
1474 if (user_defined_bullet(i).getFont() != -1) {
1475 os << "\\bullet " << i << " "
1476 << user_defined_bullet(i).getFont() << " "
1477 << user_defined_bullet(i).getCharacter() << " "
1478 << user_defined_bullet(i).getSize() << "\n";
1482 os << "\\bulletLaTeX " << i << " \""
1483 << lyx::to_ascii(user_defined_bullet(i).getText())
1489 os << "\\tracking_changes "
1490 << (save_transient_properties ? convert<string>(track_changes) : "false")
1493 os << "\\output_changes "
1494 << (save_transient_properties ? convert<string>(output_changes) : "false")
1497 os << "\\change_bars "
1498 << (save_transient_properties ? convert<string>(change_bars) : "false")
1501 os << "\\postpone_fragile_content " << convert<string>(postpone_fragile_content) << '\n';
1503 os << "\\html_math_output " << html_math_output << '\n'
1504 << "\\html_css_as_file " << html_css_as_file << '\n'
1505 << "\\html_be_strict " << convert<string>(html_be_strict) << '\n';
1507 os << "\\docbook_table_output " << docbook_table_output << '\n';
1509 if (html_math_img_scale != 1.0)
1510 os << "\\html_math_img_scale " << convert<string>(html_math_img_scale) << '\n';
1511 if (!html_latex_start.empty())
1512 os << "\\html_latex_start " << html_latex_start << '\n';
1513 if (!html_latex_end.empty())
1514 os << "\\html_latex_end " << html_latex_end << '\n';
1516 os << pimpl_->authorlist;
1520 void BufferParams::validate(LaTeXFeatures & features) const
1522 features.require(documentClass().required());
1524 if (columns > 1 && language->rightToLeft())
1525 features.require("rtloutputdblcol");
1527 if (output_changes) {
1528 bool xcolorulem = LaTeXFeatures::isAvailable("ulem") &&
1529 LaTeXFeatures::isAvailable("xcolor");
1531 switch (features.runparams().flavor) {
1533 case Flavor::DviLuaTeX:
1535 features.require("ct-xcolor-ulem");
1536 features.require("ulem");
1537 features.require("xcolor");
1539 features.require("ct-none");
1542 case Flavor::LuaTeX:
1543 case Flavor::PdfLaTeX:
1546 features.require("ct-xcolor-ulem");
1547 features.require("ulem");
1548 features.require("xcolor");
1549 // improves color handling in PDF output
1550 features.require("pdfcolmk");
1552 features.require("ct-none");
1559 features.require("changebar");
1562 // Floats with 'Here definitely' as default setting.
1563 if (float_placement.find('H') != string::npos)
1564 features.require("float");
1566 for (auto const & pm : use_packages) {
1567 if (pm.first == "amsmath") {
1568 // AMS Style is at document level
1569 if (pm.second == package_on ||
1570 features.isProvided("amsmath"))
1571 features.require(pm.first);
1572 } else if (pm.second == package_on)
1573 features.require(pm.first);
1576 // Document-level line spacing
1577 if (spacing().getSpace() != Spacing::Single && !spacing().isDefault())
1578 features.require("setspace");
1580 // the bullet shapes are buffer level not paragraph level
1581 // so they are tested here
1582 for (int i = 0; i < 4; ++i) {
1583 if (user_defined_bullet(i) == ITEMIZE_DEFAULTS[i])
1585 int const font = user_defined_bullet(i).getFont();
1587 int const c = user_defined_bullet(i).getCharacter();
1593 features.require("latexsym");
1595 } else if (font == 1) {
1596 features.require("amssymb");
1597 } else if (font >= 2 && font <= 5) {
1598 features.require("pifont");
1602 if (pdfoptions().use_hyperref) {
1603 features.require("hyperref");
1604 // due to interferences with babel and hyperref, the color package has to
1605 // be loaded after hyperref when hyperref is used with the colorlinks
1606 // option, see http://www.lyx.org/trac/ticket/5291
1607 if (pdfoptions().colorlinks)
1608 features.require("color");
1610 if (!listings_params.empty()) {
1611 // do not test validity because listings_params is
1612 // supposed to be valid
1614 InsetListingsParams(listings_params).separatedParams(true);
1615 // we can't support all packages, but we should load the color package
1616 if (par.find("\\color", 0) != string::npos)
1617 features.require("color");
1620 // some languages are only available via polyglossia
1621 if (features.hasPolyglossiaExclusiveLanguages())
1622 features.require("polyglossia");
1624 if (useNonTeXFonts && fontsMath() != "auto")
1625 features.require("unicode-math");
1628 features.require("microtype");
1630 if (!language->required().empty())
1631 features.require(language->required());
1635 bool BufferParams::writeLaTeX(otexstream & os, LaTeXFeatures & features,
1636 FileName const & filepath) const
1638 // http://www.tug.org/texmf-dist/doc/latex/base/fixltx2e.pdf
1639 // !! To use the Fix-cm package, load it before \documentclass, and use the command
1640 // \RequirePackage to do so, rather than the normal \usepackage
1641 // Do not try to load any other package before the document class, unless you
1642 // have a thorough understanding of the LATEX internals and know exactly what you
1644 if (features.mustProvide("fix-cm"))
1645 os << "\\RequirePackage{fix-cm}\n";
1646 // Likewise for fixltx2e. If other packages conflict with this policy,
1647 // treat it as a package bug (and report it!)
1648 // See http://www.latex-project.org/cgi-bin/ltxbugs2html?pr=latex/4407
1649 if (features.mustProvide("fixltx2e"))
1650 os << "\\RequirePackage{fixltx2e}\n";
1652 os << "\\documentclass";
1654 DocumentClass const & tclass = documentClass();
1656 ostringstream clsoptions; // the document class options.
1658 if (tokenPos(tclass.opt_fontsize(),
1659 '|', fontsize) >= 0) {
1660 // only write if existing in list (and not default)
1661 clsoptions << subst(tclass.fontsizeformat(), "$$s", fontsize) << ",";
1664 // paper sizes not supported by the class itself need the
1666 vector<string> classpsizes = getVectorFromString(tclass.opt_pagesize(), "|");
1667 bool class_supported_papersize = papersize == PAPER_DEFAULT
1668 || find(classpsizes.begin(), classpsizes.end(), string_papersize[papersize]) != classpsizes.end();
1670 if ((!use_geometry || features.isProvided("geometry-light"))
1671 && class_supported_papersize && papersize != PAPER_DEFAULT)
1672 clsoptions << subst(tclass.pagesizeformat(), "$$s", string_papersize[papersize]) << ",";
1675 if (sides != tclass.sides()) {
1678 clsoptions << "oneside,";
1681 clsoptions << "twoside,";
1687 if (columns != tclass.columns()) {
1689 clsoptions << "twocolumn,";
1691 clsoptions << "onecolumn,";
1695 && orientation == ORIENTATION_LANDSCAPE)
1696 clsoptions << "landscape,";
1699 clsoptions << "fleqn,";
1701 switch(math_numbering_side) {
1703 clsoptions << "leqno,";
1706 clsoptions << "reqno,";
1707 features.require("amsmath");
1713 // language should be a parameter to \documentclass
1714 if (language->babel() == "hebrew"
1715 && default_language->babel() != "hebrew")
1716 // This seems necessary
1717 features.useLanguage(default_language);
1719 ostringstream language_options;
1720 bool const use_babel = features.useBabel() && !features.isProvided("babel");
1721 bool const use_polyglossia = features.usePolyglossia();
1722 bool const global = lyxrc.language_global_options;
1723 if (features.useBabel() || (use_polyglossia && global)) {
1724 language_options << features.getBabelLanguages();
1725 if (!language->babel().empty()) {
1726 if (!language_options.str().empty())
1727 language_options << ',';
1728 language_options << language->babel();
1730 if (global && !language_options.str().empty())
1731 clsoptions << language_options.str() << ',';
1734 // the predefined options from the layout
1735 if (use_default_options && !tclass.options().empty())
1736 clsoptions << tclass.options() << ',';
1738 // the user-defined options
1739 if (!options.empty()) {
1740 clsoptions << options << ',';
1743 docstring const strOptions = from_utf8(clsoptions.str());
1744 if (!strOptions.empty()) {
1745 // Check if class options contain uncodable glyphs
1746 docstring uncodable_glyphs;
1747 docstring options_encodable;
1748 Encoding const * const enc = features.runparams().encoding;
1750 for (char_type c : strOptions) {
1751 if (!enc->encodable(c)) {
1752 docstring const glyph(1, c);
1753 LYXERR0("Uncodable character '"
1755 << "' in class options!");
1756 uncodable_glyphs += glyph;
1757 if (features.runparams().dryrun) {
1758 options_encodable += "<" + _("LyX Warning: ")
1759 + _("uncodable character") + " '";
1760 options_encodable += c;
1761 options_encodable += "'>";
1764 options_encodable += c;
1767 options_encodable = strOptions;
1769 // On BUFFER_VIEW|UPDATE, warn user if we found uncodable glyphs
1770 if (!features.runparams().dryrun && !uncodable_glyphs.empty()) {
1771 frontend::Alert::warning(
1772 _("Uncodable character in class options"),
1774 _("The class options of your document contain glyphs "
1775 "that are unknown in the current document encoding "
1776 "(namely %1$s).\nThese glyphs are omitted "
1777 " from the output, which may result in "
1778 "incomplete output."
1779 "\n\nPlease select an appropriate "
1780 "document encoding\n"
1781 "(such as utf8) or change the "
1782 "class options accordingly."),
1785 options_encodable = rtrim(options_encodable, ",");
1786 os << '[' << options_encodable << ']';
1789 os << '{' << from_ascii(tclass.latexname()) << "}\n";
1790 // end of \documentclass defs
1792 // The package options (via \PassOptionsToPackage)
1793 os << from_ascii(features.getPackageOptions());
1795 // if we use fontspec or newtxmath, we have to load the AMS packages here
1796 string const ams = features.loadAMSPackages();
1797 bool const ot1 = (main_font_encoding() == "default" || main_font_encoding() == "OT1");
1798 bool const use_newtxmath =
1799 theLaTeXFonts().getLaTeXFont(from_ascii(fontsMath())).getUsedPackage(
1800 ot1, false, false) == "newtxmath";
1801 if ((useNonTeXFonts || use_newtxmath) && !ams.empty())
1802 os << from_ascii(ams);
1804 if (useNonTeXFonts) {
1805 // Babel (as of 2017/11/03) loads fontspec itself
1806 if (!features.isProvided("fontspec")
1807 && !(features.useBabel() && features.isAvailable("babel-2017/11/03")))
1808 os << "\\usepackage{fontspec}\n";
1809 if (features.mustProvide("unicode-math")
1810 && features.isAvailable("unicode-math"))
1811 os << "\\usepackage{unicode-math}\n";
1814 // load CJK support package before font selection
1815 // (see autotests/export/latex/CJK/micro-sign_utf8-cjk-libertine.lyx)
1816 if (!useNonTeXFonts && encoding().package() != Encoding::none && inputenc != "utf8x"
1817 && (encoding().package() == Encoding::CJK || features.mustProvide("CJK"))) {
1818 if (inputenc == "utf8-cjk" || inputenc == "utf8")
1819 os << "\\usepackage{CJKutf8}\n";
1821 os << "\\usepackage[encapsulated]{CJK}\n";
1824 // font selection must be done before loading fontenc.sty
1825 // but after babel with non-TeX fonts
1826 string const fonts = loadFonts(features);
1827 if (!fonts.empty() && (!features.useBabel() || !useNonTeXFonts))
1828 os << from_utf8(fonts);
1830 if (fonts_default_family != "default")
1831 os << "\\renewcommand{\\familydefault}{\\"
1832 << from_ascii(fonts_default_family) << "}\n";
1834 // set font encoding
1835 // non-TeX fonts use font encoding TU (set by fontspec)
1836 if (!useNonTeXFonts && !features.isProvided("fontenc")
1837 && main_font_encoding() != "default") {
1838 // get main font encodings
1839 vector<string> fontencs = font_encodings();
1840 // get font encodings of secondary languages
1841 // FIXME: some languages (hebrew, ...) assume a standard font encoding as last
1842 // option (for text in other languages).
1843 features.getFontEncodings(fontencs);
1844 if (!fontencs.empty()) {
1845 os << "\\usepackage["
1846 << from_ascii(getStringFromVector(fontencs))
1851 // Load textcomp and pmboxdraw before (lua)inputenc (#11454)
1852 if (features.mustProvide("textcomp"))
1853 os << "\\usepackage{textcomp}\n";
1854 if (features.mustProvide("pmboxdraw"))
1855 os << "\\usepackage{pmboxdraw}\n";
1857 // handle inputenc etc.
1858 // (In documents containing text in Thai language,
1859 // we must load inputenc after babel, see lib/languages).
1860 if (!contains(features.getBabelPostsettings(), from_ascii("thai.ldf")))
1861 writeEncodingPreamble(os, features);
1864 if (!features.runparams().includeall && !included_children_.empty()) {
1865 os << "\\includeonly{";
1867 for (auto incfile : included_children_) {
1868 FileName inc = makeAbsPath(incfile, filepath.absFileName());
1869 string mangled = DocFileName(changeExtension(inc.absFileName(), ".tex")).
1871 if (!features.runparams().nice)
1873 // \includeonly doesn't want an extension
1874 incfile = changeExtension(incfile, string());
1875 incfile = support::latex_path(incfile);
1876 if (!incfile.empty()) {
1879 os << from_utf8(incfile);
1886 if (!features.isProvided("geometry")
1887 && (use_geometry || !class_supported_papersize)) {
1888 odocstringstream ods;
1889 if (!getGraphicsDriver("geometry").empty())
1890 ods << getGraphicsDriver("geometry");
1891 if (orientation == ORIENTATION_LANDSCAPE)
1892 ods << ",landscape";
1893 switch (papersize) {
1895 if (!paperwidth.empty())
1896 ods << ",paperwidth="
1897 << from_ascii(paperwidth);
1898 if (!paperheight.empty())
1899 ods << ",paperheight="
1900 << from_ascii(paperheight);
1902 case PAPER_USLETTER:
1904 case PAPER_USEXECUTIVE:
1933 ods << "," << from_ascii(string_papersize_geometry[papersize]);
1938 docstring g_options = trim(ods.str(), ",");
1939 os << "\\usepackage";
1940 // geometry-light means that the class works with geometry, but overwrites
1941 // the package options and paper sizes (memoir does this).
1942 // In this case, all options need to go to \geometry
1943 // and the standard paper sizes need to go to the class options.
1944 if (!g_options.empty() && !features.isProvided("geometry-light")) {
1945 os << '[' << g_options << ']';
1948 os << "{geometry}\n";
1949 if (use_geometry || features.isProvided("geometry-light")) {
1950 os << "\\geometry{verbose";
1951 if (!g_options.empty())
1952 // Output general options here with "geometry light".
1953 os << "," << g_options;
1954 // output this only if use_geometry is true
1956 if (!topmargin.empty())
1957 os << ",tmargin=" << from_ascii(Length(topmargin).asLatexString());
1958 if (!bottommargin.empty())
1959 os << ",bmargin=" << from_ascii(Length(bottommargin).asLatexString());
1960 if (!leftmargin.empty())
1961 os << ",lmargin=" << from_ascii(Length(leftmargin).asLatexString());
1962 if (!rightmargin.empty())
1963 os << ",rmargin=" << from_ascii(Length(rightmargin).asLatexString());
1964 if (!headheight.empty())
1965 os << ",headheight=" << from_ascii(Length(headheight).asLatexString());
1966 if (!headsep.empty())
1967 os << ",headsep=" << from_ascii(Length(headsep).asLatexString());
1968 if (!footskip.empty())
1969 os << ",footskip=" << from_ascii(Length(footskip).asLatexString());
1970 if (!columnsep.empty())
1971 os << ",columnsep=" << from_ascii(Length(columnsep).asLatexString());
1975 } else if (orientation == ORIENTATION_LANDSCAPE
1976 || papersize != PAPER_DEFAULT) {
1977 features.require("papersize");
1980 if (tokenPos(tclass.opt_pagestyle(), '|', pagestyle) >= 0) {
1981 if (pagestyle == "fancy")
1982 os << "\\usepackage{fancyhdr}\n";
1983 os << "\\pagestyle{" << from_ascii(pagestyle) << "}\n";
1986 // only output when the background color is not default
1987 if (isbackgroundcolor) {
1988 // only require color here, the background color will be defined
1989 // in LaTeXFeatures.cpp to avoid interferences with the LaTeX
1991 features.require("color");
1992 features.require("pagecolor");
1995 // only output when the font color is not default
1997 // only require color here, the font color will be defined
1998 // in LaTeXFeatures.cpp to avoid interferences with the LaTeX
2000 features.require("color");
2001 features.require("fontcolor");
2004 // Only if class has a ToC hierarchy
2005 if (tclass.hasTocLevels()) {
2006 if (secnumdepth != tclass.secnumdepth()) {
2007 os << "\\setcounter{secnumdepth}{"
2011 if (tocdepth != tclass.tocdepth()) {
2012 os << "\\setcounter{tocdepth}{"
2018 if (paragraph_separation) {
2019 // when skip separation
2021 switch (getDefSkip().kind()) {
2022 case VSpace::SMALLSKIP:
2023 psopt = "\\smallskipamount";
2025 case VSpace::MEDSKIP:
2026 psopt = "\\medskipamount";
2028 case VSpace::BIGSKIP:
2029 psopt = "\\bigskipamount";
2031 case VSpace::HALFLINE:
2032 // default (no option)
2034 case VSpace::FULLLINE:
2035 psopt = "\\baselineskip";
2037 case VSpace::LENGTH:
2038 psopt = getDefSkip().length().asLatexString();
2043 if (!features.isProvided("parskip")) {
2045 psopt = "[skip=" + psopt + "]";
2046 os << "\\usepackage" + psopt + "{parskip}\n";
2048 os << "\\setlength{\\parskip}{" + psopt + "}\n";
2051 // when separation by indentation
2052 // only output something when a width is given
2053 if (!getParIndent().empty()) {
2054 os << "\\setlength{\\parindent}{"
2055 << from_utf8(getParIndent().asLatexString())
2060 if (is_math_indent) {
2061 // when formula indentation
2062 // only output something when it is not the default
2063 if (!getMathIndent().empty()) {
2064 os << "\\setlength{\\mathindent}{"
2065 << from_utf8(getMathIndent().asString())
2070 // Now insert the LyX specific LaTeX commands...
2071 features.resolveAlternatives();
2072 features.expandMultiples();
2075 if (!output_sync_macro.empty())
2076 os << from_utf8(output_sync_macro) +"\n";
2077 else if (features.runparams().flavor == Flavor::LaTeX)
2078 os << "\\usepackage[active]{srcltx}\n";
2079 else if (features.runparams().flavor == Flavor::PdfLaTeX)
2080 os << "\\synctex=-1\n";
2083 // due to interferences with babel and hyperref, the color package has to
2084 // be loaded (when it is not already loaded) before babel when hyperref
2085 // is used with the colorlinks option, see
2086 // http://www.lyx.org/trac/ticket/5291
2087 // we decided therefore to load color always before babel, see
2088 // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg144349.html
2089 os << from_ascii(features.getColorOptions());
2091 // If we use hyperref, jurabib, japanese or varioref,
2092 // we have to call babel before
2094 && (features.isRequired("jurabib")
2095 || features.isRequired("hyperref")
2096 || features.isRequired("varioref")
2097 || features.isRequired("japanese"))) {
2098 os << features.getBabelPresettings();
2100 os << from_utf8(babelCall(language_options.str(),
2101 !lyxrc.language_global_options)) + '\n';
2102 os << features.getBabelPostsettings();
2105 // The optional packages;
2106 os << from_ascii(features.getPackages());
2108 // Additional Indices
2109 if (features.isRequired("splitidx")) {
2110 for (auto const & idx : indiceslist()) {
2111 os << "\\newindex{";
2112 os << escape(idx.shortcut());
2118 os << from_utf8(spacing().writePreamble(features.isProvided("SetSpace")));
2121 // * Hyperref manual: "Make sure it comes last of your loaded
2122 // packages, to give it a fighting chance of not being over-written,
2123 // since its job is to redefine many LaTeX commands."
2124 // * Email from Heiko Oberdiek: "It is usually better to load babel
2125 // before hyperref. Then hyperref has a chance to detect babel.
2126 // * Has to be loaded before the "LyX specific LaTeX commands" to
2127 // avoid errors with algorithm floats.
2128 // use hyperref explicitly if it is required
2129 if (features.isRequired("hyperref")) {
2130 OutputParams tmp_params = features.runparams();
2131 pdfoptions().writeLaTeX(tmp_params, os,
2132 features.isProvided("hyperref"));
2133 // correctly break URLs with hyperref and dvi/ps output
2134 if (features.runparams().hyperref_driver == "dvips"
2135 && features.isAvailable("breakurl"))
2136 os << "\\usepackage{breakurl}\n";
2137 } else if (features.isRequired("nameref"))
2138 // hyperref loads this automatically
2139 os << "\\usepackage{nameref}\n";
2142 os << "\\usepackage";
2143 if (!lineno_opts.empty())
2144 os << "[" << lineno_opts << "]";
2146 os << "\\linenumbers\n";
2149 // bibtopic needs to be loaded after hyperref.
2150 // the dot provides the aux file naming which LyX can detect.
2151 if (features.mustProvide("bibtopic"))
2152 os << "\\usepackage[dot]{bibtopic}\n";
2154 // Will be surrounded by \makeatletter and \makeatother when not empty
2155 otexstringstream atlyxpreamble;
2157 // Some macros LyX will need
2159 TexString tmppreamble = features.getMacros();
2160 if (!tmppreamble.str.empty())
2161 atlyxpreamble << "\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
2162 "LyX specific LaTeX commands.\n"
2163 << move(tmppreamble)
2166 // the text class specific preamble
2168 docstring tmppreamble = features.getTClassPreamble();
2169 if (!tmppreamble.empty())
2170 atlyxpreamble << "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
2171 "Textclass specific LaTeX commands.\n"
2175 // suppress date if selected
2176 // use \@ifundefined because we cannot be sure that every document class
2177 // has a \date command
2179 atlyxpreamble << "\\@ifundefined{date}{}{\\date{}}\n";
2181 /* the user-defined preamble */
2182 if (!containsOnly(preamble, " \n\t")) {
2184 atlyxpreamble << "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
2185 "User specified LaTeX commands.\n";
2187 // Check if the user preamble contains uncodable glyphs
2188 odocstringstream user_preamble;
2189 docstring uncodable_glyphs;
2190 Encoding const * const enc = features.runparams().encoding;
2192 for (char_type c : preamble) {
2193 if (!enc->encodable(c)) {
2194 docstring const glyph(1, c);
2195 LYXERR0("Uncodable character '"
2197 << "' in user preamble!");
2198 uncodable_glyphs += glyph;
2199 if (features.runparams().dryrun) {
2200 user_preamble << "<" << _("LyX Warning: ")
2201 << _("uncodable character") << " '";
2202 user_preamble.put(c);
2203 user_preamble << "'>";
2206 user_preamble.put(c);
2209 user_preamble << preamble;
2211 // On BUFFER_VIEW|UPDATE, warn user if we found uncodable glyphs
2212 if (!features.runparams().dryrun && !uncodable_glyphs.empty()) {
2213 frontend::Alert::warning(
2214 _("Uncodable character in user preamble"),
2216 _("The user preamble of your document contains glyphs "
2217 "that are unknown in the current document encoding "
2218 "(namely %1$s).\nThese glyphs are omitted "
2219 " from the output, which may result in "
2220 "incomplete output."
2221 "\n\nPlease select an appropriate "
2222 "document encoding\n"
2223 "(such as utf8) or change the "
2224 "preamble code accordingly."),
2227 atlyxpreamble << user_preamble.str() << '\n';
2230 // footmisc must be loaded after setspace
2231 // Load it here to avoid clashes with footmisc loaded in the user
2232 // preamble. For that reason we also pass the options via
2233 // \PassOptionsToPackage in getPreamble() and not here.
2234 if (features.mustProvide("footmisc"))
2235 atlyxpreamble << "\\usepackage{footmisc}\n";
2237 // subfig loads internally the LaTeX package "caption". As
2238 // caption is a very popular package, users will load it in
2239 // the preamble. Therefore we must load subfig behind the
2240 // user-defined preamble and check if the caption package was
2241 // loaded or not. For the case that caption is loaded before
2242 // subfig, there is the subfig option "caption=false". This
2243 // option also works when a koma-script class is used and
2244 // koma's own caption commands are used instead of caption. We
2245 // use \PassOptionsToPackage here because the user could have
2246 // already loaded subfig in the preamble.
2247 if (features.mustProvide("subfig"))
2248 atlyxpreamble << "\\ifdefined\\showcaptionsetup\n"
2249 " % Caption package is used. Advise subfig not to load it again.\n"
2250 " \\PassOptionsToPackage{caption=false}{subfig}\n"
2252 "\\usepackage{subfig}\n";
2254 // Itemize bullet settings need to be last in case the user
2255 // defines their own bullets that use a package included
2256 // in the user-defined preamble -- ARRae
2257 // Actually it has to be done much later than that
2258 // since some packages like frenchb make modifications
2259 // at \begin{document} time -- JMarc
2260 docstring bullets_def;
2261 for (int i = 0; i < 4; ++i) {
2262 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
2263 if (bullets_def.empty())
2264 bullets_def += "\\AtBeginDocument{\n";
2265 bullets_def += " \\def\\labelitemi";
2267 // `i' is one less than the item to modify
2274 bullets_def += "ii";
2280 bullets_def += '{' +
2281 user_defined_bullet(i).getText()
2286 if (!bullets_def.empty())
2287 atlyxpreamble << bullets_def << "}\n\n";
2289 if (!atlyxpreamble.empty())
2290 os << "\n\\makeatletter\n"
2291 << atlyxpreamble.release()
2292 << "\\makeatother\n\n";
2294 // We try to load babel late, in case it interferes with other packages.
2295 // Jurabib, hyperref, varioref, bicaption, menukeys and listings (bug 8995)
2296 // have to be called after babel, though.
2297 if (use_babel && !features.isRequired("jurabib")
2298 && !features.isRequired("hyperref")
2299 && !features.isRequired("varioref")
2300 && !features.isRequired("japanese")) {
2301 os << features.getBabelPresettings();
2303 os << from_utf8(babelCall(language_options.str(),
2304 !lyxrc.language_global_options)) + '\n';
2305 os << features.getBabelPostsettings();
2307 // In documents containing text in Thai language,
2308 // we must load inputenc after babel (see lib/languages).
2309 if (contains(features.getBabelPostsettings(), from_ascii("thai.ldf")))
2310 writeEncodingPreamble(os, features);
2312 // font selection must be done after babel with non-TeX fonts
2313 if (!fonts.empty() && features.useBabel() && useNonTeXFonts)
2314 os << from_utf8(fonts);
2316 if (features.isRequired("bicaption"))
2317 os << "\\usepackage{bicaption}\n";
2318 if (!listings_params.empty()
2319 || features.mustProvide("listings")
2320 || features.mustProvide("minted")) {
2322 os << "\\usepackage{minted}\n";
2324 os << "\\usepackage{listings}\n";
2326 string lst_params = listings_params;
2327 // If minted, do not output the language option (bug 11203)
2328 if (use_minted && contains(lst_params, "language=")) {
2329 vector<string> opts =
2330 getVectorFromString(lst_params, ",", false);
2331 for (size_t i = 0; i < opts.size(); ++i) {
2332 if (prefixIs(opts[i], "language="))
2333 opts.erase(opts.begin() + i--);
2335 lst_params = getStringFromVector(opts, ",");
2337 if (!lst_params.empty()) {
2339 os << "\\setminted{";
2342 // do not test validity because listings_params is
2343 // supposed to be valid
2345 InsetListingsParams(lst_params).separatedParams(true);
2346 os << from_utf8(par);
2350 // xunicode only needs to be loaded if tipa is used
2351 // (the rest is obsoleted by the new TU encoding).
2352 // It needs to be loaded at least after amsmath, amssymb,
2353 // esint and the other packages that provide special glyphs
2354 if (features.mustProvide("tipa") && useNonTeXFonts
2355 && !features.isProvided("xunicode")) {
2356 // The `xunicode` package officially only supports XeTeX,
2357 // but also works with LuaTeX. We work around its XeTeX test.
2358 if (features.runparams().flavor != Flavor::XeTeX) {
2359 os << "% Pretend to xunicode that we are XeTeX\n"
2360 << "\\def\\XeTeXpicfile{}\n";
2362 os << "\\usepackage{xunicode}\n";
2365 // covington must be loaded after beamerarticle
2366 if (features.isRequired("covington"))
2367 os << "\\usepackage{covington}\n";
2369 // Polyglossia must be loaded last ...
2370 if (use_polyglossia) {
2372 os << "\\usepackage{polyglossia}\n";
2373 // set the main language
2374 os << "\\setdefaultlanguage";
2375 if (!language->polyglossiaOpts().empty())
2376 os << "[" << from_ascii(language->polyglossiaOpts()) << "]";
2377 os << "{" << from_ascii(language->polyglossia()) << "}\n";
2378 // now setup the other languages
2379 set<string> const polylangs =
2380 features.getPolyglossiaLanguages();
2381 for (auto const & pl : polylangs) {
2382 // We do not output the options here; they are output in
2383 // the language switch commands. This is safer if multiple
2384 // varieties are used.
2385 if (pl == language->polyglossia())
2387 os << "\\setotherlanguage";
2388 os << "{" << from_ascii(pl) << "}\n";
2392 // ... but before biblatex (see #7065)
2393 if ((features.mustProvide("biblatex")
2394 || features.isRequired("biblatex-chicago"))
2395 && !features.isProvided("biblatex-chicago")
2396 && !features.isProvided("biblatex-natbib")
2397 && !features.isProvided("natbib-internal")
2398 && !features.isProvided("natbib")
2399 && !features.isProvided("jurabib")) {
2400 // The biblatex-chicago package has a differing interface
2401 // it uses a wrapper package and loads styles via fixed options
2402 bool const chicago = features.isRequired("biblatex-chicago");
2405 os << "\\usepackage";
2406 if (!biblatex_bibstyle.empty()
2407 && (biblatex_bibstyle == biblatex_citestyle)
2409 opts = "style=" + biblatex_bibstyle;
2411 } else if (!chicago) {
2412 if (!biblatex_bibstyle.empty()) {
2413 opts = "bibstyle=" + biblatex_bibstyle;
2416 if (!biblatex_citestyle.empty()) {
2417 opts += delim + "citestyle=" + biblatex_citestyle;
2421 if (!multibib.empty() && multibib != "child") {
2422 opts += delim + "refsection=" + multibib;
2425 if (bibtexCommand() == "bibtex8"
2426 || prefixIs(bibtexCommand(), "bibtex8 ")) {
2427 opts += delim + "backend=bibtex8";
2429 } else if (bibtexCommand() == "bibtex"
2430 || prefixIs(bibtexCommand(), "bibtex ")) {
2431 opts += delim + "backend=bibtex";
2434 if (!bib_encoding.empty() && encodings.fromLyXName(bib_encoding)) {
2435 opts += delim + "bibencoding="
2436 + encodings.fromLyXName(bib_encoding)->latexName();
2439 if (!biblio_opts.empty())
2440 opts += delim + biblio_opts;
2442 os << "[" << opts << "]";
2444 os << "{biblatex-chicago}\n";
2446 os << "{biblatex}\n";
2450 // Load custom language package here
2451 if (features.langPackage() == LaTeXFeatures::LANG_PACK_CUSTOM) {
2452 if (lang_package == "default")
2453 os << from_utf8(lyxrc.language_custom_package);
2455 os << from_utf8(lang_package);
2459 // Since menukeys uses catoptions, which does some heavy changes on key-value options,
2460 // it is recommended to load menukeys as the last package (even after hyperref)
2461 if (features.isRequired("menukeys"))
2462 os << "\\usepackage{menukeys}\n";
2464 docstring const i18npreamble =
2465 features.getTClassI18nPreamble(use_babel, use_polyglossia,
2467 if (!i18npreamble.empty())
2468 os << i18npreamble + '\n';
2474 void BufferParams::useClassDefaults()
2476 DocumentClass const & tclass = documentClass();
2478 sides = tclass.sides();
2479 columns = tclass.columns();
2480 pagestyle = tclass.pagestyle();
2481 tablestyle = tclass.tablestyle();
2482 use_default_options = true;
2483 // Only if class has a ToC hierarchy
2484 if (tclass.hasTocLevels()) {
2485 secnumdepth = tclass.secnumdepth();
2486 tocdepth = tclass.tocdepth();
2491 bool BufferParams::hasClassDefaults() const
2493 DocumentClass const & tclass = documentClass();
2495 return sides == tclass.sides()
2496 && columns == tclass.columns()
2497 && pagestyle == tclass.pagestyle()
2498 && tablestyle == tclass.tablestyle()
2499 && use_default_options
2500 && secnumdepth == tclass.secnumdepth()
2501 && tocdepth == tclass.tocdepth();
2505 DocumentClass const & BufferParams::documentClass() const
2511 DocumentClassConstPtr BufferParams::documentClassPtr() const
2517 void BufferParams::setDocumentClass(DocumentClassConstPtr tc)
2519 // evil, but this function is evil
2520 doc_class_ = const_pointer_cast<DocumentClass>(tc);
2521 invalidateConverterCache();
2525 bool BufferParams::setBaseClass(string const & classname, string const & path)
2527 LYXERR(Debug::TCLASS, "setBaseClass: " << classname);
2528 LayoutFileList & bcl = LayoutFileList::get();
2529 if (!bcl.haveClass(classname)) {
2531 bformat(_("The layout file:\n"
2533 "could not be found. A default textclass with default\n"
2534 "layouts will be used. LyX will not be able to produce\n"
2536 from_utf8(classname));
2537 frontend::Alert::error(_("Document class not found"), s);
2538 bcl.addEmptyClass(classname);
2541 bool const success = bcl[classname].load(path);
2544 bformat(_("Due to some error in it, the layout file:\n"
2546 "could not be loaded. A default textclass with default\n"
2547 "layouts will be used. LyX will not be able to produce\n"
2549 from_utf8(classname));
2550 frontend::Alert::error(_("Could not load class"), s);
2551 bcl.addEmptyClass(classname);
2554 pimpl_->baseClass_ = classname;
2555 layout_modules_.adaptToBaseClass(baseClass(), removed_modules_);
2560 LayoutFile const * BufferParams::baseClass() const
2562 if (LayoutFileList::get().haveClass(pimpl_->baseClass_))
2563 return &(LayoutFileList::get()[pimpl_->baseClass_]);
2569 LayoutFileIndex const & BufferParams::baseClassID() const
2571 return pimpl_->baseClass_;
2575 void BufferParams::makeDocumentClass(bool clone, bool internal)
2580 invalidateConverterCache();
2581 LayoutModuleList mods;
2582 for (auto const & mod : layout_modules_)
2583 mods.push_back(mod);
2585 doc_class_ = getDocumentClass(*baseClass(), mods, cite_engine_, clone, internal);
2587 TextClass::ReturnValues success = TextClass::OK;
2588 if (!forced_local_layout_.empty())
2589 success = doc_class_->read(to_utf8(forced_local_layout_),
2591 if (!local_layout_.empty() &&
2592 (success == TextClass::OK || success == TextClass::OK_OLDFORMAT))
2593 success = doc_class_->read(to_utf8(local_layout_), TextClass::MODULE);
2594 if (success != TextClass::OK && success != TextClass::OK_OLDFORMAT) {
2595 docstring const msg = _("Error reading internal layout information");
2596 frontend::Alert::warning(_("Read Error"), msg);
2601 bool BufferParams::layoutModuleCanBeAdded(string const & modName) const
2603 return layout_modules_.moduleCanBeAdded(modName, baseClass());
2607 docstring BufferParams::getLocalLayout(bool forced) const
2610 return from_utf8(doc_class_->forcedLayouts());
2612 return local_layout_;
2616 void BufferParams::setLocalLayout(docstring const & layout, bool forced)
2619 forced_local_layout_ = layout;
2621 local_layout_ = layout;
2625 bool BufferParams::addLayoutModule(string const & modName)
2627 for (auto const & mod : layout_modules_)
2630 layout_modules_.push_back(modName);
2635 string BufferParams::bufferFormat() const
2637 return documentClass().outputFormat();
2641 bool BufferParams::isExportable(string const & format, bool need_viewable) const
2643 FormatList const & formats = exportableFormats(need_viewable);
2644 for (auto const & fmt : formats) {
2645 if (fmt->name() == format)
2652 FormatList const & BufferParams::exportableFormats(bool only_viewable) const
2654 FormatList & cached = only_viewable ?
2655 pimpl_->viewableFormatList : pimpl_->exportableFormatList;
2656 bool & valid = only_viewable ?
2657 pimpl_->isViewCacheValid : pimpl_->isExportCacheValid;
2661 vector<string> const backs = backends();
2662 set<string> excludes;
2663 if (useNonTeXFonts) {
2664 excludes.insert("latex");
2665 excludes.insert("pdflatex");
2666 } else if (inputenc != "ascii" && inputenc != "utf8-plain") {
2667 // XeTeX with TeX fonts requires input encoding ascii (#10600).
2668 excludes.insert("xetex");
2672 theConverters().getReachable(backs[0], only_viewable, true, excludes);
2673 vector<string>::const_iterator it = backs.begin() + 1;
2674 for (; it != backs.end(); ++it) {
2675 FormatList r = theConverters().getReachable(*it, only_viewable,
2677 result.insert(result.end(), r.begin(), r.end());
2679 sort(result.begin(), result.end(), Format::formatSorter);
2686 vector<string> BufferParams::backends() const
2689 string const buffmt = bufferFormat();
2691 // FIXME: Don't hardcode format names here, but use a flag
2692 if (buffmt == "latex") {
2693 if (encoding().package() == Encoding::japanese)
2694 v.push_back("platex");
2696 if (!useNonTeXFonts) {
2697 v.push_back("pdflatex");
2698 v.push_back("latex");
2701 || inputenc == "ascii" || inputenc == "utf8-plain")
2702 v.push_back("xetex");
2703 v.push_back("luatex");
2704 v.push_back("dviluatex");
2707 string rbuffmt = buffmt;
2708 // If we use an OutputFormat in Japanese docs,
2709 // we need special format in order to get the path
2710 // via pLaTeX (#8823)
2711 if (documentClass().hasOutputFormat()
2712 && encoding().package() == Encoding::japanese)
2714 v.push_back(rbuffmt);
2717 v.push_back("xhtml");
2718 v.push_back("docbook5");
2719 v.push_back("text");
2725 Flavor BufferParams::getOutputFlavor(string const & format) const
2727 string const dformat = (format.empty() || format == "default") ?
2728 getDefaultOutputFormat() : format;
2729 DefaultFlavorCache::const_iterator it =
2730 default_flavors_.find(dformat);
2732 if (it != default_flavors_.end())
2735 Flavor result = Flavor::LaTeX;
2737 // FIXME It'd be better not to hardcode this, but to do
2738 // something with formats.
2739 if (dformat == "xhtml")
2740 result = Flavor::Html;
2741 else if (dformat == "docbook5")
2742 result = Flavor::DocBook5;
2743 else if (dformat == "text")
2744 result = Flavor::Text;
2745 else if (dformat == "lyx")
2746 result = Flavor::LyX;
2747 else if (dformat == "pdflatex")
2748 result = Flavor::PdfLaTeX;
2749 else if (dformat == "xetex")
2750 result = Flavor::XeTeX;
2751 else if (dformat == "luatex")
2752 result = Flavor::LuaTeX;
2753 else if (dformat == "dviluatex")
2754 result = Flavor::DviLuaTeX;
2756 // Try to determine flavor of default output format
2757 vector<string> backs = backends();
2758 if (find(backs.begin(), backs.end(), dformat) == backs.end()) {
2759 // Get shortest path to format
2760 Graph::EdgePath path;
2761 for (auto const & bvar : backs) {
2762 Graph::EdgePath p = theConverters().getPath(bvar, dformat);
2763 if (!p.empty() && (path.empty() || p.size() < path.size())) {
2768 result = theConverters().getFlavor(path);
2771 // cache this flavor
2772 default_flavors_[dformat] = result;
2777 string BufferParams::getDefaultOutputFormat() const
2779 if (!default_output_format.empty()
2780 && default_output_format != "default")
2781 return default_output_format;
2782 if (encoding().package() == Encoding::japanese)
2783 return lyxrc.default_platex_view_format;
2785 return lyxrc.default_otf_view_format;
2786 return lyxrc.default_view_format;
2789 Font const BufferParams::getFont() const
2791 FontInfo f = documentClass().defaultfont();
2792 if (fonts_default_family == "rmdefault")
2793 f.setFamily(ROMAN_FAMILY);
2794 else if (fonts_default_family == "sfdefault")
2795 f.setFamily(SANS_FAMILY);
2796 else if (fonts_default_family == "ttdefault")
2797 f.setFamily(TYPEWRITER_FAMILY);
2798 return Font(f, language);
2802 QuoteStyle BufferParams::getQuoteStyle(string const & qs) const
2804 return quotesstyletranslator().find(qs);
2808 bool BufferParams::isLatex() const
2810 return documentClass().outputType() == LATEX;
2814 bool BufferParams::isLiterate() const
2816 return documentClass().outputType() == LITERATE;
2820 void BufferParams::readPreamble(Lexer & lex)
2822 if (lex.getString() != "\\begin_preamble")
2823 lyxerr << "Error (BufferParams::readPreamble):"
2824 "consistency check failed." << endl;
2826 preamble = lex.getLongString(from_ascii("\\end_preamble"));
2830 void BufferParams::readLocalLayout(Lexer & lex, bool forced)
2832 string const expected = forced ? "\\begin_forced_local_layout" :
2833 "\\begin_local_layout";
2834 if (lex.getString() != expected)
2835 lyxerr << "Error (BufferParams::readLocalLayout):"
2836 "consistency check failed." << endl;
2839 forced_local_layout_ =
2840 lex.getLongString(from_ascii("\\end_forced_local_layout"));
2842 local_layout_ = lex.getLongString(from_ascii("\\end_local_layout"));
2846 bool BufferParams::setLanguage(string const & lang)
2848 Language const *new_language = languages.getLanguage(lang);
2849 if (!new_language) {
2850 // Language lang was not found
2853 language = new_language;
2858 void BufferParams::readLanguage(Lexer & lex)
2860 if (!lex.next()) return;
2862 string const tmptok = lex.getString();
2864 // check if tmptok is part of tex_babel in tex-defs.h
2865 if (!setLanguage(tmptok)) {
2866 // Language tmptok was not found
2867 language = default_language;
2868 lyxerr << "Warning: Setting language `"
2869 << tmptok << "' to `" << language->lang()
2875 void BufferParams::readGraphicsDriver(Lexer & lex)
2880 string const tmptok = lex.getString();
2881 // check if tmptok is part of tex_graphics in tex_defs.h
2884 string const test = tex_graphics[n++];
2886 if (test == tmptok) {
2887 graphics_driver = tmptok;
2892 "Warning: graphics driver `$$Token' not recognized!\n"
2893 " Setting graphics driver to `default'.\n");
2894 graphics_driver = "default";
2901 void BufferParams::readBullets(Lexer & lex)
2906 int const index = lex.getInteger();
2908 int temp_int = lex.getInteger();
2909 user_defined_bullet(index).setFont(temp_int);
2910 temp_bullet(index).setFont(temp_int);
2912 user_defined_bullet(index).setCharacter(temp_int);
2913 temp_bullet(index).setCharacter(temp_int);
2915 user_defined_bullet(index).setSize(temp_int);
2916 temp_bullet(index).setSize(temp_int);
2920 void BufferParams::readBulletsLaTeX(Lexer & lex)
2922 // The bullet class should be able to read this.
2925 int const index = lex.getInteger();
2927 docstring const temp_str = lex.getDocString();
2929 user_defined_bullet(index).setText(temp_str);
2930 temp_bullet(index).setText(temp_str);
2934 void BufferParams::readModules(Lexer & lex)
2936 if (!lex.eatLine()) {
2937 lyxerr << "Error (BufferParams::readModules):"
2938 "Unexpected end of input." << endl;
2942 string mod = lex.getString();
2943 if (mod == "\\end_modules")
2945 addLayoutModule(mod);
2951 void BufferParams::readRemovedModules(Lexer & lex)
2953 if (!lex.eatLine()) {
2954 lyxerr << "Error (BufferParams::readRemovedModules):"
2955 "Unexpected end of input." << endl;
2959 string mod = lex.getString();
2960 if (mod == "\\end_removed_modules")
2962 removed_modules_.push_back(mod);
2965 // now we want to remove any removed modules that were previously
2966 // added. normally, that will be because default modules were added in
2967 // setBaseClass(), which gets called when \textclass is read at the
2968 // start of the read.
2969 for (auto const & rm : removed_modules_) {
2970 LayoutModuleList::iterator const mit = layout_modules_.begin();
2971 LayoutModuleList::iterator const men = layout_modules_.end();
2972 LayoutModuleList::iterator found = find(mit, men, rm);
2975 layout_modules_.erase(found);
2980 void BufferParams::readIncludeonly(Lexer & lex)
2982 if (!lex.eatLine()) {
2983 lyxerr << "Error (BufferParams::readIncludeonly):"
2984 "Unexpected end of input." << endl;
2988 string child = lex.getString();
2989 if (child == "\\end_includeonly")
2991 included_children_.push_back(child);
2997 string BufferParams::paperSizeName(PapersizePurpose purpose, string const & psize) const
2999 PAPER_SIZE ppsize = psize.empty() ? papersize : papersizetranslator().find(psize);
3002 if (documentClass().pagesize() == "default")
3003 // could be anything, so don't guess
3005 return paperSizeName(purpose, documentClass().pagesize());
3006 case PAPER_CUSTOM: {
3007 if (purpose == XDVI && !paperwidth.empty() &&
3008 !paperheight.empty()) {
3009 // heightxwidth<unit>
3010 string first = paperwidth;
3011 string second = paperheight;
3012 if (orientation == ORIENTATION_LANDSCAPE)
3015 return first.erase(first.length() - 2)
3021 // dvips and dvipdfm do not know this
3022 if (purpose == DVIPS || purpose == DVIPDFM)
3026 if (purpose == DVIPS || purpose == DVIPDFM)
3030 if (purpose == DVIPS || purpose == DVIPDFM)
3040 if (purpose == DVIPS || purpose == DVIPDFM)
3044 if (purpose == DVIPS || purpose == DVIPDFM)
3048 if (purpose == DVIPS || purpose == DVIPDFM)
3052 if (purpose == DVIPS || purpose == DVIPDFM)
3056 if (purpose == DVIPS || purpose == DVIPDFM)
3060 // dvipdfm does not know this
3061 if (purpose == DVIPDFM)
3065 if (purpose == DVIPDFM)
3069 if (purpose == DVIPS || purpose == DVIPDFM)
3073 if (purpose == DVIPS || purpose == DVIPDFM)
3077 if (purpose == DVIPS || purpose == DVIPDFM)
3081 if (purpose == DVIPS || purpose == DVIPDFM)
3085 if (purpose == DVIPS || purpose == DVIPDFM)
3089 if (purpose == DVIPS || purpose == DVIPDFM)
3093 if (purpose == DVIPS || purpose == DVIPDFM)
3097 if (purpose == DVIPS || purpose == DVIPDFM)
3101 if (purpose == DVIPS || purpose == DVIPDFM)
3105 if (purpose == DVIPS || purpose == DVIPDFM)
3109 if (purpose == DVIPS || purpose == DVIPDFM)
3113 if (purpose == DVIPS || purpose == DVIPDFM)
3117 if (purpose == DVIPS || purpose == DVIPDFM)
3121 if (purpose == DVIPS || purpose == DVIPDFM)
3125 if (purpose == DVIPS || purpose == DVIPDFM)
3128 case PAPER_USEXECUTIVE:
3129 // dvipdfm does not know this
3130 if (purpose == DVIPDFM)
3135 case PAPER_USLETTER:
3137 if (purpose == XDVI)
3144 string const BufferParams::dvips_options() const
3148 // If the class loads the geometry package, we do not know which
3149 // paper size is used, since we do not set it (bug 7013).
3150 // Therefore we must not specify any argument here.
3151 // dvips gets the correct paper size via DVI specials in this case
3152 // (if the class uses the geometry package correctly).
3153 if (documentClass().provides("geometry"))
3157 && papersize == PAPER_CUSTOM
3158 && !lyxrc.print_paper_dimension_flag.empty()
3159 && !paperwidth.empty()
3160 && !paperheight.empty()) {
3161 // using a custom papersize
3162 result = lyxrc.print_paper_dimension_flag;
3163 result += ' ' + paperwidth;
3164 result += ',' + paperheight;
3166 string const paper_option = paperSizeName(DVIPS);
3167 if (!paper_option.empty() && (paper_option != "letter" ||
3168 orientation != ORIENTATION_LANDSCAPE)) {
3169 // dvips won't accept -t letter -t landscape.
3170 // In all other cases, include the paper size
3172 result = lyxrc.print_paper_flag;
3173 result += ' ' + paper_option;
3176 if (orientation == ORIENTATION_LANDSCAPE &&
3177 papersize != PAPER_CUSTOM)
3178 result += ' ' + lyxrc.print_landscape_flag;
3183 string const BufferParams::main_font_encoding() const
3185 if (font_encodings().empty()) {
3186 if (ascii_lowercase(language->fontenc(*this)) == "none")
3190 return font_encodings().back();
3194 vector<string> const BufferParams::font_encodings() const
3196 string doc_fontenc = (fontenc == "auto") ? string() : fontenc;
3198 vector<string> fontencs;
3200 // "default" means "no explicit font encoding"
3201 if (doc_fontenc != "default") {
3202 if (!doc_fontenc.empty())
3203 // If we have a custom setting, we use only that!
3204 return getVectorFromString(doc_fontenc);
3205 if (!language->fontenc(*this).empty()
3206 && ascii_lowercase(language->fontenc(*this)) != "none") {
3207 vector<string> fencs = getVectorFromString(language->fontenc(*this));
3208 for (auto & fe : fencs) {
3209 if (find(fontencs.begin(), fontencs.end(), fe) == fontencs.end())
3210 fontencs.push_back(fe);
3219 string BufferParams::babelCall(string const & lang_opts, bool const langoptions) const
3221 // suppress the babel call if there is no BabelName defined
3222 // for the document language in the lib/languages file and if no
3223 // other languages are used (lang_opts is then empty)
3224 if (lang_opts.empty())
3226 // The prefs may require the languages to
3227 // be submitted to babel itself (not the class).
3229 return "\\usepackage[" + lang_opts + "]{babel}";
3230 return "\\usepackage{babel}";
3234 docstring BufferParams::getGraphicsDriver(string const & package) const
3238 if (package == "geometry") {
3239 if (graphics_driver == "dvips"
3240 || graphics_driver == "dvipdfm"
3241 || graphics_driver == "pdftex"
3242 || graphics_driver == "vtex")
3243 result = from_ascii(graphics_driver);
3244 else if (graphics_driver == "dvipdfmx")
3245 result = from_ascii("dvipdfm");
3252 void BufferParams::writeEncodingPreamble(otexstream & os,
3253 LaTeXFeatures & features) const
3255 // With no-TeX fonts we use utf8-plain without encoding package.
3259 if (inputenc == "auto-legacy") {
3260 string const doc_encoding =
3261 language->encoding()->latexName();
3262 Encoding::Package const package =
3263 language->encoding()->package();
3265 // Create list of inputenc options:
3266 set<string> encoding_set;
3267 // luainputenc fails with more than one encoding
3268 if (features.runparams().flavor != Flavor::LuaTeX
3269 && features.runparams().flavor != Flavor::DviLuaTeX)
3270 // list all input encodings used in the document
3271 encoding_set = features.getEncodingSet(doc_encoding);
3273 // The "japanese" babel-language requires the pLaTeX engine
3274 // which conflicts with "inputenc".
3275 // See http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129680.html
3276 if ((!encoding_set.empty() || package == Encoding::inputenc)
3277 && !features.isRequired("japanese")
3278 && !features.isProvided("inputenc")) {
3279 os << "\\usepackage[";
3280 set<string>::const_iterator it = encoding_set.begin();
3281 set<string>::const_iterator const end = encoding_set.end();
3283 os << from_ascii(*it);
3286 for (; it != end; ++it)
3287 os << ',' << from_ascii(*it);
3288 if (package == Encoding::inputenc) {
3289 if (!encoding_set.empty())
3291 os << from_ascii(doc_encoding);
3293 if (features.runparams().flavor == Flavor::LuaTeX
3294 || features.runparams().flavor == Flavor::DviLuaTeX)
3295 os << "]{luainputenc}\n";
3297 os << "]{inputenc}\n";
3299 } else if (inputenc != "auto-legacy-plain") {
3300 switch (encoding().package()) {
3301 case Encoding::none:
3303 case Encoding::japanese:
3304 if (encoding().iconvName() != "UTF-8"
3305 && !features.runparams().isFullUnicode())
3306 // don't default to [utf8]{inputenc} with TeXLive >= 18
3307 os << "\\ifdefined\\UseRawInputEncoding\n"
3308 << " \\UseRawInputEncoding\\fi\n";
3310 case Encoding::inputenc:
3311 // do not load inputenc if japanese is used
3312 // or if the class provides inputenc
3313 if (features.isRequired("japanese")
3314 || features.isProvided("inputenc"))
3316 os << "\\usepackage[" << from_ascii(encoding().latexName());
3317 if (features.runparams().flavor == Flavor::LuaTeX
3318 || features.runparams().flavor == Flavor::DviLuaTeX)
3319 os << "]{luainputenc}\n";
3321 os << "]{inputenc}\n";
3325 if (inputenc == "auto-legacy-plain" || features.isRequired("japanese")) {
3326 // don't default to [utf8]{inputenc} with TeXLive >= 18
3327 os << "\\ifdefined\\UseRawInputEncoding\n";
3328 os << " \\UseRawInputEncoding\\fi\n";
3333 string const BufferParams::parseFontName(string const & name) const
3335 string mangled = name;
3336 size_t const idx = mangled.find('[');
3337 if (idx == string::npos || idx == 0)
3340 return mangled.substr(0, idx - 1);
3344 string const BufferParams::loadFonts(LaTeXFeatures & features) const
3346 if (fontsRoman() == "default" && fontsSans() == "default"
3347 && fontsTypewriter() == "default"
3348 && (fontsMath() == "default" || fontsMath() == "auto"))
3354 /* Fontspec (XeTeX, LuaTeX): we provide GUI support for oldstyle
3355 * numbers (Numbers=OldStyle) and sf/tt scaling. The Ligatures=TeX/
3356 * Mapping=tex-text option assures TeX ligatures (such as "--")
3357 * are resolved. Note that tt does not use these ligatures.
3359 * -- add more GUI options?
3360 * -- add more fonts (fonts for other scripts)
3361 * -- if there's a way to find out if a font really supports
3362 * OldStyle, enable/disable the widget accordingly.
3364 if (useNonTeXFonts && features.isAvailable("fontspec")) {
3365 // "Mapping=tex-text" and "Ligatures=TeX" are equivalent.
3366 // However, until v.2 (2010/07/11) fontspec only knew
3367 // Mapping=tex-text (for XeTeX only); then "Ligatures=TeX"
3368 // was introduced for both XeTeX and LuaTeX (LuaTeX
3369 // didn't understand "Mapping=tex-text", while XeTeX
3370 // understood both. With most recent versions, both
3371 // variants are understood by both engines. However,
3372 // we want to provide support for at least TeXLive 2009
3373 // (for XeTeX; LuaTeX is only supported as of v.2)
3374 // As of 2017/11/03, Babel has its own higher-level
3375 // interface on top of fontspec that is to be used.
3376 bool const babelfonts = features.useBabel()
3377 && features.isAvailable("babel-2017/11/03");
3378 string const texmapping =
3379 (features.runparams().flavor == Flavor::XeTeX) ?
3380 "Mapping=tex-text" : "Ligatures=TeX";
3381 if (fontsRoman() != "default") {
3383 os << "\\babelfont{rm}[";
3385 os << "\\setmainfont[";
3386 if (!font_roman_opts.empty())
3387 os << font_roman_opts << ',';
3389 if (fonts_roman_osf)
3390 os << ",Numbers=OldStyle";
3391 os << "]{" << parseFontName(fontsRoman()) << "}\n";
3393 if (fontsSans() != "default") {
3394 string const sans = parseFontName(fontsSans());
3395 if (fontsSansScale() != 100) {
3397 os << "\\babelfont{sf}";
3399 os << "\\setsansfont";
3401 << float(fontsSansScale()) / 100 << ',';
3403 os << "Numbers=OldStyle,";
3404 if (!font_sans_opts.empty())
3405 os << font_sans_opts << ',';
3406 os << texmapping << "]{"
3410 os << "\\babelfont{sf}[";
3412 os << "\\setsansfont[";
3414 os << "Numbers=OldStyle,";
3415 if (!font_sans_opts.empty())
3416 os << font_sans_opts << ',';
3417 os << texmapping << "]{"
3421 if (fontsTypewriter() != "default") {
3422 string const mono = parseFontName(fontsTypewriter());
3423 if (fontsTypewriterScale() != 100) {
3425 os << "\\babelfont{tt}";
3427 os << "\\setmonofont";
3429 << float(fontsTypewriterScale()) / 100;
3430 if (fonts_typewriter_osf)
3431 os << ",Numbers=OldStyle";
3432 if (!font_typewriter_opts.empty())
3433 os << ',' << font_typewriter_opts;
3438 os << "\\babelfont{tt}";
3440 os << "\\setmonofont";
3441 if (!font_typewriter_opts.empty() || fonts_typewriter_osf) {
3443 if (fonts_typewriter_osf)
3444 os << "Numbers=OldStyle";
3445 if (!font_typewriter_opts.empty()) {
3446 if (fonts_typewriter_osf)
3448 os << font_typewriter_opts;
3452 os << '{' << mono << "}\n";
3459 bool const ot1 = (main_font_encoding() == "default" || main_font_encoding() == "OT1");
3460 bool const dryrun = features.runparams().dryrun;
3461 bool const complete = (fontsSans() == "default" && fontsTypewriter() == "default");
3462 bool const nomath = (fontsMath() != "auto");
3465 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsRoman())).getLaTeXCode(
3466 dryrun, ot1, complete, fonts_expert_sc, fonts_roman_osf,
3467 nomath, font_roman_opts);
3470 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsSans())).getLaTeXCode(
3471 dryrun, ot1, complete, fonts_expert_sc, fonts_sans_osf,
3472 nomath, font_sans_opts, fontsSansScale());
3474 // MONOSPACED/TYPEWRITER
3475 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsTypewriter())).getLaTeXCode(
3476 dryrun, ot1, complete, fonts_expert_sc, fonts_typewriter_osf,
3477 nomath, font_typewriter_opts, fontsTypewriterScale());
3480 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsMath())).getLaTeXCode(
3481 dryrun, ot1, complete, fonts_expert_sc, fonts_roman_osf,
3488 Encoding const & BufferParams::encoding() const
3490 // Main encoding for LaTeX output.
3492 return *(encodings.fromLyXName("utf8-plain"));
3493 if (inputenc == "auto-legacy" || inputenc == "auto-legacy-plain")
3494 return *language->encoding();
3495 if (inputenc == "utf8" && language->lang() == "japanese")
3496 return *(encodings.fromLyXName("utf8-platex"));
3497 Encoding const * const enc = encodings.fromLyXName(inputenc);
3500 LYXERR0("Unknown inputenc value `" << inputenc
3501 << "'. Using `auto' instead.");
3502 return *language->encoding();
3506 string const & BufferParams::defaultBiblioStyle() const
3508 if (!biblio_style.empty())
3509 return biblio_style;
3511 map<string, string> const & bs = documentClass().defaultBiblioStyle();
3512 auto cit = bs.find(theCiteEnginesList.getTypeAsString(citeEngineType()));
3513 if (cit != bs.end())
3516 return empty_string();
3520 bool BufferParams::fullAuthorList() const
3522 return documentClass().fullAuthorList();
3526 string BufferParams::getCiteAlias(string const & s) const
3528 vector<string> commands =
3529 documentClass().citeCommands(citeEngineType());
3530 // If it is a real command, don't treat it as an alias
3531 if (find(commands.begin(), commands.end(), s) != commands.end())
3533 map<string,string> aliases = documentClass().citeCommandAliases();
3534 if (aliases.find(s) != aliases.end())
3540 vector<string> BufferParams::citeCommands() const
3542 static CitationStyle const default_style;
3543 vector<string> commands =
3544 documentClass().citeCommands(citeEngineType());
3545 if (commands.empty())
3546 commands.push_back(default_style.name);
3551 vector<CitationStyle> BufferParams::citeStyles() const
3553 static CitationStyle const default_style;
3554 vector<CitationStyle> styles =
3555 documentClass().citeStyles(citeEngineType());
3557 styles.push_back(default_style);
3562 string const BufferParams::bibtexCommand() const
3564 // Return document-specific setting if available
3565 if (bibtex_command != "default")
3566 return bibtex_command;
3568 // If we have "default" in document settings, consult the prefs
3569 // 1. Japanese (uses a specific processor)
3570 if (encoding().package() == Encoding::japanese) {
3571 if (lyxrc.jbibtex_command != "automatic")
3572 // Return the specified program, if "automatic" is not set
3573 return lyxrc.jbibtex_command;
3574 else if (!useBiblatex()) {
3575 // With classic BibTeX, return pbibtex, jbibtex, bibtex
3576 if (lyxrc.jbibtex_alternatives.find("pbibtex") != lyxrc.jbibtex_alternatives.end())
3578 if (lyxrc.jbibtex_alternatives.find("jbibtex") != lyxrc.jbibtex_alternatives.end())
3583 // 2. All other languages
3584 else if (lyxrc.bibtex_command != "automatic")
3585 // Return the specified program, if "automatic" is not set
3586 return lyxrc.bibtex_command;
3588 // 3. Automatic: find the most suitable for the current cite framework
3589 if (useBiblatex()) {
3590 // For Biblatex, we prefer biber (also for Japanese)
3591 // and fall back to bibtex8 and, as last resort, bibtex
3592 if (lyxrc.bibtex_alternatives.find("biber") != lyxrc.bibtex_alternatives.end())
3594 else if (lyxrc.bibtex_alternatives.find("bibtex8") != lyxrc.bibtex_alternatives.end())
3601 bool BufferParams::useBiblatex() const
3603 return theCiteEnginesList[citeEngine()]->getCiteFramework() == "biblatex";
3607 void BufferParams::invalidateConverterCache() const
3609 pimpl_->isExportCacheValid = false;
3610 pimpl_->isViewCacheValid = false;
3614 // We shouldn't need to reset the params here, since anything
3615 // we need will be recopied.
3616 void BufferParams::copyForAdvFR(const BufferParams & bp)
3618 string const & lang = bp.language->lang();
3620 layout_modules_ = bp.layout_modules_;
3621 string const & doc_class = bp.documentClass().name();
3622 setBaseClass(doc_class);
3626 void BufferParams::setBibFileEncoding(string const & file, string const & enc)
3628 bib_encodings[file] = enc;
3632 string const BufferParams::bibFileEncoding(string const & file) const
3634 if (bib_encodings.find(file) == bib_encodings.end())
3636 return bib_encodings.find(file)->second;