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 = false;
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") {
785 lex >> maintain_unincluded_children;
786 } else if (token == "\\options") {
788 options = lex.getString();
789 } else if (token == "\\use_default_options") {
790 lex >> use_default_options;
791 } else if (token == "\\master") {
793 master = lex.getString();
794 if (!filepath.empty() && FileName::isAbsolute(origin)) {
795 bool const isabs = FileName::isAbsolute(master);
796 FileName const abspath(isabs ? master : origin + master);
797 bool const moved = filepath != FileName(origin);
798 if (moved && abspath.exists()) {
799 docstring const path = isabs
801 : from_utf8(abspath.realPath());
802 docstring const refpath =
803 from_utf8(filepath.absFileName());
804 master = to_utf8(makeRelPath(path, refpath));
807 } else if (token == "\\suppress_date") {
808 lex >> suppress_date;
809 } else if (token == "\\justification") {
810 lex >> justification;
811 } else if (token == "\\language") {
813 } else if (token == "\\language_package") {
815 lang_package = lex.getString();
816 } else if (token == "\\inputencoding") {
818 } else if (token == "\\graphics") {
819 readGraphicsDriver(lex);
820 } else if (token == "\\default_output_format") {
821 lex >> default_output_format;
822 } else if (token == "\\bibtex_command") {
824 bibtex_command = lex.getString();
825 } else if (token == "\\index_command") {
827 index_command = lex.getString();
828 } else if (token == "\\fontencoding") {
830 fontenc = lex.getString();
831 } else if (token == "\\font_roman") {
832 lex >> fonts_roman[0];
833 lex >> fonts_roman[1];
834 } else if (token == "\\font_sans") {
835 lex >> fonts_sans[0];
836 lex >> fonts_sans[1];
837 } else if (token == "\\font_typewriter") {
838 lex >> fonts_typewriter[0];
839 lex >> fonts_typewriter[1];
840 } else if (token == "\\font_math") {
841 lex >> fonts_math[0];
842 lex >> fonts_math[1];
843 } else if (token == "\\font_default_family") {
844 lex >> fonts_default_family;
845 } else if (token == "\\use_non_tex_fonts") {
846 lex >> useNonTeXFonts;
847 } else if (token == "\\font_sc") {
848 lex >> fonts_expert_sc;
849 } else if (token == "\\font_roman_osf") {
850 lex >> fonts_roman_osf;
851 } else if (token == "\\font_sans_osf") {
852 lex >> fonts_sans_osf;
853 } else if (token == "\\font_typewriter_osf") {
854 lex >> fonts_typewriter_osf;
855 } else if (token == "\\font_roman_opts") {
856 lex >> font_roman_opts;
857 } else if (token == "\\font_sf_scale") {
858 lex >> fonts_sans_scale[0];
859 lex >> fonts_sans_scale[1];
860 } else if (token == "\\font_sans_opts") {
861 lex >> font_sans_opts;
862 } else if (token == "\\font_tt_scale") {
863 lex >> fonts_typewriter_scale[0];
864 lex >> fonts_typewriter_scale[1];
865 } else if (token == "\\font_typewriter_opts") {
866 lex >> font_typewriter_opts;
867 } else if (token == "\\font_cjk") {
869 } else if (token == "\\use_microtype") {
870 lex >> use_microtype;
871 } else if (token == "\\use_dash_ligatures") {
872 lex >> use_dash_ligatures;
873 } else if (token == "\\paragraph_separation") {
876 paragraph_separation = parseptranslator().find(parsep);
877 } else if (token == "\\paragraph_indentation") {
879 string parindent = lex.getString();
880 if (parindent == "default")
881 pimpl_->parindent = Length();
883 pimpl_->parindent = Length(parindent);
884 } else if (token == "\\defskip") {
886 string const defskip = lex.getString();
887 pimpl_->defskip = VSpace(defskip);
888 if (pimpl_->defskip.kind() == VSpace::DEFSKIP)
890 pimpl_->defskip = VSpace(VSpace::MEDSKIP);
891 } else if (token == "\\is_math_indent") {
892 lex >> is_math_indent;
893 } else if (token == "\\math_indentation") {
895 string mathindent = lex.getString();
896 if (mathindent == "default")
897 pimpl_->mathindent = Length();
899 pimpl_->mathindent = Length(mathindent);
900 } else if (token == "\\math_numbering_side") {
904 math_numbering_side = LEFT;
905 else if (tmp == "right")
906 math_numbering_side = RIGHT;
908 math_numbering_side = DEFAULT;
909 } else if (token == "\\quotes_style") {
912 quotes_style = quotesstyletranslator().find(qstyle);
913 } else if (token == "\\dynamic_quotes") {
914 lex >> dynamic_quotes;
915 } else if (token == "\\papersize") {
918 papersize = papersizetranslator().find(ppsize);
919 } else if (token == "\\use_geometry") {
921 } else if (token == "\\use_package") {
926 use_package(package, packagetranslator().find(use));
927 } else if (token == "\\cite_engine") {
929 cite_engine_ = lex.getString();
930 } else if (token == "\\cite_engine_type") {
933 cite_engine_type_ = theCiteEnginesList.getType(engine_type);
934 } else if (token == "\\biblio_style") {
936 biblio_style = lex.getString();
937 } else if (token == "\\biblio_options") {
939 biblio_opts = trim(lex.getString());
940 } else if (token == "\\biblatex_bibstyle") {
942 biblatex_bibstyle = trim(lex.getString());
943 } else if (token == "\\biblatex_citestyle") {
945 biblatex_citestyle = trim(lex.getString());
946 } else if (token == "\\use_bibtopic") {
948 } else if (token == "\\multibib") {
950 } else if (token == "\\use_indices") {
952 } else if (token == "\\tracking_changes") {
953 lex >> track_changes;
954 } else if (token == "\\output_changes") {
955 lex >> output_changes;
956 } else if (token == "\\change_bars") {
958 } else if (token == "\\postpone_fragile_content") {
959 lex >> postpone_fragile_content;
960 } else if (token == "\\branch") {
962 docstring branch = lex.getDocString();
963 branchlist().add(branch);
966 string const tok = lex.getString();
967 if (tok == "\\end_branch")
969 Branch * branch_ptr = branchlist().find(branch);
970 if (tok == "\\selected") {
973 branch_ptr->setSelected(lex.getInteger());
975 if (tok == "\\filename_suffix") {
978 branch_ptr->setFileNameSuffix(lex.getInteger());
980 if (tok == "\\color") {
982 string color = lex.getString();
984 branch_ptr->setColor(color);
985 // Update also the Color table:
987 color = lcolor.getX11Name(Color_background);
989 lcolor.setColor(to_utf8(branch), color);
992 } else if (token == "\\index") {
994 docstring index = lex.getDocString();
996 indiceslist().add(index);
999 string const tok = lex.getString();
1000 if (tok == "\\end_index")
1002 Index * index_ptr = indiceslist().find(index);
1003 if (tok == "\\shortcut") {
1005 shortcut = lex.getDocString();
1007 index_ptr->setShortcut(shortcut);
1009 if (tok == "\\color") {
1011 string color = lex.getString();
1013 index_ptr->setColor(color);
1014 // Update also the Color table:
1015 if (color == "none")
1016 color = lcolor.getX11Name(Color_background);
1018 if (!shortcut.empty())
1019 lcolor.setColor(to_utf8(shortcut), color);
1022 } else if (token == "\\author") {
1024 istringstream ss(lex.getString());
1028 } else if (token == "\\paperorientation") {
1031 orientation = paperorientationtranslator().find(orient);
1032 } else if (token == "\\backgroundcolor") {
1034 backgroundcolor = lyx::rgbFromHexName(lex.getString());
1035 isbackgroundcolor = true;
1036 } else if (token == "\\fontcolor") {
1038 fontcolor = lyx::rgbFromHexName(lex.getString());
1040 } else if (token == "\\notefontcolor") {
1042 string color = lex.getString();
1043 notefontcolor = lyx::rgbFromHexName(color);
1044 lcolor.setColor("notefontcolor", color);
1045 } else if (token == "\\boxbgcolor") {
1047 string color = lex.getString();
1048 boxbgcolor = lyx::rgbFromHexName(color);
1049 lcolor.setColor("boxbgcolor", color);
1050 } else if (token == "\\paperwidth") {
1052 } else if (token == "\\paperheight") {
1054 } else if (token == "\\leftmargin") {
1056 } else if (token == "\\topmargin") {
1058 } else if (token == "\\rightmargin") {
1060 } else if (token == "\\bottommargin") {
1061 lex >> bottommargin;
1062 } else if (token == "\\headheight") {
1064 } else if (token == "\\headsep") {
1066 } else if (token == "\\footskip") {
1068 } else if (token == "\\columnsep") {
1070 } else if (token == "\\paperfontsize") {
1072 } else if (token == "\\papercolumns") {
1074 } else if (token == "\\listings_params") {
1077 listings_params = InsetListingsParams(par).params();
1078 } else if (token == "\\papersides") {
1081 sides = sidestranslator().find(psides);
1082 } else if (token == "\\paperpagestyle") {
1084 } else if (token == "\\tablestyle") {
1086 } else if (token == "\\bullet") {
1088 } else if (token == "\\bulletLaTeX") {
1089 readBulletsLaTeX(lex);
1090 } else if (token == "\\secnumdepth") {
1092 } else if (token == "\\tocdepth") {
1094 } else if (token == "\\spacing") {
1098 if (nspacing == "other") {
1101 spacing().set(spacetranslator().find(nspacing), tmp_val);
1102 } else if (token == "\\float_placement") {
1103 lex >> float_placement;
1104 } else if (token == "\\float_alignment") {
1105 lex >> float_alignment;
1107 } else if (prefixIs(token, "\\pdf_") || token == "\\use_hyperref") {
1108 string toktmp = pdfoptions().readToken(lex, token);
1109 if (!toktmp.empty()) {
1110 lyxerr << "PDFOptions::readToken(): Unknown token: " <<
1114 } else if (token == "\\html_math_output") {
1117 html_math_output = static_cast<MathOutput>(temp);
1118 } else if (token == "\\html_be_strict") {
1119 lex >> html_be_strict;
1120 } else if (token == "\\html_css_as_file") {
1121 lex >> html_css_as_file;
1122 } else if (token == "\\html_math_img_scale") {
1123 lex >> html_math_img_scale;
1124 } else if (token == "\\html_latex_start") {
1126 html_latex_start = lex.getString();
1127 } else if (token == "\\html_latex_end") {
1129 html_latex_end = lex.getString();
1130 } else if (token == "\\output_sync") {
1132 } else if (token == "\\output_sync_macro") {
1133 lex >> output_sync_macro;
1134 } else if (token == "\\use_refstyle") {
1135 lex >> use_refstyle;
1136 } else if (token == "\\use_minted") {
1138 } else if (token == "\\use_lineno") {
1140 } else if (token == "\\lineno_options") {
1142 lineno_opts = trim(lex.getString());
1144 lyxerr << "BufferParams::readToken(): Unknown token: " <<
1154 // Quote argument if it contains spaces
1155 string quoteIfNeeded(string const & str) {
1156 if (contains(str, ' '))
1157 return "\"" + str + "\"";
1163 void BufferParams::writeFile(ostream & os, Buffer const * buf) const
1165 // The top of the file is written by the buffer.
1166 // Prints out the buffer info into the .lyx file given by file
1168 os << "\\save_transient_properties "
1169 << convert<string>(save_transient_properties) << '\n';
1171 // the document directory (must end with a path separator)
1172 // realPath() is used to resolve symlinks, while addPath(..., "")
1173 // ensures a trailing path separator.
1175 string filepath = addPath(buf->fileName().onlyPath().realPath(), "");
1176 string const sysdir = inSystemDir(FileName(filepath), docsys) ? docsys
1177 : addPath(package().system_support().realPath(), "");
1178 string const relpath =
1179 to_utf8(makeRelPath(from_utf8(filepath), from_utf8(sysdir)));
1180 if (!prefixIs(relpath, "../") && !FileName::isAbsolute(relpath))
1181 filepath = addPath("/systemlyxdir", relpath);
1182 else if (!save_transient_properties || !lyxrc.save_origin)
1183 filepath = "unavailable";
1184 os << "\\origin " << quoteIfNeeded(filepath) << '\n';
1187 os << "\\textclass "
1188 << quoteIfNeeded(buf->includedFilePath(addName(buf->layoutPos(),
1189 baseClass()->name()), "layout"))
1192 // then the preamble
1193 if (!preamble.empty()) {
1194 // remove '\n' from the end of preamble
1195 docstring const tmppreamble = rtrim(preamble, "\n");
1196 os << "\\begin_preamble\n"
1197 << to_utf8(tmppreamble)
1198 << "\n\\end_preamble\n";
1202 if (!options.empty()) {
1203 os << "\\options " << options << '\n';
1206 // use the class options defined in the layout?
1207 os << "\\use_default_options "
1208 << convert<string>(use_default_options) << "\n";
1210 // the master document
1211 if (!master.empty()) {
1212 os << "\\master " << master << '\n';
1216 if (!removed_modules_.empty()) {
1217 os << "\\begin_removed_modules" << '\n';
1218 for (auto const & mod : removed_modules_)
1220 os << "\\end_removed_modules" << '\n';
1224 if (!layout_modules_.empty()) {
1225 os << "\\begin_modules" << '\n';
1226 for (auto const & mod : layout_modules_)
1228 os << "\\end_modules" << '\n';
1232 if (!included_children_.empty()) {
1233 os << "\\begin_includeonly" << '\n';
1234 for (auto const & c : included_children_)
1236 os << "\\end_includeonly" << '\n';
1238 os << "\\maintain_unincluded_children "
1239 << convert<string>(maintain_unincluded_children) << '\n';
1241 // local layout information
1242 docstring const local_layout = getLocalLayout(false);
1243 if (!local_layout.empty()) {
1244 // remove '\n' from the end
1245 docstring const tmplocal = rtrim(local_layout, "\n");
1246 os << "\\begin_local_layout\n"
1247 << to_utf8(tmplocal)
1248 << "\n\\end_local_layout\n";
1250 docstring const forced_local_layout = getLocalLayout(true);
1251 if (!forced_local_layout.empty()) {
1252 // remove '\n' from the end
1253 docstring const tmplocal = rtrim(forced_local_layout, "\n");
1254 os << "\\begin_forced_local_layout\n"
1255 << to_utf8(tmplocal)
1256 << "\n\\end_forced_local_layout\n";
1259 // then the text parameters
1260 if (language != ignore_language)
1261 os << "\\language " << language->lang() << '\n';
1262 os << "\\language_package " << lang_package
1263 << "\n\\inputencoding " << inputenc
1264 << "\n\\fontencoding " << fontenc
1265 << "\n\\font_roman \"" << fonts_roman[0]
1266 << "\" \"" << fonts_roman[1] << '"'
1267 << "\n\\font_sans \"" << fonts_sans[0]
1268 << "\" \"" << fonts_sans[1] << '"'
1269 << "\n\\font_typewriter \"" << fonts_typewriter[0]
1270 << "\" \"" << fonts_typewriter[1] << '"'
1271 << "\n\\font_math \"" << fonts_math[0]
1272 << "\" \"" << fonts_math[1] << '"'
1273 << "\n\\font_default_family " << fonts_default_family
1274 << "\n\\use_non_tex_fonts " << convert<string>(useNonTeXFonts)
1275 << "\n\\font_sc " << convert<string>(fonts_expert_sc)
1276 << "\n\\font_roman_osf " << convert<string>(fonts_roman_osf)
1277 << "\n\\font_sans_osf " << convert<string>(fonts_sans_osf)
1278 << "\n\\font_typewriter_osf " << convert<string>(fonts_typewriter_osf);
1279 if (!font_roman_opts.empty())
1280 os << "\n\\font_roman_opts \"" << font_roman_opts << "\"";
1281 os << "\n\\font_sf_scale " << fonts_sans_scale[0]
1282 << ' ' << fonts_sans_scale[1];
1283 if (!font_sans_opts.empty())
1284 os << "\n\\font_sans_opts \"" << font_sans_opts << "\"";
1285 os << "\n\\font_tt_scale " << fonts_typewriter_scale[0]
1286 << ' ' << fonts_typewriter_scale[1];
1287 if (!font_typewriter_opts.empty())
1288 os << "\n\\font_typewriter_opts \"" << font_typewriter_opts << "\"";
1290 if (!fonts_cjk.empty())
1291 os << "\\font_cjk " << fonts_cjk << '\n';
1292 os << "\\use_microtype " << convert<string>(use_microtype) << '\n';
1293 os << "\\use_dash_ligatures " << convert<string>(use_dash_ligatures) << '\n';
1294 os << "\\graphics " << graphics_driver << '\n';
1295 os << "\\default_output_format " << default_output_format << '\n';
1296 os << "\\output_sync " << output_sync << '\n';
1297 if (!output_sync_macro.empty())
1298 os << "\\output_sync_macro \"" << output_sync_macro << "\"\n";
1299 os << "\\bibtex_command " << bibtex_command << '\n';
1300 os << "\\index_command " << index_command << '\n';
1302 if (!float_placement.empty())
1303 os << "\\float_placement " << float_placement << '\n';
1304 if (!float_alignment.empty())
1305 os << "\\float_alignment " << float_alignment << '\n';
1306 os << "\\paperfontsize " << fontsize << '\n';
1308 spacing().writeFile(os);
1309 pdfoptions().writeFile(os);
1311 os << "\\papersize " << string_papersize[papersize]
1312 << "\n\\use_geometry " << convert<string>(use_geometry);
1313 map<string, string> const & packages = auto_packages();
1314 for (auto const & pack : packages)
1315 os << "\n\\use_package " << pack.first << ' '
1316 << use_package(pack.first);
1318 os << "\n\\cite_engine ";
1320 if (!cite_engine_.empty())
1325 os << "\n\\cite_engine_type " << theCiteEnginesList.getTypeAsString(cite_engine_type_);
1327 if (!biblio_style.empty())
1328 os << "\n\\biblio_style " << biblio_style;
1329 if (!biblio_opts.empty())
1330 os << "\n\\biblio_options " << biblio_opts;
1331 if (!biblatex_bibstyle.empty())
1332 os << "\n\\biblatex_bibstyle " << biblatex_bibstyle;
1333 if (!biblatex_citestyle.empty())
1334 os << "\n\\biblatex_citestyle " << biblatex_citestyle;
1335 if (!multibib.empty())
1336 os << "\n\\multibib " << multibib;
1338 os << "\n\\use_bibtopic " << convert<string>(use_bibtopic)
1339 << "\n\\use_indices " << convert<string>(use_indices)
1340 << "\n\\paperorientation " << string_orientation[orientation]
1341 << "\n\\suppress_date " << convert<string>(suppress_date)
1342 << "\n\\justification " << convert<string>(justification)
1343 << "\n\\use_refstyle " << use_refstyle
1344 << "\n\\use_minted " << use_minted
1345 << "\n\\use_lineno " << use_lineno
1348 if (!lineno_opts.empty())
1349 os << "\\lineno_options " << lineno_opts << '\n';
1351 if (isbackgroundcolor == true)
1352 os << "\\backgroundcolor " << lyx::X11hexname(backgroundcolor) << '\n';
1353 if (isfontcolor == true)
1354 os << "\\fontcolor " << lyx::X11hexname(fontcolor) << '\n';
1355 if (notefontcolor != lyx::rgbFromHexName("#cccccc"))
1356 os << "\\notefontcolor " << lyx::X11hexname(notefontcolor) << '\n';
1357 if (boxbgcolor != lyx::rgbFromHexName("#ff0000"))
1358 os << "\\boxbgcolor " << lyx::X11hexname(boxbgcolor) << '\n';
1360 for (auto const & br : branchlist()) {
1361 os << "\\branch " << to_utf8(br.branch())
1362 << "\n\\selected " << br.isSelected()
1363 << "\n\\filename_suffix " << br.hasFileNameSuffix()
1364 << "\n\\color " << lyx::X11hexname(br.color())
1369 for (auto const & id : indiceslist()) {
1370 os << "\\index " << to_utf8(id.index())
1371 << "\n\\shortcut " << to_utf8(id.shortcut())
1372 << "\n\\color " << lyx::X11hexname(id.color())
1377 if (!paperwidth.empty())
1378 os << "\\paperwidth "
1379 << VSpace(paperwidth).asLyXCommand() << '\n';
1380 if (!paperheight.empty())
1381 os << "\\paperheight "
1382 << VSpace(paperheight).asLyXCommand() << '\n';
1383 if (!leftmargin.empty())
1384 os << "\\leftmargin "
1385 << VSpace(leftmargin).asLyXCommand() << '\n';
1386 if (!topmargin.empty())
1387 os << "\\topmargin "
1388 << VSpace(topmargin).asLyXCommand() << '\n';
1389 if (!rightmargin.empty())
1390 os << "\\rightmargin "
1391 << VSpace(rightmargin).asLyXCommand() << '\n';
1392 if (!bottommargin.empty())
1393 os << "\\bottommargin "
1394 << VSpace(bottommargin).asLyXCommand() << '\n';
1395 if (!headheight.empty())
1396 os << "\\headheight "
1397 << VSpace(headheight).asLyXCommand() << '\n';
1398 if (!headsep.empty())
1400 << VSpace(headsep).asLyXCommand() << '\n';
1401 if (!footskip.empty())
1403 << VSpace(footskip).asLyXCommand() << '\n';
1404 if (!columnsep.empty())
1405 os << "\\columnsep "
1406 << VSpace(columnsep).asLyXCommand() << '\n';
1407 os << "\\secnumdepth " << secnumdepth
1408 << "\n\\tocdepth " << tocdepth
1409 << "\n\\paragraph_separation "
1410 << string_paragraph_separation[paragraph_separation];
1411 if (!paragraph_separation)
1412 os << "\n\\paragraph_indentation "
1413 << (getParIndent().empty() ? "default" : getParIndent().asString());
1415 os << "\n\\defskip " << getDefSkip().asLyXCommand();
1416 os << "\n\\is_math_indent " << is_math_indent;
1418 os << "\n\\math_indentation "
1419 << (getMathIndent().empty() ? "default" : getMathIndent().asString());
1420 os << "\n\\math_numbering_side ";
1421 switch(math_numbering_side) {
1431 os << "\n\\quotes_style "
1432 << string_quotes_style[quotes_style]
1433 << "\n\\dynamic_quotes " << dynamic_quotes
1434 << "\n\\papercolumns " << columns
1435 << "\n\\papersides " << sides
1436 << "\n\\paperpagestyle " << pagestyle
1437 << "\n\\tablestyle " << tablestyle << '\n';
1438 if (!listings_params.empty())
1439 os << "\\listings_params \"" <<
1440 InsetListingsParams(listings_params).encodedString() << "\"\n";
1441 for (int i = 0; i < 4; ++i) {
1442 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
1443 if (user_defined_bullet(i).getFont() != -1) {
1444 os << "\\bullet " << i << " "
1445 << user_defined_bullet(i).getFont() << " "
1446 << user_defined_bullet(i).getCharacter() << " "
1447 << user_defined_bullet(i).getSize() << "\n";
1451 os << "\\bulletLaTeX " << i << " \""
1452 << lyx::to_ascii(user_defined_bullet(i).getText())
1458 os << "\\tracking_changes "
1459 << (save_transient_properties ? convert<string>(track_changes) : "false")
1462 os << "\\output_changes "
1463 << (save_transient_properties ? convert<string>(output_changes) : "false")
1466 os << "\\change_bars "
1467 << (save_transient_properties ? convert<string>(change_bars) : "false")
1470 os << "\\postpone_fragile_content " << convert<string>(postpone_fragile_content) << '\n';
1472 os << "\\html_math_output " << html_math_output << '\n'
1473 << "\\html_css_as_file " << html_css_as_file << '\n'
1474 << "\\html_be_strict " << convert<string>(html_be_strict) << '\n';
1476 if (html_math_img_scale != 1.0)
1477 os << "\\html_math_img_scale " << convert<string>(html_math_img_scale) << '\n';
1478 if (!html_latex_start.empty())
1479 os << "\\html_latex_start " << html_latex_start << '\n';
1480 if (!html_latex_end.empty())
1481 os << "\\html_latex_end " << html_latex_end << '\n';
1483 os << pimpl_->authorlist;
1487 void BufferParams::validate(LaTeXFeatures & features) const
1489 features.require(documentClass().required());
1491 if (columns > 1 && language->rightToLeft())
1492 features.require("rtloutputdblcol");
1494 if (output_changes) {
1495 bool xcolorulem = LaTeXFeatures::isAvailable("ulem") &&
1496 LaTeXFeatures::isAvailable("xcolor");
1498 switch (features.runparams().flavor) {
1499 case OutputParams::LATEX:
1500 case OutputParams::DVILUATEX:
1502 features.require("ct-xcolor-ulem");
1503 features.require("ulem");
1504 features.require("xcolor");
1506 features.require("ct-none");
1509 case OutputParams::LUATEX:
1510 case OutputParams::PDFLATEX:
1511 case OutputParams::XETEX:
1513 features.require("ct-xcolor-ulem");
1514 features.require("ulem");
1515 features.require("xcolor");
1516 // improves color handling in PDF output
1517 features.require("pdfcolmk");
1519 features.require("ct-none");
1526 features.require("changebar");
1529 // Floats with 'Here definitely' as default setting.
1530 if (float_placement.find('H') != string::npos)
1531 features.require("float");
1533 for (auto const & pm : use_packages) {
1534 if (pm.first == "amsmath") {
1535 // AMS Style is at document level
1536 if (pm.second == package_on ||
1537 features.isProvided("amsmath"))
1538 features.require(pm.first);
1539 } else if (pm.second == package_on)
1540 features.require(pm.first);
1543 // Document-level line spacing
1544 if (spacing().getSpace() != Spacing::Single && !spacing().isDefault())
1545 features.require("setspace");
1547 // the bullet shapes are buffer level not paragraph level
1548 // so they are tested here
1549 for (int i = 0; i < 4; ++i) {
1550 if (user_defined_bullet(i) == ITEMIZE_DEFAULTS[i])
1552 int const font = user_defined_bullet(i).getFont();
1554 int const c = user_defined_bullet(i).getCharacter();
1560 features.require("latexsym");
1562 } else if (font == 1) {
1563 features.require("amssymb");
1564 } else if (font >= 2 && font <= 5) {
1565 features.require("pifont");
1569 if (pdfoptions().use_hyperref) {
1570 features.require("hyperref");
1571 // due to interferences with babel and hyperref, the color package has to
1572 // be loaded after hyperref when hyperref is used with the colorlinks
1573 // option, see http://www.lyx.org/trac/ticket/5291
1574 if (pdfoptions().colorlinks)
1575 features.require("color");
1577 if (!listings_params.empty()) {
1578 // do not test validity because listings_params is
1579 // supposed to be valid
1581 InsetListingsParams(listings_params).separatedParams(true);
1582 // we can't support all packages, but we should load the color package
1583 if (par.find("\\color", 0) != string::npos)
1584 features.require("color");
1587 // some languages are only available via polyglossia
1588 if (features.hasPolyglossiaExclusiveLanguages())
1589 features.require("polyglossia");
1591 if (useNonTeXFonts && fontsMath() != "auto")
1592 features.require("unicode-math");
1595 features.require("microtype");
1597 if (!language->required().empty())
1598 features.require(language->required());
1602 bool BufferParams::writeLaTeX(otexstream & os, LaTeXFeatures & features,
1603 FileName const & filepath) const
1605 // http://www.tug.org/texmf-dist/doc/latex/base/fixltx2e.pdf
1606 // !! To use the Fix-cm package, load it before \documentclass, and use the command
1607 // \RequirePackage to do so, rather than the normal \usepackage
1608 // Do not try to load any other package before the document class, unless you
1609 // have a thorough understanding of the LATEX internals and know exactly what you
1611 if (features.mustProvide("fix-cm"))
1612 os << "\\RequirePackage{fix-cm}\n";
1613 // Likewise for fixltx2e. If other packages conflict with this policy,
1614 // treat it as a package bug (and report it!)
1615 // See http://www.latex-project.org/cgi-bin/ltxbugs2html?pr=latex/4407
1616 if (features.mustProvide("fixltx2e"))
1617 os << "\\RequirePackage{fixltx2e}\n";
1619 os << "\\documentclass";
1621 DocumentClass const & tclass = documentClass();
1623 ostringstream clsoptions; // the document class options.
1625 if (tokenPos(tclass.opt_fontsize(),
1626 '|', fontsize) >= 0) {
1627 // only write if existing in list (and not default)
1628 clsoptions << subst(tclass.fontsizeformat(), "$$s", fontsize) << ",";
1631 // paper sizes not supported by the class itself need the
1633 vector<string> classpsizes = getVectorFromString(tclass.opt_pagesize(), "|");
1634 bool class_supported_papersize = papersize == PAPER_DEFAULT
1635 || find(classpsizes.begin(), classpsizes.end(), string_papersize[papersize]) != classpsizes.end();
1637 if ((!use_geometry || features.isProvided("geometry-light"))
1638 && class_supported_papersize && papersize != PAPER_DEFAULT)
1639 clsoptions << subst(tclass.pagesizeformat(), "$$s", string_papersize[papersize]) << ",";
1642 if (sides != tclass.sides()) {
1645 clsoptions << "oneside,";
1648 clsoptions << "twoside,";
1654 if (columns != tclass.columns()) {
1656 clsoptions << "twocolumn,";
1658 clsoptions << "onecolumn,";
1662 && orientation == ORIENTATION_LANDSCAPE)
1663 clsoptions << "landscape,";
1666 clsoptions << "fleqn,";
1668 switch(math_numbering_side) {
1670 clsoptions << "leqno,";
1673 clsoptions << "reqno,";
1674 features.require("amsmath");
1680 // language should be a parameter to \documentclass
1681 if (language->babel() == "hebrew"
1682 && default_language->babel() != "hebrew")
1683 // This seems necessary
1684 features.useLanguage(default_language);
1686 ostringstream language_options;
1687 bool const use_babel = features.useBabel() && !features.isProvided("babel");
1688 bool const use_polyglossia = features.usePolyglossia();
1689 bool const global = lyxrc.language_global_options;
1690 if (features.useBabel() || (use_polyglossia && global)) {
1691 language_options << features.getBabelLanguages();
1692 if (!language->babel().empty()) {
1693 if (!language_options.str().empty())
1694 language_options << ',';
1695 language_options << language->babel();
1697 if (global && !language_options.str().empty())
1698 clsoptions << language_options.str() << ',';
1701 // the predefined options from the layout
1702 if (use_default_options && !tclass.options().empty())
1703 clsoptions << tclass.options() << ',';
1705 // the user-defined options
1706 if (!options.empty()) {
1707 clsoptions << options << ',';
1710 string strOptions(clsoptions.str());
1711 if (!strOptions.empty()) {
1712 strOptions = rtrim(strOptions, ",");
1714 os << '[' << from_utf8(strOptions) << ']';
1717 os << '{' << from_ascii(tclass.latexname()) << "}\n";
1718 // end of \documentclass defs
1720 // if we use fontspec or newtxmath, we have to load the AMS packages here
1721 string const ams = features.loadAMSPackages();
1722 bool const ot1 = (main_font_encoding() == "default" || main_font_encoding() == "OT1");
1723 bool const use_newtxmath =
1724 theLaTeXFonts().getLaTeXFont(from_ascii(fontsMath())).getUsedPackage(
1725 ot1, false, false) == "newtxmath";
1726 if ((useNonTeXFonts || use_newtxmath) && !ams.empty())
1727 os << from_ascii(ams);
1729 if (useNonTeXFonts) {
1730 // Babel (as of 2017/11/03) loads fontspec itself
1731 if (!features.isProvided("fontspec")
1732 && !(features.useBabel() && features.isAvailable("babel-2017/11/03")))
1733 os << "\\usepackage{fontspec}\n";
1734 if (features.mustProvide("unicode-math")
1735 && features.isAvailable("unicode-math"))
1736 os << "\\usepackage{unicode-math}\n";
1739 // load CJK support package before font selection
1740 // (see autotests/export/latex/CJK/micro-sign_utf8-cjk-libertine.lyx)
1741 if (!useNonTeXFonts && encoding().package() != Encoding::none && inputenc != "utf8x"
1742 && (encoding().package() == Encoding::CJK || features.mustProvide("CJK"))) {
1743 if (inputenc == "utf8-cjk" || inputenc == "utf8")
1744 os << "\\usepackage{CJKutf8}\n";
1746 os << "\\usepackage[encapsulated]{CJK}\n";
1749 // font selection must be done before loading fontenc.sty
1750 // but after babel with non-TeX fonts
1751 string const fonts = loadFonts(features);
1752 if (!fonts.empty() && (!features.useBabel() || !useNonTeXFonts))
1753 os << from_utf8(fonts);
1755 if (fonts_default_family != "default")
1756 os << "\\renewcommand{\\familydefault}{\\"
1757 << from_ascii(fonts_default_family) << "}\n";
1759 // set font encoding
1760 // non-TeX fonts use font encoding TU (set by fontspec)
1761 if (!useNonTeXFonts && !features.isProvided("fontenc")
1762 && main_font_encoding() != "default") {
1763 // get main font encodings
1764 vector<string> fontencs = font_encodings();
1765 // get font encodings of secondary languages
1766 // FIXME: some languages (hebrew, ...) assume a standard font encoding as last
1767 // option (for text in other languages).
1768 features.getFontEncodings(fontencs);
1769 if (!fontencs.empty()) {
1770 os << "\\usepackage["
1771 << from_ascii(getStringFromVector(fontencs))
1776 // Load textcomp and pmboxdraw before (lua)inputenc (#11454)
1777 if (features.mustProvide("textcomp"))
1778 os << "\\usepackage{textcomp}\n";
1779 if (features.mustProvide("pmboxdraw"))
1780 os << "\\usepackage{pmboxdraw}\n";
1782 // handle inputenc etc.
1783 // (In documents containing text in Thai language,
1784 // we must load inputenc after babel, see lib/languages).
1785 if (!contains(features.getBabelPostsettings(), from_ascii("thai.ldf")))
1786 writeEncodingPreamble(os, features);
1789 if (!features.runparams().includeall && !included_children_.empty()) {
1790 os << "\\includeonly{";
1792 for (auto incfile : included_children_) {
1793 FileName inc = makeAbsPath(incfile, filepath.absFileName());
1794 string mangled = DocFileName(changeExtension(inc.absFileName(), ".tex")).
1796 if (!features.runparams().nice)
1798 // \includeonly doesn't want an extension
1799 incfile = changeExtension(incfile, string());
1800 incfile = support::latex_path(incfile);
1801 if (!incfile.empty()) {
1804 os << from_utf8(incfile);
1811 if (!features.isProvided("geometry")
1812 && (use_geometry || !class_supported_papersize)) {
1813 odocstringstream ods;
1814 if (!getGraphicsDriver("geometry").empty())
1815 ods << getGraphicsDriver("geometry");
1816 if (orientation == ORIENTATION_LANDSCAPE)
1817 ods << ",landscape";
1818 switch (papersize) {
1820 if (!paperwidth.empty())
1821 ods << ",paperwidth="
1822 << from_ascii(paperwidth);
1823 if (!paperheight.empty())
1824 ods << ",paperheight="
1825 << from_ascii(paperheight);
1827 case PAPER_USLETTER:
1829 case PAPER_USEXECUTIVE:
1858 ods << "," << from_ascii(string_papersize_geometry[papersize]);
1863 docstring g_options = trim(ods.str(), ",");
1864 os << "\\usepackage";
1865 // geometry-light means that the class works with geometry, but overwrites
1866 // the package options and paper sizes (memoir does this).
1867 // In this case, all options need to go to \geometry
1868 // and the standard paper sizes need to go to the class options.
1869 if (!g_options.empty() && !features.isProvided("geometry-light")) {
1870 os << '[' << g_options << ']';
1873 os << "{geometry}\n";
1874 if (use_geometry || features.isProvided("geometry-light")) {
1875 os << "\\geometry{verbose";
1876 if (!g_options.empty())
1877 // Output general options here with "geometry light".
1878 os << "," << g_options;
1879 // output this only if use_geometry is true
1881 if (!topmargin.empty())
1882 os << ",tmargin=" << from_ascii(Length(topmargin).asLatexString());
1883 if (!bottommargin.empty())
1884 os << ",bmargin=" << from_ascii(Length(bottommargin).asLatexString());
1885 if (!leftmargin.empty())
1886 os << ",lmargin=" << from_ascii(Length(leftmargin).asLatexString());
1887 if (!rightmargin.empty())
1888 os << ",rmargin=" << from_ascii(Length(rightmargin).asLatexString());
1889 if (!headheight.empty())
1890 os << ",headheight=" << from_ascii(Length(headheight).asLatexString());
1891 if (!headsep.empty())
1892 os << ",headsep=" << from_ascii(Length(headsep).asLatexString());
1893 if (!footskip.empty())
1894 os << ",footskip=" << from_ascii(Length(footskip).asLatexString());
1895 if (!columnsep.empty())
1896 os << ",columnsep=" << from_ascii(Length(columnsep).asLatexString());
1900 } else if (orientation == ORIENTATION_LANDSCAPE
1901 || papersize != PAPER_DEFAULT) {
1902 features.require("papersize");
1905 if (tokenPos(tclass.opt_pagestyle(), '|', pagestyle) >= 0) {
1906 if (pagestyle == "fancy")
1907 os << "\\usepackage{fancyhdr}\n";
1908 os << "\\pagestyle{" << from_ascii(pagestyle) << "}\n";
1911 // only output when the background color is not default
1912 if (isbackgroundcolor == true) {
1913 // only require color here, the background color will be defined
1914 // in LaTeXFeatures.cpp to avoid interferences with the LaTeX
1916 features.require("color");
1917 features.require("pagecolor");
1920 // only output when the font color is not default
1921 if (isfontcolor == true) {
1922 // only require color here, the font color will be defined
1923 // in LaTeXFeatures.cpp to avoid interferences with the LaTeX
1925 features.require("color");
1926 features.require("fontcolor");
1929 // Only if class has a ToC hierarchy
1930 if (tclass.hasTocLevels()) {
1931 if (secnumdepth != tclass.secnumdepth()) {
1932 os << "\\setcounter{secnumdepth}{"
1936 if (tocdepth != tclass.tocdepth()) {
1937 os << "\\setcounter{tocdepth}{"
1943 if (paragraph_separation) {
1944 // when skip separation
1945 switch (getDefSkip().kind()) {
1946 case VSpace::SMALLSKIP:
1947 os << "\\setlength{\\parskip}{\\smallskipamount}\n";
1949 case VSpace::MEDSKIP:
1950 os << "\\setlength{\\parskip}{\\medskipamount}\n";
1952 case VSpace::BIGSKIP:
1953 os << "\\setlength{\\parskip}{\\bigskipamount}\n";
1955 case VSpace::LENGTH:
1956 os << "\\setlength{\\parskip}{"
1957 << from_utf8(getDefSkip().length().asLatexString())
1960 default: // should never happen // Then delete it.
1961 os << "\\setlength{\\parskip}{\\medskipamount}\n";
1964 os << "\\setlength{\\parindent}{0pt}\n";
1966 // when separation by indentation
1967 // only output something when a width is given
1968 if (!getParIndent().empty()) {
1969 os << "\\setlength{\\parindent}{"
1970 << from_utf8(getParIndent().asLatexString())
1975 if (is_math_indent) {
1976 // when formula indentation
1977 // only output something when it is not the default
1978 if (!getMathIndent().empty()) {
1979 os << "\\setlength{\\mathindent}{"
1980 << from_utf8(getMathIndent().asString())
1985 // Now insert the LyX specific LaTeX commands...
1986 features.resolveAlternatives();
1987 features.expandMultiples();
1990 if (!output_sync_macro.empty())
1991 os << from_utf8(output_sync_macro) +"\n";
1992 else if (features.runparams().flavor == OutputParams::LATEX)
1993 os << "\\usepackage[active]{srcltx}\n";
1994 else if (features.runparams().flavor == OutputParams::PDFLATEX)
1995 os << "\\synctex=-1\n";
1998 // The package options (via \PassOptionsToPackage)
1999 os << from_ascii(features.getPackageOptions());
2001 // due to interferences with babel and hyperref, the color package has to
2002 // be loaded (when it is not already loaded) before babel when hyperref
2003 // is used with the colorlinks option, see
2004 // http://www.lyx.org/trac/ticket/5291
2005 // we decided therefore to load color always before babel, see
2006 // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg144349.html
2007 os << from_ascii(features.getColorOptions());
2009 // If we use hyperref, jurabib, japanese or varioref,
2010 // we have to call babel before
2012 && (features.isRequired("jurabib")
2013 || features.isRequired("hyperref")
2014 || features.isRequired("varioref")
2015 || features.isRequired("japanese"))) {
2016 os << features.getBabelPresettings();
2018 os << from_utf8(babelCall(language_options.str(),
2019 !lyxrc.language_global_options)) + '\n';
2020 os << features.getBabelPostsettings();
2023 // The optional packages;
2024 os << from_ascii(features.getPackages());
2026 // Additional Indices
2027 if (features.isRequired("splitidx")) {
2028 for (auto const & idx : indiceslist()) {
2029 os << "\\newindex{";
2030 os << escape(idx.shortcut());
2036 os << from_utf8(spacing().writePreamble(features.isProvided("SetSpace")));
2039 // * Hyperref manual: "Make sure it comes last of your loaded
2040 // packages, to give it a fighting chance of not being over-written,
2041 // since its job is to redefine many LaTeX commands."
2042 // * Email from Heiko Oberdiek: "It is usually better to load babel
2043 // before hyperref. Then hyperref has a chance to detect babel.
2044 // * Has to be loaded before the "LyX specific LaTeX commands" to
2045 // avoid errors with algorithm floats.
2046 // use hyperref explicitly if it is required
2047 if (features.isRequired("hyperref")) {
2048 OutputParams tmp_params = features.runparams();
2049 pdfoptions().writeLaTeX(tmp_params, os,
2050 features.isProvided("hyperref"));
2051 // correctly break URLs with hyperref and dvi/ps output
2052 if (features.runparams().hyperref_driver == "dvips"
2053 && features.isAvailable("breakurl"))
2054 os << "\\usepackage{breakurl}\n";
2055 } else if (features.isRequired("nameref"))
2056 // hyperref loads this automatically
2057 os << "\\usepackage{nameref}\n";
2060 os << "\\usepackage";
2061 if (!lineno_opts.empty())
2062 os << "[" << lineno_opts << "]";
2064 os << "\\linenumbers\n";
2067 // bibtopic needs to be loaded after hyperref.
2068 // the dot provides the aux file naming which LyX can detect.
2069 if (features.mustProvide("bibtopic"))
2070 os << "\\usepackage[dot]{bibtopic}\n";
2072 // Will be surrounded by \makeatletter and \makeatother when not empty
2073 otexstringstream atlyxpreamble;
2075 // Some macros LyX will need
2077 TexString tmppreamble = features.getMacros();
2078 if (!tmppreamble.str.empty())
2079 atlyxpreamble << "\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
2080 "LyX specific LaTeX commands.\n"
2081 << move(tmppreamble)
2084 // the text class specific preamble
2086 docstring tmppreamble = features.getTClassPreamble();
2087 if (!tmppreamble.empty())
2088 atlyxpreamble << "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
2089 "Textclass specific LaTeX commands.\n"
2093 // suppress date if selected
2094 // use \@ifundefined because we cannot be sure that every document class
2095 // has a \date command
2097 atlyxpreamble << "\\@ifundefined{date}{}{\\date{}}\n";
2099 /* the user-defined preamble */
2100 if (!containsOnly(preamble, " \n\t")) {
2102 atlyxpreamble << "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
2103 "User specified LaTeX commands.\n";
2105 // Check if the user preamble contains uncodable glyphs
2106 odocstringstream user_preamble;
2107 docstring uncodable_glyphs;
2108 Encoding const * const enc = features.runparams().encoding;
2110 for (size_t n = 0; n < preamble.size(); ++n) {
2111 char_type c = preamble[n];
2112 if (!enc->encodable(c)) {
2113 docstring const glyph(1, c);
2114 LYXERR0("Uncodable character '"
2116 << "' in user preamble!");
2117 uncodable_glyphs += glyph;
2118 if (features.runparams().dryrun) {
2119 user_preamble << "<" << _("LyX Warning: ")
2120 << _("uncodable character") << " '";
2121 user_preamble.put(c);
2122 user_preamble << "'>";
2125 user_preamble.put(c);
2128 user_preamble << preamble;
2130 // On BUFFER_VIEW|UPDATE, warn user if we found uncodable glyphs
2131 if (!features.runparams().dryrun && !uncodable_glyphs.empty()) {
2132 frontend::Alert::warning(
2133 _("Uncodable character in user preamble"),
2135 _("The user preamble of your document contains glyphs "
2136 "that are unknown in the current document encoding "
2137 "(namely %1$s).\nThese glyphs are omitted "
2138 " from the output, which may result in "
2139 "incomplete output."
2140 "\n\nPlease select an appropriate "
2141 "document encoding\n"
2142 "(such as utf8) or change the "
2143 "preamble code accordingly."),
2146 atlyxpreamble << user_preamble.str() << '\n';
2149 // footmisc must be loaded after setspace
2150 // Load it here to avoid clashes with footmisc loaded in the user
2151 // preamble. For that reason we also pass the options via
2152 // \PassOptionsToPackage in getPreamble() and not here.
2153 if (features.mustProvide("footmisc"))
2154 atlyxpreamble << "\\usepackage{footmisc}\n";
2156 // subfig loads internally the LaTeX package "caption". As
2157 // caption is a very popular package, users will load it in
2158 // the preamble. Therefore we must load subfig behind the
2159 // user-defined preamble and check if the caption package was
2160 // loaded or not. For the case that caption is loaded before
2161 // subfig, there is the subfig option "caption=false". This
2162 // option also works when a koma-script class is used and
2163 // koma's own caption commands are used instead of caption. We
2164 // use \PassOptionsToPackage here because the user could have
2165 // already loaded subfig in the preamble.
2166 if (features.mustProvide("subfig"))
2167 atlyxpreamble << "\\@ifundefined{showcaptionsetup}{}{%\n"
2168 " \\PassOptionsToPackage{caption=false}{subfig}}\n"
2169 "\\usepackage{subfig}\n";
2171 // Itemize bullet settings need to be last in case the user
2172 // defines their own bullets that use a package included
2173 // in the user-defined preamble -- ARRae
2174 // Actually it has to be done much later than that
2175 // since some packages like frenchb make modifications
2176 // at \begin{document} time -- JMarc
2177 docstring bullets_def;
2178 for (int i = 0; i < 4; ++i) {
2179 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
2180 if (bullets_def.empty())
2181 bullets_def += "\\AtBeginDocument{\n";
2182 bullets_def += " \\def\\labelitemi";
2184 // `i' is one less than the item to modify
2191 bullets_def += "ii";
2197 bullets_def += '{' +
2198 user_defined_bullet(i).getText()
2203 if (!bullets_def.empty())
2204 atlyxpreamble << bullets_def << "}\n\n";
2206 if (!atlyxpreamble.empty())
2207 os << "\n\\makeatletter\n"
2208 << atlyxpreamble.release()
2209 << "\\makeatother\n\n";
2211 // We try to load babel late, in case it interferes with other packages.
2212 // Jurabib, hyperref, varioref, bicaption, menukeys and listings (bug 8995)
2213 // have to be called after babel, though.
2214 if (use_babel && !features.isRequired("jurabib")
2215 && !features.isRequired("hyperref")
2216 && !features.isRequired("varioref")
2217 && !features.isRequired("japanese")) {
2218 os << features.getBabelPresettings();
2220 os << from_utf8(babelCall(language_options.str(),
2221 !lyxrc.language_global_options)) + '\n';
2222 os << features.getBabelPostsettings();
2224 // In documents containing text in Thai language,
2225 // we must load inputenc after babel (see lib/languages).
2226 if (contains(features.getBabelPostsettings(), from_ascii("thai.ldf")))
2227 writeEncodingPreamble(os, features);
2229 // font selection must be done after babel with non-TeX fonts
2230 if (!fonts.empty() && features.useBabel() && useNonTeXFonts)
2231 os << from_utf8(fonts);
2233 if (features.isRequired("bicaption"))
2234 os << "\\usepackage{bicaption}\n";
2235 if (!listings_params.empty()
2236 || features.mustProvide("listings")
2237 || features.mustProvide("minted")) {
2239 os << "\\usepackage{minted}\n";
2241 os << "\\usepackage{listings}\n";
2243 string lst_params = listings_params;
2244 // If minted, do not output the language option (bug 11203)
2245 if (use_minted && contains(lst_params, "language=")) {
2246 vector<string> opts =
2247 getVectorFromString(lst_params, ",", false);
2248 for (size_t i = 0; i < opts.size(); ++i) {
2249 if (prefixIs(opts[i], "language="))
2250 opts.erase(opts.begin() + i--);
2252 lst_params = getStringFromVector(opts, ",");
2254 if (!lst_params.empty()) {
2256 os << "\\setminted{";
2259 // do not test validity because listings_params is
2260 // supposed to be valid
2262 InsetListingsParams(lst_params).separatedParams(true);
2263 os << from_utf8(par);
2267 // xunicode only needs to be loaded if tipa is used
2268 // (the rest is obsoleted by the new TU encoding).
2269 // It needs to be loaded at least after amsmath, amssymb,
2270 // esint and the other packages that provide special glyphs
2271 if (features.mustProvide("tipa") && useNonTeXFonts
2272 && !features.isProvided("xunicode")) {
2273 // The `xunicode` package officially only supports XeTeX,
2274 // but also works with LuaTeX. We work around its XeTeX test.
2275 if (features.runparams().flavor != OutputParams::XETEX) {
2276 os << "% Pretend to xunicode that we are XeTeX\n"
2277 << "\\def\\XeTeXpicfile{}\n";
2279 os << "\\usepackage{xunicode}\n";
2282 // covington must be loaded after beamerarticle
2283 if (features.isRequired("covington"))
2284 os << "\\usepackage{covington}\n";
2286 // Polyglossia must be loaded last ...
2287 if (use_polyglossia) {
2289 os << "\\usepackage{polyglossia}\n";
2290 // set the main language
2291 os << "\\setdefaultlanguage";
2292 if (!language->polyglossiaOpts().empty())
2293 os << "[" << from_ascii(language->polyglossiaOpts()) << "]";
2294 os << "{" << from_ascii(language->polyglossia()) << "}\n";
2295 // now setup the other languages
2296 set<string> const polylangs =
2297 features.getPolyglossiaLanguages();
2298 for (auto const & pl : polylangs) {
2299 // We do not output the options here; they are output in
2300 // the language switch commands. This is safer if multiple
2301 // varieties are used.
2302 if (pl == language->polyglossia())
2304 os << "\\setotherlanguage";
2305 os << "{" << from_ascii(pl) << "}\n";
2309 // ... but before biblatex (see #7065)
2310 if ((features.mustProvide("biblatex")
2311 || features.isRequired("biblatex-chicago"))
2312 && !features.isProvided("biblatex-chicago")
2313 && !features.isProvided("biblatex-natbib")
2314 && !features.isProvided("natbib-internal")
2315 && !features.isProvided("natbib")
2316 && !features.isProvided("jurabib")) {
2317 // The biblatex-chicago package has a differing interface
2318 // it uses a wrapper package and loads styles via fixed options
2319 bool const chicago = features.isRequired("biblatex-chicago");
2322 os << "\\usepackage";
2323 if (!biblatex_bibstyle.empty()
2324 && (biblatex_bibstyle == biblatex_citestyle)
2326 opts = "style=" + biblatex_bibstyle;
2328 } else if (!chicago) {
2329 if (!biblatex_bibstyle.empty()) {
2330 opts = "bibstyle=" + biblatex_bibstyle;
2333 if (!biblatex_citestyle.empty()) {
2334 opts += delim + "citestyle=" + biblatex_citestyle;
2338 if (!multibib.empty() && multibib != "child") {
2339 opts += delim + "refsection=" + multibib;
2342 if (bibtexCommand() == "bibtex8"
2343 || prefixIs(bibtexCommand(), "bibtex8 ")) {
2344 opts += delim + "backend=bibtex8";
2346 } else if (bibtexCommand() == "bibtex"
2347 || prefixIs(bibtexCommand(), "bibtex ")) {
2348 opts += delim + "backend=bibtex";
2351 if (!bib_encoding.empty() && encodings.fromLyXName(bib_encoding)) {
2352 opts += delim + "bibencoding="
2353 + encodings.fromLyXName(bib_encoding)->latexName();
2356 if (!biblio_opts.empty())
2357 opts += delim + biblio_opts;
2359 os << "[" << opts << "]";
2361 os << "{biblatex-chicago}\n";
2363 os << "{biblatex}\n";
2367 // Load custom language package here
2368 if (features.langPackage() == LaTeXFeatures::LANG_PACK_CUSTOM) {
2369 if (lang_package == "default")
2370 os << from_utf8(lyxrc.language_custom_package);
2372 os << from_utf8(lang_package);
2376 // Since menukeys uses catoptions, which does some heavy changes on key-value options,
2377 // it is recommended to load menukeys as the last package (even after hyperref)
2378 if (features.isRequired("menukeys"))
2379 os << "\\usepackage{menukeys}\n";
2381 docstring const i18npreamble =
2382 features.getTClassI18nPreamble(use_babel, use_polyglossia,
2384 if (!i18npreamble.empty())
2385 os << i18npreamble + '\n';
2391 void BufferParams::useClassDefaults()
2393 DocumentClass const & tclass = documentClass();
2395 sides = tclass.sides();
2396 columns = tclass.columns();
2397 pagestyle = tclass.pagestyle();
2398 tablestyle = tclass.tablestyle();
2399 use_default_options = true;
2400 // Only if class has a ToC hierarchy
2401 if (tclass.hasTocLevels()) {
2402 secnumdepth = tclass.secnumdepth();
2403 tocdepth = tclass.tocdepth();
2408 bool BufferParams::hasClassDefaults() const
2410 DocumentClass const & tclass = documentClass();
2412 return sides == tclass.sides()
2413 && columns == tclass.columns()
2414 && pagestyle == tclass.pagestyle()
2415 && tablestyle == tclass.tablestyle()
2416 && use_default_options
2417 && secnumdepth == tclass.secnumdepth()
2418 && tocdepth == tclass.tocdepth();
2422 DocumentClass const & BufferParams::documentClass() const
2428 DocumentClassConstPtr BufferParams::documentClassPtr() const
2434 void BufferParams::setDocumentClass(DocumentClassConstPtr tc)
2436 // evil, but this function is evil
2437 doc_class_ = const_pointer_cast<DocumentClass>(tc);
2438 invalidateConverterCache();
2442 bool BufferParams::setBaseClass(string const & classname, string const & path)
2444 LYXERR(Debug::TCLASS, "setBaseClass: " << classname);
2445 LayoutFileList & bcl = LayoutFileList::get();
2446 if (!bcl.haveClass(classname)) {
2448 bformat(_("The layout file:\n"
2450 "could not be found. A default textclass with default\n"
2451 "layouts will be used. LyX will not be able to produce\n"
2453 from_utf8(classname));
2454 frontend::Alert::error(_("Document class not found"), s);
2455 bcl.addEmptyClass(classname);
2458 bool const success = bcl[classname].load(path);
2461 bformat(_("Due to some error in it, the layout file:\n"
2463 "could not be loaded. A default textclass with default\n"
2464 "layouts will be used. LyX will not be able to produce\n"
2466 from_utf8(classname));
2467 frontend::Alert::error(_("Could not load class"), s);
2468 bcl.addEmptyClass(classname);
2471 pimpl_->baseClass_ = classname;
2472 layout_modules_.adaptToBaseClass(baseClass(), removed_modules_);
2477 LayoutFile const * BufferParams::baseClass() const
2479 if (LayoutFileList::get().haveClass(pimpl_->baseClass_))
2480 return &(LayoutFileList::get()[pimpl_->baseClass_]);
2486 LayoutFileIndex const & BufferParams::baseClassID() const
2488 return pimpl_->baseClass_;
2492 void BufferParams::makeDocumentClass(bool const clone)
2497 invalidateConverterCache();
2498 LayoutModuleList mods;
2499 for (auto const & mod : layout_modules_)
2500 mods.push_back(mod);
2502 doc_class_ = getDocumentClass(*baseClass(), mods, cite_engine_, clone);
2504 TextClass::ReturnValues success = TextClass::OK;
2505 if (!forced_local_layout_.empty())
2506 success = doc_class_->read(to_utf8(forced_local_layout_),
2508 if (!local_layout_.empty() &&
2509 (success == TextClass::OK || success == TextClass::OK_OLDFORMAT))
2510 success = doc_class_->read(to_utf8(local_layout_), TextClass::MODULE);
2511 if (success != TextClass::OK && success != TextClass::OK_OLDFORMAT) {
2512 docstring const msg = _("Error reading internal layout information");
2513 frontend::Alert::warning(_("Read Error"), msg);
2518 bool BufferParams::layoutModuleCanBeAdded(string const & modName) const
2520 return layout_modules_.moduleCanBeAdded(modName, baseClass());
2524 docstring BufferParams::getLocalLayout(bool forced) const
2527 return from_utf8(doc_class_->forcedLayouts());
2529 return local_layout_;
2533 void BufferParams::setLocalLayout(docstring const & layout, bool forced)
2536 forced_local_layout_ = layout;
2538 local_layout_ = layout;
2542 bool BufferParams::addLayoutModule(string const & modName)
2544 for (auto const & mod : layout_modules_)
2547 layout_modules_.push_back(modName);
2552 string BufferParams::bufferFormat() const
2554 return documentClass().outputFormat();
2558 bool BufferParams::isExportable(string const & format, bool need_viewable) const
2560 FormatList const & formats = exportableFormats(need_viewable);
2561 for (auto const & fmt : formats) {
2562 if (fmt->name() == format)
2569 FormatList const & BufferParams::exportableFormats(bool only_viewable) const
2571 FormatList & cached = only_viewable ?
2572 pimpl_->viewableFormatList : pimpl_->exportableFormatList;
2573 bool & valid = only_viewable ?
2574 pimpl_->isViewCacheValid : pimpl_->isExportCacheValid;
2578 vector<string> const backs = backends();
2579 set<string> excludes;
2580 if (useNonTeXFonts) {
2581 excludes.insert("latex");
2582 excludes.insert("pdflatex");
2583 } else if (inputenc != "ascii" && inputenc != "utf8-plain")
2584 // XeTeX with TeX fonts requires input encoding ascii (#10600).
2585 excludes.insert("xetex");
2586 FormatList result = theConverters().getReachable(backs[0], only_viewable,
2588 vector<string>::const_iterator it = backs.begin() + 1;
2589 for (; it != backs.end(); ++it) {
2590 FormatList r = theConverters().getReachable(*it, only_viewable,
2592 result.insert(result.end(), r.begin(), r.end());
2594 sort(result.begin(), result.end(), Format::formatSorter);
2601 vector<string> BufferParams::backends() const
2604 string const buffmt = bufferFormat();
2606 // FIXME: Don't hardcode format names here, but use a flag
2607 if (buffmt == "latex") {
2608 if (encoding().package() == Encoding::japanese)
2609 v.push_back("platex");
2611 if (!useNonTeXFonts) {
2612 v.push_back("pdflatex");
2613 v.push_back("latex");
2616 || inputenc == "ascii" || inputenc == "utf8-plain")
2617 v.push_back("xetex");
2618 v.push_back("luatex");
2619 v.push_back("dviluatex");
2622 string rbuffmt = buffmt;
2623 // If we use an OutputFormat in Japanese docs,
2624 // we need special format in order to get the path
2625 // via pLaTeX (#8823)
2626 if (documentClass().hasOutputFormat()
2627 && encoding().package() == Encoding::japanese)
2629 v.push_back(rbuffmt);
2632 v.push_back("xhtml");
2633 v.push_back("text");
2639 OutputParams::FLAVOR BufferParams::getOutputFlavor(string const & format) const
2641 string const dformat = (format.empty() || format == "default") ?
2642 getDefaultOutputFormat() : format;
2643 DefaultFlavorCache::const_iterator it =
2644 default_flavors_.find(dformat);
2646 if (it != default_flavors_.end())
2649 OutputParams::FLAVOR result = OutputParams::LATEX;
2651 // FIXME It'd be better not to hardcode this, but to do
2652 // something with formats.
2653 if (dformat == "xhtml")
2654 result = OutputParams::HTML;
2655 else if (dformat == "text")
2656 result = OutputParams::TEXT;
2657 else if (dformat == "lyx")
2658 result = OutputParams::LYX;
2659 else if (dformat == "pdflatex")
2660 result = OutputParams::PDFLATEX;
2661 else if (dformat == "xetex")
2662 result = OutputParams::XETEX;
2663 else if (dformat == "luatex")
2664 result = OutputParams::LUATEX;
2665 else if (dformat == "dviluatex")
2666 result = OutputParams::DVILUATEX;
2668 // Try to determine flavor of default output format
2669 vector<string> backs = backends();
2670 if (find(backs.begin(), backs.end(), dformat) == backs.end()) {
2671 // Get shortest path to format
2672 Graph::EdgePath path;
2673 for (auto const & bvar : backs) {
2674 Graph::EdgePath p = theConverters().getPath(bvar, dformat);
2675 if (!p.empty() && (path.empty() || p.size() < path.size())) {
2680 result = theConverters().getFlavor(path);
2683 // cache this flavor
2684 default_flavors_[dformat] = result;
2689 string BufferParams::getDefaultOutputFormat() const
2691 if (!default_output_format.empty()
2692 && default_output_format != "default")
2693 return default_output_format;
2695 FormatList const & formats = exportableFormats(true);
2696 if (formats.empty())
2698 // return the first we find
2699 return formats.front()->name();
2701 if (encoding().package() == Encoding::japanese)
2702 return lyxrc.default_platex_view_format;
2704 return lyxrc.default_otf_view_format;
2705 return lyxrc.default_view_format;
2708 Font const BufferParams::getFont() const
2710 FontInfo f = documentClass().defaultfont();
2711 if (fonts_default_family == "rmdefault")
2712 f.setFamily(ROMAN_FAMILY);
2713 else if (fonts_default_family == "sfdefault")
2714 f.setFamily(SANS_FAMILY);
2715 else if (fonts_default_family == "ttdefault")
2716 f.setFamily(TYPEWRITER_FAMILY);
2717 return Font(f, language);
2721 InsetQuotesParams::QuoteStyle BufferParams::getQuoteStyle(string const & qs) const
2723 return quotesstyletranslator().find(qs);
2727 bool BufferParams::isLatex() const
2729 return documentClass().outputType() == LATEX;
2733 bool BufferParams::isLiterate() const
2735 return documentClass().outputType() == LITERATE;
2739 bool BufferParams::isDocBook() const
2741 return documentClass().outputType() == DOCBOOK;
2745 void BufferParams::readPreamble(Lexer & lex)
2747 if (lex.getString() != "\\begin_preamble")
2748 lyxerr << "Error (BufferParams::readPreamble):"
2749 "consistency check failed." << endl;
2751 preamble = lex.getLongString(from_ascii("\\end_preamble"));
2755 void BufferParams::readLocalLayout(Lexer & lex, bool forced)
2757 string const expected = forced ? "\\begin_forced_local_layout" :
2758 "\\begin_local_layout";
2759 if (lex.getString() != expected)
2760 lyxerr << "Error (BufferParams::readLocalLayout):"
2761 "consistency check failed." << endl;
2764 forced_local_layout_ =
2765 lex.getLongString(from_ascii("\\end_forced_local_layout"));
2767 local_layout_ = lex.getLongString(from_ascii("\\end_local_layout"));
2771 bool BufferParams::setLanguage(string const & lang)
2773 Language const *new_language = languages.getLanguage(lang);
2774 if (!new_language) {
2775 // Language lang was not found
2778 language = new_language;
2783 void BufferParams::readLanguage(Lexer & lex)
2785 if (!lex.next()) return;
2787 string const tmptok = lex.getString();
2789 // check if tmptok is part of tex_babel in tex-defs.h
2790 if (!setLanguage(tmptok)) {
2791 // Language tmptok was not found
2792 language = default_language;
2793 lyxerr << "Warning: Setting language `"
2794 << tmptok << "' to `" << language->lang()
2800 void BufferParams::readGraphicsDriver(Lexer & lex)
2805 string const tmptok = lex.getString();
2806 // check if tmptok is part of tex_graphics in tex_defs.h
2809 string const test = tex_graphics[n++];
2811 if (test == tmptok) {
2812 graphics_driver = tmptok;
2817 "Warning: graphics driver `$$Token' not recognized!\n"
2818 " Setting graphics driver to `default'.\n");
2819 graphics_driver = "default";
2826 void BufferParams::readBullets(Lexer & lex)
2831 int const index = lex.getInteger();
2833 int temp_int = lex.getInteger();
2834 user_defined_bullet(index).setFont(temp_int);
2835 temp_bullet(index).setFont(temp_int);
2837 user_defined_bullet(index).setCharacter(temp_int);
2838 temp_bullet(index).setCharacter(temp_int);
2840 user_defined_bullet(index).setSize(temp_int);
2841 temp_bullet(index).setSize(temp_int);
2845 void BufferParams::readBulletsLaTeX(Lexer & lex)
2847 // The bullet class should be able to read this.
2850 int const index = lex.getInteger();
2852 docstring const temp_str = lex.getDocString();
2854 user_defined_bullet(index).setText(temp_str);
2855 temp_bullet(index).setText(temp_str);
2859 void BufferParams::readModules(Lexer & lex)
2861 if (!lex.eatLine()) {
2862 lyxerr << "Error (BufferParams::readModules):"
2863 "Unexpected end of input." << endl;
2867 string mod = lex.getString();
2868 if (mod == "\\end_modules")
2870 addLayoutModule(mod);
2876 void BufferParams::readRemovedModules(Lexer & lex)
2878 if (!lex.eatLine()) {
2879 lyxerr << "Error (BufferParams::readRemovedModules):"
2880 "Unexpected end of input." << endl;
2884 string mod = lex.getString();
2885 if (mod == "\\end_removed_modules")
2887 removed_modules_.push_back(mod);
2890 // now we want to remove any removed modules that were previously
2891 // added. normally, that will be because default modules were added in
2892 // setBaseClass(), which gets called when \textclass is read at the
2893 // start of the read.
2894 for (auto const & rm : removed_modules_) {
2895 LayoutModuleList::iterator const mit = layout_modules_.begin();
2896 LayoutModuleList::iterator const men = layout_modules_.end();
2897 LayoutModuleList::iterator found = find(mit, men, rm);
2900 layout_modules_.erase(found);
2905 void BufferParams::readIncludeonly(Lexer & lex)
2907 if (!lex.eatLine()) {
2908 lyxerr << "Error (BufferParams::readIncludeonly):"
2909 "Unexpected end of input." << endl;
2913 string child = lex.getString();
2914 if (child == "\\end_includeonly")
2916 included_children_.push_back(child);
2922 string BufferParams::paperSizeName(PapersizePurpose purpose, string const & psize) const
2924 PAPER_SIZE ppsize = psize.empty() ? papersize : papersizetranslator().find(psize);
2927 if (documentClass().pagesize() == "default")
2928 // could be anything, so don't guess
2930 return paperSizeName(purpose, documentClass().pagesize());
2931 case PAPER_CUSTOM: {
2932 if (purpose == XDVI && !paperwidth.empty() &&
2933 !paperheight.empty()) {
2934 // heightxwidth<unit>
2935 string first = paperwidth;
2936 string second = paperheight;
2937 if (orientation == ORIENTATION_LANDSCAPE)
2940 return first.erase(first.length() - 2)
2946 // dvips and dvipdfm do not know this
2947 if (purpose == DVIPS || purpose == DVIPDFM)
2951 if (purpose == DVIPS || purpose == DVIPDFM)
2955 if (purpose == DVIPS || purpose == DVIPDFM)
2965 if (purpose == DVIPS || purpose == DVIPDFM)
2969 if (purpose == DVIPS || purpose == DVIPDFM)
2973 if (purpose == DVIPS || purpose == DVIPDFM)
2977 if (purpose == DVIPS || purpose == DVIPDFM)
2981 if (purpose == DVIPS || purpose == DVIPDFM)
2985 // dvipdfm does not know this
2986 if (purpose == DVIPDFM)
2990 if (purpose == DVIPDFM)
2994 if (purpose == DVIPS || purpose == DVIPDFM)
2998 if (purpose == DVIPS || purpose == DVIPDFM)
3002 if (purpose == DVIPS || purpose == DVIPDFM)
3006 if (purpose == DVIPS || purpose == DVIPDFM)
3010 if (purpose == DVIPS || purpose == DVIPDFM)
3014 if (purpose == DVIPS || purpose == DVIPDFM)
3018 if (purpose == DVIPS || purpose == DVIPDFM)
3022 if (purpose == DVIPS || purpose == DVIPDFM)
3026 if (purpose == DVIPS || purpose == DVIPDFM)
3030 if (purpose == DVIPS || purpose == DVIPDFM)
3034 if (purpose == DVIPS || purpose == DVIPDFM)
3038 if (purpose == DVIPS || purpose == DVIPDFM)
3042 if (purpose == DVIPS || purpose == DVIPDFM)
3046 if (purpose == DVIPS || purpose == DVIPDFM)
3050 if (purpose == DVIPS || purpose == DVIPDFM)
3053 case PAPER_USEXECUTIVE:
3054 // dvipdfm does not know this
3055 if (purpose == DVIPDFM)
3060 case PAPER_USLETTER:
3062 if (purpose == XDVI)
3069 string const BufferParams::dvips_options() const
3073 // If the class loads the geometry package, we do not know which
3074 // paper size is used, since we do not set it (bug 7013).
3075 // Therefore we must not specify any argument here.
3076 // dvips gets the correct paper size via DVI specials in this case
3077 // (if the class uses the geometry package correctly).
3078 if (documentClass().provides("geometry"))
3082 && papersize == PAPER_CUSTOM
3083 && !lyxrc.print_paper_dimension_flag.empty()
3084 && !paperwidth.empty()
3085 && !paperheight.empty()) {
3086 // using a custom papersize
3087 result = lyxrc.print_paper_dimension_flag;
3088 result += ' ' + paperwidth;
3089 result += ',' + paperheight;
3091 string const paper_option = paperSizeName(DVIPS);
3092 if (!paper_option.empty() && (paper_option != "letter" ||
3093 orientation != ORIENTATION_LANDSCAPE)) {
3094 // dvips won't accept -t letter -t landscape.
3095 // In all other cases, include the paper size
3097 result = lyxrc.print_paper_flag;
3098 result += ' ' + paper_option;
3101 if (orientation == ORIENTATION_LANDSCAPE &&
3102 papersize != PAPER_CUSTOM)
3103 result += ' ' + lyxrc.print_landscape_flag;
3108 string const BufferParams::main_font_encoding() const
3110 if (font_encodings().empty()) {
3111 if (ascii_lowercase(language->fontenc(*this)) == "none")
3115 return font_encodings().back();
3119 vector<string> const BufferParams::font_encodings() const
3121 string doc_fontenc = (fontenc == "auto") ? string() : fontenc;
3123 vector<string> fontencs;
3125 // "default" means "no explicit font encoding"
3126 if (doc_fontenc != "default") {
3127 if (!doc_fontenc.empty())
3128 // If we have a custom setting, we use only that!
3129 return getVectorFromString(doc_fontenc);
3130 if (!language->fontenc(*this).empty()
3131 && ascii_lowercase(language->fontenc(*this)) != "none") {
3132 vector<string> fencs = getVectorFromString(language->fontenc(*this));
3133 for (auto & fe : fencs) {
3134 if (find(fontencs.begin(), fontencs.end(), fe) == fontencs.end())
3135 fontencs.push_back(fe);
3144 string BufferParams::babelCall(string const & lang_opts, bool const langoptions) const
3146 // suppress the babel call if there is no BabelName defined
3147 // for the document language in the lib/languages file and if no
3148 // other languages are used (lang_opts is then empty)
3149 if (lang_opts.empty())
3151 // The prefs may require the languages to
3152 // be submitted to babel itself (not the class).
3154 return "\\usepackage[" + lang_opts + "]{babel}";
3155 return "\\usepackage{babel}";
3159 docstring BufferParams::getGraphicsDriver(string const & package) const
3163 if (package == "geometry") {
3164 if (graphics_driver == "dvips"
3165 || graphics_driver == "dvipdfm"
3166 || graphics_driver == "pdftex"
3167 || graphics_driver == "vtex")
3168 result = from_ascii(graphics_driver);
3169 else if (graphics_driver == "dvipdfmx")
3170 result = from_ascii("dvipdfm");
3177 void BufferParams::writeEncodingPreamble(otexstream & os,
3178 LaTeXFeatures & features) const
3180 // With no-TeX fonts we use utf8-plain without encoding package.
3184 if (inputenc == "auto-legacy") {
3185 string const doc_encoding =
3186 language->encoding()->latexName();
3187 Encoding::Package const package =
3188 language->encoding()->package();
3190 // Create list of inputenc options:
3191 set<string> encoding_set;
3192 // luainputenc fails with more than one encoding
3193 if (features.runparams().flavor != OutputParams::LUATEX
3194 && features.runparams().flavor != OutputParams::DVILUATEX)
3195 // list all input encodings used in the document
3196 encoding_set = features.getEncodingSet(doc_encoding);
3198 // The "japanese" babel-language requires the pLaTeX engine
3199 // which conflicts with "inputenc".
3200 // See http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129680.html
3201 if ((!encoding_set.empty() || package == Encoding::inputenc)
3202 && !features.isRequired("japanese")
3203 && !features.isProvided("inputenc")) {
3204 os << "\\usepackage[";
3205 set<string>::const_iterator it = encoding_set.begin();
3206 set<string>::const_iterator const end = encoding_set.end();
3208 os << from_ascii(*it);
3211 for (; it != end; ++it)
3212 os << ',' << from_ascii(*it);
3213 if (package == Encoding::inputenc) {
3214 if (!encoding_set.empty())
3216 os << from_ascii(doc_encoding);
3218 if (features.runparams().flavor == OutputParams::LUATEX
3219 || features.runparams().flavor == OutputParams::DVILUATEX)
3220 os << "]{luainputenc}\n";
3222 os << "]{inputenc}\n";
3224 } else if (inputenc != "auto-legacy-plain") {
3225 switch (encoding().package()) {
3226 case Encoding::none:
3228 case Encoding::japanese:
3229 if (encoding().iconvName() != "UTF-8"
3230 && !features.runparams().isFullUnicode())
3231 // don't default to [utf8]{inputenc} with TeXLive >= 18
3232 os << "\\ifdefined\\UseRawInputEncoding\n"
3233 << " \\UseRawInputEncoding\\fi\n";
3235 case Encoding::inputenc:
3236 // do not load inputenc if japanese is used
3237 // or if the class provides inputenc
3238 if (features.isRequired("japanese")
3239 || features.isProvided("inputenc"))
3241 os << "\\usepackage[" << from_ascii(encoding().latexName());
3242 if (features.runparams().flavor == OutputParams::LUATEX
3243 || features.runparams().flavor == OutputParams::DVILUATEX)
3244 os << "]{luainputenc}\n";
3246 os << "]{inputenc}\n";
3250 if (inputenc == "auto-legacy-plain" || features.isRequired("japanese")) {
3251 // don't default to [utf8]{inputenc} with TeXLive >= 18
3252 os << "\\ifdefined\\UseRawInputEncoding\n";
3253 os << " \\UseRawInputEncoding\\fi\n";
3258 string const BufferParams::parseFontName(string const & name) const
3260 string mangled = name;
3261 size_t const idx = mangled.find('[');
3262 if (idx == string::npos || idx == 0)
3265 return mangled.substr(0, idx - 1);
3269 string const BufferParams::loadFonts(LaTeXFeatures & features) const
3271 if (fontsRoman() == "default" && fontsSans() == "default"
3272 && fontsTypewriter() == "default"
3273 && (fontsMath() == "default" || fontsMath() == "auto"))
3279 /* Fontspec (XeTeX, LuaTeX): we provide GUI support for oldstyle
3280 * numbers (Numbers=OldStyle) and sf/tt scaling. The Ligatures=TeX/
3281 * Mapping=tex-text option assures TeX ligatures (such as "--")
3282 * are resolved. Note that tt does not use these ligatures.
3284 * -- add more GUI options?
3285 * -- add more fonts (fonts for other scripts)
3286 * -- if there's a way to find out if a font really supports
3287 * OldStyle, enable/disable the widget accordingly.
3289 if (useNonTeXFonts && features.isAvailable("fontspec")) {
3290 // "Mapping=tex-text" and "Ligatures=TeX" are equivalent.
3291 // However, until v.2 (2010/07/11) fontspec only knew
3292 // Mapping=tex-text (for XeTeX only); then "Ligatures=TeX"
3293 // was introduced for both XeTeX and LuaTeX (LuaTeX
3294 // didn't understand "Mapping=tex-text", while XeTeX
3295 // understood both. With most recent versions, both
3296 // variants are understood by both engines. However,
3297 // we want to provide support for at least TeXLive 2009
3298 // (for XeTeX; LuaTeX is only supported as of v.2)
3299 // As of 2017/11/03, Babel has its own higher-level
3300 // interface on top of fontspec that is to be used.
3301 bool const babelfonts = features.useBabel()
3302 && features.isAvailable("babel-2017/11/03");
3303 string const texmapping =
3304 (features.runparams().flavor == OutputParams::XETEX) ?
3305 "Mapping=tex-text" : "Ligatures=TeX";
3306 if (fontsRoman() != "default") {
3308 os << "\\babelfont{rm}[";
3310 os << "\\setmainfont[";
3311 if (!font_roman_opts.empty())
3312 os << font_roman_opts << ',';
3314 if (fonts_roman_osf)
3315 os << ",Numbers=OldStyle";
3316 os << "]{" << parseFontName(fontsRoman()) << "}\n";
3318 if (fontsSans() != "default") {
3319 string const sans = parseFontName(fontsSans());
3320 if (fontsSansScale() != 100) {
3322 os << "\\babelfont{sf}";
3324 os << "\\setsansfont";
3326 << float(fontsSansScale()) / 100 << ',';
3328 os << "Numbers=OldStyle,";
3329 if (!font_sans_opts.empty())
3330 os << font_sans_opts << ',';
3331 os << texmapping << "]{"
3335 os << "\\babelfont{sf}[";
3337 os << "\\setsansfont[";
3339 os << "Numbers=OldStyle,";
3340 if (!font_sans_opts.empty())
3341 os << font_sans_opts << ',';
3342 os << texmapping << "]{"
3346 if (fontsTypewriter() != "default") {
3347 string const mono = parseFontName(fontsTypewriter());
3348 if (fontsTypewriterScale() != 100) {
3350 os << "\\babelfont{tt}";
3352 os << "\\setmonofont";
3354 << float(fontsTypewriterScale()) / 100;
3355 if (fonts_typewriter_osf)
3356 os << ",Numbers=OldStyle";
3357 if (!font_typewriter_opts.empty())
3358 os << ',' << font_typewriter_opts;
3363 os << "\\babelfont{tt}";
3365 os << "\\setmonofont";
3366 if (!font_typewriter_opts.empty() || fonts_typewriter_osf) {
3368 if (fonts_typewriter_osf)
3369 os << "Numbers=OldStyle";
3370 if (!font_typewriter_opts.empty()) {
3371 if (fonts_typewriter_osf)
3373 os << font_typewriter_opts;
3377 os << '{' << mono << "}\n";
3384 bool const ot1 = (main_font_encoding() == "default" || main_font_encoding() == "OT1");
3385 bool const dryrun = features.runparams().dryrun;
3386 bool const complete = (fontsSans() == "default" && fontsTypewriter() == "default");
3387 bool const nomath = (fontsMath() == "default");
3390 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsRoman())).getLaTeXCode(
3391 dryrun, ot1, complete, fonts_expert_sc, fonts_roman_osf,
3392 nomath, font_roman_opts);
3395 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsSans())).getLaTeXCode(
3396 dryrun, ot1, complete, fonts_expert_sc, fonts_sans_osf,
3397 nomath, font_sans_opts, fontsSansScale());
3399 // MONOSPACED/TYPEWRITER
3400 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsTypewriter())).getLaTeXCode(
3401 dryrun, ot1, complete, fonts_expert_sc, fonts_typewriter_osf,
3402 nomath, font_typewriter_opts, fontsTypewriterScale());
3405 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsMath())).getLaTeXCode(
3406 dryrun, ot1, complete, fonts_expert_sc, fonts_roman_osf,
3413 Encoding const & BufferParams::encoding() const
3415 // Main encoding for LaTeX output.
3417 return *(encodings.fromLyXName("utf8-plain"));
3418 if (inputenc == "auto-legacy" || inputenc == "auto-legacy-plain")
3419 return *language->encoding();
3420 if (inputenc == "utf8" && language->lang() == "japanese")
3421 return *(encodings.fromLyXName("utf8-platex"));
3422 Encoding const * const enc = encodings.fromLyXName(inputenc);
3425 LYXERR0("Unknown inputenc value `" << inputenc
3426 << "'. Using `auto' instead.");
3427 return *language->encoding();
3431 string const & BufferParams::defaultBiblioStyle() const
3433 if (!biblio_style.empty())
3434 return biblio_style;
3436 map<string, string> const & bs = documentClass().defaultBiblioStyle();
3437 auto cit = bs.find(theCiteEnginesList.getTypeAsString(citeEngineType()));
3438 if (cit != bs.end())
3441 return empty_string();
3445 bool const & BufferParams::fullAuthorList() const
3447 return documentClass().fullAuthorList();
3451 string BufferParams::getCiteAlias(string const & s) const
3453 vector<string> commands =
3454 documentClass().citeCommands(citeEngineType());
3455 // If it is a real command, don't treat it as an alias
3456 if (find(commands.begin(), commands.end(), s) != commands.end())
3458 map<string,string> aliases = documentClass().citeCommandAliases();
3459 if (aliases.find(s) != aliases.end())
3465 vector<string> BufferParams::citeCommands() const
3467 static CitationStyle const default_style;
3468 vector<string> commands =
3469 documentClass().citeCommands(citeEngineType());
3470 if (commands.empty())
3471 commands.push_back(default_style.name);
3476 vector<CitationStyle> BufferParams::citeStyles() const
3478 static CitationStyle const default_style;
3479 vector<CitationStyle> styles =
3480 documentClass().citeStyles(citeEngineType());
3482 styles.push_back(default_style);
3487 string const BufferParams::bibtexCommand() const
3489 // Return document-specific setting if available
3490 if (bibtex_command != "default")
3491 return bibtex_command;
3493 // If we have "default" in document settings, consult the prefs
3494 // 1. Japanese (uses a specific processor)
3495 if (encoding().package() == Encoding::japanese) {
3496 if (lyxrc.jbibtex_command != "automatic")
3497 // Return the specified program, if "automatic" is not set
3498 return lyxrc.jbibtex_command;
3499 else if (!useBiblatex()) {
3500 // With classic BibTeX, return pbibtex, jbibtex, bibtex
3501 if (lyxrc.jbibtex_alternatives.find("pbibtex") != lyxrc.jbibtex_alternatives.end())
3503 if (lyxrc.jbibtex_alternatives.find("jbibtex") != lyxrc.jbibtex_alternatives.end())
3508 // 2. All other languages
3509 else if (lyxrc.bibtex_command != "automatic")
3510 // Return the specified program, if "automatic" is not set
3511 return lyxrc.bibtex_command;
3513 // 3. Automatic: find the most suitable for the current cite framework
3514 if (useBiblatex()) {
3515 // For Biblatex, we prefer biber (also for Japanese)
3516 // and fall back to bibtex8 and, as last resort, bibtex
3517 if (lyxrc.bibtex_alternatives.find("biber") != lyxrc.bibtex_alternatives.end())
3519 else if (lyxrc.bibtex_alternatives.find("bibtex8") != lyxrc.bibtex_alternatives.end())
3526 bool BufferParams::useBiblatex() const
3528 return theCiteEnginesList[citeEngine()]->getCiteFramework() == "biblatex";
3532 void BufferParams::invalidateConverterCache() const
3534 pimpl_->isExportCacheValid = false;
3535 pimpl_->isViewCacheValid = false;
3539 // We shouldn't need to reset the params here, since anything
3540 // we need will be recopied.
3541 void BufferParams::copyForAdvFR(const BufferParams & bp)
3543 string const & lang = bp.language->lang();
3545 layout_modules_ = bp.layout_modules_;
3546 string const & doc_class = bp.documentClass().name();
3547 setBaseClass(doc_class);
3551 void BufferParams::setBibFileEncoding(string const & file, string const & enc)
3553 bib_encodings[file] = enc;
3557 string const BufferParams::bibFileEncoding(string const & file) const
3559 if (bib_encodings.find(file) == bib_encodings.end())
3561 return bib_encodings.find(file)->second;