2 * \file BufferParams.cpp
3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
6 * \author Alfredo Braunstein
7 * \author Lars Gullik Bjønnes
8 * \author Jean-Marc Lasgouttes
10 * \author André Pönitz
11 * \author Martin Vermeer
13 * Full author contact details are available in file CREDITS.
18 #include "BufferParams.h"
21 #include "LayoutFile.h"
22 #include "BranchList.h"
24 #include "buffer_funcs.h"
26 #include "CiteEnginesList.h"
29 #include "Converter.h"
31 #include "IndicesList.h"
33 #include "LaTeXFeatures.h"
34 #include "LaTeXFonts.h"
36 #include "ModuleList.h"
40 #include "OutputParams.h"
42 #include "texstream.h"
45 #include "PDFOptions.h"
47 #include "frontends/alert.h"
49 #include "insets/InsetListingsParams.h"
51 #include "support/convert.h"
52 #include "support/debug.h"
53 #include "support/docstream.h"
54 #include "support/FileName.h"
55 #include "support/filetools.h"
56 #include "support/gettext.h"
57 #include "support/Messages.h"
58 #include "support/mutex.h"
59 #include "support/Package.h"
60 #include "support/Translator.h"
61 #include "support/lstrings.h"
67 using namespace lyx::support;
70 static char const * const string_paragraph_separation[] = {
75 static char const * const string_quotes_style[] = {
76 "english", "swedish", "german", "polish", "swiss", "danish", "plain",
77 "british", "swedishg", "french", "frenchin", "russian", "cjk", "cjkangle", ""
81 static char const * const string_papersize[] = {
82 "default", "custom", "letterpaper", "legalpaper", "executivepaper",
83 "a0paper", "a1paper", "a2paper", "a3paper", "a4paper", "a5paper",
84 "a6paper", "b0paper", "b1paper", "b2paper","b3paper", "b4paper",
85 "b5paper", "b6paper", "c0paper", "c1paper", "c2paper", "c3paper",
86 "c4paper", "c5paper", "c6paper", "b0j", "b1j", "b2j", "b3j", "b4j", "b5j",
91 static char const * const string_orientation[] = {
92 "portrait", "landscape", ""
96 static char const * const tex_graphics[] = {
97 "default", "dvialw", "dvilaser", "dvipdf", "dvipdfm", "dvipdfmx",
98 "dvips", "dvipsone", "dvitops", "dviwin", "dviwindo", "dvi2ps", "emtex",
99 "ln", "oztex", "pctexhp", "pctexps", "pctexwin", "pctex32", "pdftex",
100 "psprint", "pubps", "tcidvi", "textures", "truetex", "vtex", "xdvi",
110 // Paragraph separation
111 typedef Translator<string, BufferParams::ParagraphSeparation> ParSepTranslator;
114 ParSepTranslator const init_parseptranslator()
116 ParSepTranslator translator
117 (string_paragraph_separation[0], BufferParams::ParagraphIndentSeparation);
118 translator.addPair(string_paragraph_separation[1], BufferParams::ParagraphSkipSeparation);
123 ParSepTranslator const & parseptranslator()
125 static ParSepTranslator const translator =
126 init_parseptranslator();
132 typedef Translator<string, InsetQuotesParams::QuoteStyle> QuotesStyleTranslator;
135 QuotesStyleTranslator const init_quotesstyletranslator()
137 QuotesStyleTranslator translator
138 (string_quotes_style[0], InsetQuotesParams::EnglishQuotes);
139 translator.addPair(string_quotes_style[1], InsetQuotesParams::SwedishQuotes);
140 translator.addPair(string_quotes_style[2], InsetQuotesParams::GermanQuotes);
141 translator.addPair(string_quotes_style[3], InsetQuotesParams::PolishQuotes);
142 translator.addPair(string_quotes_style[4], InsetQuotesParams::SwissQuotes);
143 translator.addPair(string_quotes_style[5], InsetQuotesParams::DanishQuotes);
144 translator.addPair(string_quotes_style[6], InsetQuotesParams::PlainQuotes);
145 translator.addPair(string_quotes_style[7], InsetQuotesParams::BritishQuotes);
146 translator.addPair(string_quotes_style[8], InsetQuotesParams::SwedishGQuotes);
147 translator.addPair(string_quotes_style[9], InsetQuotesParams::FrenchQuotes);
148 translator.addPair(string_quotes_style[10], InsetQuotesParams::FrenchINQuotes);
149 translator.addPair(string_quotes_style[11], InsetQuotesParams::RussianQuotes);
150 translator.addPair(string_quotes_style[12], InsetQuotesParams::CJKQuotes);
151 translator.addPair(string_quotes_style[13], InsetQuotesParams::CJKAngleQuotes);
156 QuotesStyleTranslator const & quotesstyletranslator()
158 static QuotesStyleTranslator const translator =
159 init_quotesstyletranslator();
165 typedef Translator<string, PAPER_SIZE> PaperSizeTranslator;
168 static PaperSizeTranslator initPaperSizeTranslator()
170 PaperSizeTranslator translator(string_papersize[0], PAPER_DEFAULT);
171 translator.addPair(string_papersize[1], PAPER_CUSTOM);
172 translator.addPair(string_papersize[2], PAPER_USLETTER);
173 translator.addPair(string_papersize[3], PAPER_USLEGAL);
174 translator.addPair(string_papersize[4], PAPER_USEXECUTIVE);
175 translator.addPair(string_papersize[5], PAPER_A0);
176 translator.addPair(string_papersize[6], PAPER_A1);
177 translator.addPair(string_papersize[7], PAPER_A2);
178 translator.addPair(string_papersize[8], PAPER_A3);
179 translator.addPair(string_papersize[9], PAPER_A4);
180 translator.addPair(string_papersize[10], PAPER_A5);
181 translator.addPair(string_papersize[11], PAPER_A6);
182 translator.addPair(string_papersize[12], PAPER_B0);
183 translator.addPair(string_papersize[13], PAPER_B1);
184 translator.addPair(string_papersize[14], PAPER_B2);
185 translator.addPair(string_papersize[15], PAPER_B3);
186 translator.addPair(string_papersize[16], PAPER_B4);
187 translator.addPair(string_papersize[17], PAPER_B5);
188 translator.addPair(string_papersize[18], PAPER_B6);
189 translator.addPair(string_papersize[19], PAPER_C0);
190 translator.addPair(string_papersize[20], PAPER_C1);
191 translator.addPair(string_papersize[21], PAPER_C2);
192 translator.addPair(string_papersize[22], PAPER_C3);
193 translator.addPair(string_papersize[23], PAPER_C4);
194 translator.addPair(string_papersize[24], PAPER_C5);
195 translator.addPair(string_papersize[25], PAPER_C6);
196 translator.addPair(string_papersize[26], PAPER_JISB0);
197 translator.addPair(string_papersize[27], PAPER_JISB1);
198 translator.addPair(string_papersize[28], PAPER_JISB2);
199 translator.addPair(string_papersize[29], PAPER_JISB3);
200 translator.addPair(string_papersize[30], PAPER_JISB4);
201 translator.addPair(string_papersize[31], PAPER_JISB5);
202 translator.addPair(string_papersize[32], PAPER_JISB6);
207 PaperSizeTranslator const & papersizetranslator()
209 static PaperSizeTranslator const translator =
210 initPaperSizeTranslator();
216 typedef Translator<string, PAPER_ORIENTATION> PaperOrientationTranslator;
219 PaperOrientationTranslator const init_paperorientationtranslator()
221 PaperOrientationTranslator translator(string_orientation[0], ORIENTATION_PORTRAIT);
222 translator.addPair(string_orientation[1], ORIENTATION_LANDSCAPE);
227 PaperOrientationTranslator const & paperorientationtranslator()
229 static PaperOrientationTranslator const translator =
230 init_paperorientationtranslator();
236 typedef Translator<int, PageSides> SidesTranslator;
239 SidesTranslator const init_sidestranslator()
241 SidesTranslator translator(1, OneSide);
242 translator.addPair(2, TwoSides);
247 SidesTranslator const & sidestranslator()
249 static SidesTranslator const translator = init_sidestranslator();
255 typedef Translator<int, BufferParams::Package> PackageTranslator;
258 PackageTranslator const init_packagetranslator()
260 PackageTranslator translator(0, BufferParams::package_off);
261 translator.addPair(1, BufferParams::package_auto);
262 translator.addPair(2, BufferParams::package_on);
267 PackageTranslator const & packagetranslator()
269 static PackageTranslator const translator =
270 init_packagetranslator();
276 typedef Translator<string, Spacing::Space> SpaceTranslator;
279 SpaceTranslator const init_spacetranslator()
281 SpaceTranslator translator("default", Spacing::Default);
282 translator.addPair("single", Spacing::Single);
283 translator.addPair("onehalf", Spacing::Onehalf);
284 translator.addPair("double", Spacing::Double);
285 translator.addPair("other", Spacing::Other);
290 SpaceTranslator const & spacetranslator()
292 static SpaceTranslator const translator = init_spacetranslator();
297 bool inSystemDir(FileName const & document_dir, string & system_dir)
299 // A document is assumed to be in a system LyX directory (not
300 // necessarily the system directory of the running instance)
301 // if both "configure.py" and "chkconfig.ltx" are found in
302 // either document_dir/../ or document_dir/../../.
303 // If true, the system directory path is returned in system_dir
304 // with a trailing path separator.
306 string const msg = "Checking whether document is in a system dir...";
308 string dir = document_dir.absFileName();
310 for (int i = 0; i < 3; ++i) {
311 dir = addPath(dir, "..");
312 if (!fileSearch(dir, "configure.py").empty() &&
313 !fileSearch(dir, "chkconfig.ltx").empty()) {
314 LYXERR(Debug::FILES, msg << " yes");
315 system_dir = addPath(FileName(dir).realPath(), "");
320 LYXERR(Debug::FILES, msg << " no");
321 system_dir = string();
328 class BufferParams::Impl
333 AuthorList authorlist;
334 BranchList branchlist;
335 Bullet temp_bullets[4];
336 Bullet user_defined_bullets[4];
337 IndicesList indiceslist;
341 /** This is the amount of space used for paragraph_separation "skip",
342 * and for detached paragraphs in "indented" documents.
345 PDFOptions pdfoptions;
346 LayoutFileIndex baseClass_;
347 FormatList exportableFormatList;
348 FormatList viewableFormatList;
349 bool isViewCacheValid;
350 bool isExportCacheValid;
354 BufferParams::Impl::Impl()
355 : defskip(VSpace::MEDSKIP), baseClass_(string("")),
356 isViewCacheValid(false), isExportCacheValid(false)
358 // set initial author
360 authorlist.record(Author(from_utf8(lyxrc.user_name), from_utf8(lyxrc.user_email)));
365 BufferParams::MemoryTraits::clone(BufferParams::Impl const * ptr)
368 return new BufferParams::Impl(*ptr);
372 void BufferParams::MemoryTraits::destroy(BufferParams::Impl * ptr)
378 BufferParams::BufferParams()
381 setBaseClass(defaultBaseclass());
382 cite_engine_ = "basic";
383 cite_engine_type_ = ENGINE_TYPE_DEFAULT;
385 paragraph_separation = ParagraphIndentSeparation;
386 is_math_indent = false;
387 math_numbering_side = DEFAULT;
388 quotes_style = InsetQuotesParams::EnglishQuotes;
389 dynamic_quotes = false;
390 fontsize = "default";
393 papersize = PAPER_DEFAULT;
394 orientation = ORIENTATION_PORTRAIT;
395 use_geometry = false;
396 biblio_style = string();
397 use_bibtopic = false;
400 save_transient_properties = true;
401 track_changes = false;
402 output_changes = false;
403 use_default_options = true;
404 maintain_unincluded_children = false;
407 language = default_language;
409 fonts_roman[0] = "default";
410 fonts_roman[1] = "default";
411 fonts_sans[0] = "default";
412 fonts_sans[1] = "default";
413 fonts_typewriter[0] = "default";
414 fonts_typewriter[1] = "default";
415 fonts_math[0] = "auto";
416 fonts_math[1] = "auto";
417 fonts_default_family = "default";
418 useNonTeXFonts = false;
419 use_microtype = false;
420 use_dash_ligatures = true;
421 fonts_expert_sc = false;
422 fonts_roman_osf = false;
423 fonts_sans_osf = false;
424 fonts_typewriter_osf = false;
425 fonts_sans_scale[0] = 100;
426 fonts_sans_scale[1] = 100;
427 fonts_typewriter_scale[0] = 100;
428 fonts_typewriter_scale[1] = 100;
430 lang_package = "default";
431 graphics_driver = "default";
432 default_output_format = "default";
433 bibtex_command = "default";
434 index_command = "default";
437 listings_params = string();
438 pagestyle = "default";
439 tablestyle = "default";
440 suppress_date = false;
441 justification = true;
442 // no color is the default (white)
443 backgroundcolor = lyx::rgbFromHexName("#ffffff");
444 isbackgroundcolor = false;
445 // no color is the default (black)
446 fontcolor = lyx::rgbFromHexName("#000000");
448 // light gray is the default font color for greyed-out notes
449 notefontcolor = lyx::rgbFromHexName("#cccccc");
450 boxbgcolor = lyx::rgbFromHexName("#ff0000");
451 compressed = lyxrc.save_compressed;
452 for (int iter = 0; iter < 4; ++iter) {
453 user_defined_bullet(iter) = ITEMIZE_DEFAULTS[iter];
454 temp_bullet(iter) = ITEMIZE_DEFAULTS[iter];
457 indiceslist().addDefault(B_("Index"));
458 html_be_strict = false;
459 html_math_output = MathML;
460 html_math_img_scale = 1.0;
461 html_css_as_file = false;
462 display_pixel_ratio = 1.0;
464 shell_escape = false;
470 // map current author
471 author_map_[pimpl_->authorlist.get(0).bufferId()] = 0;
475 docstring BufferParams::B_(string const & l10n) const
477 LASSERT(language, return from_utf8(l10n));
478 return getMessages(language->code()).get(l10n);
482 BufferParams::Package BufferParams::use_package(std::string const & p) const
484 PackageMap::const_iterator it = use_packages.find(p);
485 if (it == use_packages.end())
491 void BufferParams::use_package(std::string const & p, BufferParams::Package u)
497 map<string, string> const & BufferParams::auto_packages()
499 static map<string, string> packages;
500 if (packages.empty()) {
501 // We could have a race condition here that two threads
502 // discover an empty map at the same time and want to fill
503 // it, but that is no problem, since the same contents is
504 // filled in twice then. Having the locker inside the
505 // packages.empty() condition has the advantage that we
506 // don't need the mutex overhead for simple reading.
508 Mutex::Locker locker(&mutex);
509 // adding a package here implies a file format change!
510 packages["amsmath"] =
511 N_("The LaTeX package amsmath is only used if AMS formula types or symbols from the AMS math toolbars are inserted into formulas");
512 packages["amssymb"] =
513 N_("The LaTeX package amssymb is only used if symbols from the AMS math toolbars are inserted into formulas");
515 N_("The LaTeX package cancel is only used if \\cancel commands are used in formulas");
517 N_("The LaTeX package esint is only used if special integral symbols are inserted into formulas");
518 packages["mathdots"] =
519 N_("The LaTeX package mathdots is only used if the command \\iddots is inserted into formulas");
520 packages["mathtools"] =
521 N_("The LaTeX package mathtools is only used if some mathematical relations are inserted into formulas");
523 N_("The LaTeX package mhchem is only used if either the command \\ce or \\cf is inserted into formulas");
524 packages["stackrel"] =
525 N_("The LaTeX package stackrel is only used if the command \\stackrel with subscript is inserted into formulas");
526 packages["stmaryrd"] =
527 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");
528 packages["undertilde"] =
529 N_("The LaTeX package undertilde is only used if you use the math frame decoration 'utilde'");
535 bool BufferParams::useBibtopic() const
539 return (use_bibtopic || (!multibib.empty() && multibib != "child"));
543 AuthorList & BufferParams::authors()
545 return pimpl_->authorlist;
549 AuthorList const & BufferParams::authors() const
551 return pimpl_->authorlist;
555 void BufferParams::addAuthor(Author a)
557 author_map_[a.bufferId()] = pimpl_->authorlist.record(a);
561 BranchList & BufferParams::branchlist()
563 return pimpl_->branchlist;
567 BranchList const & BufferParams::branchlist() const
569 return pimpl_->branchlist;
573 IndicesList & BufferParams::indiceslist()
575 return pimpl_->indiceslist;
579 IndicesList const & BufferParams::indiceslist() const
581 return pimpl_->indiceslist;
585 Bullet & BufferParams::temp_bullet(lyx::size_type const index)
587 LASSERT(index < 4, return pimpl_->temp_bullets[0]);
588 return pimpl_->temp_bullets[index];
592 Bullet const & BufferParams::temp_bullet(lyx::size_type const index) const
594 LASSERT(index < 4, return pimpl_->temp_bullets[0]);
595 return pimpl_->temp_bullets[index];
599 Bullet & BufferParams::user_defined_bullet(lyx::size_type const index)
601 LASSERT(index < 4, return pimpl_->temp_bullets[0]);
602 return pimpl_->user_defined_bullets[index];
606 Bullet const & BufferParams::user_defined_bullet(lyx::size_type const index) const
608 LASSERT(index < 4, return pimpl_->temp_bullets[0]);
609 return pimpl_->user_defined_bullets[index];
613 Spacing & BufferParams::spacing()
615 return pimpl_->spacing;
619 Spacing const & BufferParams::spacing() const
621 return pimpl_->spacing;
625 PDFOptions & BufferParams::pdfoptions()
627 return pimpl_->pdfoptions;
631 PDFOptions const & BufferParams::pdfoptions() const
633 return pimpl_->pdfoptions;
637 Length const & BufferParams::getMathIndent() const
639 return pimpl_->mathindent;
643 void BufferParams::setMathIndent(Length const & indent)
645 pimpl_->mathindent = indent;
649 Length const & BufferParams::getParIndent() const
651 return pimpl_->parindent;
655 void BufferParams::setParIndent(Length const & indent)
657 pimpl_->parindent = indent;
661 VSpace const & BufferParams::getDefSkip() const
663 return pimpl_->defskip;
667 void BufferParams::setDefSkip(VSpace const & vs)
669 // DEFSKIP will cause an infinite loop
670 LASSERT(vs.kind() != VSpace::DEFSKIP, return);
671 pimpl_->defskip = vs;
675 BufferParams::MathNumber BufferParams::getMathNumber() const
677 if (math_numbering_side != DEFAULT)
678 return math_numbering_side;
679 // FIXME: do not hardcode language here
680 else if (language->lang() == "arabic_arabi"
681 || documentClass().provides("leqno"))
688 string BufferParams::readToken(Lexer & lex, string const & token,
689 FileName const & filepath)
693 if (token == "\\textclass") {
695 string const classname = lex.getString();
696 // if there exists a local layout file, ignore the system one
697 // NOTE: in this case, the textclass (.cls file) is assumed to
700 LayoutFileList & bcl = LayoutFileList::get();
701 if (!filepath.empty()) {
702 // If classname is an absolute path, the document is
703 // using a local layout file which could not be accessed
704 // by a relative path. In this case the path is correct
705 // even if the document was moved to a different
706 // location. However, we will have a problem if the
707 // document was generated on a different platform.
708 bool isabsolute = FileName::isAbsolute(classname);
709 string const classpath = onlyPath(classname);
710 string const path = isabsolute ? classpath
711 : FileName(addPath(filepath.absFileName(),
712 classpath)).realPath();
713 string const oldpath = isabsolute ? string()
714 : FileName(addPath(origin, classpath)).realPath();
715 tcp = bcl.addLocalLayout(onlyFileName(classname), path, oldpath);
717 // that returns non-empty if a "local" layout file is found.
719 result = to_utf8(makeRelPath(from_utf8(onlyPath(tcp)),
720 from_utf8(filepath.absFileName())));
723 setBaseClass(onlyFileName(tcp));
725 setBaseClass(onlyFileName(classname));
726 // We assume that a tex class exists for local or unknown
727 // layouts so this warning, will only be given for system layouts.
728 if (!baseClass()->isTeXClassAvailable()) {
729 docstring const desc =
730 translateIfPossible(from_utf8(baseClass()->description()));
731 docstring const prereqs =
732 from_utf8(baseClass()->prerequisites());
733 docstring const msg =
734 bformat(_("The selected document class\n"
736 "requires external files that are not available.\n"
737 "The document class can still be used, but the\n"
738 "document cannot be compiled until the following\n"
739 "prerequisites are installed:\n"
741 "See section 3.1.2.2 (Class Availability) of the\n"
742 "User's Guide for more information."), desc, prereqs);
743 frontend::Alert::warning(_("Document class not available"),
746 } else if (token == "\\save_transient_properties") {
747 lex >> save_transient_properties;
748 } else if (token == "\\origin") {
750 origin = lex.getString();
751 string const sysdirprefix = "/systemlyxdir/";
752 if (prefixIs(origin, sysdirprefix)) {
754 if (inSystemDir(filepath, docsys))
755 origin.replace(0, sysdirprefix.length() - 1, docsys);
757 origin.replace(0, sysdirprefix.length() - 1,
758 package().system_support().absFileName());
760 } else if (token == "\\begin_preamble") {
762 } else if (token == "\\begin_local_layout") {
763 readLocalLayout(lex, false);
764 } else if (token == "\\begin_forced_local_layout") {
765 readLocalLayout(lex, true);
766 } else if (token == "\\begin_modules") {
768 } else if (token == "\\begin_removed_modules") {
769 readRemovedModules(lex);
770 } else if (token == "\\begin_includeonly") {
771 readIncludeonly(lex);
772 } else if (token == "\\maintain_unincluded_children") {
773 lex >> maintain_unincluded_children;
774 } else if (token == "\\options") {
776 options = lex.getString();
777 } else if (token == "\\use_default_options") {
778 lex >> use_default_options;
779 } else if (token == "\\master") {
781 master = lex.getString();
782 if (!filepath.empty() && FileName::isAbsolute(origin)) {
783 bool const isabs = FileName::isAbsolute(master);
784 FileName const abspath(isabs ? master : origin + master);
785 bool const moved = filepath != FileName(origin);
786 if (moved && abspath.exists()) {
787 docstring const path = isabs
789 : from_utf8(abspath.realPath());
790 docstring const refpath =
791 from_utf8(filepath.absFileName());
792 master = to_utf8(makeRelPath(path, refpath));
795 } else if (token == "\\suppress_date") {
796 lex >> suppress_date;
797 } else if (token == "\\justification") {
798 lex >> justification;
799 } else if (token == "\\language") {
801 } else if (token == "\\language_package") {
803 lang_package = lex.getString();
804 } else if (token == "\\inputencoding") {
806 } else if (token == "\\graphics") {
807 readGraphicsDriver(lex);
808 } else if (token == "\\default_output_format") {
809 lex >> default_output_format;
810 } else if (token == "\\bibtex_command") {
812 bibtex_command = lex.getString();
813 } else if (token == "\\index_command") {
815 index_command = lex.getString();
816 } else if (token == "\\fontencoding") {
818 fontenc = lex.getString();
819 } else if (token == "\\font_roman") {
820 lex >> fonts_roman[0];
821 lex >> fonts_roman[1];
822 } else if (token == "\\font_sans") {
823 lex >> fonts_sans[0];
824 lex >> fonts_sans[1];
825 } else if (token == "\\font_typewriter") {
826 lex >> fonts_typewriter[0];
827 lex >> fonts_typewriter[1];
828 } else if (token == "\\font_math") {
829 lex >> fonts_math[0];
830 lex >> fonts_math[1];
831 } else if (token == "\\font_default_family") {
832 lex >> fonts_default_family;
833 } else if (token == "\\use_non_tex_fonts") {
834 lex >> useNonTeXFonts;
835 } else if (token == "\\font_sc") {
836 lex >> fonts_expert_sc;
837 } else if (token == "\\font_roman_osf") {
838 lex >> fonts_roman_osf;
839 } else if (token == "\\font_sans_osf") {
840 lex >> fonts_sans_osf;
841 } else if (token == "\\font_typewriter_osf") {
842 lex >> fonts_typewriter_osf;
843 } else if (token == "\\font_roman_opts") {
844 lex >> font_roman_opts;
845 } else if (token == "\\font_sf_scale") {
846 lex >> fonts_sans_scale[0];
847 lex >> fonts_sans_scale[1];
848 } else if (token == "\\font_sans_opts") {
849 lex >> font_sans_opts;
850 } else if (token == "\\font_tt_scale") {
851 lex >> fonts_typewriter_scale[0];
852 lex >> fonts_typewriter_scale[1];
853 } else if (token == "\\font_typewriter_opts") {
854 lex >> font_typewriter_opts;
855 } else if (token == "\\font_cjk") {
857 } else if (token == "\\use_microtype") {
858 lex >> use_microtype;
859 } else if (token == "\\use_dash_ligatures") {
860 lex >> use_dash_ligatures;
861 } else if (token == "\\paragraph_separation") {
864 paragraph_separation = parseptranslator().find(parsep);
865 } else if (token == "\\paragraph_indentation") {
867 string parindent = lex.getString();
868 if (parindent == "default")
869 pimpl_->parindent = Length();
871 pimpl_->parindent = Length(parindent);
872 } else if (token == "\\defskip") {
874 string const defskip = lex.getString();
875 pimpl_->defskip = VSpace(defskip);
876 if (pimpl_->defskip.kind() == VSpace::DEFSKIP)
878 pimpl_->defskip = VSpace(VSpace::MEDSKIP);
879 } else if (token == "\\is_math_indent") {
880 lex >> is_math_indent;
881 } else if (token == "\\math_indentation") {
883 string mathindent = lex.getString();
884 if (mathindent == "default")
885 pimpl_->mathindent = Length();
887 pimpl_->mathindent = Length(mathindent);
888 } else if (token == "\\math_numbering_side") {
892 math_numbering_side = LEFT;
893 else if (tmp == "right")
894 math_numbering_side = RIGHT;
896 math_numbering_side = DEFAULT;
897 } else if (token == "\\quotes_style") {
900 quotes_style = quotesstyletranslator().find(qstyle);
901 } else if (token == "\\dynamic_quotes") {
902 lex >> dynamic_quotes;
903 } else if (token == "\\papersize") {
906 papersize = papersizetranslator().find(ppsize);
907 } else if (token == "\\use_geometry") {
909 } else if (token == "\\use_package") {
914 use_package(package, packagetranslator().find(use));
915 } else if (token == "\\cite_engine") {
917 cite_engine_ = lex.getString();
918 } else if (token == "\\cite_engine_type") {
921 cite_engine_type_ = theCiteEnginesList.getType(engine_type);
922 } else if (token == "\\biblio_style") {
924 biblio_style = lex.getString();
925 } else if (token == "\\biblio_options") {
927 biblio_opts = trim(lex.getString());
928 } else if (token == "\\biblatex_bibstyle") {
930 biblatex_bibstyle = trim(lex.getString());
931 } else if (token == "\\biblatex_citestyle") {
933 biblatex_citestyle = trim(lex.getString());
934 } else if (token == "\\use_bibtopic") {
936 } else if (token == "\\multibib") {
938 } else if (token == "\\use_indices") {
940 } else if (token == "\\tracking_changes") {
941 lex >> track_changes;
942 } else if (token == "\\output_changes") {
943 lex >> output_changes;
944 } else if (token == "\\branch") {
946 docstring branch = lex.getDocString();
947 branchlist().add(branch);
950 string const tok = lex.getString();
951 if (tok == "\\end_branch")
953 Branch * branch_ptr = branchlist().find(branch);
954 if (tok == "\\selected") {
957 branch_ptr->setSelected(lex.getInteger());
959 if (tok == "\\filename_suffix") {
962 branch_ptr->setFileNameSuffix(lex.getInteger());
964 if (tok == "\\color") {
966 string color = lex.getString();
968 branch_ptr->setColor(color);
969 // Update also the Color table:
971 color = lcolor.getX11Name(Color_background);
973 lcolor.setColor(to_utf8(branch), color);
976 } else if (token == "\\index") {
978 docstring index = lex.getDocString();
980 indiceslist().add(index);
983 string const tok = lex.getString();
984 if (tok == "\\end_index")
986 Index * index_ptr = indiceslist().find(index);
987 if (tok == "\\shortcut") {
989 shortcut = lex.getDocString();
991 index_ptr->setShortcut(shortcut);
993 if (tok == "\\color") {
995 string color = lex.getString();
997 index_ptr->setColor(color);
998 // Update also the Color table:
1000 color = lcolor.getX11Name(Color_background);
1002 if (!shortcut.empty())
1003 lcolor.setColor(to_utf8(shortcut), color);
1006 } else if (token == "\\author") {
1008 istringstream ss(lex.getString());
1012 } else if (token == "\\paperorientation") {
1015 orientation = paperorientationtranslator().find(orient);
1016 } else if (token == "\\backgroundcolor") {
1018 backgroundcolor = lyx::rgbFromHexName(lex.getString());
1019 isbackgroundcolor = true;
1020 } else if (token == "\\fontcolor") {
1022 fontcolor = lyx::rgbFromHexName(lex.getString());
1024 } else if (token == "\\notefontcolor") {
1026 string color = lex.getString();
1027 notefontcolor = lyx::rgbFromHexName(color);
1028 lcolor.setColor("notefontcolor", color);
1029 } else if (token == "\\boxbgcolor") {
1031 string color = lex.getString();
1032 boxbgcolor = lyx::rgbFromHexName(color);
1033 lcolor.setColor("boxbgcolor", color);
1034 } else if (token == "\\paperwidth") {
1036 } else if (token == "\\paperheight") {
1038 } else if (token == "\\leftmargin") {
1040 } else if (token == "\\topmargin") {
1042 } else if (token == "\\rightmargin") {
1044 } else if (token == "\\bottommargin") {
1045 lex >> bottommargin;
1046 } else if (token == "\\headheight") {
1048 } else if (token == "\\headsep") {
1050 } else if (token == "\\footskip") {
1052 } else if (token == "\\columnsep") {
1054 } else if (token == "\\paperfontsize") {
1056 } else if (token == "\\papercolumns") {
1058 } else if (token == "\\listings_params") {
1061 listings_params = InsetListingsParams(par).params();
1062 } else if (token == "\\papersides") {
1065 sides = sidestranslator().find(psides);
1066 } else if (token == "\\paperpagestyle") {
1068 } else if (token == "\\tablestyle") {
1070 } else if (token == "\\bullet") {
1072 } else if (token == "\\bulletLaTeX") {
1073 readBulletsLaTeX(lex);
1074 } else if (token == "\\secnumdepth") {
1076 } else if (token == "\\tocdepth") {
1078 } else if (token == "\\spacing") {
1082 if (nspacing == "other") {
1085 spacing().set(spacetranslator().find(nspacing), tmp_val);
1086 } else if (token == "\\float_placement") {
1087 lex >> float_placement;
1088 } else if (token == "\\float_alignment") {
1089 lex >> float_alignment;
1091 } else if (prefixIs(token, "\\pdf_") || token == "\\use_hyperref") {
1092 string toktmp = pdfoptions().readToken(lex, token);
1093 if (!toktmp.empty()) {
1094 lyxerr << "PDFOptions::readToken(): Unknown token: " <<
1098 } else if (token == "\\html_math_output") {
1101 html_math_output = static_cast<MathOutput>(temp);
1102 } else if (token == "\\html_be_strict") {
1103 lex >> html_be_strict;
1104 } else if (token == "\\html_css_as_file") {
1105 lex >> html_css_as_file;
1106 } else if (token == "\\html_math_img_scale") {
1107 lex >> html_math_img_scale;
1108 } else if (token == "\\html_latex_start") {
1110 html_latex_start = lex.getString();
1111 } else if (token == "\\html_latex_end") {
1113 html_latex_end = lex.getString();
1114 } else if (token == "\\output_sync") {
1116 } else if (token == "\\output_sync_macro") {
1117 lex >> output_sync_macro;
1118 } else if (token == "\\use_refstyle") {
1119 lex >> use_refstyle;
1120 } else if (token == "\\use_minted") {
1122 } else if (token == "\\use_lineno") {
1124 } else if (token == "\\lineno_options") {
1126 lineno_opts = trim(lex.getString());
1128 lyxerr << "BufferParams::readToken(): Unknown token: " <<
1138 // Quote argument if it contains spaces
1139 string quoteIfNeeded(string const & str) {
1140 if (contains(str, ' '))
1141 return "\"" + str + "\"";
1147 void BufferParams::writeFile(ostream & os, Buffer const * buf) const
1149 // The top of the file is written by the buffer.
1150 // Prints out the buffer info into the .lyx file given by file
1152 os << "\\save_transient_properties "
1153 << convert<string>(save_transient_properties) << '\n';
1155 // the document directory (must end with a path separator)
1156 // realPath() is used to resolve symlinks, while addPath(..., "")
1157 // ensures a trailing path separator.
1159 string filepath = addPath(buf->fileName().onlyPath().realPath(), "");
1160 string const sysdir = inSystemDir(FileName(filepath), docsys) ? docsys
1161 : addPath(package().system_support().realPath(), "");
1162 string const relpath =
1163 to_utf8(makeRelPath(from_utf8(filepath), from_utf8(sysdir)));
1164 if (!prefixIs(relpath, "../") && !FileName::isAbsolute(relpath))
1165 filepath = addPath("/systemlyxdir", relpath);
1166 else if (!save_transient_properties || !lyxrc.save_origin)
1167 filepath = "unavailable";
1168 os << "\\origin " << quoteIfNeeded(filepath) << '\n';
1171 os << "\\textclass "
1172 << quoteIfNeeded(buf->includedFilePath(addName(buf->layoutPos(),
1173 baseClass()->name()), "layout"))
1176 // then the preamble
1177 if (!preamble.empty()) {
1178 // remove '\n' from the end of preamble
1179 docstring const tmppreamble = rtrim(preamble, "\n");
1180 os << "\\begin_preamble\n"
1181 << to_utf8(tmppreamble)
1182 << "\n\\end_preamble\n";
1186 if (!options.empty()) {
1187 os << "\\options " << options << '\n';
1190 // use the class options defined in the layout?
1191 os << "\\use_default_options "
1192 << convert<string>(use_default_options) << "\n";
1194 // the master document
1195 if (!master.empty()) {
1196 os << "\\master " << master << '\n';
1200 if (!removed_modules_.empty()) {
1201 os << "\\begin_removed_modules" << '\n';
1202 list<string>::const_iterator it = removed_modules_.begin();
1203 list<string>::const_iterator en = removed_modules_.end();
1204 for (; it != en; ++it)
1206 os << "\\end_removed_modules" << '\n';
1210 if (!layout_modules_.empty()) {
1211 os << "\\begin_modules" << '\n';
1212 LayoutModuleList::const_iterator it = layout_modules_.begin();
1213 LayoutModuleList::const_iterator en = layout_modules_.end();
1214 for (; it != en; ++it)
1216 os << "\\end_modules" << '\n';
1220 if (!included_children_.empty()) {
1221 os << "\\begin_includeonly" << '\n';
1222 list<string>::const_iterator it = included_children_.begin();
1223 list<string>::const_iterator en = included_children_.end();
1224 for (; it != en; ++it)
1226 os << "\\end_includeonly" << '\n';
1228 os << "\\maintain_unincluded_children "
1229 << convert<string>(maintain_unincluded_children) << '\n';
1231 // local layout information
1232 docstring const local_layout = getLocalLayout(false);
1233 if (!local_layout.empty()) {
1234 // remove '\n' from the end
1235 docstring const tmplocal = rtrim(local_layout, "\n");
1236 os << "\\begin_local_layout\n"
1237 << to_utf8(tmplocal)
1238 << "\n\\end_local_layout\n";
1240 docstring const forced_local_layout = getLocalLayout(true);
1241 if (!forced_local_layout.empty()) {
1242 // remove '\n' from the end
1243 docstring const tmplocal = rtrim(forced_local_layout, "\n");
1244 os << "\\begin_forced_local_layout\n"
1245 << to_utf8(tmplocal)
1246 << "\n\\end_forced_local_layout\n";
1249 // then the text parameters
1250 if (language != ignore_language)
1251 os << "\\language " << language->lang() << '\n';
1252 os << "\\language_package " << lang_package
1253 << "\n\\inputencoding " << inputenc
1254 << "\n\\fontencoding " << fontenc
1255 << "\n\\font_roman \"" << fonts_roman[0]
1256 << "\" \"" << fonts_roman[1] << '"'
1257 << "\n\\font_sans \"" << fonts_sans[0]
1258 << "\" \"" << fonts_sans[1] << '"'
1259 << "\n\\font_typewriter \"" << fonts_typewriter[0]
1260 << "\" \"" << fonts_typewriter[1] << '"'
1261 << "\n\\font_math \"" << fonts_math[0]
1262 << "\" \"" << fonts_math[1] << '"'
1263 << "\n\\font_default_family " << fonts_default_family
1264 << "\n\\use_non_tex_fonts " << convert<string>(useNonTeXFonts)
1265 << "\n\\font_sc " << convert<string>(fonts_expert_sc)
1266 << "\n\\font_roman_osf " << convert<string>(fonts_roman_osf)
1267 << "\n\\font_sans_osf " << convert<string>(fonts_sans_osf)
1268 << "\n\\font_typewriter_osf " << convert<string>(fonts_typewriter_osf);
1269 if (!font_roman_opts.empty())
1270 os << "\n\\font_roman_opts \"" << font_roman_opts << "\"";
1271 os << "\n\\font_sf_scale " << fonts_sans_scale[0]
1272 << ' ' << fonts_sans_scale[1];
1273 if (!font_sans_opts.empty())
1274 os << "\n\\font_sans_opts \"" << font_sans_opts << "\"";
1275 os << "\n\\font_tt_scale " << fonts_typewriter_scale[0]
1276 << ' ' << fonts_typewriter_scale[1];
1277 if (!font_typewriter_opts.empty())
1278 os << "\n\\font_typewriter_opts \"" << font_typewriter_opts << "\"";
1280 if (!fonts_cjk.empty())
1281 os << "\\font_cjk " << fonts_cjk << '\n';
1282 os << "\\use_microtype " << convert<string>(use_microtype) << '\n';
1283 os << "\\use_dash_ligatures " << convert<string>(use_dash_ligatures) << '\n';
1284 os << "\\graphics " << graphics_driver << '\n';
1285 os << "\\default_output_format " << default_output_format << '\n';
1286 os << "\\output_sync " << output_sync << '\n';
1287 if (!output_sync_macro.empty())
1288 os << "\\output_sync_macro \"" << output_sync_macro << "\"\n";
1289 os << "\\bibtex_command " << bibtex_command << '\n';
1290 os << "\\index_command " << index_command << '\n';
1292 if (!float_placement.empty())
1293 os << "\\float_placement " << float_placement << '\n';
1294 if (!float_alignment.empty())
1295 os << "\\float_alignment " << float_alignment << '\n';
1296 os << "\\paperfontsize " << fontsize << '\n';
1298 spacing().writeFile(os);
1299 pdfoptions().writeFile(os);
1301 os << "\\papersize " << string_papersize[papersize]
1302 << "\n\\use_geometry " << convert<string>(use_geometry);
1303 map<string, string> const & packages = auto_packages();
1304 for (map<string, string>::const_iterator it = packages.begin();
1305 it != packages.end(); ++it)
1306 os << "\n\\use_package " << it->first << ' '
1307 << use_package(it->first);
1309 os << "\n\\cite_engine ";
1311 if (!cite_engine_.empty())
1316 os << "\n\\cite_engine_type " << theCiteEnginesList.getTypeAsString(cite_engine_type_);
1318 if (!biblio_style.empty())
1319 os << "\n\\biblio_style " << biblio_style;
1320 if (!biblio_opts.empty())
1321 os << "\n\\biblio_options " << biblio_opts;
1322 if (!biblatex_bibstyle.empty())
1323 os << "\n\\biblatex_bibstyle " << biblatex_bibstyle;
1324 if (!biblatex_citestyle.empty())
1325 os << "\n\\biblatex_citestyle " << biblatex_citestyle;
1326 if (!multibib.empty())
1327 os << "\n\\multibib " << multibib;
1329 os << "\n\\use_bibtopic " << convert<string>(use_bibtopic)
1330 << "\n\\use_indices " << convert<string>(use_indices)
1331 << "\n\\paperorientation " << string_orientation[orientation]
1332 << "\n\\suppress_date " << convert<string>(suppress_date)
1333 << "\n\\justification " << convert<string>(justification)
1334 << "\n\\use_refstyle " << use_refstyle
1335 << "\n\\use_minted " << use_minted
1336 << "\n\\use_lineno " << use_lineno
1339 if (!lineno_opts.empty())
1340 os << "\\lineno_options " << lineno_opts << '\n';
1342 if (isbackgroundcolor == true)
1343 os << "\\backgroundcolor " << lyx::X11hexname(backgroundcolor) << '\n';
1344 if (isfontcolor == true)
1345 os << "\\fontcolor " << lyx::X11hexname(fontcolor) << '\n';
1346 if (notefontcolor != lyx::rgbFromHexName("#cccccc"))
1347 os << "\\notefontcolor " << lyx::X11hexname(notefontcolor) << '\n';
1348 if (boxbgcolor != lyx::rgbFromHexName("#ff0000"))
1349 os << "\\boxbgcolor " << lyx::X11hexname(boxbgcolor) << '\n';
1351 BranchList::const_iterator it = branchlist().begin();
1352 BranchList::const_iterator end = branchlist().end();
1353 for (; it != end; ++it) {
1354 os << "\\branch " << to_utf8(it->branch())
1355 << "\n\\selected " << it->isSelected()
1356 << "\n\\filename_suffix " << it->hasFileNameSuffix()
1357 << "\n\\color " << lyx::X11hexname(it->color())
1362 IndicesList::const_iterator iit = indiceslist().begin();
1363 IndicesList::const_iterator iend = indiceslist().end();
1364 for (; iit != iend; ++iit) {
1365 os << "\\index " << to_utf8(iit->index())
1366 << "\n\\shortcut " << to_utf8(iit->shortcut())
1367 << "\n\\color " << lyx::X11hexname(iit->color())
1372 if (!paperwidth.empty())
1373 os << "\\paperwidth "
1374 << VSpace(paperwidth).asLyXCommand() << '\n';
1375 if (!paperheight.empty())
1376 os << "\\paperheight "
1377 << VSpace(paperheight).asLyXCommand() << '\n';
1378 if (!leftmargin.empty())
1379 os << "\\leftmargin "
1380 << VSpace(leftmargin).asLyXCommand() << '\n';
1381 if (!topmargin.empty())
1382 os << "\\topmargin "
1383 << VSpace(topmargin).asLyXCommand() << '\n';
1384 if (!rightmargin.empty())
1385 os << "\\rightmargin "
1386 << VSpace(rightmargin).asLyXCommand() << '\n';
1387 if (!bottommargin.empty())
1388 os << "\\bottommargin "
1389 << VSpace(bottommargin).asLyXCommand() << '\n';
1390 if (!headheight.empty())
1391 os << "\\headheight "
1392 << VSpace(headheight).asLyXCommand() << '\n';
1393 if (!headsep.empty())
1395 << VSpace(headsep).asLyXCommand() << '\n';
1396 if (!footskip.empty())
1398 << VSpace(footskip).asLyXCommand() << '\n';
1399 if (!columnsep.empty())
1400 os << "\\columnsep "
1401 << VSpace(columnsep).asLyXCommand() << '\n';
1402 os << "\\secnumdepth " << secnumdepth
1403 << "\n\\tocdepth " << tocdepth
1404 << "\n\\paragraph_separation "
1405 << string_paragraph_separation[paragraph_separation];
1406 if (!paragraph_separation)
1407 os << "\n\\paragraph_indentation "
1408 << (getParIndent().empty() ? "default" : getParIndent().asString());
1410 os << "\n\\defskip " << getDefSkip().asLyXCommand();
1411 os << "\n\\is_math_indent " << is_math_indent;
1413 os << "\n\\math_indentation "
1414 << (getMathIndent().empty() ? "default" : getMathIndent().asString());
1415 os << "\n\\math_numbering_side ";
1416 switch(math_numbering_side) {
1426 os << "\n\\quotes_style "
1427 << string_quotes_style[quotes_style]
1428 << "\n\\dynamic_quotes " << dynamic_quotes
1429 << "\n\\papercolumns " << columns
1430 << "\n\\papersides " << sides
1431 << "\n\\paperpagestyle " << pagestyle
1432 << "\n\\tablestyle " << tablestyle << '\n';
1433 if (!listings_params.empty())
1434 os << "\\listings_params \"" <<
1435 InsetListingsParams(listings_params).encodedString() << "\"\n";
1436 for (int i = 0; i < 4; ++i) {
1437 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
1438 if (user_defined_bullet(i).getFont() != -1) {
1439 os << "\\bullet " << i << " "
1440 << user_defined_bullet(i).getFont() << " "
1441 << user_defined_bullet(i).getCharacter() << " "
1442 << user_defined_bullet(i).getSize() << "\n";
1446 os << "\\bulletLaTeX " << i << " \""
1447 << lyx::to_ascii(user_defined_bullet(i).getText())
1453 os << "\\tracking_changes "
1454 << (save_transient_properties ? convert<string>(track_changes) : "false")
1457 os << "\\output_changes "
1458 << (save_transient_properties ? convert<string>(output_changes) : "false")
1461 os << "\\html_math_output " << html_math_output << '\n'
1462 << "\\html_css_as_file " << html_css_as_file << '\n'
1463 << "\\html_be_strict " << convert<string>(html_be_strict) << '\n';
1465 if (html_math_img_scale != 1.0)
1466 os << "\\html_math_img_scale " << convert<string>(html_math_img_scale) << '\n';
1467 if (!html_latex_start.empty())
1468 os << "\\html_latex_start " << html_latex_start << '\n';
1469 if (!html_latex_end.empty())
1470 os << "\\html_latex_end " << html_latex_end << '\n';
1472 os << pimpl_->authorlist;
1476 void BufferParams::validate(LaTeXFeatures & features) const
1478 features.require(documentClass().requires());
1480 if (columns > 1 && language->rightToLeft())
1481 features.require("rtloutputdblcol");
1483 if (output_changes) {
1484 bool dvipost = LaTeXFeatures::isAvailable("dvipost");
1485 bool xcolorulem = LaTeXFeatures::isAvailable("ulem") &&
1486 LaTeXFeatures::isAvailable("xcolor");
1488 switch (features.runparams().flavor) {
1489 case OutputParams::LATEX:
1490 case OutputParams::DVILUATEX:
1492 features.require("ct-dvipost");
1493 features.require("dvipost");
1494 } else if (xcolorulem) {
1495 features.require("ct-xcolor-ulem");
1496 features.require("ulem");
1497 features.require("xcolor");
1499 features.require("ct-none");
1502 case OutputParams::LUATEX:
1503 case OutputParams::PDFLATEX:
1504 case OutputParams::XETEX:
1506 features.require("ct-xcolor-ulem");
1507 features.require("ulem");
1508 features.require("xcolor");
1509 // improves color handling in PDF output
1510 features.require("pdfcolmk");
1512 features.require("ct-none");
1520 // Floats with 'Here definitely' as default setting.
1521 if (float_placement.find('H') != string::npos)
1522 features.require("float");
1524 for (PackageMap::const_iterator it = use_packages.begin();
1525 it != use_packages.end(); ++it) {
1526 if (it->first == "amsmath") {
1527 // AMS Style is at document level
1528 if (it->second == package_on ||
1529 features.isProvided("amsmath"))
1530 features.require(it->first);
1531 } else if (it->second == package_on)
1532 features.require(it->first);
1535 // Document-level line spacing
1536 if (spacing().getSpace() != Spacing::Single && !spacing().isDefault())
1537 features.require("setspace");
1539 // the bullet shapes are buffer level not paragraph level
1540 // so they are tested here
1541 for (int i = 0; i < 4; ++i) {
1542 if (user_defined_bullet(i) == ITEMIZE_DEFAULTS[i])
1544 int const font = user_defined_bullet(i).getFont();
1546 int const c = user_defined_bullet(i).getCharacter();
1552 features.require("latexsym");
1554 } else if (font == 1) {
1555 features.require("amssymb");
1556 } else if (font >= 2 && font <= 5) {
1557 features.require("pifont");
1561 if (pdfoptions().use_hyperref) {
1562 features.require("hyperref");
1563 // due to interferences with babel and hyperref, the color package has to
1564 // be loaded after hyperref when hyperref is used with the colorlinks
1565 // option, see http://www.lyx.org/trac/ticket/5291
1566 if (pdfoptions().colorlinks)
1567 features.require("color");
1569 if (!listings_params.empty()) {
1570 // do not test validity because listings_params is
1571 // supposed to be valid
1573 InsetListingsParams(listings_params).separatedParams(true);
1574 // we can't support all packages, but we should load the color package
1575 if (par.find("\\color", 0) != string::npos)
1576 features.require("color");
1579 // some languages are only available via polyglossia
1580 if (features.hasPolyglossiaExclusiveLanguages())
1581 features.require("polyglossia");
1583 if (useNonTeXFonts && fontsMath() != "auto")
1584 features.require("unicode-math");
1587 features.require("microtype");
1589 if (!language->requires().empty())
1590 features.require(language->requires());
1594 bool BufferParams::writeLaTeX(otexstream & os, LaTeXFeatures & features,
1595 FileName const & filepath) const
1597 // http://www.tug.org/texmf-dist/doc/latex/base/fixltx2e.pdf
1598 // !! To use the Fix-cm package, load it before \documentclass, and use the command
1599 // \RequirePackage to do so, rather than the normal \usepackage
1600 // Do not try to load any other package before the document class, unless you
1601 // have a thorough understanding of the LATEX internals and know exactly what you
1603 if (features.mustProvide("fix-cm"))
1604 os << "\\RequirePackage{fix-cm}\n";
1605 // Likewise for fixltx2e. If other packages conflict with this policy,
1606 // treat it as a package bug (and report it!)
1607 // See http://www.latex-project.org/cgi-bin/ltxbugs2html?pr=latex/4407
1608 if (features.mustProvide("fixltx2e"))
1609 os << "\\RequirePackage{fixltx2e}\n";
1611 os << "\\documentclass";
1613 DocumentClass const & tclass = documentClass();
1615 ostringstream clsoptions; // the document class options.
1617 if (tokenPos(tclass.opt_fontsize(),
1618 '|', fontsize) >= 0) {
1619 // only write if existing in list (and not default)
1620 clsoptions << fontsize << "pt,";
1623 // all paper sizes except of A4, A5, B5 and the US sizes need the
1625 bool nonstandard_papersize = papersize != PAPER_DEFAULT
1626 && papersize != PAPER_USLETTER
1627 && papersize != PAPER_USLEGAL
1628 && papersize != PAPER_USEXECUTIVE
1629 && papersize != PAPER_A4
1630 && papersize != PAPER_A5
1631 && papersize != PAPER_B5;
1633 if (!use_geometry) {
1634 switch (papersize) {
1636 clsoptions << "a4paper,";
1638 case PAPER_USLETTER:
1639 clsoptions << "letterpaper,";
1642 clsoptions << "a5paper,";
1645 clsoptions << "b5paper,";
1647 case PAPER_USEXECUTIVE:
1648 clsoptions << "executivepaper,";
1651 clsoptions << "legalpaper,";
1685 if (sides != tclass.sides()) {
1688 clsoptions << "oneside,";
1691 clsoptions << "twoside,";
1697 if (columns != tclass.columns()) {
1699 clsoptions << "twocolumn,";
1701 clsoptions << "onecolumn,";
1705 && orientation == ORIENTATION_LANDSCAPE)
1706 clsoptions << "landscape,";
1709 clsoptions << "fleqn,";
1711 switch(math_numbering_side) {
1713 clsoptions << "leqno,";
1716 clsoptions << "reqno,";
1717 features.require("amsmath");
1723 // language should be a parameter to \documentclass
1724 if (language->babel() == "hebrew"
1725 && default_language->babel() != "hebrew")
1726 // This seems necessary
1727 features.useLanguage(default_language);
1729 ostringstream language_options;
1730 bool const use_babel = features.useBabel() && !features.isProvided("babel");
1731 bool const use_polyglossia = features.usePolyglossia();
1732 bool const global = lyxrc.language_global_options;
1733 if (features.useBabel() || (use_polyglossia && global)) {
1734 language_options << features.getBabelLanguages();
1735 if (!language->babel().empty()) {
1736 if (!language_options.str().empty())
1737 language_options << ',';
1738 language_options << language->babel();
1740 if (global && !language_options.str().empty())
1741 clsoptions << language_options.str() << ',';
1744 // the predefined options from the layout
1745 if (use_default_options && !tclass.options().empty())
1746 clsoptions << tclass.options() << ',';
1748 // the user-defined options
1749 if (!options.empty()) {
1750 clsoptions << options << ',';
1753 string strOptions(clsoptions.str());
1754 if (!strOptions.empty()) {
1755 strOptions = rtrim(strOptions, ",");
1757 os << '[' << from_utf8(strOptions) << ']';
1760 os << '{' << from_ascii(tclass.latexname()) << "}\n";
1761 // end of \documentclass defs
1763 // if we use fontspec or newtxmath, we have to load the AMS packages here
1764 string const ams = features.loadAMSPackages();
1765 bool const ot1 = (main_font_encoding() == "default" || main_font_encoding() == "OT1");
1766 bool const use_newtxmath =
1767 theLaTeXFonts().getLaTeXFont(from_ascii(fontsMath())).getUsedPackage(
1768 ot1, false, false) == "newtxmath";
1769 if ((useNonTeXFonts || use_newtxmath) && !ams.empty())
1770 os << from_ascii(ams);
1772 if (useNonTeXFonts) {
1773 // Babel (as of 2017/11/03) loads fontspec itself
1774 if (!features.isProvided("fontspec")
1775 && !(features.useBabel() && features.isAvailable("babel-2017/11/03")))
1776 os << "\\usepackage{fontspec}\n";
1777 if (features.mustProvide("unicode-math")
1778 && features.isAvailable("unicode-math"))
1779 os << "\\usepackage{unicode-math}\n";
1782 // load CJK support package before font selection
1783 // (see autotests/export/latex/CJK/micro-sign_utf8-cjk-libertine.lyx)
1784 if (!useNonTeXFonts && encoding().package() != Encoding::none && inputenc != "utf8x"
1785 && (encoding().package() == Encoding::CJK || features.mustProvide("CJK"))) {
1786 if (inputenc == "utf8-cjk" || inputenc == "utf8")
1787 os << "\\usepackage{CJKutf8}\n";
1789 os << "\\usepackage[encapsulated]{CJK}\n";
1792 // font selection must be done before loading fontenc.sty
1793 // but after babel with non-TeX fonts
1794 string const fonts = loadFonts(features);
1795 if (!fonts.empty() && (!features.useBabel() || !useNonTeXFonts))
1796 os << from_utf8(fonts);
1798 if (fonts_default_family != "default")
1799 os << "\\renewcommand{\\familydefault}{\\"
1800 << from_ascii(fonts_default_family) << "}\n";
1802 // set font encoding
1803 // non-TeX fonts use font encoding TU (set by fontspec)
1804 if (!useNonTeXFonts && !features.isProvided("fontenc")
1805 && main_font_encoding() != "default") {
1806 // get main font encodings
1807 vector<string> fontencs = font_encodings();
1808 // get font encodings of secondary languages
1809 // FIXME: some languages (hebrew, ...) assume a standard font encoding as last
1810 // option (for text in other languages).
1811 features.getFontEncodings(fontencs);
1812 if (!fontencs.empty()) {
1813 os << "\\usepackage["
1814 << from_ascii(getStringFromVector(fontencs))
1819 // Load textcomp and pmboxdraw before (lua)inputenc (#11454)
1820 if (features.mustProvide("textcomp"))
1821 os << "\\usepackage{textcomp}\n";
1822 if (features.mustProvide("pmboxdraw"))
1823 os << "\\usepackage{pmboxdraw}\n";
1825 // handle inputenc etc.
1826 // (In documents containing text in Thai language,
1827 // we must load inputenc after babel, see lib/languages).
1828 if (!contains(features.getBabelPostsettings(), from_ascii("thai.ldf")))
1829 writeEncodingPreamble(os, features);
1832 if (!features.runparams().includeall && !included_children_.empty()) {
1833 os << "\\includeonly{";
1834 list<string>::const_iterator it = included_children_.begin();
1835 list<string>::const_iterator en = included_children_.end();
1837 for (; it != en; ++it) {
1838 string incfile = *it;
1839 FileName inc = makeAbsPath(incfile, filepath.absFileName());
1840 string mangled = DocFileName(changeExtension(inc.absFileName(), ".tex")).
1842 if (!features.runparams().nice)
1844 // \includeonly doesn't want an extension
1845 incfile = changeExtension(incfile, string());
1846 incfile = support::latex_path(incfile);
1847 if (!incfile.empty()) {
1850 os << from_utf8(incfile);
1857 if (!features.isProvided("geometry")
1858 && (use_geometry || nonstandard_papersize)) {
1859 odocstringstream ods;
1860 if (!getGraphicsDriver("geometry").empty())
1861 ods << getGraphicsDriver("geometry");
1862 if (orientation == ORIENTATION_LANDSCAPE)
1863 ods << ",landscape";
1864 switch (papersize) {
1866 if (!paperwidth.empty())
1867 ods << ",paperwidth="
1868 << from_ascii(paperwidth);
1869 if (!paperheight.empty())
1870 ods << ",paperheight="
1871 << from_ascii(paperheight);
1873 case PAPER_USLETTER:
1874 ods << ",letterpaper";
1877 ods << ",legalpaper";
1879 case PAPER_USEXECUTIVE:
1880 ods << ",executivepaper";
1969 docstring const g_options = trim(ods.str(), ",");
1970 os << "\\usepackage";
1971 if (!g_options.empty())
1972 os << '[' << g_options << ']';
1973 os << "{geometry}\n";
1974 // output this only if use_geometry is true
1976 os << "\\geometry{verbose";
1977 if (!topmargin.empty())
1978 os << ",tmargin=" << from_ascii(Length(topmargin).asLatexString());
1979 if (!bottommargin.empty())
1980 os << ",bmargin=" << from_ascii(Length(bottommargin).asLatexString());
1981 if (!leftmargin.empty())
1982 os << ",lmargin=" << from_ascii(Length(leftmargin).asLatexString());
1983 if (!rightmargin.empty())
1984 os << ",rmargin=" << from_ascii(Length(rightmargin).asLatexString());
1985 if (!headheight.empty())
1986 os << ",headheight=" << from_ascii(Length(headheight).asLatexString());
1987 if (!headsep.empty())
1988 os << ",headsep=" << from_ascii(Length(headsep).asLatexString());
1989 if (!footskip.empty())
1990 os << ",footskip=" << from_ascii(Length(footskip).asLatexString());
1991 if (!columnsep.empty())
1992 os << ",columnsep=" << from_ascii(Length(columnsep).asLatexString());
1995 } else if (orientation == ORIENTATION_LANDSCAPE
1996 || papersize != PAPER_DEFAULT) {
1997 features.require("papersize");
2000 if (tokenPos(tclass.opt_pagestyle(), '|', pagestyle) >= 0) {
2001 if (pagestyle == "fancy")
2002 os << "\\usepackage{fancyhdr}\n";
2003 os << "\\pagestyle{" << from_ascii(pagestyle) << "}\n";
2006 // only output when the background color is not default
2007 if (isbackgroundcolor == true) {
2008 // only require color here, the background color will be defined
2009 // in LaTeXFeatures.cpp to avoid interferences with the LaTeX
2011 features.require("color");
2012 features.require("pagecolor");
2015 // only output when the font color is not default
2016 if (isfontcolor == true) {
2017 // only require color here, the font color will be defined
2018 // in LaTeXFeatures.cpp to avoid interferences with the LaTeX
2020 features.require("color");
2021 features.require("fontcolor");
2024 // Only if class has a ToC hierarchy
2025 if (tclass.hasTocLevels()) {
2026 if (secnumdepth != tclass.secnumdepth()) {
2027 os << "\\setcounter{secnumdepth}{"
2031 if (tocdepth != tclass.tocdepth()) {
2032 os << "\\setcounter{tocdepth}{"
2038 if (paragraph_separation) {
2039 // when skip separation
2040 switch (getDefSkip().kind()) {
2041 case VSpace::SMALLSKIP:
2042 os << "\\setlength{\\parskip}{\\smallskipamount}\n";
2044 case VSpace::MEDSKIP:
2045 os << "\\setlength{\\parskip}{\\medskipamount}\n";
2047 case VSpace::BIGSKIP:
2048 os << "\\setlength{\\parskip}{\\bigskipamount}\n";
2050 case VSpace::LENGTH:
2051 os << "\\setlength{\\parskip}{"
2052 << from_utf8(getDefSkip().length().asLatexString())
2055 default: // should never happen // Then delete it.
2056 os << "\\setlength{\\parskip}{\\medskipamount}\n";
2059 os << "\\setlength{\\parindent}{0pt}\n";
2061 // when separation by indentation
2062 // only output something when a width is given
2063 if (!getParIndent().empty()) {
2064 os << "\\setlength{\\parindent}{"
2065 << from_utf8(getParIndent().asLatexString())
2070 if (is_math_indent) {
2071 // when formula indentation
2072 // only output something when it is not the default
2073 if (!getMathIndent().empty()) {
2074 os << "\\setlength{\\mathindent}{"
2075 << from_utf8(getMathIndent().asString())
2080 // Now insert the LyX specific LaTeX commands...
2081 features.resolveAlternatives();
2082 features.expandMultiples();
2085 if (!output_sync_macro.empty())
2086 os << from_utf8(output_sync_macro) +"\n";
2087 else if (features.runparams().flavor == OutputParams::LATEX)
2088 os << "\\usepackage[active]{srcltx}\n";
2089 else if (features.runparams().flavor == OutputParams::PDFLATEX)
2090 os << "\\synctex=-1\n";
2093 // The package options (via \PassOptionsToPackage)
2094 os << from_ascii(features.getPackageOptions());
2096 // due to interferences with babel and hyperref, the color package has to
2097 // be loaded (when it is not already loaded) before babel when hyperref
2098 // is used with the colorlinks option, see
2099 // http://www.lyx.org/trac/ticket/5291
2100 // we decided therefore to load color always before babel, see
2101 // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg144349.html
2102 os << from_ascii(features.getColorOptions());
2104 // If we use hyperref, jurabib, japanese or varioref,
2105 // we have to call babel before
2107 && (features.isRequired("jurabib")
2108 || features.isRequired("hyperref")
2109 || features.isRequired("varioref")
2110 || features.isRequired("japanese"))) {
2111 os << features.getBabelPresettings();
2113 os << from_utf8(babelCall(language_options.str(),
2114 !lyxrc.language_global_options)) + '\n';
2115 os << features.getBabelPostsettings();
2118 // The optional packages;
2119 os << from_ascii(features.getPackages());
2121 // Additional Indices
2122 if (features.isRequired("splitidx")) {
2123 IndicesList::const_iterator iit = indiceslist().begin();
2124 IndicesList::const_iterator iend = indiceslist().end();
2125 for (; iit != iend; ++iit) {
2126 os << "\\newindex{";
2127 os << escape(iit->shortcut());
2133 os << from_utf8(spacing().writePreamble(features.isProvided("SetSpace")));
2136 // * Hyperref manual: "Make sure it comes last of your loaded
2137 // packages, to give it a fighting chance of not being over-written,
2138 // since its job is to redefine many LaTeX commands."
2139 // * Email from Heiko Oberdiek: "It is usually better to load babel
2140 // before hyperref. Then hyperref has a chance to detect babel.
2141 // * Has to be loaded before the "LyX specific LaTeX commands" to
2142 // avoid errors with algorithm floats.
2143 // use hyperref explicitly if it is required
2144 if (features.isRequired("hyperref")) {
2145 OutputParams tmp_params = features.runparams();
2146 pdfoptions().writeLaTeX(tmp_params, os,
2147 features.isProvided("hyperref"));
2148 // correctly break URLs with hyperref and dvi/ps output
2149 if (features.runparams().hyperref_driver == "dvips"
2150 && features.isAvailable("breakurl"))
2151 os << "\\usepackage{breakurl}\n";
2152 } else if (features.isRequired("nameref"))
2153 // hyperref loads this automatically
2154 os << "\\usepackage{nameref}\n";
2157 os << "\\usepackage";
2158 if (!lineno_opts.empty())
2159 os << "[" << lineno_opts << "]";
2161 os << "\\linenumbers\n";
2164 // bibtopic needs to be loaded after hyperref.
2165 // the dot provides the aux file naming which LyX can detect.
2166 if (features.mustProvide("bibtopic"))
2167 os << "\\usepackage[dot]{bibtopic}\n";
2169 // Will be surrounded by \makeatletter and \makeatother when not empty
2170 otexstringstream atlyxpreamble;
2172 // Some macros LyX will need
2174 TexString tmppreamble = features.getMacros();
2175 if (!tmppreamble.str.empty())
2176 atlyxpreamble << "\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
2177 "LyX specific LaTeX commands.\n"
2178 << move(tmppreamble)
2181 // the text class specific preamble
2183 docstring tmppreamble = features.getTClassPreamble();
2184 if (!tmppreamble.empty())
2185 atlyxpreamble << "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
2186 "Textclass specific LaTeX commands.\n"
2190 // suppress date if selected
2191 // use \@ifundefined because we cannot be sure that every document class
2192 // has a \date command
2194 atlyxpreamble << "\\@ifundefined{date}{}{\\date{}}\n";
2196 /* the user-defined preamble */
2197 if (!containsOnly(preamble, " \n\t")) {
2199 atlyxpreamble << "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
2200 "User specified LaTeX commands.\n";
2202 // Check if the user preamble contains uncodable glyphs
2203 odocstringstream user_preamble;
2204 docstring uncodable_glyphs;
2205 Encoding const * const enc = features.runparams().encoding;
2207 for (size_t n = 0; n < preamble.size(); ++n) {
2208 char_type c = preamble[n];
2209 if (!enc->encodable(c)) {
2210 docstring const glyph(1, c);
2211 LYXERR0("Uncodable character '"
2213 << "' in user preamble!");
2214 uncodable_glyphs += glyph;
2215 if (features.runparams().dryrun) {
2216 user_preamble << "<" << _("LyX Warning: ")
2217 << _("uncodable character") << " '";
2218 user_preamble.put(c);
2219 user_preamble << "'>";
2222 user_preamble.put(c);
2225 user_preamble << preamble;
2227 // On BUFFER_VIEW|UPDATE, warn user if we found uncodable glyphs
2228 if (!features.runparams().dryrun && !uncodable_glyphs.empty()) {
2229 frontend::Alert::warning(
2230 _("Uncodable character in user preamble"),
2232 _("The user preamble of your document contains glyphs "
2233 "that are unknown in the current document encoding "
2234 "(namely %1$s).\nThese glyphs are omitted "
2235 " from the output, which may result in "
2236 "incomplete output."
2237 "\n\nPlease select an appropriate "
2238 "document encoding\n"
2239 "(such as utf8) or change the "
2240 "preamble code accordingly."),
2243 atlyxpreamble << user_preamble.str() << '\n';
2246 // footmisc must be loaded after setspace
2247 // Load it here to avoid clashes with footmisc loaded in the user
2248 // preamble. For that reason we also pass the options via
2249 // \PassOptionsToPackage in getPreamble() and not here.
2250 if (features.mustProvide("footmisc"))
2251 atlyxpreamble << "\\usepackage{footmisc}\n";
2253 // subfig loads internally the LaTeX package "caption". As
2254 // caption is a very popular package, users will load it in
2255 // the preamble. Therefore we must load subfig behind the
2256 // user-defined preamble and check if the caption package was
2257 // loaded or not. For the case that caption is loaded before
2258 // subfig, there is the subfig option "caption=false". This
2259 // option also works when a koma-script class is used and
2260 // koma's own caption commands are used instead of caption. We
2261 // use \PassOptionsToPackage here because the user could have
2262 // already loaded subfig in the preamble.
2263 if (features.mustProvide("subfig"))
2264 atlyxpreamble << "\\@ifundefined{showcaptionsetup}{}{%\n"
2265 " \\PassOptionsToPackage{caption=false}{subfig}}\n"
2266 "\\usepackage{subfig}\n";
2268 // Itemize bullet settings need to be last in case the user
2269 // defines their own bullets that use a package included
2270 // in the user-defined preamble -- ARRae
2271 // Actually it has to be done much later than that
2272 // since some packages like frenchb make modifications
2273 // at \begin{document} time -- JMarc
2274 docstring bullets_def;
2275 for (int i = 0; i < 4; ++i) {
2276 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
2277 if (bullets_def.empty())
2278 bullets_def += "\\AtBeginDocument{\n";
2279 bullets_def += " \\def\\labelitemi";
2281 // `i' is one less than the item to modify
2288 bullets_def += "ii";
2294 bullets_def += '{' +
2295 user_defined_bullet(i).getText()
2300 if (!bullets_def.empty())
2301 atlyxpreamble << bullets_def << "}\n\n";
2303 if (!atlyxpreamble.empty())
2304 os << "\n\\makeatletter\n"
2305 << atlyxpreamble.release()
2306 << "\\makeatother\n\n";
2308 // We try to load babel late, in case it interferes with other packages.
2309 // Jurabib, hyperref, varioref, bicaption, menukeys and listings (bug 8995)
2310 // have to be called after babel, though.
2311 if (use_babel && !features.isRequired("jurabib")
2312 && !features.isRequired("hyperref")
2313 && !features.isRequired("varioref")
2314 && !features.isRequired("japanese")) {
2315 os << features.getBabelPresettings();
2317 os << from_utf8(babelCall(language_options.str(),
2318 !lyxrc.language_global_options)) + '\n';
2319 os << features.getBabelPostsettings();
2321 // In documents containing text in Thai language,
2322 // we must load inputenc after babel (see lib/languages).
2323 if (contains(features.getBabelPostsettings(), from_ascii("thai.ldf")))
2324 writeEncodingPreamble(os, features);
2326 // font selection must be done after babel with non-TeX fonts
2327 if (!fonts.empty() && features.useBabel() && useNonTeXFonts)
2328 os << from_utf8(fonts);
2330 if (features.isRequired("bicaption"))
2331 os << "\\usepackage{bicaption}\n";
2332 if (!listings_params.empty()
2333 || features.mustProvide("listings")
2334 || features.mustProvide("minted")) {
2336 os << "\\usepackage{minted}\n";
2338 os << "\\usepackage{listings}\n";
2340 string lst_params = listings_params;
2341 // If minted, do not output the language option (bug 11203)
2342 if (use_minted && contains(lst_params, "language=")) {
2343 vector<string> opts =
2344 getVectorFromString(lst_params, ",", false);
2345 for (size_t i = 0; i < opts.size(); ++i) {
2346 if (prefixIs(opts[i], "language="))
2347 opts.erase(opts.begin() + i--);
2349 lst_params = getStringFromVector(opts, ",");
2351 if (!lst_params.empty()) {
2353 os << "\\setminted{";
2356 // do not test validity because listings_params is
2357 // supposed to be valid
2359 InsetListingsParams(lst_params).separatedParams(true);
2360 os << from_utf8(par);
2364 // xunicode only needs to be loaded if tipa is used
2365 // (the rest is obsoleted by the new TU encoding).
2366 // It needs to be loaded at least after amsmath, amssymb,
2367 // esint and the other packages that provide special glyphs
2368 if (features.mustProvide("tipa") && useNonTeXFonts
2369 && !features.isProvided("xunicode")) {
2370 // The `xunicode` package officially only supports XeTeX,
2371 // but also works with LuaTeX. We work around its XeTeX test.
2372 if (features.runparams().flavor != OutputParams::XETEX) {
2373 os << "% Pretend to xunicode that we are XeTeX\n"
2374 << "\\def\\XeTeXpicfile{}\n";
2376 os << "\\usepackage{xunicode}\n";
2379 // covington must be loaded after beamerarticle
2380 if (features.isRequired("covington"))
2381 os << "\\usepackage{covington}\n";
2383 // Polyglossia must be loaded last ...
2384 if (use_polyglossia) {
2386 os << "\\usepackage{polyglossia}\n";
2387 // set the main language
2388 os << "\\setdefaultlanguage";
2389 if (!language->polyglossiaOpts().empty())
2390 os << "[" << from_ascii(language->polyglossiaOpts()) << "]";
2391 os << "{" << from_ascii(language->polyglossia()) << "}\n";
2392 // now setup the other languages
2393 set<string> const polylangs =
2394 features.getPolyglossiaLanguages();
2395 for (set<string>::const_iterator mit = polylangs.begin();
2396 mit != polylangs.end() ; ++mit) {
2397 // We do not output the options here; they are output in
2398 // the language switch commands. This is safer if multiple
2399 // varieties are used.
2400 if (*mit == language->polyglossia())
2402 os << "\\setotherlanguage";
2403 os << "{" << from_ascii(*mit) << "}\n";
2407 // ... but before biblatex (see #7065)
2408 if ((features.mustProvide("biblatex")
2409 || features.isRequired("biblatex-chicago"))
2410 && !features.isProvided("biblatex-chicago")
2411 && !features.isProvided("biblatex-natbib")
2412 && !features.isProvided("natbib-internal")
2413 && !features.isProvided("natbib")
2414 && !features.isProvided("jurabib")) {
2415 // The biblatex-chicago package has a differing interface
2416 // it uses a wrapper package and loads styles via fixed options
2417 bool const chicago = features.isRequired("biblatex-chicago");
2420 os << "\\usepackage";
2421 if (!biblatex_bibstyle.empty()
2422 && (biblatex_bibstyle == biblatex_citestyle)
2424 opts = "style=" + biblatex_bibstyle;
2426 } else if (!chicago) {
2427 if (!biblatex_bibstyle.empty()) {
2428 opts = "bibstyle=" + biblatex_bibstyle;
2431 if (!biblatex_citestyle.empty()) {
2432 opts += delim + "citestyle=" + biblatex_citestyle;
2436 if (!multibib.empty() && multibib != "child") {
2437 opts += delim + "refsection=" + multibib;
2440 if (bibtexCommand() == "bibtex8"
2441 || prefixIs(bibtexCommand(), "bibtex8 ")) {
2442 opts += delim + "backend=bibtex8";
2444 } else if (bibtexCommand() == "bibtex"
2445 || prefixIs(bibtexCommand(), "bibtex ")) {
2446 opts += delim + "backend=bibtex";
2449 if (!bib_encoding.empty() && encodings.fromLyXName(bib_encoding)) {
2450 opts += delim + "bibencoding="
2451 + encodings.fromLyXName(bib_encoding)->latexName();
2454 if (!biblio_opts.empty())
2455 opts += delim + biblio_opts;
2457 os << "[" << opts << "]";
2459 os << "{biblatex-chicago}\n";
2461 os << "{biblatex}\n";
2465 // Load custom language package here
2466 if (features.langPackage() == LaTeXFeatures::LANG_PACK_CUSTOM) {
2467 if (lang_package == "default")
2468 os << from_utf8(lyxrc.language_custom_package);
2470 os << from_utf8(lang_package);
2474 // Since menukeys uses catoptions, which does some heavy changes on key-value options,
2475 // it is recommended to load menukeys as the last package (even after hyperref)
2476 if (features.isRequired("menukeys"))
2477 os << "\\usepackage{menukeys}\n";
2479 docstring const i18npreamble =
2480 features.getTClassI18nPreamble(use_babel, use_polyglossia,
2482 if (!i18npreamble.empty())
2483 os << i18npreamble + '\n';
2489 void BufferParams::useClassDefaults()
2491 DocumentClass const & tclass = documentClass();
2493 sides = tclass.sides();
2494 columns = tclass.columns();
2495 pagestyle = tclass.pagestyle();
2496 tablestyle = tclass.tablestyle();
2497 use_default_options = true;
2498 // Only if class has a ToC hierarchy
2499 if (tclass.hasTocLevels()) {
2500 secnumdepth = tclass.secnumdepth();
2501 tocdepth = tclass.tocdepth();
2506 bool BufferParams::hasClassDefaults() const
2508 DocumentClass const & tclass = documentClass();
2510 return sides == tclass.sides()
2511 && columns == tclass.columns()
2512 && pagestyle == tclass.pagestyle()
2513 && tablestyle == tclass.tablestyle()
2514 && use_default_options
2515 && secnumdepth == tclass.secnumdepth()
2516 && tocdepth == tclass.tocdepth();
2520 DocumentClass const & BufferParams::documentClass() const
2526 DocumentClassConstPtr BufferParams::documentClassPtr() const
2532 void BufferParams::setDocumentClass(DocumentClassConstPtr tc)
2534 // evil, but this function is evil
2535 doc_class_ = const_pointer_cast<DocumentClass>(tc);
2536 invalidateConverterCache();
2540 bool BufferParams::setBaseClass(string const & classname, string const & path)
2542 LYXERR(Debug::TCLASS, "setBaseClass: " << classname);
2543 LayoutFileList & bcl = LayoutFileList::get();
2544 if (!bcl.haveClass(classname)) {
2546 bformat(_("The layout file:\n"
2548 "could not be found. A default textclass with default\n"
2549 "layouts will be used. LyX will not be able to produce\n"
2551 from_utf8(classname));
2552 frontend::Alert::error(_("Document class not found"), s);
2553 bcl.addEmptyClass(classname);
2556 bool const success = bcl[classname].load(path);
2559 bformat(_("Due to some error in it, the layout file:\n"
2561 "could not be loaded. A default textclass with default\n"
2562 "layouts will be used. LyX will not be able to produce\n"
2564 from_utf8(classname));
2565 frontend::Alert::error(_("Could not load class"), s);
2566 bcl.addEmptyClass(classname);
2569 pimpl_->baseClass_ = classname;
2570 layout_modules_.adaptToBaseClass(baseClass(), removed_modules_);
2575 LayoutFile const * BufferParams::baseClass() const
2577 if (LayoutFileList::get().haveClass(pimpl_->baseClass_))
2578 return &(LayoutFileList::get()[pimpl_->baseClass_]);
2584 LayoutFileIndex const & BufferParams::baseClassID() const
2586 return pimpl_->baseClass_;
2590 void BufferParams::makeDocumentClass(bool const clone)
2595 invalidateConverterCache();
2596 LayoutModuleList mods;
2597 LayoutModuleList::iterator it = layout_modules_.begin();
2598 LayoutModuleList::iterator en = layout_modules_.end();
2599 for (; it != en; ++it)
2600 mods.push_back(*it);
2602 doc_class_ = getDocumentClass(*baseClass(), mods, cite_engine_, clone);
2604 TextClass::ReturnValues success = TextClass::OK;
2605 if (!forced_local_layout_.empty())
2606 success = doc_class_->read(to_utf8(forced_local_layout_),
2608 if (!local_layout_.empty() &&
2609 (success == TextClass::OK || success == TextClass::OK_OLDFORMAT))
2610 success = doc_class_->read(to_utf8(local_layout_), TextClass::MODULE);
2611 if (success != TextClass::OK && success != TextClass::OK_OLDFORMAT) {
2612 docstring const msg = _("Error reading internal layout information");
2613 frontend::Alert::warning(_("Read Error"), msg);
2618 bool BufferParams::layoutModuleCanBeAdded(string const & modName) const
2620 return layout_modules_.moduleCanBeAdded(modName, baseClass());
2624 docstring BufferParams::getLocalLayout(bool forced) const
2627 return from_utf8(doc_class_->forcedLayouts());
2629 return local_layout_;
2633 void BufferParams::setLocalLayout(docstring const & layout, bool forced)
2636 forced_local_layout_ = layout;
2638 local_layout_ = layout;
2642 bool BufferParams::addLayoutModule(string const & modName)
2644 LayoutModuleList::const_iterator it = layout_modules_.begin();
2645 LayoutModuleList::const_iterator end = layout_modules_.end();
2646 for (; it != end; ++it)
2649 layout_modules_.push_back(modName);
2654 string BufferParams::bufferFormat() const
2656 return documentClass().outputFormat();
2660 bool BufferParams::isExportable(string const & format, bool need_viewable) const
2662 FormatList const & formats = exportableFormats(need_viewable);
2663 FormatList::const_iterator fit = formats.begin();
2664 FormatList::const_iterator end = formats.end();
2665 for (; fit != end ; ++fit) {
2666 if ((*fit)->name() == format)
2673 FormatList const & BufferParams::exportableFormats(bool only_viewable) const
2675 FormatList & cached = only_viewable ?
2676 pimpl_->viewableFormatList : pimpl_->exportableFormatList;
2677 bool & valid = only_viewable ?
2678 pimpl_->isViewCacheValid : pimpl_->isExportCacheValid;
2682 vector<string> const backs = backends();
2683 set<string> excludes;
2684 if (useNonTeXFonts) {
2685 excludes.insert("latex");
2686 excludes.insert("pdflatex");
2687 } else if (inputenc != "ascii" && inputenc != "utf8-plain")
2688 // XeTeX with TeX fonts requires input encoding ascii (#10600).
2689 excludes.insert("xetex");
2690 FormatList result = theConverters().getReachable(backs[0], only_viewable,
2692 for (vector<string>::const_iterator it = backs.begin() + 1;
2693 it != backs.end(); ++it) {
2694 FormatList r = theConverters().getReachable(*it, only_viewable,
2696 result.insert(result.end(), r.begin(), r.end());
2698 sort(result.begin(), result.end(), Format::formatSorter);
2705 vector<string> BufferParams::backends() const
2708 string const buffmt = bufferFormat();
2710 // FIXME: Don't hardcode format names here, but use a flag
2711 if (buffmt == "latex") {
2712 if (encoding().package() == Encoding::japanese)
2713 v.push_back("platex");
2715 if (!useNonTeXFonts) {
2716 v.push_back("pdflatex");
2717 v.push_back("latex");
2720 || inputenc == "ascii" || inputenc == "utf8-plain")
2721 v.push_back("xetex");
2722 v.push_back("luatex");
2723 v.push_back("dviluatex");
2726 string rbuffmt = buffmt;
2727 // If we use an OutputFormat in Japanese docs,
2728 // we need special format in order to get the path
2729 // via pLaTeX (#8823)
2730 if (documentClass().hasOutputFormat()
2731 && encoding().package() == Encoding::japanese)
2733 v.push_back(rbuffmt);
2736 v.push_back("xhtml");
2737 v.push_back("text");
2743 OutputParams::FLAVOR BufferParams::getOutputFlavor(string const & format) const
2745 string const dformat = (format.empty() || format == "default") ?
2746 getDefaultOutputFormat() : format;
2747 DefaultFlavorCache::const_iterator it =
2748 default_flavors_.find(dformat);
2750 if (it != default_flavors_.end())
2753 OutputParams::FLAVOR result = OutputParams::LATEX;
2755 // FIXME It'd be better not to hardcode this, but to do
2756 // something with formats.
2757 if (dformat == "xhtml")
2758 result = OutputParams::HTML;
2759 else if (dformat == "text")
2760 result = OutputParams::TEXT;
2761 else if (dformat == "lyx")
2762 result = OutputParams::LYX;
2763 else if (dformat == "pdflatex")
2764 result = OutputParams::PDFLATEX;
2765 else if (dformat == "xetex")
2766 result = OutputParams::XETEX;
2767 else if (dformat == "luatex")
2768 result = OutputParams::LUATEX;
2769 else if (dformat == "dviluatex")
2770 result = OutputParams::DVILUATEX;
2772 // Try to determine flavor of default output format
2773 vector<string> backs = backends();
2774 if (find(backs.begin(), backs.end(), dformat) == backs.end()) {
2775 // Get shortest path to format
2776 Graph::EdgePath path;
2777 for (auto const & bvar : backs) {
2778 Graph::EdgePath p = theConverters().getPath(bvar, dformat);
2779 if (!p.empty() && (path.empty() || p.size() < path.size())) {
2784 result = theConverters().getFlavor(path);
2787 // cache this flavor
2788 default_flavors_[dformat] = result;
2793 string BufferParams::getDefaultOutputFormat() const
2795 if (!default_output_format.empty()
2796 && default_output_format != "default")
2797 return default_output_format;
2799 FormatList const & formats = exportableFormats(true);
2800 if (formats.empty())
2802 // return the first we find
2803 return formats.front()->name();
2805 if (encoding().package() == Encoding::japanese)
2806 return lyxrc.default_platex_view_format;
2808 return lyxrc.default_otf_view_format;
2809 return lyxrc.default_view_format;
2812 Font const BufferParams::getFont() const
2814 FontInfo f = documentClass().defaultfont();
2815 if (fonts_default_family == "rmdefault")
2816 f.setFamily(ROMAN_FAMILY);
2817 else if (fonts_default_family == "sfdefault")
2818 f.setFamily(SANS_FAMILY);
2819 else if (fonts_default_family == "ttdefault")
2820 f.setFamily(TYPEWRITER_FAMILY);
2821 return Font(f, language);
2825 InsetQuotesParams::QuoteStyle BufferParams::getQuoteStyle(string const & qs) const
2827 return quotesstyletranslator().find(qs);
2831 bool BufferParams::isLatex() const
2833 return documentClass().outputType() == LATEX;
2837 bool BufferParams::isLiterate() const
2839 return documentClass().outputType() == LITERATE;
2843 bool BufferParams::isDocBook() const
2845 return documentClass().outputType() == DOCBOOK;
2849 void BufferParams::readPreamble(Lexer & lex)
2851 if (lex.getString() != "\\begin_preamble")
2852 lyxerr << "Error (BufferParams::readPreamble):"
2853 "consistency check failed." << endl;
2855 preamble = lex.getLongString(from_ascii("\\end_preamble"));
2859 void BufferParams::readLocalLayout(Lexer & lex, bool forced)
2861 string const expected = forced ? "\\begin_forced_local_layout" :
2862 "\\begin_local_layout";
2863 if (lex.getString() != expected)
2864 lyxerr << "Error (BufferParams::readLocalLayout):"
2865 "consistency check failed." << endl;
2868 forced_local_layout_ =
2869 lex.getLongString(from_ascii("\\end_forced_local_layout"));
2871 local_layout_ = lex.getLongString(from_ascii("\\end_local_layout"));
2875 bool BufferParams::setLanguage(string const & lang)
2877 Language const *new_language = languages.getLanguage(lang);
2878 if (!new_language) {
2879 // Language lang was not found
2882 language = new_language;
2887 void BufferParams::readLanguage(Lexer & lex)
2889 if (!lex.next()) return;
2891 string const tmptok = lex.getString();
2893 // check if tmptok is part of tex_babel in tex-defs.h
2894 if (!setLanguage(tmptok)) {
2895 // Language tmptok was not found
2896 language = default_language;
2897 lyxerr << "Warning: Setting language `"
2898 << tmptok << "' to `" << language->lang()
2904 void BufferParams::readGraphicsDriver(Lexer & lex)
2909 string const tmptok = lex.getString();
2910 // check if tmptok is part of tex_graphics in tex_defs.h
2913 string const test = tex_graphics[n++];
2915 if (test == tmptok) {
2916 graphics_driver = tmptok;
2921 "Warning: graphics driver `$$Token' not recognized!\n"
2922 " Setting graphics driver to `default'.\n");
2923 graphics_driver = "default";
2930 void BufferParams::readBullets(Lexer & lex)
2935 int const index = lex.getInteger();
2937 int temp_int = lex.getInteger();
2938 user_defined_bullet(index).setFont(temp_int);
2939 temp_bullet(index).setFont(temp_int);
2941 user_defined_bullet(index).setCharacter(temp_int);
2942 temp_bullet(index).setCharacter(temp_int);
2944 user_defined_bullet(index).setSize(temp_int);
2945 temp_bullet(index).setSize(temp_int);
2949 void BufferParams::readBulletsLaTeX(Lexer & lex)
2951 // The bullet class should be able to read this.
2954 int const index = lex.getInteger();
2956 docstring const temp_str = lex.getDocString();
2958 user_defined_bullet(index).setText(temp_str);
2959 temp_bullet(index).setText(temp_str);
2963 void BufferParams::readModules(Lexer & lex)
2965 if (!lex.eatLine()) {
2966 lyxerr << "Error (BufferParams::readModules):"
2967 "Unexpected end of input." << endl;
2971 string mod = lex.getString();
2972 if (mod == "\\end_modules")
2974 addLayoutModule(mod);
2980 void BufferParams::readRemovedModules(Lexer & lex)
2982 if (!lex.eatLine()) {
2983 lyxerr << "Error (BufferParams::readRemovedModules):"
2984 "Unexpected end of input." << endl;
2988 string mod = lex.getString();
2989 if (mod == "\\end_removed_modules")
2991 removed_modules_.push_back(mod);
2994 // now we want to remove any removed modules that were previously
2995 // added. normally, that will be because default modules were added in
2996 // setBaseClass(), which gets called when \textclass is read at the
2997 // start of the read.
2998 list<string>::const_iterator rit = removed_modules_.begin();
2999 list<string>::const_iterator const ren = removed_modules_.end();
3000 for (; rit != ren; ++rit) {
3001 LayoutModuleList::iterator const mit = layout_modules_.begin();
3002 LayoutModuleList::iterator const men = layout_modules_.end();
3003 LayoutModuleList::iterator found = find(mit, men, *rit);
3006 layout_modules_.erase(found);
3011 void BufferParams::readIncludeonly(Lexer & lex)
3013 if (!lex.eatLine()) {
3014 lyxerr << "Error (BufferParams::readIncludeonly):"
3015 "Unexpected end of input." << endl;
3019 string child = lex.getString();
3020 if (child == "\\end_includeonly")
3022 included_children_.push_back(child);
3028 string BufferParams::paperSizeName(PapersizePurpose purpose) const
3030 switch (papersize) {
3032 // could be anything, so don't guess
3034 case PAPER_CUSTOM: {
3035 if (purpose == XDVI && !paperwidth.empty() &&
3036 !paperheight.empty()) {
3037 // heightxwidth<unit>
3038 string first = paperwidth;
3039 string second = paperheight;
3040 if (orientation == ORIENTATION_LANDSCAPE)
3043 return first.erase(first.length() - 2)
3049 // dvips and dvipdfm do not know this
3050 if (purpose == DVIPS || purpose == DVIPDFM)
3054 if (purpose == DVIPS || purpose == DVIPDFM)
3058 if (purpose == DVIPS || purpose == DVIPDFM)
3068 if (purpose == DVIPS || purpose == DVIPDFM)
3072 if (purpose == DVIPS || purpose == DVIPDFM)
3076 if (purpose == DVIPS || purpose == DVIPDFM)
3080 if (purpose == DVIPS || purpose == DVIPDFM)
3084 if (purpose == DVIPS || purpose == DVIPDFM)
3088 // dvipdfm does not know this
3089 if (purpose == DVIPDFM)
3093 if (purpose == DVIPDFM)
3097 if (purpose == DVIPS || purpose == DVIPDFM)
3101 if (purpose == DVIPS || purpose == DVIPDFM)
3105 if (purpose == DVIPS || purpose == DVIPDFM)
3109 if (purpose == DVIPS || purpose == DVIPDFM)
3113 if (purpose == DVIPS || purpose == DVIPDFM)
3117 if (purpose == DVIPS || purpose == DVIPDFM)
3121 if (purpose == DVIPS || purpose == DVIPDFM)
3125 if (purpose == DVIPS || purpose == DVIPDFM)
3129 if (purpose == DVIPS || purpose == DVIPDFM)
3133 if (purpose == DVIPS || purpose == DVIPDFM)
3137 if (purpose == DVIPS || purpose == DVIPDFM)
3141 if (purpose == DVIPS || purpose == DVIPDFM)
3145 if (purpose == DVIPS || purpose == DVIPDFM)
3149 if (purpose == DVIPS || purpose == DVIPDFM)
3153 if (purpose == DVIPS || purpose == DVIPDFM)
3156 case PAPER_USEXECUTIVE:
3157 // dvipdfm does not know this
3158 if (purpose == DVIPDFM)
3163 case PAPER_USLETTER:
3165 if (purpose == XDVI)
3172 string const BufferParams::dvips_options() const
3176 // If the class loads the geometry package, we do not know which
3177 // paper size is used, since we do not set it (bug 7013).
3178 // Therefore we must not specify any argument here.
3179 // dvips gets the correct paper size via DVI specials in this case
3180 // (if the class uses the geometry package correctly).
3181 if (documentClass().provides("geometry"))
3185 && papersize == PAPER_CUSTOM
3186 && !lyxrc.print_paper_dimension_flag.empty()
3187 && !paperwidth.empty()
3188 && !paperheight.empty()) {
3189 // using a custom papersize
3190 result = lyxrc.print_paper_dimension_flag;
3191 result += ' ' + paperwidth;
3192 result += ',' + paperheight;
3194 string const paper_option = paperSizeName(DVIPS);
3195 if (!paper_option.empty() && (paper_option != "letter" ||
3196 orientation != ORIENTATION_LANDSCAPE)) {
3197 // dvips won't accept -t letter -t landscape.
3198 // In all other cases, include the paper size
3200 result = lyxrc.print_paper_flag;
3201 result += ' ' + paper_option;
3204 if (orientation == ORIENTATION_LANDSCAPE &&
3205 papersize != PAPER_CUSTOM)
3206 result += ' ' + lyxrc.print_landscape_flag;
3211 string const BufferParams::main_font_encoding() const
3213 if (font_encodings().empty()) {
3214 if (ascii_lowercase(language->fontenc(*this)) == "none")
3218 return font_encodings().back();
3222 vector<string> const BufferParams::font_encodings() const
3224 string doc_fontenc = (fontenc == "auto") ? string() : fontenc;
3226 vector<string> fontencs;
3228 // "default" means "no explicit font encoding"
3229 if (doc_fontenc != "default") {
3230 if (!doc_fontenc.empty())
3231 // If we have a custom setting, we use only that!
3232 return getVectorFromString(doc_fontenc);
3233 if (!language->fontenc(*this).empty()
3234 && ascii_lowercase(language->fontenc(*this)) != "none") {
3235 vector<string> fencs = getVectorFromString(language->fontenc(*this));
3236 for (auto & fe : fencs) {
3237 if (find(fontencs.begin(), fontencs.end(), fe) == fontencs.end())
3238 fontencs.push_back(fe);
3247 string BufferParams::babelCall(string const & lang_opts, bool const langoptions) const
3249 // suppress the babel call if there is no BabelName defined
3250 // for the document language in the lib/languages file and if no
3251 // other languages are used (lang_opts is then empty)
3252 if (lang_opts.empty())
3254 // The prefs may require the languages to
3255 // be submitted to babel itself (not the class).
3257 return "\\usepackage[" + lang_opts + "]{babel}";
3258 return "\\usepackage{babel}";
3262 docstring BufferParams::getGraphicsDriver(string const & package) const
3266 if (package == "geometry") {
3267 if (graphics_driver == "dvips"
3268 || graphics_driver == "dvipdfm"
3269 || graphics_driver == "pdftex"
3270 || graphics_driver == "vtex")
3271 result = from_ascii(graphics_driver);
3272 else if (graphics_driver == "dvipdfmx")
3273 result = from_ascii("dvipdfm");
3280 void BufferParams::writeEncodingPreamble(otexstream & os,
3281 LaTeXFeatures & features) const
3283 // With no-TeX fonts we use utf8-plain without encoding package.
3287 if (inputenc == "auto-legacy") {
3288 string const doc_encoding =
3289 language->encoding()->latexName();
3290 Encoding::Package const package =
3291 language->encoding()->package();
3293 // Create list of inputenc options:
3294 set<string> encoding_set;
3295 // luainputenc fails with more than one encoding
3296 if (features.runparams().flavor != OutputParams::LUATEX
3297 && features.runparams().flavor != OutputParams::DVILUATEX)
3298 // list all input encodings used in the document
3299 encoding_set = features.getEncodingSet(doc_encoding);
3301 // The "japanese" babel-language requires the pLaTeX engine
3302 // which conflicts with "inputenc".
3303 // See http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129680.html
3304 if ((!encoding_set.empty() || package == Encoding::inputenc)
3305 && !features.isRequired("japanese")
3306 && !features.isProvided("inputenc")) {
3307 os << "\\usepackage[";
3308 set<string>::const_iterator it = encoding_set.begin();
3309 set<string>::const_iterator const end = encoding_set.end();
3311 os << from_ascii(*it);
3314 for (; it != end; ++it)
3315 os << ',' << from_ascii(*it);
3316 if (package == Encoding::inputenc) {
3317 if (!encoding_set.empty())
3319 os << from_ascii(doc_encoding);
3321 if (features.runparams().flavor == OutputParams::LUATEX
3322 || features.runparams().flavor == OutputParams::DVILUATEX)
3323 os << "]{luainputenc}\n";
3325 os << "]{inputenc}\n";
3327 } else if (inputenc != "auto-legacy-plain") {
3328 switch (encoding().package()) {
3329 case Encoding::none:
3331 case Encoding::japanese:
3332 if (encoding().iconvName() != "UTF-8"
3333 && !features.runparams().isFullUnicode())
3334 // don't default to [utf8]{inputenc} with TeXLive >= 18
3335 os << "\\ifdefined\\UseRawInputEncoding\n"
3336 << " \\UseRawInputEncoding\\fi\n";
3338 case Encoding::inputenc:
3339 // do not load inputenc if japanese is used
3340 // or if the class provides inputenc
3341 if (features.isRequired("japanese")
3342 || features.isProvided("inputenc"))
3344 os << "\\usepackage[" << from_ascii(encoding().latexName());
3345 if (features.runparams().flavor == OutputParams::LUATEX
3346 || features.runparams().flavor == OutputParams::DVILUATEX)
3347 os << "]{luainputenc}\n";
3349 os << "]{inputenc}\n";
3353 if (inputenc == "auto-legacy-plain" || features.isRequired("japanese")) {
3354 // don't default to [utf8]{inputenc} with TeXLive >= 18
3355 os << "\\ifdefined\\UseRawInputEncoding\n";
3356 os << " \\UseRawInputEncoding\\fi\n";
3361 string const BufferParams::parseFontName(string const & name) const
3363 string mangled = name;
3364 size_t const idx = mangled.find('[');
3365 if (idx == string::npos || idx == 0)
3368 return mangled.substr(0, idx - 1);
3372 string const BufferParams::loadFonts(LaTeXFeatures & features) const
3374 if (fontsRoman() == "default" && fontsSans() == "default"
3375 && fontsTypewriter() == "default"
3376 && (fontsMath() == "default" || fontsMath() == "auto"))
3382 /* Fontspec (XeTeX, LuaTeX): we provide GUI support for oldstyle
3383 * numbers (Numbers=OldStyle) and sf/tt scaling. The Ligatures=TeX/
3384 * Mapping=tex-text option assures TeX ligatures (such as "--")
3385 * are resolved. Note that tt does not use these ligatures.
3387 * -- add more GUI options?
3388 * -- add more fonts (fonts for other scripts)
3389 * -- if there's a way to find out if a font really supports
3390 * OldStyle, enable/disable the widget accordingly.
3392 if (useNonTeXFonts && features.isAvailable("fontspec")) {
3393 // "Mapping=tex-text" and "Ligatures=TeX" are equivalent.
3394 // However, until v.2 (2010/07/11) fontspec only knew
3395 // Mapping=tex-text (for XeTeX only); then "Ligatures=TeX"
3396 // was introduced for both XeTeX and LuaTeX (LuaTeX
3397 // didn't understand "Mapping=tex-text", while XeTeX
3398 // understood both. With most recent versions, both
3399 // variants are understood by both engines. However,
3400 // we want to provide support for at least TeXLive 2009
3401 // (for XeTeX; LuaTeX is only supported as of v.2)
3402 // As of 2017/11/03, Babel has its own higher-level
3403 // interface on top of fontspec that is to be used.
3404 bool const babelfonts = features.useBabel()
3405 && features.isAvailable("babel-2017/11/03");
3406 string const texmapping =
3407 (features.runparams().flavor == OutputParams::XETEX) ?
3408 "Mapping=tex-text" : "Ligatures=TeX";
3409 if (fontsRoman() != "default") {
3411 os << "\\babelfont{rm}[";
3413 os << "\\setmainfont[";
3414 if (!font_roman_opts.empty())
3415 os << font_roman_opts << ',';
3417 if (fonts_roman_osf)
3418 os << ",Numbers=OldStyle";
3419 os << "]{" << parseFontName(fontsRoman()) << "}\n";
3421 if (fontsSans() != "default") {
3422 string const sans = parseFontName(fontsSans());
3423 if (fontsSansScale() != 100) {
3425 os << "\\babelfont{sf}";
3427 os << "\\setsansfont";
3429 << float(fontsSansScale()) / 100 << ',';
3431 os << "Numbers=OldStyle,";
3432 if (!font_sans_opts.empty())
3433 os << font_sans_opts << ',';
3434 os << texmapping << "]{"
3438 os << "\\babelfont{sf}[";
3440 os << "\\setsansfont[";
3442 os << "Numbers=OldStyle,";
3443 if (!font_sans_opts.empty())
3444 os << font_sans_opts << ',';
3445 os << texmapping << "]{"
3449 if (fontsTypewriter() != "default") {
3450 string const mono = parseFontName(fontsTypewriter());
3451 if (fontsTypewriterScale() != 100) {
3453 os << "\\babelfont{tt}";
3455 os << "\\setmonofont";
3457 << float(fontsTypewriterScale()) / 100;
3458 if (fonts_typewriter_osf)
3459 os << ",Numbers=OldStyle";
3460 if (!font_typewriter_opts.empty())
3461 os << ',' << font_typewriter_opts;
3466 os << "\\babelfont{tt}";
3468 os << "\\setmonofont";
3469 if (!font_typewriter_opts.empty() || fonts_typewriter_osf) {
3471 if (fonts_typewriter_osf)
3472 os << "Numbers=OldStyle";
3473 if (!font_typewriter_opts.empty()) {
3474 if (fonts_typewriter_osf)
3476 os << font_typewriter_opts;
3480 os << '{' << mono << "}\n";
3487 bool const ot1 = (main_font_encoding() == "default" || main_font_encoding() == "OT1");
3488 bool const dryrun = features.runparams().dryrun;
3489 bool const complete = (fontsSans() == "default" && fontsTypewriter() == "default");
3490 bool const nomath = (fontsMath() == "default");
3493 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsRoman())).getLaTeXCode(
3494 dryrun, ot1, complete, fonts_expert_sc, fonts_roman_osf,
3495 nomath, font_roman_opts);
3498 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsSans())).getLaTeXCode(
3499 dryrun, ot1, complete, fonts_expert_sc, fonts_sans_osf,
3500 nomath, font_sans_opts, fontsSansScale());
3502 // MONOSPACED/TYPEWRITER
3503 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsTypewriter())).getLaTeXCode(
3504 dryrun, ot1, complete, fonts_expert_sc, fonts_typewriter_osf,
3505 nomath, font_typewriter_opts, fontsTypewriterScale());
3508 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsMath())).getLaTeXCode(
3509 dryrun, ot1, complete, fonts_expert_sc, fonts_roman_osf,
3516 Encoding const & BufferParams::encoding() const
3518 // Main encoding for LaTeX output.
3520 return *(encodings.fromLyXName("utf8-plain"));
3521 if (inputenc == "auto-legacy" || inputenc == "auto-legacy-plain")
3522 return *language->encoding();
3523 if (inputenc == "utf8" && language->lang() == "japanese")
3524 return *(encodings.fromLyXName("utf8-platex"));
3525 Encoding const * const enc = encodings.fromLyXName(inputenc);
3528 LYXERR0("Unknown inputenc value `" << inputenc
3529 << "'. Using `auto' instead.");
3530 return *language->encoding();
3534 string const & BufferParams::defaultBiblioStyle() const
3536 if (!biblio_style.empty())
3537 return biblio_style;
3539 map<string, string> const & bs = documentClass().defaultBiblioStyle();
3540 auto cit = bs.find(theCiteEnginesList.getTypeAsString(citeEngineType()));
3541 if (cit != bs.end())
3544 return empty_string();
3548 bool const & BufferParams::fullAuthorList() const
3550 return documentClass().fullAuthorList();
3554 string BufferParams::getCiteAlias(string const & s) const
3556 vector<string> commands =
3557 documentClass().citeCommands(citeEngineType());
3558 // If it is a real command, don't treat it as an alias
3559 if (find(commands.begin(), commands.end(), s) != commands.end())
3561 map<string,string> aliases = documentClass().citeCommandAliases();
3562 if (aliases.find(s) != aliases.end())
3568 vector<string> BufferParams::citeCommands() const
3570 static CitationStyle const default_style;
3571 vector<string> commands =
3572 documentClass().citeCommands(citeEngineType());
3573 if (commands.empty())
3574 commands.push_back(default_style.name);
3579 vector<CitationStyle> BufferParams::citeStyles() const
3581 static CitationStyle const default_style;
3582 vector<CitationStyle> styles =
3583 documentClass().citeStyles(citeEngineType());
3585 styles.push_back(default_style);
3590 string const BufferParams::bibtexCommand() const
3592 // Return document-specific setting if available
3593 if (bibtex_command != "default")
3594 return bibtex_command;
3596 // If we have "default" in document settings, consult the prefs
3597 // 1. Japanese (uses a specific processor)
3598 if (encoding().package() == Encoding::japanese) {
3599 if (lyxrc.jbibtex_command != "automatic")
3600 // Return the specified program, if "automatic" is not set
3601 return lyxrc.jbibtex_command;
3602 else if (!useBiblatex()) {
3603 // With classic BibTeX, return pbibtex, jbibtex, bibtex
3604 if (lyxrc.jbibtex_alternatives.find("pbibtex") != lyxrc.jbibtex_alternatives.end())
3606 if (lyxrc.jbibtex_alternatives.find("jbibtex") != lyxrc.jbibtex_alternatives.end())
3611 // 2. All other languages
3612 else if (lyxrc.bibtex_command != "automatic")
3613 // Return the specified program, if "automatic" is not set
3614 return lyxrc.bibtex_command;
3616 // 3. Automatic: find the most suitable for the current cite framework
3617 if (useBiblatex()) {
3618 // For Biblatex, we prefer biber (also for Japanese)
3619 // and fall back to bibtex8 and, as last resort, bibtex
3620 if (lyxrc.bibtex_alternatives.find("biber") != lyxrc.bibtex_alternatives.end())
3622 else if (lyxrc.bibtex_alternatives.find("bibtex8") != lyxrc.bibtex_alternatives.end())
3629 bool BufferParams::useBiblatex() const
3631 return theCiteEnginesList[citeEngine()]->getCiteFramework() == "biblatex";
3635 void BufferParams::invalidateConverterCache() const
3637 pimpl_->isExportCacheValid = false;
3638 pimpl_->isViewCacheValid = false;
3642 // We shouldn't need to reset the params here, since anything
3643 // we need will be recopied.
3644 void BufferParams::copyForAdvFR(const BufferParams & bp)
3646 string const & lang = bp.language->lang();
3648 layout_modules_ = bp.layout_modules_;
3649 string const & doc_class = bp.documentClass().name();
3650 setBaseClass(doc_class);
3654 void BufferParams::setBibFileEncoding(string const & file, string const & enc)
3656 bib_encodings[file] = enc;
3660 string const BufferParams::bibFileEncoding(string const & file) const
3662 if (bib_encodings.find(file) == bib_encodings.end())
3664 return bib_encodings.find(file)->second;