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"
32 #include "IndicesList.h"
34 #include "LaTeXFeatures.h"
35 #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/Length.h"
58 #include "support/Messages.h"
59 #include "support/mutex.h"
60 #include "support/Package.h"
61 #include "support/Translator.h"
62 #include "support/lstrings.h"
68 using namespace lyx::support;
71 static char const * const string_paragraph_separation[] = {
76 static char const * const string_quotes_style[] = {
77 "english", "swedish", "german", "polish", "swiss", "danish", "plain",
78 "british", "swedishg", "french", "frenchin", "russian", "cjk", "cjkangle", ""
82 static char const * const string_papersize[] = {
83 "default", "custom", "letter", "legal", "executive",
84 "a0", "a1", "a2", "a3", "a4", "a5", "a6",
85 "b0", "b1", "b2", "b3", "b4", "b5", "b6",
86 "c0", "c1", "c2", "c3", "c4", "c5", "c6",
87 "b0j", "b1j", "b2j", "b3j", "b4j", "b5j", "b6j", ""
91 static char const * const string_papersize_geometry[] = {
92 "default", "custom", "letterpaper", "legalpaper", "executivepaper",
93 "a0paper", "a1paper", "a2paper", "a3paper", "a4paper", "a5paper", "a6paper",
94 "b0paper", "b1paper", "b2paper", "b3paper", "b4paper", "b5paper", "b6paper",
95 "c0paper", "c1paper", "c2paper", "c3paper", "c4paper", "c5paper", "c6paper",
96 "b0j", "b1j", "b2j", "b3j", "b4j", "b5j", "b6j", ""
100 static char const * const string_orientation[] = {
101 "portrait", "landscape", ""
105 static char const * const tex_graphics[] = {
106 "default", "dvialw", "dvilaser", "dvipdf", "dvipdfm", "dvipdfmx",
107 "dvips", "dvipsone", "dvitops", "dviwin", "dviwindo", "dvi2ps", "emtex",
108 "ln", "oztex", "pctexhp", "pctexps", "pctexwin", "pctex32", "pdftex",
109 "psprint", "pubps", "tcidvi", "textures", "truetex", "vtex", "xdvi",
119 // Paragraph separation
120 typedef Translator<string, BufferParams::ParagraphSeparation> ParSepTranslator;
123 ParSepTranslator const init_parseptranslator()
125 ParSepTranslator translator
126 (string_paragraph_separation[0], BufferParams::ParagraphIndentSeparation);
127 translator.addPair(string_paragraph_separation[1], BufferParams::ParagraphSkipSeparation);
132 ParSepTranslator const & parseptranslator()
134 static ParSepTranslator const translator =
135 init_parseptranslator();
141 typedef Translator<string, InsetQuotesParams::QuoteStyle> QuotesStyleTranslator;
144 QuotesStyleTranslator const init_quotesstyletranslator()
146 QuotesStyleTranslator translator
147 (string_quotes_style[0], InsetQuotesParams::EnglishQuotes);
148 translator.addPair(string_quotes_style[1], InsetQuotesParams::SwedishQuotes);
149 translator.addPair(string_quotes_style[2], InsetQuotesParams::GermanQuotes);
150 translator.addPair(string_quotes_style[3], InsetQuotesParams::PolishQuotes);
151 translator.addPair(string_quotes_style[4], InsetQuotesParams::SwissQuotes);
152 translator.addPair(string_quotes_style[5], InsetQuotesParams::DanishQuotes);
153 translator.addPair(string_quotes_style[6], InsetQuotesParams::PlainQuotes);
154 translator.addPair(string_quotes_style[7], InsetQuotesParams::BritishQuotes);
155 translator.addPair(string_quotes_style[8], InsetQuotesParams::SwedishGQuotes);
156 translator.addPair(string_quotes_style[9], InsetQuotesParams::FrenchQuotes);
157 translator.addPair(string_quotes_style[10], InsetQuotesParams::FrenchINQuotes);
158 translator.addPair(string_quotes_style[11], InsetQuotesParams::RussianQuotes);
159 translator.addPair(string_quotes_style[12], InsetQuotesParams::CJKQuotes);
160 translator.addPair(string_quotes_style[13], InsetQuotesParams::CJKAngleQuotes);
165 QuotesStyleTranslator const & quotesstyletranslator()
167 static QuotesStyleTranslator const translator =
168 init_quotesstyletranslator();
174 typedef Translator<string, PAPER_SIZE> PaperSizeTranslator;
177 static PaperSizeTranslator initPaperSizeTranslator()
179 PaperSizeTranslator translator(string_papersize[0], PAPER_DEFAULT);
180 translator.addPair(string_papersize[1], PAPER_CUSTOM);
181 translator.addPair(string_papersize[2], PAPER_USLETTER);
182 translator.addPair(string_papersize[3], PAPER_USLEGAL);
183 translator.addPair(string_papersize[4], PAPER_USEXECUTIVE);
184 translator.addPair(string_papersize[5], PAPER_A0);
185 translator.addPair(string_papersize[6], PAPER_A1);
186 translator.addPair(string_papersize[7], PAPER_A2);
187 translator.addPair(string_papersize[8], PAPER_A3);
188 translator.addPair(string_papersize[9], PAPER_A4);
189 translator.addPair(string_papersize[10], PAPER_A5);
190 translator.addPair(string_papersize[11], PAPER_A6);
191 translator.addPair(string_papersize[12], PAPER_B0);
192 translator.addPair(string_papersize[13], PAPER_B1);
193 translator.addPair(string_papersize[14], PAPER_B2);
194 translator.addPair(string_papersize[15], PAPER_B3);
195 translator.addPair(string_papersize[16], PAPER_B4);
196 translator.addPair(string_papersize[17], PAPER_B5);
197 translator.addPair(string_papersize[18], PAPER_B6);
198 translator.addPair(string_papersize[19], PAPER_C0);
199 translator.addPair(string_papersize[20], PAPER_C1);
200 translator.addPair(string_papersize[21], PAPER_C2);
201 translator.addPair(string_papersize[22], PAPER_C3);
202 translator.addPair(string_papersize[23], PAPER_C4);
203 translator.addPair(string_papersize[24], PAPER_C5);
204 translator.addPair(string_papersize[25], PAPER_C6);
205 translator.addPair(string_papersize[26], PAPER_JISB0);
206 translator.addPair(string_papersize[27], PAPER_JISB1);
207 translator.addPair(string_papersize[28], PAPER_JISB2);
208 translator.addPair(string_papersize[29], PAPER_JISB3);
209 translator.addPair(string_papersize[30], PAPER_JISB4);
210 translator.addPair(string_papersize[31], PAPER_JISB5);
211 translator.addPair(string_papersize[32], PAPER_JISB6);
216 PaperSizeTranslator const & papersizetranslator()
218 static PaperSizeTranslator const translator =
219 initPaperSizeTranslator();
225 typedef Translator<string, PAPER_ORIENTATION> PaperOrientationTranslator;
228 PaperOrientationTranslator const init_paperorientationtranslator()
230 PaperOrientationTranslator translator(string_orientation[0], ORIENTATION_PORTRAIT);
231 translator.addPair(string_orientation[1], ORIENTATION_LANDSCAPE);
236 PaperOrientationTranslator const & paperorientationtranslator()
238 static PaperOrientationTranslator const translator =
239 init_paperorientationtranslator();
245 typedef Translator<int, PageSides> SidesTranslator;
248 SidesTranslator const init_sidestranslator()
250 SidesTranslator translator(1, OneSide);
251 translator.addPair(2, TwoSides);
256 SidesTranslator const & sidestranslator()
258 static SidesTranslator const translator = init_sidestranslator();
264 typedef Translator<int, BufferParams::Package> PackageTranslator;
267 PackageTranslator const init_packagetranslator()
269 PackageTranslator translator(0, BufferParams::package_off);
270 translator.addPair(1, BufferParams::package_auto);
271 translator.addPair(2, BufferParams::package_on);
276 PackageTranslator const & packagetranslator()
278 static PackageTranslator const translator =
279 init_packagetranslator();
285 typedef Translator<string, Spacing::Space> SpaceTranslator;
288 SpaceTranslator const init_spacetranslator()
290 SpaceTranslator translator("default", Spacing::Default);
291 translator.addPair("single", Spacing::Single);
292 translator.addPair("onehalf", Spacing::Onehalf);
293 translator.addPair("double", Spacing::Double);
294 translator.addPair("other", Spacing::Other);
299 SpaceTranslator const & spacetranslator()
301 static SpaceTranslator const translator = init_spacetranslator();
306 bool inSystemDir(FileName const & document_dir, string & system_dir)
308 // A document is assumed to be in a system LyX directory (not
309 // necessarily the system directory of the running instance)
310 // if both "configure.py" and "chkconfig.ltx" are found in
311 // either document_dir/../ or document_dir/../../.
312 // If true, the system directory path is returned in system_dir
313 // with a trailing path separator.
315 string const msg = "Checking whether document is in a system dir...";
317 string dir = document_dir.absFileName();
319 for (int i = 0; i < 3; ++i) {
320 dir = addPath(dir, "..");
321 if (!fileSearch(dir, "configure.py").empty() &&
322 !fileSearch(dir, "chkconfig.ltx").empty()) {
323 LYXERR(Debug::FILES, msg << " yes");
324 system_dir = addPath(FileName(dir).realPath(), "");
329 LYXERR(Debug::FILES, msg << " no");
330 system_dir = string();
337 class BufferParams::Impl
342 AuthorList authorlist;
343 BranchList branchlist;
344 Bullet temp_bullets[4];
345 Bullet user_defined_bullets[4];
346 IndicesList indiceslist;
350 /** This is the amount of space used for paragraph_separation "skip",
351 * and for detached paragraphs in "indented" documents.
354 PDFOptions pdfoptions;
355 LayoutFileIndex baseClass_;
356 FormatList exportableFormatList;
357 FormatList viewableFormatList;
358 bool isViewCacheValid;
359 bool isExportCacheValid;
363 BufferParams::Impl::Impl()
364 : defskip(VSpace::MEDSKIP), baseClass_(string("")),
365 isViewCacheValid(false), isExportCacheValid(false)
367 // set initial author
369 authorlist.record(Author(from_utf8(lyxrc.user_name),
370 from_utf8(lyxrc.user_email),
371 from_utf8(lyxrc.user_initials)));
376 BufferParams::MemoryTraits::clone(BufferParams::Impl const * ptr)
379 return new BufferParams::Impl(*ptr);
383 void BufferParams::MemoryTraits::destroy(BufferParams::Impl * ptr)
389 BufferParams::BufferParams()
392 setBaseClass(defaultBaseclass());
393 cite_engine_ = "basic";
394 cite_engine_type_ = ENGINE_TYPE_DEFAULT;
396 paragraph_separation = ParagraphIndentSeparation;
397 is_math_indent = false;
398 math_numbering_side = DEFAULT;
399 quotes_style = InsetQuotesParams::EnglishQuotes;
400 dynamic_quotes = false;
401 fontsize = "default";
404 papersize = PAPER_DEFAULT;
405 orientation = ORIENTATION_PORTRAIT;
406 use_geometry = false;
407 biblio_style = string();
408 use_bibtopic = false;
411 save_transient_properties = true;
412 track_changes = false;
413 output_changes = false;
415 postpone_fragile_content = true;
416 use_default_options = true;
417 maintain_unincluded_children = CM_None;
420 language = default_language;
422 fonts_roman[0] = "default";
423 fonts_roman[1] = "default";
424 fonts_sans[0] = "default";
425 fonts_sans[1] = "default";
426 fonts_typewriter[0] = "default";
427 fonts_typewriter[1] = "default";
428 fonts_math[0] = "auto";
429 fonts_math[1] = "auto";
430 fonts_default_family = "default";
431 useNonTeXFonts = false;
432 use_microtype = false;
433 use_dash_ligatures = true;
434 fonts_expert_sc = false;
435 fonts_roman_osf = false;
436 fonts_sans_osf = false;
437 fonts_typewriter_osf = false;
438 fonts_sans_scale[0] = 100;
439 fonts_sans_scale[1] = 100;
440 fonts_typewriter_scale[0] = 100;
441 fonts_typewriter_scale[1] = 100;
443 lang_package = "default";
444 graphics_driver = "default";
445 default_output_format = "default";
446 bibtex_command = "default";
447 index_command = "default";
450 listings_params = string();
451 pagestyle = "default";
452 tablestyle = "default";
453 float_alignment = "class";
454 float_placement = "class";
455 suppress_date = false;
456 justification = true;
457 // no color is the default (white)
458 backgroundcolor = lyx::rgbFromHexName("#ffffff");
459 isbackgroundcolor = false;
460 // no color is the default (black)
461 fontcolor = lyx::rgbFromHexName("#000000");
463 // light gray is the default font color for greyed-out notes
464 notefontcolor = lyx::rgbFromHexName("#cccccc");
465 boxbgcolor = lyx::rgbFromHexName("#ff0000");
466 compressed = lyxrc.save_compressed;
467 for (int iter = 0; iter < 4; ++iter) {
468 user_defined_bullet(iter) = ITEMIZE_DEFAULTS[iter];
469 temp_bullet(iter) = ITEMIZE_DEFAULTS[iter];
472 indiceslist().addDefault(B_("Index"));
473 html_be_strict = false;
474 html_math_output = MathML;
475 html_math_img_scale = 1.0;
476 html_css_as_file = false;
477 docbook_table_output = HTMLTable;
478 display_pixel_ratio = 1.0;
480 shell_escape = false;
486 // map current author
487 author_map_[pimpl_->authorlist.get(0).bufferId()] = 0;
491 docstring BufferParams::B_(string const & l10n) const
493 LASSERT(language, return from_utf8(l10n));
494 return getMessages(language->code()).get(l10n);
498 BufferParams::Package BufferParams::use_package(std::string const & p) const
500 PackageMap::const_iterator it = use_packages.find(p);
501 if (it == use_packages.end())
507 void BufferParams::use_package(std::string const & p, BufferParams::Package u)
513 map<string, string> const & BufferParams::auto_packages()
515 static map<string, string> packages;
516 if (packages.empty()) {
517 // We could have a race condition here that two threads
518 // discover an empty map at the same time and want to fill
519 // it, but that is no problem, since the same contents is
520 // filled in twice then. Having the locker inside the
521 // packages.empty() condition has the advantage that we
522 // don't need the mutex overhead for simple reading.
524 Mutex::Locker locker(&mutex);
525 // adding a package here implies a file format change!
526 packages["amsmath"] =
527 N_("The LaTeX package amsmath is only used if AMS formula types or symbols from the AMS math toolbars are inserted into formulas");
528 packages["amssymb"] =
529 N_("The LaTeX package amssymb is only used if symbols from the AMS math toolbars are inserted into formulas");
531 N_("The LaTeX package cancel is only used if \\cancel commands are used in formulas");
533 N_("The LaTeX package esint is only used if special integral symbols are inserted into formulas");
534 packages["mathdots"] =
535 N_("The LaTeX package mathdots is only used if the command \\iddots is inserted into formulas");
536 packages["mathtools"] =
537 N_("The LaTeX package mathtools is only used if some mathematical relations are inserted into formulas");
539 N_("The LaTeX package mhchem is only used if either the command \\ce or \\cf is inserted into formulas");
540 packages["stackrel"] =
541 N_("The LaTeX package stackrel is only used if the command \\stackrel with subscript is inserted into formulas");
542 packages["stmaryrd"] =
543 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");
544 packages["undertilde"] =
545 N_("The LaTeX package undertilde is only used if you use the math frame decoration 'utilde'");
551 bool BufferParams::useBibtopic() const
555 return (use_bibtopic || (!multibib.empty() && multibib != "child"));
559 AuthorList & BufferParams::authors()
561 return pimpl_->authorlist;
565 AuthorList const & BufferParams::authors() const
567 return pimpl_->authorlist;
571 void BufferParams::addAuthor(Author const & a)
573 author_map_[a.bufferId()] = pimpl_->authorlist.record(a);
577 BranchList & BufferParams::branchlist()
579 return pimpl_->branchlist;
583 BranchList const & BufferParams::branchlist() const
585 return pimpl_->branchlist;
589 IndicesList & BufferParams::indiceslist()
591 return pimpl_->indiceslist;
595 IndicesList const & BufferParams::indiceslist() const
597 return pimpl_->indiceslist;
601 Bullet & BufferParams::temp_bullet(lyx::size_type const index)
603 LASSERT(index < 4, return pimpl_->temp_bullets[0]);
604 return pimpl_->temp_bullets[index];
608 Bullet const & BufferParams::temp_bullet(lyx::size_type const index) const
610 LASSERT(index < 4, return pimpl_->temp_bullets[0]);
611 return pimpl_->temp_bullets[index];
615 Bullet & BufferParams::user_defined_bullet(lyx::size_type const index)
617 LASSERT(index < 4, return pimpl_->temp_bullets[0]);
618 return pimpl_->user_defined_bullets[index];
622 Bullet const & BufferParams::user_defined_bullet(lyx::size_type const index) const
624 LASSERT(index < 4, return pimpl_->temp_bullets[0]);
625 return pimpl_->user_defined_bullets[index];
629 Spacing & BufferParams::spacing()
631 return pimpl_->spacing;
635 Spacing const & BufferParams::spacing() const
637 return pimpl_->spacing;
641 PDFOptions & BufferParams::pdfoptions()
643 return pimpl_->pdfoptions;
647 PDFOptions const & BufferParams::pdfoptions() const
649 return pimpl_->pdfoptions;
653 Length const & BufferParams::getMathIndent() const
655 return pimpl_->mathindent;
659 void BufferParams::setMathIndent(Length const & indent)
661 pimpl_->mathindent = indent;
665 Length const & BufferParams::getParIndent() const
667 return pimpl_->parindent;
671 void BufferParams::setParIndent(Length const & indent)
673 pimpl_->parindent = indent;
677 VSpace const & BufferParams::getDefSkip() const
679 return pimpl_->defskip;
683 void BufferParams::setDefSkip(VSpace const & vs)
685 // DEFSKIP will cause an infinite loop
686 LASSERT(vs.kind() != VSpace::DEFSKIP, return);
687 pimpl_->defskip = vs;
691 BufferParams::MathNumber BufferParams::getMathNumber() const
693 if (math_numbering_side != DEFAULT)
694 return math_numbering_side;
695 // FIXME: do not hardcode language here
696 else if (language->lang() == "arabic_arabi"
697 || documentClass().provides("leqno"))
704 string BufferParams::readToken(Lexer & lex, string const & token,
705 FileName const & filepath)
709 if (token == "\\textclass") {
711 string const classname = lex.getString();
712 // if there exists a local layout file, ignore the system one
713 // NOTE: in this case, the textclass (.cls file) is assumed to
716 LayoutFileList & bcl = LayoutFileList::get();
717 if (!filepath.empty()) {
718 // If classname is an absolute path, the document is
719 // using a local layout file which could not be accessed
720 // by a relative path. In this case the path is correct
721 // even if the document was moved to a different
722 // location. However, we will have a problem if the
723 // document was generated on a different platform.
724 bool isabsolute = FileName::isAbsolute(classname);
725 string const classpath = onlyPath(classname);
726 string const path = isabsolute ? classpath
727 : FileName(addPath(filepath.absFileName(),
728 classpath)).realPath();
729 string const oldpath = isabsolute ? string()
730 : FileName(addPath(origin, classpath)).realPath();
731 tcp = bcl.addLocalLayout(onlyFileName(classname), path, oldpath);
733 // that returns non-empty if a "local" layout file is found.
735 result = to_utf8(makeRelPath(from_utf8(onlyPath(tcp)),
736 from_utf8(filepath.absFileName())));
739 setBaseClass(onlyFileName(tcp));
741 setBaseClass(onlyFileName(classname));
742 // We assume that a tex class exists for local or unknown
743 // layouts so this warning, will only be given for system layouts.
744 if (!baseClass()->isTeXClassAvailable()) {
745 docstring const desc =
746 translateIfPossible(from_utf8(baseClass()->description()));
747 docstring const prereqs =
748 from_utf8(baseClass()->prerequisites());
749 docstring const msg =
750 bformat(_("The selected document class\n"
752 "requires external files that are not available.\n"
753 "The document class can still be used, but the\n"
754 "document cannot be compiled until the following\n"
755 "prerequisites are installed:\n"
757 "See section 3.1.2.2 (Class Availability) of the\n"
758 "User's Guide for more information."), desc, prereqs);
759 frontend::Alert::warning(_("Document class not available"),
762 } else if (token == "\\save_transient_properties") {
763 lex >> save_transient_properties;
764 } else if (token == "\\origin") {
766 origin = lex.getString();
767 string const sysdirprefix = "/systemlyxdir/";
768 if (prefixIs(origin, sysdirprefix)) {
770 if (inSystemDir(filepath, docsys))
771 origin.replace(0, sysdirprefix.length() - 1, docsys);
773 origin.replace(0, sysdirprefix.length() - 1,
774 package().system_support().absFileName());
776 } else if (token == "\\begin_preamble") {
778 } else if (token == "\\begin_local_layout") {
779 readLocalLayout(lex, false);
780 } else if (token == "\\begin_forced_local_layout") {
781 readLocalLayout(lex, true);
782 } else if (token == "\\begin_modules") {
784 } else if (token == "\\begin_removed_modules") {
785 readRemovedModules(lex);
786 } else if (token == "\\begin_includeonly") {
787 readIncludeonly(lex);
788 } else if (token == "\\maintain_unincluded_children") {
792 maintain_unincluded_children = CM_None;
793 else if (tmp == "mostly")
794 maintain_unincluded_children = CM_Mostly;
795 else if (tmp == "strict")
796 maintain_unincluded_children = CM_Strict;
797 } else if (token == "\\options") {
799 options = lex.getString();
800 } else if (token == "\\use_default_options") {
801 lex >> use_default_options;
802 } else if (token == "\\master") {
804 master = lex.getString();
805 if (!filepath.empty() && FileName::isAbsolute(origin)) {
806 bool const isabs = FileName::isAbsolute(master);
807 FileName const abspath(isabs ? master : origin + master);
808 bool const moved = filepath != FileName(origin);
809 if (moved && abspath.exists()) {
810 docstring const path = isabs
812 : from_utf8(abspath.realPath());
813 docstring const refpath =
814 from_utf8(filepath.absFileName());
815 master = to_utf8(makeRelPath(path, refpath));
818 } else if (token == "\\suppress_date") {
819 lex >> suppress_date;
820 } else if (token == "\\justification") {
821 lex >> justification;
822 } else if (token == "\\language") {
824 } else if (token == "\\language_package") {
826 lang_package = lex.getString();
827 } else if (token == "\\inputencoding") {
829 } else if (token == "\\graphics") {
830 readGraphicsDriver(lex);
831 } else if (token == "\\default_output_format") {
832 lex >> default_output_format;
833 } else if (token == "\\bibtex_command") {
835 bibtex_command = lex.getString();
836 } else if (token == "\\index_command") {
838 index_command = lex.getString();
839 } else if (token == "\\fontencoding") {
841 fontenc = lex.getString();
842 } else if (token == "\\font_roman") {
843 lex >> fonts_roman[0];
844 lex >> fonts_roman[1];
845 } else if (token == "\\font_sans") {
846 lex >> fonts_sans[0];
847 lex >> fonts_sans[1];
848 } else if (token == "\\font_typewriter") {
849 lex >> fonts_typewriter[0];
850 lex >> fonts_typewriter[1];
851 } else if (token == "\\font_math") {
852 lex >> fonts_math[0];
853 lex >> fonts_math[1];
854 } else if (token == "\\font_default_family") {
855 lex >> fonts_default_family;
856 } else if (token == "\\use_non_tex_fonts") {
857 lex >> useNonTeXFonts;
858 } else if (token == "\\font_sc") {
859 lex >> fonts_expert_sc;
860 } else if (token == "\\font_roman_osf") {
861 lex >> fonts_roman_osf;
862 } else if (token == "\\font_sans_osf") {
863 lex >> fonts_sans_osf;
864 } else if (token == "\\font_typewriter_osf") {
865 lex >> fonts_typewriter_osf;
866 } else if (token == "\\font_roman_opts") {
867 lex >> font_roman_opts;
868 } else if (token == "\\font_sf_scale") {
869 lex >> fonts_sans_scale[0];
870 lex >> fonts_sans_scale[1];
871 } else if (token == "\\font_sans_opts") {
872 lex >> font_sans_opts;
873 } else if (token == "\\font_tt_scale") {
874 lex >> fonts_typewriter_scale[0];
875 lex >> fonts_typewriter_scale[1];
876 } else if (token == "\\font_typewriter_opts") {
877 lex >> font_typewriter_opts;
878 } else if (token == "\\font_cjk") {
880 } else if (token == "\\use_microtype") {
881 lex >> use_microtype;
882 } else if (token == "\\use_dash_ligatures") {
883 lex >> use_dash_ligatures;
884 } else if (token == "\\paragraph_separation") {
887 paragraph_separation = parseptranslator().find(parsep);
888 } else if (token == "\\paragraph_indentation") {
890 string parindent = lex.getString();
891 if (parindent == "default")
892 pimpl_->parindent = Length();
894 pimpl_->parindent = Length(parindent);
895 } else if (token == "\\defskip") {
897 string const defskip = lex.getString();
898 pimpl_->defskip = VSpace(defskip);
899 if (pimpl_->defskip.kind() == VSpace::DEFSKIP)
901 pimpl_->defskip = VSpace(VSpace::MEDSKIP);
902 } else if (token == "\\is_math_indent") {
903 lex >> is_math_indent;
904 } else if (token == "\\math_indentation") {
906 string mathindent = lex.getString();
907 if (mathindent == "default")
908 pimpl_->mathindent = Length();
910 pimpl_->mathindent = Length(mathindent);
911 } else if (token == "\\math_numbering_side") {
915 math_numbering_side = LEFT;
916 else if (tmp == "right")
917 math_numbering_side = RIGHT;
919 math_numbering_side = DEFAULT;
920 } else if (token == "\\quotes_style") {
923 quotes_style = quotesstyletranslator().find(qstyle);
924 } else if (token == "\\dynamic_quotes") {
925 lex >> dynamic_quotes;
926 } else if (token == "\\papersize") {
929 papersize = papersizetranslator().find(ppsize);
930 } else if (token == "\\use_geometry") {
932 } else if (token == "\\use_package") {
937 use_package(package, packagetranslator().find(use));
938 } else if (token == "\\cite_engine") {
940 cite_engine_ = lex.getString();
941 } else if (token == "\\cite_engine_type") {
944 cite_engine_type_ = theCiteEnginesList.getType(engine_type);
945 } else if (token == "\\biblio_style") {
947 biblio_style = lex.getString();
948 } else if (token == "\\biblio_options") {
950 biblio_opts = trim(lex.getString());
951 } else if (token == "\\biblatex_bibstyle") {
953 biblatex_bibstyle = trim(lex.getString());
954 } else if (token == "\\biblatex_citestyle") {
956 biblatex_citestyle = trim(lex.getString());
957 } else if (token == "\\use_bibtopic") {
959 } else if (token == "\\multibib") {
961 } else if (token == "\\use_indices") {
963 } else if (token == "\\tracking_changes") {
964 lex >> track_changes;
965 } else if (token == "\\output_changes") {
966 lex >> output_changes;
967 } else if (token == "\\change_bars") {
969 } else if (token == "\\postpone_fragile_content") {
970 lex >> postpone_fragile_content;
971 } else if (token == "\\branch") {
973 docstring branch = lex.getDocString();
974 branchlist().add(branch);
977 string const tok = lex.getString();
978 if (tok == "\\end_branch")
980 Branch * branch_ptr = branchlist().find(branch);
981 if (tok == "\\selected") {
984 branch_ptr->setSelected(lex.getInteger());
986 if (tok == "\\filename_suffix") {
989 branch_ptr->setFileNameSuffix(lex.getInteger());
991 if (tok == "\\color") {
993 string color = lex.getString();
995 branch_ptr->setColor(color);
996 // Update also the Color table:
998 color = lcolor.getX11HexName(Color_background);
1000 lcolor.setColor(to_utf8(branch), color);
1003 } else if (token == "\\index") {
1005 docstring index = lex.getDocString();
1007 indiceslist().add(index);
1010 string const tok = lex.getString();
1011 if (tok == "\\end_index")
1013 Index * index_ptr = indiceslist().find(index);
1014 if (tok == "\\shortcut") {
1016 shortcut = lex.getDocString();
1018 index_ptr->setShortcut(shortcut);
1020 if (tok == "\\color") {
1022 string color = lex.getString();
1024 index_ptr->setColor(color);
1025 // Update also the Color table:
1026 if (color == "none")
1027 color = lcolor.getX11HexName(Color_background);
1029 if (!shortcut.empty())
1030 lcolor.setColor(to_utf8(shortcut), color);
1033 } else if (token == "\\author") {
1035 istringstream ss(lex.getString());
1039 } else if (token == "\\paperorientation") {
1042 orientation = paperorientationtranslator().find(orient);
1043 } else if (token == "\\backgroundcolor") {
1045 backgroundcolor = lyx::rgbFromHexName(lex.getString());
1046 isbackgroundcolor = true;
1047 } else if (token == "\\fontcolor") {
1049 fontcolor = lyx::rgbFromHexName(lex.getString());
1051 } else if (token == "\\notefontcolor") {
1053 string color = lex.getString();
1054 notefontcolor = lyx::rgbFromHexName(color);
1055 lcolor.setColor("notefontcolor", color);
1056 } else if (token == "\\boxbgcolor") {
1058 string color = lex.getString();
1059 boxbgcolor = lyx::rgbFromHexName(color);
1060 lcolor.setColor("boxbgcolor", color);
1061 } else if (token == "\\paperwidth") {
1063 } else if (token == "\\paperheight") {
1065 } else if (token == "\\leftmargin") {
1067 } else if (token == "\\topmargin") {
1069 } else if (token == "\\rightmargin") {
1071 } else if (token == "\\bottommargin") {
1072 lex >> bottommargin;
1073 } else if (token == "\\headheight") {
1075 } else if (token == "\\headsep") {
1077 } else if (token == "\\footskip") {
1079 } else if (token == "\\columnsep") {
1081 } else if (token == "\\paperfontsize") {
1083 } else if (token == "\\papercolumns") {
1085 } else if (token == "\\listings_params") {
1088 listings_params = InsetListingsParams(par).params();
1089 } else if (token == "\\papersides") {
1092 sides = sidestranslator().find(psides);
1093 } else if (token == "\\paperpagestyle") {
1095 } else if (token == "\\tablestyle") {
1097 } else if (token == "\\bullet") {
1099 } else if (token == "\\bulletLaTeX") {
1100 readBulletsLaTeX(lex);
1101 } else if (token == "\\secnumdepth") {
1103 } else if (token == "\\tocdepth") {
1105 } else if (token == "\\spacing") {
1109 if (nspacing == "other") {
1112 spacing().set(spacetranslator().find(nspacing), tmp_val);
1113 } else if (token == "\\float_placement") {
1114 lex >> float_placement;
1115 } else if (token == "\\float_alignment") {
1116 lex >> float_alignment;
1118 } else if (prefixIs(token, "\\pdf_") || token == "\\use_hyperref") {
1119 string toktmp = pdfoptions().readToken(lex, token);
1120 if (!toktmp.empty()) {
1121 lyxerr << "PDFOptions::readToken(): Unknown token: " <<
1125 } else if (token == "\\html_math_output") {
1128 html_math_output = static_cast<MathOutput>(temp);
1129 } else if (token == "\\html_be_strict") {
1130 lex >> html_be_strict;
1131 } else if (token == "\\html_css_as_file") {
1132 lex >> html_css_as_file;
1133 } else if (token == "\\html_math_img_scale") {
1134 lex >> html_math_img_scale;
1135 } else if (token == "\\html_latex_start") {
1137 html_latex_start = lex.getString();
1138 } else if (token == "\\html_latex_end") {
1140 html_latex_end = lex.getString();
1141 } else if (token == "\\docbook_table_output") {
1144 docbook_table_output = static_cast<TableOutput>(temp);
1145 } else if (token == "\\output_sync") {
1147 } else if (token == "\\output_sync_macro") {
1148 lex >> output_sync_macro;
1149 } else if (token == "\\use_refstyle") {
1150 lex >> use_refstyle;
1151 } else if (token == "\\use_minted") {
1153 } else if (token == "\\use_lineno") {
1155 } else if (token == "\\lineno_options") {
1157 lineno_opts = trim(lex.getString());
1159 lyxerr << "BufferParams::readToken(): Unknown token: " <<
1169 // Quote argument if it contains spaces
1170 string quoteIfNeeded(string const & str) {
1171 if (contains(str, ' '))
1172 return "\"" + str + "\"";
1178 void BufferParams::writeFile(ostream & os, Buffer const * buf) const
1180 // The top of the file is written by the buffer.
1181 // Prints out the buffer info into the .lyx file given by file
1183 os << "\\save_transient_properties "
1184 << convert<string>(save_transient_properties) << '\n';
1186 // the document directory (must end with a path separator)
1187 // realPath() is used to resolve symlinks, while addPath(..., "")
1188 // ensures a trailing path separator.
1190 string filepath = addPath(buf->fileName().onlyPath().realPath(), "");
1191 string const sysdir = inSystemDir(FileName(filepath), docsys) ? docsys
1192 : addPath(package().system_support().realPath(), "");
1193 string const relpath =
1194 to_utf8(makeRelPath(from_utf8(filepath), from_utf8(sysdir)));
1195 if (!prefixIs(relpath, "../") && !FileName::isAbsolute(relpath))
1196 filepath = addPath("/systemlyxdir", relpath);
1197 else if (!save_transient_properties || !lyxrc.save_origin)
1198 filepath = "unavailable";
1199 os << "\\origin " << quoteIfNeeded(filepath) << '\n';
1202 os << "\\textclass "
1203 << quoteIfNeeded(buf->includedFilePath(addName(buf->layoutPos(),
1204 baseClass()->name()), "layout"))
1207 // then the preamble
1208 if (!preamble.empty()) {
1209 // remove '\n' from the end of preamble
1210 docstring const tmppreamble = rtrim(preamble, "\n");
1211 os << "\\begin_preamble\n"
1212 << to_utf8(tmppreamble)
1213 << "\n\\end_preamble\n";
1217 if (!options.empty()) {
1218 os << "\\options " << options << '\n';
1221 // use the class options defined in the layout?
1222 os << "\\use_default_options "
1223 << convert<string>(use_default_options) << "\n";
1225 // the master document
1226 if (!master.empty()) {
1227 os << "\\master " << master << '\n';
1231 if (!removed_modules_.empty()) {
1232 os << "\\begin_removed_modules" << '\n';
1233 for (auto const & mod : removed_modules_)
1235 os << "\\end_removed_modules" << '\n';
1239 if (!layout_modules_.empty()) {
1240 os << "\\begin_modules" << '\n';
1241 for (auto const & mod : layout_modules_)
1243 os << "\\end_modules" << '\n';
1247 if (!included_children_.empty()) {
1248 os << "\\begin_includeonly" << '\n';
1249 for (auto const & c : included_children_)
1251 os << "\\end_includeonly" << '\n';
1254 switch (maintain_unincluded_children) {
1265 os << "\\maintain_unincluded_children " << muc << '\n';
1267 // local layout information
1268 docstring const local_layout = getLocalLayout(false);
1269 if (!local_layout.empty()) {
1270 // remove '\n' from the end
1271 docstring const tmplocal = rtrim(local_layout, "\n");
1272 os << "\\begin_local_layout\n"
1273 << to_utf8(tmplocal)
1274 << "\n\\end_local_layout\n";
1276 docstring const forced_local_layout = getLocalLayout(true);
1277 if (!forced_local_layout.empty()) {
1278 // remove '\n' from the end
1279 docstring const tmplocal = rtrim(forced_local_layout, "\n");
1280 os << "\\begin_forced_local_layout\n"
1281 << to_utf8(tmplocal)
1282 << "\n\\end_forced_local_layout\n";
1285 // then the text parameters
1286 if (language != ignore_language)
1287 os << "\\language " << language->lang() << '\n';
1288 os << "\\language_package " << lang_package
1289 << "\n\\inputencoding " << inputenc
1290 << "\n\\fontencoding " << fontenc
1291 << "\n\\font_roman \"" << fonts_roman[0]
1292 << "\" \"" << fonts_roman[1] << '"'
1293 << "\n\\font_sans \"" << fonts_sans[0]
1294 << "\" \"" << fonts_sans[1] << '"'
1295 << "\n\\font_typewriter \"" << fonts_typewriter[0]
1296 << "\" \"" << fonts_typewriter[1] << '"'
1297 << "\n\\font_math \"" << fonts_math[0]
1298 << "\" \"" << fonts_math[1] << '"'
1299 << "\n\\font_default_family " << fonts_default_family
1300 << "\n\\use_non_tex_fonts " << convert<string>(useNonTeXFonts)
1301 << "\n\\font_sc " << convert<string>(fonts_expert_sc)
1302 << "\n\\font_roman_osf " << convert<string>(fonts_roman_osf)
1303 << "\n\\font_sans_osf " << convert<string>(fonts_sans_osf)
1304 << "\n\\font_typewriter_osf " << convert<string>(fonts_typewriter_osf);
1305 if (!font_roman_opts.empty())
1306 os << "\n\\font_roman_opts \"" << font_roman_opts << "\"";
1307 os << "\n\\font_sf_scale " << fonts_sans_scale[0]
1308 << ' ' << fonts_sans_scale[1];
1309 if (!font_sans_opts.empty())
1310 os << "\n\\font_sans_opts \"" << font_sans_opts << "\"";
1311 os << "\n\\font_tt_scale " << fonts_typewriter_scale[0]
1312 << ' ' << fonts_typewriter_scale[1];
1313 if (!font_typewriter_opts.empty())
1314 os << "\n\\font_typewriter_opts \"" << font_typewriter_opts << "\"";
1316 if (!fonts_cjk.empty())
1317 os << "\\font_cjk " << fonts_cjk << '\n';
1318 os << "\\use_microtype " << convert<string>(use_microtype) << '\n';
1319 os << "\\use_dash_ligatures " << convert<string>(use_dash_ligatures) << '\n';
1320 os << "\\graphics " << graphics_driver << '\n';
1321 os << "\\default_output_format " << default_output_format << '\n';
1322 os << "\\output_sync " << output_sync << '\n';
1323 if (!output_sync_macro.empty())
1324 os << "\\output_sync_macro \"" << output_sync_macro << "\"\n";
1325 os << "\\bibtex_command " << bibtex_command << '\n';
1326 os << "\\index_command " << index_command << '\n';
1328 if (!float_placement.empty())
1329 os << "\\float_placement " << float_placement << '\n';
1330 if (!float_alignment.empty())
1331 os << "\\float_alignment " << float_alignment << '\n';
1332 os << "\\paperfontsize " << fontsize << '\n';
1334 spacing().writeFile(os);
1335 pdfoptions().writeFile(os);
1337 os << "\\papersize " << string_papersize[papersize]
1338 << "\n\\use_geometry " << convert<string>(use_geometry);
1339 map<string, string> const & packages = auto_packages();
1340 for (auto const & pack : packages)
1341 os << "\n\\use_package " << pack.first << ' '
1342 << use_package(pack.first);
1344 os << "\n\\cite_engine ";
1346 if (!cite_engine_.empty())
1351 os << "\n\\cite_engine_type " << theCiteEnginesList.getTypeAsString(cite_engine_type_);
1353 if (!biblio_style.empty())
1354 os << "\n\\biblio_style " << biblio_style;
1355 if (!biblio_opts.empty())
1356 os << "\n\\biblio_options " << biblio_opts;
1357 if (!biblatex_bibstyle.empty())
1358 os << "\n\\biblatex_bibstyle " << biblatex_bibstyle;
1359 if (!biblatex_citestyle.empty())
1360 os << "\n\\biblatex_citestyle " << biblatex_citestyle;
1361 if (!multibib.empty())
1362 os << "\n\\multibib " << multibib;
1364 os << "\n\\use_bibtopic " << convert<string>(use_bibtopic)
1365 << "\n\\use_indices " << convert<string>(use_indices)
1366 << "\n\\paperorientation " << string_orientation[orientation]
1367 << "\n\\suppress_date " << convert<string>(suppress_date)
1368 << "\n\\justification " << convert<string>(justification)
1369 << "\n\\use_refstyle " << use_refstyle
1370 << "\n\\use_minted " << use_minted
1371 << "\n\\use_lineno " << use_lineno
1374 if (!lineno_opts.empty())
1375 os << "\\lineno_options " << lineno_opts << '\n';
1377 if (isbackgroundcolor)
1378 os << "\\backgroundcolor " << lyx::X11hexname(backgroundcolor) << '\n';
1380 os << "\\fontcolor " << lyx::X11hexname(fontcolor) << '\n';
1381 if (notefontcolor != lyx::rgbFromHexName("#cccccc"))
1382 os << "\\notefontcolor " << lyx::X11hexname(notefontcolor) << '\n';
1383 if (boxbgcolor != lyx::rgbFromHexName("#ff0000"))
1384 os << "\\boxbgcolor " << lyx::X11hexname(boxbgcolor) << '\n';
1386 for (auto const & br : branchlist()) {
1387 os << "\\branch " << to_utf8(br.branch())
1388 << "\n\\selected " << br.isSelected()
1389 << "\n\\filename_suffix " << br.hasFileNameSuffix()
1390 << "\n\\color " << lyx::X11hexname(br.color())
1395 for (auto const & id : indiceslist()) {
1396 os << "\\index " << to_utf8(id.index())
1397 << "\n\\shortcut " << to_utf8(id.shortcut())
1398 << "\n\\color " << lyx::X11hexname(id.color())
1403 if (!paperwidth.empty())
1404 os << "\\paperwidth "
1405 << VSpace(paperwidth).asLyXCommand() << '\n';
1406 if (!paperheight.empty())
1407 os << "\\paperheight "
1408 << VSpace(paperheight).asLyXCommand() << '\n';
1409 if (!leftmargin.empty())
1410 os << "\\leftmargin "
1411 << VSpace(leftmargin).asLyXCommand() << '\n';
1412 if (!topmargin.empty())
1413 os << "\\topmargin "
1414 << VSpace(topmargin).asLyXCommand() << '\n';
1415 if (!rightmargin.empty())
1416 os << "\\rightmargin "
1417 << VSpace(rightmargin).asLyXCommand() << '\n';
1418 if (!bottommargin.empty())
1419 os << "\\bottommargin "
1420 << VSpace(bottommargin).asLyXCommand() << '\n';
1421 if (!headheight.empty())
1422 os << "\\headheight "
1423 << VSpace(headheight).asLyXCommand() << '\n';
1424 if (!headsep.empty())
1426 << VSpace(headsep).asLyXCommand() << '\n';
1427 if (!footskip.empty())
1429 << VSpace(footskip).asLyXCommand() << '\n';
1430 if (!columnsep.empty())
1431 os << "\\columnsep "
1432 << VSpace(columnsep).asLyXCommand() << '\n';
1433 os << "\\secnumdepth " << secnumdepth
1434 << "\n\\tocdepth " << tocdepth
1435 << "\n\\paragraph_separation "
1436 << string_paragraph_separation[paragraph_separation];
1437 if (!paragraph_separation)
1438 os << "\n\\paragraph_indentation "
1439 << (getParIndent().empty() ? "default" : getParIndent().asString());
1441 os << "\n\\defskip " << getDefSkip().asLyXCommand();
1442 os << "\n\\is_math_indent " << is_math_indent;
1444 os << "\n\\math_indentation "
1445 << (getMathIndent().empty() ? "default" : getMathIndent().asString());
1446 os << "\n\\math_numbering_side ";
1447 switch(math_numbering_side) {
1457 os << "\n\\quotes_style "
1458 << string_quotes_style[quotes_style]
1459 << "\n\\dynamic_quotes " << dynamic_quotes
1460 << "\n\\papercolumns " << columns
1461 << "\n\\papersides " << sides
1462 << "\n\\paperpagestyle " << pagestyle
1463 << "\n\\tablestyle " << tablestyle << '\n';
1464 if (!listings_params.empty())
1465 os << "\\listings_params \"" <<
1466 InsetListingsParams(listings_params).encodedString() << "\"\n";
1467 for (int i = 0; i < 4; ++i) {
1468 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
1469 if (user_defined_bullet(i).getFont() != -1) {
1470 os << "\\bullet " << i << " "
1471 << user_defined_bullet(i).getFont() << " "
1472 << user_defined_bullet(i).getCharacter() << " "
1473 << user_defined_bullet(i).getSize() << "\n";
1477 os << "\\bulletLaTeX " << i << " \""
1478 << lyx::to_ascii(user_defined_bullet(i).getText())
1484 os << "\\tracking_changes "
1485 << (save_transient_properties ? convert<string>(track_changes) : "false")
1488 os << "\\output_changes "
1489 << (save_transient_properties ? convert<string>(output_changes) : "false")
1492 os << "\\change_bars "
1493 << (save_transient_properties ? convert<string>(change_bars) : "false")
1496 os << "\\postpone_fragile_content " << convert<string>(postpone_fragile_content) << '\n';
1498 os << "\\html_math_output " << html_math_output << '\n'
1499 << "\\html_css_as_file " << html_css_as_file << '\n'
1500 << "\\html_be_strict " << convert<string>(html_be_strict) << '\n';
1502 os << "\\docbook_table_output " << docbook_table_output << '\n';
1504 if (html_math_img_scale != 1.0)
1505 os << "\\html_math_img_scale " << convert<string>(html_math_img_scale) << '\n';
1506 if (!html_latex_start.empty())
1507 os << "\\html_latex_start " << html_latex_start << '\n';
1508 if (!html_latex_end.empty())
1509 os << "\\html_latex_end " << html_latex_end << '\n';
1511 os << pimpl_->authorlist;
1515 void BufferParams::validate(LaTeXFeatures & features) const
1517 features.require(documentClass().required());
1519 if (columns > 1 && language->rightToLeft())
1520 features.require("rtloutputdblcol");
1522 if (output_changes) {
1523 bool xcolorulem = LaTeXFeatures::isAvailable("ulem") &&
1524 LaTeXFeatures::isAvailable("xcolor");
1526 switch (features.runparams().flavor) {
1527 case OutputParams::LATEX:
1528 case OutputParams::DVILUATEX:
1530 features.require("ct-xcolor-ulem");
1531 features.require("ulem");
1532 features.require("xcolor");
1534 features.require("ct-none");
1537 case OutputParams::LUATEX:
1538 case OutputParams::PDFLATEX:
1539 case OutputParams::XETEX:
1541 features.require("ct-xcolor-ulem");
1542 features.require("ulem");
1543 features.require("xcolor");
1544 // improves color handling in PDF output
1545 features.require("pdfcolmk");
1547 features.require("ct-none");
1554 features.require("changebar");
1557 // Floats with 'Here definitely' as default setting.
1558 if (float_placement.find('H') != string::npos)
1559 features.require("float");
1561 for (auto const & pm : use_packages) {
1562 if (pm.first == "amsmath") {
1563 // AMS Style is at document level
1564 if (pm.second == package_on ||
1565 features.isProvided("amsmath"))
1566 features.require(pm.first);
1567 } else if (pm.second == package_on)
1568 features.require(pm.first);
1571 // Document-level line spacing
1572 if (spacing().getSpace() != Spacing::Single && !spacing().isDefault())
1573 features.require("setspace");
1575 // the bullet shapes are buffer level not paragraph level
1576 // so they are tested here
1577 for (int i = 0; i < 4; ++i) {
1578 if (user_defined_bullet(i) == ITEMIZE_DEFAULTS[i])
1580 int const font = user_defined_bullet(i).getFont();
1582 int const c = user_defined_bullet(i).getCharacter();
1588 features.require("latexsym");
1590 } else if (font == 1) {
1591 features.require("amssymb");
1592 } else if (font >= 2 && font <= 5) {
1593 features.require("pifont");
1597 if (pdfoptions().use_hyperref) {
1598 features.require("hyperref");
1599 // due to interferences with babel and hyperref, the color package has to
1600 // be loaded after hyperref when hyperref is used with the colorlinks
1601 // option, see http://www.lyx.org/trac/ticket/5291
1602 if (pdfoptions().colorlinks)
1603 features.require("color");
1605 if (!listings_params.empty()) {
1606 // do not test validity because listings_params is
1607 // supposed to be valid
1609 InsetListingsParams(listings_params).separatedParams(true);
1610 // we can't support all packages, but we should load the color package
1611 if (par.find("\\color", 0) != string::npos)
1612 features.require("color");
1615 // some languages are only available via polyglossia
1616 if (features.hasPolyglossiaExclusiveLanguages())
1617 features.require("polyglossia");
1619 if (useNonTeXFonts && fontsMath() != "auto")
1620 features.require("unicode-math");
1623 features.require("microtype");
1625 if (!language->required().empty())
1626 features.require(language->required());
1630 bool BufferParams::writeLaTeX(otexstream & os, LaTeXFeatures & features,
1631 FileName const & filepath) const
1633 // http://www.tug.org/texmf-dist/doc/latex/base/fixltx2e.pdf
1634 // !! To use the Fix-cm package, load it before \documentclass, and use the command
1635 // \RequirePackage to do so, rather than the normal \usepackage
1636 // Do not try to load any other package before the document class, unless you
1637 // have a thorough understanding of the LATEX internals and know exactly what you
1639 if (features.mustProvide("fix-cm"))
1640 os << "\\RequirePackage{fix-cm}\n";
1641 // Likewise for fixltx2e. If other packages conflict with this policy,
1642 // treat it as a package bug (and report it!)
1643 // See http://www.latex-project.org/cgi-bin/ltxbugs2html?pr=latex/4407
1644 if (features.mustProvide("fixltx2e"))
1645 os << "\\RequirePackage{fixltx2e}\n";
1647 os << "\\documentclass";
1649 DocumentClass const & tclass = documentClass();
1651 ostringstream clsoptions; // the document class options.
1653 if (tokenPos(tclass.opt_fontsize(),
1654 '|', fontsize) >= 0) {
1655 // only write if existing in list (and not default)
1656 clsoptions << subst(tclass.fontsizeformat(), "$$s", fontsize) << ",";
1659 // paper sizes not supported by the class itself need the
1661 vector<string> classpsizes = getVectorFromString(tclass.opt_pagesize(), "|");
1662 bool class_supported_papersize = papersize == PAPER_DEFAULT
1663 || find(classpsizes.begin(), classpsizes.end(), string_papersize[papersize]) != classpsizes.end();
1665 if ((!use_geometry || features.isProvided("geometry-light"))
1666 && class_supported_papersize && papersize != PAPER_DEFAULT)
1667 clsoptions << subst(tclass.pagesizeformat(), "$$s", string_papersize[papersize]) << ",";
1670 if (sides != tclass.sides()) {
1673 clsoptions << "oneside,";
1676 clsoptions << "twoside,";
1682 if (columns != tclass.columns()) {
1684 clsoptions << "twocolumn,";
1686 clsoptions << "onecolumn,";
1690 && orientation == ORIENTATION_LANDSCAPE)
1691 clsoptions << "landscape,";
1694 clsoptions << "fleqn,";
1696 switch(math_numbering_side) {
1698 clsoptions << "leqno,";
1701 clsoptions << "reqno,";
1702 features.require("amsmath");
1708 // language should be a parameter to \documentclass
1709 if (language->babel() == "hebrew"
1710 && default_language->babel() != "hebrew")
1711 // This seems necessary
1712 features.useLanguage(default_language);
1714 ostringstream language_options;
1715 bool const use_babel = features.useBabel() && !features.isProvided("babel");
1716 bool const use_polyglossia = features.usePolyglossia();
1717 bool const global = lyxrc.language_global_options;
1718 if (features.useBabel() || (use_polyglossia && global)) {
1719 language_options << features.getBabelLanguages();
1720 if (!language->babel().empty()) {
1721 if (!language_options.str().empty())
1722 language_options << ',';
1723 language_options << language->babel();
1725 if (global && !language_options.str().empty())
1726 clsoptions << language_options.str() << ',';
1729 // the predefined options from the layout
1730 if (use_default_options && !tclass.options().empty())
1731 clsoptions << tclass.options() << ',';
1733 // the user-defined options
1734 if (!options.empty()) {
1735 clsoptions << options << ',';
1738 docstring const strOptions = from_utf8(clsoptions.str());
1739 if (!strOptions.empty()) {
1740 // Check if class options contain uncodable glyphs
1741 docstring uncodable_glyphs;
1742 docstring options_encodable;
1743 Encoding const * const enc = features.runparams().encoding;
1745 for (char_type c : strOptions) {
1746 if (!enc->encodable(c)) {
1747 docstring const glyph(1, c);
1748 LYXERR0("Uncodable character '"
1750 << "' in class options!");
1751 uncodable_glyphs += glyph;
1752 if (features.runparams().dryrun) {
1753 options_encodable += "<" + _("LyX Warning: ")
1754 + _("uncodable character") + " '";
1755 options_encodable += c;
1756 options_encodable += "'>";
1759 options_encodable += c;
1762 options_encodable = strOptions;
1764 // On BUFFER_VIEW|UPDATE, warn user if we found uncodable glyphs
1765 if (!features.runparams().dryrun && !uncodable_glyphs.empty()) {
1766 frontend::Alert::warning(
1767 _("Uncodable character in class options"),
1769 _("The class options of your document contain glyphs "
1770 "that are unknown in the current document encoding "
1771 "(namely %1$s).\nThese glyphs are omitted "
1772 " from the output, which may result in "
1773 "incomplete output."
1774 "\n\nPlease select an appropriate "
1775 "document encoding\n"
1776 "(such as utf8) or change the "
1777 "class options accordingly."),
1780 options_encodable = rtrim(options_encodable, ",");
1781 os << '[' << options_encodable << ']';
1784 os << '{' << from_ascii(tclass.latexname()) << "}\n";
1785 // end of \documentclass defs
1787 // The package options (via \PassOptionsToPackage)
1788 os << from_ascii(features.getPackageOptions());
1790 // if we use fontspec or newtxmath, we have to load the AMS packages here
1791 string const ams = features.loadAMSPackages();
1792 bool const ot1 = (main_font_encoding() == "default" || main_font_encoding() == "OT1");
1793 bool const use_newtxmath =
1794 theLaTeXFonts().getLaTeXFont(from_ascii(fontsMath())).getUsedPackage(
1795 ot1, false, false) == "newtxmath";
1796 if ((useNonTeXFonts || use_newtxmath) && !ams.empty())
1797 os << from_ascii(ams);
1799 if (useNonTeXFonts) {
1800 // Babel (as of 2017/11/03) loads fontspec itself
1801 if (!features.isProvided("fontspec")
1802 && !(features.useBabel() && features.isAvailable("babel-2017/11/03")))
1803 os << "\\usepackage{fontspec}\n";
1804 if (features.mustProvide("unicode-math")
1805 && features.isAvailable("unicode-math"))
1806 os << "\\usepackage{unicode-math}\n";
1809 // load CJK support package before font selection
1810 // (see autotests/export/latex/CJK/micro-sign_utf8-cjk-libertine.lyx)
1811 if (!useNonTeXFonts && encoding().package() != Encoding::none && inputenc != "utf8x"
1812 && (encoding().package() == Encoding::CJK || features.mustProvide("CJK"))) {
1813 if (inputenc == "utf8-cjk" || inputenc == "utf8")
1814 os << "\\usepackage{CJKutf8}\n";
1816 os << "\\usepackage[encapsulated]{CJK}\n";
1819 // font selection must be done before loading fontenc.sty
1820 // but after babel with non-TeX fonts
1821 string const fonts = loadFonts(features);
1822 if (!fonts.empty() && (!features.useBabel() || !useNonTeXFonts))
1823 os << from_utf8(fonts);
1825 if (fonts_default_family != "default")
1826 os << "\\renewcommand{\\familydefault}{\\"
1827 << from_ascii(fonts_default_family) << "}\n";
1829 // set font encoding
1830 // non-TeX fonts use font encoding TU (set by fontspec)
1831 if (!useNonTeXFonts && !features.isProvided("fontenc")
1832 && main_font_encoding() != "default") {
1833 // get main font encodings
1834 vector<string> fontencs = font_encodings();
1835 // get font encodings of secondary languages
1836 // FIXME: some languages (hebrew, ...) assume a standard font encoding as last
1837 // option (for text in other languages).
1838 features.getFontEncodings(fontencs);
1839 if (!fontencs.empty()) {
1840 os << "\\usepackage["
1841 << from_ascii(getStringFromVector(fontencs))
1846 // Load textcomp and pmboxdraw before (lua)inputenc (#11454)
1847 if (features.mustProvide("textcomp"))
1848 os << "\\usepackage{textcomp}\n";
1849 if (features.mustProvide("pmboxdraw"))
1850 os << "\\usepackage{pmboxdraw}\n";
1852 // handle inputenc etc.
1853 // (In documents containing text in Thai language,
1854 // we must load inputenc after babel, see lib/languages).
1855 if (!contains(features.getBabelPostsettings(), from_ascii("thai.ldf")))
1856 writeEncodingPreamble(os, features);
1859 if (!features.runparams().includeall && !included_children_.empty()) {
1860 os << "\\includeonly{";
1862 for (auto incfile : included_children_) {
1863 FileName inc = makeAbsPath(incfile, filepath.absFileName());
1864 string mangled = DocFileName(changeExtension(inc.absFileName(), ".tex")).
1866 if (!features.runparams().nice)
1868 // \includeonly doesn't want an extension
1869 incfile = changeExtension(incfile, string());
1870 incfile = support::latex_path(incfile);
1871 if (!incfile.empty()) {
1874 os << from_utf8(incfile);
1881 if (!features.isProvided("geometry")
1882 && (use_geometry || !class_supported_papersize)) {
1883 odocstringstream ods;
1884 if (!getGraphicsDriver("geometry").empty())
1885 ods << getGraphicsDriver("geometry");
1886 if (orientation == ORIENTATION_LANDSCAPE)
1887 ods << ",landscape";
1888 switch (papersize) {
1890 if (!paperwidth.empty())
1891 ods << ",paperwidth="
1892 << from_ascii(paperwidth);
1893 if (!paperheight.empty())
1894 ods << ",paperheight="
1895 << from_ascii(paperheight);
1897 case PAPER_USLETTER:
1899 case PAPER_USEXECUTIVE:
1928 ods << "," << from_ascii(string_papersize_geometry[papersize]);
1933 docstring g_options = trim(ods.str(), ",");
1934 os << "\\usepackage";
1935 // geometry-light means that the class works with geometry, but overwrites
1936 // the package options and paper sizes (memoir does this).
1937 // In this case, all options need to go to \geometry
1938 // and the standard paper sizes need to go to the class options.
1939 if (!g_options.empty() && !features.isProvided("geometry-light")) {
1940 os << '[' << g_options << ']';
1943 os << "{geometry}\n";
1944 if (use_geometry || features.isProvided("geometry-light")) {
1945 os << "\\geometry{verbose";
1946 if (!g_options.empty())
1947 // Output general options here with "geometry light".
1948 os << "," << g_options;
1949 // output this only if use_geometry is true
1951 if (!topmargin.empty())
1952 os << ",tmargin=" << from_ascii(Length(topmargin).asLatexString());
1953 if (!bottommargin.empty())
1954 os << ",bmargin=" << from_ascii(Length(bottommargin).asLatexString());
1955 if (!leftmargin.empty())
1956 os << ",lmargin=" << from_ascii(Length(leftmargin).asLatexString());
1957 if (!rightmargin.empty())
1958 os << ",rmargin=" << from_ascii(Length(rightmargin).asLatexString());
1959 if (!headheight.empty())
1960 os << ",headheight=" << from_ascii(Length(headheight).asLatexString());
1961 if (!headsep.empty())
1962 os << ",headsep=" << from_ascii(Length(headsep).asLatexString());
1963 if (!footskip.empty())
1964 os << ",footskip=" << from_ascii(Length(footskip).asLatexString());
1965 if (!columnsep.empty())
1966 os << ",columnsep=" << from_ascii(Length(columnsep).asLatexString());
1970 } else if (orientation == ORIENTATION_LANDSCAPE
1971 || papersize != PAPER_DEFAULT) {
1972 features.require("papersize");
1975 if (tokenPos(tclass.opt_pagestyle(), '|', pagestyle) >= 0) {
1976 if (pagestyle == "fancy")
1977 os << "\\usepackage{fancyhdr}\n";
1978 os << "\\pagestyle{" << from_ascii(pagestyle) << "}\n";
1981 // only output when the background color is not default
1982 if (isbackgroundcolor) {
1983 // only require color here, the background color will be defined
1984 // in LaTeXFeatures.cpp to avoid interferences with the LaTeX
1986 features.require("color");
1987 features.require("pagecolor");
1990 // only output when the font color is not default
1992 // only require color here, the font color will be defined
1993 // in LaTeXFeatures.cpp to avoid interferences with the LaTeX
1995 features.require("color");
1996 features.require("fontcolor");
1999 // Only if class has a ToC hierarchy
2000 if (tclass.hasTocLevels()) {
2001 if (secnumdepth != tclass.secnumdepth()) {
2002 os << "\\setcounter{secnumdepth}{"
2006 if (tocdepth != tclass.tocdepth()) {
2007 os << "\\setcounter{tocdepth}{"
2013 if (paragraph_separation) {
2014 // when skip separation
2016 switch (getDefSkip().kind()) {
2017 case VSpace::SMALLSKIP:
2018 psopt = "\\smallskipamount";
2020 case VSpace::MEDSKIP:
2021 psopt = "\\medskipamount";
2023 case VSpace::BIGSKIP:
2024 psopt = "\\bigskipamount";
2026 case VSpace::HALFLINE:
2027 // default (no option)
2029 case VSpace::FULLLINE:
2030 psopt = "\\baselineskip";
2032 case VSpace::LENGTH:
2033 psopt = getDefSkip().length().asLatexString();
2038 if (!features.isProvided("parskip")) {
2040 psopt = "[skip=" + psopt + "]";
2041 os << "\\usepackage" + psopt + "{parskip}\n";
2043 os << "\\setlength{\\parskip}{" + psopt + "}\n";
2046 // when separation by indentation
2047 // only output something when a width is given
2048 if (!getParIndent().empty()) {
2049 os << "\\setlength{\\parindent}{"
2050 << from_utf8(getParIndent().asLatexString())
2055 if (is_math_indent) {
2056 // when formula indentation
2057 // only output something when it is not the default
2058 if (!getMathIndent().empty()) {
2059 os << "\\setlength{\\mathindent}{"
2060 << from_utf8(getMathIndent().asString())
2065 // Now insert the LyX specific LaTeX commands...
2066 features.resolveAlternatives();
2067 features.expandMultiples();
2070 if (!output_sync_macro.empty())
2071 os << from_utf8(output_sync_macro) +"\n";
2072 else if (features.runparams().flavor == OutputParams::LATEX)
2073 os << "\\usepackage[active]{srcltx}\n";
2074 else if (features.runparams().flavor == OutputParams::PDFLATEX)
2075 os << "\\synctex=-1\n";
2078 // due to interferences with babel and hyperref, the color package has to
2079 // be loaded (when it is not already loaded) before babel when hyperref
2080 // is used with the colorlinks option, see
2081 // http://www.lyx.org/trac/ticket/5291
2082 // we decided therefore to load color always before babel, see
2083 // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg144349.html
2084 os << from_ascii(features.getColorOptions());
2086 // If we use hyperref, jurabib, japanese or varioref,
2087 // we have to call babel before
2089 && (features.isRequired("jurabib")
2090 || features.isRequired("hyperref")
2091 || features.isRequired("varioref")
2092 || features.isRequired("japanese"))) {
2093 os << features.getBabelPresettings();
2095 os << from_utf8(babelCall(language_options.str(),
2096 !lyxrc.language_global_options)) + '\n';
2097 os << features.getBabelPostsettings();
2100 // The optional packages;
2101 os << from_ascii(features.getPackages());
2103 // Additional Indices
2104 if (features.isRequired("splitidx")) {
2105 for (auto const & idx : indiceslist()) {
2106 os << "\\newindex{";
2107 os << escape(idx.shortcut());
2113 os << from_utf8(spacing().writePreamble(features.isProvided("SetSpace")));
2116 // * Hyperref manual: "Make sure it comes last of your loaded
2117 // packages, to give it a fighting chance of not being over-written,
2118 // since its job is to redefine many LaTeX commands."
2119 // * Email from Heiko Oberdiek: "It is usually better to load babel
2120 // before hyperref. Then hyperref has a chance to detect babel.
2121 // * Has to be loaded before the "LyX specific LaTeX commands" to
2122 // avoid errors with algorithm floats.
2123 // use hyperref explicitly if it is required
2124 if (features.isRequired("hyperref")) {
2125 OutputParams tmp_params = features.runparams();
2126 pdfoptions().writeLaTeX(tmp_params, os,
2127 features.isProvided("hyperref"));
2128 // correctly break URLs with hyperref and dvi/ps output
2129 if (features.runparams().hyperref_driver == "dvips"
2130 && features.isAvailable("breakurl"))
2131 os << "\\usepackage{breakurl}\n";
2132 } else if (features.isRequired("nameref"))
2133 // hyperref loads this automatically
2134 os << "\\usepackage{nameref}\n";
2137 os << "\\usepackage";
2138 if (!lineno_opts.empty())
2139 os << "[" << lineno_opts << "]";
2141 os << "\\linenumbers\n";
2144 // bibtopic needs to be loaded after hyperref.
2145 // the dot provides the aux file naming which LyX can detect.
2146 if (features.mustProvide("bibtopic"))
2147 os << "\\usepackage[dot]{bibtopic}\n";
2149 // Will be surrounded by \makeatletter and \makeatother when not empty
2150 otexstringstream atlyxpreamble;
2152 // Some macros LyX will need
2154 TexString tmppreamble = features.getMacros();
2155 if (!tmppreamble.str.empty())
2156 atlyxpreamble << "\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
2157 "LyX specific LaTeX commands.\n"
2158 << move(tmppreamble)
2161 // the text class specific preamble
2163 docstring tmppreamble = features.getTClassPreamble();
2164 if (!tmppreamble.empty())
2165 atlyxpreamble << "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
2166 "Textclass specific LaTeX commands.\n"
2170 // suppress date if selected
2171 // use \@ifundefined because we cannot be sure that every document class
2172 // has a \date command
2174 atlyxpreamble << "\\@ifundefined{date}{}{\\date{}}\n";
2176 /* the user-defined preamble */
2177 if (!containsOnly(preamble, " \n\t")) {
2179 atlyxpreamble << "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
2180 "User specified LaTeX commands.\n";
2182 // Check if the user preamble contains uncodable glyphs
2183 odocstringstream user_preamble;
2184 docstring uncodable_glyphs;
2185 Encoding const * const enc = features.runparams().encoding;
2187 for (char_type c : preamble) {
2188 if (!enc->encodable(c)) {
2189 docstring const glyph(1, c);
2190 LYXERR0("Uncodable character '"
2192 << "' in user preamble!");
2193 uncodable_glyphs += glyph;
2194 if (features.runparams().dryrun) {
2195 user_preamble << "<" << _("LyX Warning: ")
2196 << _("uncodable character") << " '";
2197 user_preamble.put(c);
2198 user_preamble << "'>";
2201 user_preamble.put(c);
2204 user_preamble << preamble;
2206 // On BUFFER_VIEW|UPDATE, warn user if we found uncodable glyphs
2207 if (!features.runparams().dryrun && !uncodable_glyphs.empty()) {
2208 frontend::Alert::warning(
2209 _("Uncodable character in user preamble"),
2211 _("The user preamble of your document contains glyphs "
2212 "that are unknown in the current document encoding "
2213 "(namely %1$s).\nThese glyphs are omitted "
2214 " from the output, which may result in "
2215 "incomplete output."
2216 "\n\nPlease select an appropriate "
2217 "document encoding\n"
2218 "(such as utf8) or change the "
2219 "preamble code accordingly."),
2222 atlyxpreamble << user_preamble.str() << '\n';
2225 // footmisc must be loaded after setspace
2226 // Load it here to avoid clashes with footmisc loaded in the user
2227 // preamble. For that reason we also pass the options via
2228 // \PassOptionsToPackage in getPreamble() and not here.
2229 if (features.mustProvide("footmisc"))
2230 atlyxpreamble << "\\usepackage{footmisc}\n";
2232 // subfig loads internally the LaTeX package "caption". As
2233 // caption is a very popular package, users will load it in
2234 // the preamble. Therefore we must load subfig behind the
2235 // user-defined preamble and check if the caption package was
2236 // loaded or not. For the case that caption is loaded before
2237 // subfig, there is the subfig option "caption=false". This
2238 // option also works when a koma-script class is used and
2239 // koma's own caption commands are used instead of caption. We
2240 // use \PassOptionsToPackage here because the user could have
2241 // already loaded subfig in the preamble.
2242 if (features.mustProvide("subfig"))
2243 atlyxpreamble << "\\@ifundefined{showcaptionsetup}{}{%\n"
2244 " \\PassOptionsToPackage{caption=false}{subfig}}\n"
2245 "\\usepackage{subfig}\n";
2247 // Itemize bullet settings need to be last in case the user
2248 // defines their own bullets that use a package included
2249 // in the user-defined preamble -- ARRae
2250 // Actually it has to be done much later than that
2251 // since some packages like frenchb make modifications
2252 // at \begin{document} time -- JMarc
2253 docstring bullets_def;
2254 for (int i = 0; i < 4; ++i) {
2255 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
2256 if (bullets_def.empty())
2257 bullets_def += "\\AtBeginDocument{\n";
2258 bullets_def += " \\def\\labelitemi";
2260 // `i' is one less than the item to modify
2267 bullets_def += "ii";
2273 bullets_def += '{' +
2274 user_defined_bullet(i).getText()
2279 if (!bullets_def.empty())
2280 atlyxpreamble << bullets_def << "}\n\n";
2282 if (!atlyxpreamble.empty())
2283 os << "\n\\makeatletter\n"
2284 << atlyxpreamble.release()
2285 << "\\makeatother\n\n";
2287 // We try to load babel late, in case it interferes with other packages.
2288 // Jurabib, hyperref, varioref, bicaption, menukeys and listings (bug 8995)
2289 // have to be called after babel, though.
2290 if (use_babel && !features.isRequired("jurabib")
2291 && !features.isRequired("hyperref")
2292 && !features.isRequired("varioref")
2293 && !features.isRequired("japanese")) {
2294 os << features.getBabelPresettings();
2296 os << from_utf8(babelCall(language_options.str(),
2297 !lyxrc.language_global_options)) + '\n';
2298 os << features.getBabelPostsettings();
2300 // In documents containing text in Thai language,
2301 // we must load inputenc after babel (see lib/languages).
2302 if (contains(features.getBabelPostsettings(), from_ascii("thai.ldf")))
2303 writeEncodingPreamble(os, features);
2305 // font selection must be done after babel with non-TeX fonts
2306 if (!fonts.empty() && features.useBabel() && useNonTeXFonts)
2307 os << from_utf8(fonts);
2309 if (features.isRequired("bicaption"))
2310 os << "\\usepackage{bicaption}\n";
2311 if (!listings_params.empty()
2312 || features.mustProvide("listings")
2313 || features.mustProvide("minted")) {
2315 os << "\\usepackage{minted}\n";
2317 os << "\\usepackage{listings}\n";
2319 string lst_params = listings_params;
2320 // If minted, do not output the language option (bug 11203)
2321 if (use_minted && contains(lst_params, "language=")) {
2322 vector<string> opts =
2323 getVectorFromString(lst_params, ",", false);
2324 for (size_t i = 0; i < opts.size(); ++i) {
2325 if (prefixIs(opts[i], "language="))
2326 opts.erase(opts.begin() + i--);
2328 lst_params = getStringFromVector(opts, ",");
2330 if (!lst_params.empty()) {
2332 os << "\\setminted{";
2335 // do not test validity because listings_params is
2336 // supposed to be valid
2338 InsetListingsParams(lst_params).separatedParams(true);
2339 os << from_utf8(par);
2343 // xunicode only needs to be loaded if tipa is used
2344 // (the rest is obsoleted by the new TU encoding).
2345 // It needs to be loaded at least after amsmath, amssymb,
2346 // esint and the other packages that provide special glyphs
2347 if (features.mustProvide("tipa") && useNonTeXFonts
2348 && !features.isProvided("xunicode")) {
2349 // The `xunicode` package officially only supports XeTeX,
2350 // but also works with LuaTeX. We work around its XeTeX test.
2351 if (features.runparams().flavor != OutputParams::XETEX) {
2352 os << "% Pretend to xunicode that we are XeTeX\n"
2353 << "\\def\\XeTeXpicfile{}\n";
2355 os << "\\usepackage{xunicode}\n";
2358 // covington must be loaded after beamerarticle
2359 if (features.isRequired("covington"))
2360 os << "\\usepackage{covington}\n";
2362 // Polyglossia must be loaded last ...
2363 if (use_polyglossia) {
2365 os << "\\usepackage{polyglossia}\n";
2366 // set the main language
2367 os << "\\setdefaultlanguage";
2368 if (!language->polyglossiaOpts().empty())
2369 os << "[" << from_ascii(language->polyglossiaOpts()) << "]";
2370 os << "{" << from_ascii(language->polyglossia()) << "}\n";
2371 // now setup the other languages
2372 set<string> const polylangs =
2373 features.getPolyglossiaLanguages();
2374 for (auto const & pl : polylangs) {
2375 // We do not output the options here; they are output in
2376 // the language switch commands. This is safer if multiple
2377 // varieties are used.
2378 if (pl == language->polyglossia())
2380 os << "\\setotherlanguage";
2381 os << "{" << from_ascii(pl) << "}\n";
2385 // ... but before biblatex (see #7065)
2386 if ((features.mustProvide("biblatex")
2387 || features.isRequired("biblatex-chicago"))
2388 && !features.isProvided("biblatex-chicago")
2389 && !features.isProvided("biblatex-natbib")
2390 && !features.isProvided("natbib-internal")
2391 && !features.isProvided("natbib")
2392 && !features.isProvided("jurabib")) {
2393 // The biblatex-chicago package has a differing interface
2394 // it uses a wrapper package and loads styles via fixed options
2395 bool const chicago = features.isRequired("biblatex-chicago");
2398 os << "\\usepackage";
2399 if (!biblatex_bibstyle.empty()
2400 && (biblatex_bibstyle == biblatex_citestyle)
2402 opts = "style=" + biblatex_bibstyle;
2404 } else if (!chicago) {
2405 if (!biblatex_bibstyle.empty()) {
2406 opts = "bibstyle=" + biblatex_bibstyle;
2409 if (!biblatex_citestyle.empty()) {
2410 opts += delim + "citestyle=" + biblatex_citestyle;
2414 if (!multibib.empty() && multibib != "child") {
2415 opts += delim + "refsection=" + multibib;
2418 if (bibtexCommand() == "bibtex8"
2419 || prefixIs(bibtexCommand(), "bibtex8 ")) {
2420 opts += delim + "backend=bibtex8";
2422 } else if (bibtexCommand() == "bibtex"
2423 || prefixIs(bibtexCommand(), "bibtex ")) {
2424 opts += delim + "backend=bibtex";
2427 if (!bib_encoding.empty() && encodings.fromLyXName(bib_encoding)) {
2428 opts += delim + "bibencoding="
2429 + encodings.fromLyXName(bib_encoding)->latexName();
2432 if (!biblio_opts.empty())
2433 opts += delim + biblio_opts;
2435 os << "[" << opts << "]";
2437 os << "{biblatex-chicago}\n";
2439 os << "{biblatex}\n";
2443 // Load custom language package here
2444 if (features.langPackage() == LaTeXFeatures::LANG_PACK_CUSTOM) {
2445 if (lang_package == "default")
2446 os << from_utf8(lyxrc.language_custom_package);
2448 os << from_utf8(lang_package);
2452 // Since menukeys uses catoptions, which does some heavy changes on key-value options,
2453 // it is recommended to load menukeys as the last package (even after hyperref)
2454 if (features.isRequired("menukeys"))
2455 os << "\\usepackage{menukeys}\n";
2457 docstring const i18npreamble =
2458 features.getTClassI18nPreamble(use_babel, use_polyglossia,
2460 if (!i18npreamble.empty())
2461 os << i18npreamble + '\n';
2467 void BufferParams::useClassDefaults()
2469 DocumentClass const & tclass = documentClass();
2471 sides = tclass.sides();
2472 columns = tclass.columns();
2473 pagestyle = tclass.pagestyle();
2474 tablestyle = tclass.tablestyle();
2475 use_default_options = true;
2476 // Only if class has a ToC hierarchy
2477 if (tclass.hasTocLevels()) {
2478 secnumdepth = tclass.secnumdepth();
2479 tocdepth = tclass.tocdepth();
2484 bool BufferParams::hasClassDefaults() const
2486 DocumentClass const & tclass = documentClass();
2488 return sides == tclass.sides()
2489 && columns == tclass.columns()
2490 && pagestyle == tclass.pagestyle()
2491 && tablestyle == tclass.tablestyle()
2492 && use_default_options
2493 && secnumdepth == tclass.secnumdepth()
2494 && tocdepth == tclass.tocdepth();
2498 DocumentClass const & BufferParams::documentClass() const
2504 DocumentClassConstPtr BufferParams::documentClassPtr() const
2510 void BufferParams::setDocumentClass(DocumentClassConstPtr tc)
2512 // evil, but this function is evil
2513 doc_class_ = const_pointer_cast<DocumentClass>(tc);
2514 invalidateConverterCache();
2518 bool BufferParams::setBaseClass(string const & classname, string const & path)
2520 LYXERR(Debug::TCLASS, "setBaseClass: " << classname);
2521 LayoutFileList & bcl = LayoutFileList::get();
2522 if (!bcl.haveClass(classname)) {
2524 bformat(_("The layout file:\n"
2526 "could not be found. A default textclass with default\n"
2527 "layouts will be used. LyX will not be able to produce\n"
2529 from_utf8(classname));
2530 frontend::Alert::error(_("Document class not found"), s);
2531 bcl.addEmptyClass(classname);
2534 bool const success = bcl[classname].load(path);
2537 bformat(_("Due to some error in it, the layout file:\n"
2539 "could not be loaded. A default textclass with default\n"
2540 "layouts will be used. LyX will not be able to produce\n"
2542 from_utf8(classname));
2543 frontend::Alert::error(_("Could not load class"), s);
2544 bcl.addEmptyClass(classname);
2547 pimpl_->baseClass_ = classname;
2548 layout_modules_.adaptToBaseClass(baseClass(), removed_modules_);
2553 LayoutFile const * BufferParams::baseClass() const
2555 if (LayoutFileList::get().haveClass(pimpl_->baseClass_))
2556 return &(LayoutFileList::get()[pimpl_->baseClass_]);
2562 LayoutFileIndex const & BufferParams::baseClassID() const
2564 return pimpl_->baseClass_;
2568 void BufferParams::makeDocumentClass(bool const clone)
2573 invalidateConverterCache();
2574 LayoutModuleList mods;
2575 for (auto const & mod : layout_modules_)
2576 mods.push_back(mod);
2578 doc_class_ = getDocumentClass(*baseClass(), mods, cite_engine_, clone);
2580 TextClass::ReturnValues success = TextClass::OK;
2581 if (!forced_local_layout_.empty())
2582 success = doc_class_->read(to_utf8(forced_local_layout_),
2584 if (!local_layout_.empty() &&
2585 (success == TextClass::OK || success == TextClass::OK_OLDFORMAT))
2586 success = doc_class_->read(to_utf8(local_layout_), TextClass::MODULE);
2587 if (success != TextClass::OK && success != TextClass::OK_OLDFORMAT) {
2588 docstring const msg = _("Error reading internal layout information");
2589 frontend::Alert::warning(_("Read Error"), msg);
2594 bool BufferParams::layoutModuleCanBeAdded(string const & modName) const
2596 return layout_modules_.moduleCanBeAdded(modName, baseClass());
2600 docstring BufferParams::getLocalLayout(bool forced) const
2603 return from_utf8(doc_class_->forcedLayouts());
2605 return local_layout_;
2609 void BufferParams::setLocalLayout(docstring const & layout, bool forced)
2612 forced_local_layout_ = layout;
2614 local_layout_ = layout;
2618 bool BufferParams::addLayoutModule(string const & modName)
2620 for (auto const & mod : layout_modules_)
2623 layout_modules_.push_back(modName);
2628 string BufferParams::bufferFormat() const
2630 return documentClass().outputFormat();
2634 bool BufferParams::isExportable(string const & format, bool need_viewable) const
2636 FormatList const & formats = exportableFormats(need_viewable);
2637 for (auto const & fmt : formats) {
2638 if (fmt->name() == format)
2645 FormatList const & BufferParams::exportableFormats(bool only_viewable) const
2647 FormatList & cached = only_viewable ?
2648 pimpl_->viewableFormatList : pimpl_->exportableFormatList;
2649 bool & valid = only_viewable ?
2650 pimpl_->isViewCacheValid : pimpl_->isExportCacheValid;
2654 vector<string> const backs = backends();
2655 set<string> excludes;
2656 if (useNonTeXFonts) {
2657 excludes.insert("latex");
2658 excludes.insert("pdflatex");
2659 } else if (inputenc != "ascii" && inputenc != "utf8-plain") {
2660 // XeTeX with TeX fonts requires input encoding ascii (#10600).
2661 excludes.insert("xetex");
2665 theConverters().getReachable(backs[0], only_viewable, true, excludes);
2666 vector<string>::const_iterator it = backs.begin() + 1;
2667 for (; it != backs.end(); ++it) {
2668 FormatList r = theConverters().getReachable(*it, only_viewable,
2670 result.insert(result.end(), r.begin(), r.end());
2672 sort(result.begin(), result.end(), Format::formatSorter);
2679 vector<string> BufferParams::backends() const
2682 string const buffmt = bufferFormat();
2684 // FIXME: Don't hardcode format names here, but use a flag
2685 if (buffmt == "latex") {
2686 if (encoding().package() == Encoding::japanese)
2687 v.push_back("platex");
2689 if (!useNonTeXFonts) {
2690 v.push_back("pdflatex");
2691 v.push_back("latex");
2694 || inputenc == "ascii" || inputenc == "utf8-plain")
2695 v.push_back("xetex");
2696 v.push_back("luatex");
2697 v.push_back("dviluatex");
2700 string rbuffmt = buffmt;
2701 // If we use an OutputFormat in Japanese docs,
2702 // we need special format in order to get the path
2703 // via pLaTeX (#8823)
2704 if (documentClass().hasOutputFormat()
2705 && encoding().package() == Encoding::japanese)
2707 v.push_back(rbuffmt);
2710 v.push_back("xhtml");
2711 v.push_back("docbook5");
2712 v.push_back("text");
2718 OutputParams::FLAVOR BufferParams::getOutputFlavor(string const & format) const
2720 string const dformat = (format.empty() || format == "default") ?
2721 getDefaultOutputFormat() : format;
2722 DefaultFlavorCache::const_iterator it =
2723 default_flavors_.find(dformat);
2725 if (it != default_flavors_.end())
2728 OutputParams::FLAVOR result = OutputParams::LATEX;
2730 // FIXME It'd be better not to hardcode this, but to do
2731 // something with formats.
2732 if (dformat == "xhtml")
2733 result = OutputParams::HTML;
2734 else if (dformat == "docbook5")
2735 result = OutputParams::DOCBOOK5;
2736 else if (dformat == "text")
2737 result = OutputParams::TEXT;
2738 else if (dformat == "lyx")
2739 result = OutputParams::LYX;
2740 else if (dformat == "pdflatex")
2741 result = OutputParams::PDFLATEX;
2742 else if (dformat == "xetex")
2743 result = OutputParams::XETEX;
2744 else if (dformat == "luatex")
2745 result = OutputParams::LUATEX;
2746 else if (dformat == "dviluatex")
2747 result = OutputParams::DVILUATEX;
2749 // Try to determine flavor of default output format
2750 vector<string> backs = backends();
2751 if (find(backs.begin(), backs.end(), dformat) == backs.end()) {
2752 // Get shortest path to format
2753 Graph::EdgePath path;
2754 for (auto const & bvar : backs) {
2755 Graph::EdgePath p = theConverters().getPath(bvar, dformat);
2756 if (!p.empty() && (path.empty() || p.size() < path.size())) {
2761 result = theConverters().getFlavor(path);
2764 // cache this flavor
2765 default_flavors_[dformat] = result;
2770 string BufferParams::getDefaultOutputFormat() const
2772 if (!default_output_format.empty()
2773 && default_output_format != "default")
2774 return default_output_format;
2775 if (encoding().package() == Encoding::japanese)
2776 return lyxrc.default_platex_view_format;
2778 return lyxrc.default_otf_view_format;
2779 return lyxrc.default_view_format;
2782 Font const BufferParams::getFont() const
2784 FontInfo f = documentClass().defaultfont();
2785 if (fonts_default_family == "rmdefault")
2786 f.setFamily(ROMAN_FAMILY);
2787 else if (fonts_default_family == "sfdefault")
2788 f.setFamily(SANS_FAMILY);
2789 else if (fonts_default_family == "ttdefault")
2790 f.setFamily(TYPEWRITER_FAMILY);
2791 return Font(f, language);
2795 InsetQuotesParams::QuoteStyle BufferParams::getQuoteStyle(string const & qs) const
2797 return quotesstyletranslator().find(qs);
2801 bool BufferParams::isLatex() const
2803 return documentClass().outputType() == LATEX;
2807 bool BufferParams::isLiterate() const
2809 return documentClass().outputType() == LITERATE;
2813 void BufferParams::readPreamble(Lexer & lex)
2815 if (lex.getString() != "\\begin_preamble")
2816 lyxerr << "Error (BufferParams::readPreamble):"
2817 "consistency check failed." << endl;
2819 preamble = lex.getLongString(from_ascii("\\end_preamble"));
2823 void BufferParams::readLocalLayout(Lexer & lex, bool forced)
2825 string const expected = forced ? "\\begin_forced_local_layout" :
2826 "\\begin_local_layout";
2827 if (lex.getString() != expected)
2828 lyxerr << "Error (BufferParams::readLocalLayout):"
2829 "consistency check failed." << endl;
2832 forced_local_layout_ =
2833 lex.getLongString(from_ascii("\\end_forced_local_layout"));
2835 local_layout_ = lex.getLongString(from_ascii("\\end_local_layout"));
2839 bool BufferParams::setLanguage(string const & lang)
2841 Language const *new_language = languages.getLanguage(lang);
2842 if (!new_language) {
2843 // Language lang was not found
2846 language = new_language;
2851 void BufferParams::readLanguage(Lexer & lex)
2853 if (!lex.next()) return;
2855 string const tmptok = lex.getString();
2857 // check if tmptok is part of tex_babel in tex-defs.h
2858 if (!setLanguage(tmptok)) {
2859 // Language tmptok was not found
2860 language = default_language;
2861 lyxerr << "Warning: Setting language `"
2862 << tmptok << "' to `" << language->lang()
2868 void BufferParams::readGraphicsDriver(Lexer & lex)
2873 string const tmptok = lex.getString();
2874 // check if tmptok is part of tex_graphics in tex_defs.h
2877 string const test = tex_graphics[n++];
2879 if (test == tmptok) {
2880 graphics_driver = tmptok;
2885 "Warning: graphics driver `$$Token' not recognized!\n"
2886 " Setting graphics driver to `default'.\n");
2887 graphics_driver = "default";
2894 void BufferParams::readBullets(Lexer & lex)
2899 int const index = lex.getInteger();
2901 int temp_int = lex.getInteger();
2902 user_defined_bullet(index).setFont(temp_int);
2903 temp_bullet(index).setFont(temp_int);
2905 user_defined_bullet(index).setCharacter(temp_int);
2906 temp_bullet(index).setCharacter(temp_int);
2908 user_defined_bullet(index).setSize(temp_int);
2909 temp_bullet(index).setSize(temp_int);
2913 void BufferParams::readBulletsLaTeX(Lexer & lex)
2915 // The bullet class should be able to read this.
2918 int const index = lex.getInteger();
2920 docstring const temp_str = lex.getDocString();
2922 user_defined_bullet(index).setText(temp_str);
2923 temp_bullet(index).setText(temp_str);
2927 void BufferParams::readModules(Lexer & lex)
2929 if (!lex.eatLine()) {
2930 lyxerr << "Error (BufferParams::readModules):"
2931 "Unexpected end of input." << endl;
2935 string mod = lex.getString();
2936 if (mod == "\\end_modules")
2938 addLayoutModule(mod);
2944 void BufferParams::readRemovedModules(Lexer & lex)
2946 if (!lex.eatLine()) {
2947 lyxerr << "Error (BufferParams::readRemovedModules):"
2948 "Unexpected end of input." << endl;
2952 string mod = lex.getString();
2953 if (mod == "\\end_removed_modules")
2955 removed_modules_.push_back(mod);
2958 // now we want to remove any removed modules that were previously
2959 // added. normally, that will be because default modules were added in
2960 // setBaseClass(), which gets called when \textclass is read at the
2961 // start of the read.
2962 for (auto const & rm : removed_modules_) {
2963 LayoutModuleList::iterator const mit = layout_modules_.begin();
2964 LayoutModuleList::iterator const men = layout_modules_.end();
2965 LayoutModuleList::iterator found = find(mit, men, rm);
2968 layout_modules_.erase(found);
2973 void BufferParams::readIncludeonly(Lexer & lex)
2975 if (!lex.eatLine()) {
2976 lyxerr << "Error (BufferParams::readIncludeonly):"
2977 "Unexpected end of input." << endl;
2981 string child = lex.getString();
2982 if (child == "\\end_includeonly")
2984 included_children_.push_back(child);
2990 string BufferParams::paperSizeName(PapersizePurpose purpose, string const & psize) const
2992 PAPER_SIZE ppsize = psize.empty() ? papersize : papersizetranslator().find(psize);
2995 if (documentClass().pagesize() == "default")
2996 // could be anything, so don't guess
2998 return paperSizeName(purpose, documentClass().pagesize());
2999 case PAPER_CUSTOM: {
3000 if (purpose == XDVI && !paperwidth.empty() &&
3001 !paperheight.empty()) {
3002 // heightxwidth<unit>
3003 string first = paperwidth;
3004 string second = paperheight;
3005 if (orientation == ORIENTATION_LANDSCAPE)
3008 return first.erase(first.length() - 2)
3014 // dvips and dvipdfm do not know this
3015 if (purpose == DVIPS || purpose == DVIPDFM)
3019 if (purpose == DVIPS || purpose == DVIPDFM)
3023 if (purpose == DVIPS || purpose == DVIPDFM)
3033 if (purpose == DVIPS || purpose == DVIPDFM)
3037 if (purpose == DVIPS || purpose == DVIPDFM)
3041 if (purpose == DVIPS || purpose == DVIPDFM)
3045 if (purpose == DVIPS || purpose == DVIPDFM)
3049 if (purpose == DVIPS || purpose == DVIPDFM)
3053 // dvipdfm does not know this
3054 if (purpose == DVIPDFM)
3058 if (purpose == DVIPDFM)
3062 if (purpose == DVIPS || purpose == DVIPDFM)
3066 if (purpose == DVIPS || purpose == DVIPDFM)
3070 if (purpose == DVIPS || purpose == DVIPDFM)
3074 if (purpose == DVIPS || purpose == DVIPDFM)
3078 if (purpose == DVIPS || purpose == DVIPDFM)
3082 if (purpose == DVIPS || purpose == DVIPDFM)
3086 if (purpose == DVIPS || purpose == DVIPDFM)
3090 if (purpose == DVIPS || purpose == DVIPDFM)
3094 if (purpose == DVIPS || purpose == DVIPDFM)
3098 if (purpose == DVIPS || purpose == DVIPDFM)
3102 if (purpose == DVIPS || purpose == DVIPDFM)
3106 if (purpose == DVIPS || purpose == DVIPDFM)
3110 if (purpose == DVIPS || purpose == DVIPDFM)
3114 if (purpose == DVIPS || purpose == DVIPDFM)
3118 if (purpose == DVIPS || purpose == DVIPDFM)
3121 case PAPER_USEXECUTIVE:
3122 // dvipdfm does not know this
3123 if (purpose == DVIPDFM)
3128 case PAPER_USLETTER:
3130 if (purpose == XDVI)
3137 string const BufferParams::dvips_options() const
3141 // If the class loads the geometry package, we do not know which
3142 // paper size is used, since we do not set it (bug 7013).
3143 // Therefore we must not specify any argument here.
3144 // dvips gets the correct paper size via DVI specials in this case
3145 // (if the class uses the geometry package correctly).
3146 if (documentClass().provides("geometry"))
3150 && papersize == PAPER_CUSTOM
3151 && !lyxrc.print_paper_dimension_flag.empty()
3152 && !paperwidth.empty()
3153 && !paperheight.empty()) {
3154 // using a custom papersize
3155 result = lyxrc.print_paper_dimension_flag;
3156 result += ' ' + paperwidth;
3157 result += ',' + paperheight;
3159 string const paper_option = paperSizeName(DVIPS);
3160 if (!paper_option.empty() && (paper_option != "letter" ||
3161 orientation != ORIENTATION_LANDSCAPE)) {
3162 // dvips won't accept -t letter -t landscape.
3163 // In all other cases, include the paper size
3165 result = lyxrc.print_paper_flag;
3166 result += ' ' + paper_option;
3169 if (orientation == ORIENTATION_LANDSCAPE &&
3170 papersize != PAPER_CUSTOM)
3171 result += ' ' + lyxrc.print_landscape_flag;
3176 string const BufferParams::main_font_encoding() const
3178 if (font_encodings().empty()) {
3179 if (ascii_lowercase(language->fontenc(*this)) == "none")
3183 return font_encodings().back();
3187 vector<string> const BufferParams::font_encodings() const
3189 string doc_fontenc = (fontenc == "auto") ? string() : fontenc;
3191 vector<string> fontencs;
3193 // "default" means "no explicit font encoding"
3194 if (doc_fontenc != "default") {
3195 if (!doc_fontenc.empty())
3196 // If we have a custom setting, we use only that!
3197 return getVectorFromString(doc_fontenc);
3198 if (!language->fontenc(*this).empty()
3199 && ascii_lowercase(language->fontenc(*this)) != "none") {
3200 vector<string> fencs = getVectorFromString(language->fontenc(*this));
3201 for (auto & fe : fencs) {
3202 if (find(fontencs.begin(), fontencs.end(), fe) == fontencs.end())
3203 fontencs.push_back(fe);
3212 string BufferParams::babelCall(string const & lang_opts, bool const langoptions) const
3214 // suppress the babel call if there is no BabelName defined
3215 // for the document language in the lib/languages file and if no
3216 // other languages are used (lang_opts is then empty)
3217 if (lang_opts.empty())
3219 // The prefs may require the languages to
3220 // be submitted to babel itself (not the class).
3222 return "\\usepackage[" + lang_opts + "]{babel}";
3223 return "\\usepackage{babel}";
3227 docstring BufferParams::getGraphicsDriver(string const & package) const
3231 if (package == "geometry") {
3232 if (graphics_driver == "dvips"
3233 || graphics_driver == "dvipdfm"
3234 || graphics_driver == "pdftex"
3235 || graphics_driver == "vtex")
3236 result = from_ascii(graphics_driver);
3237 else if (graphics_driver == "dvipdfmx")
3238 result = from_ascii("dvipdfm");
3245 void BufferParams::writeEncodingPreamble(otexstream & os,
3246 LaTeXFeatures & features) const
3248 // With no-TeX fonts we use utf8-plain without encoding package.
3252 if (inputenc == "auto-legacy") {
3253 string const doc_encoding =
3254 language->encoding()->latexName();
3255 Encoding::Package const package =
3256 language->encoding()->package();
3258 // Create list of inputenc options:
3259 set<string> encoding_set;
3260 // luainputenc fails with more than one encoding
3261 if (features.runparams().flavor != OutputParams::LUATEX
3262 && features.runparams().flavor != OutputParams::DVILUATEX)
3263 // list all input encodings used in the document
3264 encoding_set = features.getEncodingSet(doc_encoding);
3266 // The "japanese" babel-language requires the pLaTeX engine
3267 // which conflicts with "inputenc".
3268 // See http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129680.html
3269 if ((!encoding_set.empty() || package == Encoding::inputenc)
3270 && !features.isRequired("japanese")
3271 && !features.isProvided("inputenc")) {
3272 os << "\\usepackage[";
3273 set<string>::const_iterator it = encoding_set.begin();
3274 set<string>::const_iterator const end = encoding_set.end();
3276 os << from_ascii(*it);
3279 for (; it != end; ++it)
3280 os << ',' << from_ascii(*it);
3281 if (package == Encoding::inputenc) {
3282 if (!encoding_set.empty())
3284 os << from_ascii(doc_encoding);
3286 if (features.runparams().flavor == OutputParams::LUATEX
3287 || features.runparams().flavor == OutputParams::DVILUATEX)
3288 os << "]{luainputenc}\n";
3290 os << "]{inputenc}\n";
3292 } else if (inputenc != "auto-legacy-plain") {
3293 switch (encoding().package()) {
3294 case Encoding::none:
3296 case Encoding::japanese:
3297 if (encoding().iconvName() != "UTF-8"
3298 && !features.runparams().isFullUnicode())
3299 // don't default to [utf8]{inputenc} with TeXLive >= 18
3300 os << "\\ifdefined\\UseRawInputEncoding\n"
3301 << " \\UseRawInputEncoding\\fi\n";
3303 case Encoding::inputenc:
3304 // do not load inputenc if japanese is used
3305 // or if the class provides inputenc
3306 if (features.isRequired("japanese")
3307 || features.isProvided("inputenc"))
3309 os << "\\usepackage[" << from_ascii(encoding().latexName());
3310 if (features.runparams().flavor == OutputParams::LUATEX
3311 || features.runparams().flavor == OutputParams::DVILUATEX)
3312 os << "]{luainputenc}\n";
3314 os << "]{inputenc}\n";
3318 if (inputenc == "auto-legacy-plain" || features.isRequired("japanese")) {
3319 // don't default to [utf8]{inputenc} with TeXLive >= 18
3320 os << "\\ifdefined\\UseRawInputEncoding\n";
3321 os << " \\UseRawInputEncoding\\fi\n";
3326 string const BufferParams::parseFontName(string const & name) const
3328 string mangled = name;
3329 size_t const idx = mangled.find('[');
3330 if (idx == string::npos || idx == 0)
3333 return mangled.substr(0, idx - 1);
3337 string const BufferParams::loadFonts(LaTeXFeatures & features) const
3339 if (fontsRoman() == "default" && fontsSans() == "default"
3340 && fontsTypewriter() == "default"
3341 && (fontsMath() == "default" || fontsMath() == "auto"))
3347 /* Fontspec (XeTeX, LuaTeX): we provide GUI support for oldstyle
3348 * numbers (Numbers=OldStyle) and sf/tt scaling. The Ligatures=TeX/
3349 * Mapping=tex-text option assures TeX ligatures (such as "--")
3350 * are resolved. Note that tt does not use these ligatures.
3352 * -- add more GUI options?
3353 * -- add more fonts (fonts for other scripts)
3354 * -- if there's a way to find out if a font really supports
3355 * OldStyle, enable/disable the widget accordingly.
3357 if (useNonTeXFonts && features.isAvailable("fontspec")) {
3358 // "Mapping=tex-text" and "Ligatures=TeX" are equivalent.
3359 // However, until v.2 (2010/07/11) fontspec only knew
3360 // Mapping=tex-text (for XeTeX only); then "Ligatures=TeX"
3361 // was introduced for both XeTeX and LuaTeX (LuaTeX
3362 // didn't understand "Mapping=tex-text", while XeTeX
3363 // understood both. With most recent versions, both
3364 // variants are understood by both engines. However,
3365 // we want to provide support for at least TeXLive 2009
3366 // (for XeTeX; LuaTeX is only supported as of v.2)
3367 // As of 2017/11/03, Babel has its own higher-level
3368 // interface on top of fontspec that is to be used.
3369 bool const babelfonts = features.useBabel()
3370 && features.isAvailable("babel-2017/11/03");
3371 string const texmapping =
3372 (features.runparams().flavor == OutputParams::XETEX) ?
3373 "Mapping=tex-text" : "Ligatures=TeX";
3374 if (fontsRoman() != "default") {
3376 os << "\\babelfont{rm}[";
3378 os << "\\setmainfont[";
3379 if (!font_roman_opts.empty())
3380 os << font_roman_opts << ',';
3382 if (fonts_roman_osf)
3383 os << ",Numbers=OldStyle";
3384 os << "]{" << parseFontName(fontsRoman()) << "}\n";
3386 if (fontsSans() != "default") {
3387 string const sans = parseFontName(fontsSans());
3388 if (fontsSansScale() != 100) {
3390 os << "\\babelfont{sf}";
3392 os << "\\setsansfont";
3394 << float(fontsSansScale()) / 100 << ',';
3396 os << "Numbers=OldStyle,";
3397 if (!font_sans_opts.empty())
3398 os << font_sans_opts << ',';
3399 os << texmapping << "]{"
3403 os << "\\babelfont{sf}[";
3405 os << "\\setsansfont[";
3407 os << "Numbers=OldStyle,";
3408 if (!font_sans_opts.empty())
3409 os << font_sans_opts << ',';
3410 os << texmapping << "]{"
3414 if (fontsTypewriter() != "default") {
3415 string const mono = parseFontName(fontsTypewriter());
3416 if (fontsTypewriterScale() != 100) {
3418 os << "\\babelfont{tt}";
3420 os << "\\setmonofont";
3422 << float(fontsTypewriterScale()) / 100;
3423 if (fonts_typewriter_osf)
3424 os << ",Numbers=OldStyle";
3425 if (!font_typewriter_opts.empty())
3426 os << ',' << font_typewriter_opts;
3431 os << "\\babelfont{tt}";
3433 os << "\\setmonofont";
3434 if (!font_typewriter_opts.empty() || fonts_typewriter_osf) {
3436 if (fonts_typewriter_osf)
3437 os << "Numbers=OldStyle";
3438 if (!font_typewriter_opts.empty()) {
3439 if (fonts_typewriter_osf)
3441 os << font_typewriter_opts;
3445 os << '{' << mono << "}\n";
3452 bool const ot1 = (main_font_encoding() == "default" || main_font_encoding() == "OT1");
3453 bool const dryrun = features.runparams().dryrun;
3454 bool const complete = (fontsSans() == "default" && fontsTypewriter() == "default");
3455 bool const nomath = (fontsMath() == "default");
3458 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsRoman())).getLaTeXCode(
3459 dryrun, ot1, complete, fonts_expert_sc, fonts_roman_osf,
3460 nomath, font_roman_opts);
3463 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsSans())).getLaTeXCode(
3464 dryrun, ot1, complete, fonts_expert_sc, fonts_sans_osf,
3465 nomath, font_sans_opts, fontsSansScale());
3467 // MONOSPACED/TYPEWRITER
3468 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsTypewriter())).getLaTeXCode(
3469 dryrun, ot1, complete, fonts_expert_sc, fonts_typewriter_osf,
3470 nomath, font_typewriter_opts, fontsTypewriterScale());
3473 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsMath())).getLaTeXCode(
3474 dryrun, ot1, complete, fonts_expert_sc, fonts_roman_osf,
3481 Encoding const & BufferParams::encoding() const
3483 // Main encoding for LaTeX output.
3485 return *(encodings.fromLyXName("utf8-plain"));
3486 if (inputenc == "auto-legacy" || inputenc == "auto-legacy-plain")
3487 return *language->encoding();
3488 if (inputenc == "utf8" && language->lang() == "japanese")
3489 return *(encodings.fromLyXName("utf8-platex"));
3490 Encoding const * const enc = encodings.fromLyXName(inputenc);
3493 LYXERR0("Unknown inputenc value `" << inputenc
3494 << "'. Using `auto' instead.");
3495 return *language->encoding();
3499 string const & BufferParams::defaultBiblioStyle() const
3501 if (!biblio_style.empty())
3502 return biblio_style;
3504 map<string, string> const & bs = documentClass().defaultBiblioStyle();
3505 auto cit = bs.find(theCiteEnginesList.getTypeAsString(citeEngineType()));
3506 if (cit != bs.end())
3509 return empty_string();
3513 bool BufferParams::fullAuthorList() const
3515 return documentClass().fullAuthorList();
3519 string BufferParams::getCiteAlias(string const & s) const
3521 vector<string> commands =
3522 documentClass().citeCommands(citeEngineType());
3523 // If it is a real command, don't treat it as an alias
3524 if (find(commands.begin(), commands.end(), s) != commands.end())
3526 map<string,string> aliases = documentClass().citeCommandAliases();
3527 if (aliases.find(s) != aliases.end())
3533 vector<string> BufferParams::citeCommands() const
3535 static CitationStyle const default_style;
3536 vector<string> commands =
3537 documentClass().citeCommands(citeEngineType());
3538 if (commands.empty())
3539 commands.push_back(default_style.name);
3544 vector<CitationStyle> BufferParams::citeStyles() const
3546 static CitationStyle const default_style;
3547 vector<CitationStyle> styles =
3548 documentClass().citeStyles(citeEngineType());
3550 styles.push_back(default_style);
3555 string const BufferParams::bibtexCommand() const
3557 // Return document-specific setting if available
3558 if (bibtex_command != "default")
3559 return bibtex_command;
3561 // If we have "default" in document settings, consult the prefs
3562 // 1. Japanese (uses a specific processor)
3563 if (encoding().package() == Encoding::japanese) {
3564 if (lyxrc.jbibtex_command != "automatic")
3565 // Return the specified program, if "automatic" is not set
3566 return lyxrc.jbibtex_command;
3567 else if (!useBiblatex()) {
3568 // With classic BibTeX, return pbibtex, jbibtex, bibtex
3569 if (lyxrc.jbibtex_alternatives.find("pbibtex") != lyxrc.jbibtex_alternatives.end())
3571 if (lyxrc.jbibtex_alternatives.find("jbibtex") != lyxrc.jbibtex_alternatives.end())
3576 // 2. All other languages
3577 else if (lyxrc.bibtex_command != "automatic")
3578 // Return the specified program, if "automatic" is not set
3579 return lyxrc.bibtex_command;
3581 // 3. Automatic: find the most suitable for the current cite framework
3582 if (useBiblatex()) {
3583 // For Biblatex, we prefer biber (also for Japanese)
3584 // and fall back to bibtex8 and, as last resort, bibtex
3585 if (lyxrc.bibtex_alternatives.find("biber") != lyxrc.bibtex_alternatives.end())
3587 else if (lyxrc.bibtex_alternatives.find("bibtex8") != lyxrc.bibtex_alternatives.end())
3594 bool BufferParams::useBiblatex() const
3596 return theCiteEnginesList[citeEngine()]->getCiteFramework() == "biblatex";
3600 void BufferParams::invalidateConverterCache() const
3602 pimpl_->isExportCacheValid = false;
3603 pimpl_->isViewCacheValid = false;
3607 // We shouldn't need to reset the params here, since anything
3608 // we need will be recopied.
3609 void BufferParams::copyForAdvFR(const BufferParams & bp)
3611 string const & lang = bp.language->lang();
3613 layout_modules_ = bp.layout_modules_;
3614 string const & doc_class = bp.documentClass().name();
3615 setBaseClass(doc_class);
3619 void BufferParams::setBibFileEncoding(string const & file, string const & enc)
3621 bib_encodings[file] = enc;
3625 string const BufferParams::bibFileEncoding(string const & file) const
3627 if (bib_encodings.find(file) == bib_encodings.end())
3629 return bib_encodings.find(file)->second;