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 WordLangTable 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)));
373 // set comparison author
374 authorlist.record(Author(from_utf8("Document Comparison"),
375 docstring(), docstring()));
380 BufferParams::MemoryTraits::clone(BufferParams::Impl const * ptr)
383 return new BufferParams::Impl(*ptr);
387 void BufferParams::MemoryTraits::destroy(BufferParams::Impl * ptr)
393 BufferParams::BufferParams()
396 setBaseClass(defaultBaseclass());
397 cite_engine_ = "basic";
398 cite_engine_type_ = ENGINE_TYPE_DEFAULT;
400 paragraph_separation = ParagraphIndentSeparation;
401 is_math_indent = false;
402 math_numbering_side = DEFAULT;
403 quotes_style = QuoteStyle::English;
404 dynamic_quotes = false;
405 fontsize = "default";
408 papersize = PAPER_DEFAULT;
409 orientation = ORIENTATION_PORTRAIT;
410 use_geometry = false;
411 biblio_style = string();
412 use_bibtopic = false;
415 save_transient_properties = true;
416 track_changes = false;
417 output_changes = false;
419 postpone_fragile_content = true;
420 use_default_options = true;
421 maintain_unincluded_children = CM_None;
424 language = default_language;
426 fonts_roman[0] = "default";
427 fonts_roman[1] = "default";
428 fonts_sans[0] = "default";
429 fonts_sans[1] = "default";
430 fonts_typewriter[0] = "default";
431 fonts_typewriter[1] = "default";
432 fonts_math[0] = "auto";
433 fonts_math[1] = "auto";
434 fonts_default_family = "default";
435 useNonTeXFonts = false;
436 use_microtype = false;
437 use_dash_ligatures = true;
438 fonts_expert_sc = false;
439 fonts_roman_osf = false;
440 fonts_sans_osf = false;
441 fonts_typewriter_osf = false;
442 fonts_sans_scale[0] = 100;
443 fonts_sans_scale[1] = 100;
444 fonts_typewriter_scale[0] = 100;
445 fonts_typewriter_scale[1] = 100;
447 lang_package = "default";
448 graphics_driver = "default";
449 default_output_format = "default";
450 bibtex_command = "default";
451 index_command = "default";
454 listings_params = string();
455 pagestyle = "default";
456 tablestyle = "default";
457 float_alignment = "class";
458 float_placement = "class";
459 suppress_date = false;
460 justification = true;
461 // no color is the default (white)
462 backgroundcolor = lyx::rgbFromHexName("#ffffff");
463 isbackgroundcolor = false;
464 // no color is the default (black)
465 fontcolor = lyx::rgbFromHexName("#000000");
467 // light gray is the default font color for greyed-out notes
468 notefontcolor = lyx::rgbFromHexName("#cccccc");
469 isnotefontcolor = false;
470 boxbgcolor = lyx::rgbFromHexName("#ff0000");
471 isboxbgcolor = false;
472 compressed = lyxrc.save_compressed;
473 for (int iter = 0; iter < 4; ++iter) {
474 user_defined_bullet(iter) = ITEMIZE_DEFAULTS[iter];
475 temp_bullet(iter) = ITEMIZE_DEFAULTS[iter];
478 indiceslist().addDefault(B_("Index"));
479 html_be_strict = false;
480 html_math_output = MathML;
481 html_math_img_scale = 1.0;
482 html_css_as_file = false;
483 docbook_table_output = HTMLTable;
484 docbook_mathml_prefix = MPrefix;
485 display_pixel_ratio = 1.0;
487 shell_escape = false;
493 // map current author
494 author_map_[pimpl_->authorlist.get(0).bufferId()] = 0;
498 docstring BufferParams::B_(string const & l10n) const
500 LASSERT(language, return from_utf8(l10n));
501 return getMessages(language->code()).get(l10n);
505 BufferParams::Package BufferParams::use_package(std::string const & p) const
507 PackageMap::const_iterator it = use_packages.find(p);
508 if (it == use_packages.end())
514 void BufferParams::use_package(std::string const & p, BufferParams::Package u)
520 map<string, string> const & BufferParams::auto_packages()
522 static map<string, string> packages;
523 if (packages.empty()) {
524 // We could have a race condition here that two threads
525 // discover an empty map at the same time and want to fill
526 // it, but that is no problem, since the same contents is
527 // filled in twice then. Having the locker inside the
528 // packages.empty() condition has the advantage that we
529 // don't need the mutex overhead for simple reading.
531 Mutex::Locker locker(&mutex);
532 // adding a package here implies a file format change!
533 packages["amsmath"] =
534 N_("The LaTeX package amsmath is only used if AMS formula types or symbols from the AMS math toolbars are inserted into formulas");
535 packages["amssymb"] =
536 N_("The LaTeX package amssymb is only used if symbols from the AMS math toolbars are inserted into formulas");
538 N_("The LaTeX package cancel is only used if \\cancel commands are used in formulas");
540 N_("The LaTeX package esint is only used if special integral symbols are inserted into formulas");
541 packages["mathdots"] =
542 N_("The LaTeX package mathdots is only used if the command \\iddots is inserted into formulas");
543 packages["mathtools"] =
544 N_("The LaTeX package mathtools is only used if some mathematical relations are inserted into formulas");
546 N_("The LaTeX package mhchem is only used if either the command \\ce or \\cf is inserted into formulas");
547 packages["stackrel"] =
548 N_("The LaTeX package stackrel is only used if the command \\stackrel with subscript is inserted into formulas");
549 packages["stmaryrd"] =
550 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");
551 packages["undertilde"] =
552 N_("The LaTeX package undertilde is only used if you use the math frame decoration 'utilde'");
558 bool BufferParams::useBibtopic() const
562 return (use_bibtopic || (!multibib.empty() && multibib != "child"));
566 AuthorList & BufferParams::authors()
568 return pimpl_->authorlist;
572 AuthorList const & BufferParams::authors() const
574 return pimpl_->authorlist;
578 void BufferParams::addAuthor(Author const & a)
580 author_map_[a.bufferId()] = pimpl_->authorlist.record(a);
584 BranchList & BufferParams::branchlist()
586 return pimpl_->branchlist;
590 BranchList const & BufferParams::branchlist() const
592 return pimpl_->branchlist;
596 IndicesList & BufferParams::indiceslist()
598 return pimpl_->indiceslist;
602 IndicesList const & BufferParams::indiceslist() const
604 return pimpl_->indiceslist;
608 WordLangTable & BufferParams::spellignore()
610 return pimpl_->spellignore;
614 WordLangTable const & BufferParams::spellignore() const
616 return pimpl_->spellignore;
620 bool BufferParams::spellignored(WordLangTuple const & wl) const
622 bool has_item = false;
623 vector<WordLangTuple> il = spellignore();
624 vector<WordLangTuple>::const_iterator it = il.begin();
625 for (; it != il.end(); ++it) {
626 if (it->lang()->code() != wl.lang()->code())
628 if (it->word() == wl.word()) {
637 Bullet & BufferParams::temp_bullet(lyx::size_type const index)
639 LASSERT(index < 4, return pimpl_->temp_bullets[0]);
640 return pimpl_->temp_bullets[index];
644 Bullet const & BufferParams::temp_bullet(lyx::size_type const index) const
646 LASSERT(index < 4, return pimpl_->temp_bullets[0]);
647 return pimpl_->temp_bullets[index];
651 Bullet & BufferParams::user_defined_bullet(lyx::size_type const index)
653 LASSERT(index < 4, return pimpl_->temp_bullets[0]);
654 return pimpl_->user_defined_bullets[index];
658 Bullet const & BufferParams::user_defined_bullet(lyx::size_type const index) const
660 LASSERT(index < 4, return pimpl_->temp_bullets[0]);
661 return pimpl_->user_defined_bullets[index];
665 Spacing & BufferParams::spacing()
667 return pimpl_->spacing;
671 Spacing const & BufferParams::spacing() const
673 return pimpl_->spacing;
677 PDFOptions & BufferParams::pdfoptions()
679 return pimpl_->pdfoptions;
683 PDFOptions const & BufferParams::pdfoptions() const
685 return pimpl_->pdfoptions;
689 Length const & BufferParams::getMathIndent() const
691 return pimpl_->mathindent;
695 void BufferParams::setMathIndent(Length const & indent)
697 pimpl_->mathindent = indent;
701 Length const & BufferParams::getParIndent() const
703 return pimpl_->parindent;
707 void BufferParams::setParIndent(Length const & indent)
709 pimpl_->parindent = indent;
713 VSpace const & BufferParams::getDefSkip() const
715 return pimpl_->defskip;
719 void BufferParams::setDefSkip(VSpace const & vs)
721 // DEFSKIP will cause an infinite loop
722 LASSERT(vs.kind() != VSpace::DEFSKIP, return);
723 pimpl_->defskip = vs;
727 BufferParams::MathNumber BufferParams::getMathNumber() const
729 if (math_numbering_side != DEFAULT)
730 return math_numbering_side;
731 // FIXME: do not hardcode language here
732 else if (language->lang() == "arabic_arabi"
733 || documentClass().provides("leqno"))
740 string BufferParams::readToken(Lexer & lex, string const & token,
741 FileName const & filename)
744 FileName const & filepath = filename.onlyPath();
746 if (token == "\\textclass") {
748 string const classname = lex.getString();
749 // if there exists a local layout file, ignore the system one
750 // NOTE: in this case, the textclass (.cls file) is assumed to
753 LayoutFileList & bcl = LayoutFileList::get();
754 if (!filepath.empty()) {
755 // If classname is an absolute path, the document is
756 // using a local layout file which could not be accessed
757 // by a relative path. In this case the path is correct
758 // even if the document was moved to a different
759 // location. However, we will have a problem if the
760 // document was generated on a different platform.
761 bool isabsolute = FileName::isAbsolute(classname);
762 string const classpath = onlyPath(classname);
763 string const path = isabsolute ? classpath
764 : FileName(addPath(filepath.absFileName(),
765 classpath)).realPath();
766 string const oldpath = isabsolute ? string()
767 : FileName(addPath(origin, classpath)).realPath();
768 tcp = bcl.addLocalLayout(onlyFileName(classname), path, oldpath);
770 // that returns non-empty if a "local" layout file is found.
772 result = to_utf8(makeRelPath(from_utf8(onlyPath(tcp)),
773 from_utf8(filepath.absFileName())));
776 setBaseClass(onlyFileName(tcp));
778 setBaseClass(onlyFileName(classname));
779 // We assume that a tex class exists for local or unknown
780 // layouts so this warning, will only be given for system layouts.
781 if (!baseClass()->isTeXClassAvailable()) {
782 docstring const desc =
783 translateIfPossible(from_utf8(baseClass()->description()));
784 docstring const prereqs =
785 from_utf8(baseClass()->prerequisites());
786 docstring const msg =
787 bformat(_("The selected document class\n"
789 "requires external files that are not available.\n"
790 "The document class can still be used, but the\n"
791 "document cannot be compiled until the following\n"
792 "prerequisites are installed:\n"
794 "See section 3.1.2.2 (Class Availability) of the\n"
795 "User's Guide for more information."), desc, prereqs);
796 frontend::Alert::warning(_("Document class not available"),
799 } else if (token == "\\save_transient_properties") {
800 lex >> save_transient_properties;
801 } else if (token == "\\origin") {
803 origin = lex.getString();
804 string const sysdirprefix = "/systemlyxdir/";
805 if (prefixIs(origin, sysdirprefix)) {
807 if (inSystemDir(filepath, docsys))
808 origin.replace(0, sysdirprefix.length() - 1, docsys);
810 origin.replace(0, sysdirprefix.length() - 1,
811 package().system_support().absFileName());
813 } else if (token == "\\begin_metadata") {
814 readDocumentMetadata(lex);
815 } else if (token == "\\begin_preamble") {
817 } else if (token == "\\begin_local_layout") {
818 readLocalLayout(lex, false);
819 } else if (token == "\\begin_forced_local_layout") {
820 readLocalLayout(lex, true);
821 } else if (token == "\\begin_modules") {
823 } else if (token == "\\begin_removed_modules") {
824 readRemovedModules(lex);
825 } else if (token == "\\begin_includeonly") {
826 readIncludeonly(lex);
827 } else if (token == "\\maintain_unincluded_children") {
831 maintain_unincluded_children = CM_None;
832 else if (tmp == "mostly")
833 maintain_unincluded_children = CM_Mostly;
834 else if (tmp == "strict")
835 maintain_unincluded_children = CM_Strict;
836 } else if (token == "\\options") {
838 options = lex.getString();
839 } else if (token == "\\use_default_options") {
840 lex >> use_default_options;
841 } else if (token == "\\master") {
843 master = lex.getString();
844 if (!filepath.empty() && FileName::isAbsolute(origin)) {
845 bool const isabs = FileName::isAbsolute(master);
846 FileName const abspath(isabs ? master : origin + master);
847 bool const moved = filepath != FileName(origin);
848 if (moved && abspath.exists()) {
849 docstring const path = isabs
851 : from_utf8(abspath.realPath());
852 docstring const refpath =
853 from_utf8(filepath.absFileName());
854 master = to_utf8(makeRelPath(path, refpath));
857 } else if (token == "\\suppress_date") {
858 lex >> suppress_date;
859 } else if (token == "\\justification") {
860 lex >> justification;
861 } else if (token == "\\language") {
863 } else if (token == "\\language_package") {
865 lang_package = lex.getString();
866 } else if (token == "\\inputencoding") {
868 } else if (token == "\\graphics") {
869 readGraphicsDriver(lex);
870 } else if (token == "\\default_output_format") {
871 lex >> default_output_format;
872 } else if (token == "\\bibtex_command") {
874 bibtex_command = lex.getString();
875 } else if (token == "\\index_command") {
877 index_command = lex.getString();
878 } else if (token == "\\fontencoding") {
880 fontenc = lex.getString();
881 } else if (token == "\\font_roman") {
882 lex >> fonts_roman[0];
883 lex >> fonts_roman[1];
884 } else if (token == "\\font_sans") {
885 lex >> fonts_sans[0];
886 lex >> fonts_sans[1];
887 } else if (token == "\\font_typewriter") {
888 lex >> fonts_typewriter[0];
889 lex >> fonts_typewriter[1];
890 } else if (token == "\\font_math") {
891 lex >> fonts_math[0];
892 lex >> fonts_math[1];
893 } else if (token == "\\font_default_family") {
894 lex >> fonts_default_family;
895 } else if (token == "\\use_non_tex_fonts") {
896 lex >> useNonTeXFonts;
897 } else if (token == "\\font_sc") {
898 lex >> fonts_expert_sc;
899 } else if (token == "\\font_roman_osf") {
900 lex >> fonts_roman_osf;
901 } else if (token == "\\font_sans_osf") {
902 lex >> fonts_sans_osf;
903 } else if (token == "\\font_typewriter_osf") {
904 lex >> fonts_typewriter_osf;
905 } else if (token == "\\font_roman_opts") {
906 lex >> font_roman_opts;
907 } else if (token == "\\font_sf_scale") {
908 lex >> fonts_sans_scale[0];
909 lex >> fonts_sans_scale[1];
910 } else if (token == "\\font_sans_opts") {
911 lex >> font_sans_opts;
912 } else if (token == "\\font_tt_scale") {
913 lex >> fonts_typewriter_scale[0];
914 lex >> fonts_typewriter_scale[1];
915 } else if (token == "\\font_typewriter_opts") {
916 lex >> font_typewriter_opts;
917 } else if (token == "\\font_cjk") {
919 } else if (token == "\\use_microtype") {
920 lex >> use_microtype;
921 } else if (token == "\\use_dash_ligatures") {
922 lex >> use_dash_ligatures;
923 } else if (token == "\\paragraph_separation") {
926 paragraph_separation = parseptranslator().find(parsep);
927 } else if (token == "\\paragraph_indentation") {
929 string parindent = lex.getString();
930 if (parindent == "default")
931 pimpl_->parindent = Length();
933 pimpl_->parindent = Length(parindent);
934 } else if (token == "\\defskip") {
936 string const defskip = lex.getString();
937 pimpl_->defskip = VSpace(defskip);
938 if (pimpl_->defskip.kind() == VSpace::DEFSKIP)
940 pimpl_->defskip = VSpace(VSpace::MEDSKIP);
941 } else if (token == "\\is_math_indent") {
942 lex >> is_math_indent;
943 } else if (token == "\\math_indentation") {
945 string mathindent = lex.getString();
946 if (mathindent == "default")
947 pimpl_->mathindent = Length();
949 pimpl_->mathindent = Length(mathindent);
950 } else if (token == "\\math_numbering_side") {
954 math_numbering_side = LEFT;
955 else if (tmp == "right")
956 math_numbering_side = RIGHT;
958 math_numbering_side = DEFAULT;
959 } else if (token == "\\quotes_style") {
962 quotes_style = quotesstyletranslator().find(qstyle);
963 } else if (token == "\\dynamic_quotes") {
964 lex >> dynamic_quotes;
965 } else if (token == "\\papersize") {
968 papersize = papersizetranslator().find(ppsize);
969 } else if (token == "\\use_geometry") {
971 } else if (token == "\\use_package") {
976 use_package(package, packagetranslator().find(use));
977 } else if (token == "\\cite_engine") {
979 cite_engine_ = lex.getString();
980 } else if (token == "\\cite_engine_type") {
983 cite_engine_type_ = theCiteEnginesList.getType(engine_type);
984 } else if (token == "\\biblio_style") {
986 biblio_style = lex.getString();
987 } else if (token == "\\biblio_options") {
989 biblio_opts = trim(lex.getString());
990 } else if (token == "\\biblatex_bibstyle") {
992 biblatex_bibstyle = trim(lex.getString());
993 } else if (token == "\\biblatex_citestyle") {
995 biblatex_citestyle = trim(lex.getString());
996 } else if (token == "\\use_bibtopic") {
998 } else if (token == "\\multibib") {
1000 } else if (token == "\\use_indices") {
1002 } else if (token == "\\tracking_changes") {
1003 lex >> track_changes;
1004 } else if (token == "\\output_changes") {
1005 lex >> output_changes;
1006 } else if (token == "\\change_bars") {
1008 } else if (token == "\\postpone_fragile_content") {
1009 lex >> postpone_fragile_content;
1010 } else if (token == "\\branch") {
1012 docstring branch = lex.getDocString();
1013 branchlist().add(branch);
1016 string const tok = lex.getString();
1017 if (tok == "\\end_branch")
1019 Branch * branch_ptr = branchlist().find(branch);
1020 if (tok == "\\selected") {
1023 branch_ptr->setSelected(lex.getInteger());
1025 if (tok == "\\filename_suffix") {
1028 branch_ptr->setFileNameSuffix(lex.getInteger());
1030 if (tok == "\\color") {
1032 vector<string> const colors = getVectorFromString(lex.getString(), " ");
1033 string const lmcolor = colors.front();
1035 if (colors.size() > 1)
1036 dmcolor = colors.back();
1038 branch_ptr->setColors(lmcolor, dmcolor);
1041 } else if (token == "\\index") {
1043 docstring index = lex.getDocString();
1045 indiceslist().add(index);
1048 string const tok = lex.getString();
1049 if (tok == "\\end_index")
1051 Index * index_ptr = indiceslist().find(index);
1052 if (tok == "\\shortcut") {
1054 shortcut = lex.getDocString();
1056 index_ptr->setShortcut(shortcut);
1058 if (tok == "\\color") {
1060 string color = lex.getString();
1062 index_ptr->setColor(color);
1063 // Update also the Color table:
1064 if (color == "none")
1065 color = lcolor.getX11HexName(Color_background);
1067 if (!shortcut.empty())
1068 lcolor.setColor(to_utf8(shortcut)+ "@" + filename.absFileName(), color);
1071 } else if (token == "\\spellchecker_ignore") {
1073 docstring wl = lex.getDocString();
1075 docstring word = split(wl, language, ' ');
1076 Language const * lang = languages.getLanguage(to_ascii(language));
1078 spellignore().push_back(WordLangTuple(word, lang));
1079 } else if (token == "\\author") {
1081 istringstream ss(lex.getString());
1085 } else if (token == "\\paperorientation") {
1088 orientation = paperorientationtranslator().find(orient);
1089 } else if (token == "\\backgroundcolor") {
1091 backgroundcolor = lyx::rgbFromHexName(lex.getString());
1092 isbackgroundcolor = true;
1093 } else if (token == "\\fontcolor") {
1095 fontcolor = lyx::rgbFromHexName(lex.getString());
1097 } else if (token == "\\notefontcolor") {
1099 string color = lex.getString();
1100 notefontcolor = lyx::rgbFromHexName(color);
1101 lcolor.setColor("notefontcolor", color);
1102 lcolor.setLaTeXName("notefontcolor", "note_fontcolor");
1103 lcolor.setGUIName("notefontcolor", N_("greyedout inset text"));
1104 // set a local name for the painter
1105 lcolor.setColor("notefontcolor@" + filename.absFileName(), color);
1106 isnotefontcolor = true;
1107 } else if (token == "\\boxbgcolor") {
1109 string color = lex.getString();
1110 boxbgcolor = lyx::rgbFromHexName(color);
1111 lcolor.setColor("boxbgcolor@" + filename.absFileName(), color);
1112 isboxbgcolor = true;
1113 } else if (token == "\\paperwidth") {
1115 } else if (token == "\\paperheight") {
1117 } else if (token == "\\leftmargin") {
1119 } else if (token == "\\topmargin") {
1121 } else if (token == "\\rightmargin") {
1123 } else if (token == "\\bottommargin") {
1124 lex >> bottommargin;
1125 } else if (token == "\\headheight") {
1127 } else if (token == "\\headsep") {
1129 } else if (token == "\\footskip") {
1131 } else if (token == "\\columnsep") {
1133 } else if (token == "\\paperfontsize") {
1135 } else if (token == "\\papercolumns") {
1137 } else if (token == "\\listings_params") {
1140 listings_params = InsetListingsParams(par).params();
1141 } else if (token == "\\papersides") {
1144 sides = sidestranslator().find(psides);
1145 } else if (token == "\\paperpagestyle") {
1147 } else if (token == "\\tablestyle") {
1149 } else if (token == "\\bullet") {
1151 } else if (token == "\\bulletLaTeX") {
1152 readBulletsLaTeX(lex);
1153 } else if (token == "\\secnumdepth") {
1155 } else if (token == "\\tocdepth") {
1157 } else if (token == "\\spacing") {
1161 if (nspacing == "other") {
1164 spacing().set(spacetranslator().find(nspacing), tmp_val);
1165 } else if (token == "\\float_placement") {
1166 lex >> float_placement;
1167 } else if (token == "\\float_alignment") {
1168 lex >> float_alignment;
1170 } else if (prefixIs(token, "\\pdf_") || token == "\\use_hyperref") {
1171 string toktmp = pdfoptions().readToken(lex, token);
1172 if (!toktmp.empty()) {
1173 lyxerr << "PDFOptions::readToken(): Unknown token: " <<
1177 } else if (token == "\\html_math_output") {
1180 html_math_output = static_cast<MathOutput>(temp);
1181 } else if (token == "\\html_be_strict") {
1182 lex >> html_be_strict;
1183 } else if (token == "\\html_css_as_file") {
1184 lex >> html_css_as_file;
1185 } else if (token == "\\html_math_img_scale") {
1186 lex >> html_math_img_scale;
1187 } else if (token == "\\html_latex_start") {
1189 html_latex_start = lex.getString();
1190 } else if (token == "\\html_latex_end") {
1192 html_latex_end = lex.getString();
1193 } else if (token == "\\docbook_table_output") {
1196 docbook_table_output = static_cast<TableOutput>(temp);
1197 } else if (token == "\\docbook_mathml_prefix") {
1200 docbook_mathml_prefix = static_cast<MathMLNameSpacePrefix>(temp);
1201 } else if (token == "\\output_sync") {
1203 } else if (token == "\\output_sync_macro") {
1204 lex >> output_sync_macro;
1205 } else if (token == "\\use_refstyle") {
1206 lex >> use_refstyle;
1207 } else if (token == "\\use_minted") {
1209 } else if (token == "\\use_lineno") {
1211 } else if (token == "\\lineno_options") {
1213 lineno_opts = trim(lex.getString());
1215 lyxerr << "BufferParams::readToken(): Unknown token: " <<
1225 // Quote argument if it contains spaces
1226 string quoteIfNeeded(string const & str) {
1227 if (contains(str, ' '))
1228 return "\"" + str + "\"";
1234 void BufferParams::writeFile(ostream & os, Buffer const * buf) const
1236 // The top of the file is written by the buffer.
1237 // Prints out the buffer info into the .lyx file given by file
1239 os << "\\save_transient_properties "
1240 << convert<string>(save_transient_properties) << '\n';
1242 // the document directory (must end with a path separator)
1243 // realPath() is used to resolve symlinks, while addPath(..., "")
1244 // ensures a trailing path separator.
1246 string filepath = addPath(buf->fileName().onlyPath().realPath(), "");
1247 string const sysdir = inSystemDir(FileName(filepath), docsys) ? docsys
1248 : addPath(package().system_support().realPath(), "");
1249 string const relpath =
1250 to_utf8(makeRelPath(from_utf8(filepath), from_utf8(sysdir)));
1251 if (!prefixIs(relpath, "../") && !FileName::isAbsolute(relpath))
1252 filepath = addPath("/systemlyxdir", relpath);
1253 else if (!save_transient_properties || !lyxrc.save_origin)
1254 filepath = "unavailable";
1255 os << "\\origin " << quoteIfNeeded(filepath) << '\n';
1258 os << "\\textclass "
1259 << quoteIfNeeded(buf->includedFilePath(addName(buf->layoutPos(),
1260 baseClass()->name()), "layout"))
1263 // then document metadata
1264 if (!document_metadata.empty()) {
1265 // remove '\n' from the end of document_metadata
1266 docstring const tmpmd = rtrim(document_metadata, "\n");
1267 os << "\\begin_metadata\n"
1269 << "\n\\end_metadata\n";
1272 // then the preamble
1273 if (!preamble.empty()) {
1274 // remove '\n' from the end of preamble
1275 docstring const tmppreamble = rtrim(preamble, "\n");
1276 os << "\\begin_preamble\n"
1277 << to_utf8(tmppreamble)
1278 << "\n\\end_preamble\n";
1282 if (!options.empty()) {
1283 os << "\\options " << options << '\n';
1286 // use the class options defined in the layout?
1287 os << "\\use_default_options "
1288 << convert<string>(use_default_options) << "\n";
1290 // the master document
1291 if (!master.empty()) {
1292 os << "\\master " << master << '\n';
1296 if (!removed_modules_.empty()) {
1297 os << "\\begin_removed_modules" << '\n';
1298 for (auto const & mod : removed_modules_)
1300 os << "\\end_removed_modules" << '\n';
1304 if (!layout_modules_.empty()) {
1305 os << "\\begin_modules" << '\n';
1306 for (auto const & mod : layout_modules_)
1308 os << "\\end_modules" << '\n';
1312 if (!included_children_.empty()) {
1313 os << "\\begin_includeonly" << '\n';
1314 for (auto const & c : included_children_)
1316 os << "\\end_includeonly" << '\n';
1319 switch (maintain_unincluded_children) {
1330 os << "\\maintain_unincluded_children " << muc << '\n';
1332 // local layout information
1333 docstring const local_layout = getLocalLayout(false);
1334 if (!local_layout.empty()) {
1335 // remove '\n' from the end
1336 docstring const tmplocal = rtrim(local_layout, "\n");
1337 os << "\\begin_local_layout\n"
1338 << to_utf8(tmplocal)
1339 << "\n\\end_local_layout\n";
1341 docstring const forced_local_layout = getLocalLayout(true);
1342 if (!forced_local_layout.empty()) {
1343 // remove '\n' from the end
1344 docstring const tmplocal = rtrim(forced_local_layout, "\n");
1345 os << "\\begin_forced_local_layout\n"
1346 << to_utf8(tmplocal)
1347 << "\n\\end_forced_local_layout\n";
1350 // then the text parameters
1351 if (language != ignore_language)
1352 os << "\\language " << language->lang() << '\n';
1353 os << "\\language_package " << lang_package
1354 << "\n\\inputencoding " << inputenc
1355 << "\n\\fontencoding " << fontenc
1356 << "\n\\font_roman \"" << fonts_roman[0]
1357 << "\" \"" << fonts_roman[1] << '"'
1358 << "\n\\font_sans \"" << fonts_sans[0]
1359 << "\" \"" << fonts_sans[1] << '"'
1360 << "\n\\font_typewriter \"" << fonts_typewriter[0]
1361 << "\" \"" << fonts_typewriter[1] << '"'
1362 << "\n\\font_math \"" << fonts_math[0]
1363 << "\" \"" << fonts_math[1] << '"'
1364 << "\n\\font_default_family " << fonts_default_family
1365 << "\n\\use_non_tex_fonts " << convert<string>(useNonTeXFonts)
1366 << "\n\\font_sc " << convert<string>(fonts_expert_sc)
1367 << "\n\\font_roman_osf " << convert<string>(fonts_roman_osf)
1368 << "\n\\font_sans_osf " << convert<string>(fonts_sans_osf)
1369 << "\n\\font_typewriter_osf " << convert<string>(fonts_typewriter_osf);
1370 if (!font_roman_opts.empty())
1371 os << "\n\\font_roman_opts \"" << font_roman_opts << "\"";
1372 os << "\n\\font_sf_scale " << fonts_sans_scale[0]
1373 << ' ' << fonts_sans_scale[1];
1374 if (!font_sans_opts.empty())
1375 os << "\n\\font_sans_opts \"" << font_sans_opts << "\"";
1376 os << "\n\\font_tt_scale " << fonts_typewriter_scale[0]
1377 << ' ' << fonts_typewriter_scale[1];
1378 if (!font_typewriter_opts.empty())
1379 os << "\n\\font_typewriter_opts \"" << font_typewriter_opts << "\"";
1381 if (!fonts_cjk.empty())
1382 os << "\\font_cjk " << fonts_cjk << '\n';
1383 os << "\\use_microtype " << convert<string>(use_microtype) << '\n';
1384 os << "\\use_dash_ligatures " << convert<string>(use_dash_ligatures) << '\n';
1385 os << "\\graphics " << graphics_driver << '\n';
1386 os << "\\default_output_format " << default_output_format << '\n';
1387 os << "\\output_sync " << output_sync << '\n';
1388 if (!output_sync_macro.empty())
1389 os << "\\output_sync_macro \"" << output_sync_macro << "\"\n";
1390 os << "\\bibtex_command " << bibtex_command << '\n';
1391 os << "\\index_command " << index_command << '\n';
1393 if (!float_placement.empty())
1394 os << "\\float_placement " << float_placement << '\n';
1395 if (!float_alignment.empty())
1396 os << "\\float_alignment " << float_alignment << '\n';
1397 os << "\\paperfontsize " << fontsize << '\n';
1399 spacing().writeFile(os);
1400 pdfoptions().writeFile(os);
1402 os << "\\papersize " << string_papersize[papersize]
1403 << "\n\\use_geometry " << convert<string>(use_geometry);
1404 map<string, string> const & packages = auto_packages();
1405 for (auto const & pack : packages)
1406 os << "\n\\use_package " << pack.first << ' '
1407 << use_package(pack.first);
1409 os << "\n\\cite_engine ";
1411 if (!cite_engine_.empty())
1416 os << "\n\\cite_engine_type " << theCiteEnginesList.getTypeAsString(cite_engine_type_);
1418 if (!biblio_style.empty())
1419 os << "\n\\biblio_style " << biblio_style;
1420 if (!biblio_opts.empty())
1421 os << "\n\\biblio_options " << biblio_opts;
1422 if (!biblatex_bibstyle.empty())
1423 os << "\n\\biblatex_bibstyle " << biblatex_bibstyle;
1424 if (!biblatex_citestyle.empty())
1425 os << "\n\\biblatex_citestyle " << biblatex_citestyle;
1426 if (!multibib.empty())
1427 os << "\n\\multibib " << multibib;
1429 os << "\n\\use_bibtopic " << convert<string>(use_bibtopic)
1430 << "\n\\use_indices " << convert<string>(use_indices)
1431 << "\n\\paperorientation " << string_orientation[orientation]
1432 << "\n\\suppress_date " << convert<string>(suppress_date)
1433 << "\n\\justification " << convert<string>(justification)
1434 << "\n\\use_refstyle " << use_refstyle
1435 << "\n\\use_minted " << use_minted
1436 << "\n\\use_lineno " << use_lineno
1439 if (!lineno_opts.empty())
1440 os << "\\lineno_options " << lineno_opts << '\n';
1442 if (isbackgroundcolor)
1443 os << "\\backgroundcolor " << lyx::X11hexname(backgroundcolor) << '\n';
1445 os << "\\fontcolor " << lyx::X11hexname(fontcolor) << '\n';
1446 if (isnotefontcolor)
1447 os << "\\notefontcolor " << lyx::X11hexname(notefontcolor) << '\n';
1449 os << "\\boxbgcolor " << lyx::X11hexname(boxbgcolor) << '\n';
1451 for (auto const & br : branchlist()) {
1452 os << "\\branch " << to_utf8(br.branch())
1453 << "\n\\selected " << br.isSelected()
1454 << "\n\\filename_suffix " << br.hasFileNameSuffix()
1455 << "\n\\color " << br.lightModeColor() << " " << br.darkModeColor()
1460 for (auto const & id : indiceslist()) {
1461 os << "\\index " << to_utf8(id.index())
1462 << "\n\\shortcut " << to_utf8(id.shortcut())
1463 << "\n\\color " << lyx::X11hexname(id.color())
1468 for (auto const & si : spellignore()) {
1469 os << "\\spellchecker_ignore " << si.lang()->lang()
1470 << " " << to_utf8(si.word())
1474 if (!paperwidth.empty())
1475 os << "\\paperwidth "
1476 << VSpace(paperwidth).asLyXCommand() << '\n';
1477 if (!paperheight.empty())
1478 os << "\\paperheight "
1479 << VSpace(paperheight).asLyXCommand() << '\n';
1480 if (!leftmargin.empty())
1481 os << "\\leftmargin "
1482 << VSpace(leftmargin).asLyXCommand() << '\n';
1483 if (!topmargin.empty())
1484 os << "\\topmargin "
1485 << VSpace(topmargin).asLyXCommand() << '\n';
1486 if (!rightmargin.empty())
1487 os << "\\rightmargin "
1488 << VSpace(rightmargin).asLyXCommand() << '\n';
1489 if (!bottommargin.empty())
1490 os << "\\bottommargin "
1491 << VSpace(bottommargin).asLyXCommand() << '\n';
1492 if (!headheight.empty())
1493 os << "\\headheight "
1494 << VSpace(headheight).asLyXCommand() << '\n';
1495 if (!headsep.empty())
1497 << VSpace(headsep).asLyXCommand() << '\n';
1498 if (!footskip.empty())
1500 << VSpace(footskip).asLyXCommand() << '\n';
1501 if (!columnsep.empty())
1502 os << "\\columnsep "
1503 << VSpace(columnsep).asLyXCommand() << '\n';
1504 os << "\\secnumdepth " << secnumdepth
1505 << "\n\\tocdepth " << tocdepth
1506 << "\n\\paragraph_separation "
1507 << string_paragraph_separation[paragraph_separation];
1508 if (!paragraph_separation)
1509 os << "\n\\paragraph_indentation "
1510 << (getParIndent().empty() ? "default" : getParIndent().asString());
1512 os << "\n\\defskip " << getDefSkip().asLyXCommand();
1513 os << "\n\\is_math_indent " << is_math_indent;
1515 os << "\n\\math_indentation "
1516 << (getMathIndent().empty() ? "default" : getMathIndent().asString());
1517 os << "\n\\math_numbering_side ";
1518 switch(math_numbering_side) {
1528 os << "\n\\quotes_style "
1529 << string_quotes_style[static_cast<int>(quotes_style)]
1530 << "\n\\dynamic_quotes " << dynamic_quotes
1531 << "\n\\papercolumns " << columns
1532 << "\n\\papersides " << sides
1533 << "\n\\paperpagestyle " << pagestyle
1534 << "\n\\tablestyle " << tablestyle << '\n';
1535 if (!listings_params.empty())
1536 os << "\\listings_params \"" <<
1537 InsetListingsParams(listings_params).encodedString() << "\"\n";
1538 for (int i = 0; i < 4; ++i) {
1539 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
1540 if (user_defined_bullet(i).getFont() != -1) {
1541 os << "\\bullet " << i << " "
1542 << user_defined_bullet(i).getFont() << " "
1543 << user_defined_bullet(i).getCharacter() << " "
1544 << user_defined_bullet(i).getSize() << "\n";
1548 os << "\\bulletLaTeX " << i << " \""
1549 << lyx::to_ascii(user_defined_bullet(i).getText())
1555 os << "\\tracking_changes "
1556 << (save_transient_properties ? convert<string>(track_changes) : "false")
1559 os << "\\output_changes "
1560 << (save_transient_properties ? convert<string>(output_changes) : "false")
1563 os << "\\change_bars "
1564 << (save_transient_properties ? convert<string>(change_bars) : "false")
1567 os << "\\postpone_fragile_content " << convert<string>(postpone_fragile_content) << '\n';
1569 os << "\\html_math_output " << html_math_output << '\n'
1570 << "\\html_css_as_file " << html_css_as_file << '\n'
1571 << "\\html_be_strict " << convert<string>(html_be_strict) << '\n';
1573 os << "\\docbook_table_output " << docbook_table_output << '\n';
1574 os << "\\docbook_mathml_prefix " << docbook_mathml_prefix << '\n';
1576 if (html_math_img_scale != 1.0)
1577 os << "\\html_math_img_scale " << convert<string>(html_math_img_scale) << '\n';
1578 if (!html_latex_start.empty())
1579 os << "\\html_latex_start " << html_latex_start << '\n';
1580 if (!html_latex_end.empty())
1581 os << "\\html_latex_end " << html_latex_end << '\n';
1583 os << pimpl_->authorlist;
1587 void BufferParams::validate(LaTeXFeatures & features) const
1589 features.require(documentClass().required());
1591 if (columns > 1 && language->rightToLeft())
1592 features.require("rtloutputdblcol");
1594 if (output_changes) {
1595 bool xcolorulem = LaTeXFeatures::isAvailable("ulem") &&
1596 LaTeXFeatures::isAvailable("xcolor");
1598 switch (features.runparams().flavor) {
1600 case Flavor::DviLuaTeX:
1602 features.require("ct-xcolor-ulem");
1603 features.require("ulem");
1604 features.require("xcolor");
1606 features.require("ct-none");
1609 case Flavor::LuaTeX:
1610 case Flavor::PdfLaTeX:
1613 features.require("ct-xcolor-ulem");
1614 features.require("ulem");
1615 features.require("xcolor");
1616 // improves color handling in PDF output
1617 features.require("pdfcolmk");
1619 features.require("ct-none");
1626 features.require("changebar");
1629 // Floats with 'Here definitely' as default setting.
1630 if (float_placement.find('H') != string::npos)
1631 features.require("float");
1633 for (auto const & pm : use_packages) {
1634 if (pm.first == "amsmath") {
1635 // AMS Style is at document level
1636 if (pm.second == package_on ||
1637 features.isProvided("amsmath"))
1638 features.require(pm.first);
1639 } else if (pm.second == package_on)
1640 features.require(pm.first);
1643 // Document-level line spacing
1644 if (spacing().getSpace() != Spacing::Single && !spacing().isDefault())
1645 features.require("setspace");
1647 // the bullet shapes are buffer level not paragraph level
1648 // so they are tested here
1649 for (int i = 0; i < 4; ++i) {
1650 if (user_defined_bullet(i) == ITEMIZE_DEFAULTS[i])
1652 int const font = user_defined_bullet(i).getFont();
1654 int const c = user_defined_bullet(i).getCharacter();
1660 features.require("latexsym");
1662 } else if (font == 1) {
1663 features.require("amssymb");
1664 } else if (font >= 2 && font <= 5) {
1665 features.require("pifont");
1669 if (pdfoptions().use_hyperref) {
1670 features.require("hyperref");
1671 // due to interferences with babel and hyperref, the color package has to
1672 // be loaded after hyperref when hyperref is used with the colorlinks
1673 // option, see http://www.lyx.org/trac/ticket/5291
1674 if (pdfoptions().colorlinks)
1675 features.require("color");
1677 if (!listings_params.empty()) {
1678 // do not test validity because listings_params is
1679 // supposed to be valid
1681 InsetListingsParams(listings_params).separatedParams(true);
1682 // we can't support all packages, but we should load the color package
1683 if (par.find("\\color", 0) != string::npos)
1684 features.require("color");
1687 // some languages are only available via polyglossia
1688 if (features.hasPolyglossiaExclusiveLanguages())
1689 features.require("polyglossia");
1691 if (useNonTeXFonts && fontsMath() != "auto")
1692 features.require("unicode-math");
1695 features.require("microtype");
1697 if (!language->required().empty())
1698 features.require(language->required());
1702 bool BufferParams::writeLaTeX(otexstream & os, LaTeXFeatures & features,
1703 FileName const & filepath) const
1705 // DocumentMetadata must come before anything else
1706 if (features.isAvailableAtLeastFrom("LaTeX", 2022, 6)
1707 && !containsOnly(document_metadata, " \n\t")) {
1708 // Check if the user preamble contains uncodable glyphs
1709 odocstringstream doc_metadata;
1710 docstring uncodable_glyphs;
1711 Encoding const * const enc = features.runparams().encoding;
1713 for (char_type c : document_metadata) {
1714 if (!enc->encodable(c)) {
1715 docstring const glyph(1, c);
1716 LYXERR0("Uncodable character '"
1718 << "' in document metadata!");
1719 uncodable_glyphs += glyph;
1720 if (features.runparams().dryrun) {
1721 doc_metadata << "<" << _("LyX Warning: ")
1722 << _("uncodable character") << " '";
1723 doc_metadata.put(c);
1724 doc_metadata << "'>";
1727 doc_metadata.put(c);
1730 doc_metadata << document_metadata;
1732 // On BUFFER_VIEW|UPDATE, warn user if we found uncodable glyphs
1733 if (!features.runparams().dryrun && !uncodable_glyphs.empty()) {
1734 frontend::Alert::warning(
1735 _("Uncodable character in document metadata"),
1737 _("The metadata of your document contains glyphs "
1738 "that are unknown in the current document encoding "
1739 "(namely %1$s).\nThese glyphs are omitted "
1740 " from the output, which may result in "
1741 "incomplete output."
1742 "\n\nPlease select an appropriate "
1743 "document encoding\n"
1744 "(such as utf8) or change the "
1745 "metadata accordingly."),
1748 if (!doc_metadata.str().empty()) {
1749 os << "\\DocumentMetadata{\n"
1750 << doc_metadata.str()
1755 // http://www.tug.org/texmf-dist/doc/latex/base/fixltx2e.pdf
1756 // !! To use the Fix-cm package, load it before \documentclass, and use the command
1757 // \RequirePackage to do so, rather than the normal \usepackage
1758 // Do not try to load any other package before the document class, unless you
1759 // have a thorough understanding of the LATEX internals and know exactly what you
1761 if (features.mustProvide("fix-cm"))
1762 os << "\\RequirePackage{fix-cm}\n";
1763 // Likewise for fixltx2e. If other packages conflict with this policy,
1764 // treat it as a package bug (and report it!)
1765 // See http://www.latex-project.org/cgi-bin/ltxbugs2html?pr=latex/4407
1766 if (features.mustProvide("fixltx2e"))
1767 os << "\\RequirePackage{fixltx2e}\n";
1769 os << "\\documentclass";
1771 DocumentClass const & tclass = documentClass();
1773 ostringstream clsoptions; // the document class options.
1775 if (tokenPos(tclass.opt_fontsize(),
1776 '|', fontsize) >= 0) {
1777 // only write if existing in list (and not default)
1778 clsoptions << subst(tclass.fontsizeformat(), "$$s", fontsize) << ",";
1781 // paper sizes not supported by the class itself need the
1783 vector<string> classpsizes = getVectorFromString(tclass.opt_pagesize(), "|");
1784 bool class_supported_papersize = papersize == PAPER_DEFAULT
1785 || find(classpsizes.begin(), classpsizes.end(), string_papersize[papersize]) != classpsizes.end();
1787 if ((!use_geometry || features.isProvided("geometry-light"))
1788 && class_supported_papersize && papersize != PAPER_DEFAULT)
1789 clsoptions << subst(tclass.pagesizeformat(), "$$s", string_papersize[papersize]) << ",";
1792 if (sides != tclass.sides()) {
1795 clsoptions << "oneside,";
1798 clsoptions << "twoside,";
1804 if (columns != tclass.columns()) {
1806 clsoptions << "twocolumn,";
1808 clsoptions << "onecolumn,";
1812 && orientation == ORIENTATION_LANDSCAPE)
1813 clsoptions << "landscape,";
1816 clsoptions << "fleqn,";
1818 switch(math_numbering_side) {
1820 clsoptions << "leqno,";
1823 clsoptions << "reqno,";
1824 features.require("amsmath");
1830 // language should be a parameter to \documentclass
1831 if (language->babel() == "hebrew"
1832 && default_language->babel() != "hebrew")
1833 // This seems necessary
1834 features.useLanguage(default_language);
1836 ostringstream language_options;
1837 bool const use_babel = features.useBabel() && !features.isProvided("babel");
1838 bool const use_polyglossia = features.usePolyglossia();
1839 bool const global = lyxrc.language_global_options;
1840 if (features.useBabel() || (use_polyglossia && global)) {
1841 language_options << features.getBabelLanguages();
1842 if (!language->babel().empty()) {
1843 if (!language_options.str().empty())
1844 language_options << ',';
1845 language_options << language->babel();
1847 if (global && !language_options.str().empty())
1848 clsoptions << language_options.str() << ',';
1851 // the predefined options from the layout
1852 if (use_default_options && !tclass.options().empty())
1853 clsoptions << tclass.options() << ',';
1855 // the user-defined options
1856 if (!options.empty()) {
1857 clsoptions << options << ',';
1860 docstring const strOptions = from_utf8(clsoptions.str());
1861 if (!strOptions.empty()) {
1862 // Check if class options contain uncodable glyphs
1863 docstring uncodable_glyphs;
1864 docstring options_encodable;
1865 Encoding const * const enc = features.runparams().encoding;
1867 for (char_type c : strOptions) {
1868 if (!enc->encodable(c)) {
1869 docstring const glyph(1, c);
1870 LYXERR0("Uncodable character '"
1872 << "' in class options!");
1873 uncodable_glyphs += glyph;
1874 if (features.runparams().dryrun) {
1875 options_encodable += "<" + _("LyX Warning: ")
1876 + _("uncodable character") + " '";
1877 options_encodable += c;
1878 options_encodable += "'>";
1881 options_encodable += c;
1884 options_encodable = strOptions;
1886 // On BUFFER_VIEW|UPDATE, warn user if we found uncodable glyphs
1887 if (!features.runparams().dryrun && !uncodable_glyphs.empty()) {
1888 frontend::Alert::warning(
1889 _("Uncodable character in class options"),
1891 _("The class options of your document contain glyphs "
1892 "that are unknown in the current document encoding "
1893 "(namely %1$s).\nThese glyphs are omitted "
1894 " from the output, which may result in "
1895 "incomplete output."
1896 "\n\nPlease select an appropriate "
1897 "document encoding\n"
1898 "(such as utf8) or change the "
1899 "class options accordingly."),
1902 options_encodable = rtrim(options_encodable, ",");
1903 os << '[' << options_encodable << ']';
1906 os << '{' << from_ascii(tclass.latexname()) << "}\n";
1907 // end of \documentclass defs
1909 // The package options (via \PassOptionsToPackage)
1910 os << from_ascii(features.getPackageOptions());
1912 // if we use fontspec or newtxmath, we have to load the AMS packages here
1913 string const ams = features.loadAMSPackages();
1914 string const main_font_enc = features.runparams().main_fontenc;
1915 bool const ot1 = (main_font_enc == "default" || main_font_enc == "OT1");
1916 bool const use_newtxmath =
1917 theLaTeXFonts().getLaTeXFont(from_ascii(fontsMath())).getUsedPackage(
1918 ot1, false, false) == "newtxmath";
1919 if ((useNonTeXFonts || use_newtxmath) && !ams.empty())
1920 os << from_ascii(ams);
1922 if (useNonTeXFonts) {
1923 // Babel (as of 2017/11/03) loads fontspec itself
1924 // However, it does so only if a non-default font is requested via \babelfont
1925 // Thus load fontspec if this is not the case and we need fontspec features
1926 bool const babel_needfontspec =
1927 !features.isAvailableAtLeastFrom("babel", 2017, 11, 3)
1928 || (fontsRoman() == "default"
1929 && fontsSans() == "default"
1930 && fontsTypewriter() == "default"
1931 // these need fontspec features
1932 && (features.isRequired("textquotesinglep")
1933 || features.isRequired("textquotedblp")));
1934 if (!features.isProvided("fontspec")
1935 && (!features.useBabel() || babel_needfontspec))
1936 os << "\\usepackage{fontspec}\n";
1937 if (features.mustProvide("unicode-math")
1938 && features.isAvailable("unicode-math"))
1939 os << "\\usepackage{unicode-math}\n";
1942 // load CJK support package before font selection
1943 // (see autotests/export/latex/CJK/micro-sign_utf8-cjk-libertine.lyx)
1944 if (!useNonTeXFonts && encoding().package() != Encoding::none && inputenc != "utf8x"
1945 && (encoding().package() == Encoding::CJK || features.mustProvide("CJK"))) {
1946 if (inputenc == "utf8-cjk" || inputenc == "utf8")
1947 os << "\\usepackage{CJKutf8}\n";
1949 os << "\\usepackage[encapsulated]{CJK}\n";
1952 // font selection must be done before loading fontenc.sty
1953 // but after babel with non-TeX fonts
1954 string const fonts = loadFonts(features);
1955 if (!fonts.empty() && (!features.useBabel() || !useNonTeXFonts))
1956 os << from_utf8(fonts);
1958 if (fonts_default_family != "default")
1959 os << "\\renewcommand{\\familydefault}{\\"
1960 << from_ascii(fonts_default_family) << "}\n";
1962 // set font encoding
1963 // non-TeX fonts use font encoding TU (set by fontspec)
1964 if (!useNonTeXFonts && !features.isProvided("fontenc")
1965 && main_font_enc != "default") {
1966 // get main font encodings
1967 vector<string> fontencs = font_encodings();
1968 // get font encodings of secondary languages
1969 // FIXME: some languages (hebrew, ...) assume a standard font encoding as last
1970 // option (for text in other languages).
1971 features.getFontEncodings(fontencs);
1972 if (!fontencs.empty()) {
1973 os << "\\usepackage["
1974 << from_ascii(getStringFromVector(fontencs))
1979 // Load textcomp and pmboxdraw before (lua)inputenc (#11454)
1980 if (features.mustProvide("textcomp"))
1981 os << "\\usepackage{textcomp}\n";
1982 if (features.mustProvide("pmboxdraw"))
1983 os << "\\usepackage{pmboxdraw}\n";
1985 // handle inputenc etc.
1986 // (In documents containing text in Thai language,
1987 // we must load inputenc after babel, see lib/languages).
1988 if (!contains(features.getBabelPostsettings(), from_ascii("thai.ldf")))
1989 writeEncodingPreamble(os, features);
1992 if (!features.runparams().includeall && !included_children_.empty()) {
1993 os << "\\includeonly{";
1995 // we do not use "auto const &" here, because incfile is modified later
1996 // coverity[auto_causes_copy]
1997 for (auto incfile : included_children_) {
1998 FileName inc = makeAbsPath(incfile, filepath.absFileName());
1999 string mangled = DocFileName(changeExtension(inc.absFileName(), ".tex")).
2001 if (!features.runparams().nice)
2003 // \includeonly doesn't want an extension
2004 incfile = changeExtension(incfile, string());
2005 incfile = support::latex_path(incfile);
2006 if (!incfile.empty()) {
2009 os << from_utf8(incfile);
2016 if (!features.isProvided("geometry")
2017 && (use_geometry || !class_supported_papersize)) {
2018 odocstringstream ods;
2019 if (!getGraphicsDriver("geometry").empty())
2020 ods << getGraphicsDriver("geometry");
2021 if (orientation == ORIENTATION_LANDSCAPE)
2022 ods << ",landscape";
2023 switch (papersize) {
2025 if (!paperwidth.empty())
2026 ods << ",paperwidth="
2027 << from_ascii(paperwidth);
2028 if (!paperheight.empty())
2029 ods << ",paperheight="
2030 << from_ascii(paperheight);
2032 case PAPER_USLETTER:
2034 case PAPER_USEXECUTIVE:
2063 ods << "," << from_ascii(string_papersize_geometry[papersize]);
2068 docstring g_options = trim(ods.str(), ",");
2069 os << "\\usepackage";
2070 // geometry-light means that the class works with geometry, but overwrites
2071 // the package options and paper sizes (memoir does this).
2072 // In this case, all options need to go to \geometry
2073 // and the standard paper sizes need to go to the class options.
2074 if (!g_options.empty() && !features.isProvided("geometry-light")) {
2075 os << '[' << g_options << ']';
2078 os << "{geometry}\n";
2079 if (use_geometry || features.isProvided("geometry-light")) {
2080 os << "\\geometry{verbose";
2081 if (!g_options.empty())
2082 // Output general options here with "geometry light".
2083 os << "," << g_options;
2084 // output this only if use_geometry is true
2086 if (!topmargin.empty())
2087 os << ",tmargin=" << from_ascii(Length(topmargin).asLatexString());
2088 if (!bottommargin.empty())
2089 os << ",bmargin=" << from_ascii(Length(bottommargin).asLatexString());
2090 if (!leftmargin.empty())
2091 os << ",lmargin=" << from_ascii(Length(leftmargin).asLatexString());
2092 if (!rightmargin.empty())
2093 os << ",rmargin=" << from_ascii(Length(rightmargin).asLatexString());
2094 if (!headheight.empty())
2095 os << ",headheight=" << from_ascii(Length(headheight).asLatexString());
2096 if (!headsep.empty())
2097 os << ",headsep=" << from_ascii(Length(headsep).asLatexString());
2098 if (!footskip.empty())
2099 os << ",footskip=" << from_ascii(Length(footskip).asLatexString());
2100 if (!columnsep.empty())
2101 os << ",columnsep=" << from_ascii(Length(columnsep).asLatexString());
2105 } else if (orientation == ORIENTATION_LANDSCAPE
2106 || papersize != PAPER_DEFAULT) {
2107 features.require("papersize");
2110 if (tokenPos(tclass.opt_pagestyle(), '|', pagestyle) >= 0) {
2111 if (pagestyle == "fancy")
2112 os << "\\usepackage{fancyhdr}\n";
2113 os << "\\pagestyle{" << from_ascii(pagestyle) << "}\n";
2116 // only output when the background color is not default
2117 if (isbackgroundcolor) {
2118 // only require color here, the background color will be defined
2119 // in LaTeXFeatures.cpp to avoid interferences with the LaTeX
2121 features.require("color");
2122 features.require("pagecolor");
2125 // only output when the font color is not default
2127 // only require color here, the font color will be defined
2128 // in LaTeXFeatures.cpp to avoid interferences with the LaTeX
2130 features.require("color");
2131 features.require("fontcolor");
2134 // Only if class has a ToC hierarchy
2135 if (tclass.hasTocLevels()) {
2136 if (secnumdepth != tclass.secnumdepth()) {
2137 os << "\\setcounter{secnumdepth}{"
2141 if (tocdepth != tclass.tocdepth()) {
2142 os << "\\setcounter{tocdepth}{"
2148 if (paragraph_separation) {
2149 // when skip separation
2151 switch (getDefSkip().kind()) {
2152 case VSpace::SMALLSKIP:
2153 psopt = "\\smallskipamount";
2155 case VSpace::MEDSKIP:
2156 psopt = "\\medskipamount";
2158 case VSpace::BIGSKIP:
2159 psopt = "\\bigskipamount";
2161 case VSpace::HALFLINE:
2162 // default (no option)
2164 case VSpace::FULLLINE:
2165 psopt = "\\baselineskip";
2167 case VSpace::LENGTH:
2168 psopt = getDefSkip().length().asLatexString();
2173 if (!features.isProvided("parskip")) {
2175 psopt = "[skip=" + psopt + "]";
2176 os << "\\usepackage" + psopt + "{parskip}\n";
2178 os << "\\setlength{\\parskip}{" + psopt + "}\n";
2181 // when separation by indentation
2182 // only output something when a width is given
2183 if (!getParIndent().empty()) {
2184 os << "\\setlength{\\parindent}{"
2185 << from_utf8(getParIndent().asLatexString())
2190 if (is_math_indent) {
2191 // when formula indentation
2192 // only output something when it is not the default
2193 if (!getMathIndent().empty()) {
2194 os << "\\setlength{\\mathindent}{"
2195 << from_utf8(getMathIndent().asString())
2200 // Now insert the LyX specific LaTeX commands...
2201 features.resolveAlternatives();
2202 features.expandMultiples();
2205 if (!output_sync_macro.empty())
2206 os << from_utf8(output_sync_macro) +"\n";
2207 else if (features.runparams().flavor == Flavor::LaTeX)
2208 os << "\\usepackage[active]{srcltx}\n";
2210 os << "\\synctex=-1\n";
2213 // due to interferences with babel and hyperref, the color package has to
2214 // be loaded (when it is not already loaded) before babel when hyperref
2215 // is used with the colorlinks option, see
2216 // http://www.lyx.org/trac/ticket/5291
2217 // we decided therefore to load color always before babel, see
2218 // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg144349.html
2219 os << from_ascii(features.getColorOptions());
2221 // If we use hyperref, jurabib, japanese or varioref,
2222 // we have to call babel before
2224 && (features.isRequired("jurabib")
2225 || features.isRequired("hyperref")
2226 || features.isRequired("varioref")
2227 || features.isRequired("japanese"))) {
2228 os << features.getBabelPresettings();
2230 os << from_utf8(babelCall(language_options.str(),
2231 !lyxrc.language_global_options)) + '\n';
2232 os << features.getBabelPostsettings();
2235 // The optional packages;
2236 os << from_ascii(features.getPackages());
2238 // Additional Indices
2239 if (features.isRequired("splitidx")) {
2240 for (auto const & idx : indiceslist()) {
2241 os << "\\newindex{";
2242 os << escape(idx.shortcut());
2248 os << from_utf8(spacing().writePreamble(features.isProvided("SetSpace")));
2251 // * Hyperref manual: "Make sure it comes last of your loaded
2252 // packages, to give it a fighting chance of not being over-written,
2253 // since its job is to redefine many LaTeX commands."
2254 // * Email from Heiko Oberdiek: "It is usually better to load babel
2255 // before hyperref. Then hyperref has a chance to detect babel.
2256 // * Has to be loaded before the "LyX specific LaTeX commands" to
2257 // avoid errors with algorithm floats.
2258 // use hyperref explicitly if it is required
2259 if (features.isRequired("hyperref")) {
2260 OutputParams tmp_params = features.runparams();
2261 pdfoptions().writeLaTeX(tmp_params, os,
2262 features.isProvided("hyperref"));
2263 // correctly break URLs with hyperref and dvi/ps output
2264 if (features.runparams().hyperref_driver == "dvips"
2265 && features.isAvailable("breakurl"))
2266 os << "\\usepackage{breakurl}\n";
2267 } else if (features.isRequired("nameref"))
2268 // hyperref loads this automatically
2269 os << "\\usepackage{nameref}\n";
2272 os << "\\usepackage";
2273 if (!lineno_opts.empty())
2274 os << "[" << lineno_opts << "]";
2276 os << "\\linenumbers\n";
2279 // bibtopic needs to be loaded after hyperref.
2280 // the dot provides the aux file naming which LyX can detect.
2281 if (features.mustProvide("bibtopic"))
2282 os << "\\usepackage[dot]{bibtopic}\n";
2284 // Will be surrounded by \makeatletter and \makeatother when not empty
2285 otexstringstream atlyxpreamble;
2287 // Some macros LyX will need
2289 TexString tmppreamble = features.getMacros();
2290 if (!tmppreamble.str.empty())
2291 atlyxpreamble << "\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
2292 "LyX specific LaTeX commands.\n"
2293 << std::move(tmppreamble)
2296 // the text class specific preamble
2298 docstring tmppreamble = features.getTClassPreamble();
2299 if (!tmppreamble.empty())
2300 atlyxpreamble << "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
2301 "Textclass specific LaTeX commands.\n"
2305 // suppress date if selected
2306 // use \@ifundefined because we cannot be sure that every document class
2307 // has a \date command
2309 atlyxpreamble << "\\@ifundefined{date}{}{\\date{}}\n";
2311 /* the user-defined preamble */
2312 if (!containsOnly(preamble, " \n\t")) {
2314 atlyxpreamble << "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
2315 "User specified LaTeX commands.\n";
2317 // Check if the user preamble contains uncodable glyphs
2318 odocstringstream user_preamble;
2319 docstring uncodable_glyphs;
2320 Encoding const * const enc = features.runparams().encoding;
2322 for (char_type c : preamble) {
2323 if (!enc->encodable(c)) {
2324 docstring const glyph(1, c);
2325 LYXERR0("Uncodable character '"
2327 << "' in user preamble!");
2328 uncodable_glyphs += glyph;
2329 if (features.runparams().dryrun) {
2330 user_preamble << "<" << _("LyX Warning: ")
2331 << _("uncodable character") << " '";
2332 user_preamble.put(c);
2333 user_preamble << "'>";
2336 user_preamble.put(c);
2339 user_preamble << preamble;
2341 // On BUFFER_VIEW|UPDATE, warn user if we found uncodable glyphs
2342 if (!features.runparams().dryrun && !uncodable_glyphs.empty()) {
2343 frontend::Alert::warning(
2344 _("Uncodable character in user preamble"),
2346 _("The user preamble of your document contains glyphs "
2347 "that are unknown in the current document encoding "
2348 "(namely %1$s).\nThese glyphs are omitted "
2349 " from the output, which may result in "
2350 "incomplete output."
2351 "\n\nPlease select an appropriate "
2352 "document encoding\n"
2353 "(such as utf8) or change the "
2354 "preamble code accordingly."),
2357 atlyxpreamble << user_preamble.str() << '\n';
2360 // footmisc must be loaded after setspace
2361 // Load it here to avoid clashes with footmisc loaded in the user
2362 // preamble. For that reason we also pass the options via
2363 // \PassOptionsToPackage in getPreamble() and not here.
2364 if (features.mustProvide("footmisc"))
2365 atlyxpreamble << "\\usepackage{footmisc}\n";
2367 // subfig loads internally the LaTeX package "caption". As
2368 // caption is a very popular package, users will load it in
2369 // the preamble. Therefore we must load subfig behind the
2370 // user-defined preamble and check if the caption package was
2371 // loaded or not. For the case that caption is loaded before
2372 // subfig, there is the subfig option "caption=false". This
2373 // option also works when a koma-script class is used and
2374 // koma's own caption commands are used instead of caption. We
2375 // use \PassOptionsToPackage here because the user could have
2376 // already loaded subfig in the preamble.
2377 if (features.mustProvide("subfig"))
2378 atlyxpreamble << "\\ifdefined\\showcaptionsetup\n"
2379 " % Caption package is used. Advise subfig not to load it again.\n"
2380 " \\PassOptionsToPackage{caption=false}{subfig}\n"
2382 "\\usepackage{subfig}\n";
2384 // Itemize bullet settings need to be last in case the user
2385 // defines their own bullets that use a package included
2386 // in the user-defined preamble -- ARRae
2387 // Actually it has to be done much later than that
2388 // since some packages like frenchb make modifications
2389 // at \begin{document} time -- JMarc
2390 docstring bullets_def;
2391 for (int i = 0; i < 4; ++i) {
2392 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
2393 if (bullets_def.empty())
2394 bullets_def += "\\AtBeginDocument{\n";
2395 bullets_def += " \\def\\labelitemi";
2397 // `i' is one less than the item to modify
2404 bullets_def += "ii";
2410 bullets_def += '{' +
2411 user_defined_bullet(i).getText()
2416 if (!bullets_def.empty())
2417 atlyxpreamble << bullets_def << "}\n\n";
2419 if (!atlyxpreamble.empty())
2420 os << "\n\\makeatletter\n"
2421 << atlyxpreamble.release()
2422 << "\\makeatother\n\n";
2424 // We try to load babel late, in case it interferes with other packages.
2425 // Jurabib, hyperref, varioref, bicaption, menukeys and listings (bug 8995)
2426 // have to be called after babel, though.
2427 if (use_babel && !features.isRequired("jurabib")
2428 && !features.isRequired("hyperref")
2429 && !features.isRequired("varioref")
2430 && !features.isRequired("japanese")) {
2431 os << features.getBabelPresettings();
2433 os << from_utf8(babelCall(language_options.str(),
2434 !lyxrc.language_global_options)) + '\n';
2435 os << features.getBabelPostsettings();
2437 // In documents containing text in Thai language,
2438 // we must load inputenc after babel (see lib/languages).
2439 if (contains(features.getBabelPostsettings(), from_ascii("thai.ldf")))
2440 writeEncodingPreamble(os, features);
2442 // font selection must be done after babel with non-TeX fonts
2443 if (!fonts.empty() && features.useBabel() && useNonTeXFonts)
2444 os << from_utf8(fonts);
2446 if (features.isRequired("bicaption"))
2447 os << "\\usepackage{bicaption}\n";
2448 if (!listings_params.empty()
2449 || features.mustProvide("listings")
2450 || features.mustProvide("minted")) {
2452 os << "\\usepackage{minted}\n";
2454 os << "\\usepackage{listings}\n";
2456 string lst_params = listings_params;
2457 // If minted, do not output the language option (bug 11203)
2458 if (use_minted && contains(lst_params, "language=")) {
2459 vector<string> opts =
2460 getVectorFromString(lst_params, ",", false);
2461 for (size_t i = 0; i < opts.size(); ++i) {
2462 if (prefixIs(opts[i], "language="))
2463 opts.erase(opts.begin() + i--);
2465 lst_params = getStringFromVector(opts, ",");
2467 if (!lst_params.empty()) {
2469 os << "\\setminted{";
2472 // do not test validity because listings_params is
2473 // supposed to be valid
2475 InsetListingsParams(lst_params).separatedParams(true);
2476 os << from_utf8(par);
2480 // xunicode only needs to be loaded if tipa is used
2481 // (the rest is obsoleted by the new TU encoding).
2482 // It needs to be loaded at least after amsmath, amssymb,
2483 // esint and the other packages that provide special glyphs
2484 if (features.mustProvide("tipa") && useNonTeXFonts
2485 && !features.isProvided("xunicode")) {
2486 // The `xunicode` package officially only supports XeTeX,
2487 // but also works with LuaTeX. We work around its XeTeX test.
2488 if (features.runparams().flavor != Flavor::XeTeX) {
2489 os << "% Pretend to xunicode that we are XeTeX\n"
2490 << "\\def\\XeTeXpicfile{}\n";
2492 os << "\\usepackage{xunicode}\n";
2495 // covington must be loaded after beamerarticle
2496 if (features.isRequired("covington"))
2497 os << "\\usepackage{covington}\n";
2499 // Polyglossia must be loaded last ...
2500 if (use_polyglossia) {
2502 os << "\\usepackage{polyglossia}\n";
2503 // set the main language
2504 os << "\\setdefaultlanguage";
2505 if (!language->polyglossiaOpts().empty())
2506 os << "[" << from_ascii(language->polyglossiaOpts()) << "]";
2507 os << "{" << from_ascii(language->polyglossia()) << "}\n";
2508 // now setup the other languages
2509 set<string> const polylangs =
2510 features.getPolyglossiaLanguages();
2511 for (auto const & pl : polylangs) {
2512 // We do not output the options here; they are output in
2513 // the language switch commands. This is safer if multiple
2514 // varieties are used.
2515 if (pl == language->polyglossia())
2517 os << "\\setotherlanguage";
2518 os << "{" << from_ascii(pl) << "}\n";
2522 // ... but before biblatex (see #7065)
2523 if ((features.mustProvide("biblatex")
2524 || features.isRequired("biblatex-chicago"))
2525 && !features.isProvided("biblatex-chicago")
2526 && !features.isProvided("biblatex-natbib")
2527 && !features.isProvided("natbib-internal")
2528 && !features.isProvided("natbib")
2529 && !features.isProvided("jurabib")) {
2530 // The biblatex-chicago package has a differing interface
2531 // it uses a wrapper package and loads styles via fixed options
2532 bool const chicago = features.isRequired("biblatex-chicago");
2535 os << "\\usepackage";
2536 if (!biblatex_bibstyle.empty()
2537 && (biblatex_bibstyle == biblatex_citestyle)
2539 opts = "style=" + biblatex_bibstyle;
2541 } else if (!chicago) {
2542 if (!biblatex_bibstyle.empty()) {
2543 opts = "bibstyle=" + biblatex_bibstyle;
2546 if (!biblatex_citestyle.empty()) {
2547 opts += delim + "citestyle=" + biblatex_citestyle;
2551 if (!multibib.empty() && multibib != "child") {
2552 opts += delim + "refsection=" + multibib;
2555 if (bibtexCommand() == "bibtex8"
2556 || prefixIs(bibtexCommand(), "bibtex8 ")) {
2557 opts += delim + "backend=bibtex8";
2559 } else if (bibtexCommand() == "bibtex"
2560 || prefixIs(bibtexCommand(), "bibtex ")) {
2561 opts += delim + "backend=bibtex";
2564 if (!bib_encoding.empty() && encodings.fromLyXName(bib_encoding)) {
2565 opts += delim + "bibencoding="
2566 + encodings.fromLyXName(bib_encoding)->latexName();
2569 if (!biblio_opts.empty())
2570 opts += delim + biblio_opts;
2572 os << "[" << opts << "]";
2574 os << "{biblatex-chicago}\n";
2576 os << "{biblatex}\n";
2580 // Load custom language package here
2581 if (features.langPackage() == LaTeXFeatures::LANG_PACK_CUSTOM) {
2582 if (lang_package == "default")
2583 os << from_utf8(lyxrc.language_custom_package);
2585 os << from_utf8(lang_package);
2589 // Since menukeys uses catoptions, which does some heavy changes on key-value options,
2590 // it is recommended to load menukeys as the last package (even after hyperref)
2591 if (features.isRequired("menukeys"))
2592 os << "\\usepackage{menukeys}\n";
2594 docstring const i18npreamble =
2595 features.getTClassI18nPreamble(use_babel, use_polyglossia,
2597 if (!i18npreamble.empty())
2598 os << i18npreamble + '\n';
2604 void BufferParams::useClassDefaults()
2606 DocumentClass const & tclass = documentClass();
2608 sides = tclass.sides();
2609 columns = tclass.columns();
2610 pagestyle = tclass.pagestyle();
2611 tablestyle = tclass.tablestyle();
2612 use_default_options = true;
2613 // Only if class has a ToC hierarchy
2614 if (tclass.hasTocLevels()) {
2615 secnumdepth = tclass.secnumdepth();
2616 tocdepth = tclass.tocdepth();
2621 bool BufferParams::hasClassDefaults() const
2623 DocumentClass const & tclass = documentClass();
2625 return sides == tclass.sides()
2626 && columns == tclass.columns()
2627 && pagestyle == tclass.pagestyle()
2628 && tablestyle == tclass.tablestyle()
2629 && use_default_options
2630 && secnumdepth == tclass.secnumdepth()
2631 && tocdepth == tclass.tocdepth();
2635 DocumentClass const & BufferParams::documentClass() const
2641 DocumentClassConstPtr BufferParams::documentClassPtr() const
2647 void BufferParams::setDocumentClass(DocumentClassConstPtr tc)
2649 // evil, but this function is evil
2650 doc_class_ = const_pointer_cast<DocumentClass>(tc);
2651 invalidateConverterCache();
2655 bool BufferParams::setBaseClass(string const & classname, string const & path)
2657 LYXERR(Debug::TCLASS, "setBaseClass: " << classname);
2658 LayoutFileList & bcl = LayoutFileList::get();
2659 if (!bcl.haveClass(classname)) {
2661 bformat(_("The layout file:\n"
2663 "could not be found. A default textclass with default\n"
2664 "layouts will be used. LyX will not be able to produce\n"
2666 from_utf8(classname));
2667 frontend::Alert::error(_("Document class not found"), s);
2668 bcl.addEmptyClass(classname);
2671 bool const success = bcl[classname].load(path);
2674 bformat(_("Due to some error in it, the layout file:\n"
2676 "could not be loaded. A default textclass with default\n"
2677 "layouts will be used. LyX will not be able to produce\n"
2679 from_utf8(classname));
2680 frontend::Alert::error(_("Could not load class"), s);
2681 bcl.addEmptyClass(classname);
2684 pimpl_->baseClass_ = classname;
2685 layout_modules_.adaptToBaseClass(baseClass(), removed_modules_);
2690 LayoutFile const * BufferParams::baseClass() const
2692 if (LayoutFileList::get().haveClass(pimpl_->baseClass_))
2693 return &(LayoutFileList::get()[pimpl_->baseClass_]);
2699 LayoutFileIndex const & BufferParams::baseClassID() const
2701 return pimpl_->baseClass_;
2705 void BufferParams::makeDocumentClass(bool clone, bool internal)
2710 invalidateConverterCache();
2711 LayoutModuleList mods;
2712 for (auto const & mod : layout_modules_)
2713 mods.push_back(mod);
2715 doc_class_ = getDocumentClass(*baseClass(), mods, cite_engine_, clone, internal);
2717 TextClass::ReturnValues success = TextClass::OK;
2718 if (!forced_local_layout_.empty())
2719 success = doc_class_->read(to_utf8(forced_local_layout_),
2721 if (!local_layout_.empty() &&
2722 (success == TextClass::OK || success == TextClass::OK_OLDFORMAT))
2723 success = doc_class_->read(to_utf8(local_layout_), TextClass::MODULE);
2724 if (success != TextClass::OK && success != TextClass::OK_OLDFORMAT) {
2725 docstring const msg = _("Error reading internal layout information");
2726 frontend::Alert::warning(_("Read Error"), msg);
2731 bool BufferParams::layoutModuleCanBeAdded(string const & modName) const
2733 return layout_modules_.moduleCanBeAdded(modName, baseClass());
2737 docstring BufferParams::getLocalLayout(bool forced) const
2740 return from_utf8(doc_class_->forcedLayouts());
2742 return local_layout_;
2746 void BufferParams::setLocalLayout(docstring const & layout, bool forced)
2749 forced_local_layout_ = layout;
2751 local_layout_ = layout;
2755 bool BufferParams::addLayoutModule(string const & modName)
2757 for (auto const & mod : layout_modules_)
2760 layout_modules_.push_back(modName);
2765 string BufferParams::bufferFormat() const
2767 return documentClass().outputFormat();
2771 bool BufferParams::isExportable(string const & format, bool need_viewable) const
2773 FormatList const & formats = exportableFormats(need_viewable);
2774 for (auto const & fmt : formats) {
2775 if (fmt->name() == format)
2782 FormatList const & BufferParams::exportableFormats(bool only_viewable) const
2784 FormatList & cached = only_viewable ?
2785 pimpl_->viewableFormatList : pimpl_->exportableFormatList;
2786 bool & valid = only_viewable ?
2787 pimpl_->isViewCacheValid : pimpl_->isExportCacheValid;
2791 vector<string> const backs = backends();
2792 set<string> excludes;
2793 if (useNonTeXFonts) {
2794 excludes.insert("latex");
2795 excludes.insert("pdflatex");
2796 } else if (inputenc != "ascii" && inputenc != "utf8-plain") {
2797 // XeTeX with TeX fonts requires input encoding ascii (#10600).
2798 excludes.insert("xetex");
2802 theConverters().getReachable(backs[0], only_viewable, true, excludes);
2803 vector<string>::const_iterator it = backs.begin() + 1;
2804 for (; it != backs.end(); ++it) {
2805 FormatList r = theConverters().getReachable(*it, only_viewable,
2807 result.insert(result.end(), r.begin(), r.end());
2809 sort(result.begin(), result.end(), Format::formatSorter);
2816 vector<string> BufferParams::backends() const
2819 string const buffmt = bufferFormat();
2821 // FIXME: Don't hardcode format names here, but use a flag
2822 if (buffmt == "latex") {
2823 if (encoding().package() == Encoding::japanese)
2824 v.push_back("platex");
2826 if (!useNonTeXFonts) {
2827 v.push_back("pdflatex");
2828 v.push_back("latex");
2831 || inputenc == "ascii" || inputenc == "utf8-plain")
2832 v.push_back("xetex");
2833 v.push_back("luatex");
2834 v.push_back("dviluatex");
2837 string rbuffmt = buffmt;
2838 // If we use an OutputFormat in Japanese docs,
2839 // we need special format in order to get the path
2840 // via pLaTeX (#8823)
2841 if (documentClass().hasOutputFormat()
2842 && encoding().package() == Encoding::japanese)
2844 v.push_back(rbuffmt);
2847 v.push_back("xhtml");
2848 v.push_back("docbook5");
2849 v.push_back("text");
2855 Flavor BufferParams::getOutputFlavor(string const & format) const
2857 string const dformat = (format.empty() || format == "default") ?
2858 getDefaultOutputFormat() : format;
2859 DefaultFlavorCache::const_iterator it =
2860 default_flavors_.find(dformat);
2862 if (it != default_flavors_.end())
2865 Flavor result = Flavor::LaTeX;
2867 // FIXME It'd be better not to hardcode this, but to do
2868 // something with formats.
2869 if (dformat == "xhtml")
2870 result = Flavor::Html;
2871 else if (dformat == "docbook5")
2872 result = Flavor::DocBook5;
2873 else if (dformat == "text")
2874 result = Flavor::Text;
2875 else if (dformat == "lyx")
2876 result = Flavor::LyX;
2877 else if (dformat == "pdflatex")
2878 result = Flavor::PdfLaTeX;
2879 else if (dformat == "xetex")
2880 result = Flavor::XeTeX;
2881 else if (dformat == "luatex")
2882 result = Flavor::LuaTeX;
2883 else if (dformat == "dviluatex")
2884 result = Flavor::DviLuaTeX;
2886 // Try to determine flavor of default output format
2887 vector<string> backs = backends();
2888 if (find(backs.begin(), backs.end(), dformat) == backs.end()) {
2889 // Get shortest path to format
2890 Graph::EdgePath path;
2891 for (auto const & bvar : backs) {
2892 Graph::EdgePath p = theConverters().getPath(bvar, dformat);
2893 if (!p.empty() && (path.empty() || p.size() < path.size())) {
2898 result = theConverters().getFlavor(path);
2901 // cache this flavor
2902 default_flavors_[dformat] = result;
2907 string BufferParams::getDefaultOutputFormat() const
2909 if (!default_output_format.empty()
2910 && default_output_format != "default")
2911 return default_output_format;
2912 if (encoding().package() == Encoding::japanese)
2913 return lyxrc.default_platex_view_format;
2915 return lyxrc.default_otf_view_format;
2916 return lyxrc.default_view_format;
2919 Font const BufferParams::getFont() const
2921 FontInfo f = documentClass().defaultfont();
2922 if (fonts_default_family == "rmdefault")
2923 f.setFamily(ROMAN_FAMILY);
2924 else if (fonts_default_family == "sfdefault")
2925 f.setFamily(SANS_FAMILY);
2926 else if (fonts_default_family == "ttdefault")
2927 f.setFamily(TYPEWRITER_FAMILY);
2928 return Font(f, language);
2932 QuoteStyle BufferParams::getQuoteStyle(string const & qs) const
2934 return quotesstyletranslator().find(qs);
2938 bool BufferParams::isLatex() const
2940 return documentClass().outputType() == LATEX;
2944 bool BufferParams::isLiterate() const
2946 return documentClass().outputType() == LITERATE;
2950 void BufferParams::readPreamble(Lexer & lex)
2952 if (lex.getString() != "\\begin_preamble")
2953 lyxerr << "Error (BufferParams::readPreamble):"
2954 "consistency check failed." << endl;
2956 preamble = lex.getLongString(from_ascii("\\end_preamble"));
2960 void BufferParams::readDocumentMetadata(Lexer & lex)
2962 if (lex.getString() != "\\begin_metadata")
2963 lyxerr << "Error (BufferParams::readDocumentMetadata):"
2964 "consistency check failed." << endl;
2966 document_metadata = lex.getLongString(from_ascii("\\end_metadata"));
2970 void BufferParams::readLocalLayout(Lexer & lex, bool forced)
2972 string const expected = forced ? "\\begin_forced_local_layout" :
2973 "\\begin_local_layout";
2974 if (lex.getString() != expected)
2975 lyxerr << "Error (BufferParams::readLocalLayout):"
2976 "consistency check failed." << endl;
2979 forced_local_layout_ =
2980 lex.getLongString(from_ascii("\\end_forced_local_layout"));
2982 local_layout_ = lex.getLongString(from_ascii("\\end_local_layout"));
2986 bool BufferParams::setLanguage(string const & lang)
2988 Language const *new_language = languages.getLanguage(lang);
2989 if (!new_language) {
2990 // Language lang was not found
2993 language = new_language;
2998 void BufferParams::readLanguage(Lexer & lex)
3000 if (!lex.next()) return;
3002 string const tmptok = lex.getString();
3004 // check if tmptok is part of tex_babel in tex-defs.h
3005 if (!setLanguage(tmptok)) {
3006 // Language tmptok was not found
3007 language = default_language;
3008 lyxerr << "Warning: Setting language `"
3009 << tmptok << "' to `" << language->lang()
3015 void BufferParams::readGraphicsDriver(Lexer & lex)
3020 string const tmptok = lex.getString();
3021 // check if tmptok is part of tex_graphics in tex_defs.h
3024 string const test = tex_graphics[n++];
3026 if (test == tmptok) {
3027 graphics_driver = tmptok;
3032 "Warning: graphics driver `$$Token' not recognized!\n"
3033 " Setting graphics driver to `default'.\n");
3034 graphics_driver = "default";
3041 void BufferParams::readBullets(Lexer & lex)
3046 int const index = lex.getInteger();
3048 int temp_int = lex.getInteger();
3049 user_defined_bullet(index).setFont(temp_int);
3050 temp_bullet(index).setFont(temp_int);
3052 user_defined_bullet(index).setCharacter(temp_int);
3053 temp_bullet(index).setCharacter(temp_int);
3055 user_defined_bullet(index).setSize(temp_int);
3056 temp_bullet(index).setSize(temp_int);
3060 void BufferParams::readBulletsLaTeX(Lexer & lex)
3062 // The bullet class should be able to read this.
3065 int const index = lex.getInteger();
3067 docstring const temp_str = lex.getDocString();
3069 user_defined_bullet(index).setText(temp_str);
3070 temp_bullet(index).setText(temp_str);
3074 void BufferParams::readModules(Lexer & lex)
3076 if (!lex.eatLine()) {
3077 lyxerr << "Error (BufferParams::readModules):"
3078 "Unexpected end of input." << endl;
3082 string mod = lex.getString();
3083 if (mod == "\\end_modules")
3085 addLayoutModule(mod);
3091 void BufferParams::readRemovedModules(Lexer & lex)
3093 if (!lex.eatLine()) {
3094 lyxerr << "Error (BufferParams::readRemovedModules):"
3095 "Unexpected end of input." << endl;
3099 string mod = lex.getString();
3100 if (mod == "\\end_removed_modules")
3102 removed_modules_.push_back(mod);
3105 // now we want to remove any removed modules that were previously
3106 // added. normally, that will be because default modules were added in
3107 // setBaseClass(), which gets called when \textclass is read at the
3108 // start of the read.
3109 for (auto const & rm : removed_modules_) {
3110 LayoutModuleList::iterator const mit = layout_modules_.begin();
3111 LayoutModuleList::iterator const men = layout_modules_.end();
3112 LayoutModuleList::iterator found = find(mit, men, rm);
3115 layout_modules_.erase(found);
3120 void BufferParams::readIncludeonly(Lexer & lex)
3122 if (!lex.eatLine()) {
3123 lyxerr << "Error (BufferParams::readIncludeonly):"
3124 "Unexpected end of input." << endl;
3128 string child = lex.getString();
3129 if (child == "\\end_includeonly")
3131 included_children_.push_back(child);
3137 string BufferParams::paperSizeName(PapersizePurpose purpose, string const & psize) const
3139 PAPER_SIZE ppsize = psize.empty() ? papersize : papersizetranslator().find(psize);
3142 if (documentClass().pagesize() == "default")
3143 // could be anything, so don't guess
3145 return paperSizeName(purpose, documentClass().pagesize());
3146 case PAPER_CUSTOM: {
3147 if (purpose == XDVI && !paperwidth.empty() &&
3148 !paperheight.empty()) {
3149 // heightxwidth<unit>
3150 string first = paperwidth;
3151 string second = paperheight;
3152 if (orientation == ORIENTATION_LANDSCAPE)
3155 return first.erase(first.length() - 2)
3161 // dvips and dvipdfm do not know this
3162 if (purpose == DVIPS || purpose == DVIPDFM)
3166 if (purpose == DVIPS || purpose == DVIPDFM)
3170 if (purpose == DVIPS || purpose == DVIPDFM)
3180 if (purpose == DVIPS || purpose == DVIPDFM)
3184 if (purpose == DVIPS || purpose == DVIPDFM)
3188 if (purpose == DVIPS || purpose == DVIPDFM)
3192 if (purpose == DVIPS || purpose == DVIPDFM)
3196 if (purpose == DVIPS || purpose == DVIPDFM)
3200 // dvipdfm does not know this
3201 if (purpose == DVIPDFM)
3205 if (purpose == DVIPDFM)
3209 if (purpose == DVIPS || purpose == DVIPDFM)
3213 if (purpose == DVIPS || purpose == DVIPDFM)
3217 if (purpose == DVIPS || purpose == DVIPDFM)
3221 if (purpose == DVIPS || purpose == DVIPDFM)
3225 if (purpose == DVIPS || purpose == DVIPDFM)
3229 if (purpose == DVIPS || purpose == DVIPDFM)
3233 if (purpose == DVIPS || purpose == DVIPDFM)
3237 if (purpose == DVIPS || purpose == DVIPDFM)
3241 if (purpose == DVIPS || purpose == DVIPDFM)
3245 if (purpose == DVIPS || purpose == DVIPDFM)
3249 if (purpose == DVIPS || purpose == DVIPDFM)
3253 if (purpose == DVIPS || purpose == DVIPDFM)
3257 if (purpose == DVIPS || purpose == DVIPDFM)
3261 if (purpose == DVIPS || purpose == DVIPDFM)
3265 if (purpose == DVIPS || purpose == DVIPDFM)
3268 case PAPER_USEXECUTIVE:
3269 // dvipdfm does not know this
3270 if (purpose == DVIPDFM)
3275 case PAPER_USLETTER:
3277 if (purpose == XDVI)
3284 string const BufferParams::dvips_options() const
3288 // If the class loads the geometry package, we do not know which
3289 // paper size is used, since we do not set it (bug 7013).
3290 // Therefore we must not specify any argument here.
3291 // dvips gets the correct paper size via DVI specials in this case
3292 // (if the class uses the geometry package correctly).
3293 if (documentClass().provides("geometry"))
3297 && papersize == PAPER_CUSTOM
3298 && !lyxrc.print_paper_dimension_flag.empty()
3299 && !paperwidth.empty()
3300 && !paperheight.empty()) {
3301 // using a custom papersize
3302 result = lyxrc.print_paper_dimension_flag;
3303 result += ' ' + paperwidth;
3304 result += ',' + paperheight;
3306 string const paper_option = paperSizeName(DVIPS);
3307 if (!paper_option.empty() && (paper_option != "letter" ||
3308 orientation != ORIENTATION_LANDSCAPE)) {
3309 // dvips won't accept -t letter -t landscape.
3310 // In all other cases, include the paper size
3312 result = lyxrc.print_paper_flag;
3313 result += ' ' + paper_option;
3316 if (orientation == ORIENTATION_LANDSCAPE &&
3317 papersize != PAPER_CUSTOM)
3318 result += ' ' + lyxrc.print_landscape_flag;
3323 string const BufferParams::main_font_encoding() const
3325 vector<string> const fencs = font_encodings();
3326 if (fencs.empty()) {
3327 if (ascii_lowercase(language->fontenc(*this)) == "none")
3331 return fencs.back();
3335 vector<string> const BufferParams::font_encodings() const
3337 string doc_fontenc = (fontenc == "auto") ? string() : fontenc;
3339 vector<string> fontencs;
3341 // "default" means "no explicit font encoding"
3342 if (doc_fontenc != "default") {
3343 if (!doc_fontenc.empty())
3344 // If we have a custom setting, we use only that!
3345 return getVectorFromString(doc_fontenc);
3346 string const lfe = language->fontenc(*this);
3348 && ascii_lowercase(language->fontenc(*this)) != "none") {
3349 vector<string> fencs = getVectorFromString(lfe);
3350 for (auto & fe : fencs) {
3351 if (find(fontencs.begin(), fontencs.end(), fe) == fontencs.end())
3352 fontencs.push_back(fe);
3361 string BufferParams::babelCall(string const & lang_opts, bool const langoptions) const
3363 // suppress the babel call if there is no BabelName defined
3364 // for the document language in the lib/languages file and if no
3365 // other languages are used (lang_opts is then empty)
3366 if (lang_opts.empty())
3368 // The prefs may require the languages to
3369 // be submitted to babel itself (not the class).
3371 return "\\usepackage[" + lang_opts + "]{babel}";
3372 return "\\usepackage{babel}";
3376 docstring BufferParams::getGraphicsDriver(string const & package) const
3380 if (package == "geometry") {
3381 if (graphics_driver == "dvips"
3382 || graphics_driver == "dvipdfm"
3383 || graphics_driver == "pdftex"
3384 || graphics_driver == "vtex")
3385 result = from_ascii(graphics_driver);
3386 else if (graphics_driver == "dvipdfmx")
3387 result = from_ascii("dvipdfm");
3394 void BufferParams::writeEncodingPreamble(otexstream & os,
3395 LaTeXFeatures & features) const
3397 // With no-TeX fonts we use utf8-plain without encoding package.
3401 string const doc_encoding = encoding().latexName();
3402 Encoding::Package const package = encoding().package();
3403 // (dvi)lualatex uses luainputenc rather than inputenc
3404 string const inputenc_package =
3405 (features.runparams().flavor == Flavor::LuaTeX
3406 || features.runparams().flavor == Flavor::DviLuaTeX)
3407 ? "luainputenc" : "inputenc";
3409 if (inputenc == "auto-legacy") {
3410 // The "japanese" babel language requires the pLaTeX engine
3411 // which conflicts with "inputenc".
3412 // See http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129680.html
3413 if (!features.isRequired("japanese")
3414 && !features.isProvided("inputenc")) {
3415 if (package == Encoding::inputenc) {
3416 // Main language requires (lua)inputenc
3417 os << "\\usepackage[" << doc_encoding << "]{"
3418 << inputenc_package << "}\n";
3420 // We might have an additional language that requires inputenc
3421 set<string> encoding_set = features.getEncodingSet(doc_encoding);
3422 bool inputenc = false;
3423 for (auto const & enc : encoding_set) {
3424 if (encodings.fromLaTeXName(enc)
3425 && encodings.fromLaTeXName(enc)->package() == Encoding::inputenc) {
3431 // load (lua)inputenc without options
3432 // (the encoding is loaded later)
3433 os << "\\usepackage{" << inputenc_package << "}\n";
3436 } else if (inputenc != "auto-legacy-plain") {
3438 case Encoding::none:
3440 case Encoding::japanese:
3441 if (encoding().iconvName() != "UTF-8"
3442 && !features.runparams().isFullUnicode()
3443 && features.isAvailableAtLeastFrom("LaTeX", 2018, 4))
3444 // don't default to [utf8]{inputenc} with LaTeX >= 2018/04
3445 os << "\\UseRawInputEncoding\n";
3447 case Encoding::inputenc:
3448 // do not load inputenc if japanese is used
3449 // or if the class provides inputenc
3450 if (features.isRequired("japanese")
3451 || features.isProvided("inputenc"))
3453 // The 2022 release of ucs.sty uses the default utf8
3454 // inputenc encoding with 'utf8x' inputenc if the ucs
3455 // package is not loaded before inputenc.
3456 // This breaks existing documents that use utf8x
3457 // and also makes utf8x redundant.
3458 // Thus we load ucs.sty in order to keep functionality
3459 // that would otherwise be silently dropped.
3460 if (doc_encoding == "utf8x"
3461 && features.isAvailableAtLeastFrom("ucs", 2022, 8, 7)
3462 && !features.isProvided("ucs"))
3463 os << "\\usepackage{ucs}\n";
3464 os << "\\usepackage[" << doc_encoding << "]{"
3465 << inputenc_package << "}\n";
3469 if ((inputenc == "auto-legacy-plain" || features.isRequired("japanese"))
3470 && features.isAvailableAtLeastFrom("LaTeX", 2018, 4))
3471 // don't default to [utf8]{inputenc} with LaTeX >= 2018/04
3472 os << "\\UseRawInputEncoding\n";
3476 string const BufferParams::parseFontName(string const & name) const
3478 string mangled = name;
3479 size_t const idx = mangled.find('[');
3480 if (idx == string::npos || idx == 0)
3483 return mangled.substr(0, idx - 1);
3487 string const BufferParams::loadFonts(LaTeXFeatures & features) const
3489 if (fontsRoman() == "default" && fontsSans() == "default"
3490 && fontsTypewriter() == "default"
3491 && (fontsMath() == "default" || fontsMath() == "auto"))
3497 /* Fontspec (XeTeX, LuaTeX): we provide GUI support for oldstyle
3498 * numbers (Numbers=OldStyle) and sf/tt scaling. The Ligatures=TeX/
3499 * Mapping=tex-text option assures TeX ligatures (such as "--")
3500 * are resolved. Note that tt does not use these ligatures.
3502 * -- add more GUI options?
3503 * -- add more fonts (fonts for other scripts)
3504 * -- if there's a way to find out if a font really supports
3505 * OldStyle, enable/disable the widget accordingly.
3507 if (useNonTeXFonts && features.isAvailable("fontspec")) {
3508 // "Mapping=tex-text" and "Ligatures=TeX" are equivalent.
3509 // However, until v.2 (2010/07/11) fontspec only knew
3510 // Mapping=tex-text (for XeTeX only); then "Ligatures=TeX"
3511 // was introduced for both XeTeX and LuaTeX (LuaTeX
3512 // didn't understand "Mapping=tex-text", while XeTeX
3513 // understood both. With most recent versions, both
3514 // variants are understood by both engines. However,
3515 // we want to provide support for at least TeXLive 2009
3516 // (for XeTeX; LuaTeX is only supported as of v.2)
3517 // As of 2017/11/03, Babel has its own higher-level
3518 // interface on top of fontspec that is to be used.
3519 bool const babelfonts = features.useBabel()
3520 && features.isAvailableAtLeastFrom("babel", 2017, 11, 3);
3521 string const texmapping =
3522 (features.runparams().flavor == Flavor::XeTeX) ?
3523 "Mapping=tex-text" : "Ligatures=TeX";
3524 if (fontsRoman() != "default") {
3526 os << "\\babelfont{rm}[";
3528 os << "\\setmainfont[";
3529 if (!font_roman_opts.empty())
3530 os << font_roman_opts << ',';
3532 if (fonts_roman_osf)
3533 os << ",Numbers=OldStyle";
3534 os << "]{" << parseFontName(fontsRoman()) << "}\n";
3536 if (fontsSans() != "default") {
3537 string const sans = parseFontName(fontsSans());
3538 if (fontsSansScale() != 100) {
3540 os << "\\babelfont{sf}";
3542 os << "\\setsansfont";
3544 << float(fontsSansScale()) / 100 << ',';
3546 os << "Numbers=OldStyle,";
3547 if (!font_sans_opts.empty())
3548 os << font_sans_opts << ',';
3549 os << texmapping << "]{"
3553 os << "\\babelfont{sf}[";
3555 os << "\\setsansfont[";
3557 os << "Numbers=OldStyle,";
3558 if (!font_sans_opts.empty())
3559 os << font_sans_opts << ',';
3560 os << texmapping << "]{"
3564 if (fontsTypewriter() != "default") {
3565 string const mono = parseFontName(fontsTypewriter());
3566 if (fontsTypewriterScale() != 100) {
3568 os << "\\babelfont{tt}";
3570 os << "\\setmonofont";
3572 << float(fontsTypewriterScale()) / 100;
3573 if (fonts_typewriter_osf)
3574 os << ",Numbers=OldStyle";
3575 if (!font_typewriter_opts.empty())
3576 os << ',' << font_typewriter_opts;
3581 os << "\\babelfont{tt}";
3583 os << "\\setmonofont";
3584 if (!font_typewriter_opts.empty() || fonts_typewriter_osf) {
3586 if (fonts_typewriter_osf)
3587 os << "Numbers=OldStyle";
3588 if (!font_typewriter_opts.empty()) {
3589 if (fonts_typewriter_osf)
3591 os << font_typewriter_opts;
3595 os << '{' << mono << "}\n";
3602 bool const ot1 = (features.runparams().main_fontenc == "default"
3603 || features.runparams().main_fontenc == "OT1");
3604 bool const dryrun = features.runparams().dryrun;
3605 bool const complete = (fontsSans() == "default" && fontsTypewriter() == "default");
3606 bool const nomath = (fontsMath() != "auto");
3609 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsRoman())).getLaTeXCode(
3610 dryrun, ot1, complete, fonts_expert_sc, fonts_roman_osf,
3611 nomath, font_roman_opts);
3614 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsSans())).getLaTeXCode(
3615 dryrun, ot1, complete, fonts_expert_sc, fonts_sans_osf,
3616 nomath, font_sans_opts, fontsSansScale());
3618 // MONOSPACED/TYPEWRITER
3619 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsTypewriter())).getLaTeXCode(
3620 dryrun, ot1, complete, fonts_expert_sc, fonts_typewriter_osf,
3621 nomath, font_typewriter_opts, fontsTypewriterScale());
3624 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsMath())).getLaTeXCode(
3625 dryrun, ot1, complete, fonts_expert_sc, fonts_roman_osf,
3632 Encoding const & BufferParams::encoding() const
3634 // Main encoding for LaTeX output.
3636 return *(encodings.fromLyXName("utf8-plain"));
3637 if (inputenc == "auto-legacy" || inputenc == "auto-legacy-plain")
3638 return *language->encoding();
3639 if (inputenc == "utf8" && language->lang() == "japanese")
3640 return *(encodings.fromLyXName("utf8-platex"));
3641 Encoding const * const enc = encodings.fromLyXName(inputenc);
3644 LYXERR0("Unknown inputenc value `" << inputenc
3645 << "'. Using `auto' instead.");
3646 return *language->encoding();
3650 string const & BufferParams::defaultBiblioStyle() const
3652 if (!biblio_style.empty())
3653 return biblio_style;
3655 map<string, string> const & bs = documentClass().defaultBiblioStyle();
3656 auto cit = bs.find(theCiteEnginesList.getTypeAsString(citeEngineType()));
3657 if (cit != bs.end())
3660 return empty_string();
3664 bool BufferParams::fullAuthorList() const
3666 return documentClass().fullAuthorList();
3670 string BufferParams::getCiteAlias(string const & s) const
3672 vector<string> commands =
3673 documentClass().citeCommands(citeEngineType());
3674 // If it is a real command, don't treat it as an alias
3675 if (find(commands.begin(), commands.end(), s) != commands.end())
3677 map<string,string> aliases = documentClass().citeCommandAliases();
3678 if (aliases.find(s) != aliases.end())
3684 vector<string> BufferParams::citeCommands() const
3686 static CitationStyle const default_style;
3687 vector<string> commands =
3688 documentClass().citeCommands(citeEngineType());
3689 if (commands.empty())
3690 commands.push_back(default_style.name);
3695 vector<CitationStyle> BufferParams::citeStyles() const
3697 static CitationStyle const default_style;
3698 vector<CitationStyle> styles =
3699 documentClass().citeStyles(citeEngineType());
3701 styles.push_back(default_style);
3706 string const BufferParams::getBibtexCommand(string const cmd, bool const warn) const
3708 // split from options
3710 split(cmd, command_in, ' ');
3712 // Look if the requested command is available. If so, use that.
3713 for (auto const & alts : lyxrc.bibtex_alternatives) {
3714 string command_prov;
3715 split(alts, command_prov, ' ');
3716 if (command_in == command_prov)
3720 // If not, find the most suitable fallback for the current cite framework,
3721 // and warn. Note that we omit options in any such case.
3723 if (useBiblatex()) {
3724 // For Biblatex, we prefer biber (also for Japanese)
3725 // and try to fall back to bibtex8
3726 if (lyxrc.bibtex_alternatives.find("biber") != lyxrc.bibtex_alternatives.end())
3728 else if (lyxrc.bibtex_alternatives.find("bibtex8") != lyxrc.bibtex_alternatives.end())
3729 fallback = "bibtex8";
3731 // For classic BibTeX and as last resort for biblatex, try bibtex
3732 if (fallback.empty()) {
3733 if (lyxrc.bibtex_alternatives.find("bibtex") != lyxrc.bibtex_alternatives.end())
3734 fallback = "bibtex";
3740 if (fallback.empty()) {
3741 frontend::Alert::warning(
3742 _("No bibliography processor found!"),
3744 _("The bibliography processor requested by this document "
3745 "(%1$s) is not available and no appropriate "
3746 "alternative has been found. "
3747 "No bibliography and references will be generated.\n"
3748 "Please fix your installation!"),
3751 frontend::Alert::warning(
3752 _("Requested bibliography processor not found!"),
3754 _("The bibliography processor requested by this document "
3755 "(%1$s) is not available. "
3756 "As a fallback, '%2$s' will be used, options are omitted. "
3757 "This might result in errors or unwanted changes in "
3758 "the bibliography. Please check carefully!\n"
3759 "It is suggested to install the missing processor."),
3760 from_utf8(cmd), from_utf8(fallback)));
3766 string const BufferParams::bibtexCommand(bool const warn) const
3768 // Return document-specific setting if available
3769 if (bibtex_command != "default")
3770 return getBibtexCommand(bibtex_command, warn);
3772 // If we have "default" in document settings, consult the prefs
3773 // 1. Japanese (uses a specific processor)
3774 if (encoding().package() == Encoding::japanese) {
3775 if (lyxrc.jbibtex_command != "automatic")
3776 // Return the specified program, if "automatic" is not set
3777 return lyxrc.jbibtex_command;
3778 else if (!useBiblatex()) {
3779 // With classic BibTeX, return pbibtex, jbibtex, bibtex
3780 if (lyxrc.jbibtex_alternatives.find("pbibtex") != lyxrc.jbibtex_alternatives.end())
3782 if (lyxrc.jbibtex_alternatives.find("jbibtex") != lyxrc.jbibtex_alternatives.end())
3787 // 2. All other languages
3788 else if (lyxrc.bibtex_command != "automatic")
3789 // Return the specified program, if "automatic" is not set
3790 return getBibtexCommand(lyxrc.bibtex_command, warn);
3792 // 3. Automatic: find the most suitable for the current cite framework
3793 if (useBiblatex()) {
3794 // For Biblatex, we prefer biber (also for Japanese)
3795 // and fall back to bibtex8 and, as last resort, bibtex
3796 if (lyxrc.bibtex_alternatives.find("biber") != lyxrc.bibtex_alternatives.end())
3798 else if (lyxrc.bibtex_alternatives.find("bibtex8") != lyxrc.bibtex_alternatives.end())
3805 bool BufferParams::useBiblatex() const
3807 return theCiteEnginesList[citeEngine()]->getCiteFramework() == "biblatex";
3811 void BufferParams::invalidateConverterCache() const
3813 pimpl_->isExportCacheValid = false;
3814 pimpl_->isViewCacheValid = false;
3818 // We shouldn't need to reset the params here, since anything
3819 // we need will be recopied.
3820 void BufferParams::copyForAdvFR(const BufferParams & bp)
3822 string const & lang = bp.language->lang();
3824 quotes_style = bp.quotes_style;
3825 layout_modules_ = bp.layout_modules_;
3826 string const & doc_class = bp.documentClass().name();
3827 setBaseClass(doc_class);
3831 void BufferParams::setBibFileEncoding(string const & file, string const & enc)
3833 bib_encodings[file] = enc;
3837 string const BufferParams::bibFileEncoding(string const & file) const
3839 if (bib_encodings.find(file) == bib_encodings.end())
3841 return bib_encodings.find(file)->second;
3845 BufferParams const & defaultBufferParams()
3847 static BufferParams default_params;
3848 return default_params;