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"
24 #include "buffer_funcs.h"
26 #include "CiteEnginesList.h"
29 #include "Converter.h"
31 #include "IndicesList.h"
33 #include "LaTeXFeatures.h"
34 #include "LaTeXFonts.h"
35 #include "ModuleList.h"
39 #include "OutputParams.h"
41 #include "texstream.h"
44 #include "PDFOptions.h"
46 #include "frontends/alert.h"
48 #include "insets/InsetListingsParams.h"
50 #include "support/convert.h"
51 #include "support/debug.h"
52 #include "support/docstream.h"
53 #include "support/FileName.h"
54 #include "support/filetools.h"
55 #include "support/gettext.h"
56 #include "support/Length.h"
57 #include "support/Messages.h"
58 #include "support/mutex.h"
59 #include "support/Package.h"
60 #include "support/Translator.h"
61 #include "support/lstrings.h"
67 using namespace lyx::support;
70 static char const * const string_paragraph_separation[] = {
75 static char const * const string_quotes_style[] = {
76 "english", "swedish", "german", "polish", "swiss", "danish", "plain",
77 "british", "swedishg", "french", "frenchin", "russian", "cjk", "cjkangle", ""
81 static char const * const string_papersize[] = {
82 "default", "custom", "letter", "legal", "executive",
83 "a0", "a1", "a2", "a3", "a4", "a5", "a6",
84 "b0", "b1", "b2", "b3", "b4", "b5", "b6",
85 "c0", "c1", "c2", "c3", "c4", "c5", "c6",
86 "b0j", "b1j", "b2j", "b3j", "b4j", "b5j", "b6j", ""
90 static char const * const string_papersize_geometry[] = {
91 "default", "custom", "letterpaper", "legalpaper", "executivepaper",
92 "a0paper", "a1paper", "a2paper", "a3paper", "a4paper", "a5paper", "a6paper",
93 "b0paper", "b1paper", "b2paper", "b3paper", "b4paper", "b5paper", "b6paper",
94 "c0paper", "c1paper", "c2paper", "c3paper", "c4paper", "c5paper", "c6paper",
95 "b0j", "b1j", "b2j", "b3j", "b4j", "b5j", "b6j", ""
99 static char const * const string_orientation[] = {
100 "portrait", "landscape", ""
104 static char const * const tex_graphics[] = {
105 "default", "dvialw", "dvilaser", "dvipdf", "dvipdfm", "dvipdfmx",
106 "dvips", "dvipsone", "dvitops", "dviwin", "dviwindo", "dvi2ps", "emtex",
107 "ln", "oztex", "pctexhp", "pctexps", "pctexwin", "pctex32", "pdftex",
108 "psprint", "pubps", "tcidvi", "textures", "truetex", "vtex", "xdvi",
118 // Paragraph separation
119 typedef Translator<string, BufferParams::ParagraphSeparation> ParSepTranslator;
122 ParSepTranslator const init_parseptranslator()
124 ParSepTranslator translator
125 (string_paragraph_separation[0], BufferParams::ParagraphIndentSeparation);
126 translator.addPair(string_paragraph_separation[1], BufferParams::ParagraphSkipSeparation);
131 ParSepTranslator const & parseptranslator()
133 static ParSepTranslator const translator =
134 init_parseptranslator();
140 typedef Translator<string, InsetQuotesParams::QuoteStyle> QuotesStyleTranslator;
143 QuotesStyleTranslator const init_quotesstyletranslator()
145 QuotesStyleTranslator translator
146 (string_quotes_style[0], InsetQuotesParams::EnglishQuotes);
147 translator.addPair(string_quotes_style[1], InsetQuotesParams::SwedishQuotes);
148 translator.addPair(string_quotes_style[2], InsetQuotesParams::GermanQuotes);
149 translator.addPair(string_quotes_style[3], InsetQuotesParams::PolishQuotes);
150 translator.addPair(string_quotes_style[4], InsetQuotesParams::SwissQuotes);
151 translator.addPair(string_quotes_style[5], InsetQuotesParams::DanishQuotes);
152 translator.addPair(string_quotes_style[6], InsetQuotesParams::PlainQuotes);
153 translator.addPair(string_quotes_style[7], InsetQuotesParams::BritishQuotes);
154 translator.addPair(string_quotes_style[8], InsetQuotesParams::SwedishGQuotes);
155 translator.addPair(string_quotes_style[9], InsetQuotesParams::FrenchQuotes);
156 translator.addPair(string_quotes_style[10], InsetQuotesParams::FrenchINQuotes);
157 translator.addPair(string_quotes_style[11], InsetQuotesParams::RussianQuotes);
158 translator.addPair(string_quotes_style[12], InsetQuotesParams::CJKQuotes);
159 translator.addPair(string_quotes_style[13], InsetQuotesParams::CJKAngleQuotes);
164 QuotesStyleTranslator const & quotesstyletranslator()
166 static QuotesStyleTranslator const translator =
167 init_quotesstyletranslator();
173 typedef Translator<string, PAPER_SIZE> PaperSizeTranslator;
176 static PaperSizeTranslator initPaperSizeTranslator()
178 PaperSizeTranslator translator(string_papersize[0], PAPER_DEFAULT);
179 translator.addPair(string_papersize[1], PAPER_CUSTOM);
180 translator.addPair(string_papersize[2], PAPER_USLETTER);
181 translator.addPair(string_papersize[3], PAPER_USLEGAL);
182 translator.addPair(string_papersize[4], PAPER_USEXECUTIVE);
183 translator.addPair(string_papersize[5], PAPER_A0);
184 translator.addPair(string_papersize[6], PAPER_A1);
185 translator.addPair(string_papersize[7], PAPER_A2);
186 translator.addPair(string_papersize[8], PAPER_A3);
187 translator.addPair(string_papersize[9], PAPER_A4);
188 translator.addPair(string_papersize[10], PAPER_A5);
189 translator.addPair(string_papersize[11], PAPER_A6);
190 translator.addPair(string_papersize[12], PAPER_B0);
191 translator.addPair(string_papersize[13], PAPER_B1);
192 translator.addPair(string_papersize[14], PAPER_B2);
193 translator.addPair(string_papersize[15], PAPER_B3);
194 translator.addPair(string_papersize[16], PAPER_B4);
195 translator.addPair(string_papersize[17], PAPER_B5);
196 translator.addPair(string_papersize[18], PAPER_B6);
197 translator.addPair(string_papersize[19], PAPER_C0);
198 translator.addPair(string_papersize[20], PAPER_C1);
199 translator.addPair(string_papersize[21], PAPER_C2);
200 translator.addPair(string_papersize[22], PAPER_C3);
201 translator.addPair(string_papersize[23], PAPER_C4);
202 translator.addPair(string_papersize[24], PAPER_C5);
203 translator.addPair(string_papersize[25], PAPER_C6);
204 translator.addPair(string_papersize[26], PAPER_JISB0);
205 translator.addPair(string_papersize[27], PAPER_JISB1);
206 translator.addPair(string_papersize[28], PAPER_JISB2);
207 translator.addPair(string_papersize[29], PAPER_JISB3);
208 translator.addPair(string_papersize[30], PAPER_JISB4);
209 translator.addPair(string_papersize[31], PAPER_JISB5);
210 translator.addPair(string_papersize[32], PAPER_JISB6);
215 PaperSizeTranslator const & papersizetranslator()
217 static PaperSizeTranslator const translator =
218 initPaperSizeTranslator();
224 typedef Translator<string, PAPER_ORIENTATION> PaperOrientationTranslator;
227 PaperOrientationTranslator const init_paperorientationtranslator()
229 PaperOrientationTranslator translator(string_orientation[0], ORIENTATION_PORTRAIT);
230 translator.addPair(string_orientation[1], ORIENTATION_LANDSCAPE);
235 PaperOrientationTranslator const & paperorientationtranslator()
237 static PaperOrientationTranslator const translator =
238 init_paperorientationtranslator();
244 typedef Translator<int, PageSides> SidesTranslator;
247 SidesTranslator const init_sidestranslator()
249 SidesTranslator translator(1, OneSide);
250 translator.addPair(2, TwoSides);
255 SidesTranslator const & sidestranslator()
257 static SidesTranslator const translator = init_sidestranslator();
263 typedef Translator<int, BufferParams::Package> PackageTranslator;
266 PackageTranslator const init_packagetranslator()
268 PackageTranslator translator(0, BufferParams::package_off);
269 translator.addPair(1, BufferParams::package_auto);
270 translator.addPair(2, BufferParams::package_on);
275 PackageTranslator const & packagetranslator()
277 static PackageTranslator const translator =
278 init_packagetranslator();
284 typedef Translator<string, Spacing::Space> SpaceTranslator;
287 SpaceTranslator const init_spacetranslator()
289 SpaceTranslator translator("default", Spacing::Default);
290 translator.addPair("single", Spacing::Single);
291 translator.addPair("onehalf", Spacing::Onehalf);
292 translator.addPair("double", Spacing::Double);
293 translator.addPair("other", Spacing::Other);
298 SpaceTranslator const & spacetranslator()
300 static SpaceTranslator const translator = init_spacetranslator();
305 bool inSystemDir(FileName const & document_dir, string & system_dir)
307 // A document is assumed to be in a system LyX directory (not
308 // necessarily the system directory of the running instance)
309 // if both "configure.py" and "chkconfig.ltx" are found in
310 // either document_dir/../ or document_dir/../../.
311 // If true, the system directory path is returned in system_dir
312 // with a trailing path separator.
314 string const msg = "Checking whether document is in a system dir...";
316 string dir = document_dir.absFileName();
318 for (int i = 0; i < 3; ++i) {
319 dir = addPath(dir, "..");
320 if (!fileSearch(dir, "configure.py").empty() &&
321 !fileSearch(dir, "chkconfig.ltx").empty()) {
322 LYXERR(Debug::FILES, msg << " yes");
323 system_dir = addPath(FileName(dir).realPath(), "");
328 LYXERR(Debug::FILES, msg << " no");
329 system_dir = string();
336 class BufferParams::Impl
341 AuthorList authorlist;
342 BranchList branchlist;
343 Bullet temp_bullets[4];
344 Bullet user_defined_bullets[4];
345 IndicesList indiceslist;
349 /** This is the amount of space used for paragraph_separation "skip",
350 * and for detached paragraphs in "indented" documents.
353 PDFOptions pdfoptions;
354 LayoutFileIndex baseClass_;
355 FormatList exportableFormatList;
356 FormatList viewableFormatList;
357 bool isViewCacheValid;
358 bool isExportCacheValid;
362 BufferParams::Impl::Impl()
363 : defskip(VSpace::MEDSKIP), baseClass_(string("")),
364 isViewCacheValid(false), isExportCacheValid(false)
366 // set initial author
368 authorlist.record(Author(from_utf8(lyxrc.user_name),
369 from_utf8(lyxrc.user_email),
370 from_utf8(lyxrc.user_initials)));
375 BufferParams::MemoryTraits::clone(BufferParams::Impl const * ptr)
378 return new BufferParams::Impl(*ptr);
382 void BufferParams::MemoryTraits::destroy(BufferParams::Impl * ptr)
388 BufferParams::BufferParams()
391 setBaseClass(defaultBaseclass());
392 cite_engine_ = "basic";
393 cite_engine_type_ = ENGINE_TYPE_DEFAULT;
395 paragraph_separation = ParagraphIndentSeparation;
396 is_math_indent = false;
397 math_numbering_side = DEFAULT;
398 quotes_style = InsetQuotesParams::EnglishQuotes;
399 dynamic_quotes = false;
400 fontsize = "default";
403 papersize = PAPER_DEFAULT;
404 orientation = ORIENTATION_PORTRAIT;
405 use_geometry = false;
406 biblio_style = string();
407 use_bibtopic = false;
410 save_transient_properties = true;
411 track_changes = false;
412 output_changes = false;
414 postpone_fragile_content = true;
415 use_default_options = true;
416 maintain_unincluded_children = CM_None;
419 language = default_language;
421 fonts_roman[0] = "default";
422 fonts_roman[1] = "default";
423 fonts_sans[0] = "default";
424 fonts_sans[1] = "default";
425 fonts_typewriter[0] = "default";
426 fonts_typewriter[1] = "default";
427 fonts_math[0] = "auto";
428 fonts_math[1] = "auto";
429 fonts_default_family = "default";
430 useNonTeXFonts = false;
431 use_microtype = false;
432 use_dash_ligatures = true;
433 fonts_expert_sc = false;
434 fonts_roman_osf = false;
435 fonts_sans_osf = false;
436 fonts_typewriter_osf = false;
437 fonts_sans_scale[0] = 100;
438 fonts_sans_scale[1] = 100;
439 fonts_typewriter_scale[0] = 100;
440 fonts_typewriter_scale[1] = 100;
442 lang_package = "default";
443 graphics_driver = "default";
444 default_output_format = "default";
445 bibtex_command = "default";
446 index_command = "default";
449 listings_params = string();
450 pagestyle = "default";
451 tablestyle = "default";
452 float_alignment = "class";
453 float_placement = "class";
454 suppress_date = false;
455 justification = true;
456 // no color is the default (white)
457 backgroundcolor = lyx::rgbFromHexName("#ffffff");
458 isbackgroundcolor = false;
459 // no color is the default (black)
460 fontcolor = lyx::rgbFromHexName("#000000");
462 // light gray is the default font color for greyed-out notes
463 notefontcolor = lyx::rgbFromHexName("#cccccc");
464 boxbgcolor = lyx::rgbFromHexName("#ff0000");
465 compressed = lyxrc.save_compressed;
466 for (int iter = 0; iter < 4; ++iter) {
467 user_defined_bullet(iter) = ITEMIZE_DEFAULTS[iter];
468 temp_bullet(iter) = ITEMIZE_DEFAULTS[iter];
471 indiceslist().addDefault(B_("Index"));
472 html_be_strict = false;
473 html_math_output = MathML;
474 html_math_img_scale = 1.0;
475 html_css_as_file = false;
476 docbook_table_output = HTMLTable;
477 display_pixel_ratio = 1.0;
479 shell_escape = false;
485 // map current author
486 author_map_[pimpl_->authorlist.get(0).bufferId()] = 0;
490 docstring BufferParams::B_(string const & l10n) const
492 LASSERT(language, return from_utf8(l10n));
493 return getMessages(language->code()).get(l10n);
497 BufferParams::Package BufferParams::use_package(std::string const & p) const
499 PackageMap::const_iterator it = use_packages.find(p);
500 if (it == use_packages.end())
506 void BufferParams::use_package(std::string const & p, BufferParams::Package u)
512 map<string, string> const & BufferParams::auto_packages()
514 static map<string, string> packages;
515 if (packages.empty()) {
516 // We could have a race condition here that two threads
517 // discover an empty map at the same time and want to fill
518 // it, but that is no problem, since the same contents is
519 // filled in twice then. Having the locker inside the
520 // packages.empty() condition has the advantage that we
521 // don't need the mutex overhead for simple reading.
523 Mutex::Locker locker(&mutex);
524 // adding a package here implies a file format change!
525 packages["amsmath"] =
526 N_("The LaTeX package amsmath is only used if AMS formula types or symbols from the AMS math toolbars are inserted into formulas");
527 packages["amssymb"] =
528 N_("The LaTeX package amssymb is only used if symbols from the AMS math toolbars are inserted into formulas");
530 N_("The LaTeX package cancel is only used if \\cancel commands are used in formulas");
532 N_("The LaTeX package esint is only used if special integral symbols are inserted into formulas");
533 packages["mathdots"] =
534 N_("The LaTeX package mathdots is only used if the command \\iddots is inserted into formulas");
535 packages["mathtools"] =
536 N_("The LaTeX package mathtools is only used if some mathematical relations are inserted into formulas");
538 N_("The LaTeX package mhchem is only used if either the command \\ce or \\cf is inserted into formulas");
539 packages["stackrel"] =
540 N_("The LaTeX package stackrel is only used if the command \\stackrel with subscript is inserted into formulas");
541 packages["stmaryrd"] =
542 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");
543 packages["undertilde"] =
544 N_("The LaTeX package undertilde is only used if you use the math frame decoration 'utilde'");
550 bool BufferParams::useBibtopic() const
554 return (use_bibtopic || (!multibib.empty() && multibib != "child"));
558 AuthorList & BufferParams::authors()
560 return pimpl_->authorlist;
564 AuthorList const & BufferParams::authors() const
566 return pimpl_->authorlist;
570 void BufferParams::addAuthor(Author a)
572 author_map_[a.bufferId()] = pimpl_->authorlist.record(a);
576 BranchList & BufferParams::branchlist()
578 return pimpl_->branchlist;
582 BranchList const & BufferParams::branchlist() const
584 return pimpl_->branchlist;
588 IndicesList & BufferParams::indiceslist()
590 return pimpl_->indiceslist;
594 IndicesList const & BufferParams::indiceslist() const
596 return pimpl_->indiceslist;
600 Bullet & BufferParams::temp_bullet(lyx::size_type const index)
602 LASSERT(index < 4, return pimpl_->temp_bullets[0]);
603 return pimpl_->temp_bullets[index];
607 Bullet const & BufferParams::temp_bullet(lyx::size_type const index) const
609 LASSERT(index < 4, return pimpl_->temp_bullets[0]);
610 return pimpl_->temp_bullets[index];
614 Bullet & BufferParams::user_defined_bullet(lyx::size_type const index)
616 LASSERT(index < 4, return pimpl_->temp_bullets[0]);
617 return pimpl_->user_defined_bullets[index];
621 Bullet const & BufferParams::user_defined_bullet(lyx::size_type const index) const
623 LASSERT(index < 4, return pimpl_->temp_bullets[0]);
624 return pimpl_->user_defined_bullets[index];
628 Spacing & BufferParams::spacing()
630 return pimpl_->spacing;
634 Spacing const & BufferParams::spacing() const
636 return pimpl_->spacing;
640 PDFOptions & BufferParams::pdfoptions()
642 return pimpl_->pdfoptions;
646 PDFOptions const & BufferParams::pdfoptions() const
648 return pimpl_->pdfoptions;
652 Length const & BufferParams::getMathIndent() const
654 return pimpl_->mathindent;
658 void BufferParams::setMathIndent(Length const & indent)
660 pimpl_->mathindent = indent;
664 Length const & BufferParams::getParIndent() const
666 return pimpl_->parindent;
670 void BufferParams::setParIndent(Length const & indent)
672 pimpl_->parindent = indent;
676 VSpace const & BufferParams::getDefSkip() const
678 return pimpl_->defskip;
682 void BufferParams::setDefSkip(VSpace const & vs)
684 // DEFSKIP will cause an infinite loop
685 LASSERT(vs.kind() != VSpace::DEFSKIP, return);
686 pimpl_->defskip = vs;
690 BufferParams::MathNumber BufferParams::getMathNumber() const
692 if (math_numbering_side != DEFAULT)
693 return math_numbering_side;
694 // FIXME: do not hardcode language here
695 else if (language->lang() == "arabic_arabi"
696 || documentClass().provides("leqno"))
703 string BufferParams::readToken(Lexer & lex, string const & token,
704 FileName const & filepath)
708 if (token == "\\textclass") {
710 string const classname = lex.getString();
711 // if there exists a local layout file, ignore the system one
712 // NOTE: in this case, the textclass (.cls file) is assumed to
715 LayoutFileList & bcl = LayoutFileList::get();
716 if (!filepath.empty()) {
717 // If classname is an absolute path, the document is
718 // using a local layout file which could not be accessed
719 // by a relative path. In this case the path is correct
720 // even if the document was moved to a different
721 // location. However, we will have a problem if the
722 // document was generated on a different platform.
723 bool isabsolute = FileName::isAbsolute(classname);
724 string const classpath = onlyPath(classname);
725 string const path = isabsolute ? classpath
726 : FileName(addPath(filepath.absFileName(),
727 classpath)).realPath();
728 string const oldpath = isabsolute ? string()
729 : FileName(addPath(origin, classpath)).realPath();
730 tcp = bcl.addLocalLayout(onlyFileName(classname), path, oldpath);
732 // that returns non-empty if a "local" layout file is found.
734 result = to_utf8(makeRelPath(from_utf8(onlyPath(tcp)),
735 from_utf8(filepath.absFileName())));
738 setBaseClass(onlyFileName(tcp));
740 setBaseClass(onlyFileName(classname));
741 // We assume that a tex class exists for local or unknown
742 // layouts so this warning, will only be given for system layouts.
743 if (!baseClass()->isTeXClassAvailable()) {
744 docstring const desc =
745 translateIfPossible(from_utf8(baseClass()->description()));
746 docstring const prereqs =
747 from_utf8(baseClass()->prerequisites());
748 docstring const msg =
749 bformat(_("The selected document class\n"
751 "requires external files that are not available.\n"
752 "The document class can still be used, but the\n"
753 "document cannot be compiled until the following\n"
754 "prerequisites are installed:\n"
756 "See section 3.1.2.2 (Class Availability) of the\n"
757 "User's Guide for more information."), desc, prereqs);
758 frontend::Alert::warning(_("Document class not available"),
761 } else if (token == "\\save_transient_properties") {
762 lex >> save_transient_properties;
763 } else if (token == "\\origin") {
765 origin = lex.getString();
766 string const sysdirprefix = "/systemlyxdir/";
767 if (prefixIs(origin, sysdirprefix)) {
769 if (inSystemDir(filepath, docsys))
770 origin.replace(0, sysdirprefix.length() - 1, docsys);
772 origin.replace(0, sysdirprefix.length() - 1,
773 package().system_support().absFileName());
775 } else if (token == "\\begin_preamble") {
777 } else if (token == "\\begin_local_layout") {
778 readLocalLayout(lex, false);
779 } else if (token == "\\begin_forced_local_layout") {
780 readLocalLayout(lex, true);
781 } else if (token == "\\begin_modules") {
783 } else if (token == "\\begin_removed_modules") {
784 readRemovedModules(lex);
785 } else if (token == "\\begin_includeonly") {
786 readIncludeonly(lex);
787 } else if (token == "\\maintain_unincluded_children") {
791 maintain_unincluded_children = CM_None;
792 else if (tmp == "mostly")
793 maintain_unincluded_children = CM_Mostly;
794 else if (tmp == "strict")
795 maintain_unincluded_children = CM_Strict;
796 } else if (token == "\\options") {
798 options = lex.getString();
799 } else if (token == "\\use_default_options") {
800 lex >> use_default_options;
801 } else if (token == "\\master") {
803 master = lex.getString();
804 if (!filepath.empty() && FileName::isAbsolute(origin)) {
805 bool const isabs = FileName::isAbsolute(master);
806 FileName const abspath(isabs ? master : origin + master);
807 bool const moved = filepath != FileName(origin);
808 if (moved && abspath.exists()) {
809 docstring const path = isabs
811 : from_utf8(abspath.realPath());
812 docstring const refpath =
813 from_utf8(filepath.absFileName());
814 master = to_utf8(makeRelPath(path, refpath));
817 } else if (token == "\\suppress_date") {
818 lex >> suppress_date;
819 } else if (token == "\\justification") {
820 lex >> justification;
821 } else if (token == "\\language") {
823 } else if (token == "\\language_package") {
825 lang_package = lex.getString();
826 } else if (token == "\\inputencoding") {
828 } else if (token == "\\graphics") {
829 readGraphicsDriver(lex);
830 } else if (token == "\\default_output_format") {
831 lex >> default_output_format;
832 } else if (token == "\\bibtex_command") {
834 bibtex_command = lex.getString();
835 } else if (token == "\\index_command") {
837 index_command = lex.getString();
838 } else if (token == "\\fontencoding") {
840 fontenc = lex.getString();
841 } else if (token == "\\font_roman") {
842 lex >> fonts_roman[0];
843 lex >> fonts_roman[1];
844 } else if (token == "\\font_sans") {
845 lex >> fonts_sans[0];
846 lex >> fonts_sans[1];
847 } else if (token == "\\font_typewriter") {
848 lex >> fonts_typewriter[0];
849 lex >> fonts_typewriter[1];
850 } else if (token == "\\font_math") {
851 lex >> fonts_math[0];
852 lex >> fonts_math[1];
853 } else if (token == "\\font_default_family") {
854 lex >> fonts_default_family;
855 } else if (token == "\\use_non_tex_fonts") {
856 lex >> useNonTeXFonts;
857 } else if (token == "\\font_sc") {
858 lex >> fonts_expert_sc;
859 } else if (token == "\\font_roman_osf") {
860 lex >> fonts_roman_osf;
861 } else if (token == "\\font_sans_osf") {
862 lex >> fonts_sans_osf;
863 } else if (token == "\\font_typewriter_osf") {
864 lex >> fonts_typewriter_osf;
865 } else if (token == "\\font_roman_opts") {
866 lex >> font_roman_opts;
867 } else if (token == "\\font_sf_scale") {
868 lex >> fonts_sans_scale[0];
869 lex >> fonts_sans_scale[1];
870 } else if (token == "\\font_sans_opts") {
871 lex >> font_sans_opts;
872 } else if (token == "\\font_tt_scale") {
873 lex >> fonts_typewriter_scale[0];
874 lex >> fonts_typewriter_scale[1];
875 } else if (token == "\\font_typewriter_opts") {
876 lex >> font_typewriter_opts;
877 } else if (token == "\\font_cjk") {
879 } else if (token == "\\use_microtype") {
880 lex >> use_microtype;
881 } else if (token == "\\use_dash_ligatures") {
882 lex >> use_dash_ligatures;
883 } else if (token == "\\paragraph_separation") {
886 paragraph_separation = parseptranslator().find(parsep);
887 } else if (token == "\\paragraph_indentation") {
889 string parindent = lex.getString();
890 if (parindent == "default")
891 pimpl_->parindent = Length();
893 pimpl_->parindent = Length(parindent);
894 } else if (token == "\\defskip") {
896 string const defskip = lex.getString();
897 pimpl_->defskip = VSpace(defskip);
898 if (pimpl_->defskip.kind() == VSpace::DEFSKIP)
900 pimpl_->defskip = VSpace(VSpace::MEDSKIP);
901 } else if (token == "\\is_math_indent") {
902 lex >> is_math_indent;
903 } else if (token == "\\math_indentation") {
905 string mathindent = lex.getString();
906 if (mathindent == "default")
907 pimpl_->mathindent = Length();
909 pimpl_->mathindent = Length(mathindent);
910 } else if (token == "\\math_numbering_side") {
914 math_numbering_side = LEFT;
915 else if (tmp == "right")
916 math_numbering_side = RIGHT;
918 math_numbering_side = DEFAULT;
919 } else if (token == "\\quotes_style") {
922 quotes_style = quotesstyletranslator().find(qstyle);
923 } else if (token == "\\dynamic_quotes") {
924 lex >> dynamic_quotes;
925 } else if (token == "\\papersize") {
928 papersize = papersizetranslator().find(ppsize);
929 } else if (token == "\\use_geometry") {
931 } else if (token == "\\use_package") {
936 use_package(package, packagetranslator().find(use));
937 } else if (token == "\\cite_engine") {
939 cite_engine_ = lex.getString();
940 } else if (token == "\\cite_engine_type") {
943 cite_engine_type_ = theCiteEnginesList.getType(engine_type);
944 } else if (token == "\\biblio_style") {
946 biblio_style = lex.getString();
947 } else if (token == "\\biblio_options") {
949 biblio_opts = trim(lex.getString());
950 } else if (token == "\\biblatex_bibstyle") {
952 biblatex_bibstyle = trim(lex.getString());
953 } else if (token == "\\biblatex_citestyle") {
955 biblatex_citestyle = trim(lex.getString());
956 } else if (token == "\\use_bibtopic") {
958 } else if (token == "\\multibib") {
960 } else if (token == "\\use_indices") {
962 } else if (token == "\\tracking_changes") {
963 lex >> track_changes;
964 } else if (token == "\\output_changes") {
965 lex >> output_changes;
966 } else if (token == "\\change_bars") {
968 } else if (token == "\\postpone_fragile_content") {
969 lex >> postpone_fragile_content;
970 } else if (token == "\\branch") {
972 docstring branch = lex.getDocString();
973 branchlist().add(branch);
976 string const tok = lex.getString();
977 if (tok == "\\end_branch")
979 Branch * branch_ptr = branchlist().find(branch);
980 if (tok == "\\selected") {
983 branch_ptr->setSelected(lex.getInteger());
985 if (tok == "\\filename_suffix") {
988 branch_ptr->setFileNameSuffix(lex.getInteger());
990 if (tok == "\\color") {
992 string color = lex.getString();
994 branch_ptr->setColor(color);
995 // Update also the Color table:
997 color = lcolor.getX11HexName(Color_background);
999 lcolor.setColor(to_utf8(branch), color);
1002 } else if (token == "\\index") {
1004 docstring index = lex.getDocString();
1006 indiceslist().add(index);
1009 string const tok = lex.getString();
1010 if (tok == "\\end_index")
1012 Index * index_ptr = indiceslist().find(index);
1013 if (tok == "\\shortcut") {
1015 shortcut = lex.getDocString();
1017 index_ptr->setShortcut(shortcut);
1019 if (tok == "\\color") {
1021 string color = lex.getString();
1023 index_ptr->setColor(color);
1024 // Update also the Color table:
1025 if (color == "none")
1026 color = lcolor.getX11HexName(Color_background);
1028 if (!shortcut.empty())
1029 lcolor.setColor(to_utf8(shortcut), color);
1032 } else if (token == "\\author") {
1034 istringstream ss(lex.getString());
1038 } else if (token == "\\paperorientation") {
1041 orientation = paperorientationtranslator().find(orient);
1042 } else if (token == "\\backgroundcolor") {
1044 backgroundcolor = lyx::rgbFromHexName(lex.getString());
1045 isbackgroundcolor = true;
1046 } else if (token == "\\fontcolor") {
1048 fontcolor = lyx::rgbFromHexName(lex.getString());
1050 } else if (token == "\\notefontcolor") {
1052 string color = lex.getString();
1053 notefontcolor = lyx::rgbFromHexName(color);
1054 lcolor.setColor("notefontcolor", color);
1055 } else if (token == "\\boxbgcolor") {
1057 string color = lex.getString();
1058 boxbgcolor = lyx::rgbFromHexName(color);
1059 lcolor.setColor("boxbgcolor", color);
1060 } else if (token == "\\paperwidth") {
1062 } else if (token == "\\paperheight") {
1064 } else if (token == "\\leftmargin") {
1066 } else if (token == "\\topmargin") {
1068 } else if (token == "\\rightmargin") {
1070 } else if (token == "\\bottommargin") {
1071 lex >> bottommargin;
1072 } else if (token == "\\headheight") {
1074 } else if (token == "\\headsep") {
1076 } else if (token == "\\footskip") {
1078 } else if (token == "\\columnsep") {
1080 } else if (token == "\\paperfontsize") {
1082 } else if (token == "\\papercolumns") {
1084 } else if (token == "\\listings_params") {
1087 listings_params = InsetListingsParams(par).params();
1088 } else if (token == "\\papersides") {
1091 sides = sidestranslator().find(psides);
1092 } else if (token == "\\paperpagestyle") {
1094 } else if (token == "\\tablestyle") {
1096 } else if (token == "\\bullet") {
1098 } else if (token == "\\bulletLaTeX") {
1099 readBulletsLaTeX(lex);
1100 } else if (token == "\\secnumdepth") {
1102 } else if (token == "\\tocdepth") {
1104 } else if (token == "\\spacing") {
1108 if (nspacing == "other") {
1111 spacing().set(spacetranslator().find(nspacing), tmp_val);
1112 } else if (token == "\\float_placement") {
1113 lex >> float_placement;
1114 } else if (token == "\\float_alignment") {
1115 lex >> float_alignment;
1117 } else if (prefixIs(token, "\\pdf_") || token == "\\use_hyperref") {
1118 string toktmp = pdfoptions().readToken(lex, token);
1119 if (!toktmp.empty()) {
1120 lyxerr << "PDFOptions::readToken(): Unknown token: " <<
1124 } else if (token == "\\html_math_output") {
1127 html_math_output = static_cast<MathOutput>(temp);
1128 } else if (token == "\\html_be_strict") {
1129 lex >> html_be_strict;
1130 } else if (token == "\\html_css_as_file") {
1131 lex >> html_css_as_file;
1132 } else if (token == "\\html_math_img_scale") {
1133 lex >> html_math_img_scale;
1134 } else if (token == "\\html_latex_start") {
1136 html_latex_start = lex.getString();
1137 } else if (token == "\\html_latex_end") {
1139 html_latex_end = lex.getString();
1140 } else if (token == "\\docbook_table_output") {
1143 docbook_table_output = static_cast<TableOutput>(temp);
1144 } else if (token == "\\output_sync") {
1146 } else if (token == "\\output_sync_macro") {
1147 lex >> output_sync_macro;
1148 } else if (token == "\\use_refstyle") {
1149 lex >> use_refstyle;
1150 } else if (token == "\\use_minted") {
1152 } else if (token == "\\use_lineno") {
1154 } else if (token == "\\lineno_options") {
1156 lineno_opts = trim(lex.getString());
1158 lyxerr << "BufferParams::readToken(): Unknown token: " <<
1168 // Quote argument if it contains spaces
1169 string quoteIfNeeded(string const & str) {
1170 if (contains(str, ' '))
1171 return "\"" + str + "\"";
1177 void BufferParams::writeFile(ostream & os, Buffer const * buf) const
1179 // The top of the file is written by the buffer.
1180 // Prints out the buffer info into the .lyx file given by file
1182 os << "\\save_transient_properties "
1183 << convert<string>(save_transient_properties) << '\n';
1185 // the document directory (must end with a path separator)
1186 // realPath() is used to resolve symlinks, while addPath(..., "")
1187 // ensures a trailing path separator.
1189 string filepath = addPath(buf->fileName().onlyPath().realPath(), "");
1190 string const sysdir = inSystemDir(FileName(filepath), docsys) ? docsys
1191 : addPath(package().system_support().realPath(), "");
1192 string const relpath =
1193 to_utf8(makeRelPath(from_utf8(filepath), from_utf8(sysdir)));
1194 if (!prefixIs(relpath, "../") && !FileName::isAbsolute(relpath))
1195 filepath = addPath("/systemlyxdir", relpath);
1196 else if (!save_transient_properties || !lyxrc.save_origin)
1197 filepath = "unavailable";
1198 os << "\\origin " << quoteIfNeeded(filepath) << '\n';
1201 os << "\\textclass "
1202 << quoteIfNeeded(buf->includedFilePath(addName(buf->layoutPos(),
1203 baseClass()->name()), "layout"))
1206 // then the preamble
1207 if (!preamble.empty()) {
1208 // remove '\n' from the end of preamble
1209 docstring const tmppreamble = rtrim(preamble, "\n");
1210 os << "\\begin_preamble\n"
1211 << to_utf8(tmppreamble)
1212 << "\n\\end_preamble\n";
1216 if (!options.empty()) {
1217 os << "\\options " << options << '\n';
1220 // use the class options defined in the layout?
1221 os << "\\use_default_options "
1222 << convert<string>(use_default_options) << "\n";
1224 // the master document
1225 if (!master.empty()) {
1226 os << "\\master " << master << '\n';
1230 if (!removed_modules_.empty()) {
1231 os << "\\begin_removed_modules" << '\n';
1232 for (auto const & mod : removed_modules_)
1234 os << "\\end_removed_modules" << '\n';
1238 if (!layout_modules_.empty()) {
1239 os << "\\begin_modules" << '\n';
1240 for (auto const & mod : layout_modules_)
1242 os << "\\end_modules" << '\n';
1246 if (!included_children_.empty()) {
1247 os << "\\begin_includeonly" << '\n';
1248 for (auto const & c : included_children_)
1250 os << "\\end_includeonly" << '\n';
1253 switch (maintain_unincluded_children) {
1264 os << "\\maintain_unincluded_children " << muc << '\n';
1266 // local layout information
1267 docstring const local_layout = getLocalLayout(false);
1268 if (!local_layout.empty()) {
1269 // remove '\n' from the end
1270 docstring const tmplocal = rtrim(local_layout, "\n");
1271 os << "\\begin_local_layout\n"
1272 << to_utf8(tmplocal)
1273 << "\n\\end_local_layout\n";
1275 docstring const forced_local_layout = getLocalLayout(true);
1276 if (!forced_local_layout.empty()) {
1277 // remove '\n' from the end
1278 docstring const tmplocal = rtrim(forced_local_layout, "\n");
1279 os << "\\begin_forced_local_layout\n"
1280 << to_utf8(tmplocal)
1281 << "\n\\end_forced_local_layout\n";
1284 // then the text parameters
1285 if (language != ignore_language)
1286 os << "\\language " << language->lang() << '\n';
1287 os << "\\language_package " << lang_package
1288 << "\n\\inputencoding " << inputenc
1289 << "\n\\fontencoding " << fontenc
1290 << "\n\\font_roman \"" << fonts_roman[0]
1291 << "\" \"" << fonts_roman[1] << '"'
1292 << "\n\\font_sans \"" << fonts_sans[0]
1293 << "\" \"" << fonts_sans[1] << '"'
1294 << "\n\\font_typewriter \"" << fonts_typewriter[0]
1295 << "\" \"" << fonts_typewriter[1] << '"'
1296 << "\n\\font_math \"" << fonts_math[0]
1297 << "\" \"" << fonts_math[1] << '"'
1298 << "\n\\font_default_family " << fonts_default_family
1299 << "\n\\use_non_tex_fonts " << convert<string>(useNonTeXFonts)
1300 << "\n\\font_sc " << convert<string>(fonts_expert_sc)
1301 << "\n\\font_roman_osf " << convert<string>(fonts_roman_osf)
1302 << "\n\\font_sans_osf " << convert<string>(fonts_sans_osf)
1303 << "\n\\font_typewriter_osf " << convert<string>(fonts_typewriter_osf);
1304 if (!font_roman_opts.empty())
1305 os << "\n\\font_roman_opts \"" << font_roman_opts << "\"";
1306 os << "\n\\font_sf_scale " << fonts_sans_scale[0]
1307 << ' ' << fonts_sans_scale[1];
1308 if (!font_sans_opts.empty())
1309 os << "\n\\font_sans_opts \"" << font_sans_opts << "\"";
1310 os << "\n\\font_tt_scale " << fonts_typewriter_scale[0]
1311 << ' ' << fonts_typewriter_scale[1];
1312 if (!font_typewriter_opts.empty())
1313 os << "\n\\font_typewriter_opts \"" << font_typewriter_opts << "\"";
1315 if (!fonts_cjk.empty())
1316 os << "\\font_cjk " << fonts_cjk << '\n';
1317 os << "\\use_microtype " << convert<string>(use_microtype) << '\n';
1318 os << "\\use_dash_ligatures " << convert<string>(use_dash_ligatures) << '\n';
1319 os << "\\graphics " << graphics_driver << '\n';
1320 os << "\\default_output_format " << default_output_format << '\n';
1321 os << "\\output_sync " << output_sync << '\n';
1322 if (!output_sync_macro.empty())
1323 os << "\\output_sync_macro \"" << output_sync_macro << "\"\n";
1324 os << "\\bibtex_command " << bibtex_command << '\n';
1325 os << "\\index_command " << index_command << '\n';
1327 if (!float_placement.empty())
1328 os << "\\float_placement " << float_placement << '\n';
1329 if (!float_alignment.empty())
1330 os << "\\float_alignment " << float_alignment << '\n';
1331 os << "\\paperfontsize " << fontsize << '\n';
1333 spacing().writeFile(os);
1334 pdfoptions().writeFile(os);
1336 os << "\\papersize " << string_papersize[papersize]
1337 << "\n\\use_geometry " << convert<string>(use_geometry);
1338 map<string, string> const & packages = auto_packages();
1339 for (auto const & pack : packages)
1340 os << "\n\\use_package " << pack.first << ' '
1341 << use_package(pack.first);
1343 os << "\n\\cite_engine ";
1345 if (!cite_engine_.empty())
1350 os << "\n\\cite_engine_type " << theCiteEnginesList.getTypeAsString(cite_engine_type_);
1352 if (!biblio_style.empty())
1353 os << "\n\\biblio_style " << biblio_style;
1354 if (!biblio_opts.empty())
1355 os << "\n\\biblio_options " << biblio_opts;
1356 if (!biblatex_bibstyle.empty())
1357 os << "\n\\biblatex_bibstyle " << biblatex_bibstyle;
1358 if (!biblatex_citestyle.empty())
1359 os << "\n\\biblatex_citestyle " << biblatex_citestyle;
1360 if (!multibib.empty())
1361 os << "\n\\multibib " << multibib;
1363 os << "\n\\use_bibtopic " << convert<string>(use_bibtopic)
1364 << "\n\\use_indices " << convert<string>(use_indices)
1365 << "\n\\paperorientation " << string_orientation[orientation]
1366 << "\n\\suppress_date " << convert<string>(suppress_date)
1367 << "\n\\justification " << convert<string>(justification)
1368 << "\n\\use_refstyle " << use_refstyle
1369 << "\n\\use_minted " << use_minted
1370 << "\n\\use_lineno " << use_lineno
1373 if (!lineno_opts.empty())
1374 os << "\\lineno_options " << lineno_opts << '\n';
1376 if (isbackgroundcolor == true)
1377 os << "\\backgroundcolor " << lyx::X11hexname(backgroundcolor) << '\n';
1378 if (isfontcolor == true)
1379 os << "\\fontcolor " << lyx::X11hexname(fontcolor) << '\n';
1380 if (notefontcolor != lyx::rgbFromHexName("#cccccc"))
1381 os << "\\notefontcolor " << lyx::X11hexname(notefontcolor) << '\n';
1382 if (boxbgcolor != lyx::rgbFromHexName("#ff0000"))
1383 os << "\\boxbgcolor " << lyx::X11hexname(boxbgcolor) << '\n';
1385 for (auto const & br : branchlist()) {
1386 os << "\\branch " << to_utf8(br.branch())
1387 << "\n\\selected " << br.isSelected()
1388 << "\n\\filename_suffix " << br.hasFileNameSuffix()
1389 << "\n\\color " << lyx::X11hexname(br.color())
1394 for (auto const & id : indiceslist()) {
1395 os << "\\index " << to_utf8(id.index())
1396 << "\n\\shortcut " << to_utf8(id.shortcut())
1397 << "\n\\color " << lyx::X11hexname(id.color())
1402 if (!paperwidth.empty())
1403 os << "\\paperwidth "
1404 << VSpace(paperwidth).asLyXCommand() << '\n';
1405 if (!paperheight.empty())
1406 os << "\\paperheight "
1407 << VSpace(paperheight).asLyXCommand() << '\n';
1408 if (!leftmargin.empty())
1409 os << "\\leftmargin "
1410 << VSpace(leftmargin).asLyXCommand() << '\n';
1411 if (!topmargin.empty())
1412 os << "\\topmargin "
1413 << VSpace(topmargin).asLyXCommand() << '\n';
1414 if (!rightmargin.empty())
1415 os << "\\rightmargin "
1416 << VSpace(rightmargin).asLyXCommand() << '\n';
1417 if (!bottommargin.empty())
1418 os << "\\bottommargin "
1419 << VSpace(bottommargin).asLyXCommand() << '\n';
1420 if (!headheight.empty())
1421 os << "\\headheight "
1422 << VSpace(headheight).asLyXCommand() << '\n';
1423 if (!headsep.empty())
1425 << VSpace(headsep).asLyXCommand() << '\n';
1426 if (!footskip.empty())
1428 << VSpace(footskip).asLyXCommand() << '\n';
1429 if (!columnsep.empty())
1430 os << "\\columnsep "
1431 << VSpace(columnsep).asLyXCommand() << '\n';
1432 os << "\\secnumdepth " << secnumdepth
1433 << "\n\\tocdepth " << tocdepth
1434 << "\n\\paragraph_separation "
1435 << string_paragraph_separation[paragraph_separation];
1436 if (!paragraph_separation)
1437 os << "\n\\paragraph_indentation "
1438 << (getParIndent().empty() ? "default" : getParIndent().asString());
1440 os << "\n\\defskip " << getDefSkip().asLyXCommand();
1441 os << "\n\\is_math_indent " << is_math_indent;
1443 os << "\n\\math_indentation "
1444 << (getMathIndent().empty() ? "default" : getMathIndent().asString());
1445 os << "\n\\math_numbering_side ";
1446 switch(math_numbering_side) {
1456 os << "\n\\quotes_style "
1457 << string_quotes_style[quotes_style]
1458 << "\n\\dynamic_quotes " << dynamic_quotes
1459 << "\n\\papercolumns " << columns
1460 << "\n\\papersides " << sides
1461 << "\n\\paperpagestyle " << pagestyle
1462 << "\n\\tablestyle " << tablestyle << '\n';
1463 if (!listings_params.empty())
1464 os << "\\listings_params \"" <<
1465 InsetListingsParams(listings_params).encodedString() << "\"\n";
1466 for (int i = 0; i < 4; ++i) {
1467 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
1468 if (user_defined_bullet(i).getFont() != -1) {
1469 os << "\\bullet " << i << " "
1470 << user_defined_bullet(i).getFont() << " "
1471 << user_defined_bullet(i).getCharacter() << " "
1472 << user_defined_bullet(i).getSize() << "\n";
1476 os << "\\bulletLaTeX " << i << " \""
1477 << lyx::to_ascii(user_defined_bullet(i).getText())
1483 os << "\\tracking_changes "
1484 << (save_transient_properties ? convert<string>(track_changes) : "false")
1487 os << "\\output_changes "
1488 << (save_transient_properties ? convert<string>(output_changes) : "false")
1491 os << "\\change_bars "
1492 << (save_transient_properties ? convert<string>(change_bars) : "false")
1495 os << "\\postpone_fragile_content " << convert<string>(postpone_fragile_content) << '\n';
1497 os << "\\html_math_output " << html_math_output << '\n'
1498 << "\\html_css_as_file " << html_css_as_file << '\n'
1499 << "\\html_be_strict " << convert<string>(html_be_strict) << '\n';
1501 os << "\\docbook_table_output " << docbook_table_output << '\n';
1503 if (html_math_img_scale != 1.0)
1504 os << "\\html_math_img_scale " << convert<string>(html_math_img_scale) << '\n';
1505 if (!html_latex_start.empty())
1506 os << "\\html_latex_start " << html_latex_start << '\n';
1507 if (!html_latex_end.empty())
1508 os << "\\html_latex_end " << html_latex_end << '\n';
1510 os << pimpl_->authorlist;
1514 void BufferParams::validate(LaTeXFeatures & features) const
1516 features.require(documentClass().required());
1518 if (columns > 1 && language->rightToLeft())
1519 features.require("rtloutputdblcol");
1521 if (output_changes) {
1522 bool xcolorulem = LaTeXFeatures::isAvailable("ulem") &&
1523 LaTeXFeatures::isAvailable("xcolor");
1525 switch (features.runparams().flavor) {
1526 case OutputParams::LATEX:
1527 case OutputParams::DVILUATEX:
1529 features.require("ct-xcolor-ulem");
1530 features.require("ulem");
1531 features.require("xcolor");
1533 features.require("ct-none");
1536 case OutputParams::LUATEX:
1537 case OutputParams::PDFLATEX:
1538 case OutputParams::XETEX:
1540 features.require("ct-xcolor-ulem");
1541 features.require("ulem");
1542 features.require("xcolor");
1543 // improves color handling in PDF output
1544 features.require("pdfcolmk");
1546 features.require("ct-none");
1553 features.require("changebar");
1556 // Floats with 'Here definitely' as default setting.
1557 if (float_placement.find('H') != string::npos)
1558 features.require("float");
1560 for (auto const & pm : use_packages) {
1561 if (pm.first == "amsmath") {
1562 // AMS Style is at document level
1563 if (pm.second == package_on ||
1564 features.isProvided("amsmath"))
1565 features.require(pm.first);
1566 } else if (pm.second == package_on)
1567 features.require(pm.first);
1570 // Document-level line spacing
1571 if (spacing().getSpace() != Spacing::Single && !spacing().isDefault())
1572 features.require("setspace");
1574 // the bullet shapes are buffer level not paragraph level
1575 // so they are tested here
1576 for (int i = 0; i < 4; ++i) {
1577 if (user_defined_bullet(i) == ITEMIZE_DEFAULTS[i])
1579 int const font = user_defined_bullet(i).getFont();
1581 int const c = user_defined_bullet(i).getCharacter();
1587 features.require("latexsym");
1589 } else if (font == 1) {
1590 features.require("amssymb");
1591 } else if (font >= 2 && font <= 5) {
1592 features.require("pifont");
1596 if (pdfoptions().use_hyperref) {
1597 features.require("hyperref");
1598 // due to interferences with babel and hyperref, the color package has to
1599 // be loaded after hyperref when hyperref is used with the colorlinks
1600 // option, see http://www.lyx.org/trac/ticket/5291
1601 if (pdfoptions().colorlinks)
1602 features.require("color");
1604 if (!listings_params.empty()) {
1605 // do not test validity because listings_params is
1606 // supposed to be valid
1608 InsetListingsParams(listings_params).separatedParams(true);
1609 // we can't support all packages, but we should load the color package
1610 if (par.find("\\color", 0) != string::npos)
1611 features.require("color");
1614 // some languages are only available via polyglossia
1615 if (features.hasPolyglossiaExclusiveLanguages())
1616 features.require("polyglossia");
1618 if (useNonTeXFonts && fontsMath() != "auto")
1619 features.require("unicode-math");
1622 features.require("microtype");
1624 if (!language->required().empty())
1625 features.require(language->required());
1629 bool BufferParams::writeLaTeX(otexstream & os, LaTeXFeatures & features,
1630 FileName const & filepath) const
1632 // http://www.tug.org/texmf-dist/doc/latex/base/fixltx2e.pdf
1633 // !! To use the Fix-cm package, load it before \documentclass, and use the command
1634 // \RequirePackage to do so, rather than the normal \usepackage
1635 // Do not try to load any other package before the document class, unless you
1636 // have a thorough understanding of the LATEX internals and know exactly what you
1638 if (features.mustProvide("fix-cm"))
1639 os << "\\RequirePackage{fix-cm}\n";
1640 // Likewise for fixltx2e. If other packages conflict with this policy,
1641 // treat it as a package bug (and report it!)
1642 // See http://www.latex-project.org/cgi-bin/ltxbugs2html?pr=latex/4407
1643 if (features.mustProvide("fixltx2e"))
1644 os << "\\RequirePackage{fixltx2e}\n";
1646 os << "\\documentclass";
1648 DocumentClass const & tclass = documentClass();
1650 ostringstream clsoptions; // the document class options.
1652 if (tokenPos(tclass.opt_fontsize(),
1653 '|', fontsize) >= 0) {
1654 // only write if existing in list (and not default)
1655 clsoptions << subst(tclass.fontsizeformat(), "$$s", fontsize) << ",";
1658 // paper sizes not supported by the class itself need the
1660 vector<string> classpsizes = getVectorFromString(tclass.opt_pagesize(), "|");
1661 bool class_supported_papersize = papersize == PAPER_DEFAULT
1662 || find(classpsizes.begin(), classpsizes.end(), string_papersize[papersize]) != classpsizes.end();
1664 if ((!use_geometry || features.isProvided("geometry-light"))
1665 && class_supported_papersize && papersize != PAPER_DEFAULT)
1666 clsoptions << subst(tclass.pagesizeformat(), "$$s", string_papersize[papersize]) << ",";
1669 if (sides != tclass.sides()) {
1672 clsoptions << "oneside,";
1675 clsoptions << "twoside,";
1681 if (columns != tclass.columns()) {
1683 clsoptions << "twocolumn,";
1685 clsoptions << "onecolumn,";
1689 && orientation == ORIENTATION_LANDSCAPE)
1690 clsoptions << "landscape,";
1693 clsoptions << "fleqn,";
1695 switch(math_numbering_side) {
1697 clsoptions << "leqno,";
1700 clsoptions << "reqno,";
1701 features.require("amsmath");
1707 // language should be a parameter to \documentclass
1708 if (language->babel() == "hebrew"
1709 && default_language->babel() != "hebrew")
1710 // This seems necessary
1711 features.useLanguage(default_language);
1713 ostringstream language_options;
1714 bool const use_babel = features.useBabel() && !features.isProvided("babel");
1715 bool const use_polyglossia = features.usePolyglossia();
1716 bool const global = lyxrc.language_global_options;
1717 if (features.useBabel() || (use_polyglossia && global)) {
1718 language_options << features.getBabelLanguages();
1719 if (!language->babel().empty()) {
1720 if (!language_options.str().empty())
1721 language_options << ',';
1722 language_options << language->babel();
1724 if (global && !language_options.str().empty())
1725 clsoptions << language_options.str() << ',';
1728 // the predefined options from the layout
1729 if (use_default_options && !tclass.options().empty())
1730 clsoptions << tclass.options() << ',';
1732 // the user-defined options
1733 if (!options.empty()) {
1734 clsoptions << options << ',';
1737 docstring const strOptions = from_utf8(clsoptions.str());
1738 if (!strOptions.empty()) {
1739 // Check if class options contain uncodable glyphs
1740 docstring uncodable_glyphs;
1741 docstring options_encodable;
1742 Encoding const * const enc = features.runparams().encoding;
1744 for (size_t n = 0; n < strOptions.size(); ++n) {
1745 char_type c = strOptions[n];
1746 if (!enc->encodable(c)) {
1747 docstring const glyph(1, c);
1748 LYXERR0("Uncodable character '"
1750 << "' in class options!");
1751 uncodable_glyphs += glyph;
1752 if (features.runparams().dryrun) {
1753 options_encodable += "<" + _("LyX Warning: ")
1754 + _("uncodable character") + " '";
1755 options_encodable += c;
1756 options_encodable += "'>";
1759 options_encodable += c;
1762 options_encodable = strOptions;
1764 // On BUFFER_VIEW|UPDATE, warn user if we found uncodable glyphs
1765 if (!features.runparams().dryrun && !uncodable_glyphs.empty()) {
1766 frontend::Alert::warning(
1767 _("Uncodable character in class options"),
1769 _("The class options of your document contain glyphs "
1770 "that are unknown in the current document encoding "
1771 "(namely %1$s).\nThese glyphs are omitted "
1772 " from the output, which may result in "
1773 "incomplete output."
1774 "\n\nPlease select an appropriate "
1775 "document encoding\n"
1776 "(such as utf8) or change the "
1777 "class options accordingly."),
1780 options_encodable = rtrim(options_encodable, ",");
1781 os << '[' << options_encodable << ']';
1784 os << '{' << from_ascii(tclass.latexname()) << "}\n";
1785 // end of \documentclass defs
1787 // The package options (via \PassOptionsToPackage)
1788 os << from_ascii(features.getPackageOptions());
1790 // if we use fontspec or newtxmath, we have to load the AMS packages here
1791 string const ams = features.loadAMSPackages();
1792 bool const ot1 = (main_font_encoding() == "default" || main_font_encoding() == "OT1");
1793 bool const use_newtxmath =
1794 theLaTeXFonts().getLaTeXFont(from_ascii(fontsMath())).getUsedPackage(
1795 ot1, false, false) == "newtxmath";
1796 if ((useNonTeXFonts || use_newtxmath) && !ams.empty())
1797 os << from_ascii(ams);
1799 if (useNonTeXFonts) {
1800 // Babel (as of 2017/11/03) loads fontspec itself
1801 if (!features.isProvided("fontspec")
1802 && !(features.useBabel() && features.isAvailable("babel-2017/11/03")))
1803 os << "\\usepackage{fontspec}\n";
1804 if (features.mustProvide("unicode-math")
1805 && features.isAvailable("unicode-math"))
1806 os << "\\usepackage{unicode-math}\n";
1809 // load CJK support package before font selection
1810 // (see autotests/export/latex/CJK/micro-sign_utf8-cjk-libertine.lyx)
1811 if (!useNonTeXFonts && encoding().package() != Encoding::none && inputenc != "utf8x"
1812 && (encoding().package() == Encoding::CJK || features.mustProvide("CJK"))) {
1813 if (inputenc == "utf8-cjk" || inputenc == "utf8")
1814 os << "\\usepackage{CJKutf8}\n";
1816 os << "\\usepackage[encapsulated]{CJK}\n";
1819 // font selection must be done before loading fontenc.sty
1820 // but after babel with non-TeX fonts
1821 string const fonts = loadFonts(features);
1822 if (!fonts.empty() && (!features.useBabel() || !useNonTeXFonts))
1823 os << from_utf8(fonts);
1825 if (fonts_default_family != "default")
1826 os << "\\renewcommand{\\familydefault}{\\"
1827 << from_ascii(fonts_default_family) << "}\n";
1829 // set font encoding
1830 // non-TeX fonts use font encoding TU (set by fontspec)
1831 if (!useNonTeXFonts && !features.isProvided("fontenc")
1832 && main_font_encoding() != "default") {
1833 // get main font encodings
1834 vector<string> fontencs = font_encodings();
1835 // get font encodings of secondary languages
1836 // FIXME: some languages (hebrew, ...) assume a standard font encoding as last
1837 // option (for text in other languages).
1838 features.getFontEncodings(fontencs);
1839 if (!fontencs.empty()) {
1840 os << "\\usepackage["
1841 << from_ascii(getStringFromVector(fontencs))
1846 // Load textcomp and pmboxdraw before (lua)inputenc (#11454)
1847 if (features.mustProvide("textcomp"))
1848 os << "\\usepackage{textcomp}\n";
1849 if (features.mustProvide("pmboxdraw"))
1850 os << "\\usepackage{pmboxdraw}\n";
1852 // handle inputenc etc.
1853 // (In documents containing text in Thai language,
1854 // we must load inputenc after babel, see lib/languages).
1855 if (!contains(features.getBabelPostsettings(), from_ascii("thai.ldf")))
1856 writeEncodingPreamble(os, features);
1859 if (!features.runparams().includeall && !included_children_.empty()) {
1860 os << "\\includeonly{";
1862 for (auto incfile : included_children_) {
1863 FileName inc = makeAbsPath(incfile, filepath.absFileName());
1864 string mangled = DocFileName(changeExtension(inc.absFileName(), ".tex")).
1866 if (!features.runparams().nice)
1868 // \includeonly doesn't want an extension
1869 incfile = changeExtension(incfile, string());
1870 incfile = support::latex_path(incfile);
1871 if (!incfile.empty()) {
1874 os << from_utf8(incfile);
1881 if (!features.isProvided("geometry")
1882 && (use_geometry || !class_supported_papersize)) {
1883 odocstringstream ods;
1884 if (!getGraphicsDriver("geometry").empty())
1885 ods << getGraphicsDriver("geometry");
1886 if (orientation == ORIENTATION_LANDSCAPE)
1887 ods << ",landscape";
1888 switch (papersize) {
1890 if (!paperwidth.empty())
1891 ods << ",paperwidth="
1892 << from_ascii(paperwidth);
1893 if (!paperheight.empty())
1894 ods << ",paperheight="
1895 << from_ascii(paperheight);
1897 case PAPER_USLETTER:
1899 case PAPER_USEXECUTIVE:
1928 ods << "," << from_ascii(string_papersize_geometry[papersize]);
1933 docstring g_options = trim(ods.str(), ",");
1934 os << "\\usepackage";
1935 // geometry-light means that the class works with geometry, but overwrites
1936 // the package options and paper sizes (memoir does this).
1937 // In this case, all options need to go to \geometry
1938 // and the standard paper sizes need to go to the class options.
1939 if (!g_options.empty() && !features.isProvided("geometry-light")) {
1940 os << '[' << g_options << ']';
1943 os << "{geometry}\n";
1944 if (use_geometry || features.isProvided("geometry-light")) {
1945 os << "\\geometry{verbose";
1946 if (!g_options.empty())
1947 // Output general options here with "geometry light".
1948 os << "," << g_options;
1949 // output this only if use_geometry is true
1951 if (!topmargin.empty())
1952 os << ",tmargin=" << from_ascii(Length(topmargin).asLatexString());
1953 if (!bottommargin.empty())
1954 os << ",bmargin=" << from_ascii(Length(bottommargin).asLatexString());
1955 if (!leftmargin.empty())
1956 os << ",lmargin=" << from_ascii(Length(leftmargin).asLatexString());
1957 if (!rightmargin.empty())
1958 os << ",rmargin=" << from_ascii(Length(rightmargin).asLatexString());
1959 if (!headheight.empty())
1960 os << ",headheight=" << from_ascii(Length(headheight).asLatexString());
1961 if (!headsep.empty())
1962 os << ",headsep=" << from_ascii(Length(headsep).asLatexString());
1963 if (!footskip.empty())
1964 os << ",footskip=" << from_ascii(Length(footskip).asLatexString());
1965 if (!columnsep.empty())
1966 os << ",columnsep=" << from_ascii(Length(columnsep).asLatexString());
1970 } else if (orientation == ORIENTATION_LANDSCAPE
1971 || papersize != PAPER_DEFAULT) {
1972 features.require("papersize");
1975 if (tokenPos(tclass.opt_pagestyle(), '|', pagestyle) >= 0) {
1976 if (pagestyle == "fancy")
1977 os << "\\usepackage{fancyhdr}\n";
1978 os << "\\pagestyle{" << from_ascii(pagestyle) << "}\n";
1981 // only output when the background color is not default
1982 if (isbackgroundcolor == true) {
1983 // only require color here, the background color will be defined
1984 // in LaTeXFeatures.cpp to avoid interferences with the LaTeX
1986 features.require("color");
1987 features.require("pagecolor");
1990 // only output when the font color is not default
1991 if (isfontcolor == true) {
1992 // only require color here, the font color will be defined
1993 // in LaTeXFeatures.cpp to avoid interferences with the LaTeX
1995 features.require("color");
1996 features.require("fontcolor");
1999 // Only if class has a ToC hierarchy
2000 if (tclass.hasTocLevels()) {
2001 if (secnumdepth != tclass.secnumdepth()) {
2002 os << "\\setcounter{secnumdepth}{"
2006 if (tocdepth != tclass.tocdepth()) {
2007 os << "\\setcounter{tocdepth}{"
2013 if (paragraph_separation) {
2014 // when skip separation
2016 switch (getDefSkip().kind()) {
2017 case VSpace::SMALLSKIP:
2018 psopt = "\\smallskipamount";
2020 case VSpace::MEDSKIP:
2021 psopt = "\\medskipamount";
2023 case VSpace::BIGSKIP:
2024 psopt = "\\bigskipamount";
2026 case VSpace::HALFLINE:
2027 // default (no option)
2029 case VSpace::FULLLINE:
2030 psopt = "\\baselineskip";
2032 case VSpace::LENGTH:
2033 psopt = getDefSkip().length().asLatexString();
2038 if (!features.isProvided("parskip")) {
2040 psopt = "[skip=" + psopt + "]";
2041 os << "\\usepackage" + psopt + "{parskip}\n";
2043 os << "\\setlength{\\parskip}{" + psopt + "}\n";
2046 // when separation by indentation
2047 // only output something when a width is given
2048 if (!getParIndent().empty()) {
2049 os << "\\setlength{\\parindent}{"
2050 << from_utf8(getParIndent().asLatexString())
2055 if (is_math_indent) {
2056 // when formula indentation
2057 // only output something when it is not the default
2058 if (!getMathIndent().empty()) {
2059 os << "\\setlength{\\mathindent}{"
2060 << from_utf8(getMathIndent().asString())
2065 // Now insert the LyX specific LaTeX commands...
2066 features.resolveAlternatives();
2067 features.expandMultiples();
2070 if (!output_sync_macro.empty())
2071 os << from_utf8(output_sync_macro) +"\n";
2072 else if (features.runparams().flavor == OutputParams::LATEX)
2073 os << "\\usepackage[active]{srcltx}\n";
2074 else if (features.runparams().flavor == OutputParams::PDFLATEX)
2075 os << "\\synctex=-1\n";
2078 // due to interferences with babel and hyperref, the color package has to
2079 // be loaded (when it is not already loaded) before babel when hyperref
2080 // is used with the colorlinks option, see
2081 // http://www.lyx.org/trac/ticket/5291
2082 // we decided therefore to load color always before babel, see
2083 // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg144349.html
2084 os << from_ascii(features.getColorOptions());
2086 // If we use hyperref, jurabib, japanese or varioref,
2087 // we have to call babel before
2089 && (features.isRequired("jurabib")
2090 || features.isRequired("hyperref")
2091 || features.isRequired("varioref")
2092 || features.isRequired("japanese"))) {
2093 os << features.getBabelPresettings();
2095 os << from_utf8(babelCall(language_options.str(),
2096 !lyxrc.language_global_options)) + '\n';
2097 os << features.getBabelPostsettings();
2100 // The optional packages;
2101 os << from_ascii(features.getPackages());
2103 // Additional Indices
2104 if (features.isRequired("splitidx")) {
2105 for (auto const & idx : indiceslist()) {
2106 os << "\\newindex{";
2107 os << escape(idx.shortcut());
2113 os << from_utf8(spacing().writePreamble(features.isProvided("SetSpace")));
2116 // * Hyperref manual: "Make sure it comes last of your loaded
2117 // packages, to give it a fighting chance of not being over-written,
2118 // since its job is to redefine many LaTeX commands."
2119 // * Email from Heiko Oberdiek: "It is usually better to load babel
2120 // before hyperref. Then hyperref has a chance to detect babel.
2121 // * Has to be loaded before the "LyX specific LaTeX commands" to
2122 // avoid errors with algorithm floats.
2123 // use hyperref explicitly if it is required
2124 if (features.isRequired("hyperref")) {
2125 OutputParams tmp_params = features.runparams();
2126 pdfoptions().writeLaTeX(tmp_params, os,
2127 features.isProvided("hyperref"));
2128 // correctly break URLs with hyperref and dvi/ps output
2129 if (features.runparams().hyperref_driver == "dvips"
2130 && features.isAvailable("breakurl"))
2131 os << "\\usepackage{breakurl}\n";
2132 } else if (features.isRequired("nameref"))
2133 // hyperref loads this automatically
2134 os << "\\usepackage{nameref}\n";
2137 os << "\\usepackage";
2138 if (!lineno_opts.empty())
2139 os << "[" << lineno_opts << "]";
2141 os << "\\linenumbers\n";
2144 // bibtopic needs to be loaded after hyperref.
2145 // the dot provides the aux file naming which LyX can detect.
2146 if (features.mustProvide("bibtopic"))
2147 os << "\\usepackage[dot]{bibtopic}\n";
2149 // Will be surrounded by \makeatletter and \makeatother when not empty
2150 otexstringstream atlyxpreamble;
2152 // Some macros LyX will need
2154 TexString tmppreamble = features.getMacros();
2155 if (!tmppreamble.str.empty())
2156 atlyxpreamble << "\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
2157 "LyX specific LaTeX commands.\n"
2158 << move(tmppreamble)
2161 // the text class specific preamble
2163 docstring tmppreamble = features.getTClassPreamble();
2164 if (!tmppreamble.empty())
2165 atlyxpreamble << "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
2166 "Textclass specific LaTeX commands.\n"
2170 // suppress date if selected
2171 // use \@ifundefined because we cannot be sure that every document class
2172 // has a \date command
2174 atlyxpreamble << "\\@ifundefined{date}{}{\\date{}}\n";
2176 /* the user-defined preamble */
2177 if (!containsOnly(preamble, " \n\t")) {
2179 atlyxpreamble << "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
2180 "User specified LaTeX commands.\n";
2182 // Check if the user preamble contains uncodable glyphs
2183 odocstringstream user_preamble;
2184 docstring uncodable_glyphs;
2185 Encoding const * const enc = features.runparams().encoding;
2187 for (size_t n = 0; n < preamble.size(); ++n) {
2188 char_type c = preamble[n];
2189 if (!enc->encodable(c)) {
2190 docstring const glyph(1, c);
2191 LYXERR0("Uncodable character '"
2193 << "' in user preamble!");
2194 uncodable_glyphs += glyph;
2195 if (features.runparams().dryrun) {
2196 user_preamble << "<" << _("LyX Warning: ")
2197 << _("uncodable character") << " '";
2198 user_preamble.put(c);
2199 user_preamble << "'>";
2202 user_preamble.put(c);
2205 user_preamble << preamble;
2207 // On BUFFER_VIEW|UPDATE, warn user if we found uncodable glyphs
2208 if (!features.runparams().dryrun && !uncodable_glyphs.empty()) {
2209 frontend::Alert::warning(
2210 _("Uncodable character in user preamble"),
2212 _("The user preamble of your document contains glyphs "
2213 "that are unknown in the current document encoding "
2214 "(namely %1$s).\nThese glyphs are omitted "
2215 " from the output, which may result in "
2216 "incomplete output."
2217 "\n\nPlease select an appropriate "
2218 "document encoding\n"
2219 "(such as utf8) or change the "
2220 "preamble code accordingly."),
2223 atlyxpreamble << user_preamble.str() << '\n';
2226 // footmisc must be loaded after setspace
2227 // Load it here to avoid clashes with footmisc loaded in the user
2228 // preamble. For that reason we also pass the options via
2229 // \PassOptionsToPackage in getPreamble() and not here.
2230 if (features.mustProvide("footmisc"))
2231 atlyxpreamble << "\\usepackage{footmisc}\n";
2233 // subfig loads internally the LaTeX package "caption". As
2234 // caption is a very popular package, users will load it in
2235 // the preamble. Therefore we must load subfig behind the
2236 // user-defined preamble and check if the caption package was
2237 // loaded or not. For the case that caption is loaded before
2238 // subfig, there is the subfig option "caption=false". This
2239 // option also works when a koma-script class is used and
2240 // koma's own caption commands are used instead of caption. We
2241 // use \PassOptionsToPackage here because the user could have
2242 // already loaded subfig in the preamble.
2243 if (features.mustProvide("subfig"))
2244 atlyxpreamble << "\\@ifundefined{showcaptionsetup}{}{%\n"
2245 " \\PassOptionsToPackage{caption=false}{subfig}}\n"
2246 "\\usepackage{subfig}\n";
2248 // Itemize bullet settings need to be last in case the user
2249 // defines their own bullets that use a package included
2250 // in the user-defined preamble -- ARRae
2251 // Actually it has to be done much later than that
2252 // since some packages like frenchb make modifications
2253 // at \begin{document} time -- JMarc
2254 docstring bullets_def;
2255 for (int i = 0; i < 4; ++i) {
2256 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
2257 if (bullets_def.empty())
2258 bullets_def += "\\AtBeginDocument{\n";
2259 bullets_def += " \\def\\labelitemi";
2261 // `i' is one less than the item to modify
2268 bullets_def += "ii";
2274 bullets_def += '{' +
2275 user_defined_bullet(i).getText()
2280 if (!bullets_def.empty())
2281 atlyxpreamble << bullets_def << "}\n\n";
2283 if (!atlyxpreamble.empty())
2284 os << "\n\\makeatletter\n"
2285 << atlyxpreamble.release()
2286 << "\\makeatother\n\n";
2288 // We try to load babel late, in case it interferes with other packages.
2289 // Jurabib, hyperref, varioref, bicaption, menukeys and listings (bug 8995)
2290 // have to be called after babel, though.
2291 if (use_babel && !features.isRequired("jurabib")
2292 && !features.isRequired("hyperref")
2293 && !features.isRequired("varioref")
2294 && !features.isRequired("japanese")) {
2295 os << features.getBabelPresettings();
2297 os << from_utf8(babelCall(language_options.str(),
2298 !lyxrc.language_global_options)) + '\n';
2299 os << features.getBabelPostsettings();
2301 // In documents containing text in Thai language,
2302 // we must load inputenc after babel (see lib/languages).
2303 if (contains(features.getBabelPostsettings(), from_ascii("thai.ldf")))
2304 writeEncodingPreamble(os, features);
2306 // font selection must be done after babel with non-TeX fonts
2307 if (!fonts.empty() && features.useBabel() && useNonTeXFonts)
2308 os << from_utf8(fonts);
2310 if (features.isRequired("bicaption"))
2311 os << "\\usepackage{bicaption}\n";
2312 if (!listings_params.empty()
2313 || features.mustProvide("listings")
2314 || features.mustProvide("minted")) {
2316 os << "\\usepackage{minted}\n";
2318 os << "\\usepackage{listings}\n";
2320 string lst_params = listings_params;
2321 // If minted, do not output the language option (bug 11203)
2322 if (use_minted && contains(lst_params, "language=")) {
2323 vector<string> opts =
2324 getVectorFromString(lst_params, ",", false);
2325 for (size_t i = 0; i < opts.size(); ++i) {
2326 if (prefixIs(opts[i], "language="))
2327 opts.erase(opts.begin() + i--);
2329 lst_params = getStringFromVector(opts, ",");
2331 if (!lst_params.empty()) {
2333 os << "\\setminted{";
2336 // do not test validity because listings_params is
2337 // supposed to be valid
2339 InsetListingsParams(lst_params).separatedParams(true);
2340 os << from_utf8(par);
2344 // xunicode only needs to be loaded if tipa is used
2345 // (the rest is obsoleted by the new TU encoding).
2346 // It needs to be loaded at least after amsmath, amssymb,
2347 // esint and the other packages that provide special glyphs
2348 if (features.mustProvide("tipa") && useNonTeXFonts
2349 && !features.isProvided("xunicode")) {
2350 // The `xunicode` package officially only supports XeTeX,
2351 // but also works with LuaTeX. We work around its XeTeX test.
2352 if (features.runparams().flavor != OutputParams::XETEX) {
2353 os << "% Pretend to xunicode that we are XeTeX\n"
2354 << "\\def\\XeTeXpicfile{}\n";
2356 os << "\\usepackage{xunicode}\n";
2359 // covington must be loaded after beamerarticle
2360 if (features.isRequired("covington"))
2361 os << "\\usepackage{covington}\n";
2363 // Polyglossia must be loaded last ...
2364 if (use_polyglossia) {
2366 os << "\\usepackage{polyglossia}\n";
2367 // set the main language
2368 os << "\\setdefaultlanguage";
2369 if (!language->polyglossiaOpts().empty())
2370 os << "[" << from_ascii(language->polyglossiaOpts()) << "]";
2371 os << "{" << from_ascii(language->polyglossia()) << "}\n";
2372 // now setup the other languages
2373 set<string> const polylangs =
2374 features.getPolyglossiaLanguages();
2375 for (auto const & pl : polylangs) {
2376 // We do not output the options here; they are output in
2377 // the language switch commands. This is safer if multiple
2378 // varieties are used.
2379 if (pl == language->polyglossia())
2381 os << "\\setotherlanguage";
2382 os << "{" << from_ascii(pl) << "}\n";
2386 // ... but before biblatex (see #7065)
2387 if ((features.mustProvide("biblatex")
2388 || features.isRequired("biblatex-chicago"))
2389 && !features.isProvided("biblatex-chicago")
2390 && !features.isProvided("biblatex-natbib")
2391 && !features.isProvided("natbib-internal")
2392 && !features.isProvided("natbib")
2393 && !features.isProvided("jurabib")) {
2394 // The biblatex-chicago package has a differing interface
2395 // it uses a wrapper package and loads styles via fixed options
2396 bool const chicago = features.isRequired("biblatex-chicago");
2399 os << "\\usepackage";
2400 if (!biblatex_bibstyle.empty()
2401 && (biblatex_bibstyle == biblatex_citestyle)
2403 opts = "style=" + biblatex_bibstyle;
2405 } else if (!chicago) {
2406 if (!biblatex_bibstyle.empty()) {
2407 opts = "bibstyle=" + biblatex_bibstyle;
2410 if (!biblatex_citestyle.empty()) {
2411 opts += delim + "citestyle=" + biblatex_citestyle;
2415 if (!multibib.empty() && multibib != "child") {
2416 opts += delim + "refsection=" + multibib;
2419 if (bibtexCommand() == "bibtex8"
2420 || prefixIs(bibtexCommand(), "bibtex8 ")) {
2421 opts += delim + "backend=bibtex8";
2423 } else if (bibtexCommand() == "bibtex"
2424 || prefixIs(bibtexCommand(), "bibtex ")) {
2425 opts += delim + "backend=bibtex";
2428 if (!bib_encoding.empty() && encodings.fromLyXName(bib_encoding)) {
2429 opts += delim + "bibencoding="
2430 + encodings.fromLyXName(bib_encoding)->latexName();
2433 if (!biblio_opts.empty())
2434 opts += delim + biblio_opts;
2436 os << "[" << opts << "]";
2438 os << "{biblatex-chicago}\n";
2440 os << "{biblatex}\n";
2444 // Load custom language package here
2445 if (features.langPackage() == LaTeXFeatures::LANG_PACK_CUSTOM) {
2446 if (lang_package == "default")
2447 os << from_utf8(lyxrc.language_custom_package);
2449 os << from_utf8(lang_package);
2453 // Since menukeys uses catoptions, which does some heavy changes on key-value options,
2454 // it is recommended to load menukeys as the last package (even after hyperref)
2455 if (features.isRequired("menukeys"))
2456 os << "\\usepackage{menukeys}\n";
2458 docstring const i18npreamble =
2459 features.getTClassI18nPreamble(use_babel, use_polyglossia,
2461 if (!i18npreamble.empty())
2462 os << i18npreamble + '\n';
2468 void BufferParams::useClassDefaults()
2470 DocumentClass const & tclass = documentClass();
2472 sides = tclass.sides();
2473 columns = tclass.columns();
2474 pagestyle = tclass.pagestyle();
2475 tablestyle = tclass.tablestyle();
2476 use_default_options = true;
2477 // Only if class has a ToC hierarchy
2478 if (tclass.hasTocLevels()) {
2479 secnumdepth = tclass.secnumdepth();
2480 tocdepth = tclass.tocdepth();
2485 bool BufferParams::hasClassDefaults() const
2487 DocumentClass const & tclass = documentClass();
2489 return sides == tclass.sides()
2490 && columns == tclass.columns()
2491 && pagestyle == tclass.pagestyle()
2492 && tablestyle == tclass.tablestyle()
2493 && use_default_options
2494 && secnumdepth == tclass.secnumdepth()
2495 && tocdepth == tclass.tocdepth();
2499 DocumentClass const & BufferParams::documentClass() const
2505 DocumentClassConstPtr BufferParams::documentClassPtr() const
2511 void BufferParams::setDocumentClass(DocumentClassConstPtr tc)
2513 // evil, but this function is evil
2514 doc_class_ = const_pointer_cast<DocumentClass>(tc);
2515 invalidateConverterCache();
2519 bool BufferParams::setBaseClass(string const & classname, string const & path)
2521 LYXERR(Debug::TCLASS, "setBaseClass: " << classname);
2522 LayoutFileList & bcl = LayoutFileList::get();
2523 if (!bcl.haveClass(classname)) {
2525 bformat(_("The layout file:\n"
2527 "could not be found. A default textclass with default\n"
2528 "layouts will be used. LyX will not be able to produce\n"
2530 from_utf8(classname));
2531 frontend::Alert::error(_("Document class not found"), s);
2532 bcl.addEmptyClass(classname);
2535 bool const success = bcl[classname].load(path);
2538 bformat(_("Due to some error in it, the layout file:\n"
2540 "could not be loaded. A default textclass with default\n"
2541 "layouts will be used. LyX will not be able to produce\n"
2543 from_utf8(classname));
2544 frontend::Alert::error(_("Could not load class"), s);
2545 bcl.addEmptyClass(classname);
2548 pimpl_->baseClass_ = classname;
2549 layout_modules_.adaptToBaseClass(baseClass(), removed_modules_);
2554 LayoutFile const * BufferParams::baseClass() const
2556 if (LayoutFileList::get().haveClass(pimpl_->baseClass_))
2557 return &(LayoutFileList::get()[pimpl_->baseClass_]);
2563 LayoutFileIndex const & BufferParams::baseClassID() const
2565 return pimpl_->baseClass_;
2569 void BufferParams::makeDocumentClass(bool const clone)
2574 invalidateConverterCache();
2575 LayoutModuleList mods;
2576 for (auto const & mod : layout_modules_)
2577 mods.push_back(mod);
2579 doc_class_ = getDocumentClass(*baseClass(), mods, cite_engine_, clone);
2581 TextClass::ReturnValues success = TextClass::OK;
2582 if (!forced_local_layout_.empty())
2583 success = doc_class_->read(to_utf8(forced_local_layout_),
2585 if (!local_layout_.empty() &&
2586 (success == TextClass::OK || success == TextClass::OK_OLDFORMAT))
2587 success = doc_class_->read(to_utf8(local_layout_), TextClass::MODULE);
2588 if (success != TextClass::OK && success != TextClass::OK_OLDFORMAT) {
2589 docstring const msg = _("Error reading internal layout information");
2590 frontend::Alert::warning(_("Read Error"), msg);
2595 bool BufferParams::layoutModuleCanBeAdded(string const & modName) const
2597 return layout_modules_.moduleCanBeAdded(modName, baseClass());
2601 docstring BufferParams::getLocalLayout(bool forced) const
2604 return from_utf8(doc_class_->forcedLayouts());
2606 return local_layout_;
2610 void BufferParams::setLocalLayout(docstring const & layout, bool forced)
2613 forced_local_layout_ = layout;
2615 local_layout_ = layout;
2619 bool BufferParams::addLayoutModule(string const & modName)
2621 for (auto const & mod : layout_modules_)
2624 layout_modules_.push_back(modName);
2629 string BufferParams::bufferFormat() const
2631 return documentClass().outputFormat();
2635 bool BufferParams::isExportable(string const & format, bool need_viewable) const
2637 FormatList const & formats = exportableFormats(need_viewable);
2638 for (auto const & fmt : formats) {
2639 if (fmt->name() == format)
2646 FormatList const & BufferParams::exportableFormats(bool only_viewable) const
2648 FormatList & cached = only_viewable ?
2649 pimpl_->viewableFormatList : pimpl_->exportableFormatList;
2650 bool & valid = only_viewable ?
2651 pimpl_->isViewCacheValid : pimpl_->isExportCacheValid;
2655 vector<string> const backs = backends();
2656 set<string> excludes;
2657 if (useNonTeXFonts) {
2658 excludes.insert("latex");
2659 excludes.insert("pdflatex");
2660 } else if (inputenc != "ascii" && inputenc != "utf8-plain") {
2661 // XeTeX with TeX fonts requires input encoding ascii (#10600).
2662 excludes.insert("xetex");
2666 theConverters().getReachable(backs[0], only_viewable, true, excludes);
2667 vector<string>::const_iterator it = backs.begin() + 1;
2668 for (; it != backs.end(); ++it) {
2669 FormatList r = theConverters().getReachable(*it, only_viewable,
2671 result.insert(result.end(), r.begin(), r.end());
2673 sort(result.begin(), result.end(), Format::formatSorter);
2680 vector<string> BufferParams::backends() const
2683 string const buffmt = bufferFormat();
2685 // FIXME: Don't hardcode format names here, but use a flag
2686 if (buffmt == "latex") {
2687 if (encoding().package() == Encoding::japanese)
2688 v.push_back("platex");
2690 if (!useNonTeXFonts) {
2691 v.push_back("pdflatex");
2692 v.push_back("latex");
2695 || inputenc == "ascii" || inputenc == "utf8-plain")
2696 v.push_back("xetex");
2697 v.push_back("luatex");
2698 v.push_back("dviluatex");
2701 string rbuffmt = buffmt;
2702 // If we use an OutputFormat in Japanese docs,
2703 // we need special format in order to get the path
2704 // via pLaTeX (#8823)
2705 if (documentClass().hasOutputFormat()
2706 && encoding().package() == Encoding::japanese)
2708 v.push_back(rbuffmt);
2711 v.push_back("xhtml");
2712 v.push_back("docbook5");
2713 v.push_back("text");
2719 OutputParams::FLAVOR BufferParams::getOutputFlavor(string const & format) const
2721 string const dformat = (format.empty() || format == "default") ?
2722 getDefaultOutputFormat() : format;
2723 DefaultFlavorCache::const_iterator it =
2724 default_flavors_.find(dformat);
2726 if (it != default_flavors_.end())
2729 OutputParams::FLAVOR result = OutputParams::LATEX;
2731 // FIXME It'd be better not to hardcode this, but to do
2732 // something with formats.
2733 if (dformat == "xhtml")
2734 result = OutputParams::HTML;
2735 else if (dformat == "docbook5")
2736 result = OutputParams::DOCBOOK5;
2737 else if (dformat == "text")
2738 result = OutputParams::TEXT;
2739 else if (dformat == "lyx")
2740 result = OutputParams::LYX;
2741 else if (dformat == "pdflatex")
2742 result = OutputParams::PDFLATEX;
2743 else if (dformat == "xetex")
2744 result = OutputParams::XETEX;
2745 else if (dformat == "luatex")
2746 result = OutputParams::LUATEX;
2747 else if (dformat == "dviluatex")
2748 result = OutputParams::DVILUATEX;
2750 // Try to determine flavor of default output format
2751 vector<string> backs = backends();
2752 if (find(backs.begin(), backs.end(), dformat) == backs.end()) {
2753 // Get shortest path to format
2754 Graph::EdgePath path;
2755 for (auto const & bvar : backs) {
2756 Graph::EdgePath p = theConverters().getPath(bvar, dformat);
2757 if (!p.empty() && (path.empty() || p.size() < path.size())) {
2762 result = theConverters().getFlavor(path);
2765 // cache this flavor
2766 default_flavors_[dformat] = result;
2771 string BufferParams::getDefaultOutputFormat() const
2773 if (!default_output_format.empty()
2774 && default_output_format != "default")
2775 return default_output_format;
2776 if (encoding().package() == Encoding::japanese)
2777 return lyxrc.default_platex_view_format;
2779 return lyxrc.default_otf_view_format;
2780 return lyxrc.default_view_format;
2783 Font const BufferParams::getFont() const
2785 FontInfo f = documentClass().defaultfont();
2786 if (fonts_default_family == "rmdefault")
2787 f.setFamily(ROMAN_FAMILY);
2788 else if (fonts_default_family == "sfdefault")
2789 f.setFamily(SANS_FAMILY);
2790 else if (fonts_default_family == "ttdefault")
2791 f.setFamily(TYPEWRITER_FAMILY);
2792 return Font(f, language);
2796 InsetQuotesParams::QuoteStyle BufferParams::getQuoteStyle(string const & qs) const
2798 return quotesstyletranslator().find(qs);
2802 bool BufferParams::isLatex() const
2804 return documentClass().outputType() == LATEX;
2808 bool BufferParams::isLiterate() const
2810 return documentClass().outputType() == LITERATE;
2814 void BufferParams::readPreamble(Lexer & lex)
2816 if (lex.getString() != "\\begin_preamble")
2817 lyxerr << "Error (BufferParams::readPreamble):"
2818 "consistency check failed." << endl;
2820 preamble = lex.getLongString(from_ascii("\\end_preamble"));
2824 void BufferParams::readLocalLayout(Lexer & lex, bool forced)
2826 string const expected = forced ? "\\begin_forced_local_layout" :
2827 "\\begin_local_layout";
2828 if (lex.getString() != expected)
2829 lyxerr << "Error (BufferParams::readLocalLayout):"
2830 "consistency check failed." << endl;
2833 forced_local_layout_ =
2834 lex.getLongString(from_ascii("\\end_forced_local_layout"));
2836 local_layout_ = lex.getLongString(from_ascii("\\end_local_layout"));
2840 bool BufferParams::setLanguage(string const & lang)
2842 Language const *new_language = languages.getLanguage(lang);
2843 if (!new_language) {
2844 // Language lang was not found
2847 language = new_language;
2852 void BufferParams::readLanguage(Lexer & lex)
2854 if (!lex.next()) return;
2856 string const tmptok = lex.getString();
2858 // check if tmptok is part of tex_babel in tex-defs.h
2859 if (!setLanguage(tmptok)) {
2860 // Language tmptok was not found
2861 language = default_language;
2862 lyxerr << "Warning: Setting language `"
2863 << tmptok << "' to `" << language->lang()
2869 void BufferParams::readGraphicsDriver(Lexer & lex)
2874 string const tmptok = lex.getString();
2875 // check if tmptok is part of tex_graphics in tex_defs.h
2878 string const test = tex_graphics[n++];
2880 if (test == tmptok) {
2881 graphics_driver = tmptok;
2886 "Warning: graphics driver `$$Token' not recognized!\n"
2887 " Setting graphics driver to `default'.\n");
2888 graphics_driver = "default";
2895 void BufferParams::readBullets(Lexer & lex)
2900 int const index = lex.getInteger();
2902 int temp_int = lex.getInteger();
2903 user_defined_bullet(index).setFont(temp_int);
2904 temp_bullet(index).setFont(temp_int);
2906 user_defined_bullet(index).setCharacter(temp_int);
2907 temp_bullet(index).setCharacter(temp_int);
2909 user_defined_bullet(index).setSize(temp_int);
2910 temp_bullet(index).setSize(temp_int);
2914 void BufferParams::readBulletsLaTeX(Lexer & lex)
2916 // The bullet class should be able to read this.
2919 int const index = lex.getInteger();
2921 docstring const temp_str = lex.getDocString();
2923 user_defined_bullet(index).setText(temp_str);
2924 temp_bullet(index).setText(temp_str);
2928 void BufferParams::readModules(Lexer & lex)
2930 if (!lex.eatLine()) {
2931 lyxerr << "Error (BufferParams::readModules):"
2932 "Unexpected end of input." << endl;
2936 string mod = lex.getString();
2937 if (mod == "\\end_modules")
2939 addLayoutModule(mod);
2945 void BufferParams::readRemovedModules(Lexer & lex)
2947 if (!lex.eatLine()) {
2948 lyxerr << "Error (BufferParams::readRemovedModules):"
2949 "Unexpected end of input." << endl;
2953 string mod = lex.getString();
2954 if (mod == "\\end_removed_modules")
2956 removed_modules_.push_back(mod);
2959 // now we want to remove any removed modules that were previously
2960 // added. normally, that will be because default modules were added in
2961 // setBaseClass(), which gets called when \textclass is read at the
2962 // start of the read.
2963 for (auto const & rm : removed_modules_) {
2964 LayoutModuleList::iterator const mit = layout_modules_.begin();
2965 LayoutModuleList::iterator const men = layout_modules_.end();
2966 LayoutModuleList::iterator found = find(mit, men, rm);
2969 layout_modules_.erase(found);
2974 void BufferParams::readIncludeonly(Lexer & lex)
2976 if (!lex.eatLine()) {
2977 lyxerr << "Error (BufferParams::readIncludeonly):"
2978 "Unexpected end of input." << endl;
2982 string child = lex.getString();
2983 if (child == "\\end_includeonly")
2985 included_children_.push_back(child);
2991 string BufferParams::paperSizeName(PapersizePurpose purpose, string const & psize) const
2993 PAPER_SIZE ppsize = psize.empty() ? papersize : papersizetranslator().find(psize);
2996 if (documentClass().pagesize() == "default")
2997 // could be anything, so don't guess
2999 return paperSizeName(purpose, documentClass().pagesize());
3000 case PAPER_CUSTOM: {
3001 if (purpose == XDVI && !paperwidth.empty() &&
3002 !paperheight.empty()) {
3003 // heightxwidth<unit>
3004 string first = paperwidth;
3005 string second = paperheight;
3006 if (orientation == ORIENTATION_LANDSCAPE)
3009 return first.erase(first.length() - 2)
3015 // dvips and dvipdfm do not know this
3016 if (purpose == DVIPS || purpose == DVIPDFM)
3020 if (purpose == DVIPS || purpose == DVIPDFM)
3024 if (purpose == DVIPS || purpose == DVIPDFM)
3034 if (purpose == DVIPS || purpose == DVIPDFM)
3038 if (purpose == DVIPS || purpose == DVIPDFM)
3042 if (purpose == DVIPS || purpose == DVIPDFM)
3046 if (purpose == DVIPS || purpose == DVIPDFM)
3050 if (purpose == DVIPS || purpose == DVIPDFM)
3054 // dvipdfm does not know this
3055 if (purpose == DVIPDFM)
3059 if (purpose == DVIPDFM)
3063 if (purpose == DVIPS || purpose == DVIPDFM)
3067 if (purpose == DVIPS || purpose == DVIPDFM)
3071 if (purpose == DVIPS || purpose == DVIPDFM)
3075 if (purpose == DVIPS || purpose == DVIPDFM)
3079 if (purpose == DVIPS || purpose == DVIPDFM)
3083 if (purpose == DVIPS || purpose == DVIPDFM)
3087 if (purpose == DVIPS || purpose == DVIPDFM)
3091 if (purpose == DVIPS || purpose == DVIPDFM)
3095 if (purpose == DVIPS || purpose == DVIPDFM)
3099 if (purpose == DVIPS || purpose == DVIPDFM)
3103 if (purpose == DVIPS || purpose == DVIPDFM)
3107 if (purpose == DVIPS || purpose == DVIPDFM)
3111 if (purpose == DVIPS || purpose == DVIPDFM)
3115 if (purpose == DVIPS || purpose == DVIPDFM)
3119 if (purpose == DVIPS || purpose == DVIPDFM)
3122 case PAPER_USEXECUTIVE:
3123 // dvipdfm does not know this
3124 if (purpose == DVIPDFM)
3129 case PAPER_USLETTER:
3131 if (purpose == XDVI)
3138 string const BufferParams::dvips_options() const
3142 // If the class loads the geometry package, we do not know which
3143 // paper size is used, since we do not set it (bug 7013).
3144 // Therefore we must not specify any argument here.
3145 // dvips gets the correct paper size via DVI specials in this case
3146 // (if the class uses the geometry package correctly).
3147 if (documentClass().provides("geometry"))
3151 && papersize == PAPER_CUSTOM
3152 && !lyxrc.print_paper_dimension_flag.empty()
3153 && !paperwidth.empty()
3154 && !paperheight.empty()) {
3155 // using a custom papersize
3156 result = lyxrc.print_paper_dimension_flag;
3157 result += ' ' + paperwidth;
3158 result += ',' + paperheight;
3160 string const paper_option = paperSizeName(DVIPS);
3161 if (!paper_option.empty() && (paper_option != "letter" ||
3162 orientation != ORIENTATION_LANDSCAPE)) {
3163 // dvips won't accept -t letter -t landscape.
3164 // In all other cases, include the paper size
3166 result = lyxrc.print_paper_flag;
3167 result += ' ' + paper_option;
3170 if (orientation == ORIENTATION_LANDSCAPE &&
3171 papersize != PAPER_CUSTOM)
3172 result += ' ' + lyxrc.print_landscape_flag;
3177 string const BufferParams::main_font_encoding() const
3179 if (font_encodings().empty()) {
3180 if (ascii_lowercase(language->fontenc(*this)) == "none")
3184 return font_encodings().back();
3188 vector<string> const BufferParams::font_encodings() const
3190 string doc_fontenc = (fontenc == "auto") ? string() : fontenc;
3192 vector<string> fontencs;
3194 // "default" means "no explicit font encoding"
3195 if (doc_fontenc != "default") {
3196 if (!doc_fontenc.empty())
3197 // If we have a custom setting, we use only that!
3198 return getVectorFromString(doc_fontenc);
3199 if (!language->fontenc(*this).empty()
3200 && ascii_lowercase(language->fontenc(*this)) != "none") {
3201 vector<string> fencs = getVectorFromString(language->fontenc(*this));
3202 for (auto & fe : fencs) {
3203 if (find(fontencs.begin(), fontencs.end(), fe) == fontencs.end())
3204 fontencs.push_back(fe);
3213 string BufferParams::babelCall(string const & lang_opts, bool const langoptions) const
3215 // suppress the babel call if there is no BabelName defined
3216 // for the document language in the lib/languages file and if no
3217 // other languages are used (lang_opts is then empty)
3218 if (lang_opts.empty())
3220 // The prefs may require the languages to
3221 // be submitted to babel itself (not the class).
3223 return "\\usepackage[" + lang_opts + "]{babel}";
3224 return "\\usepackage{babel}";
3228 docstring BufferParams::getGraphicsDriver(string const & package) const
3232 if (package == "geometry") {
3233 if (graphics_driver == "dvips"
3234 || graphics_driver == "dvipdfm"
3235 || graphics_driver == "pdftex"
3236 || graphics_driver == "vtex")
3237 result = from_ascii(graphics_driver);
3238 else if (graphics_driver == "dvipdfmx")
3239 result = from_ascii("dvipdfm");
3246 void BufferParams::writeEncodingPreamble(otexstream & os,
3247 LaTeXFeatures & features) const
3249 // With no-TeX fonts we use utf8-plain without encoding package.
3253 if (inputenc == "auto-legacy") {
3254 string const doc_encoding =
3255 language->encoding()->latexName();
3256 Encoding::Package const package =
3257 language->encoding()->package();
3259 // Create list of inputenc options:
3260 set<string> encoding_set;
3261 // luainputenc fails with more than one encoding
3262 if (features.runparams().flavor != OutputParams::LUATEX
3263 && features.runparams().flavor != OutputParams::DVILUATEX)
3264 // list all input encodings used in the document
3265 encoding_set = features.getEncodingSet(doc_encoding);
3267 // The "japanese" babel-language requires the pLaTeX engine
3268 // which conflicts with "inputenc".
3269 // See http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129680.html
3270 if ((!encoding_set.empty() || package == Encoding::inputenc)
3271 && !features.isRequired("japanese")
3272 && !features.isProvided("inputenc")) {
3273 os << "\\usepackage[";
3274 set<string>::const_iterator it = encoding_set.begin();
3275 set<string>::const_iterator const end = encoding_set.end();
3277 os << from_ascii(*it);
3280 for (; it != end; ++it)
3281 os << ',' << from_ascii(*it);
3282 if (package == Encoding::inputenc) {
3283 if (!encoding_set.empty())
3285 os << from_ascii(doc_encoding);
3287 if (features.runparams().flavor == OutputParams::LUATEX
3288 || features.runparams().flavor == OutputParams::DVILUATEX)
3289 os << "]{luainputenc}\n";
3291 os << "]{inputenc}\n";
3293 } else if (inputenc != "auto-legacy-plain") {
3294 switch (encoding().package()) {
3295 case Encoding::none:
3297 case Encoding::japanese:
3298 if (encoding().iconvName() != "UTF-8"
3299 && !features.runparams().isFullUnicode())
3300 // don't default to [utf8]{inputenc} with TeXLive >= 18
3301 os << "\\ifdefined\\UseRawInputEncoding\n"
3302 << " \\UseRawInputEncoding\\fi\n";
3304 case Encoding::inputenc:
3305 // do not load inputenc if japanese is used
3306 // or if the class provides inputenc
3307 if (features.isRequired("japanese")
3308 || features.isProvided("inputenc"))
3310 os << "\\usepackage[" << from_ascii(encoding().latexName());
3311 if (features.runparams().flavor == OutputParams::LUATEX
3312 || features.runparams().flavor == OutputParams::DVILUATEX)
3313 os << "]{luainputenc}\n";
3315 os << "]{inputenc}\n";
3319 if (inputenc == "auto-legacy-plain" || features.isRequired("japanese")) {
3320 // don't default to [utf8]{inputenc} with TeXLive >= 18
3321 os << "\\ifdefined\\UseRawInputEncoding\n";
3322 os << " \\UseRawInputEncoding\\fi\n";
3327 string const BufferParams::parseFontName(string const & name) const
3329 string mangled = name;
3330 size_t const idx = mangled.find('[');
3331 if (idx == string::npos || idx == 0)
3334 return mangled.substr(0, idx - 1);
3338 string const BufferParams::loadFonts(LaTeXFeatures & features) const
3340 if (fontsRoman() == "default" && fontsSans() == "default"
3341 && fontsTypewriter() == "default"
3342 && (fontsMath() == "default" || fontsMath() == "auto"))
3348 /* Fontspec (XeTeX, LuaTeX): we provide GUI support for oldstyle
3349 * numbers (Numbers=OldStyle) and sf/tt scaling. The Ligatures=TeX/
3350 * Mapping=tex-text option assures TeX ligatures (such as "--")
3351 * are resolved. Note that tt does not use these ligatures.
3353 * -- add more GUI options?
3354 * -- add more fonts (fonts for other scripts)
3355 * -- if there's a way to find out if a font really supports
3356 * OldStyle, enable/disable the widget accordingly.
3358 if (useNonTeXFonts && features.isAvailable("fontspec")) {
3359 // "Mapping=tex-text" and "Ligatures=TeX" are equivalent.
3360 // However, until v.2 (2010/07/11) fontspec only knew
3361 // Mapping=tex-text (for XeTeX only); then "Ligatures=TeX"
3362 // was introduced for both XeTeX and LuaTeX (LuaTeX
3363 // didn't understand "Mapping=tex-text", while XeTeX
3364 // understood both. With most recent versions, both
3365 // variants are understood by both engines. However,
3366 // we want to provide support for at least TeXLive 2009
3367 // (for XeTeX; LuaTeX is only supported as of v.2)
3368 // As of 2017/11/03, Babel has its own higher-level
3369 // interface on top of fontspec that is to be used.
3370 bool const babelfonts = features.useBabel()
3371 && features.isAvailable("babel-2017/11/03");
3372 string const texmapping =
3373 (features.runparams().flavor == OutputParams::XETEX) ?
3374 "Mapping=tex-text" : "Ligatures=TeX";
3375 if (fontsRoman() != "default") {
3377 os << "\\babelfont{rm}[";
3379 os << "\\setmainfont[";
3380 if (!font_roman_opts.empty())
3381 os << font_roman_opts << ',';
3383 if (fonts_roman_osf)
3384 os << ",Numbers=OldStyle";
3385 os << "]{" << parseFontName(fontsRoman()) << "}\n";
3387 if (fontsSans() != "default") {
3388 string const sans = parseFontName(fontsSans());
3389 if (fontsSansScale() != 100) {
3391 os << "\\babelfont{sf}";
3393 os << "\\setsansfont";
3395 << float(fontsSansScale()) / 100 << ',';
3397 os << "Numbers=OldStyle,";
3398 if (!font_sans_opts.empty())
3399 os << font_sans_opts << ',';
3400 os << texmapping << "]{"
3404 os << "\\babelfont{sf}[";
3406 os << "\\setsansfont[";
3408 os << "Numbers=OldStyle,";
3409 if (!font_sans_opts.empty())
3410 os << font_sans_opts << ',';
3411 os << texmapping << "]{"
3415 if (fontsTypewriter() != "default") {
3416 string const mono = parseFontName(fontsTypewriter());
3417 if (fontsTypewriterScale() != 100) {
3419 os << "\\babelfont{tt}";
3421 os << "\\setmonofont";
3423 << float(fontsTypewriterScale()) / 100;
3424 if (fonts_typewriter_osf)
3425 os << ",Numbers=OldStyle";
3426 if (!font_typewriter_opts.empty())
3427 os << ',' << font_typewriter_opts;
3432 os << "\\babelfont{tt}";
3434 os << "\\setmonofont";
3435 if (!font_typewriter_opts.empty() || fonts_typewriter_osf) {
3437 if (fonts_typewriter_osf)
3438 os << "Numbers=OldStyle";
3439 if (!font_typewriter_opts.empty()) {
3440 if (fonts_typewriter_osf)
3442 os << font_typewriter_opts;
3446 os << '{' << mono << "}\n";
3453 bool const ot1 = (main_font_encoding() == "default" || main_font_encoding() == "OT1");
3454 bool const dryrun = features.runparams().dryrun;
3455 bool const complete = (fontsSans() == "default" && fontsTypewriter() == "default");
3456 bool const nomath = (fontsMath() == "default");
3459 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsRoman())).getLaTeXCode(
3460 dryrun, ot1, complete, fonts_expert_sc, fonts_roman_osf,
3461 nomath, font_roman_opts);
3464 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsSans())).getLaTeXCode(
3465 dryrun, ot1, complete, fonts_expert_sc, fonts_sans_osf,
3466 nomath, font_sans_opts, fontsSansScale());
3468 // MONOSPACED/TYPEWRITER
3469 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsTypewriter())).getLaTeXCode(
3470 dryrun, ot1, complete, fonts_expert_sc, fonts_typewriter_osf,
3471 nomath, font_typewriter_opts, fontsTypewriterScale());
3474 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsMath())).getLaTeXCode(
3475 dryrun, ot1, complete, fonts_expert_sc, fonts_roman_osf,
3482 Encoding const & BufferParams::encoding() const
3484 // Main encoding for LaTeX output.
3486 return *(encodings.fromLyXName("utf8-plain"));
3487 if (inputenc == "auto-legacy" || inputenc == "auto-legacy-plain")
3488 return *language->encoding();
3489 if (inputenc == "utf8" && language->lang() == "japanese")
3490 return *(encodings.fromLyXName("utf8-platex"));
3491 Encoding const * const enc = encodings.fromLyXName(inputenc);
3494 LYXERR0("Unknown inputenc value `" << inputenc
3495 << "'. Using `auto' instead.");
3496 return *language->encoding();
3500 string const & BufferParams::defaultBiblioStyle() const
3502 if (!biblio_style.empty())
3503 return biblio_style;
3505 map<string, string> const & bs = documentClass().defaultBiblioStyle();
3506 auto cit = bs.find(theCiteEnginesList.getTypeAsString(citeEngineType()));
3507 if (cit != bs.end())
3510 return empty_string();
3514 bool const & BufferParams::fullAuthorList() const
3516 return documentClass().fullAuthorList();
3520 string BufferParams::getCiteAlias(string const & s) const
3522 vector<string> commands =
3523 documentClass().citeCommands(citeEngineType());
3524 // If it is a real command, don't treat it as an alias
3525 if (find(commands.begin(), commands.end(), s) != commands.end())
3527 map<string,string> aliases = documentClass().citeCommandAliases();
3528 if (aliases.find(s) != aliases.end())
3534 vector<string> BufferParams::citeCommands() const
3536 static CitationStyle const default_style;
3537 vector<string> commands =
3538 documentClass().citeCommands(citeEngineType());
3539 if (commands.empty())
3540 commands.push_back(default_style.name);
3545 vector<CitationStyle> BufferParams::citeStyles() const
3547 static CitationStyle const default_style;
3548 vector<CitationStyle> styles =
3549 documentClass().citeStyles(citeEngineType());
3551 styles.push_back(default_style);
3556 string const BufferParams::bibtexCommand() const
3558 // Return document-specific setting if available
3559 if (bibtex_command != "default")
3560 return bibtex_command;
3562 // If we have "default" in document settings, consult the prefs
3563 // 1. Japanese (uses a specific processor)
3564 if (encoding().package() == Encoding::japanese) {
3565 if (lyxrc.jbibtex_command != "automatic")
3566 // Return the specified program, if "automatic" is not set
3567 return lyxrc.jbibtex_command;
3568 else if (!useBiblatex()) {
3569 // With classic BibTeX, return pbibtex, jbibtex, bibtex
3570 if (lyxrc.jbibtex_alternatives.find("pbibtex") != lyxrc.jbibtex_alternatives.end())
3572 if (lyxrc.jbibtex_alternatives.find("jbibtex") != lyxrc.jbibtex_alternatives.end())
3577 // 2. All other languages
3578 else if (lyxrc.bibtex_command != "automatic")
3579 // Return the specified program, if "automatic" is not set
3580 return lyxrc.bibtex_command;
3582 // 3. Automatic: find the most suitable for the current cite framework
3583 if (useBiblatex()) {
3584 // For Biblatex, we prefer biber (also for Japanese)
3585 // and fall back to bibtex8 and, as last resort, bibtex
3586 if (lyxrc.bibtex_alternatives.find("biber") != lyxrc.bibtex_alternatives.end())
3588 else if (lyxrc.bibtex_alternatives.find("bibtex8") != lyxrc.bibtex_alternatives.end())
3595 bool BufferParams::useBiblatex() const
3597 return theCiteEnginesList[citeEngine()]->getCiteFramework() == "biblatex";
3601 void BufferParams::invalidateConverterCache() const
3603 pimpl_->isExportCacheValid = false;
3604 pimpl_->isViewCacheValid = false;
3608 // We shouldn't need to reset the params here, since anything
3609 // we need will be recopied.
3610 void BufferParams::copyForAdvFR(const BufferParams & bp)
3612 string const & lang = bp.language->lang();
3614 layout_modules_ = bp.layout_modules_;
3615 string const & doc_class = bp.documentClass().name();
3616 setBaseClass(doc_class);
3620 void BufferParams::setBibFileEncoding(string const & file, string const & enc)
3622 bib_encodings[file] = enc;
3626 string const BufferParams::bibFileEncoding(string const & file) const
3628 if (bib_encodings.find(file) == bib_encodings.end())
3630 return bib_encodings.find(file)->second;