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 IgnoreList spellignore;
345 Bullet temp_bullets[4];
346 Bullet user_defined_bullets[4];
347 IndicesList indiceslist;
351 /** This is the amount of space used for paragraph_separation "skip",
352 * and for detached paragraphs in "indented" documents.
355 PDFOptions pdfoptions;
356 LayoutFileIndex baseClass_;
357 FormatList exportableFormatList;
358 FormatList viewableFormatList;
359 bool isViewCacheValid;
360 bool isExportCacheValid;
364 BufferParams::Impl::Impl()
365 : defskip(VSpace::MEDSKIP), baseClass_(string("")),
366 isViewCacheValid(false), isExportCacheValid(false)
368 // set initial author
370 authorlist.record(Author(from_utf8(lyxrc.user_name),
371 from_utf8(lyxrc.user_email),
372 from_utf8(lyxrc.user_initials)));
377 BufferParams::MemoryTraits::clone(BufferParams::Impl const * ptr)
380 return new BufferParams::Impl(*ptr);
384 void BufferParams::MemoryTraits::destroy(BufferParams::Impl * ptr)
390 BufferParams::BufferParams()
393 setBaseClass(defaultBaseclass());
394 cite_engine_ = "basic";
395 cite_engine_type_ = ENGINE_TYPE_DEFAULT;
397 paragraph_separation = ParagraphIndentSeparation;
398 is_math_indent = false;
399 math_numbering_side = DEFAULT;
400 quotes_style = QuoteStyle::English;
401 dynamic_quotes = false;
402 fontsize = "default";
405 papersize = PAPER_DEFAULT;
406 orientation = ORIENTATION_PORTRAIT;
407 use_geometry = false;
408 biblio_style = string();
409 use_bibtopic = false;
412 save_transient_properties = true;
413 track_changes = false;
414 output_changes = false;
416 postpone_fragile_content = true;
417 use_default_options = true;
418 maintain_unincluded_children = CM_None;
421 language = default_language;
423 fonts_roman[0] = "default";
424 fonts_roman[1] = "default";
425 fonts_sans[0] = "default";
426 fonts_sans[1] = "default";
427 fonts_typewriter[0] = "default";
428 fonts_typewriter[1] = "default";
429 fonts_math[0] = "auto";
430 fonts_math[1] = "auto";
431 fonts_default_family = "default";
432 useNonTeXFonts = false;
433 use_microtype = false;
434 use_dash_ligatures = true;
435 fonts_expert_sc = false;
436 fonts_roman_osf = false;
437 fonts_sans_osf = false;
438 fonts_typewriter_osf = false;
439 fonts_sans_scale[0] = 100;
440 fonts_sans_scale[1] = 100;
441 fonts_typewriter_scale[0] = 100;
442 fonts_typewriter_scale[1] = 100;
444 lang_package = "default";
445 graphics_driver = "default";
446 default_output_format = "default";
447 bibtex_command = "default";
448 index_command = "default";
451 listings_params = string();
452 pagestyle = "default";
453 tablestyle = "default";
454 float_alignment = "class";
455 float_placement = "class";
456 suppress_date = false;
457 justification = true;
458 // no color is the default (white)
459 backgroundcolor = lyx::rgbFromHexName("#ffffff");
460 isbackgroundcolor = false;
461 // no color is the default (black)
462 fontcolor = lyx::rgbFromHexName("#000000");
464 // light gray is the default font color for greyed-out notes
465 notefontcolor = lyx::rgbFromHexName("#cccccc");
466 isnotefontcolor = false;
467 boxbgcolor = lyx::rgbFromHexName("#ff0000");
468 isboxbgcolor = false;
469 compressed = lyxrc.save_compressed;
470 for (int iter = 0; iter < 4; ++iter) {
471 user_defined_bullet(iter) = ITEMIZE_DEFAULTS[iter];
472 temp_bullet(iter) = ITEMIZE_DEFAULTS[iter];
475 indiceslist().addDefault(B_("Index"));
476 html_be_strict = false;
477 html_math_output = MathML;
478 html_math_img_scale = 1.0;
479 html_css_as_file = false;
480 docbook_table_output = HTMLTable;
481 display_pixel_ratio = 1.0;
483 shell_escape = false;
489 // map current author
490 author_map_[pimpl_->authorlist.get(0).bufferId()] = 0;
494 docstring BufferParams::B_(string const & l10n) const
496 LASSERT(language, return from_utf8(l10n));
497 return getMessages(language->code()).get(l10n);
501 BufferParams::Package BufferParams::use_package(std::string const & p) const
503 PackageMap::const_iterator it = use_packages.find(p);
504 if (it == use_packages.end())
510 void BufferParams::use_package(std::string const & p, BufferParams::Package u)
516 map<string, string> const & BufferParams::auto_packages()
518 static map<string, string> packages;
519 if (packages.empty()) {
520 // We could have a race condition here that two threads
521 // discover an empty map at the same time and want to fill
522 // it, but that is no problem, since the same contents is
523 // filled in twice then. Having the locker inside the
524 // packages.empty() condition has the advantage that we
525 // don't need the mutex overhead for simple reading.
527 Mutex::Locker locker(&mutex);
528 // adding a package here implies a file format change!
529 packages["amsmath"] =
530 N_("The LaTeX package amsmath is only used if AMS formula types or symbols from the AMS math toolbars are inserted into formulas");
531 packages["amssymb"] =
532 N_("The LaTeX package amssymb is only used if symbols from the AMS math toolbars are inserted into formulas");
534 N_("The LaTeX package cancel is only used if \\cancel commands are used in formulas");
536 N_("The LaTeX package esint is only used if special integral symbols are inserted into formulas");
537 packages["mathdots"] =
538 N_("The LaTeX package mathdots is only used if the command \\iddots is inserted into formulas");
539 packages["mathtools"] =
540 N_("The LaTeX package mathtools is only used if some mathematical relations are inserted into formulas");
542 N_("The LaTeX package mhchem is only used if either the command \\ce or \\cf is inserted into formulas");
543 packages["stackrel"] =
544 N_("The LaTeX package stackrel is only used if the command \\stackrel with subscript is inserted into formulas");
545 packages["stmaryrd"] =
546 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");
547 packages["undertilde"] =
548 N_("The LaTeX package undertilde is only used if you use the math frame decoration 'utilde'");
554 bool BufferParams::useBibtopic() const
558 return (use_bibtopic || (!multibib.empty() && multibib != "child"));
562 AuthorList & BufferParams::authors()
564 return pimpl_->authorlist;
568 AuthorList const & BufferParams::authors() const
570 return pimpl_->authorlist;
574 void BufferParams::addAuthor(Author const & a)
576 author_map_[a.bufferId()] = pimpl_->authorlist.record(a);
580 BranchList & BufferParams::branchlist()
582 return pimpl_->branchlist;
586 BranchList const & BufferParams::branchlist() const
588 return pimpl_->branchlist;
592 IndicesList & BufferParams::indiceslist()
594 return pimpl_->indiceslist;
598 IndicesList const & BufferParams::indiceslist() const
600 return pimpl_->indiceslist;
604 typedef std::vector<WordLangTuple> IgnoreList;
607 IgnoreList & BufferParams::spellignore()
609 return pimpl_->spellignore;
613 IgnoreList const & BufferParams::spellignore() const
615 return pimpl_->spellignore;
619 Bullet & BufferParams::temp_bullet(lyx::size_type const index)
621 LASSERT(index < 4, return pimpl_->temp_bullets[0]);
622 return pimpl_->temp_bullets[index];
626 Bullet const & BufferParams::temp_bullet(lyx::size_type const index) const
628 LASSERT(index < 4, return pimpl_->temp_bullets[0]);
629 return pimpl_->temp_bullets[index];
633 Bullet & BufferParams::user_defined_bullet(lyx::size_type const index)
635 LASSERT(index < 4, return pimpl_->temp_bullets[0]);
636 return pimpl_->user_defined_bullets[index];
640 Bullet const & BufferParams::user_defined_bullet(lyx::size_type const index) const
642 LASSERT(index < 4, return pimpl_->temp_bullets[0]);
643 return pimpl_->user_defined_bullets[index];
647 Spacing & BufferParams::spacing()
649 return pimpl_->spacing;
653 Spacing const & BufferParams::spacing() const
655 return pimpl_->spacing;
659 PDFOptions & BufferParams::pdfoptions()
661 return pimpl_->pdfoptions;
665 PDFOptions const & BufferParams::pdfoptions() const
667 return pimpl_->pdfoptions;
671 Length const & BufferParams::getMathIndent() const
673 return pimpl_->mathindent;
677 void BufferParams::setMathIndent(Length const & indent)
679 pimpl_->mathindent = indent;
683 Length const & BufferParams::getParIndent() const
685 return pimpl_->parindent;
689 void BufferParams::setParIndent(Length const & indent)
691 pimpl_->parindent = indent;
695 VSpace const & BufferParams::getDefSkip() const
697 return pimpl_->defskip;
701 void BufferParams::setDefSkip(VSpace const & vs)
703 // DEFSKIP will cause an infinite loop
704 LASSERT(vs.kind() != VSpace::DEFSKIP, return);
705 pimpl_->defskip = vs;
709 BufferParams::MathNumber BufferParams::getMathNumber() const
711 if (math_numbering_side != DEFAULT)
712 return math_numbering_side;
713 // FIXME: do not hardcode language here
714 else if (language->lang() == "arabic_arabi"
715 || documentClass().provides("leqno"))
722 string BufferParams::readToken(Lexer & lex, string const & token,
723 FileName const & filename)
726 FileName const & filepath = filename.onlyPath();
728 if (token == "\\textclass") {
730 string const classname = lex.getString();
731 // if there exists a local layout file, ignore the system one
732 // NOTE: in this case, the textclass (.cls file) is assumed to
735 LayoutFileList & bcl = LayoutFileList::get();
736 if (!filepath.empty()) {
737 // If classname is an absolute path, the document is
738 // using a local layout file which could not be accessed
739 // by a relative path. In this case the path is correct
740 // even if the document was moved to a different
741 // location. However, we will have a problem if the
742 // document was generated on a different platform.
743 bool isabsolute = FileName::isAbsolute(classname);
744 string const classpath = onlyPath(classname);
745 string const path = isabsolute ? classpath
746 : FileName(addPath(filepath.absFileName(),
747 classpath)).realPath();
748 string const oldpath = isabsolute ? string()
749 : FileName(addPath(origin, classpath)).realPath();
750 tcp = bcl.addLocalLayout(onlyFileName(classname), path, oldpath);
752 // that returns non-empty if a "local" layout file is found.
754 result = to_utf8(makeRelPath(from_utf8(onlyPath(tcp)),
755 from_utf8(filepath.absFileName())));
758 setBaseClass(onlyFileName(tcp));
760 setBaseClass(onlyFileName(classname));
761 // We assume that a tex class exists for local or unknown
762 // layouts so this warning, will only be given for system layouts.
763 if (!baseClass()->isTeXClassAvailable()) {
764 docstring const desc =
765 translateIfPossible(from_utf8(baseClass()->description()));
766 docstring const prereqs =
767 from_utf8(baseClass()->prerequisites());
768 docstring const msg =
769 bformat(_("The selected document class\n"
771 "requires external files that are not available.\n"
772 "The document class can still be used, but the\n"
773 "document cannot be compiled until the following\n"
774 "prerequisites are installed:\n"
776 "See section 3.1.2.2 (Class Availability) of the\n"
777 "User's Guide for more information."), desc, prereqs);
778 frontend::Alert::warning(_("Document class not available"),
781 } else if (token == "\\save_transient_properties") {
782 lex >> save_transient_properties;
783 } else if (token == "\\origin") {
785 origin = lex.getString();
786 string const sysdirprefix = "/systemlyxdir/";
787 if (prefixIs(origin, sysdirprefix)) {
789 if (inSystemDir(filepath, docsys))
790 origin.replace(0, sysdirprefix.length() - 1, docsys);
792 origin.replace(0, sysdirprefix.length() - 1,
793 package().system_support().absFileName());
795 } else if (token == "\\begin_preamble") {
797 } else if (token == "\\begin_local_layout") {
798 readLocalLayout(lex, false);
799 } else if (token == "\\begin_forced_local_layout") {
800 readLocalLayout(lex, true);
801 } else if (token == "\\begin_modules") {
803 } else if (token == "\\begin_removed_modules") {
804 readRemovedModules(lex);
805 } else if (token == "\\begin_includeonly") {
806 readIncludeonly(lex);
807 } else if (token == "\\maintain_unincluded_children") {
811 maintain_unincluded_children = CM_None;
812 else if (tmp == "mostly")
813 maintain_unincluded_children = CM_Mostly;
814 else if (tmp == "strict")
815 maintain_unincluded_children = CM_Strict;
816 } else if (token == "\\options") {
818 options = lex.getString();
819 } else if (token == "\\use_default_options") {
820 lex >> use_default_options;
821 } else if (token == "\\master") {
823 master = lex.getString();
824 if (!filepath.empty() && FileName::isAbsolute(origin)) {
825 bool const isabs = FileName::isAbsolute(master);
826 FileName const abspath(isabs ? master : origin + master);
827 bool const moved = filepath != FileName(origin);
828 if (moved && abspath.exists()) {
829 docstring const path = isabs
831 : from_utf8(abspath.realPath());
832 docstring const refpath =
833 from_utf8(filepath.absFileName());
834 master = to_utf8(makeRelPath(path, refpath));
837 } else if (token == "\\suppress_date") {
838 lex >> suppress_date;
839 } else if (token == "\\justification") {
840 lex >> justification;
841 } else if (token == "\\language") {
843 } else if (token == "\\language_package") {
845 lang_package = lex.getString();
846 } else if (token == "\\inputencoding") {
848 } else if (token == "\\graphics") {
849 readGraphicsDriver(lex);
850 } else if (token == "\\default_output_format") {
851 lex >> default_output_format;
852 } else if (token == "\\bibtex_command") {
854 bibtex_command = lex.getString();
855 } else if (token == "\\index_command") {
857 index_command = lex.getString();
858 } else if (token == "\\fontencoding") {
860 fontenc = lex.getString();
861 } else if (token == "\\font_roman") {
862 lex >> fonts_roman[0];
863 lex >> fonts_roman[1];
864 } else if (token == "\\font_sans") {
865 lex >> fonts_sans[0];
866 lex >> fonts_sans[1];
867 } else if (token == "\\font_typewriter") {
868 lex >> fonts_typewriter[0];
869 lex >> fonts_typewriter[1];
870 } else if (token == "\\font_math") {
871 lex >> fonts_math[0];
872 lex >> fonts_math[1];
873 } else if (token == "\\font_default_family") {
874 lex >> fonts_default_family;
875 } else if (token == "\\use_non_tex_fonts") {
876 lex >> useNonTeXFonts;
877 } else if (token == "\\font_sc") {
878 lex >> fonts_expert_sc;
879 } else if (token == "\\font_roman_osf") {
880 lex >> fonts_roman_osf;
881 } else if (token == "\\font_sans_osf") {
882 lex >> fonts_sans_osf;
883 } else if (token == "\\font_typewriter_osf") {
884 lex >> fonts_typewriter_osf;
885 } else if (token == "\\font_roman_opts") {
886 lex >> font_roman_opts;
887 } else if (token == "\\font_sf_scale") {
888 lex >> fonts_sans_scale[0];
889 lex >> fonts_sans_scale[1];
890 } else if (token == "\\font_sans_opts") {
891 lex >> font_sans_opts;
892 } else if (token == "\\font_tt_scale") {
893 lex >> fonts_typewriter_scale[0];
894 lex >> fonts_typewriter_scale[1];
895 } else if (token == "\\font_typewriter_opts") {
896 lex >> font_typewriter_opts;
897 } else if (token == "\\font_cjk") {
899 } else if (token == "\\use_microtype") {
900 lex >> use_microtype;
901 } else if (token == "\\use_dash_ligatures") {
902 lex >> use_dash_ligatures;
903 } else if (token == "\\paragraph_separation") {
906 paragraph_separation = parseptranslator().find(parsep);
907 } else if (token == "\\paragraph_indentation") {
909 string parindent = lex.getString();
910 if (parindent == "default")
911 pimpl_->parindent = Length();
913 pimpl_->parindent = Length(parindent);
914 } else if (token == "\\defskip") {
916 string const defskip = lex.getString();
917 pimpl_->defskip = VSpace(defskip);
918 if (pimpl_->defskip.kind() == VSpace::DEFSKIP)
920 pimpl_->defskip = VSpace(VSpace::MEDSKIP);
921 } else if (token == "\\is_math_indent") {
922 lex >> is_math_indent;
923 } else if (token == "\\math_indentation") {
925 string mathindent = lex.getString();
926 if (mathindent == "default")
927 pimpl_->mathindent = Length();
929 pimpl_->mathindent = Length(mathindent);
930 } else if (token == "\\math_numbering_side") {
934 math_numbering_side = LEFT;
935 else if (tmp == "right")
936 math_numbering_side = RIGHT;
938 math_numbering_side = DEFAULT;
939 } else if (token == "\\quotes_style") {
942 quotes_style = quotesstyletranslator().find(qstyle);
943 } else if (token == "\\dynamic_quotes") {
944 lex >> dynamic_quotes;
945 } else if (token == "\\papersize") {
948 papersize = papersizetranslator().find(ppsize);
949 } else if (token == "\\use_geometry") {
951 } else if (token == "\\use_package") {
956 use_package(package, packagetranslator().find(use));
957 } else if (token == "\\cite_engine") {
959 cite_engine_ = lex.getString();
960 } else if (token == "\\cite_engine_type") {
963 cite_engine_type_ = theCiteEnginesList.getType(engine_type);
964 } else if (token == "\\biblio_style") {
966 biblio_style = lex.getString();
967 } else if (token == "\\biblio_options") {
969 biblio_opts = trim(lex.getString());
970 } else if (token == "\\biblatex_bibstyle") {
972 biblatex_bibstyle = trim(lex.getString());
973 } else if (token == "\\biblatex_citestyle") {
975 biblatex_citestyle = trim(lex.getString());
976 } else if (token == "\\use_bibtopic") {
978 } else if (token == "\\multibib") {
980 } else if (token == "\\use_indices") {
982 } else if (token == "\\tracking_changes") {
983 lex >> track_changes;
984 } else if (token == "\\output_changes") {
985 lex >> output_changes;
986 } else if (token == "\\change_bars") {
988 } else if (token == "\\postpone_fragile_content") {
989 lex >> postpone_fragile_content;
990 } else if (token == "\\branch") {
992 docstring branch = lex.getDocString();
993 branchlist().add(branch);
996 string const tok = lex.getString();
997 if (tok == "\\end_branch")
999 Branch * branch_ptr = branchlist().find(branch);
1000 if (tok == "\\selected") {
1003 branch_ptr->setSelected(lex.getInteger());
1005 if (tok == "\\filename_suffix") {
1008 branch_ptr->setFileNameSuffix(lex.getInteger());
1010 if (tok == "\\color") {
1012 vector<string> const colors = getVectorFromString(lex.getString(), " ");
1013 string const lmcolor = colors.front();
1015 if (colors.size() > 1)
1016 dmcolor = colors.back();
1018 branch_ptr->setColors(lmcolor, dmcolor);
1021 } else if (token == "\\index") {
1023 docstring index = lex.getDocString();
1025 indiceslist().add(index);
1028 string const tok = lex.getString();
1029 if (tok == "\\end_index")
1031 Index * index_ptr = indiceslist().find(index);
1032 if (tok == "\\shortcut") {
1034 shortcut = lex.getDocString();
1036 index_ptr->setShortcut(shortcut);
1038 if (tok == "\\color") {
1040 string color = lex.getString();
1042 index_ptr->setColor(color);
1043 // Update also the Color table:
1044 if (color == "none")
1045 color = lcolor.getX11HexName(Color_background);
1047 if (!shortcut.empty())
1048 lcolor.setColor(to_utf8(shortcut)+ "@" + filename.absFileName(), color);
1051 } else if (token == "\\spellchecker_ignore") {
1053 docstring wl = lex.getDocString();
1055 docstring word = split(wl, langcode, ' ');
1056 Language const * lang = languages.getFromCode(to_ascii(langcode));
1058 spellignore().push_back(WordLangTuple(word, lang));
1059 } else if (token == "\\author") {
1061 istringstream ss(lex.getString());
1065 } else if (token == "\\paperorientation") {
1068 orientation = paperorientationtranslator().find(orient);
1069 } else if (token == "\\backgroundcolor") {
1071 backgroundcolor = lyx::rgbFromHexName(lex.getString());
1072 isbackgroundcolor = true;
1073 } else if (token == "\\fontcolor") {
1075 fontcolor = lyx::rgbFromHexName(lex.getString());
1077 } else if (token == "\\notefontcolor") {
1079 string color = lex.getString();
1080 notefontcolor = lyx::rgbFromHexName(color);
1081 lcolor.setColor("notefontcolor", color);
1082 lcolor.setLaTeXName("notefontcolor", "note_fontcolor");
1083 lcolor.setGUIName("notefontcolor", N_("greyedout inset text"));
1084 // set a local name for the painter
1085 lcolor.setColor("notefontcolor@" + filename.absFileName(), color);
1086 isnotefontcolor = true;
1087 } else if (token == "\\boxbgcolor") {
1089 string color = lex.getString();
1090 boxbgcolor = lyx::rgbFromHexName(color);
1091 lcolor.setColor("boxbgcolor@" + filename.absFileName(), color);
1092 isboxbgcolor = true;
1093 } else if (token == "\\paperwidth") {
1095 } else if (token == "\\paperheight") {
1097 } else if (token == "\\leftmargin") {
1099 } else if (token == "\\topmargin") {
1101 } else if (token == "\\rightmargin") {
1103 } else if (token == "\\bottommargin") {
1104 lex >> bottommargin;
1105 } else if (token == "\\headheight") {
1107 } else if (token == "\\headsep") {
1109 } else if (token == "\\footskip") {
1111 } else if (token == "\\columnsep") {
1113 } else if (token == "\\paperfontsize") {
1115 } else if (token == "\\papercolumns") {
1117 } else if (token == "\\listings_params") {
1120 listings_params = InsetListingsParams(par).params();
1121 } else if (token == "\\papersides") {
1124 sides = sidestranslator().find(psides);
1125 } else if (token == "\\paperpagestyle") {
1127 } else if (token == "\\tablestyle") {
1129 } else if (token == "\\bullet") {
1131 } else if (token == "\\bulletLaTeX") {
1132 readBulletsLaTeX(lex);
1133 } else if (token == "\\secnumdepth") {
1135 } else if (token == "\\tocdepth") {
1137 } else if (token == "\\spacing") {
1141 if (nspacing == "other") {
1144 spacing().set(spacetranslator().find(nspacing), tmp_val);
1145 } else if (token == "\\float_placement") {
1146 lex >> float_placement;
1147 } else if (token == "\\float_alignment") {
1148 lex >> float_alignment;
1150 } else if (prefixIs(token, "\\pdf_") || token == "\\use_hyperref") {
1151 string toktmp = pdfoptions().readToken(lex, token);
1152 if (!toktmp.empty()) {
1153 lyxerr << "PDFOptions::readToken(): Unknown token: " <<
1157 } else if (token == "\\html_math_output") {
1160 html_math_output = static_cast<MathOutput>(temp);
1161 } else if (token == "\\html_be_strict") {
1162 lex >> html_be_strict;
1163 } else if (token == "\\html_css_as_file") {
1164 lex >> html_css_as_file;
1165 } else if (token == "\\html_math_img_scale") {
1166 lex >> html_math_img_scale;
1167 } else if (token == "\\html_latex_start") {
1169 html_latex_start = lex.getString();
1170 } else if (token == "\\html_latex_end") {
1172 html_latex_end = lex.getString();
1173 } else if (token == "\\docbook_table_output") {
1176 docbook_table_output = static_cast<TableOutput>(temp);
1177 } else if (token == "\\output_sync") {
1179 } else if (token == "\\output_sync_macro") {
1180 lex >> output_sync_macro;
1181 } else if (token == "\\use_refstyle") {
1182 lex >> use_refstyle;
1183 } else if (token == "\\use_minted") {
1185 } else if (token == "\\use_lineno") {
1187 } else if (token == "\\lineno_options") {
1189 lineno_opts = trim(lex.getString());
1191 lyxerr << "BufferParams::readToken(): Unknown token: " <<
1201 // Quote argument if it contains spaces
1202 string quoteIfNeeded(string const & str) {
1203 if (contains(str, ' '))
1204 return "\"" + str + "\"";
1210 void BufferParams::writeFile(ostream & os, Buffer const * buf) const
1212 // The top of the file is written by the buffer.
1213 // Prints out the buffer info into the .lyx file given by file
1215 os << "\\save_transient_properties "
1216 << convert<string>(save_transient_properties) << '\n';
1218 // the document directory (must end with a path separator)
1219 // realPath() is used to resolve symlinks, while addPath(..., "")
1220 // ensures a trailing path separator.
1222 string filepath = addPath(buf->fileName().onlyPath().realPath(), "");
1223 string const sysdir = inSystemDir(FileName(filepath), docsys) ? docsys
1224 : addPath(package().system_support().realPath(), "");
1225 string const relpath =
1226 to_utf8(makeRelPath(from_utf8(filepath), from_utf8(sysdir)));
1227 if (!prefixIs(relpath, "../") && !FileName::isAbsolute(relpath))
1228 filepath = addPath("/systemlyxdir", relpath);
1229 else if (!save_transient_properties || !lyxrc.save_origin)
1230 filepath = "unavailable";
1231 os << "\\origin " << quoteIfNeeded(filepath) << '\n';
1234 os << "\\textclass "
1235 << quoteIfNeeded(buf->includedFilePath(addName(buf->layoutPos(),
1236 baseClass()->name()), "layout"))
1239 // then the preamble
1240 if (!preamble.empty()) {
1241 // remove '\n' from the end of preamble
1242 docstring const tmppreamble = rtrim(preamble, "\n");
1243 os << "\\begin_preamble\n"
1244 << to_utf8(tmppreamble)
1245 << "\n\\end_preamble\n";
1249 if (!options.empty()) {
1250 os << "\\options " << options << '\n';
1253 // use the class options defined in the layout?
1254 os << "\\use_default_options "
1255 << convert<string>(use_default_options) << "\n";
1257 // the master document
1258 if (!master.empty()) {
1259 os << "\\master " << master << '\n';
1263 if (!removed_modules_.empty()) {
1264 os << "\\begin_removed_modules" << '\n';
1265 for (auto const & mod : removed_modules_)
1267 os << "\\end_removed_modules" << '\n';
1271 if (!layout_modules_.empty()) {
1272 os << "\\begin_modules" << '\n';
1273 for (auto const & mod : layout_modules_)
1275 os << "\\end_modules" << '\n';
1279 if (!included_children_.empty()) {
1280 os << "\\begin_includeonly" << '\n';
1281 for (auto const & c : included_children_)
1283 os << "\\end_includeonly" << '\n';
1286 switch (maintain_unincluded_children) {
1297 os << "\\maintain_unincluded_children " << muc << '\n';
1299 // local layout information
1300 docstring const local_layout = getLocalLayout(false);
1301 if (!local_layout.empty()) {
1302 // remove '\n' from the end
1303 docstring const tmplocal = rtrim(local_layout, "\n");
1304 os << "\\begin_local_layout\n"
1305 << to_utf8(tmplocal)
1306 << "\n\\end_local_layout\n";
1308 docstring const forced_local_layout = getLocalLayout(true);
1309 if (!forced_local_layout.empty()) {
1310 // remove '\n' from the end
1311 docstring const tmplocal = rtrim(forced_local_layout, "\n");
1312 os << "\\begin_forced_local_layout\n"
1313 << to_utf8(tmplocal)
1314 << "\n\\end_forced_local_layout\n";
1317 // then the text parameters
1318 if (language != ignore_language)
1319 os << "\\language " << language->lang() << '\n';
1320 os << "\\language_package " << lang_package
1321 << "\n\\inputencoding " << inputenc
1322 << "\n\\fontencoding " << fontenc
1323 << "\n\\font_roman \"" << fonts_roman[0]
1324 << "\" \"" << fonts_roman[1] << '"'
1325 << "\n\\font_sans \"" << fonts_sans[0]
1326 << "\" \"" << fonts_sans[1] << '"'
1327 << "\n\\font_typewriter \"" << fonts_typewriter[0]
1328 << "\" \"" << fonts_typewriter[1] << '"'
1329 << "\n\\font_math \"" << fonts_math[0]
1330 << "\" \"" << fonts_math[1] << '"'
1331 << "\n\\font_default_family " << fonts_default_family
1332 << "\n\\use_non_tex_fonts " << convert<string>(useNonTeXFonts)
1333 << "\n\\font_sc " << convert<string>(fonts_expert_sc)
1334 << "\n\\font_roman_osf " << convert<string>(fonts_roman_osf)
1335 << "\n\\font_sans_osf " << convert<string>(fonts_sans_osf)
1336 << "\n\\font_typewriter_osf " << convert<string>(fonts_typewriter_osf);
1337 if (!font_roman_opts.empty())
1338 os << "\n\\font_roman_opts \"" << font_roman_opts << "\"";
1339 os << "\n\\font_sf_scale " << fonts_sans_scale[0]
1340 << ' ' << fonts_sans_scale[1];
1341 if (!font_sans_opts.empty())
1342 os << "\n\\font_sans_opts \"" << font_sans_opts << "\"";
1343 os << "\n\\font_tt_scale " << fonts_typewriter_scale[0]
1344 << ' ' << fonts_typewriter_scale[1];
1345 if (!font_typewriter_opts.empty())
1346 os << "\n\\font_typewriter_opts \"" << font_typewriter_opts << "\"";
1348 if (!fonts_cjk.empty())
1349 os << "\\font_cjk " << fonts_cjk << '\n';
1350 os << "\\use_microtype " << convert<string>(use_microtype) << '\n';
1351 os << "\\use_dash_ligatures " << convert<string>(use_dash_ligatures) << '\n';
1352 os << "\\graphics " << graphics_driver << '\n';
1353 os << "\\default_output_format " << default_output_format << '\n';
1354 os << "\\output_sync " << output_sync << '\n';
1355 if (!output_sync_macro.empty())
1356 os << "\\output_sync_macro \"" << output_sync_macro << "\"\n";
1357 os << "\\bibtex_command " << bibtex_command << '\n';
1358 os << "\\index_command " << index_command << '\n';
1360 if (!float_placement.empty())
1361 os << "\\float_placement " << float_placement << '\n';
1362 if (!float_alignment.empty())
1363 os << "\\float_alignment " << float_alignment << '\n';
1364 os << "\\paperfontsize " << fontsize << '\n';
1366 spacing().writeFile(os);
1367 pdfoptions().writeFile(os);
1369 os << "\\papersize " << string_papersize[papersize]
1370 << "\n\\use_geometry " << convert<string>(use_geometry);
1371 map<string, string> const & packages = auto_packages();
1372 for (auto const & pack : packages)
1373 os << "\n\\use_package " << pack.first << ' '
1374 << use_package(pack.first);
1376 os << "\n\\cite_engine ";
1378 if (!cite_engine_.empty())
1383 os << "\n\\cite_engine_type " << theCiteEnginesList.getTypeAsString(cite_engine_type_);
1385 if (!biblio_style.empty())
1386 os << "\n\\biblio_style " << biblio_style;
1387 if (!biblio_opts.empty())
1388 os << "\n\\biblio_options " << biblio_opts;
1389 if (!biblatex_bibstyle.empty())
1390 os << "\n\\biblatex_bibstyle " << biblatex_bibstyle;
1391 if (!biblatex_citestyle.empty())
1392 os << "\n\\biblatex_citestyle " << biblatex_citestyle;
1393 if (!multibib.empty())
1394 os << "\n\\multibib " << multibib;
1396 os << "\n\\use_bibtopic " << convert<string>(use_bibtopic)
1397 << "\n\\use_indices " << convert<string>(use_indices)
1398 << "\n\\paperorientation " << string_orientation[orientation]
1399 << "\n\\suppress_date " << convert<string>(suppress_date)
1400 << "\n\\justification " << convert<string>(justification)
1401 << "\n\\use_refstyle " << use_refstyle
1402 << "\n\\use_minted " << use_minted
1403 << "\n\\use_lineno " << use_lineno
1406 if (!lineno_opts.empty())
1407 os << "\\lineno_options " << lineno_opts << '\n';
1409 if (isbackgroundcolor)
1410 os << "\\backgroundcolor " << lyx::X11hexname(backgroundcolor) << '\n';
1412 os << "\\fontcolor " << lyx::X11hexname(fontcolor) << '\n';
1413 if (isnotefontcolor)
1414 os << "\\notefontcolor " << lyx::X11hexname(notefontcolor) << '\n';
1416 os << "\\boxbgcolor " << lyx::X11hexname(boxbgcolor) << '\n';
1418 for (auto const & br : branchlist()) {
1419 os << "\\branch " << to_utf8(br.branch())
1420 << "\n\\selected " << br.isSelected()
1421 << "\n\\filename_suffix " << br.hasFileNameSuffix()
1422 << "\n\\color " << br.lightModeColor() << " " << br.darkModeColor()
1427 for (auto const & id : indiceslist()) {
1428 os << "\\index " << to_utf8(id.index())
1429 << "\n\\shortcut " << to_utf8(id.shortcut())
1430 << "\n\\color " << lyx::X11hexname(id.color())
1435 for (auto const & si : spellignore()) {
1436 os << "\\spellchecker_ignore " << si.lang()->code()
1437 << " " << to_utf8(si.word())
1441 if (!paperwidth.empty())
1442 os << "\\paperwidth "
1443 << VSpace(paperwidth).asLyXCommand() << '\n';
1444 if (!paperheight.empty())
1445 os << "\\paperheight "
1446 << VSpace(paperheight).asLyXCommand() << '\n';
1447 if (!leftmargin.empty())
1448 os << "\\leftmargin "
1449 << VSpace(leftmargin).asLyXCommand() << '\n';
1450 if (!topmargin.empty())
1451 os << "\\topmargin "
1452 << VSpace(topmargin).asLyXCommand() << '\n';
1453 if (!rightmargin.empty())
1454 os << "\\rightmargin "
1455 << VSpace(rightmargin).asLyXCommand() << '\n';
1456 if (!bottommargin.empty())
1457 os << "\\bottommargin "
1458 << VSpace(bottommargin).asLyXCommand() << '\n';
1459 if (!headheight.empty())
1460 os << "\\headheight "
1461 << VSpace(headheight).asLyXCommand() << '\n';
1462 if (!headsep.empty())
1464 << VSpace(headsep).asLyXCommand() << '\n';
1465 if (!footskip.empty())
1467 << VSpace(footskip).asLyXCommand() << '\n';
1468 if (!columnsep.empty())
1469 os << "\\columnsep "
1470 << VSpace(columnsep).asLyXCommand() << '\n';
1471 os << "\\secnumdepth " << secnumdepth
1472 << "\n\\tocdepth " << tocdepth
1473 << "\n\\paragraph_separation "
1474 << string_paragraph_separation[paragraph_separation];
1475 if (!paragraph_separation)
1476 os << "\n\\paragraph_indentation "
1477 << (getParIndent().empty() ? "default" : getParIndent().asString());
1479 os << "\n\\defskip " << getDefSkip().asLyXCommand();
1480 os << "\n\\is_math_indent " << is_math_indent;
1482 os << "\n\\math_indentation "
1483 << (getMathIndent().empty() ? "default" : getMathIndent().asString());
1484 os << "\n\\math_numbering_side ";
1485 switch(math_numbering_side) {
1495 os << "\n\\quotes_style "
1496 << string_quotes_style[static_cast<int>(quotes_style)]
1497 << "\n\\dynamic_quotes " << dynamic_quotes
1498 << "\n\\papercolumns " << columns
1499 << "\n\\papersides " << sides
1500 << "\n\\paperpagestyle " << pagestyle
1501 << "\n\\tablestyle " << tablestyle << '\n';
1502 if (!listings_params.empty())
1503 os << "\\listings_params \"" <<
1504 InsetListingsParams(listings_params).encodedString() << "\"\n";
1505 for (int i = 0; i < 4; ++i) {
1506 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
1507 if (user_defined_bullet(i).getFont() != -1) {
1508 os << "\\bullet " << i << " "
1509 << user_defined_bullet(i).getFont() << " "
1510 << user_defined_bullet(i).getCharacter() << " "
1511 << user_defined_bullet(i).getSize() << "\n";
1515 os << "\\bulletLaTeX " << i << " \""
1516 << lyx::to_ascii(user_defined_bullet(i).getText())
1522 os << "\\tracking_changes "
1523 << (save_transient_properties ? convert<string>(track_changes) : "false")
1526 os << "\\output_changes "
1527 << (save_transient_properties ? convert<string>(output_changes) : "false")
1530 os << "\\change_bars "
1531 << (save_transient_properties ? convert<string>(change_bars) : "false")
1534 os << "\\postpone_fragile_content " << convert<string>(postpone_fragile_content) << '\n';
1536 os << "\\html_math_output " << html_math_output << '\n'
1537 << "\\html_css_as_file " << html_css_as_file << '\n'
1538 << "\\html_be_strict " << convert<string>(html_be_strict) << '\n';
1540 os << "\\docbook_table_output " << docbook_table_output << '\n';
1542 if (html_math_img_scale != 1.0)
1543 os << "\\html_math_img_scale " << convert<string>(html_math_img_scale) << '\n';
1544 if (!html_latex_start.empty())
1545 os << "\\html_latex_start " << html_latex_start << '\n';
1546 if (!html_latex_end.empty())
1547 os << "\\html_latex_end " << html_latex_end << '\n';
1549 os << pimpl_->authorlist;
1553 void BufferParams::validate(LaTeXFeatures & features) const
1555 features.require(documentClass().required());
1557 if (columns > 1 && language->rightToLeft())
1558 features.require("rtloutputdblcol");
1560 if (output_changes) {
1561 bool xcolorulem = LaTeXFeatures::isAvailable("ulem") &&
1562 LaTeXFeatures::isAvailable("xcolor");
1564 switch (features.runparams().flavor) {
1566 case Flavor::DviLuaTeX:
1568 features.require("ct-xcolor-ulem");
1569 features.require("ulem");
1570 features.require("xcolor");
1572 features.require("ct-none");
1575 case Flavor::LuaTeX:
1576 case Flavor::PdfLaTeX:
1579 features.require("ct-xcolor-ulem");
1580 features.require("ulem");
1581 features.require("xcolor");
1582 // improves color handling in PDF output
1583 features.require("pdfcolmk");
1585 features.require("ct-none");
1592 features.require("changebar");
1595 // Floats with 'Here definitely' as default setting.
1596 if (float_placement.find('H') != string::npos)
1597 features.require("float");
1599 for (auto const & pm : use_packages) {
1600 if (pm.first == "amsmath") {
1601 // AMS Style is at document level
1602 if (pm.second == package_on ||
1603 features.isProvided("amsmath"))
1604 features.require(pm.first);
1605 } else if (pm.second == package_on)
1606 features.require(pm.first);
1609 // Document-level line spacing
1610 if (spacing().getSpace() != Spacing::Single && !spacing().isDefault())
1611 features.require("setspace");
1613 // the bullet shapes are buffer level not paragraph level
1614 // so they are tested here
1615 for (int i = 0; i < 4; ++i) {
1616 if (user_defined_bullet(i) == ITEMIZE_DEFAULTS[i])
1618 int const font = user_defined_bullet(i).getFont();
1620 int const c = user_defined_bullet(i).getCharacter();
1626 features.require("latexsym");
1628 } else if (font == 1) {
1629 features.require("amssymb");
1630 } else if (font >= 2 && font <= 5) {
1631 features.require("pifont");
1635 if (pdfoptions().use_hyperref) {
1636 features.require("hyperref");
1637 // due to interferences with babel and hyperref, the color package has to
1638 // be loaded after hyperref when hyperref is used with the colorlinks
1639 // option, see http://www.lyx.org/trac/ticket/5291
1640 if (pdfoptions().colorlinks)
1641 features.require("color");
1643 if (!listings_params.empty()) {
1644 // do not test validity because listings_params is
1645 // supposed to be valid
1647 InsetListingsParams(listings_params).separatedParams(true);
1648 // we can't support all packages, but we should load the color package
1649 if (par.find("\\color", 0) != string::npos)
1650 features.require("color");
1653 // some languages are only available via polyglossia
1654 if (features.hasPolyglossiaExclusiveLanguages())
1655 features.require("polyglossia");
1657 if (useNonTeXFonts && fontsMath() != "auto")
1658 features.require("unicode-math");
1661 features.require("microtype");
1663 if (!language->required().empty())
1664 features.require(language->required());
1668 bool BufferParams::writeLaTeX(otexstream & os, LaTeXFeatures & features,
1669 FileName const & filepath) const
1671 // http://www.tug.org/texmf-dist/doc/latex/base/fixltx2e.pdf
1672 // !! To use the Fix-cm package, load it before \documentclass, and use the command
1673 // \RequirePackage to do so, rather than the normal \usepackage
1674 // Do not try to load any other package before the document class, unless you
1675 // have a thorough understanding of the LATEX internals and know exactly what you
1677 if (features.mustProvide("fix-cm"))
1678 os << "\\RequirePackage{fix-cm}\n";
1679 // Likewise for fixltx2e. If other packages conflict with this policy,
1680 // treat it as a package bug (and report it!)
1681 // See http://www.latex-project.org/cgi-bin/ltxbugs2html?pr=latex/4407
1682 if (features.mustProvide("fixltx2e"))
1683 os << "\\RequirePackage{fixltx2e}\n";
1685 os << "\\documentclass";
1687 DocumentClass const & tclass = documentClass();
1689 ostringstream clsoptions; // the document class options.
1691 if (tokenPos(tclass.opt_fontsize(),
1692 '|', fontsize) >= 0) {
1693 // only write if existing in list (and not default)
1694 clsoptions << subst(tclass.fontsizeformat(), "$$s", fontsize) << ",";
1697 // paper sizes not supported by the class itself need the
1699 vector<string> classpsizes = getVectorFromString(tclass.opt_pagesize(), "|");
1700 bool class_supported_papersize = papersize == PAPER_DEFAULT
1701 || find(classpsizes.begin(), classpsizes.end(), string_papersize[papersize]) != classpsizes.end();
1703 if ((!use_geometry || features.isProvided("geometry-light"))
1704 && class_supported_papersize && papersize != PAPER_DEFAULT)
1705 clsoptions << subst(tclass.pagesizeformat(), "$$s", string_papersize[papersize]) << ",";
1708 if (sides != tclass.sides()) {
1711 clsoptions << "oneside,";
1714 clsoptions << "twoside,";
1720 if (columns != tclass.columns()) {
1722 clsoptions << "twocolumn,";
1724 clsoptions << "onecolumn,";
1728 && orientation == ORIENTATION_LANDSCAPE)
1729 clsoptions << "landscape,";
1732 clsoptions << "fleqn,";
1734 switch(math_numbering_side) {
1736 clsoptions << "leqno,";
1739 clsoptions << "reqno,";
1740 features.require("amsmath");
1746 // language should be a parameter to \documentclass
1747 if (language->babel() == "hebrew"
1748 && default_language->babel() != "hebrew")
1749 // This seems necessary
1750 features.useLanguage(default_language);
1752 ostringstream language_options;
1753 bool const use_babel = features.useBabel() && !features.isProvided("babel");
1754 bool const use_polyglossia = features.usePolyglossia();
1755 bool const global = lyxrc.language_global_options;
1756 if (features.useBabel() || (use_polyglossia && global)) {
1757 language_options << features.getBabelLanguages();
1758 if (!language->babel().empty()) {
1759 if (!language_options.str().empty())
1760 language_options << ',';
1761 language_options << language->babel();
1763 if (global && !language_options.str().empty())
1764 clsoptions << language_options.str() << ',';
1767 // the predefined options from the layout
1768 if (use_default_options && !tclass.options().empty())
1769 clsoptions << tclass.options() << ',';
1771 // the user-defined options
1772 if (!options.empty()) {
1773 clsoptions << options << ',';
1776 docstring const strOptions = from_utf8(clsoptions.str());
1777 if (!strOptions.empty()) {
1778 // Check if class options contain uncodable glyphs
1779 docstring uncodable_glyphs;
1780 docstring options_encodable;
1781 Encoding const * const enc = features.runparams().encoding;
1783 for (char_type c : strOptions) {
1784 if (!enc->encodable(c)) {
1785 docstring const glyph(1, c);
1786 LYXERR0("Uncodable character '"
1788 << "' in class options!");
1789 uncodable_glyphs += glyph;
1790 if (features.runparams().dryrun) {
1791 options_encodable += "<" + _("LyX Warning: ")
1792 + _("uncodable character") + " '";
1793 options_encodable += c;
1794 options_encodable += "'>";
1797 options_encodable += c;
1800 options_encodable = strOptions;
1802 // On BUFFER_VIEW|UPDATE, warn user if we found uncodable glyphs
1803 if (!features.runparams().dryrun && !uncodable_glyphs.empty()) {
1804 frontend::Alert::warning(
1805 _("Uncodable character in class options"),
1807 _("The class options of your document contain glyphs "
1808 "that are unknown in the current document encoding "
1809 "(namely %1$s).\nThese glyphs are omitted "
1810 " from the output, which may result in "
1811 "incomplete output."
1812 "\n\nPlease select an appropriate "
1813 "document encoding\n"
1814 "(such as utf8) or change the "
1815 "class options accordingly."),
1818 options_encodable = rtrim(options_encodable, ",");
1819 os << '[' << options_encodable << ']';
1822 os << '{' << from_ascii(tclass.latexname()) << "}\n";
1823 // end of \documentclass defs
1825 // The package options (via \PassOptionsToPackage)
1826 os << from_ascii(features.getPackageOptions());
1828 // if we use fontspec or newtxmath, we have to load the AMS packages here
1829 string const ams = features.loadAMSPackages();
1830 bool const ot1 = (main_font_encoding() == "default" || main_font_encoding() == "OT1");
1831 bool const use_newtxmath =
1832 theLaTeXFonts().getLaTeXFont(from_ascii(fontsMath())).getUsedPackage(
1833 ot1, false, false) == "newtxmath";
1834 if ((useNonTeXFonts || use_newtxmath) && !ams.empty())
1835 os << from_ascii(ams);
1837 if (useNonTeXFonts) {
1838 // Babel (as of 2017/11/03) loads fontspec itself
1839 if (!features.isProvided("fontspec")
1840 && !(features.useBabel() && features.isAvailable("babel-2017/11/03")))
1841 os << "\\usepackage{fontspec}\n";
1842 if (features.mustProvide("unicode-math")
1843 && features.isAvailable("unicode-math"))
1844 os << "\\usepackage{unicode-math}\n";
1847 // load CJK support package before font selection
1848 // (see autotests/export/latex/CJK/micro-sign_utf8-cjk-libertine.lyx)
1849 if (!useNonTeXFonts && encoding().package() != Encoding::none && inputenc != "utf8x"
1850 && (encoding().package() == Encoding::CJK || features.mustProvide("CJK"))) {
1851 if (inputenc == "utf8-cjk" || inputenc == "utf8")
1852 os << "\\usepackage{CJKutf8}\n";
1854 os << "\\usepackage[encapsulated]{CJK}\n";
1857 // font selection must be done before loading fontenc.sty
1858 // but after babel with non-TeX fonts
1859 string const fonts = loadFonts(features);
1860 if (!fonts.empty() && (!features.useBabel() || !useNonTeXFonts))
1861 os << from_utf8(fonts);
1863 if (fonts_default_family != "default")
1864 os << "\\renewcommand{\\familydefault}{\\"
1865 << from_ascii(fonts_default_family) << "}\n";
1867 // set font encoding
1868 // non-TeX fonts use font encoding TU (set by fontspec)
1869 if (!useNonTeXFonts && !features.isProvided("fontenc")
1870 && main_font_encoding() != "default") {
1871 // get main font encodings
1872 vector<string> fontencs = font_encodings();
1873 // get font encodings of secondary languages
1874 // FIXME: some languages (hebrew, ...) assume a standard font encoding as last
1875 // option (for text in other languages).
1876 features.getFontEncodings(fontencs);
1877 if (!fontencs.empty()) {
1878 os << "\\usepackage["
1879 << from_ascii(getStringFromVector(fontencs))
1884 // Load textcomp and pmboxdraw before (lua)inputenc (#11454)
1885 if (features.mustProvide("textcomp"))
1886 os << "\\usepackage{textcomp}\n";
1887 if (features.mustProvide("pmboxdraw"))
1888 os << "\\usepackage{pmboxdraw}\n";
1890 // handle inputenc etc.
1891 // (In documents containing text in Thai language,
1892 // we must load inputenc after babel, see lib/languages).
1893 if (!contains(features.getBabelPostsettings(), from_ascii("thai.ldf")))
1894 writeEncodingPreamble(os, features);
1897 if (!features.runparams().includeall && !included_children_.empty()) {
1898 os << "\\includeonly{";
1900 for (auto incfile : included_children_) {
1901 FileName inc = makeAbsPath(incfile, filepath.absFileName());
1902 string mangled = DocFileName(changeExtension(inc.absFileName(), ".tex")).
1904 if (!features.runparams().nice)
1906 // \includeonly doesn't want an extension
1907 incfile = changeExtension(incfile, string());
1908 incfile = support::latex_path(incfile);
1909 if (!incfile.empty()) {
1912 os << from_utf8(incfile);
1919 if (!features.isProvided("geometry")
1920 && (use_geometry || !class_supported_papersize)) {
1921 odocstringstream ods;
1922 if (!getGraphicsDriver("geometry").empty())
1923 ods << getGraphicsDriver("geometry");
1924 if (orientation == ORIENTATION_LANDSCAPE)
1925 ods << ",landscape";
1926 switch (papersize) {
1928 if (!paperwidth.empty())
1929 ods << ",paperwidth="
1930 << from_ascii(paperwidth);
1931 if (!paperheight.empty())
1932 ods << ",paperheight="
1933 << from_ascii(paperheight);
1935 case PAPER_USLETTER:
1937 case PAPER_USEXECUTIVE:
1966 ods << "," << from_ascii(string_papersize_geometry[papersize]);
1971 docstring g_options = trim(ods.str(), ",");
1972 os << "\\usepackage";
1973 // geometry-light means that the class works with geometry, but overwrites
1974 // the package options and paper sizes (memoir does this).
1975 // In this case, all options need to go to \geometry
1976 // and the standard paper sizes need to go to the class options.
1977 if (!g_options.empty() && !features.isProvided("geometry-light")) {
1978 os << '[' << g_options << ']';
1981 os << "{geometry}\n";
1982 if (use_geometry || features.isProvided("geometry-light")) {
1983 os << "\\geometry{verbose";
1984 if (!g_options.empty())
1985 // Output general options here with "geometry light".
1986 os << "," << g_options;
1987 // output this only if use_geometry is true
1989 if (!topmargin.empty())
1990 os << ",tmargin=" << from_ascii(Length(topmargin).asLatexString());
1991 if (!bottommargin.empty())
1992 os << ",bmargin=" << from_ascii(Length(bottommargin).asLatexString());
1993 if (!leftmargin.empty())
1994 os << ",lmargin=" << from_ascii(Length(leftmargin).asLatexString());
1995 if (!rightmargin.empty())
1996 os << ",rmargin=" << from_ascii(Length(rightmargin).asLatexString());
1997 if (!headheight.empty())
1998 os << ",headheight=" << from_ascii(Length(headheight).asLatexString());
1999 if (!headsep.empty())
2000 os << ",headsep=" << from_ascii(Length(headsep).asLatexString());
2001 if (!footskip.empty())
2002 os << ",footskip=" << from_ascii(Length(footskip).asLatexString());
2003 if (!columnsep.empty())
2004 os << ",columnsep=" << from_ascii(Length(columnsep).asLatexString());
2008 } else if (orientation == ORIENTATION_LANDSCAPE
2009 || papersize != PAPER_DEFAULT) {
2010 features.require("papersize");
2013 if (tokenPos(tclass.opt_pagestyle(), '|', pagestyle) >= 0) {
2014 if (pagestyle == "fancy")
2015 os << "\\usepackage{fancyhdr}\n";
2016 os << "\\pagestyle{" << from_ascii(pagestyle) << "}\n";
2019 // only output when the background color is not default
2020 if (isbackgroundcolor) {
2021 // only require color here, the background color will be defined
2022 // in LaTeXFeatures.cpp to avoid interferences with the LaTeX
2024 features.require("color");
2025 features.require("pagecolor");
2028 // only output when the font color is not default
2030 // only require color here, the font color will be defined
2031 // in LaTeXFeatures.cpp to avoid interferences with the LaTeX
2033 features.require("color");
2034 features.require("fontcolor");
2037 // Only if class has a ToC hierarchy
2038 if (tclass.hasTocLevels()) {
2039 if (secnumdepth != tclass.secnumdepth()) {
2040 os << "\\setcounter{secnumdepth}{"
2044 if (tocdepth != tclass.tocdepth()) {
2045 os << "\\setcounter{tocdepth}{"
2051 if (paragraph_separation) {
2052 // when skip separation
2054 switch (getDefSkip().kind()) {
2055 case VSpace::SMALLSKIP:
2056 psopt = "\\smallskipamount";
2058 case VSpace::MEDSKIP:
2059 psopt = "\\medskipamount";
2061 case VSpace::BIGSKIP:
2062 psopt = "\\bigskipamount";
2064 case VSpace::HALFLINE:
2065 // default (no option)
2067 case VSpace::FULLLINE:
2068 psopt = "\\baselineskip";
2070 case VSpace::LENGTH:
2071 psopt = getDefSkip().length().asLatexString();
2076 if (!features.isProvided("parskip")) {
2078 psopt = "[skip=" + psopt + "]";
2079 os << "\\usepackage" + psopt + "{parskip}\n";
2081 os << "\\setlength{\\parskip}{" + psopt + "}\n";
2084 // when separation by indentation
2085 // only output something when a width is given
2086 if (!getParIndent().empty()) {
2087 os << "\\setlength{\\parindent}{"
2088 << from_utf8(getParIndent().asLatexString())
2093 if (is_math_indent) {
2094 // when formula indentation
2095 // only output something when it is not the default
2096 if (!getMathIndent().empty()) {
2097 os << "\\setlength{\\mathindent}{"
2098 << from_utf8(getMathIndent().asString())
2103 // Now insert the LyX specific LaTeX commands...
2104 features.resolveAlternatives();
2105 features.expandMultiples();
2108 if (!output_sync_macro.empty())
2109 os << from_utf8(output_sync_macro) +"\n";
2110 else if (features.runparams().flavor == Flavor::LaTeX)
2111 os << "\\usepackage[active]{srcltx}\n";
2112 else if (features.runparams().flavor == Flavor::PdfLaTeX)
2113 os << "\\synctex=-1\n";
2116 // due to interferences with babel and hyperref, the color package has to
2117 // be loaded (when it is not already loaded) before babel when hyperref
2118 // is used with the colorlinks option, see
2119 // http://www.lyx.org/trac/ticket/5291
2120 // we decided therefore to load color always before babel, see
2121 // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg144349.html
2122 os << from_ascii(features.getColorOptions());
2124 // If we use hyperref, jurabib, japanese or varioref,
2125 // we have to call babel before
2127 && (features.isRequired("jurabib")
2128 || features.isRequired("hyperref")
2129 || features.isRequired("varioref")
2130 || features.isRequired("japanese"))) {
2131 os << features.getBabelPresettings();
2133 os << from_utf8(babelCall(language_options.str(),
2134 !lyxrc.language_global_options)) + '\n';
2135 os << features.getBabelPostsettings();
2138 // The optional packages;
2139 os << from_ascii(features.getPackages());
2141 // Additional Indices
2142 if (features.isRequired("splitidx")) {
2143 for (auto const & idx : indiceslist()) {
2144 os << "\\newindex{";
2145 os << escape(idx.shortcut());
2151 os << from_utf8(spacing().writePreamble(features.isProvided("SetSpace")));
2154 // * Hyperref manual: "Make sure it comes last of your loaded
2155 // packages, to give it a fighting chance of not being over-written,
2156 // since its job is to redefine many LaTeX commands."
2157 // * Email from Heiko Oberdiek: "It is usually better to load babel
2158 // before hyperref. Then hyperref has a chance to detect babel.
2159 // * Has to be loaded before the "LyX specific LaTeX commands" to
2160 // avoid errors with algorithm floats.
2161 // use hyperref explicitly if it is required
2162 if (features.isRequired("hyperref")) {
2163 OutputParams tmp_params = features.runparams();
2164 pdfoptions().writeLaTeX(tmp_params, os,
2165 features.isProvided("hyperref"));
2166 // correctly break URLs with hyperref and dvi/ps output
2167 if (features.runparams().hyperref_driver == "dvips"
2168 && features.isAvailable("breakurl"))
2169 os << "\\usepackage{breakurl}\n";
2170 } else if (features.isRequired("nameref"))
2171 // hyperref loads this automatically
2172 os << "\\usepackage{nameref}\n";
2175 os << "\\usepackage";
2176 if (!lineno_opts.empty())
2177 os << "[" << lineno_opts << "]";
2179 os << "\\linenumbers\n";
2182 // bibtopic needs to be loaded after hyperref.
2183 // the dot provides the aux file naming which LyX can detect.
2184 if (features.mustProvide("bibtopic"))
2185 os << "\\usepackage[dot]{bibtopic}\n";
2187 // Will be surrounded by \makeatletter and \makeatother when not empty
2188 otexstringstream atlyxpreamble;
2190 // Some macros LyX will need
2192 TexString tmppreamble = features.getMacros();
2193 if (!tmppreamble.str.empty())
2194 atlyxpreamble << "\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
2195 "LyX specific LaTeX commands.\n"
2196 << move(tmppreamble)
2199 // the text class specific preamble
2201 docstring tmppreamble = features.getTClassPreamble();
2202 if (!tmppreamble.empty())
2203 atlyxpreamble << "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
2204 "Textclass specific LaTeX commands.\n"
2208 // suppress date if selected
2209 // use \@ifundefined because we cannot be sure that every document class
2210 // has a \date command
2212 atlyxpreamble << "\\@ifundefined{date}{}{\\date{}}\n";
2214 /* the user-defined preamble */
2215 if (!containsOnly(preamble, " \n\t")) {
2217 atlyxpreamble << "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
2218 "User specified LaTeX commands.\n";
2220 // Check if the user preamble contains uncodable glyphs
2221 odocstringstream user_preamble;
2222 docstring uncodable_glyphs;
2223 Encoding const * const enc = features.runparams().encoding;
2225 for (char_type c : preamble) {
2226 if (!enc->encodable(c)) {
2227 docstring const glyph(1, c);
2228 LYXERR0("Uncodable character '"
2230 << "' in user preamble!");
2231 uncodable_glyphs += glyph;
2232 if (features.runparams().dryrun) {
2233 user_preamble << "<" << _("LyX Warning: ")
2234 << _("uncodable character") << " '";
2235 user_preamble.put(c);
2236 user_preamble << "'>";
2239 user_preamble.put(c);
2242 user_preamble << preamble;
2244 // On BUFFER_VIEW|UPDATE, warn user if we found uncodable glyphs
2245 if (!features.runparams().dryrun && !uncodable_glyphs.empty()) {
2246 frontend::Alert::warning(
2247 _("Uncodable character in user preamble"),
2249 _("The user preamble of your document contains glyphs "
2250 "that are unknown in the current document encoding "
2251 "(namely %1$s).\nThese glyphs are omitted "
2252 " from the output, which may result in "
2253 "incomplete output."
2254 "\n\nPlease select an appropriate "
2255 "document encoding\n"
2256 "(such as utf8) or change the "
2257 "preamble code accordingly."),
2260 atlyxpreamble << user_preamble.str() << '\n';
2263 // footmisc must be loaded after setspace
2264 // Load it here to avoid clashes with footmisc loaded in the user
2265 // preamble. For that reason we also pass the options via
2266 // \PassOptionsToPackage in getPreamble() and not here.
2267 if (features.mustProvide("footmisc"))
2268 atlyxpreamble << "\\usepackage{footmisc}\n";
2270 // subfig loads internally the LaTeX package "caption". As
2271 // caption is a very popular package, users will load it in
2272 // the preamble. Therefore we must load subfig behind the
2273 // user-defined preamble and check if the caption package was
2274 // loaded or not. For the case that caption is loaded before
2275 // subfig, there is the subfig option "caption=false". This
2276 // option also works when a koma-script class is used and
2277 // koma's own caption commands are used instead of caption. We
2278 // use \PassOptionsToPackage here because the user could have
2279 // already loaded subfig in the preamble.
2280 if (features.mustProvide("subfig"))
2281 atlyxpreamble << "\\ifdefined\\showcaptionsetup\n"
2282 " % Caption package is used. Advise subfig not to load it again.\n"
2283 " \\PassOptionsToPackage{caption=false}{subfig}\n"
2285 "\\usepackage{subfig}\n";
2287 // Itemize bullet settings need to be last in case the user
2288 // defines their own bullets that use a package included
2289 // in the user-defined preamble -- ARRae
2290 // Actually it has to be done much later than that
2291 // since some packages like frenchb make modifications
2292 // at \begin{document} time -- JMarc
2293 docstring bullets_def;
2294 for (int i = 0; i < 4; ++i) {
2295 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
2296 if (bullets_def.empty())
2297 bullets_def += "\\AtBeginDocument{\n";
2298 bullets_def += " \\def\\labelitemi";
2300 // `i' is one less than the item to modify
2307 bullets_def += "ii";
2313 bullets_def += '{' +
2314 user_defined_bullet(i).getText()
2319 if (!bullets_def.empty())
2320 atlyxpreamble << bullets_def << "}\n\n";
2322 if (!atlyxpreamble.empty())
2323 os << "\n\\makeatletter\n"
2324 << atlyxpreamble.release()
2325 << "\\makeatother\n\n";
2327 // We try to load babel late, in case it interferes with other packages.
2328 // Jurabib, hyperref, varioref, bicaption, menukeys and listings (bug 8995)
2329 // have to be called after babel, though.
2330 if (use_babel && !features.isRequired("jurabib")
2331 && !features.isRequired("hyperref")
2332 && !features.isRequired("varioref")
2333 && !features.isRequired("japanese")) {
2334 os << features.getBabelPresettings();
2336 os << from_utf8(babelCall(language_options.str(),
2337 !lyxrc.language_global_options)) + '\n';
2338 os << features.getBabelPostsettings();
2340 // In documents containing text in Thai language,
2341 // we must load inputenc after babel (see lib/languages).
2342 if (contains(features.getBabelPostsettings(), from_ascii("thai.ldf")))
2343 writeEncodingPreamble(os, features);
2345 // font selection must be done after babel with non-TeX fonts
2346 if (!fonts.empty() && features.useBabel() && useNonTeXFonts)
2347 os << from_utf8(fonts);
2349 if (features.isRequired("bicaption"))
2350 os << "\\usepackage{bicaption}\n";
2351 if (!listings_params.empty()
2352 || features.mustProvide("listings")
2353 || features.mustProvide("minted")) {
2355 os << "\\usepackage{minted}\n";
2357 os << "\\usepackage{listings}\n";
2359 string lst_params = listings_params;
2360 // If minted, do not output the language option (bug 11203)
2361 if (use_minted && contains(lst_params, "language=")) {
2362 vector<string> opts =
2363 getVectorFromString(lst_params, ",", false);
2364 for (size_t i = 0; i < opts.size(); ++i) {
2365 if (prefixIs(opts[i], "language="))
2366 opts.erase(opts.begin() + i--);
2368 lst_params = getStringFromVector(opts, ",");
2370 if (!lst_params.empty()) {
2372 os << "\\setminted{";
2375 // do not test validity because listings_params is
2376 // supposed to be valid
2378 InsetListingsParams(lst_params).separatedParams(true);
2379 os << from_utf8(par);
2383 // xunicode only needs to be loaded if tipa is used
2384 // (the rest is obsoleted by the new TU encoding).
2385 // It needs to be loaded at least after amsmath, amssymb,
2386 // esint and the other packages that provide special glyphs
2387 if (features.mustProvide("tipa") && useNonTeXFonts
2388 && !features.isProvided("xunicode")) {
2389 // The `xunicode` package officially only supports XeTeX,
2390 // but also works with LuaTeX. We work around its XeTeX test.
2391 if (features.runparams().flavor != Flavor::XeTeX) {
2392 os << "% Pretend to xunicode that we are XeTeX\n"
2393 << "\\def\\XeTeXpicfile{}\n";
2395 os << "\\usepackage{xunicode}\n";
2398 // covington must be loaded after beamerarticle
2399 if (features.isRequired("covington"))
2400 os << "\\usepackage{covington}\n";
2402 // Polyglossia must be loaded last ...
2403 if (use_polyglossia) {
2405 os << "\\usepackage{polyglossia}\n";
2406 // set the main language
2407 os << "\\setdefaultlanguage";
2408 if (!language->polyglossiaOpts().empty())
2409 os << "[" << from_ascii(language->polyglossiaOpts()) << "]";
2410 os << "{" << from_ascii(language->polyglossia()) << "}\n";
2411 // now setup the other languages
2412 set<string> const polylangs =
2413 features.getPolyglossiaLanguages();
2414 for (auto const & pl : polylangs) {
2415 // We do not output the options here; they are output in
2416 // the language switch commands. This is safer if multiple
2417 // varieties are used.
2418 if (pl == language->polyglossia())
2420 os << "\\setotherlanguage";
2421 os << "{" << from_ascii(pl) << "}\n";
2425 // ... but before biblatex (see #7065)
2426 if ((features.mustProvide("biblatex")
2427 || features.isRequired("biblatex-chicago"))
2428 && !features.isProvided("biblatex-chicago")
2429 && !features.isProvided("biblatex-natbib")
2430 && !features.isProvided("natbib-internal")
2431 && !features.isProvided("natbib")
2432 && !features.isProvided("jurabib")) {
2433 // The biblatex-chicago package has a differing interface
2434 // it uses a wrapper package and loads styles via fixed options
2435 bool const chicago = features.isRequired("biblatex-chicago");
2438 os << "\\usepackage";
2439 if (!biblatex_bibstyle.empty()
2440 && (biblatex_bibstyle == biblatex_citestyle)
2442 opts = "style=" + biblatex_bibstyle;
2444 } else if (!chicago) {
2445 if (!biblatex_bibstyle.empty()) {
2446 opts = "bibstyle=" + biblatex_bibstyle;
2449 if (!biblatex_citestyle.empty()) {
2450 opts += delim + "citestyle=" + biblatex_citestyle;
2454 if (!multibib.empty() && multibib != "child") {
2455 opts += delim + "refsection=" + multibib;
2458 if (bibtexCommand() == "bibtex8"
2459 || prefixIs(bibtexCommand(), "bibtex8 ")) {
2460 opts += delim + "backend=bibtex8";
2462 } else if (bibtexCommand() == "bibtex"
2463 || prefixIs(bibtexCommand(), "bibtex ")) {
2464 opts += delim + "backend=bibtex";
2467 if (!bib_encoding.empty() && encodings.fromLyXName(bib_encoding)) {
2468 opts += delim + "bibencoding="
2469 + encodings.fromLyXName(bib_encoding)->latexName();
2472 if (!biblio_opts.empty())
2473 opts += delim + biblio_opts;
2475 os << "[" << opts << "]";
2477 os << "{biblatex-chicago}\n";
2479 os << "{biblatex}\n";
2483 // Load custom language package here
2484 if (features.langPackage() == LaTeXFeatures::LANG_PACK_CUSTOM) {
2485 if (lang_package == "default")
2486 os << from_utf8(lyxrc.language_custom_package);
2488 os << from_utf8(lang_package);
2492 // Since menukeys uses catoptions, which does some heavy changes on key-value options,
2493 // it is recommended to load menukeys as the last package (even after hyperref)
2494 if (features.isRequired("menukeys"))
2495 os << "\\usepackage{menukeys}\n";
2497 docstring const i18npreamble =
2498 features.getTClassI18nPreamble(use_babel, use_polyglossia,
2500 if (!i18npreamble.empty())
2501 os << i18npreamble + '\n';
2507 void BufferParams::useClassDefaults()
2509 DocumentClass const & tclass = documentClass();
2511 sides = tclass.sides();
2512 columns = tclass.columns();
2513 pagestyle = tclass.pagestyle();
2514 tablestyle = tclass.tablestyle();
2515 use_default_options = true;
2516 // Only if class has a ToC hierarchy
2517 if (tclass.hasTocLevels()) {
2518 secnumdepth = tclass.secnumdepth();
2519 tocdepth = tclass.tocdepth();
2524 bool BufferParams::hasClassDefaults() const
2526 DocumentClass const & tclass = documentClass();
2528 return sides == tclass.sides()
2529 && columns == tclass.columns()
2530 && pagestyle == tclass.pagestyle()
2531 && tablestyle == tclass.tablestyle()
2532 && use_default_options
2533 && secnumdepth == tclass.secnumdepth()
2534 && tocdepth == tclass.tocdepth();
2538 DocumentClass const & BufferParams::documentClass() const
2544 DocumentClassConstPtr BufferParams::documentClassPtr() const
2550 void BufferParams::setDocumentClass(DocumentClassConstPtr tc)
2552 // evil, but this function is evil
2553 doc_class_ = const_pointer_cast<DocumentClass>(tc);
2554 invalidateConverterCache();
2558 bool BufferParams::setBaseClass(string const & classname, string const & path)
2560 LYXERR(Debug::TCLASS, "setBaseClass: " << classname);
2561 LayoutFileList & bcl = LayoutFileList::get();
2562 if (!bcl.haveClass(classname)) {
2564 bformat(_("The layout file:\n"
2566 "could not be found. A default textclass with default\n"
2567 "layouts will be used. LyX will not be able to produce\n"
2569 from_utf8(classname));
2570 frontend::Alert::error(_("Document class not found"), s);
2571 bcl.addEmptyClass(classname);
2574 bool const success = bcl[classname].load(path);
2577 bformat(_("Due to some error in it, the layout file:\n"
2579 "could not be loaded. A default textclass with default\n"
2580 "layouts will be used. LyX will not be able to produce\n"
2582 from_utf8(classname));
2583 frontend::Alert::error(_("Could not load class"), s);
2584 bcl.addEmptyClass(classname);
2587 pimpl_->baseClass_ = classname;
2588 layout_modules_.adaptToBaseClass(baseClass(), removed_modules_);
2593 LayoutFile const * BufferParams::baseClass() const
2595 if (LayoutFileList::get().haveClass(pimpl_->baseClass_))
2596 return &(LayoutFileList::get()[pimpl_->baseClass_]);
2602 LayoutFileIndex const & BufferParams::baseClassID() const
2604 return pimpl_->baseClass_;
2608 void BufferParams::makeDocumentClass(bool clone, bool internal)
2613 invalidateConverterCache();
2614 LayoutModuleList mods;
2615 for (auto const & mod : layout_modules_)
2616 mods.push_back(mod);
2618 doc_class_ = getDocumentClass(*baseClass(), mods, cite_engine_, clone, internal);
2620 TextClass::ReturnValues success = TextClass::OK;
2621 if (!forced_local_layout_.empty())
2622 success = doc_class_->read(to_utf8(forced_local_layout_),
2624 if (!local_layout_.empty() &&
2625 (success == TextClass::OK || success == TextClass::OK_OLDFORMAT))
2626 success = doc_class_->read(to_utf8(local_layout_), TextClass::MODULE);
2627 if (success != TextClass::OK && success != TextClass::OK_OLDFORMAT) {
2628 docstring const msg = _("Error reading internal layout information");
2629 frontend::Alert::warning(_("Read Error"), msg);
2634 bool BufferParams::layoutModuleCanBeAdded(string const & modName) const
2636 return layout_modules_.moduleCanBeAdded(modName, baseClass());
2640 docstring BufferParams::getLocalLayout(bool forced) const
2643 return from_utf8(doc_class_->forcedLayouts());
2645 return local_layout_;
2649 void BufferParams::setLocalLayout(docstring const & layout, bool forced)
2652 forced_local_layout_ = layout;
2654 local_layout_ = layout;
2658 bool BufferParams::addLayoutModule(string const & modName)
2660 for (auto const & mod : layout_modules_)
2663 layout_modules_.push_back(modName);
2668 string BufferParams::bufferFormat() const
2670 return documentClass().outputFormat();
2674 bool BufferParams::isExportable(string const & format, bool need_viewable) const
2676 FormatList const & formats = exportableFormats(need_viewable);
2677 for (auto const & fmt : formats) {
2678 if (fmt->name() == format)
2685 FormatList const & BufferParams::exportableFormats(bool only_viewable) const
2687 FormatList & cached = only_viewable ?
2688 pimpl_->viewableFormatList : pimpl_->exportableFormatList;
2689 bool & valid = only_viewable ?
2690 pimpl_->isViewCacheValid : pimpl_->isExportCacheValid;
2694 vector<string> const backs = backends();
2695 set<string> excludes;
2696 if (useNonTeXFonts) {
2697 excludes.insert("latex");
2698 excludes.insert("pdflatex");
2699 } else if (inputenc != "ascii" && inputenc != "utf8-plain") {
2700 // XeTeX with TeX fonts requires input encoding ascii (#10600).
2701 excludes.insert("xetex");
2705 theConverters().getReachable(backs[0], only_viewable, true, excludes);
2706 vector<string>::const_iterator it = backs.begin() + 1;
2707 for (; it != backs.end(); ++it) {
2708 FormatList r = theConverters().getReachable(*it, only_viewable,
2710 result.insert(result.end(), r.begin(), r.end());
2712 sort(result.begin(), result.end(), Format::formatSorter);
2719 vector<string> BufferParams::backends() const
2722 string const buffmt = bufferFormat();
2724 // FIXME: Don't hardcode format names here, but use a flag
2725 if (buffmt == "latex") {
2726 if (encoding().package() == Encoding::japanese)
2727 v.push_back("platex");
2729 if (!useNonTeXFonts) {
2730 v.push_back("pdflatex");
2731 v.push_back("latex");
2734 || inputenc == "ascii" || inputenc == "utf8-plain")
2735 v.push_back("xetex");
2736 v.push_back("luatex");
2737 v.push_back("dviluatex");
2740 string rbuffmt = buffmt;
2741 // If we use an OutputFormat in Japanese docs,
2742 // we need special format in order to get the path
2743 // via pLaTeX (#8823)
2744 if (documentClass().hasOutputFormat()
2745 && encoding().package() == Encoding::japanese)
2747 v.push_back(rbuffmt);
2750 v.push_back("xhtml");
2751 v.push_back("docbook5");
2752 v.push_back("text");
2758 Flavor BufferParams::getOutputFlavor(string const & format) const
2760 string const dformat = (format.empty() || format == "default") ?
2761 getDefaultOutputFormat() : format;
2762 DefaultFlavorCache::const_iterator it =
2763 default_flavors_.find(dformat);
2765 if (it != default_flavors_.end())
2768 Flavor result = Flavor::LaTeX;
2770 // FIXME It'd be better not to hardcode this, but to do
2771 // something with formats.
2772 if (dformat == "xhtml")
2773 result = Flavor::Html;
2774 else if (dformat == "docbook5")
2775 result = Flavor::DocBook5;
2776 else if (dformat == "text")
2777 result = Flavor::Text;
2778 else if (dformat == "lyx")
2779 result = Flavor::LyX;
2780 else if (dformat == "pdflatex")
2781 result = Flavor::PdfLaTeX;
2782 else if (dformat == "xetex")
2783 result = Flavor::XeTeX;
2784 else if (dformat == "luatex")
2785 result = Flavor::LuaTeX;
2786 else if (dformat == "dviluatex")
2787 result = Flavor::DviLuaTeX;
2789 // Try to determine flavor of default output format
2790 vector<string> backs = backends();
2791 if (find(backs.begin(), backs.end(), dformat) == backs.end()) {
2792 // Get shortest path to format
2793 Graph::EdgePath path;
2794 for (auto const & bvar : backs) {
2795 Graph::EdgePath p = theConverters().getPath(bvar, dformat);
2796 if (!p.empty() && (path.empty() || p.size() < path.size())) {
2801 result = theConverters().getFlavor(path);
2804 // cache this flavor
2805 default_flavors_[dformat] = result;
2810 string BufferParams::getDefaultOutputFormat() const
2812 if (!default_output_format.empty()
2813 && default_output_format != "default")
2814 return default_output_format;
2815 if (encoding().package() == Encoding::japanese)
2816 return lyxrc.default_platex_view_format;
2818 return lyxrc.default_otf_view_format;
2819 return lyxrc.default_view_format;
2822 Font const BufferParams::getFont() const
2824 FontInfo f = documentClass().defaultfont();
2825 if (fonts_default_family == "rmdefault")
2826 f.setFamily(ROMAN_FAMILY);
2827 else if (fonts_default_family == "sfdefault")
2828 f.setFamily(SANS_FAMILY);
2829 else if (fonts_default_family == "ttdefault")
2830 f.setFamily(TYPEWRITER_FAMILY);
2831 return Font(f, language);
2835 QuoteStyle BufferParams::getQuoteStyle(string const & qs) const
2837 return quotesstyletranslator().find(qs);
2841 bool BufferParams::isLatex() const
2843 return documentClass().outputType() == LATEX;
2847 bool BufferParams::isLiterate() const
2849 return documentClass().outputType() == LITERATE;
2853 void BufferParams::readPreamble(Lexer & lex)
2855 if (lex.getString() != "\\begin_preamble")
2856 lyxerr << "Error (BufferParams::readPreamble):"
2857 "consistency check failed." << endl;
2859 preamble = lex.getLongString(from_ascii("\\end_preamble"));
2863 void BufferParams::readLocalLayout(Lexer & lex, bool forced)
2865 string const expected = forced ? "\\begin_forced_local_layout" :
2866 "\\begin_local_layout";
2867 if (lex.getString() != expected)
2868 lyxerr << "Error (BufferParams::readLocalLayout):"
2869 "consistency check failed." << endl;
2872 forced_local_layout_ =
2873 lex.getLongString(from_ascii("\\end_forced_local_layout"));
2875 local_layout_ = lex.getLongString(from_ascii("\\end_local_layout"));
2879 bool BufferParams::setLanguage(string const & lang)
2881 Language const *new_language = languages.getLanguage(lang);
2882 if (!new_language) {
2883 // Language lang was not found
2886 language = new_language;
2891 void BufferParams::readLanguage(Lexer & lex)
2893 if (!lex.next()) return;
2895 string const tmptok = lex.getString();
2897 // check if tmptok is part of tex_babel in tex-defs.h
2898 if (!setLanguage(tmptok)) {
2899 // Language tmptok was not found
2900 language = default_language;
2901 lyxerr << "Warning: Setting language `"
2902 << tmptok << "' to `" << language->lang()
2908 void BufferParams::readGraphicsDriver(Lexer & lex)
2913 string const tmptok = lex.getString();
2914 // check if tmptok is part of tex_graphics in tex_defs.h
2917 string const test = tex_graphics[n++];
2919 if (test == tmptok) {
2920 graphics_driver = tmptok;
2925 "Warning: graphics driver `$$Token' not recognized!\n"
2926 " Setting graphics driver to `default'.\n");
2927 graphics_driver = "default";
2934 void BufferParams::readBullets(Lexer & lex)
2939 int const index = lex.getInteger();
2941 int temp_int = lex.getInteger();
2942 user_defined_bullet(index).setFont(temp_int);
2943 temp_bullet(index).setFont(temp_int);
2945 user_defined_bullet(index).setCharacter(temp_int);
2946 temp_bullet(index).setCharacter(temp_int);
2948 user_defined_bullet(index).setSize(temp_int);
2949 temp_bullet(index).setSize(temp_int);
2953 void BufferParams::readBulletsLaTeX(Lexer & lex)
2955 // The bullet class should be able to read this.
2958 int const index = lex.getInteger();
2960 docstring const temp_str = lex.getDocString();
2962 user_defined_bullet(index).setText(temp_str);
2963 temp_bullet(index).setText(temp_str);
2967 void BufferParams::readModules(Lexer & lex)
2969 if (!lex.eatLine()) {
2970 lyxerr << "Error (BufferParams::readModules):"
2971 "Unexpected end of input." << endl;
2975 string mod = lex.getString();
2976 if (mod == "\\end_modules")
2978 addLayoutModule(mod);
2984 void BufferParams::readRemovedModules(Lexer & lex)
2986 if (!lex.eatLine()) {
2987 lyxerr << "Error (BufferParams::readRemovedModules):"
2988 "Unexpected end of input." << endl;
2992 string mod = lex.getString();
2993 if (mod == "\\end_removed_modules")
2995 removed_modules_.push_back(mod);
2998 // now we want to remove any removed modules that were previously
2999 // added. normally, that will be because default modules were added in
3000 // setBaseClass(), which gets called when \textclass is read at the
3001 // start of the read.
3002 for (auto const & rm : removed_modules_) {
3003 LayoutModuleList::iterator const mit = layout_modules_.begin();
3004 LayoutModuleList::iterator const men = layout_modules_.end();
3005 LayoutModuleList::iterator found = find(mit, men, rm);
3008 layout_modules_.erase(found);
3013 void BufferParams::readIncludeonly(Lexer & lex)
3015 if (!lex.eatLine()) {
3016 lyxerr << "Error (BufferParams::readIncludeonly):"
3017 "Unexpected end of input." << endl;
3021 string child = lex.getString();
3022 if (child == "\\end_includeonly")
3024 included_children_.push_back(child);
3030 string BufferParams::paperSizeName(PapersizePurpose purpose, string const & psize) const
3032 PAPER_SIZE ppsize = psize.empty() ? papersize : papersizetranslator().find(psize);
3035 if (documentClass().pagesize() == "default")
3036 // could be anything, so don't guess
3038 return paperSizeName(purpose, documentClass().pagesize());
3039 case PAPER_CUSTOM: {
3040 if (purpose == XDVI && !paperwidth.empty() &&
3041 !paperheight.empty()) {
3042 // heightxwidth<unit>
3043 string first = paperwidth;
3044 string second = paperheight;
3045 if (orientation == ORIENTATION_LANDSCAPE)
3048 return first.erase(first.length() - 2)
3054 // dvips and dvipdfm do not know this
3055 if (purpose == DVIPS || purpose == DVIPDFM)
3059 if (purpose == DVIPS || purpose == DVIPDFM)
3063 if (purpose == DVIPS || purpose == DVIPDFM)
3073 if (purpose == DVIPS || purpose == DVIPDFM)
3077 if (purpose == DVIPS || purpose == DVIPDFM)
3081 if (purpose == DVIPS || purpose == DVIPDFM)
3085 if (purpose == DVIPS || purpose == DVIPDFM)
3089 if (purpose == DVIPS || purpose == DVIPDFM)
3093 // dvipdfm does not know this
3094 if (purpose == DVIPDFM)
3098 if (purpose == DVIPDFM)
3102 if (purpose == DVIPS || purpose == DVIPDFM)
3106 if (purpose == DVIPS || purpose == DVIPDFM)
3110 if (purpose == DVIPS || purpose == DVIPDFM)
3114 if (purpose == DVIPS || purpose == DVIPDFM)
3118 if (purpose == DVIPS || purpose == DVIPDFM)
3122 if (purpose == DVIPS || purpose == DVIPDFM)
3126 if (purpose == DVIPS || purpose == DVIPDFM)
3130 if (purpose == DVIPS || purpose == DVIPDFM)
3134 if (purpose == DVIPS || purpose == DVIPDFM)
3138 if (purpose == DVIPS || purpose == DVIPDFM)
3142 if (purpose == DVIPS || purpose == DVIPDFM)
3146 if (purpose == DVIPS || purpose == DVIPDFM)
3150 if (purpose == DVIPS || purpose == DVIPDFM)
3154 if (purpose == DVIPS || purpose == DVIPDFM)
3158 if (purpose == DVIPS || purpose == DVIPDFM)
3161 case PAPER_USEXECUTIVE:
3162 // dvipdfm does not know this
3163 if (purpose == DVIPDFM)
3168 case PAPER_USLETTER:
3170 if (purpose == XDVI)
3177 string const BufferParams::dvips_options() const
3181 // If the class loads the geometry package, we do not know which
3182 // paper size is used, since we do not set it (bug 7013).
3183 // Therefore we must not specify any argument here.
3184 // dvips gets the correct paper size via DVI specials in this case
3185 // (if the class uses the geometry package correctly).
3186 if (documentClass().provides("geometry"))
3190 && papersize == PAPER_CUSTOM
3191 && !lyxrc.print_paper_dimension_flag.empty()
3192 && !paperwidth.empty()
3193 && !paperheight.empty()) {
3194 // using a custom papersize
3195 result = lyxrc.print_paper_dimension_flag;
3196 result += ' ' + paperwidth;
3197 result += ',' + paperheight;
3199 string const paper_option = paperSizeName(DVIPS);
3200 if (!paper_option.empty() && (paper_option != "letter" ||
3201 orientation != ORIENTATION_LANDSCAPE)) {
3202 // dvips won't accept -t letter -t landscape.
3203 // In all other cases, include the paper size
3205 result = lyxrc.print_paper_flag;
3206 result += ' ' + paper_option;
3209 if (orientation == ORIENTATION_LANDSCAPE &&
3210 papersize != PAPER_CUSTOM)
3211 result += ' ' + lyxrc.print_landscape_flag;
3216 string const BufferParams::main_font_encoding() const
3218 if (font_encodings().empty()) {
3219 if (ascii_lowercase(language->fontenc(*this)) == "none")
3223 return font_encodings().back();
3227 vector<string> const BufferParams::font_encodings() const
3229 string doc_fontenc = (fontenc == "auto") ? string() : fontenc;
3231 vector<string> fontencs;
3233 // "default" means "no explicit font encoding"
3234 if (doc_fontenc != "default") {
3235 if (!doc_fontenc.empty())
3236 // If we have a custom setting, we use only that!
3237 return getVectorFromString(doc_fontenc);
3238 if (!language->fontenc(*this).empty()
3239 && ascii_lowercase(language->fontenc(*this)) != "none") {
3240 vector<string> fencs = getVectorFromString(language->fontenc(*this));
3241 for (auto & fe : fencs) {
3242 if (find(fontencs.begin(), fontencs.end(), fe) == fontencs.end())
3243 fontencs.push_back(fe);
3252 string BufferParams::babelCall(string const & lang_opts, bool const langoptions) const
3254 // suppress the babel call if there is no BabelName defined
3255 // for the document language in the lib/languages file and if no
3256 // other languages are used (lang_opts is then empty)
3257 if (lang_opts.empty())
3259 // The prefs may require the languages to
3260 // be submitted to babel itself (not the class).
3262 return "\\usepackage[" + lang_opts + "]{babel}";
3263 return "\\usepackage{babel}";
3267 docstring BufferParams::getGraphicsDriver(string const & package) const
3271 if (package == "geometry") {
3272 if (graphics_driver == "dvips"
3273 || graphics_driver == "dvipdfm"
3274 || graphics_driver == "pdftex"
3275 || graphics_driver == "vtex")
3276 result = from_ascii(graphics_driver);
3277 else if (graphics_driver == "dvipdfmx")
3278 result = from_ascii("dvipdfm");
3285 void BufferParams::writeEncodingPreamble(otexstream & os,
3286 LaTeXFeatures & features) const
3288 // With no-TeX fonts we use utf8-plain without encoding package.
3292 if (inputenc == "auto-legacy") {
3293 string const doc_encoding =
3294 language->encoding()->latexName();
3295 Encoding::Package const package =
3296 language->encoding()->package();
3298 // Create list of inputenc options:
3299 set<string> encoding_set;
3300 // luainputenc fails with more than one encoding
3301 if (features.runparams().flavor != Flavor::LuaTeX
3302 && features.runparams().flavor != Flavor::DviLuaTeX)
3303 // list all input encodings used in the document
3304 encoding_set = features.getEncodingSet(doc_encoding);
3306 // The "japanese" babel-language requires the pLaTeX engine
3307 // which conflicts with "inputenc".
3308 // See http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129680.html
3309 if ((!encoding_set.empty() || package == Encoding::inputenc)
3310 && !features.isRequired("japanese")
3311 && !features.isProvided("inputenc")) {
3312 os << "\\usepackage[";
3313 set<string>::const_iterator it = encoding_set.begin();
3314 set<string>::const_iterator const end = encoding_set.end();
3316 os << from_ascii(*it);
3319 for (; it != end; ++it)
3320 os << ',' << from_ascii(*it);
3321 if (package == Encoding::inputenc) {
3322 if (!encoding_set.empty())
3324 os << from_ascii(doc_encoding);
3326 if (features.runparams().flavor == Flavor::LuaTeX
3327 || features.runparams().flavor == Flavor::DviLuaTeX)
3328 os << "]{luainputenc}\n";
3330 os << "]{inputenc}\n";
3332 } else if (inputenc != "auto-legacy-plain") {
3333 switch (encoding().package()) {
3334 case Encoding::none:
3336 case Encoding::japanese:
3337 if (encoding().iconvName() != "UTF-8"
3338 && !features.runparams().isFullUnicode())
3339 // don't default to [utf8]{inputenc} with TeXLive >= 18
3340 os << "\\ifdefined\\UseRawInputEncoding\n"
3341 << " \\UseRawInputEncoding\\fi\n";
3343 case Encoding::inputenc:
3344 // do not load inputenc if japanese is used
3345 // or if the class provides inputenc
3346 if (features.isRequired("japanese")
3347 || features.isProvided("inputenc"))
3349 os << "\\usepackage[" << from_ascii(encoding().latexName());
3350 if (features.runparams().flavor == Flavor::LuaTeX
3351 || features.runparams().flavor == Flavor::DviLuaTeX)
3352 os << "]{luainputenc}\n";
3354 os << "]{inputenc}\n";
3358 if (inputenc == "auto-legacy-plain" || features.isRequired("japanese")) {
3359 // don't default to [utf8]{inputenc} with TeXLive >= 18
3360 os << "\\ifdefined\\UseRawInputEncoding\n";
3361 os << " \\UseRawInputEncoding\\fi\n";
3366 string const BufferParams::parseFontName(string const & name) const
3368 string mangled = name;
3369 size_t const idx = mangled.find('[');
3370 if (idx == string::npos || idx == 0)
3373 return mangled.substr(0, idx - 1);
3377 string const BufferParams::loadFonts(LaTeXFeatures & features) const
3379 if (fontsRoman() == "default" && fontsSans() == "default"
3380 && fontsTypewriter() == "default"
3381 && (fontsMath() == "default" || fontsMath() == "auto"))
3387 /* Fontspec (XeTeX, LuaTeX): we provide GUI support for oldstyle
3388 * numbers (Numbers=OldStyle) and sf/tt scaling. The Ligatures=TeX/
3389 * Mapping=tex-text option assures TeX ligatures (such as "--")
3390 * are resolved. Note that tt does not use these ligatures.
3392 * -- add more GUI options?
3393 * -- add more fonts (fonts for other scripts)
3394 * -- if there's a way to find out if a font really supports
3395 * OldStyle, enable/disable the widget accordingly.
3397 if (useNonTeXFonts && features.isAvailable("fontspec")) {
3398 // "Mapping=tex-text" and "Ligatures=TeX" are equivalent.
3399 // However, until v.2 (2010/07/11) fontspec only knew
3400 // Mapping=tex-text (for XeTeX only); then "Ligatures=TeX"
3401 // was introduced for both XeTeX and LuaTeX (LuaTeX
3402 // didn't understand "Mapping=tex-text", while XeTeX
3403 // understood both. With most recent versions, both
3404 // variants are understood by both engines. However,
3405 // we want to provide support for at least TeXLive 2009
3406 // (for XeTeX; LuaTeX is only supported as of v.2)
3407 // As of 2017/11/03, Babel has its own higher-level
3408 // interface on top of fontspec that is to be used.
3409 bool const babelfonts = features.useBabel()
3410 && features.isAvailable("babel-2017/11/03");
3411 string const texmapping =
3412 (features.runparams().flavor == Flavor::XeTeX) ?
3413 "Mapping=tex-text" : "Ligatures=TeX";
3414 if (fontsRoman() != "default") {
3416 os << "\\babelfont{rm}[";
3418 os << "\\setmainfont[";
3419 if (!font_roman_opts.empty())
3420 os << font_roman_opts << ',';
3422 if (fonts_roman_osf)
3423 os << ",Numbers=OldStyle";
3424 os << "]{" << parseFontName(fontsRoman()) << "}\n";
3426 if (fontsSans() != "default") {
3427 string const sans = parseFontName(fontsSans());
3428 if (fontsSansScale() != 100) {
3430 os << "\\babelfont{sf}";
3432 os << "\\setsansfont";
3434 << float(fontsSansScale()) / 100 << ',';
3436 os << "Numbers=OldStyle,";
3437 if (!font_sans_opts.empty())
3438 os << font_sans_opts << ',';
3439 os << texmapping << "]{"
3443 os << "\\babelfont{sf}[";
3445 os << "\\setsansfont[";
3447 os << "Numbers=OldStyle,";
3448 if (!font_sans_opts.empty())
3449 os << font_sans_opts << ',';
3450 os << texmapping << "]{"
3454 if (fontsTypewriter() != "default") {
3455 string const mono = parseFontName(fontsTypewriter());
3456 if (fontsTypewriterScale() != 100) {
3458 os << "\\babelfont{tt}";
3460 os << "\\setmonofont";
3462 << float(fontsTypewriterScale()) / 100;
3463 if (fonts_typewriter_osf)
3464 os << ",Numbers=OldStyle";
3465 if (!font_typewriter_opts.empty())
3466 os << ',' << font_typewriter_opts;
3471 os << "\\babelfont{tt}";
3473 os << "\\setmonofont";
3474 if (!font_typewriter_opts.empty() || fonts_typewriter_osf) {
3476 if (fonts_typewriter_osf)
3477 os << "Numbers=OldStyle";
3478 if (!font_typewriter_opts.empty()) {
3479 if (fonts_typewriter_osf)
3481 os << font_typewriter_opts;
3485 os << '{' << mono << "}\n";
3492 bool const ot1 = (main_font_encoding() == "default" || main_font_encoding() == "OT1");
3493 bool const dryrun = features.runparams().dryrun;
3494 bool const complete = (fontsSans() == "default" && fontsTypewriter() == "default");
3495 bool const nomath = (fontsMath() != "auto");
3498 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsRoman())).getLaTeXCode(
3499 dryrun, ot1, complete, fonts_expert_sc, fonts_roman_osf,
3500 nomath, font_roman_opts);
3503 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsSans())).getLaTeXCode(
3504 dryrun, ot1, complete, fonts_expert_sc, fonts_sans_osf,
3505 nomath, font_sans_opts, fontsSansScale());
3507 // MONOSPACED/TYPEWRITER
3508 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsTypewriter())).getLaTeXCode(
3509 dryrun, ot1, complete, fonts_expert_sc, fonts_typewriter_osf,
3510 nomath, font_typewriter_opts, fontsTypewriterScale());
3513 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsMath())).getLaTeXCode(
3514 dryrun, ot1, complete, fonts_expert_sc, fonts_roman_osf,
3521 Encoding const & BufferParams::encoding() const
3523 // Main encoding for LaTeX output.
3525 return *(encodings.fromLyXName("utf8-plain"));
3526 if (inputenc == "auto-legacy" || inputenc == "auto-legacy-plain")
3527 return *language->encoding();
3528 if (inputenc == "utf8" && language->lang() == "japanese")
3529 return *(encodings.fromLyXName("utf8-platex"));
3530 Encoding const * const enc = encodings.fromLyXName(inputenc);
3533 LYXERR0("Unknown inputenc value `" << inputenc
3534 << "'. Using `auto' instead.");
3535 return *language->encoding();
3539 string const & BufferParams::defaultBiblioStyle() const
3541 if (!biblio_style.empty())
3542 return biblio_style;
3544 map<string, string> const & bs = documentClass().defaultBiblioStyle();
3545 auto cit = bs.find(theCiteEnginesList.getTypeAsString(citeEngineType()));
3546 if (cit != bs.end())
3549 return empty_string();
3553 bool BufferParams::fullAuthorList() const
3555 return documentClass().fullAuthorList();
3559 string BufferParams::getCiteAlias(string const & s) const
3561 vector<string> commands =
3562 documentClass().citeCommands(citeEngineType());
3563 // If it is a real command, don't treat it as an alias
3564 if (find(commands.begin(), commands.end(), s) != commands.end())
3566 map<string,string> aliases = documentClass().citeCommandAliases();
3567 if (aliases.find(s) != aliases.end())
3573 vector<string> BufferParams::citeCommands() const
3575 static CitationStyle const default_style;
3576 vector<string> commands =
3577 documentClass().citeCommands(citeEngineType());
3578 if (commands.empty())
3579 commands.push_back(default_style.name);
3584 vector<CitationStyle> BufferParams::citeStyles() const
3586 static CitationStyle const default_style;
3587 vector<CitationStyle> styles =
3588 documentClass().citeStyles(citeEngineType());
3590 styles.push_back(default_style);
3595 string const BufferParams::bibtexCommand() const
3597 // Return document-specific setting if available
3598 if (bibtex_command != "default")
3599 return bibtex_command;
3601 // If we have "default" in document settings, consult the prefs
3602 // 1. Japanese (uses a specific processor)
3603 if (encoding().package() == Encoding::japanese) {
3604 if (lyxrc.jbibtex_command != "automatic")
3605 // Return the specified program, if "automatic" is not set
3606 return lyxrc.jbibtex_command;
3607 else if (!useBiblatex()) {
3608 // With classic BibTeX, return pbibtex, jbibtex, bibtex
3609 if (lyxrc.jbibtex_alternatives.find("pbibtex") != lyxrc.jbibtex_alternatives.end())
3611 if (lyxrc.jbibtex_alternatives.find("jbibtex") != lyxrc.jbibtex_alternatives.end())
3616 // 2. All other languages
3617 else if (lyxrc.bibtex_command != "automatic")
3618 // Return the specified program, if "automatic" is not set
3619 return lyxrc.bibtex_command;
3621 // 3. Automatic: find the most suitable for the current cite framework
3622 if (useBiblatex()) {
3623 // For Biblatex, we prefer biber (also for Japanese)
3624 // and fall back to bibtex8 and, as last resort, bibtex
3625 if (lyxrc.bibtex_alternatives.find("biber") != lyxrc.bibtex_alternatives.end())
3627 else if (lyxrc.bibtex_alternatives.find("bibtex8") != lyxrc.bibtex_alternatives.end())
3634 bool BufferParams::useBiblatex() const
3636 return theCiteEnginesList[citeEngine()]->getCiteFramework() == "biblatex";
3640 void BufferParams::invalidateConverterCache() const
3642 pimpl_->isExportCacheValid = false;
3643 pimpl_->isViewCacheValid = false;
3647 // We shouldn't need to reset the params here, since anything
3648 // we need will be recopied.
3649 void BufferParams::copyForAdvFR(const BufferParams & bp)
3651 string const & lang = bp.language->lang();
3653 layout_modules_ = bp.layout_modules_;
3654 string const & doc_class = bp.documentClass().name();
3655 setBaseClass(doc_class);
3659 void BufferParams::setBibFileEncoding(string const & file, string const & enc)
3661 bib_encodings[file] = enc;
3665 string const BufferParams::bibFileEncoding(string const & file) const
3667 if (bib_encodings.find(file) == bib_encodings.end())
3669 return bib_encodings.find(file)->second;