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"
37 #include "OutputParams.h"
39 #include "texstream.h"
42 #include "PDFOptions.h"
44 #include "frontends/alert.h"
46 #include "insets/InsetListingsParams.h"
47 #include "insets/InsetQuotes.h"
49 #include "support/convert.h"
50 #include "support/debug.h"
51 #include "support/FileName.h"
52 #include "support/filetools.h"
53 #include "support/gettext.h"
54 #include "support/Length.h"
55 #include "support/Lexer.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",
77 "hungarian", "hebrew", ""
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);
161 translator.addPair(string_quotes_style[15], QuoteStyle::Hebrew);
166 QuotesStyleTranslator const & quotesstyletranslator()
168 static QuotesStyleTranslator const translator =
169 init_quotesstyletranslator();
175 typedef Translator<string, PAPER_SIZE> PaperSizeTranslator;
178 static PaperSizeTranslator initPaperSizeTranslator()
180 PaperSizeTranslator translator(string_papersize[0], PAPER_DEFAULT);
181 translator.addPair(string_papersize[1], PAPER_CUSTOM);
182 translator.addPair(string_papersize[2], PAPER_USLETTER);
183 translator.addPair(string_papersize[3], PAPER_USLEGAL);
184 translator.addPair(string_papersize[4], PAPER_USEXECUTIVE);
185 translator.addPair(string_papersize[5], PAPER_A0);
186 translator.addPair(string_papersize[6], PAPER_A1);
187 translator.addPair(string_papersize[7], PAPER_A2);
188 translator.addPair(string_papersize[8], PAPER_A3);
189 translator.addPair(string_papersize[9], PAPER_A4);
190 translator.addPair(string_papersize[10], PAPER_A5);
191 translator.addPair(string_papersize[11], PAPER_A6);
192 translator.addPair(string_papersize[12], PAPER_B0);
193 translator.addPair(string_papersize[13], PAPER_B1);
194 translator.addPair(string_papersize[14], PAPER_B2);
195 translator.addPair(string_papersize[15], PAPER_B3);
196 translator.addPair(string_papersize[16], PAPER_B4);
197 translator.addPair(string_papersize[17], PAPER_B5);
198 translator.addPair(string_papersize[18], PAPER_B6);
199 translator.addPair(string_papersize[19], PAPER_C0);
200 translator.addPair(string_papersize[20], PAPER_C1);
201 translator.addPair(string_papersize[21], PAPER_C2);
202 translator.addPair(string_papersize[22], PAPER_C3);
203 translator.addPair(string_papersize[23], PAPER_C4);
204 translator.addPair(string_papersize[24], PAPER_C5);
205 translator.addPair(string_papersize[25], PAPER_C6);
206 translator.addPair(string_papersize[26], PAPER_JISB0);
207 translator.addPair(string_papersize[27], PAPER_JISB1);
208 translator.addPair(string_papersize[28], PAPER_JISB2);
209 translator.addPair(string_papersize[29], PAPER_JISB3);
210 translator.addPair(string_papersize[30], PAPER_JISB4);
211 translator.addPair(string_papersize[31], PAPER_JISB5);
212 translator.addPair(string_papersize[32], PAPER_JISB6);
217 PaperSizeTranslator const & papersizetranslator()
219 static PaperSizeTranslator const translator =
220 initPaperSizeTranslator();
226 typedef Translator<string, PAPER_ORIENTATION> PaperOrientationTranslator;
229 PaperOrientationTranslator const init_paperorientationtranslator()
231 PaperOrientationTranslator translator(string_orientation[0], ORIENTATION_PORTRAIT);
232 translator.addPair(string_orientation[1], ORIENTATION_LANDSCAPE);
237 PaperOrientationTranslator const & paperorientationtranslator()
239 static PaperOrientationTranslator const translator =
240 init_paperorientationtranslator();
246 typedef Translator<int, PageSides> SidesTranslator;
249 SidesTranslator const init_sidestranslator()
251 SidesTranslator translator(1, OneSide);
252 translator.addPair(2, TwoSides);
257 SidesTranslator const & sidestranslator()
259 static SidesTranslator const translator = init_sidestranslator();
265 typedef Translator<int, BufferParams::Package> PackageTranslator;
268 PackageTranslator const init_packagetranslator()
270 PackageTranslator translator(0, BufferParams::package_off);
271 translator.addPair(1, BufferParams::package_auto);
272 translator.addPair(2, BufferParams::package_on);
277 PackageTranslator const & packagetranslator()
279 static PackageTranslator const translator =
280 init_packagetranslator();
286 typedef Translator<string, Spacing::Space> SpaceTranslator;
289 SpaceTranslator const init_spacetranslator()
291 SpaceTranslator translator("default", Spacing::Default);
292 translator.addPair("single", Spacing::Single);
293 translator.addPair("onehalf", Spacing::Onehalf);
294 translator.addPair("double", Spacing::Double);
295 translator.addPair("other", Spacing::Other);
300 SpaceTranslator const & spacetranslator()
302 static SpaceTranslator const translator = init_spacetranslator();
307 bool inSystemDir(FileName const & document_dir, string & system_dir)
309 // A document is assumed to be in a system LyX directory (not
310 // necessarily the system directory of the running instance)
311 // if both "configure.py" and "chkconfig.ltx" are found in
312 // either document_dir/../ or document_dir/../../.
313 // If true, the system directory path is returned in system_dir
314 // with a trailing path separator.
316 string const msg = "Checking whether document is in a system dir...";
318 string dir = document_dir.absFileName();
320 for (int i = 0; i < 3; ++i) {
321 dir = addPath(dir, "..");
322 if (!fileSearch(dir, "configure.py").empty() &&
323 !fileSearch(dir, "chkconfig.ltx").empty()) {
324 LYXERR(Debug::FILES, msg << " yes");
325 system_dir = addPath(FileName(dir).realPath(), "");
330 LYXERR(Debug::FILES, msg << " no");
331 system_dir = string();
338 class BufferParams::Impl
343 AuthorList authorlist;
344 BranchList branchlist;
345 WordLangTable spellignore;
346 Bullet temp_bullets[4];
347 Bullet user_defined_bullets[4];
348 IndicesList indiceslist;
352 /** This is the amount of space used for paragraph_separation "skip",
353 * and for detached paragraphs in "indented" documents.
356 PDFOptions pdfoptions;
357 LayoutFileIndex baseClass_;
358 FormatList exportableFormatList;
359 FormatList viewableFormatList;
360 bool isViewCacheValid;
361 bool isExportCacheValid;
365 BufferParams::Impl::Impl()
366 : defskip(VSpace::MEDSKIP), baseClass_(string("")),
367 isViewCacheValid(false), isExportCacheValid(false)
369 // set initial author
371 authorlist.record(Author(from_utf8(lyxrc.user_name),
372 from_utf8(lyxrc.user_email),
373 from_utf8(lyxrc.user_initials)));
374 // set comparison author
375 authorlist.record(Author(from_utf8("Document Comparison"),
376 docstring(), docstring()));
381 BufferParams::MemoryTraits::clone(BufferParams::Impl const * ptr)
384 return new BufferParams::Impl(*ptr);
388 void BufferParams::MemoryTraits::destroy(BufferParams::Impl * ptr)
394 BufferParams::BufferParams()
397 setBaseClass(defaultBaseclass());
398 cite_engine_ = "basic";
399 cite_engine_type_ = ENGINE_TYPE_DEFAULT;
401 paragraph_separation = ParagraphIndentSeparation;
402 is_math_indent = false;
403 math_numbering_side = DEFAULT;
404 quotes_style = QuoteStyle::English;
405 dynamic_quotes = false;
406 fontsize = "default";
409 papersize = PAPER_DEFAULT;
410 orientation = ORIENTATION_PORTRAIT;
411 use_geometry = false;
412 biblio_style = string();
413 use_bibtopic = false;
416 save_transient_properties = true;
417 track_changes = false;
418 output_changes = false;
420 postpone_fragile_content = true;
421 use_default_options = true;
422 maintain_unincluded_children = CM_None;
425 language = default_language;
427 fonts_roman[0] = "default";
428 fonts_roman[1] = "default";
429 fonts_sans[0] = "default";
430 fonts_sans[1] = "default";
431 fonts_typewriter[0] = "default";
432 fonts_typewriter[1] = "default";
433 fonts_math[0] = "auto";
434 fonts_math[1] = "auto";
435 fonts_default_family = "default";
436 useNonTeXFonts = false;
437 use_microtype = false;
438 use_dash_ligatures = true;
439 fonts_expert_sc = false;
440 fonts_roman_osf = false;
441 fonts_sans_osf = false;
442 fonts_typewriter_osf = false;
443 fonts_sans_scale[0] = 100;
444 fonts_sans_scale[1] = 100;
445 fonts_typewriter_scale[0] = 100;
446 fonts_typewriter_scale[1] = 100;
448 lang_package = "default";
449 graphics_driver = "default";
450 default_output_format = "default";
451 bibtex_command = "default";
452 index_command = "default";
455 listings_params = string();
456 pagestyle = "default";
457 tablestyle = "default";
458 float_alignment = "class";
459 float_placement = "class";
460 suppress_date = false;
461 justification = true;
462 // no color is the default (white)
463 backgroundcolor = lyx::rgbFromHexName("#ffffff");
464 isbackgroundcolor = false;
465 // no color is the default (black)
466 fontcolor = lyx::rgbFromHexName("#000000");
468 // light gray is the default font color for greyed-out notes
469 notefontcolor = lyx::rgbFromHexName("#cccccc");
470 isnotefontcolor = false;
471 boxbgcolor = lyx::rgbFromHexName("#ff0000");
472 isboxbgcolor = false;
473 compressed = lyxrc.save_compressed;
474 for (int iter = 0; iter < 4; ++iter) {
475 user_defined_bullet(iter) = ITEMIZE_DEFAULTS[iter];
476 temp_bullet(iter) = ITEMIZE_DEFAULTS[iter];
479 indiceslist().addDefault(B_("Index"));
480 html_be_strict = false;
481 html_math_output = MathML;
482 html_math_img_scale = 1.0;
483 html_css_as_file = false;
484 docbook_table_output = HTMLTable;
485 docbook_mathml_prefix = MPrefix;
486 display_pixel_ratio = 1.0;
488 shell_escape = false;
491 use_formatted_ref = false;
495 // map current author
496 author_map_[pimpl_->authorlist.get(0).bufferId()] = 0;
500 docstring BufferParams::B_(string const & l10n) const
502 LASSERT(language, return from_utf8(l10n));
503 return getMessages(language->code()).get(l10n);
507 BufferParams::Package BufferParams::use_package(std::string const & p) const
509 PackageMap::const_iterator it = use_packages.find(p);
510 if (it == use_packages.end())
516 void BufferParams::use_package(std::string const & p, BufferParams::Package u)
522 map<string, string> const & BufferParams::auto_packages()
524 static map<string, string> packages;
525 if (packages.empty()) {
526 // We could have a race condition here that two threads
527 // discover an empty map at the same time and want to fill
528 // it, but that is no problem, since the same contents is
529 // filled in twice then. Having the locker inside the
530 // packages.empty() condition has the advantage that we
531 // don't need the mutex overhead for simple reading.
533 Mutex::Locker locker(&mutex);
534 // adding a package here implies a file format change!
535 packages["amsmath"] =
536 N_("The LaTeX package amsmath is only used if AMS formula types or symbols from the AMS math toolbars are inserted into formulas");
537 packages["amssymb"] =
538 N_("The LaTeX package amssymb is only used if symbols from the AMS math toolbars are inserted into formulas");
540 N_("The LaTeX package cancel is only used if \\cancel commands are used in formulas");
542 N_("The LaTeX package esint is only used if special integral symbols are inserted into formulas");
543 packages["mathdots"] =
544 N_("The LaTeX package mathdots is only used if the command \\iddots is inserted into formulas");
545 packages["mathtools"] =
546 N_("The LaTeX package mathtools is only used if some mathematical relations are inserted into formulas");
548 N_("The LaTeX package mhchem is only used if either the command \\ce or \\cf is inserted into formulas");
549 packages["stackrel"] =
550 N_("The LaTeX package stackrel is only used if the command \\stackrel with subscript is inserted into formulas");
551 packages["stmaryrd"] =
552 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");
553 packages["undertilde"] =
554 N_("The LaTeX package undertilde is only used if you use the math frame decoration 'utilde'");
560 bool BufferParams::useBibtopic() const
564 return (use_bibtopic || (!multibib.empty() && multibib != "child"));
568 AuthorList & BufferParams::authors()
570 return pimpl_->authorlist;
574 AuthorList const & BufferParams::authors() const
576 return pimpl_->authorlist;
580 void BufferParams::addAuthor(Author const & a)
582 author_map_[a.bufferId()] = pimpl_->authorlist.record(a);
586 BranchList & BufferParams::branchlist()
588 return pimpl_->branchlist;
592 BranchList const & BufferParams::branchlist() const
594 return pimpl_->branchlist;
598 IndicesList & BufferParams::indiceslist()
600 return pimpl_->indiceslist;
604 IndicesList const & BufferParams::indiceslist() const
606 return pimpl_->indiceslist;
610 WordLangTable & BufferParams::spellignore()
612 return pimpl_->spellignore;
616 WordLangTable const & BufferParams::spellignore() const
618 return pimpl_->spellignore;
622 bool BufferParams::spellignored(WordLangTuple const & wl) const
624 bool has_item = false;
625 vector<WordLangTuple> il = spellignore();
626 vector<WordLangTuple>::const_iterator it = il.begin();
627 for (; it != il.end(); ++it) {
628 if (it->lang()->code() != wl.lang()->code())
630 if (it->word() == wl.word()) {
639 Bullet & BufferParams::temp_bullet(lyx::size_type const index)
641 LASSERT(index < 4, return pimpl_->temp_bullets[0]);
642 return pimpl_->temp_bullets[index];
646 Bullet const & BufferParams::temp_bullet(lyx::size_type const index) const
648 LASSERT(index < 4, return pimpl_->temp_bullets[0]);
649 return pimpl_->temp_bullets[index];
653 Bullet & BufferParams::user_defined_bullet(lyx::size_type const index)
655 LASSERT(index < 4, return pimpl_->temp_bullets[0]);
656 return pimpl_->user_defined_bullets[index];
660 Bullet const & BufferParams::user_defined_bullet(lyx::size_type const index) const
662 LASSERT(index < 4, return pimpl_->temp_bullets[0]);
663 return pimpl_->user_defined_bullets[index];
667 Spacing & BufferParams::spacing()
669 return pimpl_->spacing;
673 Spacing const & BufferParams::spacing() const
675 return pimpl_->spacing;
679 PDFOptions & BufferParams::pdfoptions()
681 return pimpl_->pdfoptions;
685 PDFOptions const & BufferParams::pdfoptions() const
687 return pimpl_->pdfoptions;
691 Length const & BufferParams::getMathIndent() const
693 return pimpl_->mathindent;
697 void BufferParams::setMathIndent(Length const & indent)
699 pimpl_->mathindent = indent;
703 Length const & BufferParams::getParIndent() const
705 return pimpl_->parindent;
709 void BufferParams::setParIndent(Length const & indent)
711 pimpl_->parindent = indent;
715 VSpace const & BufferParams::getDefSkip() const
717 return pimpl_->defskip;
721 void BufferParams::setDefSkip(VSpace const & vs)
723 // DEFSKIP will cause an infinite loop
724 LASSERT(vs.kind() != VSpace::DEFSKIP, return);
725 pimpl_->defskip = vs;
729 BufferParams::MathNumber BufferParams::getMathNumber() const
731 if (math_numbering_side != DEFAULT)
732 return math_numbering_side;
733 // FIXME: do not hardcode language here
734 else if (language->lang() == "arabic_arabi"
735 || documentClass().provides("leqno"))
742 string BufferParams::readToken(Lexer & lex, string const & token,
743 FileName const & filename)
746 FileName const & filepath = filename.onlyPath();
748 if (token == "\\textclass") {
750 string const classname = lex.getString();
751 // if there exists a local layout file, ignore the system one
752 // NOTE: in this case, the textclass (.cls file) is assumed to
755 LayoutFileList & bcl = LayoutFileList::get();
756 if (!filepath.empty()) {
757 // If classname is an absolute path, the document is
758 // using a local layout file which could not be accessed
759 // by a relative path. In this case the path is correct
760 // even if the document was moved to a different
761 // location. However, we will have a problem if the
762 // document was generated on a different platform.
763 bool isabsolute = FileName::isAbsolute(classname);
764 string const classpath = onlyPath(classname);
765 string const path = isabsolute ? classpath
766 : FileName(addPath(filepath.absFileName(),
767 classpath)).realPath();
768 string const oldpath = isabsolute ? string()
769 : FileName(addPath(origin, classpath)).realPath();
770 tcp = bcl.addLocalLayout(onlyFileName(classname), path, oldpath);
772 // that returns non-empty if a "local" layout file is found.
774 result = to_utf8(makeRelPath(from_utf8(onlyPath(tcp)),
775 from_utf8(filepath.absFileName())));
778 setBaseClass(onlyFileName(tcp));
780 setBaseClass(onlyFileName(classname));
781 // We assume that a tex class exists for local or unknown
782 // layouts so this warning, will only be given for system layouts.
783 if (!baseClass()->isTeXClassAvailable()) {
784 docstring const desc =
785 translateIfPossible(from_utf8(baseClass()->description()));
786 docstring const prereqs =
787 from_utf8(baseClass()->prerequisites());
788 docstring const msg =
789 bformat(_("The selected document class\n"
791 "requires external files that are not available.\n"
792 "The document class can still be used, but the\n"
793 "document cannot be compiled until the following\n"
794 "prerequisites are installed:\n"
796 "See section 3.1.2.2 (Class Availability) of the\n"
797 "User's Guide for more information."), desc, prereqs);
798 frontend::Alert::warning(_("Document class not available"),
801 } else if (token == "\\save_transient_properties") {
802 lex >> save_transient_properties;
803 } else if (token == "\\origin") {
805 origin = lex.getString();
806 string const sysdirprefix = "/systemlyxdir/";
807 if (prefixIs(origin, sysdirprefix)) {
809 if (inSystemDir(filepath, docsys))
810 origin.replace(0, sysdirprefix.length() - 1, docsys);
812 origin.replace(0, sysdirprefix.length() - 1,
813 package().system_support().absFileName());
815 } else if (token == "\\begin_metadata") {
816 readDocumentMetadata(lex);
817 } else if (token == "\\begin_preamble") {
819 } else if (token == "\\begin_local_layout") {
820 readLocalLayout(lex, false);
821 } else if (token == "\\begin_forced_local_layout") {
822 readLocalLayout(lex, true);
823 } else if (token == "\\begin_modules") {
825 } else if (token == "\\begin_removed_modules") {
826 readRemovedModules(lex);
827 } else if (token == "\\begin_includeonly") {
828 readIncludeonly(lex);
829 } else if (token == "\\maintain_unincluded_children") {
833 maintain_unincluded_children = CM_None;
834 else if (tmp == "mostly")
835 maintain_unincluded_children = CM_Mostly;
836 else if (tmp == "strict")
837 maintain_unincluded_children = CM_Strict;
838 } else if (token == "\\options") {
840 options = lex.getString();
841 } else if (token == "\\use_default_options") {
842 lex >> use_default_options;
843 } else if (token == "\\master") {
845 master = lex.getString();
846 if (!filepath.empty() && FileName::isAbsolute(origin)) {
847 bool const isabs = FileName::isAbsolute(master);
848 FileName const abspath(isabs ? master : origin + master);
849 bool const moved = filepath != FileName(origin);
850 if (moved && abspath.exists()) {
851 docstring const path = isabs
853 : from_utf8(abspath.realPath());
854 docstring const refpath =
855 from_utf8(filepath.absFileName());
856 master = to_utf8(makeRelPath(path, refpath));
859 } else if (token == "\\suppress_date") {
860 lex >> suppress_date;
861 } else if (token == "\\justification") {
862 lex >> justification;
863 } else if (token == "\\language") {
865 } else if (token == "\\language_package") {
867 lang_package = lex.getString();
868 } else if (token == "\\inputencoding") {
870 } else if (token == "\\graphics") {
871 readGraphicsDriver(lex);
872 } else if (token == "\\default_output_format") {
873 lex >> default_output_format;
874 } else if (token == "\\bibtex_command") {
876 bibtex_command = lex.getString();
877 } else if (token == "\\index_command") {
879 index_command = lex.getString();
880 } else if (token == "\\fontencoding") {
882 fontenc = lex.getString();
883 } else if (token == "\\font_roman") {
884 lex >> fonts_roman[0];
885 lex >> fonts_roman[1];
886 } else if (token == "\\font_sans") {
887 lex >> fonts_sans[0];
888 lex >> fonts_sans[1];
889 } else if (token == "\\font_typewriter") {
890 lex >> fonts_typewriter[0];
891 lex >> fonts_typewriter[1];
892 } else if (token == "\\font_math") {
893 lex >> fonts_math[0];
894 lex >> fonts_math[1];
895 } else if (token == "\\font_default_family") {
896 lex >> fonts_default_family;
897 } else if (token == "\\use_non_tex_fonts") {
898 lex >> useNonTeXFonts;
899 } else if (token == "\\font_sc") {
900 lex >> fonts_expert_sc;
901 } else if (token == "\\font_roman_osf") {
902 lex >> fonts_roman_osf;
903 } else if (token == "\\font_sans_osf") {
904 lex >> fonts_sans_osf;
905 } else if (token == "\\font_typewriter_osf") {
906 lex >> fonts_typewriter_osf;
907 } else if (token == "\\font_roman_opts") {
908 lex >> font_roman_opts;
909 } else if (token == "\\font_sf_scale") {
910 lex >> fonts_sans_scale[0];
911 lex >> fonts_sans_scale[1];
912 } else if (token == "\\font_sans_opts") {
913 lex >> font_sans_opts;
914 } else if (token == "\\font_tt_scale") {
915 lex >> fonts_typewriter_scale[0];
916 lex >> fonts_typewriter_scale[1];
917 } else if (token == "\\font_typewriter_opts") {
918 lex >> font_typewriter_opts;
919 } else if (token == "\\font_cjk") {
921 } else if (token == "\\use_microtype") {
922 lex >> use_microtype;
923 } else if (token == "\\use_dash_ligatures") {
924 lex >> use_dash_ligatures;
925 } else if (token == "\\paragraph_separation") {
928 paragraph_separation = parseptranslator().find(parsep);
929 } else if (token == "\\paragraph_indentation") {
931 string parindent = lex.getString();
932 if (parindent == "default")
933 pimpl_->parindent = Length();
935 pimpl_->parindent = Length(parindent);
936 } else if (token == "\\defskip") {
938 string const defskip = lex.getString();
939 pimpl_->defskip = VSpace(defskip);
940 if (pimpl_->defskip.kind() == VSpace::DEFSKIP)
942 pimpl_->defskip = VSpace(VSpace::MEDSKIP);
943 } else if (token == "\\is_math_indent") {
944 lex >> is_math_indent;
945 } else if (token == "\\math_indentation") {
947 string mathindent = lex.getString();
948 if (mathindent == "default")
949 pimpl_->mathindent = Length();
951 pimpl_->mathindent = Length(mathindent);
952 } else if (token == "\\math_numbering_side") {
956 math_numbering_side = LEFT;
957 else if (tmp == "right")
958 math_numbering_side = RIGHT;
960 math_numbering_side = DEFAULT;
961 } else if (token == "\\quotes_style") {
964 quotes_style = quotesstyletranslator().find(qstyle);
965 } else if (token == "\\dynamic_quotes") {
966 lex >> dynamic_quotes;
967 } else if (token == "\\papersize") {
970 papersize = papersizetranslator().find(ppsize);
971 } else if (token == "\\use_geometry") {
973 } else if (token == "\\use_package") {
978 use_package(package, packagetranslator().find(use));
979 } else if (token == "\\cite_engine") {
981 cite_engine_ = lex.getString();
982 } else if (token == "\\cite_engine_type") {
985 cite_engine_type_ = theCiteEnginesList.getType(engine_type);
986 } else if (token == "\\biblio_style") {
988 biblio_style = lex.getString();
989 } else if (token == "\\biblio_options") {
991 biblio_opts = trim(lex.getString());
992 } else if (token == "\\biblatex_bibstyle") {
994 biblatex_bibstyle = trim(lex.getString());
995 } else if (token == "\\biblatex_citestyle") {
997 biblatex_citestyle = trim(lex.getString());
998 } else if (token == "\\use_bibtopic") {
1000 } else if (token == "\\multibib") {
1002 } else if (token == "\\use_indices") {
1004 } else if (token == "\\tracking_changes") {
1005 lex >> track_changes;
1006 } else if (token == "\\output_changes") {
1007 lex >> output_changes;
1008 } else if (token == "\\change_bars") {
1010 } else if (token == "\\postpone_fragile_content") {
1011 lex >> postpone_fragile_content;
1012 } else if (token == "\\branch") {
1014 docstring branch = lex.getDocString();
1015 branchlist().add(branch);
1018 string const tok = lex.getString();
1019 if (tok == "\\end_branch")
1021 Branch * branch_ptr = branchlist().find(branch);
1022 if (tok == "\\selected") {
1025 branch_ptr->setSelected(lex.getInteger());
1027 if (tok == "\\filename_suffix") {
1030 branch_ptr->setFileNameSuffix(lex.getInteger());
1032 if (tok == "\\color") {
1034 vector<string> const colors = getVectorFromString(lex.getString(), " ");
1035 string const lmcolor = colors.front();
1037 if (colors.size() > 1)
1038 dmcolor = colors.back();
1040 branch_ptr->setColors(lmcolor, dmcolor);
1043 } else if (token == "\\index") {
1045 docstring index = lex.getDocString();
1047 indiceslist().add(index);
1050 string const tok = lex.getString();
1051 if (tok == "\\end_index")
1053 Index * index_ptr = indiceslist().find(index);
1054 if (tok == "\\shortcut") {
1056 shortcut = lex.getDocString();
1058 index_ptr->setShortcut(shortcut);
1060 if (tok == "\\color") {
1062 string color = lex.getString();
1064 index_ptr->setColor(color);
1065 // Update also the Color table:
1066 if (color == "none")
1067 color = lcolor.getX11HexName(Color_background);
1069 if (!shortcut.empty())
1070 lcolor.setColor(to_utf8(shortcut)+ "@" + filename.absFileName(), color);
1073 } else if (token == "\\spellchecker_ignore") {
1075 docstring wl = lex.getDocString();
1077 docstring word = split(wl, language, ' ');
1078 Language const * lang = languages.getLanguage(to_ascii(language));
1080 spellignore().push_back(WordLangTuple(word, lang));
1081 } else if (token == "\\author") {
1083 istringstream ss(lex.getString());
1087 } else if (token == "\\paperorientation") {
1090 orientation = paperorientationtranslator().find(orient);
1091 } else if (token == "\\backgroundcolor") {
1093 backgroundcolor = lyx::rgbFromHexName(lex.getString());
1094 isbackgroundcolor = true;
1095 } else if (token == "\\fontcolor") {
1097 fontcolor = lyx::rgbFromHexName(lex.getString());
1099 } else if (token == "\\notefontcolor") {
1101 string color = lex.getString();
1102 notefontcolor = lyx::rgbFromHexName(color);
1103 lcolor.setColor("notefontcolor", color);
1104 lcolor.setLaTeXName("notefontcolor", "note_fontcolor");
1105 lcolor.setGUIName("notefontcolor", N_("greyedout inset text"));
1106 // set a local name for the painter
1107 lcolor.setColor("notefontcolor@" + filename.absFileName(), color);
1108 isnotefontcolor = true;
1109 } else if (token == "\\boxbgcolor") {
1111 string color = lex.getString();
1112 boxbgcolor = lyx::rgbFromHexName(color);
1113 lcolor.setColor("boxbgcolor@" + filename.absFileName(), color);
1114 isboxbgcolor = true;
1115 } else if (token == "\\paperwidth") {
1117 } else if (token == "\\paperheight") {
1119 } else if (token == "\\leftmargin") {
1121 } else if (token == "\\topmargin") {
1123 } else if (token == "\\rightmargin") {
1125 } else if (token == "\\bottommargin") {
1126 lex >> bottommargin;
1127 } else if (token == "\\headheight") {
1129 } else if (token == "\\headsep") {
1131 } else if (token == "\\footskip") {
1133 } else if (token == "\\columnsep") {
1135 } else if (token == "\\paperfontsize") {
1137 } else if (token == "\\papercolumns") {
1139 } else if (token == "\\listings_params") {
1142 listings_params = InsetListingsParams(par).params();
1143 } else if (token == "\\papersides") {
1146 sides = sidestranslator().find(psides);
1147 } else if (token == "\\paperpagestyle") {
1149 } else if (token == "\\tablestyle") {
1151 } else if (token == "\\bullet") {
1153 } else if (token == "\\bulletLaTeX") {
1154 readBulletsLaTeX(lex);
1155 } else if (token == "\\secnumdepth") {
1157 } else if (token == "\\tocdepth") {
1159 } else if (token == "\\spacing") {
1163 if (nspacing == "other") {
1166 spacing().set(spacetranslator().find(nspacing), tmp_val);
1167 } else if (token == "\\float_placement") {
1168 lex >> float_placement;
1169 } else if (token == "\\float_alignment") {
1170 lex >> float_alignment;
1172 } else if (prefixIs(token, "\\pdf_") || token == "\\use_hyperref") {
1173 string toktmp = pdfoptions().readToken(lex, token);
1174 if (!toktmp.empty()) {
1175 lyxerr << "PDFOptions::readToken(): Unknown token: " <<
1179 } else if (token == "\\html_math_output") {
1182 html_math_output = static_cast<MathOutput>(temp);
1183 } else if (token == "\\html_be_strict") {
1184 lex >> html_be_strict;
1185 } else if (token == "\\html_css_as_file") {
1186 lex >> html_css_as_file;
1187 } else if (token == "\\html_math_img_scale") {
1188 lex >> html_math_img_scale;
1189 } else if (token == "\\html_latex_start") {
1191 html_latex_start = lex.getString();
1192 } else if (token == "\\html_latex_end") {
1194 html_latex_end = lex.getString();
1195 } else if (token == "\\docbook_table_output") {
1198 docbook_table_output = static_cast<TableOutput>(temp);
1199 } else if (token == "\\docbook_mathml_prefix") {
1202 docbook_mathml_prefix = static_cast<MathMLNameSpacePrefix>(temp);
1203 } else if (token == "\\output_sync") {
1205 } else if (token == "\\output_sync_macro") {
1206 lex >> output_sync_macro;
1207 } else if (token == "\\use_refstyle") {
1208 lex >> use_refstyle;
1209 } else if (token == "\\use_formatted_ref") {
1210 lex >> use_formatted_ref;
1211 } else if (token == "\\use_minted") {
1213 } else if (token == "\\use_lineno") {
1215 } else if (token == "\\lineno_options") {
1217 lineno_opts = trim(lex.getString());
1219 lyxerr << "BufferParams::readToken(): Unknown token: " <<
1229 // Quote argument if it contains spaces
1230 string quoteIfNeeded(string const & str) {
1231 if (contains(str, ' '))
1232 return "\"" + str + "\"";
1238 void BufferParams::writeFile(ostream & os, Buffer const * buf) const
1240 // The top of the file is written by the buffer.
1241 // Prints out the buffer info into the .lyx file given by file
1243 os << "\\save_transient_properties "
1244 << convert<string>(save_transient_properties) << '\n';
1246 // the document directory (must end with a path separator)
1247 // realPath() is used to resolve symlinks, while addPath(..., "")
1248 // ensures a trailing path separator.
1250 string filepath = addPath(buf->fileName().onlyPath().realPath(), "");
1251 string const sysdir = inSystemDir(FileName(filepath), docsys) ? docsys
1252 : addPath(package().system_support().realPath(), "");
1253 string const relpath =
1254 to_utf8(makeRelPath(from_utf8(filepath), from_utf8(sysdir)));
1255 if (!prefixIs(relpath, "../") && !FileName::isAbsolute(relpath))
1256 filepath = addPath("/systemlyxdir", relpath);
1257 else if (!save_transient_properties || !lyxrc.save_origin)
1258 filepath = "unavailable";
1259 os << "\\origin " << quoteIfNeeded(filepath) << '\n';
1262 os << "\\textclass "
1263 << quoteIfNeeded(buf->includedFilePath(addName(buf->layoutPos(),
1264 baseClass()->name()), "layout"))
1267 // then document metadata
1268 if (!document_metadata.empty()) {
1269 // remove '\n' from the end of document_metadata
1270 docstring const tmpmd = rtrim(document_metadata, "\n");
1271 os << "\\begin_metadata\n"
1273 << "\n\\end_metadata\n";
1276 // then the preamble
1277 if (!preamble.empty()) {
1278 // remove '\n' from the end of preamble
1279 docstring const tmppreamble = rtrim(preamble, "\n");
1280 os << "\\begin_preamble\n"
1281 << to_utf8(tmppreamble)
1282 << "\n\\end_preamble\n";
1286 if (!options.empty()) {
1287 os << "\\options " << options << '\n';
1290 // use the class options defined in the layout?
1291 os << "\\use_default_options "
1292 << convert<string>(use_default_options) << "\n";
1294 // the master document
1295 if (!master.empty()) {
1296 os << "\\master " << master << '\n';
1300 if (!removed_modules_.empty()) {
1301 os << "\\begin_removed_modules" << '\n';
1302 for (auto const & mod : removed_modules_)
1304 os << "\\end_removed_modules" << '\n';
1308 if (!layout_modules_.empty()) {
1309 os << "\\begin_modules" << '\n';
1310 for (auto const & mod : layout_modules_)
1312 os << "\\end_modules" << '\n';
1316 if (!included_children_.empty()) {
1317 os << "\\begin_includeonly" << '\n';
1318 for (auto const & c : included_children_)
1320 os << "\\end_includeonly" << '\n';
1323 switch (maintain_unincluded_children) {
1334 os << "\\maintain_unincluded_children " << muc << '\n';
1336 // local layout information
1337 docstring const local_layout = getLocalLayout(false);
1338 if (!local_layout.empty()) {
1339 // remove '\n' from the end
1340 docstring const tmplocal = rtrim(local_layout, "\n");
1341 os << "\\begin_local_layout\n"
1342 << to_utf8(tmplocal)
1343 << "\n\\end_local_layout\n";
1345 docstring const forced_local_layout = getLocalLayout(true);
1346 if (!forced_local_layout.empty()) {
1347 // remove '\n' from the end
1348 docstring const tmplocal = rtrim(forced_local_layout, "\n");
1349 os << "\\begin_forced_local_layout\n"
1350 << to_utf8(tmplocal)
1351 << "\n\\end_forced_local_layout\n";
1354 // then the text parameters
1355 if (language != ignore_language)
1356 os << "\\language " << language->lang() << '\n';
1357 os << "\\language_package " << lang_package
1358 << "\n\\inputencoding " << inputenc
1359 << "\n\\fontencoding " << fontenc
1360 << "\n\\font_roman \"" << fonts_roman[0]
1361 << "\" \"" << fonts_roman[1] << '"'
1362 << "\n\\font_sans \"" << fonts_sans[0]
1363 << "\" \"" << fonts_sans[1] << '"'
1364 << "\n\\font_typewriter \"" << fonts_typewriter[0]
1365 << "\" \"" << fonts_typewriter[1] << '"'
1366 << "\n\\font_math \"" << fonts_math[0]
1367 << "\" \"" << fonts_math[1] << '"'
1368 << "\n\\font_default_family " << fonts_default_family
1369 << "\n\\use_non_tex_fonts " << convert<string>(useNonTeXFonts)
1370 << "\n\\font_sc " << convert<string>(fonts_expert_sc)
1371 << "\n\\font_roman_osf " << convert<string>(fonts_roman_osf)
1372 << "\n\\font_sans_osf " << convert<string>(fonts_sans_osf)
1373 << "\n\\font_typewriter_osf " << convert<string>(fonts_typewriter_osf);
1374 if (!font_roman_opts.empty())
1375 os << "\n\\font_roman_opts \"" << font_roman_opts << "\"";
1376 os << "\n\\font_sf_scale " << fonts_sans_scale[0]
1377 << ' ' << fonts_sans_scale[1];
1378 if (!font_sans_opts.empty())
1379 os << "\n\\font_sans_opts \"" << font_sans_opts << "\"";
1380 os << "\n\\font_tt_scale " << fonts_typewriter_scale[0]
1381 << ' ' << fonts_typewriter_scale[1];
1382 if (!font_typewriter_opts.empty())
1383 os << "\n\\font_typewriter_opts \"" << font_typewriter_opts << "\"";
1385 if (!fonts_cjk.empty())
1386 os << "\\font_cjk " << fonts_cjk << '\n';
1387 os << "\\use_microtype " << convert<string>(use_microtype) << '\n';
1388 os << "\\use_dash_ligatures " << convert<string>(use_dash_ligatures) << '\n';
1389 os << "\\graphics " << graphics_driver << '\n';
1390 os << "\\default_output_format " << default_output_format << '\n';
1391 os << "\\output_sync " << output_sync << '\n';
1392 if (!output_sync_macro.empty())
1393 os << "\\output_sync_macro \"" << output_sync_macro << "\"\n";
1394 os << "\\bibtex_command " << bibtex_command << '\n';
1395 os << "\\index_command " << index_command << '\n';
1397 if (!float_placement.empty())
1398 os << "\\float_placement " << float_placement << '\n';
1399 if (!float_alignment.empty())
1400 os << "\\float_alignment " << float_alignment << '\n';
1401 os << "\\paperfontsize " << fontsize << '\n';
1403 spacing().writeFile(os);
1404 pdfoptions().writeFile(os);
1406 os << "\\papersize " << string_papersize[papersize]
1407 << "\n\\use_geometry " << convert<string>(use_geometry);
1408 map<string, string> const & packages = auto_packages();
1409 for (auto const & pack : packages)
1410 os << "\n\\use_package " << pack.first << ' '
1411 << use_package(pack.first);
1413 os << "\n\\cite_engine ";
1415 if (!cite_engine_.empty())
1420 os << "\n\\cite_engine_type " << theCiteEnginesList.getTypeAsString(cite_engine_type_);
1422 if (!biblio_style.empty())
1423 os << "\n\\biblio_style " << biblio_style;
1424 if (!biblio_opts.empty())
1425 os << "\n\\biblio_options " << biblio_opts;
1426 if (!biblatex_bibstyle.empty())
1427 os << "\n\\biblatex_bibstyle " << biblatex_bibstyle;
1428 if (!biblatex_citestyle.empty())
1429 os << "\n\\biblatex_citestyle " << biblatex_citestyle;
1430 if (!multibib.empty())
1431 os << "\n\\multibib " << multibib;
1433 os << "\n\\use_bibtopic " << convert<string>(use_bibtopic)
1434 << "\n\\use_indices " << convert<string>(use_indices)
1435 << "\n\\paperorientation " << string_orientation[orientation]
1436 << "\n\\suppress_date " << convert<string>(suppress_date)
1437 << "\n\\justification " << convert<string>(justification)
1438 << "\n\\use_refstyle " << use_refstyle
1439 << "\n\\use_formatted_ref " << use_formatted_ref
1440 << "\n\\use_minted " << use_minted
1441 << "\n\\use_lineno " << use_lineno
1444 if (!lineno_opts.empty())
1445 os << "\\lineno_options " << lineno_opts << '\n';
1447 if (isbackgroundcolor)
1448 os << "\\backgroundcolor " << lyx::X11hexname(backgroundcolor) << '\n';
1450 os << "\\fontcolor " << lyx::X11hexname(fontcolor) << '\n';
1451 if (isnotefontcolor)
1452 os << "\\notefontcolor " << lyx::X11hexname(notefontcolor) << '\n';
1454 os << "\\boxbgcolor " << lyx::X11hexname(boxbgcolor) << '\n';
1456 for (auto const & br : branchlist()) {
1457 os << "\\branch " << to_utf8(br.branch())
1458 << "\n\\selected " << br.isSelected()
1459 << "\n\\filename_suffix " << br.hasFileNameSuffix()
1460 << "\n\\color " << br.lightModeColor() << " " << br.darkModeColor()
1465 for (auto const & id : indiceslist()) {
1466 os << "\\index " << to_utf8(id.index())
1467 << "\n\\shortcut " << to_utf8(id.shortcut())
1468 << "\n\\color " << lyx::X11hexname(id.color())
1473 for (auto const & si : spellignore()) {
1474 os << "\\spellchecker_ignore " << si.lang()->lang()
1475 << " " << to_utf8(si.word())
1479 if (!paperwidth.empty())
1480 os << "\\paperwidth "
1481 << VSpace(paperwidth).asLyXCommand() << '\n';
1482 if (!paperheight.empty())
1483 os << "\\paperheight "
1484 << VSpace(paperheight).asLyXCommand() << '\n';
1485 if (!leftmargin.empty())
1486 os << "\\leftmargin "
1487 << VSpace(leftmargin).asLyXCommand() << '\n';
1488 if (!topmargin.empty())
1489 os << "\\topmargin "
1490 << VSpace(topmargin).asLyXCommand() << '\n';
1491 if (!rightmargin.empty())
1492 os << "\\rightmargin "
1493 << VSpace(rightmargin).asLyXCommand() << '\n';
1494 if (!bottommargin.empty())
1495 os << "\\bottommargin "
1496 << VSpace(bottommargin).asLyXCommand() << '\n';
1497 if (!headheight.empty())
1498 os << "\\headheight "
1499 << VSpace(headheight).asLyXCommand() << '\n';
1500 if (!headsep.empty())
1502 << VSpace(headsep).asLyXCommand() << '\n';
1503 if (!footskip.empty())
1505 << VSpace(footskip).asLyXCommand() << '\n';
1506 if (!columnsep.empty())
1507 os << "\\columnsep "
1508 << VSpace(columnsep).asLyXCommand() << '\n';
1509 os << "\\secnumdepth " << secnumdepth
1510 << "\n\\tocdepth " << tocdepth
1511 << "\n\\paragraph_separation "
1512 << string_paragraph_separation[paragraph_separation];
1513 if (!paragraph_separation)
1514 os << "\n\\paragraph_indentation "
1515 << (getParIndent().empty() ? "default" : getParIndent().asString());
1517 os << "\n\\defskip " << getDefSkip().asLyXCommand();
1518 os << "\n\\is_math_indent " << is_math_indent;
1520 os << "\n\\math_indentation "
1521 << (getMathIndent().empty() ? "default" : getMathIndent().asString());
1522 os << "\n\\math_numbering_side ";
1523 switch(math_numbering_side) {
1533 os << "\n\\quotes_style "
1534 << string_quotes_style[static_cast<int>(quotes_style)]
1535 << "\n\\dynamic_quotes " << dynamic_quotes
1536 << "\n\\papercolumns " << columns
1537 << "\n\\papersides " << sides
1538 << "\n\\paperpagestyle " << pagestyle
1539 << "\n\\tablestyle " << tablestyle << '\n';
1540 if (!listings_params.empty())
1541 os << "\\listings_params \"" <<
1542 InsetListingsParams(listings_params).encodedString() << "\"\n";
1543 for (int i = 0; i < 4; ++i) {
1544 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
1545 if (user_defined_bullet(i).getFont() != -1) {
1546 os << "\\bullet " << i << " "
1547 << user_defined_bullet(i).getFont() << " "
1548 << user_defined_bullet(i).getCharacter() << " "
1549 << user_defined_bullet(i).getSize() << "\n";
1553 os << "\\bulletLaTeX " << i << " \""
1554 << lyx::to_ascii(user_defined_bullet(i).getText())
1560 os << "\\tracking_changes "
1561 << (save_transient_properties ? convert<string>(track_changes) : "false")
1564 os << "\\output_changes "
1565 << (save_transient_properties ? convert<string>(output_changes) : "false")
1568 os << "\\change_bars "
1569 << (save_transient_properties ? convert<string>(change_bars) : "false")
1572 os << "\\postpone_fragile_content " << convert<string>(postpone_fragile_content) << '\n';
1574 os << "\\html_math_output " << html_math_output << '\n'
1575 << "\\html_css_as_file " << html_css_as_file << '\n'
1576 << "\\html_be_strict " << convert<string>(html_be_strict) << '\n';
1578 os << "\\docbook_table_output " << docbook_table_output << '\n';
1579 os << "\\docbook_mathml_prefix " << docbook_mathml_prefix << '\n';
1581 if (html_math_img_scale != 1.0)
1582 os << "\\html_math_img_scale " << convert<string>(html_math_img_scale) << '\n';
1583 if (!html_latex_start.empty())
1584 os << "\\html_latex_start " << html_latex_start << '\n';
1585 if (!html_latex_end.empty())
1586 os << "\\html_latex_end " << html_latex_end << '\n';
1588 os << pimpl_->authorlist;
1592 void BufferParams::validate(LaTeXFeatures & features) const
1594 features.require(documentClass().required());
1596 if (columns > 1 && language->rightToLeft()
1597 && !features.runparams().isFullUnicode()
1598 && language->babel() != "hebrew")
1599 features.require("rtloutputdblcol");
1601 if (output_changes) {
1602 bool xcolorulem = LaTeXFeatures::isAvailable("ulem") &&
1603 LaTeXFeatures::isAvailable("xcolor");
1605 switch (features.runparams().flavor) {
1607 case Flavor::DviLuaTeX:
1609 features.require("ct-xcolor-ulem");
1610 features.require("ulem");
1611 features.require("xcolor");
1613 features.require("ct-none");
1616 case Flavor::LuaTeX:
1617 case Flavor::PdfLaTeX:
1620 features.require("ct-xcolor-ulem");
1621 features.require("ulem");
1622 features.require("xcolor");
1623 // improves color handling in PDF output
1625 features.require("ct-none");
1632 features.require("changebar");
1635 // Floats with 'Here definitely' as default setting.
1636 if (float_placement.find('H') != string::npos)
1637 features.require("float");
1639 for (auto const & pm : use_packages) {
1640 if (pm.first == "amsmath") {
1641 // AMS Style is at document level
1642 if (pm.second == package_on ||
1643 features.isProvided("amsmath"))
1644 features.require(pm.first);
1645 } else if (pm.second == package_on)
1646 features.require(pm.first);
1649 // Document-level line spacing
1650 if (spacing().getSpace() != Spacing::Single && !spacing().isDefault())
1651 features.require("setspace");
1653 // the bullet shapes are buffer level not paragraph level
1654 // so they are tested here
1655 for (int i = 0; i < 4; ++i) {
1656 if (user_defined_bullet(i) == ITEMIZE_DEFAULTS[i])
1658 int const font = user_defined_bullet(i).getFont();
1660 int const c = user_defined_bullet(i).getCharacter();
1666 features.require("latexsym");
1668 } else if (font == 1) {
1669 features.require("amssymb");
1670 } else if (font >= 2 && font <= 5) {
1671 features.require("pifont");
1675 if (pdfoptions().use_hyperref) {
1676 features.require("hyperref");
1677 // due to interferences with babel and hyperref, the color package has to
1678 // be loaded after hyperref when hyperref is used with the colorlinks
1679 // option, see http://www.lyx.org/trac/ticket/5291
1680 if (pdfoptions().colorlinks)
1681 features.require("color");
1683 if (!listings_params.empty()) {
1684 // do not test validity because listings_params is
1685 // supposed to be valid
1687 InsetListingsParams(listings_params).separatedParams(true);
1688 // we can't support all packages, but we should load the color package
1689 if (par.find("\\color", 0) != string::npos)
1690 features.require("color");
1693 // some languages are only available via polyglossia
1694 if (features.hasPolyglossiaExclusiveLanguages())
1695 features.require("polyglossia");
1697 if (useNonTeXFonts && fontsMath() != "auto")
1698 features.require("unicode-math");
1701 features.require("microtype");
1703 if (!language->required().empty())
1704 features.require(language->required());
1708 bool BufferParams::writeLaTeX(otexstream & os, LaTeXFeatures & features,
1709 FileName const & filepath) const
1711 // DocumentMetadata must come before anything else
1712 if (features.isAvailableAtLeastFrom("LaTeX", 2022, 6)
1713 && !containsOnly(document_metadata, " \n\t")) {
1714 // Check if the user preamble contains uncodable glyphs
1715 odocstringstream doc_metadata;
1716 docstring uncodable_glyphs;
1717 Encoding const * const enc = features.runparams().encoding;
1719 for (char_type c : document_metadata) {
1720 if (!enc->encodable(c)) {
1721 docstring const glyph(1, c);
1722 LYXERR0("Uncodable character '"
1724 << "' in document metadata!");
1725 uncodable_glyphs += glyph;
1726 if (features.runparams().dryrun) {
1727 doc_metadata << "<" << _("LyX Warning: ")
1728 << _("uncodable character") << " '";
1729 doc_metadata.put(c);
1730 doc_metadata << "'>";
1733 doc_metadata.put(c);
1736 doc_metadata << document_metadata;
1738 // On BUFFER_VIEW|UPDATE, warn user if we found uncodable glyphs
1739 if (!features.runparams().dryrun && !uncodable_glyphs.empty()) {
1740 frontend::Alert::warning(
1741 _("Uncodable character in document metadata"),
1743 _("The metadata of your document contains glyphs "
1744 "that are unknown in the current document encoding "
1745 "(namely %1$s).\nThese glyphs are omitted "
1746 " from the output, which may result in "
1747 "incomplete output."
1748 "\n\nPlease select an appropriate "
1749 "document encoding\n"
1750 "(such as utf8) or change the "
1751 "metadata accordingly."),
1754 if (!doc_metadata.str().empty()) {
1755 os << "\\DocumentMetadata{\n"
1756 << doc_metadata.str()
1761 // http://www.tug.org/texmf-dist/doc/latex/base/fixltx2e.pdf
1762 // !! To use the Fix-cm package, load it before \documentclass, and use the command
1763 // \RequirePackage to do so, rather than the normal \usepackage
1764 // Do not try to load any other package before the document class, unless you
1765 // have a thorough understanding of the LATEX internals and know exactly what you
1767 if (features.mustProvide("fix-cm"))
1768 os << "\\RequirePackage{fix-cm}\n";
1769 // Likewise for fixltx2e. If other packages conflict with this policy,
1770 // treat it as a package bug (and report it!)
1771 // See http://www.latex-project.org/cgi-bin/ltxbugs2html?pr=latex/4407
1772 if (features.mustProvide("fixltx2e"))
1773 os << "\\RequirePackage{fixltx2e}\n";
1775 os << "\\documentclass";
1777 DocumentClass const & tclass = documentClass();
1779 ostringstream clsoptions; // the document class options.
1781 if (tokenPos(tclass.opt_fontsize(),
1782 '|', fontsize) >= 0) {
1783 // only write if existing in list (and not default)
1784 clsoptions << subst(tclass.fontsizeformat(), "$$s", fontsize) << ",";
1787 // paper sizes not supported by the class itself need the
1789 vector<string> classpsizes = getVectorFromString(tclass.opt_pagesize(), "|");
1790 bool class_supported_papersize = papersize == PAPER_DEFAULT
1791 || find(classpsizes.begin(), classpsizes.end(), string_papersize[papersize]) != classpsizes.end();
1793 if ((!use_geometry || features.isProvided("geometry-light"))
1794 && class_supported_papersize && papersize != PAPER_DEFAULT)
1795 clsoptions << subst(tclass.pagesizeformat(), "$$s", string_papersize[papersize]) << ",";
1798 if (sides != tclass.sides()) {
1801 clsoptions << "oneside,";
1804 clsoptions << "twoside,";
1810 if (columns != tclass.columns()) {
1812 clsoptions << "twocolumn,";
1814 clsoptions << "onecolumn,";
1818 && orientation == ORIENTATION_LANDSCAPE)
1819 clsoptions << "landscape,";
1822 clsoptions << "fleqn,";
1824 switch(math_numbering_side) {
1826 clsoptions << "leqno,";
1829 clsoptions << "reqno,";
1830 features.require("amsmath");
1836 if (paragraph_separation) {
1837 if (!tclass.halfparskip().empty() && getDefSkip().kind() == VSpace::HALFLINE)
1838 clsoptions << tclass.halfparskip() << ",";
1839 if (!tclass.fullparskip().empty() && getDefSkip().kind() == VSpace::FULLLINE)
1840 clsoptions << tclass.fullparskip() << ",";
1843 // language should be a parameter to \documentclass
1844 if (language->babel() == "hebrew"
1845 && default_language->babel() != "hebrew")
1846 // This seems necessary
1847 features.useLanguage(default_language);
1849 ostringstream language_options;
1850 bool const use_babel = features.useBabel() && !features.isProvided("babel");
1851 bool const use_polyglossia = features.usePolyglossia();
1852 bool const global = lyxrc.language_global_options;
1853 if (features.useBabel() || (use_polyglossia && global)) {
1854 language_options << features.getBabelLanguages();
1855 if (!language->babel().empty()) {
1856 if (!language_options.str().empty())
1857 language_options << ',';
1858 language_options << language->babel();
1860 if (global && !language_options.str().empty())
1861 clsoptions << language_options.str() << ',';
1864 // the predefined options from the layout
1865 if (use_default_options && !tclass.options().empty())
1866 clsoptions << tclass.options() << ',';
1868 // the user-defined options
1869 if (!options.empty()) {
1870 clsoptions << options << ',';
1873 docstring const strOptions = from_utf8(clsoptions.str());
1874 if (!strOptions.empty()) {
1875 // Check if class options contain uncodable glyphs
1876 docstring uncodable_glyphs;
1877 docstring options_encodable;
1878 Encoding const * const enc = features.runparams().encoding;
1880 for (char_type c : strOptions) {
1881 if (!enc->encodable(c)) {
1882 docstring const glyph(1, c);
1883 LYXERR0("Uncodable character '"
1885 << "' in class options!");
1886 uncodable_glyphs += glyph;
1887 if (features.runparams().dryrun) {
1888 options_encodable += "<" + _("LyX Warning: ")
1889 + _("uncodable character") + " '";
1890 options_encodable += c;
1891 options_encodable += "'>";
1894 options_encodable += c;
1897 options_encodable = strOptions;
1899 // On BUFFER_VIEW|UPDATE, warn user if we found uncodable glyphs
1900 if (!features.runparams().dryrun && !uncodable_glyphs.empty()) {
1901 frontend::Alert::warning(
1902 _("Uncodable character in class options"),
1904 _("The class options of your document contain glyphs "
1905 "that are unknown in the current document encoding "
1906 "(namely %1$s).\nThese glyphs are omitted "
1907 " from the output, which may result in "
1908 "incomplete output."
1909 "\n\nPlease select an appropriate "
1910 "document encoding\n"
1911 "(such as utf8) or change the "
1912 "class options accordingly."),
1915 options_encodable = rtrim(options_encodable, ",");
1916 os << '[' << options_encodable << ']';
1919 os << '{' << from_ascii(tclass.latexname()) << "}\n";
1920 // end of \documentclass defs
1922 // The package options (via \PassOptionsToPackage)
1923 os << from_ascii(features.getPackageOptions());
1925 // if we use fontspec or newtxmath, we have to load the AMS packages here
1926 string const ams = features.loadAMSPackages();
1927 string const main_font_enc = features.runparams().main_fontenc;
1928 bool const ot1 = (main_font_enc == "default" || main_font_enc == "OT1");
1929 bool const use_newtxmath =
1930 theLaTeXFonts().getLaTeXFont(from_ascii(fontsMath())).getUsedPackage(
1931 ot1, false, false) == "newtxmath";
1932 if ((useNonTeXFonts || use_newtxmath) && !ams.empty())
1933 os << from_ascii(ams);
1935 if (useNonTeXFonts) {
1936 // Babel (as of 2017/11/03) loads fontspec itself
1937 // However, it does so only if a non-default font is requested via \babelfont
1938 // Thus load fontspec if this is not the case and we need fontspec features
1939 bool const babel_needfontspec =
1940 !features.isAvailableAtLeastFrom("babel", 2017, 11, 3)
1941 || (fontsRoman() == "default"
1942 && fontsSans() == "default"
1943 && fontsTypewriter() == "default"
1944 // these need fontspec features
1945 && (features.isRequired("textquotesinglep")
1946 || features.isRequired("textquotedblp")));
1947 if (!features.isProvided("fontspec")
1948 && (!features.useBabel() || babel_needfontspec))
1949 os << "\\usepackage{fontspec}\n";
1950 if (features.mustProvide("unicode-math")
1951 && features.isAvailable("unicode-math"))
1952 os << "\\usepackage{unicode-math}\n";
1955 // load CJK support package before font selection
1956 // (see autotests/export/latex/CJK/micro-sign_utf8-cjk-libertine.lyx)
1957 if (!useNonTeXFonts && encoding().package() != Encoding::none && inputenc != "utf8x"
1958 && (encoding().package() == Encoding::CJK || features.mustProvide("CJK"))) {
1959 if (inputenc == "utf8-cjk" || inputenc == "utf8")
1960 os << "\\usepackage{CJKutf8}\n";
1962 os << "\\usepackage[encapsulated]{CJK}\n";
1965 // font selection must be done before loading fontenc.sty
1966 // but after babel with non-TeX fonts
1967 string const fonts = loadFonts(features);
1968 if (!fonts.empty() && (!features.useBabel() || !useNonTeXFonts))
1969 os << from_utf8(fonts);
1971 if (fonts_default_family != "default")
1972 os << "\\renewcommand{\\familydefault}{\\"
1973 << from_ascii(fonts_default_family) << "}\n";
1975 // set font encoding
1976 // non-TeX fonts use font encoding TU (set by fontspec)
1977 if (!useNonTeXFonts && !features.isProvided("fontenc")
1978 && main_font_enc != "default") {
1979 // get main font encodings
1980 vector<string> fontencs = font_encodings();
1981 // get font encodings of secondary languages
1982 // FIXME: some languages (hebrew, ...) assume a standard font encoding as last
1983 // option (for text in other languages).
1984 features.getFontEncodings(fontencs);
1985 if (!fontencs.empty()) {
1986 os << "\\usepackage["
1987 << from_ascii(getStringFromVector(fontencs))
1992 // Load textcomp and pmboxdraw before (lua)inputenc (#11454)
1993 if (features.mustProvide("textcomp"))
1994 os << "\\usepackage{textcomp}\n";
1995 if (features.mustProvide("pmboxdraw"))
1996 os << "\\usepackage{pmboxdraw}\n";
1998 // handle inputenc etc.
1999 // (In documents containing text in Thai language,
2000 // we must load inputenc after babel, see lib/languages).
2001 if (!contains(features.getBabelPostsettings(), from_ascii("thai.ldf")))
2002 writeEncodingPreamble(os, features);
2005 if (!features.runparams().includeall && !included_children_.empty()) {
2006 os << "\\includeonly{";
2008 // we do not use "auto const &" here, because incfile is modified later
2009 // coverity[auto_causes_copy]
2010 for (auto incfile : included_children_) {
2011 FileName inc = makeAbsPath(incfile, filepath.absFileName());
2012 string mangled = DocFileName(changeExtension(inc.absFileName(), ".tex")).
2014 if (!features.runparams().nice)
2016 // \includeonly doesn't want an extension
2017 incfile = changeExtension(incfile, string());
2018 incfile = support::latex_path(incfile);
2019 if (!incfile.empty()) {
2022 os << from_utf8(incfile);
2029 if (!features.isProvided("geometry")
2030 && (use_geometry || !class_supported_papersize)) {
2031 odocstringstream ods;
2032 if (!getGraphicsDriver("geometry").empty())
2033 ods << getGraphicsDriver("geometry");
2034 if (orientation == ORIENTATION_LANDSCAPE)
2035 ods << ",landscape";
2036 switch (papersize) {
2038 if (!paperwidth.empty())
2039 ods << ",paperwidth="
2040 << from_ascii(paperwidth);
2041 if (!paperheight.empty())
2042 ods << ",paperheight="
2043 << from_ascii(paperheight);
2045 case PAPER_USLETTER:
2047 case PAPER_USEXECUTIVE:
2076 ods << "," << from_ascii(string_papersize_geometry[papersize]);
2081 docstring g_options = trim(ods.str(), ",");
2082 os << "\\usepackage";
2083 // geometry-light means that the class works with geometry, but overwrites
2084 // the package options and paper sizes (memoir does this).
2085 // In this case, all options need to go to \geometry
2086 // and the standard paper sizes need to go to the class options.
2087 if (!g_options.empty() && !features.isProvided("geometry-light")) {
2088 os << '[' << g_options << ']';
2091 os << "{geometry}\n";
2092 if (use_geometry || features.isProvided("geometry-light")) {
2093 os << "\\geometry{verbose";
2094 if (!g_options.empty())
2095 // Output general options here with "geometry light".
2096 os << "," << g_options;
2097 // output this only if use_geometry is true
2099 if (!topmargin.empty())
2100 os << ",tmargin=" << from_ascii(Length(topmargin).asLatexString());
2101 if (!bottommargin.empty())
2102 os << ",bmargin=" << from_ascii(Length(bottommargin).asLatexString());
2103 if (!leftmargin.empty())
2104 os << ",lmargin=" << from_ascii(Length(leftmargin).asLatexString());
2105 if (!rightmargin.empty())
2106 os << ",rmargin=" << from_ascii(Length(rightmargin).asLatexString());
2107 if (!headheight.empty())
2108 os << ",headheight=" << from_ascii(Length(headheight).asLatexString());
2109 if (!headsep.empty())
2110 os << ",headsep=" << from_ascii(Length(headsep).asLatexString());
2111 if (!footskip.empty())
2112 os << ",footskip=" << from_ascii(Length(footskip).asLatexString());
2113 if (!columnsep.empty())
2114 os << ",columnsep=" << from_ascii(Length(columnsep).asLatexString());
2118 } else if (orientation == ORIENTATION_LANDSCAPE
2119 || papersize != PAPER_DEFAULT) {
2120 features.require("papersize");
2123 if (tokenPos(tclass.opt_pagestyle(), '|', pagestyle) >= 0) {
2124 if (pagestyle == "fancy")
2125 os << "\\usepackage{fancyhdr}\n";
2126 os << "\\pagestyle{" << from_ascii(pagestyle) << "}\n";
2129 // only output when the background color is not default
2130 if (isbackgroundcolor) {
2131 // only require color here, the background color will be defined
2132 // in LaTeXFeatures.cpp to avoid interferences with the LaTeX
2134 features.require("color");
2135 features.require("pagecolor");
2138 // only output when the font color is not default
2140 // only require color here, the font color will be defined
2141 // in LaTeXFeatures.cpp to avoid interferences with the LaTeX
2143 features.require("color");
2144 features.require("fontcolor");
2147 // Only if class has a ToC hierarchy
2148 if (tclass.hasTocLevels()) {
2149 if (secnumdepth != tclass.secnumdepth()) {
2150 os << "\\setcounter{secnumdepth}{"
2154 if (tocdepth != tclass.tocdepth()) {
2155 os << "\\setcounter{tocdepth}{"
2161 if (paragraph_separation) {
2162 // when skip separation
2164 bool default_skip = false;
2165 bool by_class_option = false;
2166 switch (getDefSkip().kind()) {
2167 case VSpace::SMALLSKIP:
2168 psopt = "\\smallskipamount";
2170 case VSpace::MEDSKIP:
2171 psopt = "\\medskipamount";
2173 case VSpace::BIGSKIP:
2174 psopt = "\\bigskipamount";
2176 case VSpace::HALFLINE:
2177 // default (no option)
2178 default_skip = true;
2179 by_class_option = !tclass.halfparskip().empty();
2181 case VSpace::FULLLINE:
2182 psopt = "\\baselineskip";
2183 by_class_option = !tclass.fullparskip().empty();
2185 case VSpace::LENGTH:
2186 psopt = getDefSkip().length().asLatexString();
2191 if (features.isProvided("parskip")) {
2192 // package already loaded (with arbitrary options)
2193 // change parskip value only
2195 os << "\\setlength{\\parskip}{" + psopt + "}\n";
2196 else if (default_skip)
2197 // explicitly reset default (might have been changed
2198 // in a class or package)
2199 os << "\\parskip=.5\\baselineskip plus 2pt\\relax\n";
2200 } else if (!by_class_option) {
2201 // load parskip package with required options
2203 if (!psopt.empty()) {
2204 if (contains(psopt, ' '))
2205 // glue length has spaces: embrace
2206 psopts = "skip={" + psopt + "}";
2208 psopts = "skip=" + psopt;
2210 string const xpsopts = getPackageOptions("parskip");
2211 if (!xpsopts.empty()) {
2212 if (!psopts.empty())
2216 os << "\\usepackage";
2217 if (!psopts.empty())
2218 os << "[" << psopts << "]";
2219 os << "{parskip}\n";
2222 // when separation by indentation
2223 // only output something when a width is given
2224 if (!getParIndent().empty()) {
2225 os << "\\setlength{\\parindent}{"
2226 << from_utf8(getParIndent().asLatexString())
2231 if (is_math_indent) {
2232 // when formula indentation
2233 // only output something when it is not the default
2234 if (!getMathIndent().empty()) {
2235 os << "\\setlength{\\mathindent}{"
2236 << from_utf8(getMathIndent().asString())
2241 // Now insert the LyX specific LaTeX commands...
2242 features.resolveAlternatives();
2243 features.expandMultiples();
2246 if (!output_sync_macro.empty())
2247 os << from_utf8(output_sync_macro) +"\n";
2248 else if (features.runparams().flavor == Flavor::LaTeX)
2249 os << "\\usepackage[active]{srcltx}\n";
2251 os << "\\synctex=-1\n";
2254 // due to interferences with babel and hyperref, the color package has to
2255 // be loaded (when it is not already loaded) before babel when hyperref
2256 // is used with the colorlinks option, see
2257 // http://www.lyx.org/trac/ticket/5291
2258 // we decided therefore to load color always before babel, see
2259 // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg144349.html
2260 os << from_ascii(features.getColorOptions());
2262 // If we use hyperref, jurabib, japanese or varioref,
2263 // we have to call babel before
2265 && (features.isRequired("jurabib")
2266 || features.isRequired("hyperref")
2267 || features.isRequired("varioref")
2268 || features.isRequired("japanese"))) {
2269 os << features.getBabelPresettings();
2271 os << from_utf8(babelCall(language_options.str(),
2272 !lyxrc.language_global_options)) + '\n';
2273 os << features.getBabelPostsettings();
2276 // The optional packages;
2277 os << from_ascii(features.getPackages());
2279 // Additional Indices
2280 if (features.isRequired("splitidx")) {
2281 for (auto const & idx : indiceslist()) {
2282 os << "\\newindex{";
2283 os << escape(idx.shortcut());
2289 os << from_utf8(spacing().writePreamble(features.isProvided("SetSpace")));
2292 // * Hyperref manual: "Make sure it comes last of your loaded
2293 // packages, to give it a fighting chance of not being over-written,
2294 // since its job is to redefine many LaTeX commands."
2295 // * Email from Heiko Oberdiek: "It is usually better to load babel
2296 // before hyperref. Then hyperref has a chance to detect babel.
2297 // * Has to be loaded before the "LyX specific LaTeX commands" to
2298 // avoid errors with algorithm floats.
2299 // use hyperref explicitly if it is required
2300 if (features.isRequired("hyperref")) {
2301 OutputParams tmp_params = features.runparams();
2302 pdfoptions().writeLaTeX(tmp_params, os,
2303 features.isProvided("hyperref"));
2304 // correctly break URLs with hyperref and dvi/ps output
2305 if (features.runparams().hyperref_driver == "dvips"
2306 && features.isAvailable("breakurl"))
2307 os << "\\usepackage{breakurl}\n";
2308 } else if (features.isRequired("nameref"))
2309 // hyperref loads this automatically
2310 os << "\\usepackage{nameref}\n";
2313 os << "\\usepackage";
2314 if (!lineno_opts.empty())
2315 os << "[" << lineno_opts << "]";
2317 os << "\\linenumbers\n";
2320 // bibtopic needs to be loaded after hyperref.
2321 // the dot provides the aux file naming which LyX can detect.
2322 if (features.mustProvide("bibtopic"))
2323 os << "\\usepackage[dot]{bibtopic}\n";
2325 // Will be surrounded by \makeatletter and \makeatother when not empty
2326 otexstringstream atlyxpreamble;
2328 // Some macros LyX will need
2330 TexString tmppreamble = features.getMacros();
2331 if (!tmppreamble.str.empty())
2332 atlyxpreamble << "\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
2333 "LyX specific LaTeX commands.\n"
2334 << std::move(tmppreamble)
2337 // the text class specific preamble
2339 docstring tmppreamble = features.getTClassPreamble();
2340 if (!tmppreamble.empty())
2341 atlyxpreamble << "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
2342 "Textclass specific LaTeX commands.\n"
2346 // suppress date if selected
2347 // use \@ifundefined because we cannot be sure that every document class
2348 // has a \date command
2350 atlyxpreamble << "\\@ifundefined{date}{}{\\date{}}\n";
2352 /* the user-defined preamble */
2353 if (!containsOnly(preamble, " \n\t")) {
2355 atlyxpreamble << "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
2356 "User specified LaTeX commands.\n";
2358 // Check if the user preamble contains uncodable glyphs
2359 odocstringstream user_preamble;
2360 docstring uncodable_glyphs;
2361 Encoding const * const enc = features.runparams().encoding;
2363 for (char_type c : preamble) {
2364 if (!enc->encodable(c)) {
2365 docstring const glyph(1, c);
2366 LYXERR0("Uncodable character '"
2368 << "' in user preamble!");
2369 uncodable_glyphs += glyph;
2370 if (features.runparams().dryrun) {
2371 user_preamble << "<" << _("LyX Warning: ")
2372 << _("uncodable character") << " '";
2373 user_preamble.put(c);
2374 user_preamble << "'>";
2377 user_preamble.put(c);
2380 user_preamble << preamble;
2382 // On BUFFER_VIEW|UPDATE, warn user if we found uncodable glyphs
2383 if (!features.runparams().dryrun && !uncodable_glyphs.empty()) {
2384 frontend::Alert::warning(
2385 _("Uncodable character in user preamble"),
2387 _("The user preamble of your document contains glyphs "
2388 "that are unknown in the current document encoding "
2389 "(namely %1$s).\nThese glyphs are omitted "
2390 " from the output, which may result in "
2391 "incomplete output."
2392 "\n\nPlease select an appropriate "
2393 "document encoding\n"
2394 "(such as utf8) or change the "
2395 "preamble code accordingly."),
2398 atlyxpreamble << user_preamble.str() << '\n';
2401 // footmisc must be loaded after setspace
2402 // Load it here to avoid clashes with footmisc loaded in the user
2403 // preamble. For that reason we also pass the options via
2404 // \PassOptionsToPackage in getPreamble() and not here.
2405 if (features.mustProvide("footmisc"))
2406 atlyxpreamble << "\\usepackage{footmisc}\n";
2408 // subfig loads internally the LaTeX package "caption". As
2409 // caption is a very popular package, users will load it in
2410 // the preamble. Therefore we must load subfig behind the
2411 // user-defined preamble and check if the caption package was
2412 // loaded or not. For the case that caption is loaded before
2413 // subfig, there is the subfig option "caption=false". This
2414 // option also works when a koma-script class is used and
2415 // koma's own caption commands are used instead of caption. We
2416 // use \PassOptionsToPackage here because the user could have
2417 // already loaded subfig in the preamble.
2418 if (features.mustProvide("subfig"))
2419 atlyxpreamble << "\\ifdefined\\showcaptionsetup\n"
2420 " % Caption package is used. Advise subfig not to load it again.\n"
2421 " \\PassOptionsToPackage{caption=false}{subfig}\n"
2423 "\\usepackage{subfig}\n";
2425 // Itemize bullet settings need to be last in case the user
2426 // defines their own bullets that use a package included
2427 // in the user-defined preamble -- ARRae
2428 // Actually it has to be done much later than that
2429 // since some packages like frenchb make modifications
2430 // at \begin{document} time -- JMarc
2431 docstring bullets_def;
2432 for (int i = 0; i < 4; ++i) {
2433 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
2434 if (bullets_def.empty())
2435 bullets_def += "\\AtBeginDocument{\n";
2436 bullets_def += " \\def\\labelitemi";
2438 // `i' is one less than the item to modify
2445 bullets_def += "ii";
2451 bullets_def += '{' +
2452 user_defined_bullet(i).getText()
2457 if (!bullets_def.empty())
2458 atlyxpreamble << bullets_def << "}\n\n";
2460 if (!atlyxpreamble.empty())
2461 os << "\n\\makeatletter\n"
2462 << atlyxpreamble.release()
2463 << "\\makeatother\n\n";
2465 // We try to load babel late, in case it interferes with other packages.
2466 // Jurabib, hyperref, varioref, bicaption, menukeys and listings (bug 8995)
2467 // have to be called after babel, though.
2468 if (use_babel && !features.isRequired("jurabib")
2469 && !features.isRequired("hyperref")
2470 && !features.isRequired("varioref")
2471 && !features.isRequired("japanese")) {
2472 os << features.getBabelPresettings();
2474 os << from_utf8(babelCall(language_options.str(),
2475 !lyxrc.language_global_options)) + '\n';
2476 os << features.getBabelPostsettings();
2478 // In documents containing text in Thai language,
2479 // we must load inputenc after babel (see lib/languages).
2480 if (contains(features.getBabelPostsettings(), from_ascii("thai.ldf")))
2481 writeEncodingPreamble(os, features);
2483 // font selection must be done after babel with non-TeX fonts
2484 if (!fonts.empty() && features.useBabel() && useNonTeXFonts)
2485 os << from_utf8(fonts);
2487 if (features.isRequired("bicaption"))
2488 os << "\\usepackage{bicaption}\n";
2489 if (!listings_params.empty()
2490 || features.mustProvide("listings")
2491 || features.mustProvide("minted")) {
2493 os << "\\usepackage{minted}\n";
2495 os << "\\usepackage{listings}\n";
2497 string lst_params = listings_params;
2498 // If minted, do not output the language option (bug 11203)
2499 if (use_minted && contains(lst_params, "language=")) {
2500 vector<string> opts =
2501 getVectorFromString(lst_params, ",", false);
2502 for (size_t i = 0; i < opts.size(); ++i) {
2503 if (prefixIs(opts[i], "language="))
2504 opts.erase(opts.begin() + i--);
2506 lst_params = getStringFromVector(opts, ",");
2508 if (!lst_params.empty()) {
2510 os << "\\setminted{";
2513 // do not test validity because listings_params is
2514 // supposed to be valid
2516 InsetListingsParams(lst_params).separatedParams(true);
2517 os << from_utf8(par);
2521 // xunicode only needs to be loaded if tipa is used
2522 // (the rest is obsoleted by the new TU encoding).
2523 // It needs to be loaded at least after amsmath, amssymb,
2524 // esint and the other packages that provide special glyphs
2525 if (features.mustProvide("tipa") && useNonTeXFonts
2526 && !features.isProvided("xunicode")) {
2527 // The `xunicode` package officially only supports XeTeX,
2528 // but also works with LuaTeX. We work around its XeTeX test.
2529 if (features.runparams().flavor != Flavor::XeTeX) {
2530 os << "% Pretend to xunicode that we are XeTeX\n"
2531 << "\\def\\XeTeXpicfile{}\n";
2533 os << "\\usepackage{xunicode}\n";
2536 // covington must be loaded after beamerarticle
2537 if (features.isRequired("covington"))
2538 os << "\\usepackage{covington}\n";
2540 // Polyglossia must be loaded last ...
2541 if (use_polyglossia) {
2543 os << "\\usepackage{polyglossia}\n";
2544 // set the main language
2545 os << "\\setdefaultlanguage";
2546 if (!language->polyglossiaOpts().empty())
2547 os << "[" << from_ascii(language->polyglossiaOpts()) << "]";
2548 os << "{" << from_ascii(language->polyglossia()) << "}\n";
2549 // now setup the other languages
2550 set<string> const polylangs =
2551 features.getPolyglossiaLanguages();
2552 for (auto const & pl : polylangs) {
2553 // We do not output the options here; they are output in
2554 // the language switch commands. This is safer if multiple
2555 // varieties are used.
2556 if (pl == language->polyglossia())
2558 os << "\\setotherlanguage";
2559 os << "{" << from_ascii(pl) << "}\n";
2563 // ... but before biblatex (see #7065)
2564 if ((features.mustProvide("biblatex")
2565 || features.isRequired("biblatex-chicago"))
2566 && !features.isProvided("biblatex-chicago")
2567 && !features.isProvided("biblatex-natbib")
2568 && !features.isProvided("natbib-internal")
2569 && !features.isProvided("natbib")
2570 && !features.isProvided("jurabib")) {
2571 // The biblatex-chicago package has a differing interface
2572 // it uses a wrapper package and loads styles via fixed options
2573 bool const chicago = features.isRequired("biblatex-chicago");
2576 os << "\\usepackage";
2577 if (!biblatex_bibstyle.empty()
2578 && (biblatex_bibstyle == biblatex_citestyle)
2580 opts = "style=" + biblatex_bibstyle;
2582 } else if (!chicago) {
2583 if (!biblatex_bibstyle.empty()) {
2584 opts = "bibstyle=" + biblatex_bibstyle;
2587 if (!biblatex_citestyle.empty()) {
2588 opts += delim + "citestyle=" + biblatex_citestyle;
2592 if (!multibib.empty() && multibib != "child") {
2593 opts += delim + "refsection=" + multibib;
2596 if (bibtexCommand() == "bibtex8"
2597 || prefixIs(bibtexCommand(), "bibtex8 ")) {
2598 opts += delim + "backend=bibtex8";
2600 } else if (bibtexCommand() == "bibtex"
2601 || prefixIs(bibtexCommand(), "bibtex ")) {
2602 opts += delim + "backend=bibtex";
2605 if (!bib_encoding.empty() && encodings.fromLyXName(bib_encoding)) {
2606 opts += delim + "bibencoding="
2607 + encodings.fromLyXName(bib_encoding)->latexName();
2610 if (!biblio_opts.empty())
2611 opts += delim + biblio_opts;
2613 os << "[" << opts << "]";
2615 os << "{biblatex-chicago}\n";
2617 os << "{biblatex}\n";
2621 // Load custom language package here
2622 if (features.langPackage() == LaTeXFeatures::LANG_PACK_CUSTOM) {
2623 if (lang_package == "default")
2624 os << from_utf8(lyxrc.language_custom_package);
2626 os << from_utf8(lang_package);
2630 // Since menukeys uses catoptions, which does some heavy changes on key-value options,
2631 // it is recommended to load menukeys as the last package (even after hyperref)
2632 if (features.isRequired("menukeys"))
2633 os << "\\usepackage{menukeys}\n";
2635 docstring const i18npreamble =
2636 features.getTClassI18nPreamble(use_babel, use_polyglossia,
2638 if (!i18npreamble.empty())
2639 os << i18npreamble + '\n';
2645 void BufferParams::useClassDefaults()
2647 DocumentClass const & tclass = documentClass();
2649 sides = tclass.sides();
2650 columns = tclass.columns();
2651 pagestyle = tclass.pagestyle();
2652 tablestyle = tclass.tablestyle();
2653 use_default_options = true;
2654 // Only if class has a ToC hierarchy
2655 if (tclass.hasTocLevels()) {
2656 secnumdepth = tclass.secnumdepth();
2657 tocdepth = tclass.tocdepth();
2662 bool BufferParams::hasClassDefaults() const
2664 DocumentClass const & tclass = documentClass();
2666 return sides == tclass.sides()
2667 && columns == tclass.columns()
2668 && pagestyle == tclass.pagestyle()
2669 && tablestyle == tclass.tablestyle()
2670 && use_default_options
2671 && secnumdepth == tclass.secnumdepth()
2672 && tocdepth == tclass.tocdepth();
2676 DocumentClass const & BufferParams::documentClass() const
2682 DocumentClassConstPtr BufferParams::documentClassPtr() const
2688 void BufferParams::setDocumentClass(DocumentClassConstPtr tc)
2690 // evil, but this function is evil
2691 doc_class_ = const_pointer_cast<DocumentClass>(tc);
2692 invalidateConverterCache();
2696 bool BufferParams::setBaseClass(string const & classname, string const & path)
2698 LYXERR(Debug::TCLASS, "setBaseClass: " << classname);
2699 LayoutFileList & bcl = LayoutFileList::get();
2700 if (!bcl.haveClass(classname)) {
2702 bformat(_("The layout file:\n"
2704 "could not be found. A default textclass with default\n"
2705 "layouts will be used. LyX will not be able to produce\n"
2707 from_utf8(classname));
2708 frontend::Alert::error(_("Document class not found"), s);
2709 bcl.addEmptyClass(classname);
2712 bool const success = bcl[classname].load(path);
2715 bformat(_("Due to some error in it, the layout file:\n"
2717 "could not be loaded. A default textclass with default\n"
2718 "layouts will be used. LyX will not be able to produce\n"
2720 from_utf8(classname));
2721 frontend::Alert::error(_("Could not load class"), s);
2722 bcl.addEmptyClass(classname);
2725 pimpl_->baseClass_ = classname;
2726 layout_modules_.adaptToBaseClass(baseClass(), removed_modules_);
2731 LayoutFile const * BufferParams::baseClass() const
2733 if (LayoutFileList::get().haveClass(pimpl_->baseClass_))
2734 return &(LayoutFileList::get()[pimpl_->baseClass_]);
2740 LayoutFileIndex const & BufferParams::baseClassID() const
2742 return pimpl_->baseClass_;
2746 void BufferParams::makeDocumentClass(bool clone, bool internal)
2751 invalidateConverterCache();
2752 LayoutModuleList mods;
2753 for (auto const & mod : layout_modules_)
2754 mods.push_back(mod);
2756 doc_class_ = getDocumentClass(*baseClass(), mods, cite_engine_, clone, internal);
2758 TextClass::ReturnValues success = TextClass::OK;
2759 if (!forced_local_layout_.empty())
2760 success = doc_class_->read(to_utf8(forced_local_layout_),
2762 if (!local_layout_.empty() &&
2763 (success == TextClass::OK || success == TextClass::OK_OLDFORMAT))
2764 success = doc_class_->read(to_utf8(local_layout_), TextClass::MODULE);
2765 if (success != TextClass::OK && success != TextClass::OK_OLDFORMAT) {
2766 docstring const msg = _("Error reading internal layout information");
2767 frontend::Alert::warning(_("Read Error"), msg);
2772 bool BufferParams::layoutModuleCanBeAdded(string const & modName) const
2774 return layout_modules_.moduleCanBeAdded(modName, baseClass());
2778 docstring BufferParams::getLocalLayout(bool forced) const
2781 return from_utf8(doc_class_->forcedLayouts());
2783 return local_layout_;
2787 void BufferParams::setLocalLayout(docstring const & layout, bool forced)
2790 forced_local_layout_ = layout;
2792 local_layout_ = layout;
2796 bool BufferParams::addLayoutModule(string const & modName)
2798 for (auto const & mod : layout_modules_)
2801 layout_modules_.push_back(modName);
2806 string BufferParams::bufferFormat() const
2808 return documentClass().outputFormat();
2812 bool BufferParams::isExportable(string const & format, bool need_viewable) const
2814 FormatList const & formats = exportableFormats(need_viewable);
2815 for (auto const & fmt : formats) {
2816 if (fmt->name() == format)
2823 FormatList const & BufferParams::exportableFormats(bool only_viewable) const
2825 FormatList & cached = only_viewable ?
2826 pimpl_->viewableFormatList : pimpl_->exportableFormatList;
2827 bool & valid = only_viewable ?
2828 pimpl_->isViewCacheValid : pimpl_->isExportCacheValid;
2832 vector<string> const backs = backends();
2833 set<string> excludes;
2834 if (useNonTeXFonts) {
2835 excludes.insert("latex");
2836 excludes.insert("pdflatex");
2837 } else if (inputenc != "ascii" && inputenc != "utf8-plain") {
2838 // XeTeX with TeX fonts requires input encoding ascii (#10600).
2839 excludes.insert("xetex");
2843 theConverters().getReachable(backs[0], only_viewable, true, excludes);
2844 vector<string>::const_iterator it = backs.begin() + 1;
2845 for (; it != backs.end(); ++it) {
2846 FormatList r = theConverters().getReachable(*it, only_viewable,
2848 result.insert(result.end(), r.begin(), r.end());
2850 sort(result.begin(), result.end(), Format::formatSorter);
2857 vector<string> BufferParams::backends() const
2860 string const buffmt = bufferFormat();
2862 // FIXME: Don't hardcode format names here, but use a flag
2863 if (buffmt == "latex") {
2864 if (encoding().package() == Encoding::japanese)
2865 v.push_back("platex");
2867 if (!useNonTeXFonts) {
2868 v.push_back("pdflatex");
2869 v.push_back("latex");
2872 || inputenc == "ascii" || inputenc == "utf8-plain")
2873 v.push_back("xetex");
2874 v.push_back("luatex");
2875 v.push_back("dviluatex");
2878 string rbuffmt = buffmt;
2879 // If we use an OutputFormat in Japanese docs,
2880 // we need special format in order to get the path
2881 // via pLaTeX (#8823)
2882 if (documentClass().hasOutputFormat()
2883 && encoding().package() == Encoding::japanese)
2885 v.push_back(rbuffmt);
2888 v.push_back("xhtml");
2889 v.push_back("docbook5");
2890 v.push_back("text");
2896 Flavor BufferParams::getOutputFlavor(string const & format) const
2898 string const dformat = (format.empty() || format == "default") ?
2899 getDefaultOutputFormat() : format;
2900 DefaultFlavorCache::const_iterator it =
2901 default_flavors_.find(dformat);
2903 if (it != default_flavors_.end())
2906 Flavor result = Flavor::LaTeX;
2908 // FIXME It'd be better not to hardcode this, but to do
2909 // something with formats.
2910 if (dformat == "xhtml")
2911 result = Flavor::Html;
2912 else if (dformat == "docbook5")
2913 result = Flavor::DocBook5;
2914 else if (dformat == "text")
2915 result = Flavor::Text;
2916 else if (dformat == "lyx")
2917 result = Flavor::LyX;
2918 else if (dformat == "pdflatex")
2919 result = Flavor::PdfLaTeX;
2920 else if (dformat == "xetex")
2921 result = Flavor::XeTeX;
2922 else if (dformat == "luatex")
2923 result = Flavor::LuaTeX;
2924 else if (dformat == "dviluatex")
2925 result = Flavor::DviLuaTeX;
2927 // Try to determine flavor of default output format
2928 vector<string> backs = backends();
2929 if (find(backs.begin(), backs.end(), dformat) == backs.end()) {
2930 // Get shortest path to format
2931 Graph::EdgePath path;
2932 for (auto const & bvar : backs) {
2933 Graph::EdgePath p = theConverters().getPath(bvar, dformat);
2934 if (!p.empty() && (path.empty() || p.size() < path.size())) {
2939 result = theConverters().getFlavor(path);
2942 // cache this flavor
2943 default_flavors_[dformat] = result;
2948 string BufferParams::getDefaultOutputFormat() const
2950 if (!default_output_format.empty()
2951 && default_output_format != "default")
2952 return default_output_format;
2953 if (encoding().package() == Encoding::japanese)
2954 return lyxrc.default_platex_view_format;
2956 return lyxrc.default_otf_view_format;
2957 return lyxrc.default_view_format;
2960 Font const BufferParams::getFont() const
2962 FontInfo f = documentClass().defaultfont();
2963 if (fonts_default_family == "rmdefault")
2964 f.setFamily(ROMAN_FAMILY);
2965 else if (fonts_default_family == "sfdefault")
2966 f.setFamily(SANS_FAMILY);
2967 else if (fonts_default_family == "ttdefault")
2968 f.setFamily(TYPEWRITER_FAMILY);
2969 return Font(f, language);
2973 QuoteStyle BufferParams::getQuoteStyle(string const & qs) const
2975 return quotesstyletranslator().find(qs);
2979 bool BufferParams::isLatex() const
2981 return documentClass().outputType() == LATEX;
2985 bool BufferParams::isLiterate() const
2987 return documentClass().outputType() == LITERATE;
2991 bool BufferParams::hasPackageOption(string const package, string const opt) const
2993 for (auto const & p : documentClass().packageOptions())
2994 if (package == p.first && opt == p.second)
3000 string BufferParams::getPackageOptions(string const package) const
3002 for (auto const & p : documentClass().packageOptions())
3003 if (package == p.first)
3009 bool BufferParams::useBidiPackage(OutputParams const & rp) const
3011 return (rp.use_polyglossia
3012 // as of babel 3.29, bidi=bidi-* is supported by babel
3013 // So we check whether we use a respective version and
3014 // whethert bidi-r or bidi-l have been requested either via class
3015 // or package options
3017 && LaTeXFeatures::isAvailableAtLeastFrom("babel", 2019, 4, 3)
3018 && (hasPackageOption("babel", "bidi-r")
3019 || hasPackageOption("babel", "bidi-l")
3020 || contains(options, "bidi-r")
3021 || contains(options, "bidi-l")))
3023 && rp.flavor == Flavor::XeTeX;
3027 void BufferParams::readPreamble(Lexer & lex)
3029 if (lex.getString() != "\\begin_preamble")
3030 lyxerr << "Error (BufferParams::readPreamble):"
3031 "consistency check failed." << endl;
3033 preamble = lex.getLongString(from_ascii("\\end_preamble"));
3037 void BufferParams::readDocumentMetadata(Lexer & lex)
3039 if (lex.getString() != "\\begin_metadata")
3040 lyxerr << "Error (BufferParams::readDocumentMetadata):"
3041 "consistency check failed." << endl;
3043 document_metadata = lex.getLongString(from_ascii("\\end_metadata"));
3047 void BufferParams::readLocalLayout(Lexer & lex, bool forced)
3049 string const expected = forced ? "\\begin_forced_local_layout" :
3050 "\\begin_local_layout";
3051 if (lex.getString() != expected)
3052 lyxerr << "Error (BufferParams::readLocalLayout):"
3053 "consistency check failed." << endl;
3056 forced_local_layout_ =
3057 lex.getLongString(from_ascii("\\end_forced_local_layout"));
3059 local_layout_ = lex.getLongString(from_ascii("\\end_local_layout"));
3063 bool BufferParams::setLanguage(string const & lang)
3065 Language const *new_language = languages.getLanguage(lang);
3066 if (!new_language) {
3067 // Language lang was not found
3070 language = new_language;
3075 void BufferParams::readLanguage(Lexer & lex)
3077 if (!lex.next()) return;
3079 string const tmptok = lex.getString();
3081 // check if tmptok is part of tex_babel in tex-defs.h
3082 if (!setLanguage(tmptok)) {
3083 // Language tmptok was not found
3084 language = default_language;
3085 lyxerr << "Warning: Setting language `"
3086 << tmptok << "' to `" << language->lang()
3092 void BufferParams::readGraphicsDriver(Lexer & lex)
3097 string const tmptok = lex.getString();
3098 // check if tmptok is part of tex_graphics in tex_defs.h
3101 string const test = tex_graphics[n++];
3103 if (test == tmptok) {
3104 graphics_driver = tmptok;
3109 "Warning: graphics driver `$$Token' not recognized!\n"
3110 " Setting graphics driver to `default'.\n");
3111 graphics_driver = "default";
3118 void BufferParams::readBullets(Lexer & lex)
3123 int const index = lex.getInteger();
3125 int temp_int = lex.getInteger();
3126 user_defined_bullet(index).setFont(temp_int);
3127 temp_bullet(index).setFont(temp_int);
3129 user_defined_bullet(index).setCharacter(temp_int);
3130 temp_bullet(index).setCharacter(temp_int);
3132 user_defined_bullet(index).setSize(temp_int);
3133 temp_bullet(index).setSize(temp_int);
3137 void BufferParams::readBulletsLaTeX(Lexer & lex)
3139 // The bullet class should be able to read this.
3142 int const index = lex.getInteger();
3144 docstring const temp_str = lex.getDocString();
3146 user_defined_bullet(index).setText(temp_str);
3147 temp_bullet(index).setText(temp_str);
3151 void BufferParams::readModules(Lexer & lex)
3153 if (!lex.eatLine()) {
3154 lyxerr << "Error (BufferParams::readModules):"
3155 "Unexpected end of input." << endl;
3159 string mod = lex.getString();
3160 if (mod == "\\end_modules")
3162 addLayoutModule(mod);
3168 void BufferParams::readRemovedModules(Lexer & lex)
3170 if (!lex.eatLine()) {
3171 lyxerr << "Error (BufferParams::readRemovedModules):"
3172 "Unexpected end of input." << endl;
3176 string mod = lex.getString();
3177 if (mod == "\\end_removed_modules")
3179 removed_modules_.push_back(mod);
3182 // now we want to remove any removed modules that were previously
3183 // added. normally, that will be because default modules were added in
3184 // setBaseClass(), which gets called when \textclass is read at the
3185 // start of the read.
3186 for (auto const & rm : removed_modules_) {
3187 LayoutModuleList::iterator const mit = layout_modules_.begin();
3188 LayoutModuleList::iterator const men = layout_modules_.end();
3189 LayoutModuleList::iterator found = find(mit, men, rm);
3192 layout_modules_.erase(found);
3197 void BufferParams::readIncludeonly(Lexer & lex)
3199 if (!lex.eatLine()) {
3200 lyxerr << "Error (BufferParams::readIncludeonly):"
3201 "Unexpected end of input." << endl;
3205 string child = lex.getString();
3206 if (child == "\\end_includeonly")
3208 included_children_.push_back(child);
3214 string BufferParams::paperSizeName(PapersizePurpose purpose, string const & psize) const
3216 PAPER_SIZE ppsize = psize.empty() ? papersize : papersizetranslator().find(psize);
3219 if (documentClass().pagesize() == "default")
3220 // could be anything, so don't guess
3222 return paperSizeName(purpose, documentClass().pagesize());
3223 case PAPER_CUSTOM: {
3224 if (purpose == XDVI && !paperwidth.empty() &&
3225 !paperheight.empty()) {
3226 // heightxwidth<unit>
3227 string first = paperwidth;
3228 string second = paperheight;
3229 if (orientation == ORIENTATION_LANDSCAPE)
3232 return first.erase(first.length() - 2)
3238 // dvips and dvipdfm do not know this
3239 if (purpose == DVIPS || purpose == DVIPDFM)
3243 if (purpose == DVIPS || purpose == DVIPDFM)
3247 if (purpose == DVIPS || purpose == DVIPDFM)
3257 if (purpose == DVIPS || purpose == DVIPDFM)
3261 if (purpose == DVIPS || purpose == DVIPDFM)
3265 if (purpose == DVIPS || purpose == DVIPDFM)
3269 if (purpose == DVIPS || purpose == DVIPDFM)
3273 if (purpose == DVIPS || purpose == DVIPDFM)
3277 // dvipdfm does not know this
3278 if (purpose == DVIPDFM)
3282 if (purpose == DVIPDFM)
3286 if (purpose == DVIPS || purpose == DVIPDFM)
3290 if (purpose == DVIPS || purpose == DVIPDFM)
3294 if (purpose == DVIPS || purpose == DVIPDFM)
3298 if (purpose == DVIPS || purpose == DVIPDFM)
3302 if (purpose == DVIPS || purpose == DVIPDFM)
3306 if (purpose == DVIPS || purpose == DVIPDFM)
3310 if (purpose == DVIPS || purpose == DVIPDFM)
3314 if (purpose == DVIPS || purpose == DVIPDFM)
3318 if (purpose == DVIPS || purpose == DVIPDFM)
3322 if (purpose == DVIPS || purpose == DVIPDFM)
3326 if (purpose == DVIPS || purpose == DVIPDFM)
3330 if (purpose == DVIPS || purpose == DVIPDFM)
3334 if (purpose == DVIPS || purpose == DVIPDFM)
3338 if (purpose == DVIPS || purpose == DVIPDFM)
3342 if (purpose == DVIPS || purpose == DVIPDFM)
3345 case PAPER_USEXECUTIVE:
3346 // dvipdfm does not know this
3347 if (purpose == DVIPDFM)
3352 case PAPER_USLETTER:
3354 if (purpose == XDVI)
3361 string const BufferParams::dvips_options() const
3365 // If the class loads the geometry package, we do not know which
3366 // paper size is used, since we do not set it (bug 7013).
3367 // Therefore we must not specify any argument here.
3368 // dvips gets the correct paper size via DVI specials in this case
3369 // (if the class uses the geometry package correctly).
3370 if (documentClass().provides("geometry"))
3374 && papersize == PAPER_CUSTOM
3375 && !lyxrc.print_paper_dimension_flag.empty()
3376 && !paperwidth.empty()
3377 && !paperheight.empty()) {
3378 // using a custom papersize
3379 result = lyxrc.print_paper_dimension_flag;
3380 result += ' ' + paperwidth;
3381 result += ',' + paperheight;
3383 string const paper_option = paperSizeName(DVIPS);
3384 if (!paper_option.empty() && (paper_option != "letter" ||
3385 orientation != ORIENTATION_LANDSCAPE)) {
3386 // dvips won't accept -t letter -t landscape.
3387 // In all other cases, include the paper size
3389 result = lyxrc.print_paper_flag;
3390 result += ' ' + paper_option;
3393 if (orientation == ORIENTATION_LANDSCAPE &&
3394 papersize != PAPER_CUSTOM)
3395 result += ' ' + lyxrc.print_landscape_flag;
3400 string const BufferParams::main_font_encoding() const
3402 vector<string> const fencs = font_encodings();
3403 if (fencs.empty()) {
3404 if (ascii_lowercase(language->fontenc(*this)) == "none")
3408 return fencs.back();
3412 vector<string> const BufferParams::font_encodings() const
3414 string doc_fontenc = (fontenc == "auto") ? string() : fontenc;
3416 vector<string> fontencs;
3418 // "default" means "no explicit font encoding"
3419 if (doc_fontenc != "default") {
3420 if (!doc_fontenc.empty())
3421 // If we have a custom setting, we use only that!
3422 return getVectorFromString(doc_fontenc);
3423 string const lfe = language->fontenc(*this);
3425 && ascii_lowercase(language->fontenc(*this)) != "none") {
3426 vector<string> fencs = getVectorFromString(lfe);
3427 for (auto & fe : fencs) {
3428 if (find(fontencs.begin(), fontencs.end(), fe) == fontencs.end())
3429 fontencs.push_back(fe);
3438 string BufferParams::babelCall(string const & lang_opts, bool const langoptions) const
3440 // suppress the babel call if there is no BabelName defined
3441 // for the document language in the lib/languages file and if no
3442 // other languages are used (lang_opts is then empty)
3443 if (lang_opts.empty())
3445 // The prefs may require the languages to
3446 // be submitted to babel itself (not the class).
3448 return "\\usepackage[" + lang_opts + "]{babel}";
3449 return "\\usepackage{babel}";
3453 docstring BufferParams::getGraphicsDriver(string const & package) const
3457 if (package == "geometry") {
3458 if (graphics_driver == "dvips"
3459 || graphics_driver == "dvipdfm"
3460 || graphics_driver == "pdftex"
3461 || graphics_driver == "vtex")
3462 result = from_ascii(graphics_driver);
3463 else if (graphics_driver == "dvipdfmx")
3464 result = from_ascii("dvipdfm");
3471 void BufferParams::writeEncodingPreamble(otexstream & os,
3472 LaTeXFeatures & features) const
3474 // With no-TeX fonts we use utf8-plain without encoding package.
3478 string const doc_encoding = encoding().latexName();
3479 Encoding::Package const package = encoding().package();
3480 // (dvi)lualatex uses luainputenc rather than inputenc
3481 string const inputenc_package =
3482 (features.runparams().flavor == Flavor::LuaTeX
3483 || features.runparams().flavor == Flavor::DviLuaTeX)
3484 ? "luainputenc" : "inputenc";
3486 if (inputenc == "auto-legacy") {
3487 // The "japanese" babel language requires the pLaTeX engine
3488 // which conflicts with "inputenc".
3489 // See http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129680.html
3490 if (!features.isRequired("japanese")
3491 && !features.isProvided("inputenc")) {
3492 if (package == Encoding::inputenc) {
3493 // Main language requires (lua)inputenc
3494 os << "\\usepackage[" << doc_encoding << "]{"
3495 << inputenc_package << "}\n";
3497 // We might have an additional language that requires inputenc
3498 set<string> encoding_set = features.getEncodingSet(doc_encoding);
3499 bool inputenc = false;
3500 for (auto const & enc : encoding_set) {
3501 if (encodings.fromLaTeXName(enc)
3502 && encodings.fromLaTeXName(enc)->package() == Encoding::inputenc) {
3508 // load (lua)inputenc without options
3509 // (the encoding is loaded later)
3510 os << "\\usepackage{" << inputenc_package << "}\n";
3513 } else if (inputenc != "auto-legacy-plain") {
3515 case Encoding::none:
3517 case Encoding::japanese:
3518 if (encoding().iconvName() != "UTF-8"
3519 && !features.runparams().isFullUnicode()
3520 && features.isAvailableAtLeastFrom("LaTeX", 2018, 4))
3521 // don't default to [utf8]{inputenc} with LaTeX >= 2018/04
3522 os << "\\UseRawInputEncoding\n";
3524 case Encoding::inputenc:
3525 // do not load inputenc if japanese is used
3526 // or if the class provides inputenc
3527 if (features.isRequired("japanese")
3528 || features.isProvided("inputenc"))
3530 // The 2022 release of ucs.sty uses the default utf8
3531 // inputenc encoding with 'utf8x' inputenc if the ucs
3532 // package is not loaded before inputenc.
3533 // This breaks existing documents that use utf8x
3534 // and also makes utf8x redundant.
3535 // Thus we load ucs.sty in order to keep functionality
3536 // that would otherwise be silently dropped.
3537 if (doc_encoding == "utf8x"
3538 && features.isAvailableAtLeastFrom("ucs", 2022, 8, 7)
3539 && !features.isProvided("ucs"))
3540 os << "\\usepackage{ucs}\n";
3541 os << "\\usepackage[" << doc_encoding << "]{"
3542 << inputenc_package << "}\n";
3546 if ((inputenc == "auto-legacy-plain" || features.isRequired("japanese"))
3547 && features.isAvailableAtLeastFrom("LaTeX", 2018, 4))
3548 // don't default to [utf8]{inputenc} with LaTeX >= 2018/04
3549 os << "\\UseRawInputEncoding\n";
3553 string const BufferParams::parseFontName(string const & name) const
3555 string mangled = name;
3556 size_t const idx = mangled.find('[');
3557 if (idx == string::npos || idx == 0)
3560 return mangled.substr(0, idx - 1);
3564 string const BufferParams::loadFonts(LaTeXFeatures & features) const
3566 if (fontsRoman() == "default" && fontsSans() == "default"
3567 && fontsTypewriter() == "default"
3568 && (fontsMath() == "default" || fontsMath() == "auto"))
3574 /* Fontspec (XeTeX, LuaTeX): we provide GUI support for oldstyle
3575 * numbers (Numbers=OldStyle) and sf/tt scaling. The Ligatures=TeX/
3576 * Mapping=tex-text option assures TeX ligatures (such as "--")
3577 * are resolved. Note that tt does not use these ligatures.
3579 * -- add more GUI options?
3580 * -- add more fonts (fonts for other scripts)
3581 * -- if there's a way to find out if a font really supports
3582 * OldStyle, enable/disable the widget accordingly.
3584 if (useNonTeXFonts && features.isAvailable("fontspec")) {
3585 // "Mapping=tex-text" and "Ligatures=TeX" are equivalent.
3586 // However, until v.2 (2010/07/11) fontspec only knew
3587 // Mapping=tex-text (for XeTeX only); then "Ligatures=TeX"
3588 // was introduced for both XeTeX and LuaTeX (LuaTeX
3589 // didn't understand "Mapping=tex-text", while XeTeX
3590 // understood both. With most recent versions, both
3591 // variants are understood by both engines. However,
3592 // we want to provide support for at least TeXLive 2009
3593 // (for XeTeX; LuaTeX is only supported as of v.2)
3594 // As of 2017/11/03, Babel has its own higher-level
3595 // interface on top of fontspec that is to be used.
3596 bool const babelfonts = features.useBabel()
3597 && features.isAvailableAtLeastFrom("babel", 2017, 11, 3);
3598 string const texmapping =
3599 (features.runparams().flavor == Flavor::XeTeX) ?
3600 "Mapping=tex-text" : "Ligatures=TeX";
3601 if (fontsRoman() != "default") {
3603 os << "\\babelfont{rm}[";
3605 os << "\\setmainfont[";
3607 if (fonts_roman_osf)
3608 os << ",Numbers=OldStyle";
3609 if (!font_roman_opts.empty())
3610 os << ',' << font_roman_opts;
3611 os << "]{" << parseFontName(fontsRoman()) << "}\n";
3613 if (fontsSans() != "default") {
3614 string const sans = parseFontName(fontsSans());
3615 if (fontsSansScale() != 100) {
3617 os << "\\babelfont{sf}";
3619 os << "\\setsansfont";
3621 << float(fontsSansScale()) / 100 << ',';
3623 os << "Numbers=OldStyle,";
3625 if (!font_sans_opts.empty())
3626 os << ',' << font_sans_opts;
3627 os << "]{" << sans << "}\n";
3630 os << "\\babelfont{sf}[";
3632 os << "\\setsansfont[";
3634 os << "Numbers=OldStyle,";
3636 if (!font_sans_opts.empty())
3637 os << ',' << font_sans_opts;
3638 os << "]{" << sans << "}\n";
3641 if (fontsTypewriter() != "default") {
3642 string const mono = parseFontName(fontsTypewriter());
3643 if (fontsTypewriterScale() != 100) {
3645 os << "\\babelfont{tt}";
3647 os << "\\setmonofont";
3649 << float(fontsTypewriterScale()) / 100;
3650 if (fonts_typewriter_osf)
3651 os << ",Numbers=OldStyle";
3652 if (!font_typewriter_opts.empty())
3653 os << ',' << font_typewriter_opts;
3658 os << "\\babelfont{tt}";
3660 os << "\\setmonofont";
3661 if (!font_typewriter_opts.empty() || fonts_typewriter_osf) {
3663 if (fonts_typewriter_osf)
3664 os << "Numbers=OldStyle";
3665 if (!font_typewriter_opts.empty()) {
3666 if (fonts_typewriter_osf)
3668 os << font_typewriter_opts;
3672 os << '{' << mono << "}\n";
3679 bool const ot1 = (features.runparams().main_fontenc == "default"
3680 || features.runparams().main_fontenc == "OT1");
3681 bool const dryrun = features.runparams().dryrun;
3682 bool const complete = (fontsSans() == "default" && fontsTypewriter() == "default");
3683 bool const nomath = (fontsMath() != "auto");
3686 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsRoman())).getLaTeXCode(
3687 dryrun, ot1, complete, fonts_expert_sc, fonts_roman_osf,
3688 nomath, font_roman_opts);
3691 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsSans())).getLaTeXCode(
3692 dryrun, ot1, complete, fonts_expert_sc, fonts_sans_osf,
3693 nomath, font_sans_opts, fontsSansScale());
3695 // MONOSPACED/TYPEWRITER
3696 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsTypewriter())).getLaTeXCode(
3697 dryrun, ot1, complete, fonts_expert_sc, fonts_typewriter_osf,
3698 nomath, font_typewriter_opts, fontsTypewriterScale());
3701 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsMath())).getLaTeXCode(
3702 dryrun, ot1, complete, fonts_expert_sc, fonts_roman_osf,
3709 Encoding const & BufferParams::encoding() const
3711 // Main encoding for LaTeX output.
3713 return *(encodings.fromLyXName("utf8-plain"));
3714 if (inputenc == "auto-legacy" || inputenc == "auto-legacy-plain")
3715 return *language->encoding();
3716 if (inputenc == "utf8" && language->lang() == "japanese")
3717 return *(encodings.fromLyXName("utf8-platex"));
3718 Encoding const * const enc = encodings.fromLyXName(inputenc);
3721 LYXERR0("Unknown inputenc value `" << inputenc
3722 << "'. Using `auto' instead.");
3723 return *language->encoding();
3727 string const & BufferParams::defaultBiblioStyle() const
3729 if (!biblio_style.empty())
3730 return biblio_style;
3732 map<string, string> const & bs = documentClass().defaultBiblioStyle();
3733 auto cit = bs.find(theCiteEnginesList.getTypeAsString(citeEngineType()));
3734 if (cit != bs.end())
3737 return empty_string();
3741 bool BufferParams::fullAuthorList() const
3743 return documentClass().fullAuthorList();
3747 string BufferParams::getCiteAlias(string const & s) const
3749 vector<string> commands =
3750 documentClass().citeCommands(citeEngineType());
3751 // If it is a real command, don't treat it as an alias
3752 if (find(commands.begin(), commands.end(), s) != commands.end())
3754 map<string,string> aliases = documentClass().citeCommandAliases();
3755 if (aliases.find(s) != aliases.end())
3761 vector<string> BufferParams::citeCommands() const
3763 static CitationStyle const default_style;
3764 vector<string> commands =
3765 documentClass().citeCommands(citeEngineType());
3766 if (commands.empty())
3767 commands.push_back(default_style.name);
3772 vector<CitationStyle> BufferParams::citeStyles() const
3774 static CitationStyle const default_style;
3775 vector<CitationStyle> styles =
3776 documentClass().citeStyles(citeEngineType());
3778 styles.push_back(default_style);
3783 string const BufferParams::getBibtexCommand(string const cmd, bool const warn) const
3785 // split from options
3787 split(cmd, command_in, ' ');
3789 // Look if the requested command is available. If so, use that.
3790 for (auto const & alts : lyxrc.bibtex_alternatives) {
3791 string command_prov;
3792 split(alts, command_prov, ' ');
3793 if (command_in == command_prov)
3797 // If not, find the most suitable fallback for the current cite framework,
3798 // and warn. Note that we omit options in any such case.
3800 if (useBiblatex()) {
3801 // For Biblatex, we prefer biber (also for Japanese)
3802 // and try to fall back to bibtex8
3803 if (lyxrc.bibtex_alternatives.find("biber") != lyxrc.bibtex_alternatives.end())
3805 else if (lyxrc.bibtex_alternatives.find("bibtex8") != lyxrc.bibtex_alternatives.end())
3806 fallback = "bibtex8";
3808 // For classic BibTeX and as last resort for biblatex, try bibtex
3809 if (fallback.empty()) {
3810 if (lyxrc.bibtex_alternatives.find("bibtex") != lyxrc.bibtex_alternatives.end())
3811 fallback = "bibtex";
3817 if (fallback.empty()) {
3818 frontend::Alert::warning(
3819 _("No bibliography processor found!"),
3821 _("The bibliography processor requested by this document "
3822 "(%1$s) is not available and no appropriate "
3823 "alternative has been found. "
3824 "No bibliography and references will be generated.\n"
3825 "Please fix your installation!"),
3828 frontend::Alert::warning(
3829 _("Requested bibliography processor not found!"),
3831 _("The bibliography processor requested by this document "
3832 "(%1$s) is not available. "
3833 "As a fallback, '%2$s' will be used, options are omitted. "
3834 "This might result in errors or unwanted changes in "
3835 "the bibliography. Please check carefully!\n"
3836 "It is suggested to install the missing processor."),
3837 from_utf8(cmd), from_utf8(fallback)));
3843 string const BufferParams::bibtexCommand(bool const warn) const
3845 // Return document-specific setting if available
3846 if (bibtex_command != "default")
3847 return getBibtexCommand(bibtex_command, warn);
3849 // If we have "default" in document settings, consult the prefs
3850 // 1. Japanese (uses a specific processor)
3851 if (encoding().package() == Encoding::japanese) {
3852 if (lyxrc.jbibtex_command != "automatic")
3853 // Return the specified program, if "automatic" is not set
3854 return lyxrc.jbibtex_command;
3855 else if (!useBiblatex()) {
3856 // With classic BibTeX, return pbibtex, jbibtex, bibtex
3857 if (lyxrc.jbibtex_alternatives.find("pbibtex") != lyxrc.jbibtex_alternatives.end())
3859 if (lyxrc.jbibtex_alternatives.find("jbibtex") != lyxrc.jbibtex_alternatives.end())
3864 // 2. All other languages
3865 else if (lyxrc.bibtex_command != "automatic")
3866 // Return the specified program, if "automatic" is not set
3867 return getBibtexCommand(lyxrc.bibtex_command, warn);
3869 // 3. Automatic: find the most suitable for the current cite framework
3870 if (useBiblatex()) {
3871 // For Biblatex, we prefer biber (also for Japanese)
3872 // and fall back to bibtex8 and, as last resort, bibtex
3873 if (lyxrc.bibtex_alternatives.find("biber") != lyxrc.bibtex_alternatives.end())
3875 else if (lyxrc.bibtex_alternatives.find("bibtex8") != lyxrc.bibtex_alternatives.end())
3882 bool BufferParams::useBiblatex() const
3884 return theCiteEnginesList[citeEngine()]->getCiteFramework() == "biblatex";
3888 void BufferParams::invalidateConverterCache() const
3890 pimpl_->isExportCacheValid = false;
3891 pimpl_->isViewCacheValid = false;
3895 // We shouldn't need to reset the params here, since anything
3896 // we need will be recopied.
3897 void BufferParams::copyForAdvFR(const BufferParams & bp)
3899 string const & lang = bp.language->lang();
3901 quotes_style = bp.quotes_style;
3902 layout_modules_ = bp.layout_modules_;
3903 string const & doc_class = bp.documentClass().name();
3904 setBaseClass(doc_class);
3908 void BufferParams::setBibFileEncoding(string const & file, string const & enc)
3910 bib_encodings[file] = enc;
3914 string const BufferParams::bibFileEncoding(string const & file) const
3916 if (bib_encodings.find(file) == bib_encodings.end())
3918 return bib_encodings.find(file)->second;
3922 BufferParams const & defaultBufferParams()
3924 static BufferParams default_params;
3925 return default_params;