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"
36 #include "ModuleList.h"
40 #include "OutputParams.h"
42 #include "texstream.h"
45 #include "PDFOptions.h"
47 #include "frontends/alert.h"
49 #include "insets/InsetListingsParams.h"
51 #include "support/convert.h"
52 #include "support/debug.h"
53 #include "support/docstream.h"
54 #include "support/FileName.h"
55 #include "support/filetools.h"
56 #include "support/gettext.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 suppress_date = false;
453 justification = true;
454 // no color is the default (white)
455 backgroundcolor = lyx::rgbFromHexName("#ffffff");
456 isbackgroundcolor = false;
457 // no color is the default (black)
458 fontcolor = lyx::rgbFromHexName("#000000");
460 // light gray is the default font color for greyed-out notes
461 notefontcolor = lyx::rgbFromHexName("#cccccc");
462 boxbgcolor = lyx::rgbFromHexName("#ff0000");
463 compressed = lyxrc.save_compressed;
464 for (int iter = 0; iter < 4; ++iter) {
465 user_defined_bullet(iter) = ITEMIZE_DEFAULTS[iter];
466 temp_bullet(iter) = ITEMIZE_DEFAULTS[iter];
469 indiceslist().addDefault(B_("Index"));
470 html_be_strict = false;
471 html_math_output = MathML;
472 html_math_img_scale = 1.0;
473 html_css_as_file = false;
474 display_pixel_ratio = 1.0;
476 shell_escape = false;
482 // map current author
483 author_map_[pimpl_->authorlist.get(0).bufferId()] = 0;
487 docstring BufferParams::B_(string const & l10n) const
489 LASSERT(language, return from_utf8(l10n));
490 return getMessages(language->code()).get(l10n);
494 BufferParams::Package BufferParams::use_package(std::string const & p) const
496 PackageMap::const_iterator it = use_packages.find(p);
497 if (it == use_packages.end())
503 void BufferParams::use_package(std::string const & p, BufferParams::Package u)
509 map<string, string> const & BufferParams::auto_packages()
511 static map<string, string> packages;
512 if (packages.empty()) {
513 // We could have a race condition here that two threads
514 // discover an empty map at the same time and want to fill
515 // it, but that is no problem, since the same contents is
516 // filled in twice then. Having the locker inside the
517 // packages.empty() condition has the advantage that we
518 // don't need the mutex overhead for simple reading.
520 Mutex::Locker locker(&mutex);
521 // adding a package here implies a file format change!
522 packages["amsmath"] =
523 N_("The LaTeX package amsmath is only used if AMS formula types or symbols from the AMS math toolbars are inserted into formulas");
524 packages["amssymb"] =
525 N_("The LaTeX package amssymb is only used if symbols from the AMS math toolbars are inserted into formulas");
527 N_("The LaTeX package cancel is only used if \\cancel commands are used in formulas");
529 N_("The LaTeX package esint is only used if special integral symbols are inserted into formulas");
530 packages["mathdots"] =
531 N_("The LaTeX package mathdots is only used if the command \\iddots is inserted into formulas");
532 packages["mathtools"] =
533 N_("The LaTeX package mathtools is only used if some mathematical relations are inserted into formulas");
535 N_("The LaTeX package mhchem is only used if either the command \\ce or \\cf is inserted into formulas");
536 packages["stackrel"] =
537 N_("The LaTeX package stackrel is only used if the command \\stackrel with subscript is inserted into formulas");
538 packages["stmaryrd"] =
539 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");
540 packages["undertilde"] =
541 N_("The LaTeX package undertilde is only used if you use the math frame decoration 'utilde'");
547 bool BufferParams::useBibtopic() const
551 return (use_bibtopic || (!multibib.empty() && multibib != "child"));
555 AuthorList & BufferParams::authors()
557 return pimpl_->authorlist;
561 AuthorList const & BufferParams::authors() const
563 return pimpl_->authorlist;
567 void BufferParams::addAuthor(Author a)
569 author_map_[a.bufferId()] = pimpl_->authorlist.record(a);
573 BranchList & BufferParams::branchlist()
575 return pimpl_->branchlist;
579 BranchList const & BufferParams::branchlist() const
581 return pimpl_->branchlist;
585 IndicesList & BufferParams::indiceslist()
587 return pimpl_->indiceslist;
591 IndicesList const & BufferParams::indiceslist() const
593 return pimpl_->indiceslist;
597 Bullet & BufferParams::temp_bullet(lyx::size_type const index)
599 LASSERT(index < 4, return pimpl_->temp_bullets[0]);
600 return pimpl_->temp_bullets[index];
604 Bullet const & BufferParams::temp_bullet(lyx::size_type const index) const
606 LASSERT(index < 4, return pimpl_->temp_bullets[0]);
607 return pimpl_->temp_bullets[index];
611 Bullet & BufferParams::user_defined_bullet(lyx::size_type const index)
613 LASSERT(index < 4, return pimpl_->temp_bullets[0]);
614 return pimpl_->user_defined_bullets[index];
618 Bullet const & BufferParams::user_defined_bullet(lyx::size_type const index) const
620 LASSERT(index < 4, return pimpl_->temp_bullets[0]);
621 return pimpl_->user_defined_bullets[index];
625 Spacing & BufferParams::spacing()
627 return pimpl_->spacing;
631 Spacing const & BufferParams::spacing() const
633 return pimpl_->spacing;
637 PDFOptions & BufferParams::pdfoptions()
639 return pimpl_->pdfoptions;
643 PDFOptions const & BufferParams::pdfoptions() const
645 return pimpl_->pdfoptions;
649 Length const & BufferParams::getMathIndent() const
651 return pimpl_->mathindent;
655 void BufferParams::setMathIndent(Length const & indent)
657 pimpl_->mathindent = indent;
661 Length const & BufferParams::getParIndent() const
663 return pimpl_->parindent;
667 void BufferParams::setParIndent(Length const & indent)
669 pimpl_->parindent = indent;
673 VSpace const & BufferParams::getDefSkip() const
675 return pimpl_->defskip;
679 void BufferParams::setDefSkip(VSpace const & vs)
681 // DEFSKIP will cause an infinite loop
682 LASSERT(vs.kind() != VSpace::DEFSKIP, return);
683 pimpl_->defskip = vs;
687 BufferParams::MathNumber BufferParams::getMathNumber() const
689 if (math_numbering_side != DEFAULT)
690 return math_numbering_side;
691 // FIXME: do not hardcode language here
692 else if (language->lang() == "arabic_arabi"
693 || documentClass().provides("leqno"))
700 string BufferParams::readToken(Lexer & lex, string const & token,
701 FileName const & filepath)
705 if (token == "\\textclass") {
707 string const classname = lex.getString();
708 // if there exists a local layout file, ignore the system one
709 // NOTE: in this case, the textclass (.cls file) is assumed to
712 LayoutFileList & bcl = LayoutFileList::get();
713 if (!filepath.empty()) {
714 // If classname is an absolute path, the document is
715 // using a local layout file which could not be accessed
716 // by a relative path. In this case the path is correct
717 // even if the document was moved to a different
718 // location. However, we will have a problem if the
719 // document was generated on a different platform.
720 bool isabsolute = FileName::isAbsolute(classname);
721 string const classpath = onlyPath(classname);
722 string const path = isabsolute ? classpath
723 : FileName(addPath(filepath.absFileName(),
724 classpath)).realPath();
725 string const oldpath = isabsolute ? string()
726 : FileName(addPath(origin, classpath)).realPath();
727 tcp = bcl.addLocalLayout(onlyFileName(classname), path, oldpath);
729 // that returns non-empty if a "local" layout file is found.
731 result = to_utf8(makeRelPath(from_utf8(onlyPath(tcp)),
732 from_utf8(filepath.absFileName())));
735 setBaseClass(onlyFileName(tcp));
737 setBaseClass(onlyFileName(classname));
738 // We assume that a tex class exists for local or unknown
739 // layouts so this warning, will only be given for system layouts.
740 if (!baseClass()->isTeXClassAvailable()) {
741 docstring const desc =
742 translateIfPossible(from_utf8(baseClass()->description()));
743 docstring const prereqs =
744 from_utf8(baseClass()->prerequisites());
745 docstring const msg =
746 bformat(_("The selected document class\n"
748 "requires external files that are not available.\n"
749 "The document class can still be used, but the\n"
750 "document cannot be compiled until the following\n"
751 "prerequisites are installed:\n"
753 "See section 3.1.2.2 (Class Availability) of the\n"
754 "User's Guide for more information."), desc, prereqs);
755 frontend::Alert::warning(_("Document class not available"),
758 } else if (token == "\\save_transient_properties") {
759 lex >> save_transient_properties;
760 } else if (token == "\\origin") {
762 origin = lex.getString();
763 string const sysdirprefix = "/systemlyxdir/";
764 if (prefixIs(origin, sysdirprefix)) {
766 if (inSystemDir(filepath, docsys))
767 origin.replace(0, sysdirprefix.length() - 1, docsys);
769 origin.replace(0, sysdirprefix.length() - 1,
770 package().system_support().absFileName());
772 } else if (token == "\\begin_preamble") {
774 } else if (token == "\\begin_local_layout") {
775 readLocalLayout(lex, false);
776 } else if (token == "\\begin_forced_local_layout") {
777 readLocalLayout(lex, true);
778 } else if (token == "\\begin_modules") {
780 } else if (token == "\\begin_removed_modules") {
781 readRemovedModules(lex);
782 } else if (token == "\\begin_includeonly") {
783 readIncludeonly(lex);
784 } else if (token == "\\maintain_unincluded_children") {
788 maintain_unincluded_children = CM_None;
789 else if (tmp == "mostly")
790 maintain_unincluded_children = CM_Mostly;
791 else if (tmp == "strict")
792 maintain_unincluded_children = CM_Strict;
793 } else if (token == "\\options") {
795 options = lex.getString();
796 } else if (token == "\\use_default_options") {
797 lex >> use_default_options;
798 } else if (token == "\\master") {
800 master = lex.getString();
801 if (!filepath.empty() && FileName::isAbsolute(origin)) {
802 bool const isabs = FileName::isAbsolute(master);
803 FileName const abspath(isabs ? master : origin + master);
804 bool const moved = filepath != FileName(origin);
805 if (moved && abspath.exists()) {
806 docstring const path = isabs
808 : from_utf8(abspath.realPath());
809 docstring const refpath =
810 from_utf8(filepath.absFileName());
811 master = to_utf8(makeRelPath(path, refpath));
814 } else if (token == "\\suppress_date") {
815 lex >> suppress_date;
816 } else if (token == "\\justification") {
817 lex >> justification;
818 } else if (token == "\\language") {
820 } else if (token == "\\language_package") {
822 lang_package = lex.getString();
823 } else if (token == "\\inputencoding") {
825 } else if (token == "\\graphics") {
826 readGraphicsDriver(lex);
827 } else if (token == "\\default_output_format") {
828 lex >> default_output_format;
829 } else if (token == "\\bibtex_command") {
831 bibtex_command = lex.getString();
832 } else if (token == "\\index_command") {
834 index_command = lex.getString();
835 } else if (token == "\\fontencoding") {
837 fontenc = lex.getString();
838 } else if (token == "\\font_roman") {
839 lex >> fonts_roman[0];
840 lex >> fonts_roman[1];
841 } else if (token == "\\font_sans") {
842 lex >> fonts_sans[0];
843 lex >> fonts_sans[1];
844 } else if (token == "\\font_typewriter") {
845 lex >> fonts_typewriter[0];
846 lex >> fonts_typewriter[1];
847 } else if (token == "\\font_math") {
848 lex >> fonts_math[0];
849 lex >> fonts_math[1];
850 } else if (token == "\\font_default_family") {
851 lex >> fonts_default_family;
852 } else if (token == "\\use_non_tex_fonts") {
853 lex >> useNonTeXFonts;
854 } else if (token == "\\font_sc") {
855 lex >> fonts_expert_sc;
856 } else if (token == "\\font_roman_osf") {
857 lex >> fonts_roman_osf;
858 } else if (token == "\\font_sans_osf") {
859 lex >> fonts_sans_osf;
860 } else if (token == "\\font_typewriter_osf") {
861 lex >> fonts_typewriter_osf;
862 } else if (token == "\\font_roman_opts") {
863 lex >> font_roman_opts;
864 } else if (token == "\\font_sf_scale") {
865 lex >> fonts_sans_scale[0];
866 lex >> fonts_sans_scale[1];
867 } else if (token == "\\font_sans_opts") {
868 lex >> font_sans_opts;
869 } else if (token == "\\font_tt_scale") {
870 lex >> fonts_typewriter_scale[0];
871 lex >> fonts_typewriter_scale[1];
872 } else if (token == "\\font_typewriter_opts") {
873 lex >> font_typewriter_opts;
874 } else if (token == "\\font_cjk") {
876 } else if (token == "\\use_microtype") {
877 lex >> use_microtype;
878 } else if (token == "\\use_dash_ligatures") {
879 lex >> use_dash_ligatures;
880 } else if (token == "\\paragraph_separation") {
883 paragraph_separation = parseptranslator().find(parsep);
884 } else if (token == "\\paragraph_indentation") {
886 string parindent = lex.getString();
887 if (parindent == "default")
888 pimpl_->parindent = Length();
890 pimpl_->parindent = Length(parindent);
891 } else if (token == "\\defskip") {
893 string const defskip = lex.getString();
894 pimpl_->defskip = VSpace(defskip);
895 if (pimpl_->defskip.kind() == VSpace::DEFSKIP)
897 pimpl_->defskip = VSpace(VSpace::MEDSKIP);
898 } else if (token == "\\is_math_indent") {
899 lex >> is_math_indent;
900 } else if (token == "\\math_indentation") {
902 string mathindent = lex.getString();
903 if (mathindent == "default")
904 pimpl_->mathindent = Length();
906 pimpl_->mathindent = Length(mathindent);
907 } else if (token == "\\math_numbering_side") {
911 math_numbering_side = LEFT;
912 else if (tmp == "right")
913 math_numbering_side = RIGHT;
915 math_numbering_side = DEFAULT;
916 } else if (token == "\\quotes_style") {
919 quotes_style = quotesstyletranslator().find(qstyle);
920 } else if (token == "\\dynamic_quotes") {
921 lex >> dynamic_quotes;
922 } else if (token == "\\papersize") {
925 papersize = papersizetranslator().find(ppsize);
926 } else if (token == "\\use_geometry") {
928 } else if (token == "\\use_package") {
933 use_package(package, packagetranslator().find(use));
934 } else if (token == "\\cite_engine") {
936 cite_engine_ = lex.getString();
937 } else if (token == "\\cite_engine_type") {
940 cite_engine_type_ = theCiteEnginesList.getType(engine_type);
941 } else if (token == "\\biblio_style") {
943 biblio_style = lex.getString();
944 } else if (token == "\\biblio_options") {
946 biblio_opts = trim(lex.getString());
947 } else if (token == "\\biblatex_bibstyle") {
949 biblatex_bibstyle = trim(lex.getString());
950 } else if (token == "\\biblatex_citestyle") {
952 biblatex_citestyle = trim(lex.getString());
953 } else if (token == "\\use_bibtopic") {
955 } else if (token == "\\multibib") {
957 } else if (token == "\\use_indices") {
959 } else if (token == "\\tracking_changes") {
960 lex >> track_changes;
961 } else if (token == "\\output_changes") {
962 lex >> output_changes;
963 } else if (token == "\\change_bars") {
965 } else if (token == "\\postpone_fragile_content") {
966 lex >> postpone_fragile_content;
967 } else if (token == "\\branch") {
969 docstring branch = lex.getDocString();
970 branchlist().add(branch);
973 string const tok = lex.getString();
974 if (tok == "\\end_branch")
976 Branch * branch_ptr = branchlist().find(branch);
977 if (tok == "\\selected") {
980 branch_ptr->setSelected(lex.getInteger());
982 if (tok == "\\filename_suffix") {
985 branch_ptr->setFileNameSuffix(lex.getInteger());
987 if (tok == "\\color") {
989 string color = lex.getString();
991 branch_ptr->setColor(color);
992 // Update also the Color table:
994 color = lcolor.getX11Name(Color_background);
996 lcolor.setColor(to_utf8(branch), color);
999 } else if (token == "\\index") {
1001 docstring index = lex.getDocString();
1003 indiceslist().add(index);
1006 string const tok = lex.getString();
1007 if (tok == "\\end_index")
1009 Index * index_ptr = indiceslist().find(index);
1010 if (tok == "\\shortcut") {
1012 shortcut = lex.getDocString();
1014 index_ptr->setShortcut(shortcut);
1016 if (tok == "\\color") {
1018 string color = lex.getString();
1020 index_ptr->setColor(color);
1021 // Update also the Color table:
1022 if (color == "none")
1023 color = lcolor.getX11Name(Color_background);
1025 if (!shortcut.empty())
1026 lcolor.setColor(to_utf8(shortcut), color);
1029 } else if (token == "\\author") {
1031 istringstream ss(lex.getString());
1035 } else if (token == "\\paperorientation") {
1038 orientation = paperorientationtranslator().find(orient);
1039 } else if (token == "\\backgroundcolor") {
1041 backgroundcolor = lyx::rgbFromHexName(lex.getString());
1042 isbackgroundcolor = true;
1043 } else if (token == "\\fontcolor") {
1045 fontcolor = lyx::rgbFromHexName(lex.getString());
1047 } else if (token == "\\notefontcolor") {
1049 string color = lex.getString();
1050 notefontcolor = lyx::rgbFromHexName(color);
1051 lcolor.setColor("notefontcolor", color);
1052 } else if (token == "\\boxbgcolor") {
1054 string color = lex.getString();
1055 boxbgcolor = lyx::rgbFromHexName(color);
1056 lcolor.setColor("boxbgcolor", color);
1057 } else if (token == "\\paperwidth") {
1059 } else if (token == "\\paperheight") {
1061 } else if (token == "\\leftmargin") {
1063 } else if (token == "\\topmargin") {
1065 } else if (token == "\\rightmargin") {
1067 } else if (token == "\\bottommargin") {
1068 lex >> bottommargin;
1069 } else if (token == "\\headheight") {
1071 } else if (token == "\\headsep") {
1073 } else if (token == "\\footskip") {
1075 } else if (token == "\\columnsep") {
1077 } else if (token == "\\paperfontsize") {
1079 } else if (token == "\\papercolumns") {
1081 } else if (token == "\\listings_params") {
1084 listings_params = InsetListingsParams(par).params();
1085 } else if (token == "\\papersides") {
1088 sides = sidestranslator().find(psides);
1089 } else if (token == "\\paperpagestyle") {
1091 } else if (token == "\\tablestyle") {
1093 } else if (token == "\\bullet") {
1095 } else if (token == "\\bulletLaTeX") {
1096 readBulletsLaTeX(lex);
1097 } else if (token == "\\secnumdepth") {
1099 } else if (token == "\\tocdepth") {
1101 } else if (token == "\\spacing") {
1105 if (nspacing == "other") {
1108 spacing().set(spacetranslator().find(nspacing), tmp_val);
1109 } else if (token == "\\float_placement") {
1110 lex >> float_placement;
1111 } else if (token == "\\float_alignment") {
1112 lex >> float_alignment;
1114 } else if (prefixIs(token, "\\pdf_") || token == "\\use_hyperref") {
1115 string toktmp = pdfoptions().readToken(lex, token);
1116 if (!toktmp.empty()) {
1117 lyxerr << "PDFOptions::readToken(): Unknown token: " <<
1121 } else if (token == "\\html_math_output") {
1124 html_math_output = static_cast<MathOutput>(temp);
1125 } else if (token == "\\html_be_strict") {
1126 lex >> html_be_strict;
1127 } else if (token == "\\html_css_as_file") {
1128 lex >> html_css_as_file;
1129 } else if (token == "\\html_math_img_scale") {
1130 lex >> html_math_img_scale;
1131 } else if (token == "\\html_latex_start") {
1133 html_latex_start = lex.getString();
1134 } else if (token == "\\html_latex_end") {
1136 html_latex_end = lex.getString();
1137 } else if (token == "\\output_sync") {
1139 } else if (token == "\\output_sync_macro") {
1140 lex >> output_sync_macro;
1141 } else if (token == "\\use_refstyle") {
1142 lex >> use_refstyle;
1143 } else if (token == "\\use_minted") {
1145 } else if (token == "\\use_lineno") {
1147 } else if (token == "\\lineno_options") {
1149 lineno_opts = trim(lex.getString());
1151 lyxerr << "BufferParams::readToken(): Unknown token: " <<
1161 // Quote argument if it contains spaces
1162 string quoteIfNeeded(string const & str) {
1163 if (contains(str, ' '))
1164 return "\"" + str + "\"";
1170 void BufferParams::writeFile(ostream & os, Buffer const * buf) const
1172 // The top of the file is written by the buffer.
1173 // Prints out the buffer info into the .lyx file given by file
1175 os << "\\save_transient_properties "
1176 << convert<string>(save_transient_properties) << '\n';
1178 // the document directory (must end with a path separator)
1179 // realPath() is used to resolve symlinks, while addPath(..., "")
1180 // ensures a trailing path separator.
1182 string filepath = addPath(buf->fileName().onlyPath().realPath(), "");
1183 string const sysdir = inSystemDir(FileName(filepath), docsys) ? docsys
1184 : addPath(package().system_support().realPath(), "");
1185 string const relpath =
1186 to_utf8(makeRelPath(from_utf8(filepath), from_utf8(sysdir)));
1187 if (!prefixIs(relpath, "../") && !FileName::isAbsolute(relpath))
1188 filepath = addPath("/systemlyxdir", relpath);
1189 else if (!save_transient_properties || !lyxrc.save_origin)
1190 filepath = "unavailable";
1191 os << "\\origin " << quoteIfNeeded(filepath) << '\n';
1194 os << "\\textclass "
1195 << quoteIfNeeded(buf->includedFilePath(addName(buf->layoutPos(),
1196 baseClass()->name()), "layout"))
1199 // then the preamble
1200 if (!preamble.empty()) {
1201 // remove '\n' from the end of preamble
1202 docstring const tmppreamble = rtrim(preamble, "\n");
1203 os << "\\begin_preamble\n"
1204 << to_utf8(tmppreamble)
1205 << "\n\\end_preamble\n";
1209 if (!options.empty()) {
1210 os << "\\options " << options << '\n';
1213 // use the class options defined in the layout?
1214 os << "\\use_default_options "
1215 << convert<string>(use_default_options) << "\n";
1217 // the master document
1218 if (!master.empty()) {
1219 os << "\\master " << master << '\n';
1223 if (!removed_modules_.empty()) {
1224 os << "\\begin_removed_modules" << '\n';
1225 for (auto const & mod : removed_modules_)
1227 os << "\\end_removed_modules" << '\n';
1231 if (!layout_modules_.empty()) {
1232 os << "\\begin_modules" << '\n';
1233 for (auto const & mod : layout_modules_)
1235 os << "\\end_modules" << '\n';
1239 if (!included_children_.empty()) {
1240 os << "\\begin_includeonly" << '\n';
1241 for (auto const & c : included_children_)
1243 os << "\\end_includeonly" << '\n';
1246 switch (maintain_unincluded_children) {
1257 os << "\\maintain_unincluded_children " << muc << '\n';
1259 // local layout information
1260 docstring const local_layout = getLocalLayout(false);
1261 if (!local_layout.empty()) {
1262 // remove '\n' from the end
1263 docstring const tmplocal = rtrim(local_layout, "\n");
1264 os << "\\begin_local_layout\n"
1265 << to_utf8(tmplocal)
1266 << "\n\\end_local_layout\n";
1268 docstring const forced_local_layout = getLocalLayout(true);
1269 if (!forced_local_layout.empty()) {
1270 // remove '\n' from the end
1271 docstring const tmplocal = rtrim(forced_local_layout, "\n");
1272 os << "\\begin_forced_local_layout\n"
1273 << to_utf8(tmplocal)
1274 << "\n\\end_forced_local_layout\n";
1277 // then the text parameters
1278 if (language != ignore_language)
1279 os << "\\language " << language->lang() << '\n';
1280 os << "\\language_package " << lang_package
1281 << "\n\\inputencoding " << inputenc
1282 << "\n\\fontencoding " << fontenc
1283 << "\n\\font_roman \"" << fonts_roman[0]
1284 << "\" \"" << fonts_roman[1] << '"'
1285 << "\n\\font_sans \"" << fonts_sans[0]
1286 << "\" \"" << fonts_sans[1] << '"'
1287 << "\n\\font_typewriter \"" << fonts_typewriter[0]
1288 << "\" \"" << fonts_typewriter[1] << '"'
1289 << "\n\\font_math \"" << fonts_math[0]
1290 << "\" \"" << fonts_math[1] << '"'
1291 << "\n\\font_default_family " << fonts_default_family
1292 << "\n\\use_non_tex_fonts " << convert<string>(useNonTeXFonts)
1293 << "\n\\font_sc " << convert<string>(fonts_expert_sc)
1294 << "\n\\font_roman_osf " << convert<string>(fonts_roman_osf)
1295 << "\n\\font_sans_osf " << convert<string>(fonts_sans_osf)
1296 << "\n\\font_typewriter_osf " << convert<string>(fonts_typewriter_osf);
1297 if (!font_roman_opts.empty())
1298 os << "\n\\font_roman_opts \"" << font_roman_opts << "\"";
1299 os << "\n\\font_sf_scale " << fonts_sans_scale[0]
1300 << ' ' << fonts_sans_scale[1];
1301 if (!font_sans_opts.empty())
1302 os << "\n\\font_sans_opts \"" << font_sans_opts << "\"";
1303 os << "\n\\font_tt_scale " << fonts_typewriter_scale[0]
1304 << ' ' << fonts_typewriter_scale[1];
1305 if (!font_typewriter_opts.empty())
1306 os << "\n\\font_typewriter_opts \"" << font_typewriter_opts << "\"";
1308 if (!fonts_cjk.empty())
1309 os << "\\font_cjk " << fonts_cjk << '\n';
1310 os << "\\use_microtype " << convert<string>(use_microtype) << '\n';
1311 os << "\\use_dash_ligatures " << convert<string>(use_dash_ligatures) << '\n';
1312 os << "\\graphics " << graphics_driver << '\n';
1313 os << "\\default_output_format " << default_output_format << '\n';
1314 os << "\\output_sync " << output_sync << '\n';
1315 if (!output_sync_macro.empty())
1316 os << "\\output_sync_macro \"" << output_sync_macro << "\"\n";
1317 os << "\\bibtex_command " << bibtex_command << '\n';
1318 os << "\\index_command " << index_command << '\n';
1320 if (!float_placement.empty())
1321 os << "\\float_placement " << float_placement << '\n';
1322 if (!float_alignment.empty())
1323 os << "\\float_alignment " << float_alignment << '\n';
1324 os << "\\paperfontsize " << fontsize << '\n';
1326 spacing().writeFile(os);
1327 pdfoptions().writeFile(os);
1329 os << "\\papersize " << string_papersize[papersize]
1330 << "\n\\use_geometry " << convert<string>(use_geometry);
1331 map<string, string> const & packages = auto_packages();
1332 for (auto const & pack : packages)
1333 os << "\n\\use_package " << pack.first << ' '
1334 << use_package(pack.first);
1336 os << "\n\\cite_engine ";
1338 if (!cite_engine_.empty())
1343 os << "\n\\cite_engine_type " << theCiteEnginesList.getTypeAsString(cite_engine_type_);
1345 if (!biblio_style.empty())
1346 os << "\n\\biblio_style " << biblio_style;
1347 if (!biblio_opts.empty())
1348 os << "\n\\biblio_options " << biblio_opts;
1349 if (!biblatex_bibstyle.empty())
1350 os << "\n\\biblatex_bibstyle " << biblatex_bibstyle;
1351 if (!biblatex_citestyle.empty())
1352 os << "\n\\biblatex_citestyle " << biblatex_citestyle;
1353 if (!multibib.empty())
1354 os << "\n\\multibib " << multibib;
1356 os << "\n\\use_bibtopic " << convert<string>(use_bibtopic)
1357 << "\n\\use_indices " << convert<string>(use_indices)
1358 << "\n\\paperorientation " << string_orientation[orientation]
1359 << "\n\\suppress_date " << convert<string>(suppress_date)
1360 << "\n\\justification " << convert<string>(justification)
1361 << "\n\\use_refstyle " << use_refstyle
1362 << "\n\\use_minted " << use_minted
1363 << "\n\\use_lineno " << use_lineno
1366 if (!lineno_opts.empty())
1367 os << "\\lineno_options " << lineno_opts << '\n';
1369 if (isbackgroundcolor == true)
1370 os << "\\backgroundcolor " << lyx::X11hexname(backgroundcolor) << '\n';
1371 if (isfontcolor == true)
1372 os << "\\fontcolor " << lyx::X11hexname(fontcolor) << '\n';
1373 if (notefontcolor != lyx::rgbFromHexName("#cccccc"))
1374 os << "\\notefontcolor " << lyx::X11hexname(notefontcolor) << '\n';
1375 if (boxbgcolor != lyx::rgbFromHexName("#ff0000"))
1376 os << "\\boxbgcolor " << lyx::X11hexname(boxbgcolor) << '\n';
1378 for (auto const & br : branchlist()) {
1379 os << "\\branch " << to_utf8(br.branch())
1380 << "\n\\selected " << br.isSelected()
1381 << "\n\\filename_suffix " << br.hasFileNameSuffix()
1382 << "\n\\color " << lyx::X11hexname(br.color())
1387 for (auto const & id : indiceslist()) {
1388 os << "\\index " << to_utf8(id.index())
1389 << "\n\\shortcut " << to_utf8(id.shortcut())
1390 << "\n\\color " << lyx::X11hexname(id.color())
1395 if (!paperwidth.empty())
1396 os << "\\paperwidth "
1397 << VSpace(paperwidth).asLyXCommand() << '\n';
1398 if (!paperheight.empty())
1399 os << "\\paperheight "
1400 << VSpace(paperheight).asLyXCommand() << '\n';
1401 if (!leftmargin.empty())
1402 os << "\\leftmargin "
1403 << VSpace(leftmargin).asLyXCommand() << '\n';
1404 if (!topmargin.empty())
1405 os << "\\topmargin "
1406 << VSpace(topmargin).asLyXCommand() << '\n';
1407 if (!rightmargin.empty())
1408 os << "\\rightmargin "
1409 << VSpace(rightmargin).asLyXCommand() << '\n';
1410 if (!bottommargin.empty())
1411 os << "\\bottommargin "
1412 << VSpace(bottommargin).asLyXCommand() << '\n';
1413 if (!headheight.empty())
1414 os << "\\headheight "
1415 << VSpace(headheight).asLyXCommand() << '\n';
1416 if (!headsep.empty())
1418 << VSpace(headsep).asLyXCommand() << '\n';
1419 if (!footskip.empty())
1421 << VSpace(footskip).asLyXCommand() << '\n';
1422 if (!columnsep.empty())
1423 os << "\\columnsep "
1424 << VSpace(columnsep).asLyXCommand() << '\n';
1425 os << "\\secnumdepth " << secnumdepth
1426 << "\n\\tocdepth " << tocdepth
1427 << "\n\\paragraph_separation "
1428 << string_paragraph_separation[paragraph_separation];
1429 if (!paragraph_separation)
1430 os << "\n\\paragraph_indentation "
1431 << (getParIndent().empty() ? "default" : getParIndent().asString());
1433 os << "\n\\defskip " << getDefSkip().asLyXCommand();
1434 os << "\n\\is_math_indent " << is_math_indent;
1436 os << "\n\\math_indentation "
1437 << (getMathIndent().empty() ? "default" : getMathIndent().asString());
1438 os << "\n\\math_numbering_side ";
1439 switch(math_numbering_side) {
1449 os << "\n\\quotes_style "
1450 << string_quotes_style[quotes_style]
1451 << "\n\\dynamic_quotes " << dynamic_quotes
1452 << "\n\\papercolumns " << columns
1453 << "\n\\papersides " << sides
1454 << "\n\\paperpagestyle " << pagestyle
1455 << "\n\\tablestyle " << tablestyle << '\n';
1456 if (!listings_params.empty())
1457 os << "\\listings_params \"" <<
1458 InsetListingsParams(listings_params).encodedString() << "\"\n";
1459 for (int i = 0; i < 4; ++i) {
1460 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
1461 if (user_defined_bullet(i).getFont() != -1) {
1462 os << "\\bullet " << i << " "
1463 << user_defined_bullet(i).getFont() << " "
1464 << user_defined_bullet(i).getCharacter() << " "
1465 << user_defined_bullet(i).getSize() << "\n";
1469 os << "\\bulletLaTeX " << i << " \""
1470 << lyx::to_ascii(user_defined_bullet(i).getText())
1476 os << "\\tracking_changes "
1477 << (save_transient_properties ? convert<string>(track_changes) : "false")
1480 os << "\\output_changes "
1481 << (save_transient_properties ? convert<string>(output_changes) : "false")
1484 os << "\\change_bars "
1485 << (save_transient_properties ? convert<string>(change_bars) : "false")
1488 os << "\\postpone_fragile_content " << convert<string>(postpone_fragile_content) << '\n';
1490 os << "\\html_math_output " << html_math_output << '\n'
1491 << "\\html_css_as_file " << html_css_as_file << '\n'
1492 << "\\html_be_strict " << convert<string>(html_be_strict) << '\n';
1494 if (html_math_img_scale != 1.0)
1495 os << "\\html_math_img_scale " << convert<string>(html_math_img_scale) << '\n';
1496 if (!html_latex_start.empty())
1497 os << "\\html_latex_start " << html_latex_start << '\n';
1498 if (!html_latex_end.empty())
1499 os << "\\html_latex_end " << html_latex_end << '\n';
1501 os << pimpl_->authorlist;
1505 void BufferParams::validate(LaTeXFeatures & features) const
1507 features.require(documentClass().required());
1509 if (columns > 1 && language->rightToLeft())
1510 features.require("rtloutputdblcol");
1512 if (output_changes) {
1513 bool xcolorulem = LaTeXFeatures::isAvailable("ulem") &&
1514 LaTeXFeatures::isAvailable("xcolor");
1516 switch (features.runparams().flavor) {
1517 case OutputParams::LATEX:
1518 case OutputParams::DVILUATEX:
1520 features.require("ct-xcolor-ulem");
1521 features.require("ulem");
1522 features.require("xcolor");
1524 features.require("ct-none");
1527 case OutputParams::LUATEX:
1528 case OutputParams::PDFLATEX:
1529 case OutputParams::XETEX:
1531 features.require("ct-xcolor-ulem");
1532 features.require("ulem");
1533 features.require("xcolor");
1534 // improves color handling in PDF output
1535 features.require("pdfcolmk");
1537 features.require("ct-none");
1544 features.require("changebar");
1547 // Floats with 'Here definitely' as default setting.
1548 if (float_placement.find('H') != string::npos)
1549 features.require("float");
1551 for (auto const & pm : use_packages) {
1552 if (pm.first == "amsmath") {
1553 // AMS Style is at document level
1554 if (pm.second == package_on ||
1555 features.isProvided("amsmath"))
1556 features.require(pm.first);
1557 } else if (pm.second == package_on)
1558 features.require(pm.first);
1561 // Document-level line spacing
1562 if (spacing().getSpace() != Spacing::Single && !spacing().isDefault())
1563 features.require("setspace");
1565 // the bullet shapes are buffer level not paragraph level
1566 // so they are tested here
1567 for (int i = 0; i < 4; ++i) {
1568 if (user_defined_bullet(i) == ITEMIZE_DEFAULTS[i])
1570 int const font = user_defined_bullet(i).getFont();
1572 int const c = user_defined_bullet(i).getCharacter();
1578 features.require("latexsym");
1580 } else if (font == 1) {
1581 features.require("amssymb");
1582 } else if (font >= 2 && font <= 5) {
1583 features.require("pifont");
1587 if (pdfoptions().use_hyperref) {
1588 features.require("hyperref");
1589 // due to interferences with babel and hyperref, the color package has to
1590 // be loaded after hyperref when hyperref is used with the colorlinks
1591 // option, see http://www.lyx.org/trac/ticket/5291
1592 if (pdfoptions().colorlinks)
1593 features.require("color");
1595 if (!listings_params.empty()) {
1596 // do not test validity because listings_params is
1597 // supposed to be valid
1599 InsetListingsParams(listings_params).separatedParams(true);
1600 // we can't support all packages, but we should load the color package
1601 if (par.find("\\color", 0) != string::npos)
1602 features.require("color");
1605 // some languages are only available via polyglossia
1606 if (features.hasPolyglossiaExclusiveLanguages())
1607 features.require("polyglossia");
1609 if (useNonTeXFonts && fontsMath() != "auto")
1610 features.require("unicode-math");
1613 features.require("microtype");
1615 if (!language->required().empty())
1616 features.require(language->required());
1620 bool BufferParams::writeLaTeX(otexstream & os, LaTeXFeatures & features,
1621 FileName const & filepath) const
1623 // http://www.tug.org/texmf-dist/doc/latex/base/fixltx2e.pdf
1624 // !! To use the Fix-cm package, load it before \documentclass, and use the command
1625 // \RequirePackage to do so, rather than the normal \usepackage
1626 // Do not try to load any other package before the document class, unless you
1627 // have a thorough understanding of the LATEX internals and know exactly what you
1629 if (features.mustProvide("fix-cm"))
1630 os << "\\RequirePackage{fix-cm}\n";
1631 // Likewise for fixltx2e. If other packages conflict with this policy,
1632 // treat it as a package bug (and report it!)
1633 // See http://www.latex-project.org/cgi-bin/ltxbugs2html?pr=latex/4407
1634 if (features.mustProvide("fixltx2e"))
1635 os << "\\RequirePackage{fixltx2e}\n";
1637 os << "\\documentclass";
1639 DocumentClass const & tclass = documentClass();
1641 ostringstream clsoptions; // the document class options.
1643 if (tokenPos(tclass.opt_fontsize(),
1644 '|', fontsize) >= 0) {
1645 // only write if existing in list (and not default)
1646 clsoptions << subst(tclass.fontsizeformat(), "$$s", fontsize) << ",";
1649 // paper sizes not supported by the class itself need the
1651 vector<string> classpsizes = getVectorFromString(tclass.opt_pagesize(), "|");
1652 bool class_supported_papersize = papersize == PAPER_DEFAULT
1653 || find(classpsizes.begin(), classpsizes.end(), string_papersize[papersize]) != classpsizes.end();
1655 if ((!use_geometry || features.isProvided("geometry-light"))
1656 && class_supported_papersize && papersize != PAPER_DEFAULT)
1657 clsoptions << subst(tclass.pagesizeformat(), "$$s", string_papersize[papersize]) << ",";
1660 if (sides != tclass.sides()) {
1663 clsoptions << "oneside,";
1666 clsoptions << "twoside,";
1672 if (columns != tclass.columns()) {
1674 clsoptions << "twocolumn,";
1676 clsoptions << "onecolumn,";
1680 && orientation == ORIENTATION_LANDSCAPE)
1681 clsoptions << "landscape,";
1684 clsoptions << "fleqn,";
1686 switch(math_numbering_side) {
1688 clsoptions << "leqno,";
1691 clsoptions << "reqno,";
1692 features.require("amsmath");
1698 // language should be a parameter to \documentclass
1699 if (language->babel() == "hebrew"
1700 && default_language->babel() != "hebrew")
1701 // This seems necessary
1702 features.useLanguage(default_language);
1704 ostringstream language_options;
1705 bool const use_babel = features.useBabel() && !features.isProvided("babel");
1706 bool const use_polyglossia = features.usePolyglossia();
1707 bool const global = lyxrc.language_global_options;
1708 if (features.useBabel() || (use_polyglossia && global)) {
1709 language_options << features.getBabelLanguages();
1710 if (!language->babel().empty()) {
1711 if (!language_options.str().empty())
1712 language_options << ',';
1713 language_options << language->babel();
1715 if (global && !language_options.str().empty())
1716 clsoptions << language_options.str() << ',';
1719 // the predefined options from the layout
1720 if (use_default_options && !tclass.options().empty())
1721 clsoptions << tclass.options() << ',';
1723 // the user-defined options
1724 if (!options.empty()) {
1725 clsoptions << options << ',';
1728 docstring const strOptions = from_utf8(clsoptions.str());
1729 if (!strOptions.empty()) {
1730 // Check if class options contain uncodable glyphs
1731 docstring uncodable_glyphs;
1732 docstring options_encodable;
1733 Encoding const * const enc = features.runparams().encoding;
1735 for (size_t n = 0; n < strOptions.size(); ++n) {
1736 char_type c = strOptions[n];
1737 if (!enc->encodable(c)) {
1738 docstring const glyph(1, c);
1739 LYXERR0("Uncodable character '"
1741 << "' in class options!");
1742 uncodable_glyphs += glyph;
1743 if (features.runparams().dryrun) {
1744 options_encodable += "<" + _("LyX Warning: ")
1745 + _("uncodable character") + " '";
1746 options_encodable += c;
1747 options_encodable += "'>";
1750 options_encodable += c;
1753 options_encodable = strOptions;
1755 // On BUFFER_VIEW|UPDATE, warn user if we found uncodable glyphs
1756 if (!features.runparams().dryrun && !uncodable_glyphs.empty()) {
1757 frontend::Alert::warning(
1758 _("Uncodable character in class options"),
1760 _("The class options of your document contain glyphs "
1761 "that are unknown in the current document encoding "
1762 "(namely %1$s).\nThese glyphs are omitted "
1763 " from the output, which may result in "
1764 "incomplete output."
1765 "\n\nPlease select an appropriate "
1766 "document encoding\n"
1767 "(such as utf8) or change the "
1768 "class options accordingly."),
1771 options_encodable = rtrim(options_encodable, ",");
1772 os << '[' << options_encodable << ']';
1775 os << '{' << from_ascii(tclass.latexname()) << "}\n";
1776 // end of \documentclass defs
1778 // The package options (via \PassOptionsToPackage)
1779 os << from_ascii(features.getPackageOptions());
1781 // if we use fontspec or newtxmath, we have to load the AMS packages here
1782 string const ams = features.loadAMSPackages();
1783 bool const ot1 = (main_font_encoding() == "default" || main_font_encoding() == "OT1");
1784 bool const use_newtxmath =
1785 theLaTeXFonts().getLaTeXFont(from_ascii(fontsMath())).getUsedPackage(
1786 ot1, false, false) == "newtxmath";
1787 if ((useNonTeXFonts || use_newtxmath) && !ams.empty())
1788 os << from_ascii(ams);
1790 if (useNonTeXFonts) {
1791 // Babel (as of 2017/11/03) loads fontspec itself
1792 if (!features.isProvided("fontspec")
1793 && !(features.useBabel() && features.isAvailable("babel-2017/11/03")))
1794 os << "\\usepackage{fontspec}\n";
1795 if (features.mustProvide("unicode-math")
1796 && features.isAvailable("unicode-math"))
1797 os << "\\usepackage{unicode-math}\n";
1800 // load CJK support package before font selection
1801 // (see autotests/export/latex/CJK/micro-sign_utf8-cjk-libertine.lyx)
1802 if (!useNonTeXFonts && encoding().package() != Encoding::none && inputenc != "utf8x"
1803 && (encoding().package() == Encoding::CJK || features.mustProvide("CJK"))) {
1804 if (inputenc == "utf8-cjk" || inputenc == "utf8")
1805 os << "\\usepackage{CJKutf8}\n";
1807 os << "\\usepackage[encapsulated]{CJK}\n";
1810 // font selection must be done before loading fontenc.sty
1811 // but after babel with non-TeX fonts
1812 string const fonts = loadFonts(features);
1813 if (!fonts.empty() && (!features.useBabel() || !useNonTeXFonts))
1814 os << from_utf8(fonts);
1816 if (fonts_default_family != "default")
1817 os << "\\renewcommand{\\familydefault}{\\"
1818 << from_ascii(fonts_default_family) << "}\n";
1820 // set font encoding
1821 // non-TeX fonts use font encoding TU (set by fontspec)
1822 if (!useNonTeXFonts && !features.isProvided("fontenc")
1823 && main_font_encoding() != "default") {
1824 // get main font encodings
1825 vector<string> fontencs = font_encodings();
1826 // get font encodings of secondary languages
1827 // FIXME: some languages (hebrew, ...) assume a standard font encoding as last
1828 // option (for text in other languages).
1829 features.getFontEncodings(fontencs);
1830 if (!fontencs.empty()) {
1831 os << "\\usepackage["
1832 << from_ascii(getStringFromVector(fontencs))
1837 // Load textcomp and pmboxdraw before (lua)inputenc (#11454)
1838 if (features.mustProvide("textcomp"))
1839 os << "\\usepackage{textcomp}\n";
1840 if (features.mustProvide("pmboxdraw"))
1841 os << "\\usepackage{pmboxdraw}\n";
1843 // handle inputenc etc.
1844 // (In documents containing text in Thai language,
1845 // we must load inputenc after babel, see lib/languages).
1846 if (!contains(features.getBabelPostsettings(), from_ascii("thai.ldf")))
1847 writeEncodingPreamble(os, features);
1850 if (!features.runparams().includeall && !included_children_.empty()) {
1851 os << "\\includeonly{";
1853 for (auto incfile : included_children_) {
1854 FileName inc = makeAbsPath(incfile, filepath.absFileName());
1855 string mangled = DocFileName(changeExtension(inc.absFileName(), ".tex")).
1857 if (!features.runparams().nice)
1859 // \includeonly doesn't want an extension
1860 incfile = changeExtension(incfile, string());
1861 incfile = support::latex_path(incfile);
1862 if (!incfile.empty()) {
1865 os << from_utf8(incfile);
1872 if (!features.isProvided("geometry")
1873 && (use_geometry || !class_supported_papersize)) {
1874 odocstringstream ods;
1875 if (!getGraphicsDriver("geometry").empty())
1876 ods << getGraphicsDriver("geometry");
1877 if (orientation == ORIENTATION_LANDSCAPE)
1878 ods << ",landscape";
1879 switch (papersize) {
1881 if (!paperwidth.empty())
1882 ods << ",paperwidth="
1883 << from_ascii(paperwidth);
1884 if (!paperheight.empty())
1885 ods << ",paperheight="
1886 << from_ascii(paperheight);
1888 case PAPER_USLETTER:
1890 case PAPER_USEXECUTIVE:
1919 ods << "," << from_ascii(string_papersize_geometry[papersize]);
1924 docstring g_options = trim(ods.str(), ",");
1925 os << "\\usepackage";
1926 // geometry-light means that the class works with geometry, but overwrites
1927 // the package options and paper sizes (memoir does this).
1928 // In this case, all options need to go to \geometry
1929 // and the standard paper sizes need to go to the class options.
1930 if (!g_options.empty() && !features.isProvided("geometry-light")) {
1931 os << '[' << g_options << ']';
1934 os << "{geometry}\n";
1935 if (use_geometry || features.isProvided("geometry-light")) {
1936 os << "\\geometry{verbose";
1937 if (!g_options.empty())
1938 // Output general options here with "geometry light".
1939 os << "," << g_options;
1940 // output this only if use_geometry is true
1942 if (!topmargin.empty())
1943 os << ",tmargin=" << from_ascii(Length(topmargin).asLatexString());
1944 if (!bottommargin.empty())
1945 os << ",bmargin=" << from_ascii(Length(bottommargin).asLatexString());
1946 if (!leftmargin.empty())
1947 os << ",lmargin=" << from_ascii(Length(leftmargin).asLatexString());
1948 if (!rightmargin.empty())
1949 os << ",rmargin=" << from_ascii(Length(rightmargin).asLatexString());
1950 if (!headheight.empty())
1951 os << ",headheight=" << from_ascii(Length(headheight).asLatexString());
1952 if (!headsep.empty())
1953 os << ",headsep=" << from_ascii(Length(headsep).asLatexString());
1954 if (!footskip.empty())
1955 os << ",footskip=" << from_ascii(Length(footskip).asLatexString());
1956 if (!columnsep.empty())
1957 os << ",columnsep=" << from_ascii(Length(columnsep).asLatexString());
1961 } else if (orientation == ORIENTATION_LANDSCAPE
1962 || papersize != PAPER_DEFAULT) {
1963 features.require("papersize");
1966 if (tokenPos(tclass.opt_pagestyle(), '|', pagestyle) >= 0) {
1967 if (pagestyle == "fancy")
1968 os << "\\usepackage{fancyhdr}\n";
1969 os << "\\pagestyle{" << from_ascii(pagestyle) << "}\n";
1972 // only output when the background color is not default
1973 if (isbackgroundcolor == true) {
1974 // only require color here, the background color will be defined
1975 // in LaTeXFeatures.cpp to avoid interferences with the LaTeX
1977 features.require("color");
1978 features.require("pagecolor");
1981 // only output when the font color is not default
1982 if (isfontcolor == true) {
1983 // only require color here, the font color will be defined
1984 // in LaTeXFeatures.cpp to avoid interferences with the LaTeX
1986 features.require("color");
1987 features.require("fontcolor");
1990 // Only if class has a ToC hierarchy
1991 if (tclass.hasTocLevels()) {
1992 if (secnumdepth != tclass.secnumdepth()) {
1993 os << "\\setcounter{secnumdepth}{"
1997 if (tocdepth != tclass.tocdepth()) {
1998 os << "\\setcounter{tocdepth}{"
2004 if (paragraph_separation) {
2005 // when skip separation
2007 switch (getDefSkip().kind()) {
2008 case VSpace::SMALLSKIP:
2009 psopt = "\\smallskipamount";
2011 case VSpace::MEDSKIP:
2012 psopt = "\\medskipamount";
2014 case VSpace::BIGSKIP:
2015 psopt = "\\bigskipamount";
2017 case VSpace::HALFLINE:
2018 // default (no option)
2020 case VSpace::FULLLINE:
2021 psopt = "\\baselineskip";
2023 case VSpace::LENGTH:
2024 psopt = getDefSkip().length().asLatexString();
2029 if (!features.isProvided("parskip")) {
2031 psopt = "[skip=" + psopt + "]";
2032 os << "\\usepackage" + psopt + "{parskip}\n";
2034 os << "\\setlength{\\parskip}{" + psopt + "}\n";
2037 // when separation by indentation
2038 // only output something when a width is given
2039 if (!getParIndent().empty()) {
2040 os << "\\setlength{\\parindent}{"
2041 << from_utf8(getParIndent().asLatexString())
2046 if (is_math_indent) {
2047 // when formula indentation
2048 // only output something when it is not the default
2049 if (!getMathIndent().empty()) {
2050 os << "\\setlength{\\mathindent}{"
2051 << from_utf8(getMathIndent().asString())
2056 // Now insert the LyX specific LaTeX commands...
2057 features.resolveAlternatives();
2058 features.expandMultiples();
2061 if (!output_sync_macro.empty())
2062 os << from_utf8(output_sync_macro) +"\n";
2063 else if (features.runparams().flavor == OutputParams::LATEX)
2064 os << "\\usepackage[active]{srcltx}\n";
2065 else if (features.runparams().flavor == OutputParams::PDFLATEX)
2066 os << "\\synctex=-1\n";
2069 // due to interferences with babel and hyperref, the color package has to
2070 // be loaded (when it is not already loaded) before babel when hyperref
2071 // is used with the colorlinks option, see
2072 // http://www.lyx.org/trac/ticket/5291
2073 // we decided therefore to load color always before babel, see
2074 // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg144349.html
2075 os << from_ascii(features.getColorOptions());
2077 // If we use hyperref, jurabib, japanese or varioref,
2078 // we have to call babel before
2080 && (features.isRequired("jurabib")
2081 || features.isRequired("hyperref")
2082 || features.isRequired("varioref")
2083 || features.isRequired("japanese"))) {
2084 os << features.getBabelPresettings();
2086 os << from_utf8(babelCall(language_options.str(),
2087 !lyxrc.language_global_options)) + '\n';
2088 os << features.getBabelPostsettings();
2091 // The optional packages;
2092 os << from_ascii(features.getPackages());
2094 // Additional Indices
2095 if (features.isRequired("splitidx")) {
2096 for (auto const & idx : indiceslist()) {
2097 os << "\\newindex{";
2098 os << escape(idx.shortcut());
2104 os << from_utf8(spacing().writePreamble(features.isProvided("SetSpace")));
2107 // * Hyperref manual: "Make sure it comes last of your loaded
2108 // packages, to give it a fighting chance of not being over-written,
2109 // since its job is to redefine many LaTeX commands."
2110 // * Email from Heiko Oberdiek: "It is usually better to load babel
2111 // before hyperref. Then hyperref has a chance to detect babel.
2112 // * Has to be loaded before the "LyX specific LaTeX commands" to
2113 // avoid errors with algorithm floats.
2114 // use hyperref explicitly if it is required
2115 if (features.isRequired("hyperref")) {
2116 OutputParams tmp_params = features.runparams();
2117 pdfoptions().writeLaTeX(tmp_params, os,
2118 features.isProvided("hyperref"));
2119 // correctly break URLs with hyperref and dvi/ps output
2120 if (features.runparams().hyperref_driver == "dvips"
2121 && features.isAvailable("breakurl"))
2122 os << "\\usepackage{breakurl}\n";
2123 } else if (features.isRequired("nameref"))
2124 // hyperref loads this automatically
2125 os << "\\usepackage{nameref}\n";
2128 os << "\\usepackage";
2129 if (!lineno_opts.empty())
2130 os << "[" << lineno_opts << "]";
2132 os << "\\linenumbers\n";
2135 // bibtopic needs to be loaded after hyperref.
2136 // the dot provides the aux file naming which LyX can detect.
2137 if (features.mustProvide("bibtopic"))
2138 os << "\\usepackage[dot]{bibtopic}\n";
2140 // Will be surrounded by \makeatletter and \makeatother when not empty
2141 otexstringstream atlyxpreamble;
2143 // Some macros LyX will need
2145 TexString tmppreamble = features.getMacros();
2146 if (!tmppreamble.str.empty())
2147 atlyxpreamble << "\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
2148 "LyX specific LaTeX commands.\n"
2149 << move(tmppreamble)
2152 // the text class specific preamble
2154 docstring tmppreamble = features.getTClassPreamble();
2155 if (!tmppreamble.empty())
2156 atlyxpreamble << "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
2157 "Textclass specific LaTeX commands.\n"
2161 // suppress date if selected
2162 // use \@ifundefined because we cannot be sure that every document class
2163 // has a \date command
2165 atlyxpreamble << "\\@ifundefined{date}{}{\\date{}}\n";
2167 /* the user-defined preamble */
2168 if (!containsOnly(preamble, " \n\t")) {
2170 atlyxpreamble << "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
2171 "User specified LaTeX commands.\n";
2173 // Check if the user preamble contains uncodable glyphs
2174 odocstringstream user_preamble;
2175 docstring uncodable_glyphs;
2176 Encoding const * const enc = features.runparams().encoding;
2178 for (size_t n = 0; n < preamble.size(); ++n) {
2179 char_type c = preamble[n];
2180 if (!enc->encodable(c)) {
2181 docstring const glyph(1, c);
2182 LYXERR0("Uncodable character '"
2184 << "' in user preamble!");
2185 uncodable_glyphs += glyph;
2186 if (features.runparams().dryrun) {
2187 user_preamble << "<" << _("LyX Warning: ")
2188 << _("uncodable character") << " '";
2189 user_preamble.put(c);
2190 user_preamble << "'>";
2193 user_preamble.put(c);
2196 user_preamble << preamble;
2198 // On BUFFER_VIEW|UPDATE, warn user if we found uncodable glyphs
2199 if (!features.runparams().dryrun && !uncodable_glyphs.empty()) {
2200 frontend::Alert::warning(
2201 _("Uncodable character in user preamble"),
2203 _("The user preamble of your document contains glyphs "
2204 "that are unknown in the current document encoding "
2205 "(namely %1$s).\nThese glyphs are omitted "
2206 " from the output, which may result in "
2207 "incomplete output."
2208 "\n\nPlease select an appropriate "
2209 "document encoding\n"
2210 "(such as utf8) or change the "
2211 "preamble code accordingly."),
2214 atlyxpreamble << user_preamble.str() << '\n';
2217 // footmisc must be loaded after setspace
2218 // Load it here to avoid clashes with footmisc loaded in the user
2219 // preamble. For that reason we also pass the options via
2220 // \PassOptionsToPackage in getPreamble() and not here.
2221 if (features.mustProvide("footmisc"))
2222 atlyxpreamble << "\\usepackage{footmisc}\n";
2224 // subfig loads internally the LaTeX package "caption". As
2225 // caption is a very popular package, users will load it in
2226 // the preamble. Therefore we must load subfig behind the
2227 // user-defined preamble and check if the caption package was
2228 // loaded or not. For the case that caption is loaded before
2229 // subfig, there is the subfig option "caption=false". This
2230 // option also works when a koma-script class is used and
2231 // koma's own caption commands are used instead of caption. We
2232 // use \PassOptionsToPackage here because the user could have
2233 // already loaded subfig in the preamble.
2234 if (features.mustProvide("subfig"))
2235 atlyxpreamble << "\\@ifundefined{showcaptionsetup}{}{%\n"
2236 " \\PassOptionsToPackage{caption=false}{subfig}}\n"
2237 "\\usepackage{subfig}\n";
2239 // Itemize bullet settings need to be last in case the user
2240 // defines their own bullets that use a package included
2241 // in the user-defined preamble -- ARRae
2242 // Actually it has to be done much later than that
2243 // since some packages like frenchb make modifications
2244 // at \begin{document} time -- JMarc
2245 docstring bullets_def;
2246 for (int i = 0; i < 4; ++i) {
2247 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
2248 if (bullets_def.empty())
2249 bullets_def += "\\AtBeginDocument{\n";
2250 bullets_def += " \\def\\labelitemi";
2252 // `i' is one less than the item to modify
2259 bullets_def += "ii";
2265 bullets_def += '{' +
2266 user_defined_bullet(i).getText()
2271 if (!bullets_def.empty())
2272 atlyxpreamble << bullets_def << "}\n\n";
2274 if (!atlyxpreamble.empty())
2275 os << "\n\\makeatletter\n"
2276 << atlyxpreamble.release()
2277 << "\\makeatother\n\n";
2279 // We try to load babel late, in case it interferes with other packages.
2280 // Jurabib, hyperref, varioref, bicaption, menukeys and listings (bug 8995)
2281 // have to be called after babel, though.
2282 if (use_babel && !features.isRequired("jurabib")
2283 && !features.isRequired("hyperref")
2284 && !features.isRequired("varioref")
2285 && !features.isRequired("japanese")) {
2286 os << features.getBabelPresettings();
2288 os << from_utf8(babelCall(language_options.str(),
2289 !lyxrc.language_global_options)) + '\n';
2290 os << features.getBabelPostsettings();
2292 // In documents containing text in Thai language,
2293 // we must load inputenc after babel (see lib/languages).
2294 if (contains(features.getBabelPostsettings(), from_ascii("thai.ldf")))
2295 writeEncodingPreamble(os, features);
2297 // font selection must be done after babel with non-TeX fonts
2298 if (!fonts.empty() && features.useBabel() && useNonTeXFonts)
2299 os << from_utf8(fonts);
2301 if (features.isRequired("bicaption"))
2302 os << "\\usepackage{bicaption}\n";
2303 if (!listings_params.empty()
2304 || features.mustProvide("listings")
2305 || features.mustProvide("minted")) {
2307 os << "\\usepackage{minted}\n";
2309 os << "\\usepackage{listings}\n";
2311 string lst_params = listings_params;
2312 // If minted, do not output the language option (bug 11203)
2313 if (use_minted && contains(lst_params, "language=")) {
2314 vector<string> opts =
2315 getVectorFromString(lst_params, ",", false);
2316 for (size_t i = 0; i < opts.size(); ++i) {
2317 if (prefixIs(opts[i], "language="))
2318 opts.erase(opts.begin() + i--);
2320 lst_params = getStringFromVector(opts, ",");
2322 if (!lst_params.empty()) {
2324 os << "\\setminted{";
2327 // do not test validity because listings_params is
2328 // supposed to be valid
2330 InsetListingsParams(lst_params).separatedParams(true);
2331 os << from_utf8(par);
2335 // xunicode only needs to be loaded if tipa is used
2336 // (the rest is obsoleted by the new TU encoding).
2337 // It needs to be loaded at least after amsmath, amssymb,
2338 // esint and the other packages that provide special glyphs
2339 if (features.mustProvide("tipa") && useNonTeXFonts
2340 && !features.isProvided("xunicode")) {
2341 // The `xunicode` package officially only supports XeTeX,
2342 // but also works with LuaTeX. We work around its XeTeX test.
2343 if (features.runparams().flavor != OutputParams::XETEX) {
2344 os << "% Pretend to xunicode that we are XeTeX\n"
2345 << "\\def\\XeTeXpicfile{}\n";
2347 os << "\\usepackage{xunicode}\n";
2350 // covington must be loaded after beamerarticle
2351 if (features.isRequired("covington"))
2352 os << "\\usepackage{covington}\n";
2354 // Polyglossia must be loaded last ...
2355 if (use_polyglossia) {
2357 os << "\\usepackage{polyglossia}\n";
2358 // set the main language
2359 os << "\\setdefaultlanguage";
2360 if (!language->polyglossiaOpts().empty())
2361 os << "[" << from_ascii(language->polyglossiaOpts()) << "]";
2362 os << "{" << from_ascii(language->polyglossia()) << "}\n";
2363 // now setup the other languages
2364 set<string> const polylangs =
2365 features.getPolyglossiaLanguages();
2366 for (auto const & pl : polylangs) {
2367 // We do not output the options here; they are output in
2368 // the language switch commands. This is safer if multiple
2369 // varieties are used.
2370 if (pl == language->polyglossia())
2372 os << "\\setotherlanguage";
2373 os << "{" << from_ascii(pl) << "}\n";
2377 // ... but before biblatex (see #7065)
2378 if ((features.mustProvide("biblatex")
2379 || features.isRequired("biblatex-chicago"))
2380 && !features.isProvided("biblatex-chicago")
2381 && !features.isProvided("biblatex-natbib")
2382 && !features.isProvided("natbib-internal")
2383 && !features.isProvided("natbib")
2384 && !features.isProvided("jurabib")) {
2385 // The biblatex-chicago package has a differing interface
2386 // it uses a wrapper package and loads styles via fixed options
2387 bool const chicago = features.isRequired("biblatex-chicago");
2390 os << "\\usepackage";
2391 if (!biblatex_bibstyle.empty()
2392 && (biblatex_bibstyle == biblatex_citestyle)
2394 opts = "style=" + biblatex_bibstyle;
2396 } else if (!chicago) {
2397 if (!biblatex_bibstyle.empty()) {
2398 opts = "bibstyle=" + biblatex_bibstyle;
2401 if (!biblatex_citestyle.empty()) {
2402 opts += delim + "citestyle=" + biblatex_citestyle;
2406 if (!multibib.empty() && multibib != "child") {
2407 opts += delim + "refsection=" + multibib;
2410 if (bibtexCommand() == "bibtex8"
2411 || prefixIs(bibtexCommand(), "bibtex8 ")) {
2412 opts += delim + "backend=bibtex8";
2414 } else if (bibtexCommand() == "bibtex"
2415 || prefixIs(bibtexCommand(), "bibtex ")) {
2416 opts += delim + "backend=bibtex";
2419 if (!bib_encoding.empty() && encodings.fromLyXName(bib_encoding)) {
2420 opts += delim + "bibencoding="
2421 + encodings.fromLyXName(bib_encoding)->latexName();
2424 if (!biblio_opts.empty())
2425 opts += delim + biblio_opts;
2427 os << "[" << opts << "]";
2429 os << "{biblatex-chicago}\n";
2431 os << "{biblatex}\n";
2435 // Load custom language package here
2436 if (features.langPackage() == LaTeXFeatures::LANG_PACK_CUSTOM) {
2437 if (lang_package == "default")
2438 os << from_utf8(lyxrc.language_custom_package);
2440 os << from_utf8(lang_package);
2444 // Since menukeys uses catoptions, which does some heavy changes on key-value options,
2445 // it is recommended to load menukeys as the last package (even after hyperref)
2446 if (features.isRequired("menukeys"))
2447 os << "\\usepackage{menukeys}\n";
2449 docstring const i18npreamble =
2450 features.getTClassI18nPreamble(use_babel, use_polyglossia,
2452 if (!i18npreamble.empty())
2453 os << i18npreamble + '\n';
2459 void BufferParams::useClassDefaults()
2461 DocumentClass const & tclass = documentClass();
2463 sides = tclass.sides();
2464 columns = tclass.columns();
2465 pagestyle = tclass.pagestyle();
2466 tablestyle = tclass.tablestyle();
2467 use_default_options = true;
2468 // Only if class has a ToC hierarchy
2469 if (tclass.hasTocLevels()) {
2470 secnumdepth = tclass.secnumdepth();
2471 tocdepth = tclass.tocdepth();
2476 bool BufferParams::hasClassDefaults() const
2478 DocumentClass const & tclass = documentClass();
2480 return sides == tclass.sides()
2481 && columns == tclass.columns()
2482 && pagestyle == tclass.pagestyle()
2483 && tablestyle == tclass.tablestyle()
2484 && use_default_options
2485 && secnumdepth == tclass.secnumdepth()
2486 && tocdepth == tclass.tocdepth();
2490 DocumentClass const & BufferParams::documentClass() const
2496 DocumentClassConstPtr BufferParams::documentClassPtr() const
2502 void BufferParams::setDocumentClass(DocumentClassConstPtr tc)
2504 // evil, but this function is evil
2505 doc_class_ = const_pointer_cast<DocumentClass>(tc);
2506 invalidateConverterCache();
2510 bool BufferParams::setBaseClass(string const & classname, string const & path)
2512 LYXERR(Debug::TCLASS, "setBaseClass: " << classname);
2513 LayoutFileList & bcl = LayoutFileList::get();
2514 if (!bcl.haveClass(classname)) {
2516 bformat(_("The layout file:\n"
2518 "could not be found. A default textclass with default\n"
2519 "layouts will be used. LyX will not be able to produce\n"
2521 from_utf8(classname));
2522 frontend::Alert::error(_("Document class not found"), s);
2523 bcl.addEmptyClass(classname);
2526 bool const success = bcl[classname].load(path);
2529 bformat(_("Due to some error in it, the layout file:\n"
2531 "could not be loaded. A default textclass with default\n"
2532 "layouts will be used. LyX will not be able to produce\n"
2534 from_utf8(classname));
2535 frontend::Alert::error(_("Could not load class"), s);
2536 bcl.addEmptyClass(classname);
2539 pimpl_->baseClass_ = classname;
2540 layout_modules_.adaptToBaseClass(baseClass(), removed_modules_);
2545 LayoutFile const * BufferParams::baseClass() const
2547 if (LayoutFileList::get().haveClass(pimpl_->baseClass_))
2548 return &(LayoutFileList::get()[pimpl_->baseClass_]);
2554 LayoutFileIndex const & BufferParams::baseClassID() const
2556 return pimpl_->baseClass_;
2560 void BufferParams::makeDocumentClass(bool const clone)
2565 invalidateConverterCache();
2566 LayoutModuleList mods;
2567 for (auto const & mod : layout_modules_)
2568 mods.push_back(mod);
2570 doc_class_ = getDocumentClass(*baseClass(), mods, cite_engine_, clone);
2572 TextClass::ReturnValues success = TextClass::OK;
2573 if (!forced_local_layout_.empty())
2574 success = doc_class_->read(to_utf8(forced_local_layout_),
2576 if (!local_layout_.empty() &&
2577 (success == TextClass::OK || success == TextClass::OK_OLDFORMAT))
2578 success = doc_class_->read(to_utf8(local_layout_), TextClass::MODULE);
2579 if (success != TextClass::OK && success != TextClass::OK_OLDFORMAT) {
2580 docstring const msg = _("Error reading internal layout information");
2581 frontend::Alert::warning(_("Read Error"), msg);
2586 bool BufferParams::layoutModuleCanBeAdded(string const & modName) const
2588 return layout_modules_.moduleCanBeAdded(modName, baseClass());
2592 docstring BufferParams::getLocalLayout(bool forced) const
2595 return from_utf8(doc_class_->forcedLayouts());
2597 return local_layout_;
2601 void BufferParams::setLocalLayout(docstring const & layout, bool forced)
2604 forced_local_layout_ = layout;
2606 local_layout_ = layout;
2610 bool BufferParams::addLayoutModule(string const & modName)
2612 for (auto const & mod : layout_modules_)
2615 layout_modules_.push_back(modName);
2620 string BufferParams::bufferFormat() const
2622 return documentClass().outputFormat();
2626 bool BufferParams::isExportable(string const & format, bool need_viewable) const
2628 FormatList const & formats = exportableFormats(need_viewable);
2629 for (auto const & fmt : formats) {
2630 if (fmt->name() == format)
2637 FormatList const & BufferParams::exportableFormats(bool only_viewable) const
2639 FormatList & cached = only_viewable ?
2640 pimpl_->viewableFormatList : pimpl_->exportableFormatList;
2641 bool & valid = only_viewable ?
2642 pimpl_->isViewCacheValid : pimpl_->isExportCacheValid;
2646 vector<string> const backs = backends();
2647 set<string> excludes;
2648 if (useNonTeXFonts) {
2649 excludes.insert("latex");
2650 excludes.insert("pdflatex");
2651 } else if (inputenc != "ascii" && inputenc != "utf8-plain")
2652 // XeTeX with TeX fonts requires input encoding ascii (#10600).
2653 excludes.insert("xetex");
2654 FormatList result = theConverters().getReachable(backs[0], only_viewable,
2656 vector<string>::const_iterator it = backs.begin() + 1;
2657 for (; it != backs.end(); ++it) {
2658 FormatList r = theConverters().getReachable(*it, only_viewable,
2660 result.insert(result.end(), r.begin(), r.end());
2662 sort(result.begin(), result.end(), Format::formatSorter);
2669 vector<string> BufferParams::backends() const
2672 string const buffmt = bufferFormat();
2674 // FIXME: Don't hardcode format names here, but use a flag
2675 if (buffmt == "latex") {
2676 if (encoding().package() == Encoding::japanese)
2677 v.push_back("platex");
2679 if (!useNonTeXFonts) {
2680 v.push_back("pdflatex");
2681 v.push_back("latex");
2684 || inputenc == "ascii" || inputenc == "utf8-plain")
2685 v.push_back("xetex");
2686 v.push_back("luatex");
2687 v.push_back("dviluatex");
2690 string rbuffmt = buffmt;
2691 // If we use an OutputFormat in Japanese docs,
2692 // we need special format in order to get the path
2693 // via pLaTeX (#8823)
2694 if (documentClass().hasOutputFormat()
2695 && encoding().package() == Encoding::japanese)
2697 v.push_back(rbuffmt);
2700 v.push_back("xhtml");
2701 v.push_back("text");
2707 OutputParams::FLAVOR BufferParams::getOutputFlavor(string const & format) const
2709 string const dformat = (format.empty() || format == "default") ?
2710 getDefaultOutputFormat() : format;
2711 DefaultFlavorCache::const_iterator it =
2712 default_flavors_.find(dformat);
2714 if (it != default_flavors_.end())
2717 OutputParams::FLAVOR result = OutputParams::LATEX;
2719 // FIXME It'd be better not to hardcode this, but to do
2720 // something with formats.
2721 if (dformat == "xhtml")
2722 result = OutputParams::HTML;
2723 else if (dformat == "text")
2724 result = OutputParams::TEXT;
2725 else if (dformat == "lyx")
2726 result = OutputParams::LYX;
2727 else if (dformat == "pdflatex")
2728 result = OutputParams::PDFLATEX;
2729 else if (dformat == "xetex")
2730 result = OutputParams::XETEX;
2731 else if (dformat == "luatex")
2732 result = OutputParams::LUATEX;
2733 else if (dformat == "dviluatex")
2734 result = OutputParams::DVILUATEX;
2736 // Try to determine flavor of default output format
2737 vector<string> backs = backends();
2738 if (find(backs.begin(), backs.end(), dformat) == backs.end()) {
2739 // Get shortest path to format
2740 Graph::EdgePath path;
2741 for (auto const & bvar : backs) {
2742 Graph::EdgePath p = theConverters().getPath(bvar, dformat);
2743 if (!p.empty() && (path.empty() || p.size() < path.size())) {
2748 result = theConverters().getFlavor(path);
2751 // cache this flavor
2752 default_flavors_[dformat] = result;
2757 string BufferParams::getDefaultOutputFormat() const
2759 if (!default_output_format.empty()
2760 && default_output_format != "default")
2761 return default_output_format;
2763 FormatList const & formats = exportableFormats(true);
2764 if (formats.empty())
2766 // return the first we find
2767 return formats.front()->name();
2769 if (encoding().package() == Encoding::japanese)
2770 return lyxrc.default_platex_view_format;
2772 return lyxrc.default_otf_view_format;
2773 return lyxrc.default_view_format;
2776 Font const BufferParams::getFont() const
2778 FontInfo f = documentClass().defaultfont();
2779 if (fonts_default_family == "rmdefault")
2780 f.setFamily(ROMAN_FAMILY);
2781 else if (fonts_default_family == "sfdefault")
2782 f.setFamily(SANS_FAMILY);
2783 else if (fonts_default_family == "ttdefault")
2784 f.setFamily(TYPEWRITER_FAMILY);
2785 return Font(f, language);
2789 InsetQuotesParams::QuoteStyle BufferParams::getQuoteStyle(string const & qs) const
2791 return quotesstyletranslator().find(qs);
2795 bool BufferParams::isLatex() const
2797 return documentClass().outputType() == LATEX;
2801 bool BufferParams::isLiterate() const
2803 return documentClass().outputType() == LITERATE;
2807 bool BufferParams::isDocBook() const
2809 return documentClass().outputType() == DOCBOOK;
2813 void BufferParams::readPreamble(Lexer & lex)
2815 if (lex.getString() != "\\begin_preamble")
2816 lyxerr << "Error (BufferParams::readPreamble):"
2817 "consistency check failed." << endl;
2819 preamble = lex.getLongString(from_ascii("\\end_preamble"));
2823 void BufferParams::readLocalLayout(Lexer & lex, bool forced)
2825 string const expected = forced ? "\\begin_forced_local_layout" :
2826 "\\begin_local_layout";
2827 if (lex.getString() != expected)
2828 lyxerr << "Error (BufferParams::readLocalLayout):"
2829 "consistency check failed." << endl;
2832 forced_local_layout_ =
2833 lex.getLongString(from_ascii("\\end_forced_local_layout"));
2835 local_layout_ = lex.getLongString(from_ascii("\\end_local_layout"));
2839 bool BufferParams::setLanguage(string const & lang)
2841 Language const *new_language = languages.getLanguage(lang);
2842 if (!new_language) {
2843 // Language lang was not found
2846 language = new_language;
2851 void BufferParams::readLanguage(Lexer & lex)
2853 if (!lex.next()) return;
2855 string const tmptok = lex.getString();
2857 // check if tmptok is part of tex_babel in tex-defs.h
2858 if (!setLanguage(tmptok)) {
2859 // Language tmptok was not found
2860 language = default_language;
2861 lyxerr << "Warning: Setting language `"
2862 << tmptok << "' to `" << language->lang()
2868 void BufferParams::readGraphicsDriver(Lexer & lex)
2873 string const tmptok = lex.getString();
2874 // check if tmptok is part of tex_graphics in tex_defs.h
2877 string const test = tex_graphics[n++];
2879 if (test == tmptok) {
2880 graphics_driver = tmptok;
2885 "Warning: graphics driver `$$Token' not recognized!\n"
2886 " Setting graphics driver to `default'.\n");
2887 graphics_driver = "default";
2894 void BufferParams::readBullets(Lexer & lex)
2899 int const index = lex.getInteger();
2901 int temp_int = lex.getInteger();
2902 user_defined_bullet(index).setFont(temp_int);
2903 temp_bullet(index).setFont(temp_int);
2905 user_defined_bullet(index).setCharacter(temp_int);
2906 temp_bullet(index).setCharacter(temp_int);
2908 user_defined_bullet(index).setSize(temp_int);
2909 temp_bullet(index).setSize(temp_int);
2913 void BufferParams::readBulletsLaTeX(Lexer & lex)
2915 // The bullet class should be able to read this.
2918 int const index = lex.getInteger();
2920 docstring const temp_str = lex.getDocString();
2922 user_defined_bullet(index).setText(temp_str);
2923 temp_bullet(index).setText(temp_str);
2927 void BufferParams::readModules(Lexer & lex)
2929 if (!lex.eatLine()) {
2930 lyxerr << "Error (BufferParams::readModules):"
2931 "Unexpected end of input." << endl;
2935 string mod = lex.getString();
2936 if (mod == "\\end_modules")
2938 addLayoutModule(mod);
2944 void BufferParams::readRemovedModules(Lexer & lex)
2946 if (!lex.eatLine()) {
2947 lyxerr << "Error (BufferParams::readRemovedModules):"
2948 "Unexpected end of input." << endl;
2952 string mod = lex.getString();
2953 if (mod == "\\end_removed_modules")
2955 removed_modules_.push_back(mod);
2958 // now we want to remove any removed modules that were previously
2959 // added. normally, that will be because default modules were added in
2960 // setBaseClass(), which gets called when \textclass is read at the
2961 // start of the read.
2962 for (auto const & rm : removed_modules_) {
2963 LayoutModuleList::iterator const mit = layout_modules_.begin();
2964 LayoutModuleList::iterator const men = layout_modules_.end();
2965 LayoutModuleList::iterator found = find(mit, men, rm);
2968 layout_modules_.erase(found);
2973 void BufferParams::readIncludeonly(Lexer & lex)
2975 if (!lex.eatLine()) {
2976 lyxerr << "Error (BufferParams::readIncludeonly):"
2977 "Unexpected end of input." << endl;
2981 string child = lex.getString();
2982 if (child == "\\end_includeonly")
2984 included_children_.push_back(child);
2990 string BufferParams::paperSizeName(PapersizePurpose purpose, string const & psize) const
2992 PAPER_SIZE ppsize = psize.empty() ? papersize : papersizetranslator().find(psize);
2995 if (documentClass().pagesize() == "default")
2996 // could be anything, so don't guess
2998 return paperSizeName(purpose, documentClass().pagesize());
2999 case PAPER_CUSTOM: {
3000 if (purpose == XDVI && !paperwidth.empty() &&
3001 !paperheight.empty()) {
3002 // heightxwidth<unit>
3003 string first = paperwidth;
3004 string second = paperheight;
3005 if (orientation == ORIENTATION_LANDSCAPE)
3008 return first.erase(first.length() - 2)
3014 // dvips and dvipdfm do not know this
3015 if (purpose == DVIPS || purpose == DVIPDFM)
3019 if (purpose == DVIPS || purpose == DVIPDFM)
3023 if (purpose == DVIPS || purpose == DVIPDFM)
3033 if (purpose == DVIPS || purpose == DVIPDFM)
3037 if (purpose == DVIPS || purpose == DVIPDFM)
3041 if (purpose == DVIPS || purpose == DVIPDFM)
3045 if (purpose == DVIPS || purpose == DVIPDFM)
3049 if (purpose == DVIPS || purpose == DVIPDFM)
3053 // dvipdfm does not know this
3054 if (purpose == DVIPDFM)
3058 if (purpose == DVIPDFM)
3062 if (purpose == DVIPS || purpose == DVIPDFM)
3066 if (purpose == DVIPS || purpose == DVIPDFM)
3070 if (purpose == DVIPS || purpose == DVIPDFM)
3074 if (purpose == DVIPS || purpose == DVIPDFM)
3078 if (purpose == DVIPS || purpose == DVIPDFM)
3082 if (purpose == DVIPS || purpose == DVIPDFM)
3086 if (purpose == DVIPS || purpose == DVIPDFM)
3090 if (purpose == DVIPS || purpose == DVIPDFM)
3094 if (purpose == DVIPS || purpose == DVIPDFM)
3098 if (purpose == DVIPS || purpose == DVIPDFM)
3102 if (purpose == DVIPS || purpose == DVIPDFM)
3106 if (purpose == DVIPS || purpose == DVIPDFM)
3110 if (purpose == DVIPS || purpose == DVIPDFM)
3114 if (purpose == DVIPS || purpose == DVIPDFM)
3118 if (purpose == DVIPS || purpose == DVIPDFM)
3121 case PAPER_USEXECUTIVE:
3122 // dvipdfm does not know this
3123 if (purpose == DVIPDFM)
3128 case PAPER_USLETTER:
3130 if (purpose == XDVI)
3137 string const BufferParams::dvips_options() const
3141 // If the class loads the geometry package, we do not know which
3142 // paper size is used, since we do not set it (bug 7013).
3143 // Therefore we must not specify any argument here.
3144 // dvips gets the correct paper size via DVI specials in this case
3145 // (if the class uses the geometry package correctly).
3146 if (documentClass().provides("geometry"))
3150 && papersize == PAPER_CUSTOM
3151 && !lyxrc.print_paper_dimension_flag.empty()
3152 && !paperwidth.empty()
3153 && !paperheight.empty()) {
3154 // using a custom papersize
3155 result = lyxrc.print_paper_dimension_flag;
3156 result += ' ' + paperwidth;
3157 result += ',' + paperheight;
3159 string const paper_option = paperSizeName(DVIPS);
3160 if (!paper_option.empty() && (paper_option != "letter" ||
3161 orientation != ORIENTATION_LANDSCAPE)) {
3162 // dvips won't accept -t letter -t landscape.
3163 // In all other cases, include the paper size
3165 result = lyxrc.print_paper_flag;
3166 result += ' ' + paper_option;
3169 if (orientation == ORIENTATION_LANDSCAPE &&
3170 papersize != PAPER_CUSTOM)
3171 result += ' ' + lyxrc.print_landscape_flag;
3176 string const BufferParams::main_font_encoding() const
3178 if (font_encodings().empty()) {
3179 if (ascii_lowercase(language->fontenc(*this)) == "none")
3183 return font_encodings().back();
3187 vector<string> const BufferParams::font_encodings() const
3189 string doc_fontenc = (fontenc == "auto") ? string() : fontenc;
3191 vector<string> fontencs;
3193 // "default" means "no explicit font encoding"
3194 if (doc_fontenc != "default") {
3195 if (!doc_fontenc.empty())
3196 // If we have a custom setting, we use only that!
3197 return getVectorFromString(doc_fontenc);
3198 if (!language->fontenc(*this).empty()
3199 && ascii_lowercase(language->fontenc(*this)) != "none") {
3200 vector<string> fencs = getVectorFromString(language->fontenc(*this));
3201 for (auto & fe : fencs) {
3202 if (find(fontencs.begin(), fontencs.end(), fe) == fontencs.end())
3203 fontencs.push_back(fe);
3212 string BufferParams::babelCall(string const & lang_opts, bool const langoptions) const
3214 // suppress the babel call if there is no BabelName defined
3215 // for the document language in the lib/languages file and if no
3216 // other languages are used (lang_opts is then empty)
3217 if (lang_opts.empty())
3219 // The prefs may require the languages to
3220 // be submitted to babel itself (not the class).
3222 return "\\usepackage[" + lang_opts + "]{babel}";
3223 return "\\usepackage{babel}";
3227 docstring BufferParams::getGraphicsDriver(string const & package) const
3231 if (package == "geometry") {
3232 if (graphics_driver == "dvips"
3233 || graphics_driver == "dvipdfm"
3234 || graphics_driver == "pdftex"
3235 || graphics_driver == "vtex")
3236 result = from_ascii(graphics_driver);
3237 else if (graphics_driver == "dvipdfmx")
3238 result = from_ascii("dvipdfm");
3245 void BufferParams::writeEncodingPreamble(otexstream & os,
3246 LaTeXFeatures & features) const
3248 // With no-TeX fonts we use utf8-plain without encoding package.
3252 if (inputenc == "auto-legacy") {
3253 string const doc_encoding =
3254 language->encoding()->latexName();
3255 Encoding::Package const package =
3256 language->encoding()->package();
3258 // Create list of inputenc options:
3259 set<string> encoding_set;
3260 // luainputenc fails with more than one encoding
3261 if (features.runparams().flavor != OutputParams::LUATEX
3262 && features.runparams().flavor != OutputParams::DVILUATEX)
3263 // list all input encodings used in the document
3264 encoding_set = features.getEncodingSet(doc_encoding);
3266 // The "japanese" babel-language requires the pLaTeX engine
3267 // which conflicts with "inputenc".
3268 // See http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129680.html
3269 if ((!encoding_set.empty() || package == Encoding::inputenc)
3270 && !features.isRequired("japanese")
3271 && !features.isProvided("inputenc")) {
3272 os << "\\usepackage[";
3273 set<string>::const_iterator it = encoding_set.begin();
3274 set<string>::const_iterator const end = encoding_set.end();
3276 os << from_ascii(*it);
3279 for (; it != end; ++it)
3280 os << ',' << from_ascii(*it);
3281 if (package == Encoding::inputenc) {
3282 if (!encoding_set.empty())
3284 os << from_ascii(doc_encoding);
3286 if (features.runparams().flavor == OutputParams::LUATEX
3287 || features.runparams().flavor == OutputParams::DVILUATEX)
3288 os << "]{luainputenc}\n";
3290 os << "]{inputenc}\n";
3292 } else if (inputenc != "auto-legacy-plain") {
3293 switch (encoding().package()) {
3294 case Encoding::none:
3296 case Encoding::japanese:
3297 if (encoding().iconvName() != "UTF-8"
3298 && !features.runparams().isFullUnicode())
3299 // don't default to [utf8]{inputenc} with TeXLive >= 18
3300 os << "\\ifdefined\\UseRawInputEncoding\n"
3301 << " \\UseRawInputEncoding\\fi\n";
3303 case Encoding::inputenc:
3304 // do not load inputenc if japanese is used
3305 // or if the class provides inputenc
3306 if (features.isRequired("japanese")
3307 || features.isProvided("inputenc"))
3309 os << "\\usepackage[" << from_ascii(encoding().latexName());
3310 if (features.runparams().flavor == OutputParams::LUATEX
3311 || features.runparams().flavor == OutputParams::DVILUATEX)
3312 os << "]{luainputenc}\n";
3314 os << "]{inputenc}\n";
3318 if (inputenc == "auto-legacy-plain" || features.isRequired("japanese")) {
3319 // don't default to [utf8]{inputenc} with TeXLive >= 18
3320 os << "\\ifdefined\\UseRawInputEncoding\n";
3321 os << " \\UseRawInputEncoding\\fi\n";
3326 string const BufferParams::parseFontName(string const & name) const
3328 string mangled = name;
3329 size_t const idx = mangled.find('[');
3330 if (idx == string::npos || idx == 0)
3333 return mangled.substr(0, idx - 1);
3337 string const BufferParams::loadFonts(LaTeXFeatures & features) const
3339 if (fontsRoman() == "default" && fontsSans() == "default"
3340 && fontsTypewriter() == "default"
3341 && (fontsMath() == "default" || fontsMath() == "auto"))
3347 /* Fontspec (XeTeX, LuaTeX): we provide GUI support for oldstyle
3348 * numbers (Numbers=OldStyle) and sf/tt scaling. The Ligatures=TeX/
3349 * Mapping=tex-text option assures TeX ligatures (such as "--")
3350 * are resolved. Note that tt does not use these ligatures.
3352 * -- add more GUI options?
3353 * -- add more fonts (fonts for other scripts)
3354 * -- if there's a way to find out if a font really supports
3355 * OldStyle, enable/disable the widget accordingly.
3357 if (useNonTeXFonts && features.isAvailable("fontspec")) {
3358 // "Mapping=tex-text" and "Ligatures=TeX" are equivalent.
3359 // However, until v.2 (2010/07/11) fontspec only knew
3360 // Mapping=tex-text (for XeTeX only); then "Ligatures=TeX"
3361 // was introduced for both XeTeX and LuaTeX (LuaTeX
3362 // didn't understand "Mapping=tex-text", while XeTeX
3363 // understood both. With most recent versions, both
3364 // variants are understood by both engines. However,
3365 // we want to provide support for at least TeXLive 2009
3366 // (for XeTeX; LuaTeX is only supported as of v.2)
3367 // As of 2017/11/03, Babel has its own higher-level
3368 // interface on top of fontspec that is to be used.
3369 bool const babelfonts = features.useBabel()
3370 && features.isAvailable("babel-2017/11/03");
3371 string const texmapping =
3372 (features.runparams().flavor == OutputParams::XETEX) ?
3373 "Mapping=tex-text" : "Ligatures=TeX";
3374 if (fontsRoman() != "default") {
3376 os << "\\babelfont{rm}[";
3378 os << "\\setmainfont[";
3379 if (!font_roman_opts.empty())
3380 os << font_roman_opts << ',';
3382 if (fonts_roman_osf)
3383 os << ",Numbers=OldStyle";
3384 os << "]{" << parseFontName(fontsRoman()) << "}\n";
3386 if (fontsSans() != "default") {
3387 string const sans = parseFontName(fontsSans());
3388 if (fontsSansScale() != 100) {
3390 os << "\\babelfont{sf}";
3392 os << "\\setsansfont";
3394 << float(fontsSansScale()) / 100 << ',';
3396 os << "Numbers=OldStyle,";
3397 if (!font_sans_opts.empty())
3398 os << font_sans_opts << ',';
3399 os << texmapping << "]{"
3403 os << "\\babelfont{sf}[";
3405 os << "\\setsansfont[";
3407 os << "Numbers=OldStyle,";
3408 if (!font_sans_opts.empty())
3409 os << font_sans_opts << ',';
3410 os << texmapping << "]{"
3414 if (fontsTypewriter() != "default") {
3415 string const mono = parseFontName(fontsTypewriter());
3416 if (fontsTypewriterScale() != 100) {
3418 os << "\\babelfont{tt}";
3420 os << "\\setmonofont";
3422 << float(fontsTypewriterScale()) / 100;
3423 if (fonts_typewriter_osf)
3424 os << ",Numbers=OldStyle";
3425 if (!font_typewriter_opts.empty())
3426 os << ',' << font_typewriter_opts;
3431 os << "\\babelfont{tt}";
3433 os << "\\setmonofont";
3434 if (!font_typewriter_opts.empty() || fonts_typewriter_osf) {
3436 if (fonts_typewriter_osf)
3437 os << "Numbers=OldStyle";
3438 if (!font_typewriter_opts.empty()) {
3439 if (fonts_typewriter_osf)
3441 os << font_typewriter_opts;
3445 os << '{' << mono << "}\n";
3452 bool const ot1 = (main_font_encoding() == "default" || main_font_encoding() == "OT1");
3453 bool const dryrun = features.runparams().dryrun;
3454 bool const complete = (fontsSans() == "default" && fontsTypewriter() == "default");
3455 bool const nomath = (fontsMath() == "default");
3458 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsRoman())).getLaTeXCode(
3459 dryrun, ot1, complete, fonts_expert_sc, fonts_roman_osf,
3460 nomath, font_roman_opts);
3463 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsSans())).getLaTeXCode(
3464 dryrun, ot1, complete, fonts_expert_sc, fonts_sans_osf,
3465 nomath, font_sans_opts, fontsSansScale());
3467 // MONOSPACED/TYPEWRITER
3468 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsTypewriter())).getLaTeXCode(
3469 dryrun, ot1, complete, fonts_expert_sc, fonts_typewriter_osf,
3470 nomath, font_typewriter_opts, fontsTypewriterScale());
3473 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsMath())).getLaTeXCode(
3474 dryrun, ot1, complete, fonts_expert_sc, fonts_roman_osf,
3481 Encoding const & BufferParams::encoding() const
3483 // Main encoding for LaTeX output.
3485 return *(encodings.fromLyXName("utf8-plain"));
3486 if (inputenc == "auto-legacy" || inputenc == "auto-legacy-plain")
3487 return *language->encoding();
3488 if (inputenc == "utf8" && language->lang() == "japanese")
3489 return *(encodings.fromLyXName("utf8-platex"));
3490 Encoding const * const enc = encodings.fromLyXName(inputenc);
3493 LYXERR0("Unknown inputenc value `" << inputenc
3494 << "'. Using `auto' instead.");
3495 return *language->encoding();
3499 string const & BufferParams::defaultBiblioStyle() const
3501 if (!biblio_style.empty())
3502 return biblio_style;
3504 map<string, string> const & bs = documentClass().defaultBiblioStyle();
3505 auto cit = bs.find(theCiteEnginesList.getTypeAsString(citeEngineType()));
3506 if (cit != bs.end())
3509 return empty_string();
3513 bool const & BufferParams::fullAuthorList() const
3515 return documentClass().fullAuthorList();
3519 string BufferParams::getCiteAlias(string const & s) const
3521 vector<string> commands =
3522 documentClass().citeCommands(citeEngineType());
3523 // If it is a real command, don't treat it as an alias
3524 if (find(commands.begin(), commands.end(), s) != commands.end())
3526 map<string,string> aliases = documentClass().citeCommandAliases();
3527 if (aliases.find(s) != aliases.end())
3533 vector<string> BufferParams::citeCommands() const
3535 static CitationStyle const default_style;
3536 vector<string> commands =
3537 documentClass().citeCommands(citeEngineType());
3538 if (commands.empty())
3539 commands.push_back(default_style.name);
3544 vector<CitationStyle> BufferParams::citeStyles() const
3546 static CitationStyle const default_style;
3547 vector<CitationStyle> styles =
3548 documentClass().citeStyles(citeEngineType());
3550 styles.push_back(default_style);
3555 string const BufferParams::bibtexCommand() const
3557 // Return document-specific setting if available
3558 if (bibtex_command != "default")
3559 return bibtex_command;
3561 // If we have "default" in document settings, consult the prefs
3562 // 1. Japanese (uses a specific processor)
3563 if (encoding().package() == Encoding::japanese) {
3564 if (lyxrc.jbibtex_command != "automatic")
3565 // Return the specified program, if "automatic" is not set
3566 return lyxrc.jbibtex_command;
3567 else if (!useBiblatex()) {
3568 // With classic BibTeX, return pbibtex, jbibtex, bibtex
3569 if (lyxrc.jbibtex_alternatives.find("pbibtex") != lyxrc.jbibtex_alternatives.end())
3571 if (lyxrc.jbibtex_alternatives.find("jbibtex") != lyxrc.jbibtex_alternatives.end())
3576 // 2. All other languages
3577 else if (lyxrc.bibtex_command != "automatic")
3578 // Return the specified program, if "automatic" is not set
3579 return lyxrc.bibtex_command;
3581 // 3. Automatic: find the most suitable for the current cite framework
3582 if (useBiblatex()) {
3583 // For Biblatex, we prefer biber (also for Japanese)
3584 // and fall back to bibtex8 and, as last resort, bibtex
3585 if (lyxrc.bibtex_alternatives.find("biber") != lyxrc.bibtex_alternatives.end())
3587 else if (lyxrc.bibtex_alternatives.find("bibtex8") != lyxrc.bibtex_alternatives.end())
3594 bool BufferParams::useBiblatex() const
3596 return theCiteEnginesList[citeEngine()]->getCiteFramework() == "biblatex";
3600 void BufferParams::invalidateConverterCache() const
3602 pimpl_->isExportCacheValid = false;
3603 pimpl_->isViewCacheValid = false;
3607 // We shouldn't need to reset the params here, since anything
3608 // we need will be recopied.
3609 void BufferParams::copyForAdvFR(const BufferParams & bp)
3611 string const & lang = bp.language->lang();
3613 layout_modules_ = bp.layout_modules_;
3614 string const & doc_class = bp.documentClass().name();
3615 setBaseClass(doc_class);
3619 void BufferParams::setBibFileEncoding(string const & file, string const & enc)
3621 bib_encodings[file] = enc;
3625 string const BufferParams::bibFileEncoding(string const & file) const
3627 if (bib_encodings.find(file) == bib_encodings.end())
3629 return bib_encodings.find(file)->second;