2 * \file BufferParams.cpp
3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
6 * \author Alfredo Braunstein
7 * \author Lars Gullik Bjønnes
8 * \author Jean-Marc Lasgouttes
10 * \author André Pönitz
11 * \author Martin Vermeer
13 * Full author contact details are available in file CREDITS.
18 #include "BufferParams.h"
21 #include "LayoutFile.h"
22 #include "BranchList.h"
25 #include "CiteEnginesList.h"
28 #include "Converter.h"
31 #include "IndicesList.h"
33 #include "LaTeXFeatures.h"
34 #include "LaTeXFonts.h"
38 #include "OutputParams.h"
40 #include "texstream.h"
43 #include "PDFOptions.h"
45 #include "frontends/alert.h"
47 #include "insets/InsetListingsParams.h"
48 #include "insets/InsetQuotes.h"
50 #include "support/convert.h"
51 #include "support/debug.h"
52 #include "support/FileName.h"
53 #include "support/filetools.h"
54 #include "support/gettext.h"
55 #include "support/Length.h"
56 #include "support/Messages.h"
57 #include "support/mutex.h"
58 #include "support/Package.h"
59 #include "support/Translator.h"
60 #include "support/lstrings.h"
66 using namespace lyx::support;
69 static char const * const string_paragraph_separation[] = {
74 static char const * const string_quotes_style[] = {
75 "english", "swedish", "german", "polish", "swiss", "danish", "plain",
76 "british", "swedishg", "french", "frenchin", "russian", "cjk", "cjkangle",
81 static char const * const string_papersize[] = {
82 "default", "custom", "letter", "legal", "executive",
83 "a0", "a1", "a2", "a3", "a4", "a5", "a6",
84 "b0", "b1", "b2", "b3", "b4", "b5", "b6",
85 "c0", "c1", "c2", "c3", "c4", "c5", "c6",
86 "b0j", "b1j", "b2j", "b3j", "b4j", "b5j", "b6j", ""
90 static char const * const string_papersize_geometry[] = {
91 "default", "custom", "letterpaper", "legalpaper", "executivepaper",
92 "a0paper", "a1paper", "a2paper", "a3paper", "a4paper", "a5paper", "a6paper",
93 "b0paper", "b1paper", "b2paper", "b3paper", "b4paper", "b5paper", "b6paper",
94 "c0paper", "c1paper", "c2paper", "c3paper", "c4paper", "c5paper", "c6paper",
95 "b0j", "b1j", "b2j", "b3j", "b4j", "b5j", "b6j", ""
99 static char const * const string_orientation[] = {
100 "portrait", "landscape", ""
104 static char const * const tex_graphics[] = {
105 "default", "dvialw", "dvilaser", "dvipdf", "dvipdfm", "dvipdfmx",
106 "dvips", "dvipsone", "dvitops", "dviwin", "dviwindo", "dvi2ps", "emtex",
107 "ln", "oztex", "pctexhp", "pctexps", "pctexwin", "pctex32", "pdftex",
108 "psprint", "pubps", "tcidvi", "textures", "truetex", "vtex", "xdvi",
118 // Paragraph separation
119 typedef Translator<string, BufferParams::ParagraphSeparation> ParSepTranslator;
122 ParSepTranslator const init_parseptranslator()
124 ParSepTranslator translator
125 (string_paragraph_separation[0], BufferParams::ParagraphIndentSeparation);
126 translator.addPair(string_paragraph_separation[1], BufferParams::ParagraphSkipSeparation);
131 ParSepTranslator const & parseptranslator()
133 static ParSepTranslator const translator =
134 init_parseptranslator();
140 typedef Translator<string, QuoteStyle> QuotesStyleTranslator;
143 QuotesStyleTranslator const init_quotesstyletranslator()
145 QuotesStyleTranslator translator
146 (string_quotes_style[0], QuoteStyle::English);
147 translator.addPair(string_quotes_style[1], QuoteStyle::Swedish);
148 translator.addPair(string_quotes_style[2], QuoteStyle::German);
149 translator.addPair(string_quotes_style[3], QuoteStyle::Polish);
150 translator.addPair(string_quotes_style[4], QuoteStyle::Swiss);
151 translator.addPair(string_quotes_style[5], QuoteStyle::Danish);
152 translator.addPair(string_quotes_style[6], QuoteStyle::Plain);
153 translator.addPair(string_quotes_style[7], QuoteStyle::British);
154 translator.addPair(string_quotes_style[8], QuoteStyle::SwedishG);
155 translator.addPair(string_quotes_style[9], QuoteStyle::French);
156 translator.addPair(string_quotes_style[10], QuoteStyle::FrenchIN);
157 translator.addPair(string_quotes_style[11], QuoteStyle::Russian);
158 translator.addPair(string_quotes_style[12], QuoteStyle::CJK);
159 translator.addPair(string_quotes_style[13], QuoteStyle::CJKAngle);
160 translator.addPair(string_quotes_style[14], QuoteStyle::Hungarian);
165 QuotesStyleTranslator const & quotesstyletranslator()
167 static QuotesStyleTranslator const translator =
168 init_quotesstyletranslator();
174 typedef Translator<string, PAPER_SIZE> PaperSizeTranslator;
177 static PaperSizeTranslator initPaperSizeTranslator()
179 PaperSizeTranslator translator(string_papersize[0], PAPER_DEFAULT);
180 translator.addPair(string_papersize[1], PAPER_CUSTOM);
181 translator.addPair(string_papersize[2], PAPER_USLETTER);
182 translator.addPair(string_papersize[3], PAPER_USLEGAL);
183 translator.addPair(string_papersize[4], PAPER_USEXECUTIVE);
184 translator.addPair(string_papersize[5], PAPER_A0);
185 translator.addPair(string_papersize[6], PAPER_A1);
186 translator.addPair(string_papersize[7], PAPER_A2);
187 translator.addPair(string_papersize[8], PAPER_A3);
188 translator.addPair(string_papersize[9], PAPER_A4);
189 translator.addPair(string_papersize[10], PAPER_A5);
190 translator.addPair(string_papersize[11], PAPER_A6);
191 translator.addPair(string_papersize[12], PAPER_B0);
192 translator.addPair(string_papersize[13], PAPER_B1);
193 translator.addPair(string_papersize[14], PAPER_B2);
194 translator.addPair(string_papersize[15], PAPER_B3);
195 translator.addPair(string_papersize[16], PAPER_B4);
196 translator.addPair(string_papersize[17], PAPER_B5);
197 translator.addPair(string_papersize[18], PAPER_B6);
198 translator.addPair(string_papersize[19], PAPER_C0);
199 translator.addPair(string_papersize[20], PAPER_C1);
200 translator.addPair(string_papersize[21], PAPER_C2);
201 translator.addPair(string_papersize[22], PAPER_C3);
202 translator.addPair(string_papersize[23], PAPER_C4);
203 translator.addPair(string_papersize[24], PAPER_C5);
204 translator.addPair(string_papersize[25], PAPER_C6);
205 translator.addPair(string_papersize[26], PAPER_JISB0);
206 translator.addPair(string_papersize[27], PAPER_JISB1);
207 translator.addPair(string_papersize[28], PAPER_JISB2);
208 translator.addPair(string_papersize[29], PAPER_JISB3);
209 translator.addPair(string_papersize[30], PAPER_JISB4);
210 translator.addPair(string_papersize[31], PAPER_JISB5);
211 translator.addPair(string_papersize[32], PAPER_JISB6);
216 PaperSizeTranslator const & papersizetranslator()
218 static PaperSizeTranslator const translator =
219 initPaperSizeTranslator();
225 typedef Translator<string, PAPER_ORIENTATION> PaperOrientationTranslator;
228 PaperOrientationTranslator const init_paperorientationtranslator()
230 PaperOrientationTranslator translator(string_orientation[0], ORIENTATION_PORTRAIT);
231 translator.addPair(string_orientation[1], ORIENTATION_LANDSCAPE);
236 PaperOrientationTranslator const & paperorientationtranslator()
238 static PaperOrientationTranslator const translator =
239 init_paperorientationtranslator();
245 typedef Translator<int, PageSides> SidesTranslator;
248 SidesTranslator const init_sidestranslator()
250 SidesTranslator translator(1, OneSide);
251 translator.addPair(2, TwoSides);
256 SidesTranslator const & sidestranslator()
258 static SidesTranslator const translator = init_sidestranslator();
264 typedef Translator<int, BufferParams::Package> PackageTranslator;
267 PackageTranslator const init_packagetranslator()
269 PackageTranslator translator(0, BufferParams::package_off);
270 translator.addPair(1, BufferParams::package_auto);
271 translator.addPair(2, BufferParams::package_on);
276 PackageTranslator const & packagetranslator()
278 static PackageTranslator const translator =
279 init_packagetranslator();
285 typedef Translator<string, Spacing::Space> SpaceTranslator;
288 SpaceTranslator const init_spacetranslator()
290 SpaceTranslator translator("default", Spacing::Default);
291 translator.addPair("single", Spacing::Single);
292 translator.addPair("onehalf", Spacing::Onehalf);
293 translator.addPair("double", Spacing::Double);
294 translator.addPair("other", Spacing::Other);
299 SpaceTranslator const & spacetranslator()
301 static SpaceTranslator const translator = init_spacetranslator();
306 bool inSystemDir(FileName const & document_dir, string & system_dir)
308 // A document is assumed to be in a system LyX directory (not
309 // necessarily the system directory of the running instance)
310 // if both "configure.py" and "chkconfig.ltx" are found in
311 // either document_dir/../ or document_dir/../../.
312 // If true, the system directory path is returned in system_dir
313 // with a trailing path separator.
315 string const msg = "Checking whether document is in a system dir...";
317 string dir = document_dir.absFileName();
319 for (int i = 0; i < 3; ++i) {
320 dir = addPath(dir, "..");
321 if (!fileSearch(dir, "configure.py").empty() &&
322 !fileSearch(dir, "chkconfig.ltx").empty()) {
323 LYXERR(Debug::FILES, msg << " yes");
324 system_dir = addPath(FileName(dir).realPath(), "");
329 LYXERR(Debug::FILES, msg << " no");
330 system_dir = string();
337 class BufferParams::Impl
342 AuthorList authorlist;
343 BranchList branchlist;
344 Bullet temp_bullets[4];
345 Bullet user_defined_bullets[4];
346 IndicesList indiceslist;
350 /** This is the amount of space used for paragraph_separation "skip",
351 * and for detached paragraphs in "indented" documents.
354 PDFOptions pdfoptions;
355 LayoutFileIndex baseClass_;
356 FormatList exportableFormatList;
357 FormatList viewableFormatList;
358 bool isViewCacheValid;
359 bool isExportCacheValid;
363 BufferParams::Impl::Impl()
364 : defskip(VSpace::MEDSKIP), baseClass_(string("")),
365 isViewCacheValid(false), isExportCacheValid(false)
367 // set initial author
369 authorlist.record(Author(from_utf8(lyxrc.user_name),
370 from_utf8(lyxrc.user_email),
371 from_utf8(lyxrc.user_initials)));
376 BufferParams::MemoryTraits::clone(BufferParams::Impl const * ptr)
379 return new BufferParams::Impl(*ptr);
383 void BufferParams::MemoryTraits::destroy(BufferParams::Impl * ptr)
389 BufferParams::BufferParams()
392 setBaseClass(defaultBaseclass());
393 cite_engine_ = "basic";
394 cite_engine_type_ = ENGINE_TYPE_DEFAULT;
396 paragraph_separation = ParagraphIndentSeparation;
397 is_math_indent = false;
398 math_numbering_side = DEFAULT;
399 quotes_style = QuoteStyle::English;
400 dynamic_quotes = false;
401 fontsize = "default";
404 papersize = PAPER_DEFAULT;
405 orientation = ORIENTATION_PORTRAIT;
406 use_geometry = false;
407 biblio_style = string();
408 use_bibtopic = false;
411 save_transient_properties = true;
412 track_changes = false;
413 output_changes = false;
415 postpone_fragile_content = true;
416 use_default_options = true;
417 maintain_unincluded_children = CM_None;
420 language = default_language;
422 fonts_roman[0] = "default";
423 fonts_roman[1] = "default";
424 fonts_sans[0] = "default";
425 fonts_sans[1] = "default";
426 fonts_typewriter[0] = "default";
427 fonts_typewriter[1] = "default";
428 fonts_math[0] = "auto";
429 fonts_math[1] = "auto";
430 fonts_default_family = "default";
431 useNonTeXFonts = false;
432 use_microtype = false;
433 use_dash_ligatures = true;
434 fonts_expert_sc = false;
435 fonts_roman_osf = false;
436 fonts_sans_osf = false;
437 fonts_typewriter_osf = false;
438 fonts_sans_scale[0] = 100;
439 fonts_sans_scale[1] = 100;
440 fonts_typewriter_scale[0] = 100;
441 fonts_typewriter_scale[1] = 100;
443 lang_package = "default";
444 graphics_driver = "default";
445 default_output_format = "default";
446 bibtex_command = "default";
447 index_command = "default";
450 listings_params = string();
451 pagestyle = "default";
452 tablestyle = "default";
453 float_alignment = "class";
454 float_placement = "class";
455 suppress_date = false;
456 justification = true;
457 // no color is the default (white)
458 backgroundcolor = lyx::rgbFromHexName("#ffffff");
459 isbackgroundcolor = false;
460 // no color is the default (black)
461 fontcolor = lyx::rgbFromHexName("#000000");
463 // light gray is the default font color for greyed-out notes
464 notefontcolor = lyx::rgbFromHexName("#cccccc");
465 isnotefontcolor = false;
466 boxbgcolor = lyx::rgbFromHexName("#ff0000");
467 isboxbgcolor = false;
468 compressed = lyxrc.save_compressed;
469 for (int iter = 0; iter < 4; ++iter) {
470 user_defined_bullet(iter) = ITEMIZE_DEFAULTS[iter];
471 temp_bullet(iter) = ITEMIZE_DEFAULTS[iter];
474 indiceslist().addDefault(B_("Index"));
475 html_be_strict = false;
476 html_math_output = MathML;
477 html_math_img_scale = 1.0;
478 html_css_as_file = false;
479 docbook_table_output = HTMLTable;
480 display_pixel_ratio = 1.0;
482 shell_escape = false;
488 // map current author
489 author_map_[pimpl_->authorlist.get(0).bufferId()] = 0;
493 docstring BufferParams::B_(string const & l10n) const
495 LASSERT(language, return from_utf8(l10n));
496 return getMessages(language->code()).get(l10n);
500 BufferParams::Package BufferParams::use_package(std::string const & p) const
502 PackageMap::const_iterator it = use_packages.find(p);
503 if (it == use_packages.end())
509 void BufferParams::use_package(std::string const & p, BufferParams::Package u)
515 map<string, string> const & BufferParams::auto_packages()
517 static map<string, string> packages;
518 if (packages.empty()) {
519 // We could have a race condition here that two threads
520 // discover an empty map at the same time and want to fill
521 // it, but that is no problem, since the same contents is
522 // filled in twice then. Having the locker inside the
523 // packages.empty() condition has the advantage that we
524 // don't need the mutex overhead for simple reading.
526 Mutex::Locker locker(&mutex);
527 // adding a package here implies a file format change!
528 packages["amsmath"] =
529 N_("The LaTeX package amsmath is only used if AMS formula types or symbols from the AMS math toolbars are inserted into formulas");
530 packages["amssymb"] =
531 N_("The LaTeX package amssymb is only used if symbols from the AMS math toolbars are inserted into formulas");
533 N_("The LaTeX package cancel is only used if \\cancel commands are used in formulas");
535 N_("The LaTeX package esint is only used if special integral symbols are inserted into formulas");
536 packages["mathdots"] =
537 N_("The LaTeX package mathdots is only used if the command \\iddots is inserted into formulas");
538 packages["mathtools"] =
539 N_("The LaTeX package mathtools is only used if some mathematical relations are inserted into formulas");
541 N_("The LaTeX package mhchem is only used if either the command \\ce or \\cf is inserted into formulas");
542 packages["stackrel"] =
543 N_("The LaTeX package stackrel is only used if the command \\stackrel with subscript is inserted into formulas");
544 packages["stmaryrd"] =
545 N_("The LaTeX package stmaryrd is only used if symbols from the St Mary's Road symbol font for theoretical computer science are inserted into formulas");
546 packages["undertilde"] =
547 N_("The LaTeX package undertilde is only used if you use the math frame decoration 'utilde'");
553 bool BufferParams::useBibtopic() const
557 return (use_bibtopic || (!multibib.empty() && multibib != "child"));
561 AuthorList & BufferParams::authors()
563 return pimpl_->authorlist;
567 AuthorList const & BufferParams::authors() const
569 return pimpl_->authorlist;
573 void BufferParams::addAuthor(Author const & a)
575 author_map_[a.bufferId()] = pimpl_->authorlist.record(a);
579 BranchList & BufferParams::branchlist()
581 return pimpl_->branchlist;
585 BranchList const & BufferParams::branchlist() const
587 return pimpl_->branchlist;
591 IndicesList & BufferParams::indiceslist()
593 return pimpl_->indiceslist;
597 IndicesList const & BufferParams::indiceslist() const
599 return pimpl_->indiceslist;
603 Bullet & BufferParams::temp_bullet(lyx::size_type const index)
605 LASSERT(index < 4, return pimpl_->temp_bullets[0]);
606 return pimpl_->temp_bullets[index];
610 Bullet const & BufferParams::temp_bullet(lyx::size_type const index) const
612 LASSERT(index < 4, return pimpl_->temp_bullets[0]);
613 return pimpl_->temp_bullets[index];
617 Bullet & BufferParams::user_defined_bullet(lyx::size_type const index)
619 LASSERT(index < 4, return pimpl_->temp_bullets[0]);
620 return pimpl_->user_defined_bullets[index];
624 Bullet const & BufferParams::user_defined_bullet(lyx::size_type const index) const
626 LASSERT(index < 4, return pimpl_->temp_bullets[0]);
627 return pimpl_->user_defined_bullets[index];
631 Spacing & BufferParams::spacing()
633 return pimpl_->spacing;
637 Spacing const & BufferParams::spacing() const
639 return pimpl_->spacing;
643 PDFOptions & BufferParams::pdfoptions()
645 return pimpl_->pdfoptions;
649 PDFOptions const & BufferParams::pdfoptions() const
651 return pimpl_->pdfoptions;
655 Length const & BufferParams::getMathIndent() const
657 return pimpl_->mathindent;
661 void BufferParams::setMathIndent(Length const & indent)
663 pimpl_->mathindent = indent;
667 Length const & BufferParams::getParIndent() const
669 return pimpl_->parindent;
673 void BufferParams::setParIndent(Length const & indent)
675 pimpl_->parindent = indent;
679 VSpace const & BufferParams::getDefSkip() const
681 return pimpl_->defskip;
685 void BufferParams::setDefSkip(VSpace const & vs)
687 // DEFSKIP will cause an infinite loop
688 LASSERT(vs.kind() != VSpace::DEFSKIP, return);
689 pimpl_->defskip = vs;
693 BufferParams::MathNumber BufferParams::getMathNumber() const
695 if (math_numbering_side != DEFAULT)
696 return math_numbering_side;
697 // FIXME: do not hardcode language here
698 else if (language->lang() == "arabic_arabi"
699 || documentClass().provides("leqno"))
706 string BufferParams::readToken(Lexer & lex, string const & token,
707 FileName const & filename)
710 FileName const & filepath = filename.onlyPath();
712 if (token == "\\textclass") {
714 string const classname = lex.getString();
715 // if there exists a local layout file, ignore the system one
716 // NOTE: in this case, the textclass (.cls file) is assumed to
719 LayoutFileList & bcl = LayoutFileList::get();
720 if (!filepath.empty()) {
721 // If classname is an absolute path, the document is
722 // using a local layout file which could not be accessed
723 // by a relative path. In this case the path is correct
724 // even if the document was moved to a different
725 // location. However, we will have a problem if the
726 // document was generated on a different platform.
727 bool isabsolute = FileName::isAbsolute(classname);
728 string const classpath = onlyPath(classname);
729 string const path = isabsolute ? classpath
730 : FileName(addPath(filepath.absFileName(),
731 classpath)).realPath();
732 string const oldpath = isabsolute ? string()
733 : FileName(addPath(origin, classpath)).realPath();
734 tcp = bcl.addLocalLayout(onlyFileName(classname), path, oldpath);
736 // that returns non-empty if a "local" layout file is found.
738 result = to_utf8(makeRelPath(from_utf8(onlyPath(tcp)),
739 from_utf8(filepath.absFileName())));
742 setBaseClass(onlyFileName(tcp));
744 setBaseClass(onlyFileName(classname));
745 // We assume that a tex class exists for local or unknown
746 // layouts so this warning, will only be given for system layouts.
747 if (!baseClass()->isTeXClassAvailable()) {
748 docstring const desc =
749 translateIfPossible(from_utf8(baseClass()->description()));
750 docstring const prereqs =
751 from_utf8(baseClass()->prerequisites());
752 docstring const msg =
753 bformat(_("The selected document class\n"
755 "requires external files that are not available.\n"
756 "The document class can still be used, but the\n"
757 "document cannot be compiled until the following\n"
758 "prerequisites are installed:\n"
760 "See section 3.1.2.2 (Class Availability) of the\n"
761 "User's Guide for more information."), desc, prereqs);
762 frontend::Alert::warning(_("Document class not available"),
765 } else if (token == "\\save_transient_properties") {
766 lex >> save_transient_properties;
767 } else if (token == "\\origin") {
769 origin = lex.getString();
770 string const sysdirprefix = "/systemlyxdir/";
771 if (prefixIs(origin, sysdirprefix)) {
773 if (inSystemDir(filepath, docsys))
774 origin.replace(0, sysdirprefix.length() - 1, docsys);
776 origin.replace(0, sysdirprefix.length() - 1,
777 package().system_support().absFileName());
779 } else if (token == "\\begin_preamble") {
781 } else if (token == "\\begin_local_layout") {
782 readLocalLayout(lex, false);
783 } else if (token == "\\begin_forced_local_layout") {
784 readLocalLayout(lex, true);
785 } else if (token == "\\begin_modules") {
787 } else if (token == "\\begin_removed_modules") {
788 readRemovedModules(lex);
789 } else if (token == "\\begin_includeonly") {
790 readIncludeonly(lex);
791 } else if (token == "\\maintain_unincluded_children") {
795 maintain_unincluded_children = CM_None;
796 else if (tmp == "mostly")
797 maintain_unincluded_children = CM_Mostly;
798 else if (tmp == "strict")
799 maintain_unincluded_children = CM_Strict;
800 } else if (token == "\\options") {
802 options = lex.getString();
803 } else if (token == "\\use_default_options") {
804 lex >> use_default_options;
805 } else if (token == "\\master") {
807 master = lex.getString();
808 if (!filepath.empty() && FileName::isAbsolute(origin)) {
809 bool const isabs = FileName::isAbsolute(master);
810 FileName const abspath(isabs ? master : origin + master);
811 bool const moved = filepath != FileName(origin);
812 if (moved && abspath.exists()) {
813 docstring const path = isabs
815 : from_utf8(abspath.realPath());
816 docstring const refpath =
817 from_utf8(filepath.absFileName());
818 master = to_utf8(makeRelPath(path, refpath));
821 } else if (token == "\\suppress_date") {
822 lex >> suppress_date;
823 } else if (token == "\\justification") {
824 lex >> justification;
825 } else if (token == "\\language") {
827 } else if (token == "\\language_package") {
829 lang_package = lex.getString();
830 } else if (token == "\\inputencoding") {
832 } else if (token == "\\graphics") {
833 readGraphicsDriver(lex);
834 } else if (token == "\\default_output_format") {
835 lex >> default_output_format;
836 } else if (token == "\\bibtex_command") {
838 bibtex_command = lex.getString();
839 } else if (token == "\\index_command") {
841 index_command = lex.getString();
842 } else if (token == "\\fontencoding") {
844 fontenc = lex.getString();
845 } else if (token == "\\font_roman") {
846 lex >> fonts_roman[0];
847 lex >> fonts_roman[1];
848 } else if (token == "\\font_sans") {
849 lex >> fonts_sans[0];
850 lex >> fonts_sans[1];
851 } else if (token == "\\font_typewriter") {
852 lex >> fonts_typewriter[0];
853 lex >> fonts_typewriter[1];
854 } else if (token == "\\font_math") {
855 lex >> fonts_math[0];
856 lex >> fonts_math[1];
857 } else if (token == "\\font_default_family") {
858 lex >> fonts_default_family;
859 } else if (token == "\\use_non_tex_fonts") {
860 lex >> useNonTeXFonts;
861 } else if (token == "\\font_sc") {
862 lex >> fonts_expert_sc;
863 } else if (token == "\\font_roman_osf") {
864 lex >> fonts_roman_osf;
865 } else if (token == "\\font_sans_osf") {
866 lex >> fonts_sans_osf;
867 } else if (token == "\\font_typewriter_osf") {
868 lex >> fonts_typewriter_osf;
869 } else if (token == "\\font_roman_opts") {
870 lex >> font_roman_opts;
871 } else if (token == "\\font_sf_scale") {
872 lex >> fonts_sans_scale[0];
873 lex >> fonts_sans_scale[1];
874 } else if (token == "\\font_sans_opts") {
875 lex >> font_sans_opts;
876 } else if (token == "\\font_tt_scale") {
877 lex >> fonts_typewriter_scale[0];
878 lex >> fonts_typewriter_scale[1];
879 } else if (token == "\\font_typewriter_opts") {
880 lex >> font_typewriter_opts;
881 } else if (token == "\\font_cjk") {
883 } else if (token == "\\use_microtype") {
884 lex >> use_microtype;
885 } else if (token == "\\use_dash_ligatures") {
886 lex >> use_dash_ligatures;
887 } else if (token == "\\paragraph_separation") {
890 paragraph_separation = parseptranslator().find(parsep);
891 } else if (token == "\\paragraph_indentation") {
893 string parindent = lex.getString();
894 if (parindent == "default")
895 pimpl_->parindent = Length();
897 pimpl_->parindent = Length(parindent);
898 } else if (token == "\\defskip") {
900 string const defskip = lex.getString();
901 pimpl_->defskip = VSpace(defskip);
902 if (pimpl_->defskip.kind() == VSpace::DEFSKIP)
904 pimpl_->defskip = VSpace(VSpace::MEDSKIP);
905 } else if (token == "\\is_math_indent") {
906 lex >> is_math_indent;
907 } else if (token == "\\math_indentation") {
909 string mathindent = lex.getString();
910 if (mathindent == "default")
911 pimpl_->mathindent = Length();
913 pimpl_->mathindent = Length(mathindent);
914 } else if (token == "\\math_numbering_side") {
918 math_numbering_side = LEFT;
919 else if (tmp == "right")
920 math_numbering_side = RIGHT;
922 math_numbering_side = DEFAULT;
923 } else if (token == "\\quotes_style") {
926 quotes_style = quotesstyletranslator().find(qstyle);
927 } else if (token == "\\dynamic_quotes") {
928 lex >> dynamic_quotes;
929 } else if (token == "\\papersize") {
932 papersize = papersizetranslator().find(ppsize);
933 } else if (token == "\\use_geometry") {
935 } else if (token == "\\use_package") {
940 use_package(package, packagetranslator().find(use));
941 } else if (token == "\\cite_engine") {
943 cite_engine_ = lex.getString();
944 } else if (token == "\\cite_engine_type") {
947 cite_engine_type_ = theCiteEnginesList.getType(engine_type);
948 } else if (token == "\\biblio_style") {
950 biblio_style = lex.getString();
951 } else if (token == "\\biblio_options") {
953 biblio_opts = trim(lex.getString());
954 } else if (token == "\\biblatex_bibstyle") {
956 biblatex_bibstyle = trim(lex.getString());
957 } else if (token == "\\biblatex_citestyle") {
959 biblatex_citestyle = trim(lex.getString());
960 } else if (token == "\\use_bibtopic") {
962 } else if (token == "\\multibib") {
964 } else if (token == "\\use_indices") {
966 } else if (token == "\\tracking_changes") {
967 lex >> track_changes;
968 } else if (token == "\\output_changes") {
969 lex >> output_changes;
970 } else if (token == "\\change_bars") {
972 } else if (token == "\\postpone_fragile_content") {
973 lex >> postpone_fragile_content;
974 } else if (token == "\\branch") {
976 docstring branch = lex.getDocString();
977 branchlist().add(branch);
980 string const tok = lex.getString();
981 if (tok == "\\end_branch")
983 Branch * branch_ptr = branchlist().find(branch);
984 if (tok == "\\selected") {
987 branch_ptr->setSelected(lex.getInteger());
989 if (tok == "\\filename_suffix") {
992 branch_ptr->setFileNameSuffix(lex.getInteger());
994 if (tok == "\\color") {
996 vector<string> const colors = getVectorFromString(lex.getString(), " ");
997 string const lmcolor = colors.front();
999 if (colors.size() > 1)
1000 dmcolor = colors.back();
1002 branch_ptr->setColors(lmcolor, dmcolor);
1005 } else if (token == "\\index") {
1007 docstring index = lex.getDocString();
1009 indiceslist().add(index);
1012 string const tok = lex.getString();
1013 if (tok == "\\end_index")
1015 Index * index_ptr = indiceslist().find(index);
1016 if (tok == "\\shortcut") {
1018 shortcut = lex.getDocString();
1020 index_ptr->setShortcut(shortcut);
1022 if (tok == "\\color") {
1024 string color = lex.getString();
1026 index_ptr->setColor(color);
1027 // Update also the Color table:
1028 if (color == "none")
1029 color = lcolor.getX11HexName(Color_background);
1031 if (!shortcut.empty())
1032 lcolor.setColor(to_utf8(shortcut)+ "@" + filename.absFileName(), color);
1035 } else if (token == "\\author") {
1037 istringstream ss(lex.getString());
1041 } else if (token == "\\paperorientation") {
1044 orientation = paperorientationtranslator().find(orient);
1045 } else if (token == "\\backgroundcolor") {
1047 backgroundcolor = lyx::rgbFromHexName(lex.getString());
1048 isbackgroundcolor = true;
1049 } else if (token == "\\fontcolor") {
1051 fontcolor = lyx::rgbFromHexName(lex.getString());
1053 } else if (token == "\\notefontcolor") {
1055 string color = lex.getString();
1056 notefontcolor = lyx::rgbFromHexName(color);
1057 lcolor.setColor("notefontcolor", color);
1058 lcolor.setLaTeXName("notefontcolor", "note_fontcolor");
1059 // set a local name for the painter
1060 lcolor.setColor("notefontcolor@" + filename.absFileName(), color);
1061 isnotefontcolor = true;
1062 } else if (token == "\\boxbgcolor") {
1064 string color = lex.getString();
1065 boxbgcolor = lyx::rgbFromHexName(color);
1066 lcolor.setColor("boxbgcolor@" + filename.absFileName(), color);
1067 isboxbgcolor = true;
1068 } else if (token == "\\paperwidth") {
1070 } else if (token == "\\paperheight") {
1072 } else if (token == "\\leftmargin") {
1074 } else if (token == "\\topmargin") {
1076 } else if (token == "\\rightmargin") {
1078 } else if (token == "\\bottommargin") {
1079 lex >> bottommargin;
1080 } else if (token == "\\headheight") {
1082 } else if (token == "\\headsep") {
1084 } else if (token == "\\footskip") {
1086 } else if (token == "\\columnsep") {
1088 } else if (token == "\\paperfontsize") {
1090 } else if (token == "\\papercolumns") {
1092 } else if (token == "\\listings_params") {
1095 listings_params = InsetListingsParams(par).params();
1096 } else if (token == "\\papersides") {
1099 sides = sidestranslator().find(psides);
1100 } else if (token == "\\paperpagestyle") {
1102 } else if (token == "\\tablestyle") {
1104 } else if (token == "\\bullet") {
1106 } else if (token == "\\bulletLaTeX") {
1107 readBulletsLaTeX(lex);
1108 } else if (token == "\\secnumdepth") {
1110 } else if (token == "\\tocdepth") {
1112 } else if (token == "\\spacing") {
1116 if (nspacing == "other") {
1119 spacing().set(spacetranslator().find(nspacing), tmp_val);
1120 } else if (token == "\\float_placement") {
1121 lex >> float_placement;
1122 } else if (token == "\\float_alignment") {
1123 lex >> float_alignment;
1125 } else if (prefixIs(token, "\\pdf_") || token == "\\use_hyperref") {
1126 string toktmp = pdfoptions().readToken(lex, token);
1127 if (!toktmp.empty()) {
1128 lyxerr << "PDFOptions::readToken(): Unknown token: " <<
1132 } else if (token == "\\html_math_output") {
1135 html_math_output = static_cast<MathOutput>(temp);
1136 } else if (token == "\\html_be_strict") {
1137 lex >> html_be_strict;
1138 } else if (token == "\\html_css_as_file") {
1139 lex >> html_css_as_file;
1140 } else if (token == "\\html_math_img_scale") {
1141 lex >> html_math_img_scale;
1142 } else if (token == "\\html_latex_start") {
1144 html_latex_start = lex.getString();
1145 } else if (token == "\\html_latex_end") {
1147 html_latex_end = lex.getString();
1148 } else if (token == "\\docbook_table_output") {
1151 docbook_table_output = static_cast<TableOutput>(temp);
1152 } else if (token == "\\output_sync") {
1154 } else if (token == "\\output_sync_macro") {
1155 lex >> output_sync_macro;
1156 } else if (token == "\\use_refstyle") {
1157 lex >> use_refstyle;
1158 } else if (token == "\\use_minted") {
1160 } else if (token == "\\use_lineno") {
1162 } else if (token == "\\lineno_options") {
1164 lineno_opts = trim(lex.getString());
1166 lyxerr << "BufferParams::readToken(): Unknown token: " <<
1176 // Quote argument if it contains spaces
1177 string quoteIfNeeded(string const & str) {
1178 if (contains(str, ' '))
1179 return "\"" + str + "\"";
1185 void BufferParams::writeFile(ostream & os, Buffer const * buf) const
1187 // The top of the file is written by the buffer.
1188 // Prints out the buffer info into the .lyx file given by file
1190 os << "\\save_transient_properties "
1191 << convert<string>(save_transient_properties) << '\n';
1193 // the document directory (must end with a path separator)
1194 // realPath() is used to resolve symlinks, while addPath(..., "")
1195 // ensures a trailing path separator.
1197 string filepath = addPath(buf->fileName().onlyPath().realPath(), "");
1198 string const sysdir = inSystemDir(FileName(filepath), docsys) ? docsys
1199 : addPath(package().system_support().realPath(), "");
1200 string const relpath =
1201 to_utf8(makeRelPath(from_utf8(filepath), from_utf8(sysdir)));
1202 if (!prefixIs(relpath, "../") && !FileName::isAbsolute(relpath))
1203 filepath = addPath("/systemlyxdir", relpath);
1204 else if (!save_transient_properties || !lyxrc.save_origin)
1205 filepath = "unavailable";
1206 os << "\\origin " << quoteIfNeeded(filepath) << '\n';
1209 os << "\\textclass "
1210 << quoteIfNeeded(buf->includedFilePath(addName(buf->layoutPos(),
1211 baseClass()->name()), "layout"))
1214 // then the preamble
1215 if (!preamble.empty()) {
1216 // remove '\n' from the end of preamble
1217 docstring const tmppreamble = rtrim(preamble, "\n");
1218 os << "\\begin_preamble\n"
1219 << to_utf8(tmppreamble)
1220 << "\n\\end_preamble\n";
1224 if (!options.empty()) {
1225 os << "\\options " << options << '\n';
1228 // use the class options defined in the layout?
1229 os << "\\use_default_options "
1230 << convert<string>(use_default_options) << "\n";
1232 // the master document
1233 if (!master.empty()) {
1234 os << "\\master " << master << '\n';
1238 if (!removed_modules_.empty()) {
1239 os << "\\begin_removed_modules" << '\n';
1240 for (auto const & mod : removed_modules_)
1242 os << "\\end_removed_modules" << '\n';
1246 if (!layout_modules_.empty()) {
1247 os << "\\begin_modules" << '\n';
1248 for (auto const & mod : layout_modules_)
1250 os << "\\end_modules" << '\n';
1254 if (!included_children_.empty()) {
1255 os << "\\begin_includeonly" << '\n';
1256 for (auto const & c : included_children_)
1258 os << "\\end_includeonly" << '\n';
1261 switch (maintain_unincluded_children) {
1272 os << "\\maintain_unincluded_children " << muc << '\n';
1274 // local layout information
1275 docstring const local_layout = getLocalLayout(false);
1276 if (!local_layout.empty()) {
1277 // remove '\n' from the end
1278 docstring const tmplocal = rtrim(local_layout, "\n");
1279 os << "\\begin_local_layout\n"
1280 << to_utf8(tmplocal)
1281 << "\n\\end_local_layout\n";
1283 docstring const forced_local_layout = getLocalLayout(true);
1284 if (!forced_local_layout.empty()) {
1285 // remove '\n' from the end
1286 docstring const tmplocal = rtrim(forced_local_layout, "\n");
1287 os << "\\begin_forced_local_layout\n"
1288 << to_utf8(tmplocal)
1289 << "\n\\end_forced_local_layout\n";
1292 // then the text parameters
1293 if (language != ignore_language)
1294 os << "\\language " << language->lang() << '\n';
1295 os << "\\language_package " << lang_package
1296 << "\n\\inputencoding " << inputenc
1297 << "\n\\fontencoding " << fontenc
1298 << "\n\\font_roman \"" << fonts_roman[0]
1299 << "\" \"" << fonts_roman[1] << '"'
1300 << "\n\\font_sans \"" << fonts_sans[0]
1301 << "\" \"" << fonts_sans[1] << '"'
1302 << "\n\\font_typewriter \"" << fonts_typewriter[0]
1303 << "\" \"" << fonts_typewriter[1] << '"'
1304 << "\n\\font_math \"" << fonts_math[0]
1305 << "\" \"" << fonts_math[1] << '"'
1306 << "\n\\font_default_family " << fonts_default_family
1307 << "\n\\use_non_tex_fonts " << convert<string>(useNonTeXFonts)
1308 << "\n\\font_sc " << convert<string>(fonts_expert_sc)
1309 << "\n\\font_roman_osf " << convert<string>(fonts_roman_osf)
1310 << "\n\\font_sans_osf " << convert<string>(fonts_sans_osf)
1311 << "\n\\font_typewriter_osf " << convert<string>(fonts_typewriter_osf);
1312 if (!font_roman_opts.empty())
1313 os << "\n\\font_roman_opts \"" << font_roman_opts << "\"";
1314 os << "\n\\font_sf_scale " << fonts_sans_scale[0]
1315 << ' ' << fonts_sans_scale[1];
1316 if (!font_sans_opts.empty())
1317 os << "\n\\font_sans_opts \"" << font_sans_opts << "\"";
1318 os << "\n\\font_tt_scale " << fonts_typewriter_scale[0]
1319 << ' ' << fonts_typewriter_scale[1];
1320 if (!font_typewriter_opts.empty())
1321 os << "\n\\font_typewriter_opts \"" << font_typewriter_opts << "\"";
1323 if (!fonts_cjk.empty())
1324 os << "\\font_cjk " << fonts_cjk << '\n';
1325 os << "\\use_microtype " << convert<string>(use_microtype) << '\n';
1326 os << "\\use_dash_ligatures " << convert<string>(use_dash_ligatures) << '\n';
1327 os << "\\graphics " << graphics_driver << '\n';
1328 os << "\\default_output_format " << default_output_format << '\n';
1329 os << "\\output_sync " << output_sync << '\n';
1330 if (!output_sync_macro.empty())
1331 os << "\\output_sync_macro \"" << output_sync_macro << "\"\n";
1332 os << "\\bibtex_command " << bibtex_command << '\n';
1333 os << "\\index_command " << index_command << '\n';
1335 if (!float_placement.empty())
1336 os << "\\float_placement " << float_placement << '\n';
1337 if (!float_alignment.empty())
1338 os << "\\float_alignment " << float_alignment << '\n';
1339 os << "\\paperfontsize " << fontsize << '\n';
1341 spacing().writeFile(os);
1342 pdfoptions().writeFile(os);
1344 os << "\\papersize " << string_papersize[papersize]
1345 << "\n\\use_geometry " << convert<string>(use_geometry);
1346 map<string, string> const & packages = auto_packages();
1347 for (auto const & pack : packages)
1348 os << "\n\\use_package " << pack.first << ' '
1349 << use_package(pack.first);
1351 os << "\n\\cite_engine ";
1353 if (!cite_engine_.empty())
1358 os << "\n\\cite_engine_type " << theCiteEnginesList.getTypeAsString(cite_engine_type_);
1360 if (!biblio_style.empty())
1361 os << "\n\\biblio_style " << biblio_style;
1362 if (!biblio_opts.empty())
1363 os << "\n\\biblio_options " << biblio_opts;
1364 if (!biblatex_bibstyle.empty())
1365 os << "\n\\biblatex_bibstyle " << biblatex_bibstyle;
1366 if (!biblatex_citestyle.empty())
1367 os << "\n\\biblatex_citestyle " << biblatex_citestyle;
1368 if (!multibib.empty())
1369 os << "\n\\multibib " << multibib;
1371 os << "\n\\use_bibtopic " << convert<string>(use_bibtopic)
1372 << "\n\\use_indices " << convert<string>(use_indices)
1373 << "\n\\paperorientation " << string_orientation[orientation]
1374 << "\n\\suppress_date " << convert<string>(suppress_date)
1375 << "\n\\justification " << convert<string>(justification)
1376 << "\n\\use_refstyle " << use_refstyle
1377 << "\n\\use_minted " << use_minted
1378 << "\n\\use_lineno " << use_lineno
1381 if (!lineno_opts.empty())
1382 os << "\\lineno_options " << lineno_opts << '\n';
1384 if (isbackgroundcolor)
1385 os << "\\backgroundcolor " << lyx::X11hexname(backgroundcolor) << '\n';
1387 os << "\\fontcolor " << lyx::X11hexname(fontcolor) << '\n';
1388 if (isnotefontcolor)
1389 os << "\\notefontcolor " << lyx::X11hexname(notefontcolor) << '\n';
1391 os << "\\boxbgcolor " << lyx::X11hexname(boxbgcolor) << '\n';
1393 for (auto const & br : branchlist()) {
1394 os << "\\branch " << to_utf8(br.branch())
1395 << "\n\\selected " << br.isSelected()
1396 << "\n\\filename_suffix " << br.hasFileNameSuffix()
1397 << "\n\\color " << br.lightModeColor() << " " << br.darkModeColor()
1402 for (auto const & id : indiceslist()) {
1403 os << "\\index " << to_utf8(id.index())
1404 << "\n\\shortcut " << to_utf8(id.shortcut())
1405 << "\n\\color " << lyx::X11hexname(id.color())
1410 if (!paperwidth.empty())
1411 os << "\\paperwidth "
1412 << VSpace(paperwidth).asLyXCommand() << '\n';
1413 if (!paperheight.empty())
1414 os << "\\paperheight "
1415 << VSpace(paperheight).asLyXCommand() << '\n';
1416 if (!leftmargin.empty())
1417 os << "\\leftmargin "
1418 << VSpace(leftmargin).asLyXCommand() << '\n';
1419 if (!topmargin.empty())
1420 os << "\\topmargin "
1421 << VSpace(topmargin).asLyXCommand() << '\n';
1422 if (!rightmargin.empty())
1423 os << "\\rightmargin "
1424 << VSpace(rightmargin).asLyXCommand() << '\n';
1425 if (!bottommargin.empty())
1426 os << "\\bottommargin "
1427 << VSpace(bottommargin).asLyXCommand() << '\n';
1428 if (!headheight.empty())
1429 os << "\\headheight "
1430 << VSpace(headheight).asLyXCommand() << '\n';
1431 if (!headsep.empty())
1433 << VSpace(headsep).asLyXCommand() << '\n';
1434 if (!footskip.empty())
1436 << VSpace(footskip).asLyXCommand() << '\n';
1437 if (!columnsep.empty())
1438 os << "\\columnsep "
1439 << VSpace(columnsep).asLyXCommand() << '\n';
1440 os << "\\secnumdepth " << secnumdepth
1441 << "\n\\tocdepth " << tocdepth
1442 << "\n\\paragraph_separation "
1443 << string_paragraph_separation[paragraph_separation];
1444 if (!paragraph_separation)
1445 os << "\n\\paragraph_indentation "
1446 << (getParIndent().empty() ? "default" : getParIndent().asString());
1448 os << "\n\\defskip " << getDefSkip().asLyXCommand();
1449 os << "\n\\is_math_indent " << is_math_indent;
1451 os << "\n\\math_indentation "
1452 << (getMathIndent().empty() ? "default" : getMathIndent().asString());
1453 os << "\n\\math_numbering_side ";
1454 switch(math_numbering_side) {
1464 os << "\n\\quotes_style "
1465 << string_quotes_style[static_cast<int>(quotes_style)]
1466 << "\n\\dynamic_quotes " << dynamic_quotes
1467 << "\n\\papercolumns " << columns
1468 << "\n\\papersides " << sides
1469 << "\n\\paperpagestyle " << pagestyle
1470 << "\n\\tablestyle " << tablestyle << '\n';
1471 if (!listings_params.empty())
1472 os << "\\listings_params \"" <<
1473 InsetListingsParams(listings_params).encodedString() << "\"\n";
1474 for (int i = 0; i < 4; ++i) {
1475 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
1476 if (user_defined_bullet(i).getFont() != -1) {
1477 os << "\\bullet " << i << " "
1478 << user_defined_bullet(i).getFont() << " "
1479 << user_defined_bullet(i).getCharacter() << " "
1480 << user_defined_bullet(i).getSize() << "\n";
1484 os << "\\bulletLaTeX " << i << " \""
1485 << lyx::to_ascii(user_defined_bullet(i).getText())
1491 os << "\\tracking_changes "
1492 << (save_transient_properties ? convert<string>(track_changes) : "false")
1495 os << "\\output_changes "
1496 << (save_transient_properties ? convert<string>(output_changes) : "false")
1499 os << "\\change_bars "
1500 << (save_transient_properties ? convert<string>(change_bars) : "false")
1503 os << "\\postpone_fragile_content " << convert<string>(postpone_fragile_content) << '\n';
1505 os << "\\html_math_output " << html_math_output << '\n'
1506 << "\\html_css_as_file " << html_css_as_file << '\n'
1507 << "\\html_be_strict " << convert<string>(html_be_strict) << '\n';
1509 os << "\\docbook_table_output " << docbook_table_output << '\n';
1511 if (html_math_img_scale != 1.0)
1512 os << "\\html_math_img_scale " << convert<string>(html_math_img_scale) << '\n';
1513 if (!html_latex_start.empty())
1514 os << "\\html_latex_start " << html_latex_start << '\n';
1515 if (!html_latex_end.empty())
1516 os << "\\html_latex_end " << html_latex_end << '\n';
1518 os << pimpl_->authorlist;
1522 void BufferParams::validate(LaTeXFeatures & features) const
1524 features.require(documentClass().required());
1526 if (columns > 1 && language->rightToLeft())
1527 features.require("rtloutputdblcol");
1529 if (output_changes) {
1530 bool xcolorulem = LaTeXFeatures::isAvailable("ulem") &&
1531 LaTeXFeatures::isAvailable("xcolor");
1533 switch (features.runparams().flavor) {
1535 case Flavor::DviLuaTeX:
1537 features.require("ct-xcolor-ulem");
1538 features.require("ulem");
1539 features.require("xcolor");
1541 features.require("ct-none");
1544 case Flavor::LuaTeX:
1545 case Flavor::PdfLaTeX:
1548 features.require("ct-xcolor-ulem");
1549 features.require("ulem");
1550 features.require("xcolor");
1551 // improves color handling in PDF output
1552 features.require("pdfcolmk");
1554 features.require("ct-none");
1561 features.require("changebar");
1564 // Floats with 'Here definitely' as default setting.
1565 if (float_placement.find('H') != string::npos)
1566 features.require("float");
1568 for (auto const & pm : use_packages) {
1569 if (pm.first == "amsmath") {
1570 // AMS Style is at document level
1571 if (pm.second == package_on ||
1572 features.isProvided("amsmath"))
1573 features.require(pm.first);
1574 } else if (pm.second == package_on)
1575 features.require(pm.first);
1578 // Document-level line spacing
1579 if (spacing().getSpace() != Spacing::Single && !spacing().isDefault())
1580 features.require("setspace");
1582 // the bullet shapes are buffer level not paragraph level
1583 // so they are tested here
1584 for (int i = 0; i < 4; ++i) {
1585 if (user_defined_bullet(i) == ITEMIZE_DEFAULTS[i])
1587 int const font = user_defined_bullet(i).getFont();
1589 int const c = user_defined_bullet(i).getCharacter();
1595 features.require("latexsym");
1597 } else if (font == 1) {
1598 features.require("amssymb");
1599 } else if (font >= 2 && font <= 5) {
1600 features.require("pifont");
1604 if (pdfoptions().use_hyperref) {
1605 features.require("hyperref");
1606 // due to interferences with babel and hyperref, the color package has to
1607 // be loaded after hyperref when hyperref is used with the colorlinks
1608 // option, see http://www.lyx.org/trac/ticket/5291
1609 if (pdfoptions().colorlinks)
1610 features.require("color");
1612 if (!listings_params.empty()) {
1613 // do not test validity because listings_params is
1614 // supposed to be valid
1616 InsetListingsParams(listings_params).separatedParams(true);
1617 // we can't support all packages, but we should load the color package
1618 if (par.find("\\color", 0) != string::npos)
1619 features.require("color");
1622 // some languages are only available via polyglossia
1623 if (features.hasPolyglossiaExclusiveLanguages())
1624 features.require("polyglossia");
1626 if (useNonTeXFonts && fontsMath() != "auto")
1627 features.require("unicode-math");
1630 features.require("microtype");
1632 if (!language->required().empty())
1633 features.require(language->required());
1637 bool BufferParams::writeLaTeX(otexstream & os, LaTeXFeatures & features,
1638 FileName const & filepath) const
1640 // http://www.tug.org/texmf-dist/doc/latex/base/fixltx2e.pdf
1641 // !! To use the Fix-cm package, load it before \documentclass, and use the command
1642 // \RequirePackage to do so, rather than the normal \usepackage
1643 // Do not try to load any other package before the document class, unless you
1644 // have a thorough understanding of the LATEX internals and know exactly what you
1646 if (features.mustProvide("fix-cm"))
1647 os << "\\RequirePackage{fix-cm}\n";
1648 // Likewise for fixltx2e. If other packages conflict with this policy,
1649 // treat it as a package bug (and report it!)
1650 // See http://www.latex-project.org/cgi-bin/ltxbugs2html?pr=latex/4407
1651 if (features.mustProvide("fixltx2e"))
1652 os << "\\RequirePackage{fixltx2e}\n";
1654 os << "\\documentclass";
1656 DocumentClass const & tclass = documentClass();
1658 ostringstream clsoptions; // the document class options.
1660 if (tokenPos(tclass.opt_fontsize(),
1661 '|', fontsize) >= 0) {
1662 // only write if existing in list (and not default)
1663 clsoptions << subst(tclass.fontsizeformat(), "$$s", fontsize) << ",";
1666 // paper sizes not supported by the class itself need the
1668 vector<string> classpsizes = getVectorFromString(tclass.opt_pagesize(), "|");
1669 bool class_supported_papersize = papersize == PAPER_DEFAULT
1670 || find(classpsizes.begin(), classpsizes.end(), string_papersize[papersize]) != classpsizes.end();
1672 if ((!use_geometry || features.isProvided("geometry-light"))
1673 && class_supported_papersize && papersize != PAPER_DEFAULT)
1674 clsoptions << subst(tclass.pagesizeformat(), "$$s", string_papersize[papersize]) << ",";
1677 if (sides != tclass.sides()) {
1680 clsoptions << "oneside,";
1683 clsoptions << "twoside,";
1689 if (columns != tclass.columns()) {
1691 clsoptions << "twocolumn,";
1693 clsoptions << "onecolumn,";
1697 && orientation == ORIENTATION_LANDSCAPE)
1698 clsoptions << "landscape,";
1701 clsoptions << "fleqn,";
1703 switch(math_numbering_side) {
1705 clsoptions << "leqno,";
1708 clsoptions << "reqno,";
1709 features.require("amsmath");
1715 // language should be a parameter to \documentclass
1716 if (language->babel() == "hebrew"
1717 && default_language->babel() != "hebrew")
1718 // This seems necessary
1719 features.useLanguage(default_language);
1721 ostringstream language_options;
1722 bool const use_babel = features.useBabel() && !features.isProvided("babel");
1723 bool const use_polyglossia = features.usePolyglossia();
1724 bool const global = lyxrc.language_global_options;
1725 if (features.useBabel() || (use_polyglossia && global)) {
1726 language_options << features.getBabelLanguages();
1727 if (!language->babel().empty()) {
1728 if (!language_options.str().empty())
1729 language_options << ',';
1730 language_options << language->babel();
1732 if (global && !language_options.str().empty())
1733 clsoptions << language_options.str() << ',';
1736 // the predefined options from the layout
1737 if (use_default_options && !tclass.options().empty())
1738 clsoptions << tclass.options() << ',';
1740 // the user-defined options
1741 if (!options.empty()) {
1742 clsoptions << options << ',';
1745 docstring const strOptions = from_utf8(clsoptions.str());
1746 if (!strOptions.empty()) {
1747 // Check if class options contain uncodable glyphs
1748 docstring uncodable_glyphs;
1749 docstring options_encodable;
1750 Encoding const * const enc = features.runparams().encoding;
1752 for (char_type c : strOptions) {
1753 if (!enc->encodable(c)) {
1754 docstring const glyph(1, c);
1755 LYXERR0("Uncodable character '"
1757 << "' in class options!");
1758 uncodable_glyphs += glyph;
1759 if (features.runparams().dryrun) {
1760 options_encodable += "<" + _("LyX Warning: ")
1761 + _("uncodable character") + " '";
1762 options_encodable += c;
1763 options_encodable += "'>";
1766 options_encodable += c;
1769 options_encodable = strOptions;
1771 // On BUFFER_VIEW|UPDATE, warn user if we found uncodable glyphs
1772 if (!features.runparams().dryrun && !uncodable_glyphs.empty()) {
1773 frontend::Alert::warning(
1774 _("Uncodable character in class options"),
1776 _("The class options of your document contain glyphs "
1777 "that are unknown in the current document encoding "
1778 "(namely %1$s).\nThese glyphs are omitted "
1779 " from the output, which may result in "
1780 "incomplete output."
1781 "\n\nPlease select an appropriate "
1782 "document encoding\n"
1783 "(such as utf8) or change the "
1784 "class options accordingly."),
1787 options_encodable = rtrim(options_encodable, ",");
1788 os << '[' << options_encodable << ']';
1791 os << '{' << from_ascii(tclass.latexname()) << "}\n";
1792 // end of \documentclass defs
1794 // The package options (via \PassOptionsToPackage)
1795 os << from_ascii(features.getPackageOptions());
1797 // if we use fontspec or newtxmath, we have to load the AMS packages here
1798 string const ams = features.loadAMSPackages();
1799 bool const ot1 = (main_font_encoding() == "default" || main_font_encoding() == "OT1");
1800 bool const use_newtxmath =
1801 theLaTeXFonts().getLaTeXFont(from_ascii(fontsMath())).getUsedPackage(
1802 ot1, false, false) == "newtxmath";
1803 if ((useNonTeXFonts || use_newtxmath) && !ams.empty())
1804 os << from_ascii(ams);
1806 if (useNonTeXFonts) {
1807 // Babel (as of 2017/11/03) loads fontspec itself
1808 if (!features.isProvided("fontspec")
1809 && !(features.useBabel() && features.isAvailable("babel-2017/11/03")))
1810 os << "\\usepackage{fontspec}\n";
1811 if (features.mustProvide("unicode-math")
1812 && features.isAvailable("unicode-math"))
1813 os << "\\usepackage{unicode-math}\n";
1816 // load CJK support package before font selection
1817 // (see autotests/export/latex/CJK/micro-sign_utf8-cjk-libertine.lyx)
1818 if (!useNonTeXFonts && encoding().package() != Encoding::none && inputenc != "utf8x"
1819 && (encoding().package() == Encoding::CJK || features.mustProvide("CJK"))) {
1820 if (inputenc == "utf8-cjk" || inputenc == "utf8")
1821 os << "\\usepackage{CJKutf8}\n";
1823 os << "\\usepackage[encapsulated]{CJK}\n";
1826 // font selection must be done before loading fontenc.sty
1827 // but after babel with non-TeX fonts
1828 string const fonts = loadFonts(features);
1829 if (!fonts.empty() && (!features.useBabel() || !useNonTeXFonts))
1830 os << from_utf8(fonts);
1832 if (fonts_default_family != "default")
1833 os << "\\renewcommand{\\familydefault}{\\"
1834 << from_ascii(fonts_default_family) << "}\n";
1836 // set font encoding
1837 // non-TeX fonts use font encoding TU (set by fontspec)
1838 if (!useNonTeXFonts && !features.isProvided("fontenc")
1839 && main_font_encoding() != "default") {
1840 // get main font encodings
1841 vector<string> fontencs = font_encodings();
1842 // get font encodings of secondary languages
1843 // FIXME: some languages (hebrew, ...) assume a standard font encoding as last
1844 // option (for text in other languages).
1845 features.getFontEncodings(fontencs);
1846 if (!fontencs.empty()) {
1847 os << "\\usepackage["
1848 << from_ascii(getStringFromVector(fontencs))
1853 // Load textcomp and pmboxdraw before (lua)inputenc (#11454)
1854 if (features.mustProvide("textcomp"))
1855 os << "\\usepackage{textcomp}\n";
1856 if (features.mustProvide("pmboxdraw"))
1857 os << "\\usepackage{pmboxdraw}\n";
1859 // handle inputenc etc.
1860 // (In documents containing text in Thai language,
1861 // we must load inputenc after babel, see lib/languages).
1862 if (!contains(features.getBabelPostsettings(), from_ascii("thai.ldf")))
1863 writeEncodingPreamble(os, features);
1866 if (!features.runparams().includeall && !included_children_.empty()) {
1867 os << "\\includeonly{";
1869 for (auto incfile : included_children_) {
1870 FileName inc = makeAbsPath(incfile, filepath.absFileName());
1871 string mangled = DocFileName(changeExtension(inc.absFileName(), ".tex")).
1873 if (!features.runparams().nice)
1875 // \includeonly doesn't want an extension
1876 incfile = changeExtension(incfile, string());
1877 incfile = support::latex_path(incfile);
1878 if (!incfile.empty()) {
1881 os << from_utf8(incfile);
1888 if (!features.isProvided("geometry")
1889 && (use_geometry || !class_supported_papersize)) {
1890 odocstringstream ods;
1891 if (!getGraphicsDriver("geometry").empty())
1892 ods << getGraphicsDriver("geometry");
1893 if (orientation == ORIENTATION_LANDSCAPE)
1894 ods << ",landscape";
1895 switch (papersize) {
1897 if (!paperwidth.empty())
1898 ods << ",paperwidth="
1899 << from_ascii(paperwidth);
1900 if (!paperheight.empty())
1901 ods << ",paperheight="
1902 << from_ascii(paperheight);
1904 case PAPER_USLETTER:
1906 case PAPER_USEXECUTIVE:
1935 ods << "," << from_ascii(string_papersize_geometry[papersize]);
1940 docstring g_options = trim(ods.str(), ",");
1941 os << "\\usepackage";
1942 // geometry-light means that the class works with geometry, but overwrites
1943 // the package options and paper sizes (memoir does this).
1944 // In this case, all options need to go to \geometry
1945 // and the standard paper sizes need to go to the class options.
1946 if (!g_options.empty() && !features.isProvided("geometry-light")) {
1947 os << '[' << g_options << ']';
1950 os << "{geometry}\n";
1951 if (use_geometry || features.isProvided("geometry-light")) {
1952 os << "\\geometry{verbose";
1953 if (!g_options.empty())
1954 // Output general options here with "geometry light".
1955 os << "," << g_options;
1956 // output this only if use_geometry is true
1958 if (!topmargin.empty())
1959 os << ",tmargin=" << from_ascii(Length(topmargin).asLatexString());
1960 if (!bottommargin.empty())
1961 os << ",bmargin=" << from_ascii(Length(bottommargin).asLatexString());
1962 if (!leftmargin.empty())
1963 os << ",lmargin=" << from_ascii(Length(leftmargin).asLatexString());
1964 if (!rightmargin.empty())
1965 os << ",rmargin=" << from_ascii(Length(rightmargin).asLatexString());
1966 if (!headheight.empty())
1967 os << ",headheight=" << from_ascii(Length(headheight).asLatexString());
1968 if (!headsep.empty())
1969 os << ",headsep=" << from_ascii(Length(headsep).asLatexString());
1970 if (!footskip.empty())
1971 os << ",footskip=" << from_ascii(Length(footskip).asLatexString());
1972 if (!columnsep.empty())
1973 os << ",columnsep=" << from_ascii(Length(columnsep).asLatexString());
1977 } else if (orientation == ORIENTATION_LANDSCAPE
1978 || papersize != PAPER_DEFAULT) {
1979 features.require("papersize");
1982 if (tokenPos(tclass.opt_pagestyle(), '|', pagestyle) >= 0) {
1983 if (pagestyle == "fancy")
1984 os << "\\usepackage{fancyhdr}\n";
1985 os << "\\pagestyle{" << from_ascii(pagestyle) << "}\n";
1988 // only output when the background color is not default
1989 if (isbackgroundcolor) {
1990 // only require color here, the background color will be defined
1991 // in LaTeXFeatures.cpp to avoid interferences with the LaTeX
1993 features.require("color");
1994 features.require("pagecolor");
1997 // only output when the font color is not default
1999 // only require color here, the font color will be defined
2000 // in LaTeXFeatures.cpp to avoid interferences with the LaTeX
2002 features.require("color");
2003 features.require("fontcolor");
2006 // Only if class has a ToC hierarchy
2007 if (tclass.hasTocLevels()) {
2008 if (secnumdepth != tclass.secnumdepth()) {
2009 os << "\\setcounter{secnumdepth}{"
2013 if (tocdepth != tclass.tocdepth()) {
2014 os << "\\setcounter{tocdepth}{"
2020 if (paragraph_separation) {
2021 // when skip separation
2023 switch (getDefSkip().kind()) {
2024 case VSpace::SMALLSKIP:
2025 psopt = "\\smallskipamount";
2027 case VSpace::MEDSKIP:
2028 psopt = "\\medskipamount";
2030 case VSpace::BIGSKIP:
2031 psopt = "\\bigskipamount";
2033 case VSpace::HALFLINE:
2034 // default (no option)
2036 case VSpace::FULLLINE:
2037 psopt = "\\baselineskip";
2039 case VSpace::LENGTH:
2040 psopt = getDefSkip().length().asLatexString();
2045 if (!features.isProvided("parskip")) {
2047 psopt = "[skip=" + psopt + "]";
2048 os << "\\usepackage" + psopt + "{parskip}\n";
2050 os << "\\setlength{\\parskip}{" + psopt + "}\n";
2053 // when separation by indentation
2054 // only output something when a width is given
2055 if (!getParIndent().empty()) {
2056 os << "\\setlength{\\parindent}{"
2057 << from_utf8(getParIndent().asLatexString())
2062 if (is_math_indent) {
2063 // when formula indentation
2064 // only output something when it is not the default
2065 if (!getMathIndent().empty()) {
2066 os << "\\setlength{\\mathindent}{"
2067 << from_utf8(getMathIndent().asString())
2072 // Now insert the LyX specific LaTeX commands...
2073 features.resolveAlternatives();
2074 features.expandMultiples();
2077 if (!output_sync_macro.empty())
2078 os << from_utf8(output_sync_macro) +"\n";
2079 else if (features.runparams().flavor == Flavor::LaTeX)
2080 os << "\\usepackage[active]{srcltx}\n";
2081 else if (features.runparams().flavor == Flavor::PdfLaTeX)
2082 os << "\\synctex=-1\n";
2085 // due to interferences with babel and hyperref, the color package has to
2086 // be loaded (when it is not already loaded) before babel when hyperref
2087 // is used with the colorlinks option, see
2088 // http://www.lyx.org/trac/ticket/5291
2089 // we decided therefore to load color always before babel, see
2090 // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg144349.html
2091 os << from_ascii(features.getColorOptions());
2093 // If we use hyperref, jurabib, japanese or varioref,
2094 // we have to call babel before
2096 && (features.isRequired("jurabib")
2097 || features.isRequired("hyperref")
2098 || features.isRequired("varioref")
2099 || features.isRequired("japanese"))) {
2100 os << features.getBabelPresettings();
2102 os << from_utf8(babelCall(language_options.str(),
2103 !lyxrc.language_global_options)) + '\n';
2104 os << features.getBabelPostsettings();
2107 // The optional packages;
2108 os << from_ascii(features.getPackages());
2110 // Additional Indices
2111 if (features.isRequired("splitidx")) {
2112 for (auto const & idx : indiceslist()) {
2113 os << "\\newindex{";
2114 os << escape(idx.shortcut());
2120 os << from_utf8(spacing().writePreamble(features.isProvided("SetSpace")));
2123 // * Hyperref manual: "Make sure it comes last of your loaded
2124 // packages, to give it a fighting chance of not being over-written,
2125 // since its job is to redefine many LaTeX commands."
2126 // * Email from Heiko Oberdiek: "It is usually better to load babel
2127 // before hyperref. Then hyperref has a chance to detect babel.
2128 // * Has to be loaded before the "LyX specific LaTeX commands" to
2129 // avoid errors with algorithm floats.
2130 // use hyperref explicitly if it is required
2131 if (features.isRequired("hyperref")) {
2132 OutputParams tmp_params = features.runparams();
2133 pdfoptions().writeLaTeX(tmp_params, os,
2134 features.isProvided("hyperref"));
2135 // correctly break URLs with hyperref and dvi/ps output
2136 if (features.runparams().hyperref_driver == "dvips"
2137 && features.isAvailable("breakurl"))
2138 os << "\\usepackage{breakurl}\n";
2139 } else if (features.isRequired("nameref"))
2140 // hyperref loads this automatically
2141 os << "\\usepackage{nameref}\n";
2144 os << "\\usepackage";
2145 if (!lineno_opts.empty())
2146 os << "[" << lineno_opts << "]";
2148 os << "\\linenumbers\n";
2151 // bibtopic needs to be loaded after hyperref.
2152 // the dot provides the aux file naming which LyX can detect.
2153 if (features.mustProvide("bibtopic"))
2154 os << "\\usepackage[dot]{bibtopic}\n";
2156 // Will be surrounded by \makeatletter and \makeatother when not empty
2157 otexstringstream atlyxpreamble;
2159 // Some macros LyX will need
2161 TexString tmppreamble = features.getMacros();
2162 if (!tmppreamble.str.empty())
2163 atlyxpreamble << "\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
2164 "LyX specific LaTeX commands.\n"
2165 << move(tmppreamble)
2168 // the text class specific preamble
2170 docstring tmppreamble = features.getTClassPreamble();
2171 if (!tmppreamble.empty())
2172 atlyxpreamble << "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
2173 "Textclass specific LaTeX commands.\n"
2177 // suppress date if selected
2178 // use \@ifundefined because we cannot be sure that every document class
2179 // has a \date command
2181 atlyxpreamble << "\\@ifundefined{date}{}{\\date{}}\n";
2183 /* the user-defined preamble */
2184 if (!containsOnly(preamble, " \n\t")) {
2186 atlyxpreamble << "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
2187 "User specified LaTeX commands.\n";
2189 // Check if the user preamble contains uncodable glyphs
2190 odocstringstream user_preamble;
2191 docstring uncodable_glyphs;
2192 Encoding const * const enc = features.runparams().encoding;
2194 for (char_type c : preamble) {
2195 if (!enc->encodable(c)) {
2196 docstring const glyph(1, c);
2197 LYXERR0("Uncodable character '"
2199 << "' in user preamble!");
2200 uncodable_glyphs += glyph;
2201 if (features.runparams().dryrun) {
2202 user_preamble << "<" << _("LyX Warning: ")
2203 << _("uncodable character") << " '";
2204 user_preamble.put(c);
2205 user_preamble << "'>";
2208 user_preamble.put(c);
2211 user_preamble << preamble;
2213 // On BUFFER_VIEW|UPDATE, warn user if we found uncodable glyphs
2214 if (!features.runparams().dryrun && !uncodable_glyphs.empty()) {
2215 frontend::Alert::warning(
2216 _("Uncodable character in user preamble"),
2218 _("The user preamble of your document contains glyphs "
2219 "that are unknown in the current document encoding "
2220 "(namely %1$s).\nThese glyphs are omitted "
2221 " from the output, which may result in "
2222 "incomplete output."
2223 "\n\nPlease select an appropriate "
2224 "document encoding\n"
2225 "(such as utf8) or change the "
2226 "preamble code accordingly."),
2229 atlyxpreamble << user_preamble.str() << '\n';
2232 // footmisc must be loaded after setspace
2233 // Load it here to avoid clashes with footmisc loaded in the user
2234 // preamble. For that reason we also pass the options via
2235 // \PassOptionsToPackage in getPreamble() and not here.
2236 if (features.mustProvide("footmisc"))
2237 atlyxpreamble << "\\usepackage{footmisc}\n";
2239 // subfig loads internally the LaTeX package "caption". As
2240 // caption is a very popular package, users will load it in
2241 // the preamble. Therefore we must load subfig behind the
2242 // user-defined preamble and check if the caption package was
2243 // loaded or not. For the case that caption is loaded before
2244 // subfig, there is the subfig option "caption=false". This
2245 // option also works when a koma-script class is used and
2246 // koma's own caption commands are used instead of caption. We
2247 // use \PassOptionsToPackage here because the user could have
2248 // already loaded subfig in the preamble.
2249 if (features.mustProvide("subfig"))
2250 atlyxpreamble << "\\ifdefined\\showcaptionsetup\n"
2251 " % Caption package is used. Advise subfig not to load it again.\n"
2252 " \\PassOptionsToPackage{caption=false}{subfig}\n"
2254 "\\usepackage{subfig}\n";
2256 // Itemize bullet settings need to be last in case the user
2257 // defines their own bullets that use a package included
2258 // in the user-defined preamble -- ARRae
2259 // Actually it has to be done much later than that
2260 // since some packages like frenchb make modifications
2261 // at \begin{document} time -- JMarc
2262 docstring bullets_def;
2263 for (int i = 0; i < 4; ++i) {
2264 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
2265 if (bullets_def.empty())
2266 bullets_def += "\\AtBeginDocument{\n";
2267 bullets_def += " \\def\\labelitemi";
2269 // `i' is one less than the item to modify
2276 bullets_def += "ii";
2282 bullets_def += '{' +
2283 user_defined_bullet(i).getText()
2288 if (!bullets_def.empty())
2289 atlyxpreamble << bullets_def << "}\n\n";
2291 if (!atlyxpreamble.empty())
2292 os << "\n\\makeatletter\n"
2293 << atlyxpreamble.release()
2294 << "\\makeatother\n\n";
2296 // We try to load babel late, in case it interferes with other packages.
2297 // Jurabib, hyperref, varioref, bicaption, menukeys and listings (bug 8995)
2298 // have to be called after babel, though.
2299 if (use_babel && !features.isRequired("jurabib")
2300 && !features.isRequired("hyperref")
2301 && !features.isRequired("varioref")
2302 && !features.isRequired("japanese")) {
2303 os << features.getBabelPresettings();
2305 os << from_utf8(babelCall(language_options.str(),
2306 !lyxrc.language_global_options)) + '\n';
2307 os << features.getBabelPostsettings();
2309 // In documents containing text in Thai language,
2310 // we must load inputenc after babel (see lib/languages).
2311 if (contains(features.getBabelPostsettings(), from_ascii("thai.ldf")))
2312 writeEncodingPreamble(os, features);
2314 // font selection must be done after babel with non-TeX fonts
2315 if (!fonts.empty() && features.useBabel() && useNonTeXFonts)
2316 os << from_utf8(fonts);
2318 if (features.isRequired("bicaption"))
2319 os << "\\usepackage{bicaption}\n";
2320 if (!listings_params.empty()
2321 || features.mustProvide("listings")
2322 || features.mustProvide("minted")) {
2324 os << "\\usepackage{minted}\n";
2326 os << "\\usepackage{listings}\n";
2328 string lst_params = listings_params;
2329 // If minted, do not output the language option (bug 11203)
2330 if (use_minted && contains(lst_params, "language=")) {
2331 vector<string> opts =
2332 getVectorFromString(lst_params, ",", false);
2333 for (size_t i = 0; i < opts.size(); ++i) {
2334 if (prefixIs(opts[i], "language="))
2335 opts.erase(opts.begin() + i--);
2337 lst_params = getStringFromVector(opts, ",");
2339 if (!lst_params.empty()) {
2341 os << "\\setminted{";
2344 // do not test validity because listings_params is
2345 // supposed to be valid
2347 InsetListingsParams(lst_params).separatedParams(true);
2348 os << from_utf8(par);
2352 // xunicode only needs to be loaded if tipa is used
2353 // (the rest is obsoleted by the new TU encoding).
2354 // It needs to be loaded at least after amsmath, amssymb,
2355 // esint and the other packages that provide special glyphs
2356 if (features.mustProvide("tipa") && useNonTeXFonts
2357 && !features.isProvided("xunicode")) {
2358 // The `xunicode` package officially only supports XeTeX,
2359 // but also works with LuaTeX. We work around its XeTeX test.
2360 if (features.runparams().flavor != Flavor::XeTeX) {
2361 os << "% Pretend to xunicode that we are XeTeX\n"
2362 << "\\def\\XeTeXpicfile{}\n";
2364 os << "\\usepackage{xunicode}\n";
2367 // covington must be loaded after beamerarticle
2368 if (features.isRequired("covington"))
2369 os << "\\usepackage{covington}\n";
2371 // Polyglossia must be loaded last ...
2372 if (use_polyglossia) {
2374 os << "\\usepackage{polyglossia}\n";
2375 // set the main language
2376 os << "\\setdefaultlanguage";
2377 if (!language->polyglossiaOpts().empty())
2378 os << "[" << from_ascii(language->polyglossiaOpts()) << "]";
2379 os << "{" << from_ascii(language->polyglossia()) << "}\n";
2380 // now setup the other languages
2381 set<string> const polylangs =
2382 features.getPolyglossiaLanguages();
2383 for (auto const & pl : polylangs) {
2384 // We do not output the options here; they are output in
2385 // the language switch commands. This is safer if multiple
2386 // varieties are used.
2387 if (pl == language->polyglossia())
2389 os << "\\setotherlanguage";
2390 os << "{" << from_ascii(pl) << "}\n";
2394 // ... but before biblatex (see #7065)
2395 if ((features.mustProvide("biblatex")
2396 || features.isRequired("biblatex-chicago"))
2397 && !features.isProvided("biblatex-chicago")
2398 && !features.isProvided("biblatex-natbib")
2399 && !features.isProvided("natbib-internal")
2400 && !features.isProvided("natbib")
2401 && !features.isProvided("jurabib")) {
2402 // The biblatex-chicago package has a differing interface
2403 // it uses a wrapper package and loads styles via fixed options
2404 bool const chicago = features.isRequired("biblatex-chicago");
2407 os << "\\usepackage";
2408 if (!biblatex_bibstyle.empty()
2409 && (biblatex_bibstyle == biblatex_citestyle)
2411 opts = "style=" + biblatex_bibstyle;
2413 } else if (!chicago) {
2414 if (!biblatex_bibstyle.empty()) {
2415 opts = "bibstyle=" + biblatex_bibstyle;
2418 if (!biblatex_citestyle.empty()) {
2419 opts += delim + "citestyle=" + biblatex_citestyle;
2423 if (!multibib.empty() && multibib != "child") {
2424 opts += delim + "refsection=" + multibib;
2427 if (bibtexCommand() == "bibtex8"
2428 || prefixIs(bibtexCommand(), "bibtex8 ")) {
2429 opts += delim + "backend=bibtex8";
2431 } else if (bibtexCommand() == "bibtex"
2432 || prefixIs(bibtexCommand(), "bibtex ")) {
2433 opts += delim + "backend=bibtex";
2436 if (!bib_encoding.empty() && encodings.fromLyXName(bib_encoding)) {
2437 opts += delim + "bibencoding="
2438 + encodings.fromLyXName(bib_encoding)->latexName();
2441 if (!biblio_opts.empty())
2442 opts += delim + biblio_opts;
2444 os << "[" << opts << "]";
2446 os << "{biblatex-chicago}\n";
2448 os << "{biblatex}\n";
2452 // Load custom language package here
2453 if (features.langPackage() == LaTeXFeatures::LANG_PACK_CUSTOM) {
2454 if (lang_package == "default")
2455 os << from_utf8(lyxrc.language_custom_package);
2457 os << from_utf8(lang_package);
2461 // Since menukeys uses catoptions, which does some heavy changes on key-value options,
2462 // it is recommended to load menukeys as the last package (even after hyperref)
2463 if (features.isRequired("menukeys"))
2464 os << "\\usepackage{menukeys}\n";
2466 docstring const i18npreamble =
2467 features.getTClassI18nPreamble(use_babel, use_polyglossia,
2469 if (!i18npreamble.empty())
2470 os << i18npreamble + '\n';
2476 void BufferParams::useClassDefaults()
2478 DocumentClass const & tclass = documentClass();
2480 sides = tclass.sides();
2481 columns = tclass.columns();
2482 pagestyle = tclass.pagestyle();
2483 tablestyle = tclass.tablestyle();
2484 use_default_options = true;
2485 // Only if class has a ToC hierarchy
2486 if (tclass.hasTocLevels()) {
2487 secnumdepth = tclass.secnumdepth();
2488 tocdepth = tclass.tocdepth();
2493 bool BufferParams::hasClassDefaults() const
2495 DocumentClass const & tclass = documentClass();
2497 return sides == tclass.sides()
2498 && columns == tclass.columns()
2499 && pagestyle == tclass.pagestyle()
2500 && tablestyle == tclass.tablestyle()
2501 && use_default_options
2502 && secnumdepth == tclass.secnumdepth()
2503 && tocdepth == tclass.tocdepth();
2507 DocumentClass const & BufferParams::documentClass() const
2513 DocumentClassConstPtr BufferParams::documentClassPtr() const
2519 void BufferParams::setDocumentClass(DocumentClassConstPtr tc)
2521 // evil, but this function is evil
2522 doc_class_ = const_pointer_cast<DocumentClass>(tc);
2523 invalidateConverterCache();
2527 bool BufferParams::setBaseClass(string const & classname, string const & path)
2529 LYXERR(Debug::TCLASS, "setBaseClass: " << classname);
2530 LayoutFileList & bcl = LayoutFileList::get();
2531 if (!bcl.haveClass(classname)) {
2533 bformat(_("The layout file:\n"
2535 "could not be found. A default textclass with default\n"
2536 "layouts will be used. LyX will not be able to produce\n"
2538 from_utf8(classname));
2539 frontend::Alert::error(_("Document class not found"), s);
2540 bcl.addEmptyClass(classname);
2543 bool const success = bcl[classname].load(path);
2546 bformat(_("Due to some error in it, the layout file:\n"
2548 "could not be loaded. A default textclass with default\n"
2549 "layouts will be used. LyX will not be able to produce\n"
2551 from_utf8(classname));
2552 frontend::Alert::error(_("Could not load class"), s);
2553 bcl.addEmptyClass(classname);
2556 pimpl_->baseClass_ = classname;
2557 layout_modules_.adaptToBaseClass(baseClass(), removed_modules_);
2562 LayoutFile const * BufferParams::baseClass() const
2564 if (LayoutFileList::get().haveClass(pimpl_->baseClass_))
2565 return &(LayoutFileList::get()[pimpl_->baseClass_]);
2571 LayoutFileIndex const & BufferParams::baseClassID() const
2573 return pimpl_->baseClass_;
2577 void BufferParams::makeDocumentClass(bool clone, bool internal)
2582 invalidateConverterCache();
2583 LayoutModuleList mods;
2584 for (auto const & mod : layout_modules_)
2585 mods.push_back(mod);
2587 doc_class_ = getDocumentClass(*baseClass(), mods, cite_engine_, clone, internal);
2589 TextClass::ReturnValues success = TextClass::OK;
2590 if (!forced_local_layout_.empty())
2591 success = doc_class_->read(to_utf8(forced_local_layout_),
2593 if (!local_layout_.empty() &&
2594 (success == TextClass::OK || success == TextClass::OK_OLDFORMAT))
2595 success = doc_class_->read(to_utf8(local_layout_), TextClass::MODULE);
2596 if (success != TextClass::OK && success != TextClass::OK_OLDFORMAT) {
2597 docstring const msg = _("Error reading internal layout information");
2598 frontend::Alert::warning(_("Read Error"), msg);
2603 bool BufferParams::layoutModuleCanBeAdded(string const & modName) const
2605 return layout_modules_.moduleCanBeAdded(modName, baseClass());
2609 docstring BufferParams::getLocalLayout(bool forced) const
2612 return from_utf8(doc_class_->forcedLayouts());
2614 return local_layout_;
2618 void BufferParams::setLocalLayout(docstring const & layout, bool forced)
2621 forced_local_layout_ = layout;
2623 local_layout_ = layout;
2627 bool BufferParams::addLayoutModule(string const & modName)
2629 for (auto const & mod : layout_modules_)
2632 layout_modules_.push_back(modName);
2637 string BufferParams::bufferFormat() const
2639 return documentClass().outputFormat();
2643 bool BufferParams::isExportable(string const & format, bool need_viewable) const
2645 FormatList const & formats = exportableFormats(need_viewable);
2646 for (auto const & fmt : formats) {
2647 if (fmt->name() == format)
2654 FormatList const & BufferParams::exportableFormats(bool only_viewable) const
2656 FormatList & cached = only_viewable ?
2657 pimpl_->viewableFormatList : pimpl_->exportableFormatList;
2658 bool & valid = only_viewable ?
2659 pimpl_->isViewCacheValid : pimpl_->isExportCacheValid;
2663 vector<string> const backs = backends();
2664 set<string> excludes;
2665 if (useNonTeXFonts) {
2666 excludes.insert("latex");
2667 excludes.insert("pdflatex");
2668 } else if (inputenc != "ascii" && inputenc != "utf8-plain") {
2669 // XeTeX with TeX fonts requires input encoding ascii (#10600).
2670 excludes.insert("xetex");
2674 theConverters().getReachable(backs[0], only_viewable, true, excludes);
2675 vector<string>::const_iterator it = backs.begin() + 1;
2676 for (; it != backs.end(); ++it) {
2677 FormatList r = theConverters().getReachable(*it, only_viewable,
2679 result.insert(result.end(), r.begin(), r.end());
2681 sort(result.begin(), result.end(), Format::formatSorter);
2688 vector<string> BufferParams::backends() const
2691 string const buffmt = bufferFormat();
2693 // FIXME: Don't hardcode format names here, but use a flag
2694 if (buffmt == "latex") {
2695 if (encoding().package() == Encoding::japanese)
2696 v.push_back("platex");
2698 if (!useNonTeXFonts) {
2699 v.push_back("pdflatex");
2700 v.push_back("latex");
2703 || inputenc == "ascii" || inputenc == "utf8-plain")
2704 v.push_back("xetex");
2705 v.push_back("luatex");
2706 v.push_back("dviluatex");
2709 string rbuffmt = buffmt;
2710 // If we use an OutputFormat in Japanese docs,
2711 // we need special format in order to get the path
2712 // via pLaTeX (#8823)
2713 if (documentClass().hasOutputFormat()
2714 && encoding().package() == Encoding::japanese)
2716 v.push_back(rbuffmt);
2719 v.push_back("xhtml");
2720 v.push_back("docbook5");
2721 v.push_back("text");
2727 Flavor BufferParams::getOutputFlavor(string const & format) const
2729 string const dformat = (format.empty() || format == "default") ?
2730 getDefaultOutputFormat() : format;
2731 DefaultFlavorCache::const_iterator it =
2732 default_flavors_.find(dformat);
2734 if (it != default_flavors_.end())
2737 Flavor result = Flavor::LaTeX;
2739 // FIXME It'd be better not to hardcode this, but to do
2740 // something with formats.
2741 if (dformat == "xhtml")
2742 result = Flavor::Html;
2743 else if (dformat == "docbook5")
2744 result = Flavor::DocBook5;
2745 else if (dformat == "text")
2746 result = Flavor::Text;
2747 else if (dformat == "lyx")
2748 result = Flavor::LyX;
2749 else if (dformat == "pdflatex")
2750 result = Flavor::PdfLaTeX;
2751 else if (dformat == "xetex")
2752 result = Flavor::XeTeX;
2753 else if (dformat == "luatex")
2754 result = Flavor::LuaTeX;
2755 else if (dformat == "dviluatex")
2756 result = Flavor::DviLuaTeX;
2758 // Try to determine flavor of default output format
2759 vector<string> backs = backends();
2760 if (find(backs.begin(), backs.end(), dformat) == backs.end()) {
2761 // Get shortest path to format
2762 Graph::EdgePath path;
2763 for (auto const & bvar : backs) {
2764 Graph::EdgePath p = theConverters().getPath(bvar, dformat);
2765 if (!p.empty() && (path.empty() || p.size() < path.size())) {
2770 result = theConverters().getFlavor(path);
2773 // cache this flavor
2774 default_flavors_[dformat] = result;
2779 string BufferParams::getDefaultOutputFormat() const
2781 if (!default_output_format.empty()
2782 && default_output_format != "default")
2783 return default_output_format;
2784 if (encoding().package() == Encoding::japanese)
2785 return lyxrc.default_platex_view_format;
2787 return lyxrc.default_otf_view_format;
2788 return lyxrc.default_view_format;
2791 Font const BufferParams::getFont() const
2793 FontInfo f = documentClass().defaultfont();
2794 if (fonts_default_family == "rmdefault")
2795 f.setFamily(ROMAN_FAMILY);
2796 else if (fonts_default_family == "sfdefault")
2797 f.setFamily(SANS_FAMILY);
2798 else if (fonts_default_family == "ttdefault")
2799 f.setFamily(TYPEWRITER_FAMILY);
2800 return Font(f, language);
2804 QuoteStyle BufferParams::getQuoteStyle(string const & qs) const
2806 return quotesstyletranslator().find(qs);
2810 bool BufferParams::isLatex() const
2812 return documentClass().outputType() == LATEX;
2816 bool BufferParams::isLiterate() const
2818 return documentClass().outputType() == LITERATE;
2822 void BufferParams::readPreamble(Lexer & lex)
2824 if (lex.getString() != "\\begin_preamble")
2825 lyxerr << "Error (BufferParams::readPreamble):"
2826 "consistency check failed." << endl;
2828 preamble = lex.getLongString(from_ascii("\\end_preamble"));
2832 void BufferParams::readLocalLayout(Lexer & lex, bool forced)
2834 string const expected = forced ? "\\begin_forced_local_layout" :
2835 "\\begin_local_layout";
2836 if (lex.getString() != expected)
2837 lyxerr << "Error (BufferParams::readLocalLayout):"
2838 "consistency check failed." << endl;
2841 forced_local_layout_ =
2842 lex.getLongString(from_ascii("\\end_forced_local_layout"));
2844 local_layout_ = lex.getLongString(from_ascii("\\end_local_layout"));
2848 bool BufferParams::setLanguage(string const & lang)
2850 Language const *new_language = languages.getLanguage(lang);
2851 if (!new_language) {
2852 // Language lang was not found
2855 language = new_language;
2860 void BufferParams::readLanguage(Lexer & lex)
2862 if (!lex.next()) return;
2864 string const tmptok = lex.getString();
2866 // check if tmptok is part of tex_babel in tex-defs.h
2867 if (!setLanguage(tmptok)) {
2868 // Language tmptok was not found
2869 language = default_language;
2870 lyxerr << "Warning: Setting language `"
2871 << tmptok << "' to `" << language->lang()
2877 void BufferParams::readGraphicsDriver(Lexer & lex)
2882 string const tmptok = lex.getString();
2883 // check if tmptok is part of tex_graphics in tex_defs.h
2886 string const test = tex_graphics[n++];
2888 if (test == tmptok) {
2889 graphics_driver = tmptok;
2894 "Warning: graphics driver `$$Token' not recognized!\n"
2895 " Setting graphics driver to `default'.\n");
2896 graphics_driver = "default";
2903 void BufferParams::readBullets(Lexer & lex)
2908 int const index = lex.getInteger();
2910 int temp_int = lex.getInteger();
2911 user_defined_bullet(index).setFont(temp_int);
2912 temp_bullet(index).setFont(temp_int);
2914 user_defined_bullet(index).setCharacter(temp_int);
2915 temp_bullet(index).setCharacter(temp_int);
2917 user_defined_bullet(index).setSize(temp_int);
2918 temp_bullet(index).setSize(temp_int);
2922 void BufferParams::readBulletsLaTeX(Lexer & lex)
2924 // The bullet class should be able to read this.
2927 int const index = lex.getInteger();
2929 docstring const temp_str = lex.getDocString();
2931 user_defined_bullet(index).setText(temp_str);
2932 temp_bullet(index).setText(temp_str);
2936 void BufferParams::readModules(Lexer & lex)
2938 if (!lex.eatLine()) {
2939 lyxerr << "Error (BufferParams::readModules):"
2940 "Unexpected end of input." << endl;
2944 string mod = lex.getString();
2945 if (mod == "\\end_modules")
2947 addLayoutModule(mod);
2953 void BufferParams::readRemovedModules(Lexer & lex)
2955 if (!lex.eatLine()) {
2956 lyxerr << "Error (BufferParams::readRemovedModules):"
2957 "Unexpected end of input." << endl;
2961 string mod = lex.getString();
2962 if (mod == "\\end_removed_modules")
2964 removed_modules_.push_back(mod);
2967 // now we want to remove any removed modules that were previously
2968 // added. normally, that will be because default modules were added in
2969 // setBaseClass(), which gets called when \textclass is read at the
2970 // start of the read.
2971 for (auto const & rm : removed_modules_) {
2972 LayoutModuleList::iterator const mit = layout_modules_.begin();
2973 LayoutModuleList::iterator const men = layout_modules_.end();
2974 LayoutModuleList::iterator found = find(mit, men, rm);
2977 layout_modules_.erase(found);
2982 void BufferParams::readIncludeonly(Lexer & lex)
2984 if (!lex.eatLine()) {
2985 lyxerr << "Error (BufferParams::readIncludeonly):"
2986 "Unexpected end of input." << endl;
2990 string child = lex.getString();
2991 if (child == "\\end_includeonly")
2993 included_children_.push_back(child);
2999 string BufferParams::paperSizeName(PapersizePurpose purpose, string const & psize) const
3001 PAPER_SIZE ppsize = psize.empty() ? papersize : papersizetranslator().find(psize);
3004 if (documentClass().pagesize() == "default")
3005 // could be anything, so don't guess
3007 return paperSizeName(purpose, documentClass().pagesize());
3008 case PAPER_CUSTOM: {
3009 if (purpose == XDVI && !paperwidth.empty() &&
3010 !paperheight.empty()) {
3011 // heightxwidth<unit>
3012 string first = paperwidth;
3013 string second = paperheight;
3014 if (orientation == ORIENTATION_LANDSCAPE)
3017 return first.erase(first.length() - 2)
3023 // dvips and dvipdfm do not know this
3024 if (purpose == DVIPS || purpose == DVIPDFM)
3028 if (purpose == DVIPS || purpose == DVIPDFM)
3032 if (purpose == DVIPS || purpose == DVIPDFM)
3042 if (purpose == DVIPS || purpose == DVIPDFM)
3046 if (purpose == DVIPS || purpose == DVIPDFM)
3050 if (purpose == DVIPS || purpose == DVIPDFM)
3054 if (purpose == DVIPS || purpose == DVIPDFM)
3058 if (purpose == DVIPS || purpose == DVIPDFM)
3062 // dvipdfm does not know this
3063 if (purpose == DVIPDFM)
3067 if (purpose == DVIPDFM)
3071 if (purpose == DVIPS || purpose == DVIPDFM)
3075 if (purpose == DVIPS || purpose == DVIPDFM)
3079 if (purpose == DVIPS || purpose == DVIPDFM)
3083 if (purpose == DVIPS || purpose == DVIPDFM)
3087 if (purpose == DVIPS || purpose == DVIPDFM)
3091 if (purpose == DVIPS || purpose == DVIPDFM)
3095 if (purpose == DVIPS || purpose == DVIPDFM)
3099 if (purpose == DVIPS || purpose == DVIPDFM)
3103 if (purpose == DVIPS || purpose == DVIPDFM)
3107 if (purpose == DVIPS || purpose == DVIPDFM)
3111 if (purpose == DVIPS || purpose == DVIPDFM)
3115 if (purpose == DVIPS || purpose == DVIPDFM)
3119 if (purpose == DVIPS || purpose == DVIPDFM)
3123 if (purpose == DVIPS || purpose == DVIPDFM)
3127 if (purpose == DVIPS || purpose == DVIPDFM)
3130 case PAPER_USEXECUTIVE:
3131 // dvipdfm does not know this
3132 if (purpose == DVIPDFM)
3137 case PAPER_USLETTER:
3139 if (purpose == XDVI)
3146 string const BufferParams::dvips_options() const
3150 // If the class loads the geometry package, we do not know which
3151 // paper size is used, since we do not set it (bug 7013).
3152 // Therefore we must not specify any argument here.
3153 // dvips gets the correct paper size via DVI specials in this case
3154 // (if the class uses the geometry package correctly).
3155 if (documentClass().provides("geometry"))
3159 && papersize == PAPER_CUSTOM
3160 && !lyxrc.print_paper_dimension_flag.empty()
3161 && !paperwidth.empty()
3162 && !paperheight.empty()) {
3163 // using a custom papersize
3164 result = lyxrc.print_paper_dimension_flag;
3165 result += ' ' + paperwidth;
3166 result += ',' + paperheight;
3168 string const paper_option = paperSizeName(DVIPS);
3169 if (!paper_option.empty() && (paper_option != "letter" ||
3170 orientation != ORIENTATION_LANDSCAPE)) {
3171 // dvips won't accept -t letter -t landscape.
3172 // In all other cases, include the paper size
3174 result = lyxrc.print_paper_flag;
3175 result += ' ' + paper_option;
3178 if (orientation == ORIENTATION_LANDSCAPE &&
3179 papersize != PAPER_CUSTOM)
3180 result += ' ' + lyxrc.print_landscape_flag;
3185 string const BufferParams::main_font_encoding() const
3187 if (font_encodings().empty()) {
3188 if (ascii_lowercase(language->fontenc(*this)) == "none")
3192 return font_encodings().back();
3196 vector<string> const BufferParams::font_encodings() const
3198 string doc_fontenc = (fontenc == "auto") ? string() : fontenc;
3200 vector<string> fontencs;
3202 // "default" means "no explicit font encoding"
3203 if (doc_fontenc != "default") {
3204 if (!doc_fontenc.empty())
3205 // If we have a custom setting, we use only that!
3206 return getVectorFromString(doc_fontenc);
3207 if (!language->fontenc(*this).empty()
3208 && ascii_lowercase(language->fontenc(*this)) != "none") {
3209 vector<string> fencs = getVectorFromString(language->fontenc(*this));
3210 for (auto & fe : fencs) {
3211 if (find(fontencs.begin(), fontencs.end(), fe) == fontencs.end())
3212 fontencs.push_back(fe);
3221 string BufferParams::babelCall(string const & lang_opts, bool const langoptions) const
3223 // suppress the babel call if there is no BabelName defined
3224 // for the document language in the lib/languages file and if no
3225 // other languages are used (lang_opts is then empty)
3226 if (lang_opts.empty())
3228 // The prefs may require the languages to
3229 // be submitted to babel itself (not the class).
3231 return "\\usepackage[" + lang_opts + "]{babel}";
3232 return "\\usepackage{babel}";
3236 docstring BufferParams::getGraphicsDriver(string const & package) const
3240 if (package == "geometry") {
3241 if (graphics_driver == "dvips"
3242 || graphics_driver == "dvipdfm"
3243 || graphics_driver == "pdftex"
3244 || graphics_driver == "vtex")
3245 result = from_ascii(graphics_driver);
3246 else if (graphics_driver == "dvipdfmx")
3247 result = from_ascii("dvipdfm");
3254 void BufferParams::writeEncodingPreamble(otexstream & os,
3255 LaTeXFeatures & features) const
3257 // With no-TeX fonts we use utf8-plain without encoding package.
3261 if (inputenc == "auto-legacy") {
3262 string const doc_encoding =
3263 language->encoding()->latexName();
3264 Encoding::Package const package =
3265 language->encoding()->package();
3267 // Create list of inputenc options:
3268 set<string> encoding_set;
3269 // luainputenc fails with more than one encoding
3270 if (features.runparams().flavor != Flavor::LuaTeX
3271 && features.runparams().flavor != Flavor::DviLuaTeX)
3272 // list all input encodings used in the document
3273 encoding_set = features.getEncodingSet(doc_encoding);
3275 // The "japanese" babel-language requires the pLaTeX engine
3276 // which conflicts with "inputenc".
3277 // See http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129680.html
3278 if ((!encoding_set.empty() || package == Encoding::inputenc)
3279 && !features.isRequired("japanese")
3280 && !features.isProvided("inputenc")) {
3281 os << "\\usepackage[";
3282 set<string>::const_iterator it = encoding_set.begin();
3283 set<string>::const_iterator const end = encoding_set.end();
3285 os << from_ascii(*it);
3288 for (; it != end; ++it)
3289 os << ',' << from_ascii(*it);
3290 if (package == Encoding::inputenc) {
3291 if (!encoding_set.empty())
3293 os << from_ascii(doc_encoding);
3295 if (features.runparams().flavor == Flavor::LuaTeX
3296 || features.runparams().flavor == Flavor::DviLuaTeX)
3297 os << "]{luainputenc}\n";
3299 os << "]{inputenc}\n";
3301 } else if (inputenc != "auto-legacy-plain") {
3302 switch (encoding().package()) {
3303 case Encoding::none:
3305 case Encoding::japanese:
3306 if (encoding().iconvName() != "UTF-8"
3307 && !features.runparams().isFullUnicode())
3308 // don't default to [utf8]{inputenc} with TeXLive >= 18
3309 os << "\\ifdefined\\UseRawInputEncoding\n"
3310 << " \\UseRawInputEncoding\\fi\n";
3312 case Encoding::inputenc:
3313 // do not load inputenc if japanese is used
3314 // or if the class provides inputenc
3315 if (features.isRequired("japanese")
3316 || features.isProvided("inputenc"))
3318 os << "\\usepackage[" << from_ascii(encoding().latexName());
3319 if (features.runparams().flavor == Flavor::LuaTeX
3320 || features.runparams().flavor == Flavor::DviLuaTeX)
3321 os << "]{luainputenc}\n";
3323 os << "]{inputenc}\n";
3327 if (inputenc == "auto-legacy-plain" || features.isRequired("japanese")) {
3328 // don't default to [utf8]{inputenc} with TeXLive >= 18
3329 os << "\\ifdefined\\UseRawInputEncoding\n";
3330 os << " \\UseRawInputEncoding\\fi\n";
3335 string const BufferParams::parseFontName(string const & name) const
3337 string mangled = name;
3338 size_t const idx = mangled.find('[');
3339 if (idx == string::npos || idx == 0)
3342 return mangled.substr(0, idx - 1);
3346 string const BufferParams::loadFonts(LaTeXFeatures & features) const
3348 if (fontsRoman() == "default" && fontsSans() == "default"
3349 && fontsTypewriter() == "default"
3350 && (fontsMath() == "default" || fontsMath() == "auto"))
3356 /* Fontspec (XeTeX, LuaTeX): we provide GUI support for oldstyle
3357 * numbers (Numbers=OldStyle) and sf/tt scaling. The Ligatures=TeX/
3358 * Mapping=tex-text option assures TeX ligatures (such as "--")
3359 * are resolved. Note that tt does not use these ligatures.
3361 * -- add more GUI options?
3362 * -- add more fonts (fonts for other scripts)
3363 * -- if there's a way to find out if a font really supports
3364 * OldStyle, enable/disable the widget accordingly.
3366 if (useNonTeXFonts && features.isAvailable("fontspec")) {
3367 // "Mapping=tex-text" and "Ligatures=TeX" are equivalent.
3368 // However, until v.2 (2010/07/11) fontspec only knew
3369 // Mapping=tex-text (for XeTeX only); then "Ligatures=TeX"
3370 // was introduced for both XeTeX and LuaTeX (LuaTeX
3371 // didn't understand "Mapping=tex-text", while XeTeX
3372 // understood both. With most recent versions, both
3373 // variants are understood by both engines. However,
3374 // we want to provide support for at least TeXLive 2009
3375 // (for XeTeX; LuaTeX is only supported as of v.2)
3376 // As of 2017/11/03, Babel has its own higher-level
3377 // interface on top of fontspec that is to be used.
3378 bool const babelfonts = features.useBabel()
3379 && features.isAvailable("babel-2017/11/03");
3380 string const texmapping =
3381 (features.runparams().flavor == Flavor::XeTeX) ?
3382 "Mapping=tex-text" : "Ligatures=TeX";
3383 if (fontsRoman() != "default") {
3385 os << "\\babelfont{rm}[";
3387 os << "\\setmainfont[";
3388 if (!font_roman_opts.empty())
3389 os << font_roman_opts << ',';
3391 if (fonts_roman_osf)
3392 os << ",Numbers=OldStyle";
3393 os << "]{" << parseFontName(fontsRoman()) << "}\n";
3395 if (fontsSans() != "default") {
3396 string const sans = parseFontName(fontsSans());
3397 if (fontsSansScale() != 100) {
3399 os << "\\babelfont{sf}";
3401 os << "\\setsansfont";
3403 << float(fontsSansScale()) / 100 << ',';
3405 os << "Numbers=OldStyle,";
3406 if (!font_sans_opts.empty())
3407 os << font_sans_opts << ',';
3408 os << texmapping << "]{"
3412 os << "\\babelfont{sf}[";
3414 os << "\\setsansfont[";
3416 os << "Numbers=OldStyle,";
3417 if (!font_sans_opts.empty())
3418 os << font_sans_opts << ',';
3419 os << texmapping << "]{"
3423 if (fontsTypewriter() != "default") {
3424 string const mono = parseFontName(fontsTypewriter());
3425 if (fontsTypewriterScale() != 100) {
3427 os << "\\babelfont{tt}";
3429 os << "\\setmonofont";
3431 << float(fontsTypewriterScale()) / 100;
3432 if (fonts_typewriter_osf)
3433 os << ",Numbers=OldStyle";
3434 if (!font_typewriter_opts.empty())
3435 os << ',' << font_typewriter_opts;
3440 os << "\\babelfont{tt}";
3442 os << "\\setmonofont";
3443 if (!font_typewriter_opts.empty() || fonts_typewriter_osf) {
3445 if (fonts_typewriter_osf)
3446 os << "Numbers=OldStyle";
3447 if (!font_typewriter_opts.empty()) {
3448 if (fonts_typewriter_osf)
3450 os << font_typewriter_opts;
3454 os << '{' << mono << "}\n";
3461 bool const ot1 = (main_font_encoding() == "default" || main_font_encoding() == "OT1");
3462 bool const dryrun = features.runparams().dryrun;
3463 bool const complete = (fontsSans() == "default" && fontsTypewriter() == "default");
3464 bool const nomath = (fontsMath() != "auto");
3467 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsRoman())).getLaTeXCode(
3468 dryrun, ot1, complete, fonts_expert_sc, fonts_roman_osf,
3469 nomath, font_roman_opts);
3472 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsSans())).getLaTeXCode(
3473 dryrun, ot1, complete, fonts_expert_sc, fonts_sans_osf,
3474 nomath, font_sans_opts, fontsSansScale());
3476 // MONOSPACED/TYPEWRITER
3477 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsTypewriter())).getLaTeXCode(
3478 dryrun, ot1, complete, fonts_expert_sc, fonts_typewriter_osf,
3479 nomath, font_typewriter_opts, fontsTypewriterScale());
3482 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsMath())).getLaTeXCode(
3483 dryrun, ot1, complete, fonts_expert_sc, fonts_roman_osf,
3490 Encoding const & BufferParams::encoding() const
3492 // Main encoding for LaTeX output.
3494 return *(encodings.fromLyXName("utf8-plain"));
3495 if (inputenc == "auto-legacy" || inputenc == "auto-legacy-plain")
3496 return *language->encoding();
3497 if (inputenc == "utf8" && language->lang() == "japanese")
3498 return *(encodings.fromLyXName("utf8-platex"));
3499 Encoding const * const enc = encodings.fromLyXName(inputenc);
3502 LYXERR0("Unknown inputenc value `" << inputenc
3503 << "'. Using `auto' instead.");
3504 return *language->encoding();
3508 string const & BufferParams::defaultBiblioStyle() const
3510 if (!biblio_style.empty())
3511 return biblio_style;
3513 map<string, string> const & bs = documentClass().defaultBiblioStyle();
3514 auto cit = bs.find(theCiteEnginesList.getTypeAsString(citeEngineType()));
3515 if (cit != bs.end())
3518 return empty_string();
3522 bool BufferParams::fullAuthorList() const
3524 return documentClass().fullAuthorList();
3528 string BufferParams::getCiteAlias(string const & s) const
3530 vector<string> commands =
3531 documentClass().citeCommands(citeEngineType());
3532 // If it is a real command, don't treat it as an alias
3533 if (find(commands.begin(), commands.end(), s) != commands.end())
3535 map<string,string> aliases = documentClass().citeCommandAliases();
3536 if (aliases.find(s) != aliases.end())
3542 vector<string> BufferParams::citeCommands() const
3544 static CitationStyle const default_style;
3545 vector<string> commands =
3546 documentClass().citeCommands(citeEngineType());
3547 if (commands.empty())
3548 commands.push_back(default_style.name);
3553 vector<CitationStyle> BufferParams::citeStyles() const
3555 static CitationStyle const default_style;
3556 vector<CitationStyle> styles =
3557 documentClass().citeStyles(citeEngineType());
3559 styles.push_back(default_style);
3564 string const BufferParams::bibtexCommand() const
3566 // Return document-specific setting if available
3567 if (bibtex_command != "default")
3568 return bibtex_command;
3570 // If we have "default" in document settings, consult the prefs
3571 // 1. Japanese (uses a specific processor)
3572 if (encoding().package() == Encoding::japanese) {
3573 if (lyxrc.jbibtex_command != "automatic")
3574 // Return the specified program, if "automatic" is not set
3575 return lyxrc.jbibtex_command;
3576 else if (!useBiblatex()) {
3577 // With classic BibTeX, return pbibtex, jbibtex, bibtex
3578 if (lyxrc.jbibtex_alternatives.find("pbibtex") != lyxrc.jbibtex_alternatives.end())
3580 if (lyxrc.jbibtex_alternatives.find("jbibtex") != lyxrc.jbibtex_alternatives.end())
3585 // 2. All other languages
3586 else if (lyxrc.bibtex_command != "automatic")
3587 // Return the specified program, if "automatic" is not set
3588 return lyxrc.bibtex_command;
3590 // 3. Automatic: find the most suitable for the current cite framework
3591 if (useBiblatex()) {
3592 // For Biblatex, we prefer biber (also for Japanese)
3593 // and fall back to bibtex8 and, as last resort, bibtex
3594 if (lyxrc.bibtex_alternatives.find("biber") != lyxrc.bibtex_alternatives.end())
3596 else if (lyxrc.bibtex_alternatives.find("bibtex8") != lyxrc.bibtex_alternatives.end())
3603 bool BufferParams::useBiblatex() const
3605 return theCiteEnginesList[citeEngine()]->getCiteFramework() == "biblatex";
3609 void BufferParams::invalidateConverterCache() const
3611 pimpl_->isExportCacheValid = false;
3612 pimpl_->isViewCacheValid = false;
3616 // We shouldn't need to reset the params here, since anything
3617 // we need will be recopied.
3618 void BufferParams::copyForAdvFR(const BufferParams & bp)
3620 string const & lang = bp.language->lang();
3622 layout_modules_ = bp.layout_modules_;
3623 string const & doc_class = bp.documentClass().name();
3624 setBaseClass(doc_class);
3628 void BufferParams::setBibFileEncoding(string const & file, string const & enc)
3630 bib_encodings[file] = enc;
3634 string const BufferParams::bibFileEncoding(string const & file) const
3636 if (bib_encodings.find(file) == bib_encodings.end())
3638 return bib_encodings.find(file)->second;