]> git.lyx.org Git - lyx.git/blob - src/BufferParams.cpp
Amend 3093789e for cmake build
[lyx.git] / src / BufferParams.cpp
1 /**
2  * \file BufferParams.cpp
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Alfredo Braunstein
7  * \author Lars Gullik Bjønnes
8  * \author Jean-Marc Lasgouttes
9  * \author John Levon
10  * \author André Pönitz
11  * \author Martin Vermeer
12  *
13  * Full author contact details are available in file CREDITS.
14  */
15
16 #include <config.h>
17
18 #include "BufferParams.h"
19
20 #include "Author.h"
21 #include "LayoutFile.h"
22 #include "BranchList.h"
23 #include "Buffer.h"
24 #include "Bullet.h"
25 #include "CiteEnginesList.h"
26 #include "Color.h"
27 #include "ColorSet.h"
28 #include "Converter.h"
29 #include "Encoding.h"
30 #include "Format.h"
31 #include "IndicesList.h"
32 #include "Language.h"
33 #include "LaTeXFeatures.h"
34 #include "LaTeXFonts.h"
35 #include "Font.h"
36 #include "Lexer.h"
37 #include "LyXRC.h"
38 #include "OutputParams.h"
39 #include "Spacing.h"
40 #include "texstream.h"
41 #include "TexRow.h"
42 #include "VSpace.h"
43 #include "PDFOptions.h"
44
45 #include "frontends/alert.h"
46
47 #include "insets/InsetListingsParams.h"
48
49 #include "support/convert.h"
50 #include "support/debug.h"
51 #include "support/FileName.h"
52 #include "support/filetools.h"
53 #include "support/gettext.h"
54 #include "support/Length.h"
55 #include "support/Messages.h"
56 #include "support/mutex.h"
57 #include "support/Package.h"
58 #include "support/Translator.h"
59 #include "support/lstrings.h"
60
61 #include <algorithm>
62 #include <sstream>
63
64 using namespace std;
65 using namespace lyx::support;
66
67
68 static char const * const string_paragraph_separation[] = {
69         "indent", "skip", ""
70 };
71
72
73 static char const * const string_quotes_style[] = {
74         "english", "swedish", "german", "polish", "swiss", "danish", "plain",
75         "british", "swedishg", "french", "frenchin", "russian", "cjk", "cjkangle", ""
76 };
77
78
79 static char const * const string_papersize[] = {
80         "default", "custom", "letter", "legal", "executive",
81         "a0", "a1", "a2", "a3", "a4", "a5", "a6",
82         "b0", "b1", "b2", "b3", "b4", "b5", "b6",
83         "c0", "c1", "c2", "c3", "c4", "c5", "c6",
84         "b0j", "b1j", "b2j", "b3j", "b4j", "b5j", "b6j", ""
85 };
86
87
88 static char const * const string_papersize_geometry[] = {
89         "default", "custom", "letterpaper", "legalpaper", "executivepaper",
90         "a0paper", "a1paper", "a2paper", "a3paper", "a4paper", "a5paper", "a6paper",
91         "b0paper", "b1paper", "b2paper", "b3paper", "b4paper", "b5paper", "b6paper",
92         "c0paper", "c1paper", "c2paper", "c3paper", "c4paper", "c5paper", "c6paper",
93         "b0j", "b1j", "b2j", "b3j", "b4j", "b5j", "b6j", ""
94 };
95
96
97 static char const * const string_orientation[] = {
98         "portrait", "landscape", ""
99 };
100
101
102 static char const * const tex_graphics[] = {
103         "default", "dvialw", "dvilaser", "dvipdf", "dvipdfm", "dvipdfmx",
104         "dvips", "dvipsone", "dvitops", "dviwin", "dviwindo", "dvi2ps", "emtex",
105         "ln", "oztex", "pctexhp", "pctexps", "pctexwin", "pctex32", "pdftex",
106         "psprint", "pubps", "tcidvi", "textures", "truetex", "vtex", "xdvi",
107         "xetex", "none", ""
108 };
109
110
111 namespace lyx {
112
113 // Local translators
114 namespace {
115
116 // Paragraph separation
117 typedef Translator<string, BufferParams::ParagraphSeparation> ParSepTranslator;
118
119
120 ParSepTranslator const init_parseptranslator()
121 {
122         ParSepTranslator translator
123                 (string_paragraph_separation[0], BufferParams::ParagraphIndentSeparation);
124         translator.addPair(string_paragraph_separation[1], BufferParams::ParagraphSkipSeparation);
125         return translator;
126 }
127
128
129 ParSepTranslator const & parseptranslator()
130 {
131         static ParSepTranslator const translator =
132                 init_parseptranslator();
133         return translator;
134 }
135
136
137 // Quotes style
138 typedef Translator<string, InsetQuotesParams::QuoteStyle> QuotesStyleTranslator;
139
140
141 QuotesStyleTranslator const init_quotesstyletranslator()
142 {
143         QuotesStyleTranslator translator
144                 (string_quotes_style[0], InsetQuotesParams::EnglishQuotes);
145         translator.addPair(string_quotes_style[1], InsetQuotesParams::SwedishQuotes);
146         translator.addPair(string_quotes_style[2], InsetQuotesParams::GermanQuotes);
147         translator.addPair(string_quotes_style[3], InsetQuotesParams::PolishQuotes);
148         translator.addPair(string_quotes_style[4], InsetQuotesParams::SwissQuotes);
149         translator.addPair(string_quotes_style[5], InsetQuotesParams::DanishQuotes);
150         translator.addPair(string_quotes_style[6], InsetQuotesParams::PlainQuotes);
151         translator.addPair(string_quotes_style[7], InsetQuotesParams::BritishQuotes);
152         translator.addPair(string_quotes_style[8], InsetQuotesParams::SwedishGQuotes);
153         translator.addPair(string_quotes_style[9], InsetQuotesParams::FrenchQuotes);
154         translator.addPair(string_quotes_style[10], InsetQuotesParams::FrenchINQuotes);
155         translator.addPair(string_quotes_style[11], InsetQuotesParams::RussianQuotes);
156         translator.addPair(string_quotes_style[12], InsetQuotesParams::CJKQuotes);
157         translator.addPair(string_quotes_style[13], InsetQuotesParams::CJKAngleQuotes);
158         return translator;
159 }
160
161
162 QuotesStyleTranslator const & quotesstyletranslator()
163 {
164         static QuotesStyleTranslator const translator =
165                 init_quotesstyletranslator();
166         return translator;
167 }
168
169
170 // Paper size
171 typedef Translator<string, PAPER_SIZE> PaperSizeTranslator;
172
173
174 static PaperSizeTranslator initPaperSizeTranslator()
175 {
176         PaperSizeTranslator translator(string_papersize[0], PAPER_DEFAULT);
177         translator.addPair(string_papersize[1], PAPER_CUSTOM);
178         translator.addPair(string_papersize[2], PAPER_USLETTER);
179         translator.addPair(string_papersize[3], PAPER_USLEGAL);
180         translator.addPair(string_papersize[4], PAPER_USEXECUTIVE);
181         translator.addPair(string_papersize[5], PAPER_A0);
182         translator.addPair(string_papersize[6], PAPER_A1);
183         translator.addPair(string_papersize[7], PAPER_A2);
184         translator.addPair(string_papersize[8], PAPER_A3);
185         translator.addPair(string_papersize[9], PAPER_A4);
186         translator.addPair(string_papersize[10], PAPER_A5);
187         translator.addPair(string_papersize[11], PAPER_A6);
188         translator.addPair(string_papersize[12], PAPER_B0);
189         translator.addPair(string_papersize[13], PAPER_B1);
190         translator.addPair(string_papersize[14], PAPER_B2);
191         translator.addPair(string_papersize[15], PAPER_B3);
192         translator.addPair(string_papersize[16], PAPER_B4);
193         translator.addPair(string_papersize[17], PAPER_B5);
194         translator.addPair(string_papersize[18], PAPER_B6);
195         translator.addPair(string_papersize[19], PAPER_C0);
196         translator.addPair(string_papersize[20], PAPER_C1);
197         translator.addPair(string_papersize[21], PAPER_C2);
198         translator.addPair(string_papersize[22], PAPER_C3);
199         translator.addPair(string_papersize[23], PAPER_C4);
200         translator.addPair(string_papersize[24], PAPER_C5);
201         translator.addPair(string_papersize[25], PAPER_C6);
202         translator.addPair(string_papersize[26], PAPER_JISB0);
203         translator.addPair(string_papersize[27], PAPER_JISB1);
204         translator.addPair(string_papersize[28], PAPER_JISB2);
205         translator.addPair(string_papersize[29], PAPER_JISB3);
206         translator.addPair(string_papersize[30], PAPER_JISB4);
207         translator.addPair(string_papersize[31], PAPER_JISB5);
208         translator.addPair(string_papersize[32], PAPER_JISB6);
209         return translator;
210 }
211
212
213 PaperSizeTranslator const & papersizetranslator()
214 {
215         static PaperSizeTranslator const translator =
216                 initPaperSizeTranslator();
217         return translator;
218 }
219
220
221 // Paper orientation
222 typedef Translator<string, PAPER_ORIENTATION> PaperOrientationTranslator;
223
224
225 PaperOrientationTranslator const init_paperorientationtranslator()
226 {
227         PaperOrientationTranslator translator(string_orientation[0], ORIENTATION_PORTRAIT);
228         translator.addPair(string_orientation[1], ORIENTATION_LANDSCAPE);
229         return translator;
230 }
231
232
233 PaperOrientationTranslator const & paperorientationtranslator()
234 {
235         static PaperOrientationTranslator const translator =
236             init_paperorientationtranslator();
237         return translator;
238 }
239
240
241 // Page sides
242 typedef Translator<int, PageSides> SidesTranslator;
243
244
245 SidesTranslator const init_sidestranslator()
246 {
247         SidesTranslator translator(1, OneSide);
248         translator.addPair(2, TwoSides);
249         return translator;
250 }
251
252
253 SidesTranslator const & sidestranslator()
254 {
255         static SidesTranslator const translator = init_sidestranslator();
256         return translator;
257 }
258
259
260 // LaTeX packages
261 typedef Translator<int, BufferParams::Package> PackageTranslator;
262
263
264 PackageTranslator const init_packagetranslator()
265 {
266         PackageTranslator translator(0, BufferParams::package_off);
267         translator.addPair(1, BufferParams::package_auto);
268         translator.addPair(2, BufferParams::package_on);
269         return translator;
270 }
271
272
273 PackageTranslator const & packagetranslator()
274 {
275         static PackageTranslator const translator =
276                 init_packagetranslator();
277         return translator;
278 }
279
280
281 // Spacing
282 typedef Translator<string, Spacing::Space> SpaceTranslator;
283
284
285 SpaceTranslator const init_spacetranslator()
286 {
287         SpaceTranslator translator("default", Spacing::Default);
288         translator.addPair("single", Spacing::Single);
289         translator.addPair("onehalf", Spacing::Onehalf);
290         translator.addPair("double", Spacing::Double);
291         translator.addPair("other", Spacing::Other);
292         return translator;
293 }
294
295
296 SpaceTranslator const & spacetranslator()
297 {
298         static SpaceTranslator const translator = init_spacetranslator();
299         return translator;
300 }
301
302
303 bool inSystemDir(FileName const & document_dir, string & system_dir)
304 {
305         // A document is assumed to be in a system LyX directory (not
306         // necessarily the system directory of the running instance)
307         // if both "configure.py" and "chkconfig.ltx" are found in
308         // either document_dir/../ or document_dir/../../.
309         // If true, the system directory path is returned in system_dir
310         // with a trailing path separator.
311
312         string const msg = "Checking whether document is in a system dir...";
313
314         string dir = document_dir.absFileName();
315
316         for (int i = 0; i < 3; ++i) {
317                 dir = addPath(dir, "..");
318                 if (!fileSearch(dir, "configure.py").empty() &&
319                     !fileSearch(dir, "chkconfig.ltx").empty()) {
320                         LYXERR(Debug::FILES, msg << " yes");
321                         system_dir = addPath(FileName(dir).realPath(), "");
322                         return true;
323                 }
324         }
325
326         LYXERR(Debug::FILES, msg << " no");
327         system_dir = string();
328         return false;
329 }
330
331 } // namespace
332
333
334 class BufferParams::Impl
335 {
336 public:
337         Impl();
338
339         AuthorList authorlist;
340         BranchList branchlist;
341         Bullet temp_bullets[4];
342         Bullet user_defined_bullets[4];
343         IndicesList indiceslist;
344         Spacing spacing;
345         Length parindent;
346         Length mathindent;
347         /** This is the amount of space used for paragraph_separation "skip",
348          * and for detached paragraphs in "indented" documents.
349          */
350         VSpace defskip;
351         PDFOptions pdfoptions;
352         LayoutFileIndex baseClass_;
353         FormatList exportableFormatList;
354         FormatList viewableFormatList;
355         bool isViewCacheValid;
356         bool isExportCacheValid;
357 };
358
359
360 BufferParams::Impl::Impl()
361         : defskip(VSpace::MEDSKIP), baseClass_(string("")),
362           isViewCacheValid(false), isExportCacheValid(false)
363 {
364         // set initial author
365         // FIXME UNICODE
366         authorlist.record(Author(from_utf8(lyxrc.user_name),
367                                  from_utf8(lyxrc.user_email),
368                                  from_utf8(lyxrc.user_initials)));
369 }
370
371
372 BufferParams::Impl *
373 BufferParams::MemoryTraits::clone(BufferParams::Impl const * ptr)
374 {
375         LBUFERR(ptr);
376         return new BufferParams::Impl(*ptr);
377 }
378
379
380 void BufferParams::MemoryTraits::destroy(BufferParams::Impl * ptr)
381 {
382         delete ptr;
383 }
384
385
386 BufferParams::BufferParams()
387         : pimpl_(new Impl)
388 {
389         setBaseClass(defaultBaseclass());
390         cite_engine_ = "basic";
391         cite_engine_type_ = ENGINE_TYPE_DEFAULT;
392         makeDocumentClass();
393         paragraph_separation = ParagraphIndentSeparation;
394         is_math_indent = false;
395         math_numbering_side = DEFAULT;
396         quotes_style = InsetQuotesParams::EnglishQuotes;
397         dynamic_quotes = false;
398         fontsize = "default";
399
400         /*  PaperLayout */
401         papersize = PAPER_DEFAULT;
402         orientation = ORIENTATION_PORTRAIT;
403         use_geometry = false;
404         biblio_style = string();
405         use_bibtopic = false;
406         multibib = string();
407         use_indices = false;
408         save_transient_properties = true;
409         track_changes = false;
410         output_changes = false;
411         change_bars = false;
412         postpone_fragile_content = true;
413         use_default_options = true;
414         maintain_unincluded_children = CM_None;
415         secnumdepth = 3;
416         tocdepth = 3;
417         language = default_language;
418         fontenc = "auto";
419         fonts_roman[0] = "default";
420         fonts_roman[1] = "default";
421         fonts_sans[0] = "default";
422         fonts_sans[1] = "default";
423         fonts_typewriter[0] = "default";
424         fonts_typewriter[1] = "default";
425         fonts_math[0] = "auto";
426         fonts_math[1] = "auto";
427         fonts_default_family = "default";
428         useNonTeXFonts = false;
429         use_microtype = false;
430         use_dash_ligatures = true;
431         fonts_expert_sc = false;
432         fonts_roman_osf = false;
433         fonts_sans_osf = false;
434         fonts_typewriter_osf = false;
435         fonts_sans_scale[0] = 100;
436         fonts_sans_scale[1] = 100;
437         fonts_typewriter_scale[0] = 100;
438         fonts_typewriter_scale[1] = 100;
439         inputenc = "utf8";
440         lang_package = "default";
441         graphics_driver = "default";
442         default_output_format = "default";
443         bibtex_command = "default";
444         index_command = "default";
445         sides = OneSide;
446         columns = 1;
447         listings_params = string();
448         pagestyle = "default";
449         tablestyle = "default";
450         float_alignment = "class";
451         float_placement = "class";
452         suppress_date = false;
453         justification = true;
454         // no color is the default (white)
455         backgroundcolor = lyx::rgbFromHexName("#ffffff");
456         isbackgroundcolor = false;
457         // no color is the default (black)
458         fontcolor = lyx::rgbFromHexName("#000000");
459         isfontcolor = false;
460         // light gray is the default font color for greyed-out notes
461         notefontcolor = lyx::rgbFromHexName("#cccccc");
462         boxbgcolor = lyx::rgbFromHexName("#ff0000");
463         compressed = lyxrc.save_compressed;
464         for (int iter = 0; iter < 4; ++iter) {
465                 user_defined_bullet(iter) = ITEMIZE_DEFAULTS[iter];
466                 temp_bullet(iter) = ITEMIZE_DEFAULTS[iter];
467         }
468         // default index
469         indiceslist().addDefault(B_("Index"));
470         html_be_strict = false;
471         html_math_output = MathML;
472         html_math_img_scale = 1.0;
473         html_css_as_file = false;
474         docbook_table_output = HTMLTable;
475         display_pixel_ratio = 1.0;
476
477         shell_escape = false;
478         output_sync = false;
479         use_refstyle = true;
480         use_minted = false;
481         use_lineno = false;
482
483         // map current author
484         author_map_[pimpl_->authorlist.get(0).bufferId()] = 0;
485 }
486
487
488 docstring BufferParams::B_(string const & l10n) const
489 {
490         LASSERT(language, return from_utf8(l10n));
491         return getMessages(language->code()).get(l10n);
492 }
493
494
495 BufferParams::Package BufferParams::use_package(std::string const & p) const
496 {
497         PackageMap::const_iterator it = use_packages.find(p);
498         if (it == use_packages.end())
499                 return package_auto;
500         return it->second;
501 }
502
503
504 void BufferParams::use_package(std::string const & p, BufferParams::Package u)
505 {
506         use_packages[p] = u;
507 }
508
509
510 map<string, string> const & BufferParams::auto_packages()
511 {
512         static map<string, string> packages;
513         if (packages.empty()) {
514                 // We could have a race condition here that two threads
515                 // discover an empty map at the same time and want to fill
516                 // it, but that is no problem, since the same contents is
517                 // filled in twice then. Having the locker inside the
518                 // packages.empty() condition has the advantage that we
519                 // don't need the mutex overhead for simple reading.
520                 static Mutex mutex;
521                 Mutex::Locker locker(&mutex);
522                 // adding a package here implies a file format change!
523                 packages["amsmath"] =
524                         N_("The LaTeX package amsmath is only used if AMS formula types or symbols from the AMS math toolbars are inserted into formulas");
525                 packages["amssymb"] =
526                         N_("The LaTeX package amssymb is only used if symbols from the AMS math toolbars are inserted into formulas");
527                 packages["cancel"] =
528                         N_("The LaTeX package cancel is only used if \\cancel commands are used in formulas");
529                 packages["esint"] =
530                         N_("The LaTeX package esint is only used if special integral symbols are inserted into formulas");
531                 packages["mathdots"] =
532                         N_("The LaTeX package mathdots is only used if the command \\iddots is inserted into formulas");
533                 packages["mathtools"] =
534                         N_("The LaTeX package mathtools is only used if some mathematical relations are inserted into formulas");
535                 packages["mhchem"] =
536                         N_("The LaTeX package mhchem is only used if either the command \\ce or \\cf is inserted into formulas");
537                 packages["stackrel"] =
538                         N_("The LaTeX package stackrel is only used if the command \\stackrel with subscript is inserted into formulas");
539                 packages["stmaryrd"] =
540                         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");
541                 packages["undertilde"] =
542                         N_("The LaTeX package undertilde is only used if you use the math frame decoration 'utilde'");
543         }
544         return packages;
545 }
546
547
548 bool BufferParams::useBibtopic() const
549 {
550         if (useBiblatex())
551                 return false;
552         return (use_bibtopic || (!multibib.empty() && multibib != "child"));
553 }
554
555
556 AuthorList & BufferParams::authors()
557 {
558         return pimpl_->authorlist;
559 }
560
561
562 AuthorList const & BufferParams::authors() const
563 {
564         return pimpl_->authorlist;
565 }
566
567
568 void BufferParams::addAuthor(Author const & a)
569 {
570         author_map_[a.bufferId()] = pimpl_->authorlist.record(a);
571 }
572
573
574 BranchList & BufferParams::branchlist()
575 {
576         return pimpl_->branchlist;
577 }
578
579
580 BranchList const & BufferParams::branchlist() const
581 {
582         return pimpl_->branchlist;
583 }
584
585
586 IndicesList & BufferParams::indiceslist()
587 {
588         return pimpl_->indiceslist;
589 }
590
591
592 IndicesList const & BufferParams::indiceslist() const
593 {
594         return pimpl_->indiceslist;
595 }
596
597
598 Bullet & BufferParams::temp_bullet(lyx::size_type const index)
599 {
600         LASSERT(index < 4, return pimpl_->temp_bullets[0]);
601         return pimpl_->temp_bullets[index];
602 }
603
604
605 Bullet const & BufferParams::temp_bullet(lyx::size_type const index) const
606 {
607         LASSERT(index < 4, return pimpl_->temp_bullets[0]);
608         return pimpl_->temp_bullets[index];
609 }
610
611
612 Bullet & BufferParams::user_defined_bullet(lyx::size_type const index)
613 {
614         LASSERT(index < 4, return pimpl_->temp_bullets[0]);
615         return pimpl_->user_defined_bullets[index];
616 }
617
618
619 Bullet const & BufferParams::user_defined_bullet(lyx::size_type const index) const
620 {
621         LASSERT(index < 4, return pimpl_->temp_bullets[0]);
622         return pimpl_->user_defined_bullets[index];
623 }
624
625
626 Spacing & BufferParams::spacing()
627 {
628         return pimpl_->spacing;
629 }
630
631
632 Spacing const & BufferParams::spacing() const
633 {
634         return pimpl_->spacing;
635 }
636
637
638 PDFOptions & BufferParams::pdfoptions()
639 {
640         return pimpl_->pdfoptions;
641 }
642
643
644 PDFOptions const & BufferParams::pdfoptions() const
645 {
646         return pimpl_->pdfoptions;
647 }
648
649
650 Length const & BufferParams::getMathIndent() const
651 {
652         return pimpl_->mathindent;
653 }
654
655
656 void BufferParams::setMathIndent(Length const & indent)
657 {
658         pimpl_->mathindent = indent;
659 }
660
661
662 Length const & BufferParams::getParIndent() const
663 {
664         return pimpl_->parindent;
665 }
666
667
668 void BufferParams::setParIndent(Length const & indent)
669 {
670         pimpl_->parindent = indent;
671 }
672
673
674 VSpace const & BufferParams::getDefSkip() const
675 {
676         return pimpl_->defskip;
677 }
678
679
680 void BufferParams::setDefSkip(VSpace const & vs)
681 {
682         // DEFSKIP will cause an infinite loop
683         LASSERT(vs.kind() != VSpace::DEFSKIP, return);
684         pimpl_->defskip = vs;
685 }
686
687
688 BufferParams::MathNumber BufferParams::getMathNumber() const
689 {
690         if (math_numbering_side != DEFAULT)
691                 return math_numbering_side;
692         // FIXME: do not hardcode language here
693         else if (language->lang() == "arabic_arabi"
694                  || documentClass().provides("leqno"))
695                 return LEFT;
696         else
697                 return RIGHT;
698 }
699
700
701 string BufferParams::readToken(Lexer & lex, string const & token,
702         FileName const & filepath)
703 {
704         string result;
705
706         if (token == "\\textclass") {
707                 lex.next();
708                 string const classname = lex.getString();
709                 // if there exists a local layout file, ignore the system one
710                 // NOTE: in this case, the textclass (.cls file) is assumed to
711                 // be available.
712                 string tcp;
713                 LayoutFileList & bcl = LayoutFileList::get();
714                 if (!filepath.empty()) {
715                         // If classname is an absolute path, the document is
716                         // using a local layout file which could not be accessed
717                         // by a relative path. In this case the path is correct
718                         // even if the document was moved to a different
719                         // location. However, we will have a problem if the
720                         // document was generated on a different platform.
721                         bool isabsolute = FileName::isAbsolute(classname);
722                         string const classpath = onlyPath(classname);
723                         string const path = isabsolute ? classpath
724                                 : FileName(addPath(filepath.absFileName(),
725                                                 classpath)).realPath();
726                         string const oldpath = isabsolute ? string()
727                                 : FileName(addPath(origin, classpath)).realPath();
728                         tcp = bcl.addLocalLayout(onlyFileName(classname), path, oldpath);
729                 }
730                 // that returns non-empty if a "local" layout file is found.
731                 if (!tcp.empty()) {
732                         result = to_utf8(makeRelPath(from_utf8(onlyPath(tcp)),
733                                                 from_utf8(filepath.absFileName())));
734                         if (result.empty())
735                                 result = ".";
736                         setBaseClass(onlyFileName(tcp));
737                 } else
738                         setBaseClass(onlyFileName(classname));
739                 // We assume that a tex class exists for local or unknown
740                 // layouts so this warning, will only be given for system layouts.
741                 if (!baseClass()->isTeXClassAvailable()) {
742                         docstring const desc =
743                                 translateIfPossible(from_utf8(baseClass()->description()));
744                         docstring const prereqs =
745                                 from_utf8(baseClass()->prerequisites());
746                         docstring const msg =
747                                 bformat(_("The selected document class\n"
748                                                  "\t%1$s\n"
749                                                  "requires external files that are not available.\n"
750                                                  "The document class can still be used, but the\n"
751                                                  "document cannot be compiled until the following\n"
752                                                  "prerequisites are installed:\n"
753                                                  "\t%2$s\n"
754                                                  "See section 3.1.2.2 (Class Availability) of the\n"
755                                                  "User's Guide for more information."), desc, prereqs);
756                         frontend::Alert::warning(_("Document class not available"),
757                                        msg, true);
758                 }
759         } else if (token == "\\save_transient_properties") {
760                 lex >> save_transient_properties;
761         } else if (token == "\\origin") {
762                 lex.eatLine();
763                 origin = lex.getString();
764                 string const sysdirprefix = "/systemlyxdir/";
765                 if (prefixIs(origin, sysdirprefix)) {
766                         string docsys;
767                         if (inSystemDir(filepath, docsys))
768                                 origin.replace(0, sysdirprefix.length() - 1, docsys);
769                         else
770                                 origin.replace(0, sysdirprefix.length() - 1,
771                                         package().system_support().absFileName());
772                 }
773         } else if (token == "\\begin_preamble") {
774                 readPreamble(lex);
775         } else if (token == "\\begin_local_layout") {
776                 readLocalLayout(lex, false);
777         } else if (token == "\\begin_forced_local_layout") {
778                 readLocalLayout(lex, true);
779         } else if (token == "\\begin_modules") {
780                 readModules(lex);
781         } else if (token == "\\begin_removed_modules") {
782                 readRemovedModules(lex);
783         } else if (token == "\\begin_includeonly") {
784                 readIncludeonly(lex);
785         } else if (token == "\\maintain_unincluded_children") {
786                 string tmp;
787                 lex >> tmp;
788                 if (tmp == "no")
789                         maintain_unincluded_children = CM_None;
790                 else if (tmp == "mostly")
791                         maintain_unincluded_children = CM_Mostly;
792                 else if (tmp == "strict")
793                         maintain_unincluded_children = CM_Strict;
794         } else if (token == "\\options") {
795                 lex.eatLine();
796                 options = lex.getString();
797         } else if (token == "\\use_default_options") {
798                 lex >> use_default_options;
799         } else if (token == "\\master") {
800                 lex.eatLine();
801                 master = lex.getString();
802                 if (!filepath.empty() && FileName::isAbsolute(origin)) {
803                         bool const isabs = FileName::isAbsolute(master);
804                         FileName const abspath(isabs ? master : origin + master);
805                         bool const moved = filepath != FileName(origin);
806                         if (moved && abspath.exists()) {
807                                 docstring const path = isabs
808                                         ? from_utf8(master)
809                                         : from_utf8(abspath.realPath());
810                                 docstring const refpath =
811                                         from_utf8(filepath.absFileName());
812                                 master = to_utf8(makeRelPath(path, refpath));
813                         }
814                 }
815         } else if (token == "\\suppress_date") {
816                 lex >> suppress_date;
817         } else if (token == "\\justification") {
818                 lex >> justification;
819         } else if (token == "\\language") {
820                 readLanguage(lex);
821         } else if (token == "\\language_package") {
822                 lex.eatLine();
823                 lang_package = lex.getString();
824         } else if (token == "\\inputencoding") {
825                 lex >> inputenc;
826         } else if (token == "\\graphics") {
827                 readGraphicsDriver(lex);
828         } else if (token == "\\default_output_format") {
829                 lex >> default_output_format;
830         } else if (token == "\\bibtex_command") {
831                 lex.eatLine();
832                 bibtex_command = lex.getString();
833         } else if (token == "\\index_command") {
834                 lex.eatLine();
835                 index_command = lex.getString();
836         } else if (token == "\\fontencoding") {
837                 lex.eatLine();
838                 fontenc = lex.getString();
839         } else if (token == "\\font_roman") {
840                 lex >> fonts_roman[0];
841                 lex >> fonts_roman[1];
842         } else if (token == "\\font_sans") {
843                 lex >> fonts_sans[0];
844                 lex >> fonts_sans[1];
845         } else if (token == "\\font_typewriter") {
846                 lex >> fonts_typewriter[0];
847                 lex >> fonts_typewriter[1];
848         } else if (token == "\\font_math") {
849                 lex >> fonts_math[0];
850                 lex >> fonts_math[1];
851         } else if (token == "\\font_default_family") {
852                 lex >> fonts_default_family;
853         } else if (token == "\\use_non_tex_fonts") {
854                 lex >> useNonTeXFonts;
855         } else if (token == "\\font_sc") {
856                 lex >> fonts_expert_sc;
857         } else if (token == "\\font_roman_osf") {
858                 lex >> fonts_roman_osf;
859         } else if (token == "\\font_sans_osf") {
860                 lex >> fonts_sans_osf;
861         } else if (token == "\\font_typewriter_osf") {
862                 lex >> fonts_typewriter_osf;
863         } else if (token == "\\font_roman_opts") {
864                 lex >> font_roman_opts;
865         } else if (token == "\\font_sf_scale") {
866                 lex >> fonts_sans_scale[0];
867                 lex >> fonts_sans_scale[1];
868         } else if (token == "\\font_sans_opts") {
869                 lex >> font_sans_opts;
870         } else if (token == "\\font_tt_scale") {
871                 lex >> fonts_typewriter_scale[0];
872                 lex >> fonts_typewriter_scale[1];
873         } else if (token == "\\font_typewriter_opts") {
874                 lex >> font_typewriter_opts;
875         } else if (token == "\\font_cjk") {
876                 lex >> fonts_cjk;
877         } else if (token == "\\use_microtype") {
878                 lex >> use_microtype;
879         } else if (token == "\\use_dash_ligatures") {
880                 lex >> use_dash_ligatures;
881         } else if (token == "\\paragraph_separation") {
882                 string parsep;
883                 lex >> parsep;
884                 paragraph_separation = parseptranslator().find(parsep);
885         } else if (token == "\\paragraph_indentation") {
886                 lex.next();
887                 string parindent = lex.getString();
888                 if (parindent == "default")
889                         pimpl_->parindent = Length();
890                 else
891                         pimpl_->parindent = Length(parindent);
892         } else if (token == "\\defskip") {
893                 lex.next();
894                 string const defskip = lex.getString();
895                 pimpl_->defskip = VSpace(defskip);
896                 if (pimpl_->defskip.kind() == VSpace::DEFSKIP)
897                         // that is invalid
898                         pimpl_->defskip = VSpace(VSpace::MEDSKIP);
899         } else if (token == "\\is_math_indent") {
900                 lex >> is_math_indent;
901         } else if (token == "\\math_indentation") {
902                 lex.next();
903                 string mathindent = lex.getString();
904                 if (mathindent == "default")
905                         pimpl_->mathindent = Length();
906                 else
907                         pimpl_->mathindent = Length(mathindent);
908         } else if (token == "\\math_numbering_side") {
909                 string tmp;
910                 lex >> tmp;
911                 if (tmp == "left")
912                         math_numbering_side = LEFT;
913                 else if (tmp == "right")
914                         math_numbering_side = RIGHT;
915                 else
916                         math_numbering_side = DEFAULT;
917         } else if (token == "\\quotes_style") {
918                 string qstyle;
919                 lex >> qstyle;
920                 quotes_style = quotesstyletranslator().find(qstyle);
921         } else if (token == "\\dynamic_quotes") {
922                 lex >> dynamic_quotes;
923         } else if (token == "\\papersize") {
924                 string ppsize;
925                 lex >> ppsize;
926                 papersize = papersizetranslator().find(ppsize);
927         } else if (token == "\\use_geometry") {
928                 lex >> use_geometry;
929         } else if (token == "\\use_package") {
930                 string package;
931                 int use;
932                 lex >> package;
933                 lex >> use;
934                 use_package(package, packagetranslator().find(use));
935         } else if (token == "\\cite_engine") {
936                 lex.eatLine();
937                 cite_engine_ = lex.getString();
938         } else if (token == "\\cite_engine_type") {
939                 string engine_type;
940                 lex >> engine_type;
941                 cite_engine_type_ = theCiteEnginesList.getType(engine_type);
942         } else if (token == "\\biblio_style") {
943                 lex.eatLine();
944                 biblio_style = lex.getString();
945         } else if (token == "\\biblio_options") {
946                 lex.eatLine();
947                 biblio_opts = trim(lex.getString());
948         } else if (token == "\\biblatex_bibstyle") {
949                 lex.eatLine();
950                 biblatex_bibstyle = trim(lex.getString());
951         } else if (token == "\\biblatex_citestyle") {
952                 lex.eatLine();
953                 biblatex_citestyle = trim(lex.getString());
954         } else if (token == "\\use_bibtopic") {
955                 lex >> use_bibtopic;
956         } else if (token == "\\multibib") {
957                 lex >> multibib;
958         } else if (token == "\\use_indices") {
959                 lex >> use_indices;
960         } else if (token == "\\tracking_changes") {
961                 lex >> track_changes;
962         } else if (token == "\\output_changes") {
963                 lex >> output_changes;
964         } else if (token == "\\change_bars") {
965                 lex >> change_bars;
966         } else if (token == "\\postpone_fragile_content") {
967                 lex >> postpone_fragile_content;
968         } else if (token == "\\branch") {
969                 lex.eatLine();
970                 docstring branch = lex.getDocString();
971                 branchlist().add(branch);
972                 while (true) {
973                         lex.next();
974                         string const tok = lex.getString();
975                         if (tok == "\\end_branch")
976                                 break;
977                         Branch * branch_ptr = branchlist().find(branch);
978                         if (tok == "\\selected") {
979                                 lex.next();
980                                 if (branch_ptr)
981                                         branch_ptr->setSelected(lex.getInteger());
982                         }
983                         if (tok == "\\filename_suffix") {
984                                 lex.next();
985                                 if (branch_ptr)
986                                         branch_ptr->setFileNameSuffix(lex.getInteger());
987                         }
988                         if (tok == "\\color") {
989                                 lex.eatLine();
990                                 string color = lex.getString();
991                                 if (branch_ptr)
992                                         branch_ptr->setColor(color);
993                                 // Update also the Color table:
994                                 if (color == "none")
995                                         color = lcolor.getX11HexName(Color_background);
996                                 // FIXME UNICODE
997                                 lcolor.setColor(to_utf8(branch), color);
998                         }
999                 }
1000         } else if (token == "\\index") {
1001                 lex.eatLine();
1002                 docstring index = lex.getDocString();
1003                 docstring shortcut;
1004                 indiceslist().add(index);
1005                 while (true) {
1006                         lex.next();
1007                         string const tok = lex.getString();
1008                         if (tok == "\\end_index")
1009                                 break;
1010                         Index * index_ptr = indiceslist().find(index);
1011                         if (tok == "\\shortcut") {
1012                                 lex.next();
1013                                 shortcut = lex.getDocString();
1014                                 if (index_ptr)
1015                                         index_ptr->setShortcut(shortcut);
1016                         }
1017                         if (tok == "\\color") {
1018                                 lex.eatLine();
1019                                 string color = lex.getString();
1020                                 if (index_ptr)
1021                                         index_ptr->setColor(color);
1022                                 // Update also the Color table:
1023                                 if (color == "none")
1024                                         color = lcolor.getX11HexName(Color_background);
1025                                 // FIXME UNICODE
1026                                 if (!shortcut.empty())
1027                                         lcolor.setColor(to_utf8(shortcut), color);
1028                         }
1029                 }
1030         } else if (token == "\\author") {
1031                 lex.eatLine();
1032                 istringstream ss(lex.getString());
1033                 Author a;
1034                 ss >> a;
1035                 addAuthor(a);
1036         } else if (token == "\\paperorientation") {
1037                 string orient;
1038                 lex >> orient;
1039                 orientation = paperorientationtranslator().find(orient);
1040         } else if (token == "\\backgroundcolor") {
1041                 lex.eatLine();
1042                 backgroundcolor = lyx::rgbFromHexName(lex.getString());
1043                 isbackgroundcolor = true;
1044         } else if (token == "\\fontcolor") {
1045                 lex.eatLine();
1046                 fontcolor = lyx::rgbFromHexName(lex.getString());
1047                 isfontcolor = true;
1048         } else if (token == "\\notefontcolor") {
1049                 lex.eatLine();
1050                 string color = lex.getString();
1051                 notefontcolor = lyx::rgbFromHexName(color);
1052                 lcolor.setColor("notefontcolor", color);
1053         } else if (token == "\\boxbgcolor") {
1054                 lex.eatLine();
1055                 string color = lex.getString();
1056                 boxbgcolor = lyx::rgbFromHexName(color);
1057                 lcolor.setColor("boxbgcolor", color);
1058         } else if (token == "\\paperwidth") {
1059                 lex >> paperwidth;
1060         } else if (token == "\\paperheight") {
1061                 lex >> paperheight;
1062         } else if (token == "\\leftmargin") {
1063                 lex >> leftmargin;
1064         } else if (token == "\\topmargin") {
1065                 lex >> topmargin;
1066         } else if (token == "\\rightmargin") {
1067                 lex >> rightmargin;
1068         } else if (token == "\\bottommargin") {
1069                 lex >> bottommargin;
1070         } else if (token == "\\headheight") {
1071                 lex >> headheight;
1072         } else if (token == "\\headsep") {
1073                 lex >> headsep;
1074         } else if (token == "\\footskip") {
1075                 lex >> footskip;
1076         } else if (token == "\\columnsep") {
1077                 lex >> columnsep;
1078         } else if (token == "\\paperfontsize") {
1079                 lex >> fontsize;
1080         } else if (token == "\\papercolumns") {
1081                 lex >> columns;
1082         } else if (token == "\\listings_params") {
1083                 string par;
1084                 lex >> par;
1085                 listings_params = InsetListingsParams(par).params();
1086         } else if (token == "\\papersides") {
1087                 int psides;
1088                 lex >> psides;
1089                 sides = sidestranslator().find(psides);
1090         } else if (token == "\\paperpagestyle") {
1091                 lex >> pagestyle;
1092         } else if (token == "\\tablestyle") {
1093                 lex >> tablestyle;
1094         } else if (token == "\\bullet") {
1095                 readBullets(lex);
1096         } else if (token == "\\bulletLaTeX") {
1097                 readBulletsLaTeX(lex);
1098         } else if (token == "\\secnumdepth") {
1099                 lex >> secnumdepth;
1100         } else if (token == "\\tocdepth") {
1101                 lex >> tocdepth;
1102         } else if (token == "\\spacing") {
1103                 string nspacing;
1104                 lex >> nspacing;
1105                 string tmp_val;
1106                 if (nspacing == "other") {
1107                         lex >> tmp_val;
1108                 }
1109                 spacing().set(spacetranslator().find(nspacing), tmp_val);
1110         } else if (token == "\\float_placement") {
1111                 lex >> float_placement;
1112         } else if (token == "\\float_alignment") {
1113                 lex >> float_alignment;
1114
1115         } else if (prefixIs(token, "\\pdf_") || token == "\\use_hyperref") {
1116                 string toktmp = pdfoptions().readToken(lex, token);
1117                 if (!toktmp.empty()) {
1118                         lyxerr << "PDFOptions::readToken(): Unknown token: " <<
1119                                 toktmp << endl;
1120                         return toktmp;
1121                 }
1122         } else if (token == "\\html_math_output") {
1123                 int temp;
1124                 lex >> temp;
1125                 html_math_output = static_cast<MathOutput>(temp);
1126         } else if (token == "\\html_be_strict") {
1127                 lex >> html_be_strict;
1128         } else if (token == "\\html_css_as_file") {
1129                 lex >> html_css_as_file;
1130         } else if (token == "\\html_math_img_scale") {
1131                 lex >> html_math_img_scale;
1132         } else if (token == "\\html_latex_start") {
1133                 lex.eatLine();
1134                 html_latex_start = lex.getString();
1135         } else if (token == "\\html_latex_end") {
1136                 lex.eatLine();
1137                 html_latex_end = lex.getString();
1138         } else if (token == "\\docbook_table_output") {
1139                 int temp;
1140                 lex >> temp;
1141                 docbook_table_output = static_cast<TableOutput>(temp);
1142         } else if (token == "\\output_sync") {
1143                 lex >> output_sync;
1144         } else if (token == "\\output_sync_macro") {
1145                 lex >> output_sync_macro;
1146         } else if (token == "\\use_refstyle") {
1147                 lex >> use_refstyle;
1148         } else if (token == "\\use_minted") {
1149                 lex >> use_minted;
1150         } else if (token == "\\use_lineno") {
1151                 lex >> use_lineno;
1152         } else if (token == "\\lineno_options") {
1153                 lex.eatLine();
1154                 lineno_opts = trim(lex.getString());
1155         } else {
1156                 lyxerr << "BufferParams::readToken(): Unknown token: " <<
1157                         token << endl;
1158                 return token;
1159         }
1160
1161         return result;
1162 }
1163
1164
1165 namespace {
1166         // Quote argument if it contains spaces
1167         string quoteIfNeeded(string const & str) {
1168                 if (contains(str, ' '))
1169                         return "\"" + str + "\"";
1170                 return str;
1171         }
1172 } // namespace
1173
1174
1175 void BufferParams::writeFile(ostream & os, Buffer const * buf) const
1176 {
1177         // The top of the file is written by the buffer.
1178         // Prints out the buffer info into the .lyx file given by file
1179
1180         os << "\\save_transient_properties "
1181            << convert<string>(save_transient_properties) << '\n';
1182
1183         // the document directory (must end with a path separator)
1184         // realPath() is used to resolve symlinks, while addPath(..., "")
1185         // ensures a trailing path separator.
1186         string docsys;
1187         string filepath = addPath(buf->fileName().onlyPath().realPath(), "");
1188         string const sysdir = inSystemDir(FileName(filepath), docsys) ? docsys
1189                         : addPath(package().system_support().realPath(), "");
1190         string const relpath =
1191                 to_utf8(makeRelPath(from_utf8(filepath), from_utf8(sysdir)));
1192         if (!prefixIs(relpath, "../") && !FileName::isAbsolute(relpath))
1193                 filepath = addPath("/systemlyxdir", relpath);
1194         else if (!save_transient_properties || !lyxrc.save_origin)
1195                 filepath = "unavailable";
1196         os << "\\origin " << quoteIfNeeded(filepath) << '\n';
1197
1198         // the textclass
1199         os << "\\textclass "
1200            << quoteIfNeeded(buf->includedFilePath(addName(buf->layoutPos(),
1201                                                 baseClass()->name()), "layout"))
1202            << '\n';
1203
1204         // then the preamble
1205         if (!preamble.empty()) {
1206                 // remove '\n' from the end of preamble
1207                 docstring const tmppreamble = rtrim(preamble, "\n");
1208                 os << "\\begin_preamble\n"
1209                    << to_utf8(tmppreamble)
1210                    << "\n\\end_preamble\n";
1211         }
1212
1213         // the options
1214         if (!options.empty()) {
1215                 os << "\\options " << options << '\n';
1216         }
1217
1218         // use the class options defined in the layout?
1219         os << "\\use_default_options "
1220            << convert<string>(use_default_options) << "\n";
1221
1222         // the master document
1223         if (!master.empty()) {
1224                 os << "\\master " << master << '\n';
1225         }
1226
1227         // removed modules
1228         if (!removed_modules_.empty()) {
1229                 os << "\\begin_removed_modules" << '\n';
1230                 for (auto const & mod : removed_modules_)
1231                         os << mod << '\n';
1232                 os << "\\end_removed_modules" << '\n';
1233         }
1234
1235         // the modules
1236         if (!layout_modules_.empty()) {
1237                 os << "\\begin_modules" << '\n';
1238                 for (auto const & mod : layout_modules_)
1239                         os << mod << '\n';
1240                 os << "\\end_modules" << '\n';
1241         }
1242
1243         // includeonly
1244         if (!included_children_.empty()) {
1245                 os << "\\begin_includeonly" << '\n';
1246                 for (auto const & c : included_children_)
1247                         os << c << '\n';
1248                 os << "\\end_includeonly" << '\n';
1249         }
1250         string muc = "no";
1251         switch (maintain_unincluded_children) {
1252         case CM_Mostly:
1253                 muc = "mostly";
1254                 break;
1255         case CM_Strict:
1256                 muc = "strict";
1257                 break;
1258         case CM_None:
1259         default:
1260                 break;
1261         }
1262         os << "\\maintain_unincluded_children " << muc << '\n';
1263
1264         // local layout information
1265         docstring const local_layout = getLocalLayout(false);
1266         if (!local_layout.empty()) {
1267                 // remove '\n' from the end
1268                 docstring const tmplocal = rtrim(local_layout, "\n");
1269                 os << "\\begin_local_layout\n"
1270                    << to_utf8(tmplocal)
1271                    << "\n\\end_local_layout\n";
1272         }
1273         docstring const forced_local_layout = getLocalLayout(true);
1274         if (!forced_local_layout.empty()) {
1275                 // remove '\n' from the end
1276                 docstring const tmplocal = rtrim(forced_local_layout, "\n");
1277                 os << "\\begin_forced_local_layout\n"
1278                    << to_utf8(tmplocal)
1279                    << "\n\\end_forced_local_layout\n";
1280         }
1281
1282         // then the text parameters
1283         if (language != ignore_language)
1284                 os << "\\language " << language->lang() << '\n';
1285         os << "\\language_package " << lang_package
1286            << "\n\\inputencoding " << inputenc
1287            << "\n\\fontencoding " << fontenc
1288            << "\n\\font_roman \"" << fonts_roman[0]
1289            << "\" \"" << fonts_roman[1] << '"'
1290            << "\n\\font_sans \"" << fonts_sans[0]
1291            << "\" \"" << fonts_sans[1] << '"'
1292            << "\n\\font_typewriter \"" << fonts_typewriter[0]
1293            << "\" \"" << fonts_typewriter[1] << '"'
1294            << "\n\\font_math \"" << fonts_math[0]
1295            << "\" \"" << fonts_math[1] << '"'
1296            << "\n\\font_default_family " << fonts_default_family
1297            << "\n\\use_non_tex_fonts " << convert<string>(useNonTeXFonts)
1298            << "\n\\font_sc " << convert<string>(fonts_expert_sc)
1299            << "\n\\font_roman_osf " << convert<string>(fonts_roman_osf)
1300            << "\n\\font_sans_osf " << convert<string>(fonts_sans_osf)
1301            << "\n\\font_typewriter_osf " << convert<string>(fonts_typewriter_osf);
1302         if (!font_roman_opts.empty())
1303                 os << "\n\\font_roman_opts \"" << font_roman_opts << "\"";
1304         os << "\n\\font_sf_scale " << fonts_sans_scale[0]
1305            << ' ' << fonts_sans_scale[1];
1306         if (!font_sans_opts.empty())
1307                 os << "\n\\font_sans_opts \"" << font_sans_opts << "\"";
1308         os << "\n\\font_tt_scale " << fonts_typewriter_scale[0]
1309            << ' ' << fonts_typewriter_scale[1];
1310         if (!font_typewriter_opts.empty())
1311                 os << "\n\\font_typewriter_opts \"" << font_typewriter_opts << "\"";
1312         os << '\n';
1313         if (!fonts_cjk.empty())
1314                 os << "\\font_cjk " << fonts_cjk << '\n';
1315         os << "\\use_microtype " << convert<string>(use_microtype) << '\n';
1316         os << "\\use_dash_ligatures " << convert<string>(use_dash_ligatures) << '\n';
1317         os << "\\graphics " << graphics_driver << '\n';
1318         os << "\\default_output_format " << default_output_format << '\n';
1319         os << "\\output_sync " << output_sync << '\n';
1320         if (!output_sync_macro.empty())
1321                 os << "\\output_sync_macro \"" << output_sync_macro << "\"\n";
1322         os << "\\bibtex_command " << bibtex_command << '\n';
1323         os << "\\index_command " << index_command << '\n';
1324
1325         if (!float_placement.empty())
1326                 os << "\\float_placement " << float_placement << '\n';
1327         if (!float_alignment.empty())
1328                 os << "\\float_alignment " << float_alignment << '\n';
1329         os << "\\paperfontsize " << fontsize << '\n';
1330
1331         spacing().writeFile(os);
1332         pdfoptions().writeFile(os);
1333
1334         os << "\\papersize " << string_papersize[papersize]
1335            << "\n\\use_geometry " << convert<string>(use_geometry);
1336         map<string, string> const & packages = auto_packages();
1337         for (auto const & pack : packages)
1338                 os << "\n\\use_package " << pack.first << ' '
1339                    << use_package(pack.first);
1340
1341         os << "\n\\cite_engine ";
1342
1343         if (!cite_engine_.empty())
1344                 os << cite_engine_;
1345         else
1346                 os << "basic";
1347
1348         os << "\n\\cite_engine_type " << theCiteEnginesList.getTypeAsString(cite_engine_type_);
1349
1350         if (!biblio_style.empty())
1351                 os << "\n\\biblio_style " << biblio_style;
1352         if (!biblio_opts.empty())
1353                 os << "\n\\biblio_options " << biblio_opts;
1354         if (!biblatex_bibstyle.empty())
1355                 os << "\n\\biblatex_bibstyle " << biblatex_bibstyle;
1356         if (!biblatex_citestyle.empty())
1357                 os << "\n\\biblatex_citestyle " << biblatex_citestyle;
1358         if (!multibib.empty())
1359                 os << "\n\\multibib " << multibib;
1360
1361         os << "\n\\use_bibtopic " << convert<string>(use_bibtopic)
1362            << "\n\\use_indices " << convert<string>(use_indices)
1363            << "\n\\paperorientation " << string_orientation[orientation]
1364            << "\n\\suppress_date " << convert<string>(suppress_date)
1365            << "\n\\justification " << convert<string>(justification)
1366            << "\n\\use_refstyle " << use_refstyle
1367            << "\n\\use_minted " << use_minted
1368            << "\n\\use_lineno " << use_lineno
1369            << '\n';
1370
1371         if (!lineno_opts.empty())
1372                 os << "\\lineno_options " << lineno_opts << '\n';
1373
1374         if (isbackgroundcolor)
1375                 os << "\\backgroundcolor " << lyx::X11hexname(backgroundcolor) << '\n';
1376         if (isfontcolor)
1377                 os << "\\fontcolor " << lyx::X11hexname(fontcolor) << '\n';
1378         if (notefontcolor != lyx::rgbFromHexName("#cccccc"))
1379                 os << "\\notefontcolor " << lyx::X11hexname(notefontcolor) << '\n';
1380         if (boxbgcolor != lyx::rgbFromHexName("#ff0000"))
1381                 os << "\\boxbgcolor " << lyx::X11hexname(boxbgcolor) << '\n';
1382
1383         for (auto const & br : branchlist()) {
1384                 os << "\\branch " << to_utf8(br.branch())
1385                    << "\n\\selected " << br.isSelected()
1386                    << "\n\\filename_suffix " << br.hasFileNameSuffix()
1387                    << "\n\\color " << lyx::X11hexname(br.color())
1388                    << "\n\\end_branch"
1389                    << "\n";
1390         }
1391
1392         for (auto const & id : indiceslist()) {
1393                 os << "\\index " << to_utf8(id.index())
1394                    << "\n\\shortcut " << to_utf8(id.shortcut())
1395                    << "\n\\color " << lyx::X11hexname(id.color())
1396                    << "\n\\end_index"
1397                    << "\n";
1398         }
1399
1400         if (!paperwidth.empty())
1401                 os << "\\paperwidth "
1402                    << VSpace(paperwidth).asLyXCommand() << '\n';
1403         if (!paperheight.empty())
1404                 os << "\\paperheight "
1405                    << VSpace(paperheight).asLyXCommand() << '\n';
1406         if (!leftmargin.empty())
1407                 os << "\\leftmargin "
1408                    << VSpace(leftmargin).asLyXCommand() << '\n';
1409         if (!topmargin.empty())
1410                 os << "\\topmargin "
1411                    << VSpace(topmargin).asLyXCommand() << '\n';
1412         if (!rightmargin.empty())
1413                 os << "\\rightmargin "
1414                    << VSpace(rightmargin).asLyXCommand() << '\n';
1415         if (!bottommargin.empty())
1416                 os << "\\bottommargin "
1417                    << VSpace(bottommargin).asLyXCommand() << '\n';
1418         if (!headheight.empty())
1419                 os << "\\headheight "
1420                    << VSpace(headheight).asLyXCommand() << '\n';
1421         if (!headsep.empty())
1422                 os << "\\headsep "
1423                    << VSpace(headsep).asLyXCommand() << '\n';
1424         if (!footskip.empty())
1425                 os << "\\footskip "
1426                    << VSpace(footskip).asLyXCommand() << '\n';
1427         if (!columnsep.empty())
1428                 os << "\\columnsep "
1429                          << VSpace(columnsep).asLyXCommand() << '\n';
1430         os << "\\secnumdepth " << secnumdepth
1431            << "\n\\tocdepth " << tocdepth
1432            << "\n\\paragraph_separation "
1433            << string_paragraph_separation[paragraph_separation];
1434         if (!paragraph_separation)
1435                 os << "\n\\paragraph_indentation "
1436                    << (getParIndent().empty() ? "default" : getParIndent().asString());
1437         else
1438                 os << "\n\\defskip " << getDefSkip().asLyXCommand();
1439         os << "\n\\is_math_indent " << is_math_indent;
1440         if (is_math_indent)
1441                 os << "\n\\math_indentation "
1442                    << (getMathIndent().empty() ? "default" : getMathIndent().asString());
1443         os << "\n\\math_numbering_side ";
1444         switch(math_numbering_side) {
1445         case LEFT:
1446                 os << "left";
1447                 break;
1448         case RIGHT:
1449                 os << "right";
1450                 break;
1451         case DEFAULT:
1452                 os << "default";
1453         }
1454         os << "\n\\quotes_style "
1455            << string_quotes_style[quotes_style]
1456            << "\n\\dynamic_quotes " << dynamic_quotes
1457            << "\n\\papercolumns " << columns
1458            << "\n\\papersides " << sides
1459            << "\n\\paperpagestyle " << pagestyle
1460            << "\n\\tablestyle " << tablestyle << '\n';
1461         if (!listings_params.empty())
1462                 os << "\\listings_params \"" <<
1463                         InsetListingsParams(listings_params).encodedString() << "\"\n";
1464         for (int i = 0; i < 4; ++i) {
1465                 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
1466                         if (user_defined_bullet(i).getFont() != -1) {
1467                                 os << "\\bullet " << i << " "
1468                                    << user_defined_bullet(i).getFont() << " "
1469                                    << user_defined_bullet(i).getCharacter() << " "
1470                                    << user_defined_bullet(i).getSize() << "\n";
1471                         }
1472                         else {
1473                                 // FIXME UNICODE
1474                                 os << "\\bulletLaTeX " << i << " \""
1475                                    << lyx::to_ascii(user_defined_bullet(i).getText())
1476                                    << "\"\n";
1477                         }
1478                 }
1479         }
1480
1481         os << "\\tracking_changes "
1482            << (save_transient_properties ? convert<string>(track_changes) : "false")
1483            << '\n';
1484
1485         os << "\\output_changes "
1486            << (save_transient_properties ? convert<string>(output_changes) : "false")
1487            << '\n';
1488
1489         os << "\\change_bars "
1490            << (save_transient_properties ? convert<string>(change_bars) : "false")
1491            << '\n';
1492
1493         os << "\\postpone_fragile_content " << convert<string>(postpone_fragile_content) << '\n';
1494
1495         os << "\\html_math_output " << html_math_output << '\n'
1496            << "\\html_css_as_file " << html_css_as_file << '\n'
1497            << "\\html_be_strict " << convert<string>(html_be_strict) << '\n';
1498
1499         os << "\\docbook_table_output " << docbook_table_output << '\n';
1500
1501         if (html_math_img_scale != 1.0)
1502                 os << "\\html_math_img_scale " << convert<string>(html_math_img_scale) << '\n';
1503         if (!html_latex_start.empty())
1504                 os << "\\html_latex_start " << html_latex_start << '\n';
1505         if (!html_latex_end.empty())
1506                  os << "\\html_latex_end " << html_latex_end << '\n';
1507
1508         os << pimpl_->authorlist;
1509 }
1510
1511
1512 void BufferParams::validate(LaTeXFeatures & features) const
1513 {
1514         features.require(documentClass().required());
1515
1516         if (columns > 1 && language->rightToLeft())
1517                 features.require("rtloutputdblcol");
1518
1519         if (output_changes) {
1520                 bool xcolorulem = LaTeXFeatures::isAvailable("ulem") &&
1521                                   LaTeXFeatures::isAvailable("xcolor");
1522
1523                 switch (features.runparams().flavor) {
1524                 case OutputParams::LATEX:
1525                 case OutputParams::DVILUATEX:
1526                         if (xcolorulem) {
1527                                 features.require("ct-xcolor-ulem");
1528                                 features.require("ulem");
1529                                 features.require("xcolor");
1530                         } else {
1531                                 features.require("ct-none");
1532                         }
1533                         break;
1534                 case OutputParams::LUATEX:
1535                 case OutputParams::PDFLATEX:
1536                 case OutputParams::XETEX:
1537                         if (xcolorulem) {
1538                                 features.require("ct-xcolor-ulem");
1539                                 features.require("ulem");
1540                                 features.require("xcolor");
1541                                 // improves color handling in PDF output
1542                                 features.require("pdfcolmk");
1543                         } else {
1544                                 features.require("ct-none");
1545                         }
1546                         break;
1547                 default:
1548                         break;
1549                 }
1550                 if (change_bars)
1551                         features.require("changebar");
1552         }
1553
1554         // Floats with 'Here definitely' as default setting.
1555         if (float_placement.find('H') != string::npos)
1556                 features.require("float");
1557
1558         for (auto const & pm : use_packages) {
1559                 if (pm.first == "amsmath") {
1560                         // AMS Style is at document level
1561                         if (pm.second == package_on ||
1562                             features.isProvided("amsmath"))
1563                                 features.require(pm.first);
1564                 } else if (pm.second == package_on)
1565                         features.require(pm.first);
1566         }
1567
1568         // Document-level line spacing
1569         if (spacing().getSpace() != Spacing::Single && !spacing().isDefault())
1570                 features.require("setspace");
1571
1572         // the bullet shapes are buffer level not paragraph level
1573         // so they are tested here
1574         for (int i = 0; i < 4; ++i) {
1575                 if (user_defined_bullet(i) == ITEMIZE_DEFAULTS[i])
1576                         continue;
1577                 int const font = user_defined_bullet(i).getFont();
1578                 if (font == 0) {
1579                         int const c = user_defined_bullet(i).getCharacter();
1580                         if (c == 16
1581                             || c == 17
1582                             || c == 25
1583                             || c == 26
1584                             || c == 31) {
1585                                 features.require("latexsym");
1586                         }
1587                 } else if (font == 1) {
1588                         features.require("amssymb");
1589                 } else if (font >= 2 && font <= 5) {
1590                         features.require("pifont");
1591                 }
1592         }
1593
1594         if (pdfoptions().use_hyperref) {
1595                 features.require("hyperref");
1596                 // due to interferences with babel and hyperref, the color package has to
1597                 // be loaded after hyperref when hyperref is used with the colorlinks
1598                 // option, see http://www.lyx.org/trac/ticket/5291
1599                 if (pdfoptions().colorlinks)
1600                         features.require("color");
1601         }
1602         if (!listings_params.empty()) {
1603                 // do not test validity because listings_params is
1604                 // supposed to be valid
1605                 string par =
1606                         InsetListingsParams(listings_params).separatedParams(true);
1607                 // we can't support all packages, but we should load the color package
1608                 if (par.find("\\color", 0) != string::npos)
1609                         features.require("color");
1610         }
1611
1612         // some languages are only available via polyglossia
1613         if (features.hasPolyglossiaExclusiveLanguages())
1614                 features.require("polyglossia");
1615
1616         if (useNonTeXFonts && fontsMath() != "auto")
1617                 features.require("unicode-math");
1618
1619         if (use_microtype)
1620                 features.require("microtype");
1621
1622         if (!language->required().empty())
1623                 features.require(language->required());
1624 }
1625
1626
1627 bool BufferParams::writeLaTeX(otexstream & os, LaTeXFeatures & features,
1628                               FileName const & filepath) const
1629 {
1630         // http://www.tug.org/texmf-dist/doc/latex/base/fixltx2e.pdf
1631         // !! To use the Fix-cm package, load it before \documentclass, and use the command
1632         // \RequirePackage to do so, rather than the normal \usepackage
1633         // Do not try to load any other package before the document class, unless you
1634         // have a thorough understanding of the LATEX internals and know exactly what you
1635         // are doing!
1636         if (features.mustProvide("fix-cm"))
1637                 os << "\\RequirePackage{fix-cm}\n";
1638         // Likewise for fixltx2e. If other packages conflict with this policy,
1639         // treat it as a package bug (and report it!)
1640         // See http://www.latex-project.org/cgi-bin/ltxbugs2html?pr=latex/4407
1641         if (features.mustProvide("fixltx2e"))
1642                 os << "\\RequirePackage{fixltx2e}\n";
1643
1644         os << "\\documentclass";
1645
1646         DocumentClass const & tclass = documentClass();
1647
1648         ostringstream clsoptions; // the document class options.
1649
1650         if (tokenPos(tclass.opt_fontsize(),
1651                      '|', fontsize) >= 0) {
1652                 // only write if existing in list (and not default)
1653                 clsoptions << subst(tclass.fontsizeformat(), "$$s", fontsize) << ",";
1654         }
1655
1656         // paper sizes not supported by the class itself need the
1657         // geometry package
1658         vector<string> classpsizes = getVectorFromString(tclass.opt_pagesize(), "|");
1659         bool class_supported_papersize = papersize == PAPER_DEFAULT
1660                 || find(classpsizes.begin(), classpsizes.end(), string_papersize[papersize]) != classpsizes.end();
1661
1662         if ((!use_geometry || features.isProvided("geometry-light"))
1663             && class_supported_papersize && papersize != PAPER_DEFAULT)
1664                 clsoptions << subst(tclass.pagesizeformat(), "$$s", string_papersize[papersize]) << ",";
1665
1666         // if needed
1667         if (sides != tclass.sides()) {
1668                 switch (sides) {
1669                 case OneSide:
1670                         clsoptions << "oneside,";
1671                         break;
1672                 case TwoSides:
1673                         clsoptions << "twoside,";
1674                         break;
1675                 }
1676         }
1677
1678         // if needed
1679         if (columns != tclass.columns()) {
1680                 if (columns == 2)
1681                         clsoptions << "twocolumn,";
1682                 else
1683                         clsoptions << "onecolumn,";
1684         }
1685
1686         if (!use_geometry
1687             && orientation == ORIENTATION_LANDSCAPE)
1688                 clsoptions << "landscape,";
1689
1690         if (is_math_indent)
1691                 clsoptions << "fleqn,";
1692
1693         switch(math_numbering_side) {
1694         case LEFT:
1695                 clsoptions << "leqno,";
1696                 break;
1697         case RIGHT:
1698                 clsoptions << "reqno,";
1699                 features.require("amsmath");
1700                 break;
1701         case DEFAULT:
1702                 break;
1703         }
1704
1705         // language should be a parameter to \documentclass
1706         if (language->babel() == "hebrew"
1707             && default_language->babel() != "hebrew")
1708                 // This seems necessary
1709                 features.useLanguage(default_language);
1710
1711         ostringstream language_options;
1712         bool const use_babel = features.useBabel() && !features.isProvided("babel");
1713         bool const use_polyglossia = features.usePolyglossia();
1714         bool const global = lyxrc.language_global_options;
1715         if (features.useBabel() || (use_polyglossia && global)) {
1716                 language_options << features.getBabelLanguages();
1717                 if (!language->babel().empty()) {
1718                         if (!language_options.str().empty())
1719                                 language_options << ',';
1720                         language_options << language->babel();
1721                 }
1722                 if (global && !language_options.str().empty())
1723                         clsoptions << language_options.str() << ',';
1724         }
1725
1726         // the predefined options from the layout
1727         if (use_default_options && !tclass.options().empty())
1728                 clsoptions << tclass.options() << ',';
1729
1730         // the user-defined options
1731         if (!options.empty()) {
1732                 clsoptions << options << ',';
1733         }
1734         
1735         docstring const strOptions = from_utf8(clsoptions.str());
1736         if (!strOptions.empty()) {
1737                 // Check if class options contain uncodable glyphs
1738                 docstring uncodable_glyphs;
1739                 docstring options_encodable;
1740                 Encoding const * const enc = features.runparams().encoding;
1741                 if (enc) {
1742                         for (char_type c : strOptions) {
1743                                 if (!enc->encodable(c)) {
1744                                         docstring const glyph(1, c);
1745                                         LYXERR0("Uncodable character '"
1746                                                 << glyph
1747                                                 << "' in class options!");
1748                                         uncodable_glyphs += glyph;
1749                                         if (features.runparams().dryrun) {
1750                                                 options_encodable += "<" + _("LyX Warning: ")
1751                                                    + _("uncodable character") + " '";
1752                                                 options_encodable += c;
1753                                                 options_encodable += "'>";
1754                                         }
1755                                 } else
1756                                         options_encodable += c;
1757                         }
1758                 } else
1759                         options_encodable = strOptions;
1760         
1761                 // On BUFFER_VIEW|UPDATE, warn user if we found uncodable glyphs
1762                 if (!features.runparams().dryrun && !uncodable_glyphs.empty()) {
1763                         frontend::Alert::warning(
1764                                 _("Uncodable character in class options"),
1765                                 support::bformat(
1766                                   _("The class options of your document contain glyphs "
1767                                     "that are unknown in the current document encoding "
1768                                     "(namely %1$s).\nThese glyphs are omitted "
1769                                     " from the output, which may result in "
1770                                     "incomplete output."
1771                                     "\n\nPlease select an appropriate "
1772                                     "document encoding\n"
1773                                     "(such as utf8) or change the "
1774                                     "class options accordingly."),
1775                                   uncodable_glyphs));
1776                 }
1777                 options_encodable = rtrim(options_encodable, ",");
1778                 os << '[' << options_encodable << ']';
1779         }
1780
1781         os << '{' << from_ascii(tclass.latexname()) << "}\n";
1782         // end of \documentclass defs
1783
1784         // The package options (via \PassOptionsToPackage)
1785         os << from_ascii(features.getPackageOptions());
1786
1787         // if we use fontspec or newtxmath, we have to load the AMS packages here
1788         string const ams = features.loadAMSPackages();
1789         bool const ot1 = (main_font_encoding() == "default" || main_font_encoding() == "OT1");
1790         bool const use_newtxmath =
1791                 theLaTeXFonts().getLaTeXFont(from_ascii(fontsMath())).getUsedPackage(
1792                         ot1, false, false) == "newtxmath";
1793         if ((useNonTeXFonts || use_newtxmath) && !ams.empty())
1794                 os << from_ascii(ams);
1795
1796         if (useNonTeXFonts) {
1797                 // Babel (as of 2017/11/03) loads fontspec itself
1798                 if (!features.isProvided("fontspec")
1799                     && !(features.useBabel() && features.isAvailable("babel-2017/11/03")))
1800                         os << "\\usepackage{fontspec}\n";
1801                 if (features.mustProvide("unicode-math")
1802                     && features.isAvailable("unicode-math"))
1803                         os << "\\usepackage{unicode-math}\n";
1804         }
1805
1806         // load CJK support package before font selection
1807         // (see autotests/export/latex/CJK/micro-sign_utf8-cjk-libertine.lyx)
1808         if (!useNonTeXFonts && encoding().package() != Encoding::none && inputenc != "utf8x"
1809                 && (encoding().package() == Encoding::CJK || features.mustProvide("CJK"))) {
1810                 if (inputenc == "utf8-cjk" || inputenc == "utf8")
1811                         os << "\\usepackage{CJKutf8}\n";
1812                 else
1813                         os << "\\usepackage[encapsulated]{CJK}\n";
1814         }
1815
1816         // font selection must be done before loading fontenc.sty
1817         // but after babel with non-TeX fonts
1818         string const fonts = loadFonts(features);
1819         if (!fonts.empty() && (!features.useBabel() || !useNonTeXFonts))
1820                 os << from_utf8(fonts);
1821
1822         if (fonts_default_family != "default")
1823                 os << "\\renewcommand{\\familydefault}{\\"
1824                    << from_ascii(fonts_default_family) << "}\n";
1825
1826         // set font encoding
1827         // non-TeX fonts use font encoding TU (set by fontspec)
1828         if (!useNonTeXFonts && !features.isProvided("fontenc")
1829             && main_font_encoding() != "default") {
1830                 // get main font encodings
1831                 vector<string> fontencs = font_encodings();
1832                 // get font encodings of secondary languages
1833                 // FIXME: some languages (hebrew, ...) assume a standard font encoding as last
1834                 // option (for text in other languages).
1835                 features.getFontEncodings(fontencs);
1836                 if (!fontencs.empty()) {
1837                         os << "\\usepackage["
1838                            << from_ascii(getStringFromVector(fontencs))
1839                            << "]{fontenc}\n";
1840                 }
1841         }
1842
1843         // Load textcomp and pmboxdraw before (lua)inputenc (#11454)
1844         if (features.mustProvide("textcomp"))
1845                 os << "\\usepackage{textcomp}\n";
1846         if (features.mustProvide("pmboxdraw"))
1847                 os << "\\usepackage{pmboxdraw}\n";
1848         
1849         // handle inputenc etc.
1850         // (In documents containing text in Thai language, 
1851         // we must load inputenc after babel, see lib/languages).
1852         if (!contains(features.getBabelPostsettings(), from_ascii("thai.ldf")))
1853                 writeEncodingPreamble(os, features);
1854
1855         // includeonly
1856         if (!features.runparams().includeall && !included_children_.empty()) {
1857                 os << "\\includeonly{";
1858                 bool first = true;
1859                 for (auto incfile : included_children_) {
1860                         FileName inc = makeAbsPath(incfile, filepath.absFileName());
1861                         string mangled = DocFileName(changeExtension(inc.absFileName(), ".tex")).
1862                                         mangledFileName();
1863                         if (!features.runparams().nice)
1864                                 incfile = mangled;
1865                         // \includeonly doesn't want an extension
1866                         incfile = changeExtension(incfile, string());
1867                         incfile = support::latex_path(incfile);
1868                         if (!incfile.empty()) {
1869                                 if (!first)
1870                                         os << ",";
1871                                 os << from_utf8(incfile);
1872                         }
1873                         first = false;
1874                 }
1875                 os << "}\n";
1876         }
1877
1878         if (!features.isProvided("geometry")
1879             && (use_geometry || !class_supported_papersize)) {
1880                 odocstringstream ods;
1881                 if (!getGraphicsDriver("geometry").empty())
1882                         ods << getGraphicsDriver("geometry");
1883                 if (orientation == ORIENTATION_LANDSCAPE)
1884                         ods << ",landscape";
1885                 switch (papersize) {
1886                 case PAPER_CUSTOM:
1887                         if (!paperwidth.empty())
1888                                 ods << ",paperwidth="
1889                                    << from_ascii(paperwidth);
1890                         if (!paperheight.empty())
1891                                 ods << ",paperheight="
1892                                    << from_ascii(paperheight);
1893                         break;
1894                 case PAPER_USLETTER:
1895                 case PAPER_USLEGAL:
1896                 case PAPER_USEXECUTIVE:
1897                 case PAPER_A0:
1898                 case PAPER_A1:
1899                 case PAPER_A2:
1900                 case PAPER_A3:
1901                 case PAPER_A4:
1902                 case PAPER_A5:
1903                 case PAPER_A6:
1904                 case PAPER_B0:
1905                 case PAPER_B1:
1906                 case PAPER_B2:
1907                 case PAPER_B3:
1908                 case PAPER_B4:
1909                 case PAPER_B5:
1910                 case PAPER_B6:
1911                 case PAPER_C0:
1912                 case PAPER_C1:
1913                 case PAPER_C2:
1914                 case PAPER_C3:
1915                 case PAPER_C4:
1916                 case PAPER_C5:
1917                 case PAPER_C6:
1918                 case PAPER_JISB0:
1919                 case PAPER_JISB1:
1920                 case PAPER_JISB2:
1921                 case PAPER_JISB3:
1922                 case PAPER_JISB4:
1923                 case PAPER_JISB5:
1924                 case PAPER_JISB6:
1925                         ods << "," << from_ascii(string_papersize_geometry[papersize]);
1926                         break;
1927                 case PAPER_DEFAULT:
1928                         break;
1929                 }
1930                 docstring g_options = trim(ods.str(), ",");
1931                 os << "\\usepackage";
1932                 // geometry-light means that the class works with geometry, but overwrites
1933                 // the package options and paper sizes (memoir does this).
1934                 // In this case, all options need to go to \geometry
1935                 // and the standard paper sizes need to go to the class options.
1936                 if (!g_options.empty() && !features.isProvided("geometry-light")) {
1937                         os << '[' << g_options << ']';
1938                         g_options.clear();
1939                 }
1940                 os << "{geometry}\n";
1941                 if (use_geometry || features.isProvided("geometry-light")) {
1942                         os << "\\geometry{verbose";
1943                         if (!g_options.empty())
1944                                 // Output general options here with "geometry light".
1945                                 os << "," << g_options;
1946                         // output this only if use_geometry is true
1947                         if (use_geometry) {
1948                                 if (!topmargin.empty())
1949                                         os << ",tmargin=" << from_ascii(Length(topmargin).asLatexString());
1950                                 if (!bottommargin.empty())
1951                                         os << ",bmargin=" << from_ascii(Length(bottommargin).asLatexString());
1952                                 if (!leftmargin.empty())
1953                                         os << ",lmargin=" << from_ascii(Length(leftmargin).asLatexString());
1954                                 if (!rightmargin.empty())
1955                                         os << ",rmargin=" << from_ascii(Length(rightmargin).asLatexString());
1956                                 if (!headheight.empty())
1957                                         os << ",headheight=" << from_ascii(Length(headheight).asLatexString());
1958                                 if (!headsep.empty())
1959                                         os << ",headsep=" << from_ascii(Length(headsep).asLatexString());
1960                                 if (!footskip.empty())
1961                                         os << ",footskip=" << from_ascii(Length(footskip).asLatexString());
1962                                 if (!columnsep.empty())
1963                                         os << ",columnsep=" << from_ascii(Length(columnsep).asLatexString());
1964                         }
1965                 os << "}\n";
1966                 }
1967         } else if (orientation == ORIENTATION_LANDSCAPE
1968                    || papersize != PAPER_DEFAULT) {
1969                 features.require("papersize");
1970         }
1971
1972         if (tokenPos(tclass.opt_pagestyle(), '|', pagestyle) >= 0) {
1973                 if (pagestyle == "fancy")
1974                         os << "\\usepackage{fancyhdr}\n";
1975                 os << "\\pagestyle{" << from_ascii(pagestyle) << "}\n";
1976         }
1977
1978         // only output when the background color is not default
1979         if (isbackgroundcolor) {
1980                 // only require color here, the background color will be defined
1981                 // in LaTeXFeatures.cpp to avoid interferences with the LaTeX
1982                 // package pdfpages
1983                 features.require("color");
1984                 features.require("pagecolor");
1985         }
1986
1987         // only output when the font color is not default
1988         if (isfontcolor) {
1989                 // only require color here, the font color will be defined
1990                 // in LaTeXFeatures.cpp to avoid interferences with the LaTeX
1991                 // package pdfpages
1992                 features.require("color");
1993                 features.require("fontcolor");
1994         }
1995
1996         // Only if class has a ToC hierarchy
1997         if (tclass.hasTocLevels()) {
1998                 if (secnumdepth != tclass.secnumdepth()) {
1999                         os << "\\setcounter{secnumdepth}{"
2000                            << secnumdepth
2001                            << "}\n";
2002                 }
2003                 if (tocdepth != tclass.tocdepth()) {
2004                         os << "\\setcounter{tocdepth}{"
2005                            << tocdepth
2006                            << "}\n";
2007                 }
2008         }
2009
2010         if (paragraph_separation) {
2011                 // when skip separation
2012                 string psopt;
2013                 switch (getDefSkip().kind()) {
2014                 case VSpace::SMALLSKIP:
2015                         psopt = "\\smallskipamount";
2016                         break;
2017                 case VSpace::MEDSKIP:
2018                         psopt = "\\medskipamount";
2019                         break;
2020                 case VSpace::BIGSKIP:
2021                         psopt = "\\bigskipamount";
2022                         break;
2023                 case VSpace::HALFLINE:
2024                         // default (no option)
2025                         break;
2026                 case VSpace::FULLLINE:
2027                         psopt = "\\baselineskip";
2028                         break;
2029                 case VSpace::LENGTH:
2030                         psopt = getDefSkip().length().asLatexString();
2031                         break;
2032                 default:
2033                         break;
2034                 }
2035                 if (!features.isProvided("parskip")) {
2036                         if (!psopt.empty())
2037                                 psopt = "[skip=" + psopt + "]";
2038                         os << "\\usepackage" + psopt + "{parskip}\n";
2039                 } else {
2040                         os << "\\setlength{\\parskip}{" + psopt + "}\n";
2041                 }
2042         } else {
2043                 // when separation by indentation
2044                 // only output something when a width is given
2045                 if (!getParIndent().empty()) {
2046                         os << "\\setlength{\\parindent}{"
2047                            << from_utf8(getParIndent().asLatexString())
2048                            << "}\n";
2049                 }
2050         }
2051
2052         if (is_math_indent) {
2053                 // when formula indentation
2054                 // only output something when it is not the default
2055                 if (!getMathIndent().empty()) {
2056                         os << "\\setlength{\\mathindent}{"
2057                            << from_utf8(getMathIndent().asString())
2058                            << "}\n";
2059                 }
2060         }
2061
2062         // Now insert the LyX specific LaTeX commands...
2063         features.resolveAlternatives();
2064         features.expandMultiples();
2065
2066         if (output_sync) {
2067                 if (!output_sync_macro.empty())
2068                         os << from_utf8(output_sync_macro) +"\n";
2069                 else if (features.runparams().flavor == OutputParams::LATEX)
2070                         os << "\\usepackage[active]{srcltx}\n";
2071                 else if (features.runparams().flavor == OutputParams::PDFLATEX)
2072                         os << "\\synctex=-1\n";
2073         }
2074
2075         // due to interferences with babel and hyperref, the color package has to
2076         // be loaded (when it is not already loaded) before babel when hyperref
2077         // is used with the colorlinks option, see
2078         // http://www.lyx.org/trac/ticket/5291
2079         // we decided therefore to load color always before babel, see
2080         // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg144349.html
2081         os << from_ascii(features.getColorOptions());
2082
2083         // If we use hyperref, jurabib, japanese or varioref,
2084         // we have to call babel before
2085         if (use_babel
2086             && (features.isRequired("jurabib")
2087                 || features.isRequired("hyperref")
2088                 || features.isRequired("varioref")
2089                 || features.isRequired("japanese"))) {
2090                         os << features.getBabelPresettings();
2091                         // FIXME UNICODE
2092                         os << from_utf8(babelCall(language_options.str(),
2093                                                                           !lyxrc.language_global_options)) + '\n';
2094                         os << features.getBabelPostsettings();
2095         }
2096
2097         // The optional packages;
2098         os << from_ascii(features.getPackages());
2099
2100         // Additional Indices
2101         if (features.isRequired("splitidx")) {
2102                 for (auto const & idx : indiceslist()) {
2103                         os << "\\newindex{";
2104                         os << escape(idx.shortcut());
2105                         os << "}\n";
2106                 }
2107         }
2108
2109         // Line spacing
2110         os << from_utf8(spacing().writePreamble(features.isProvided("SetSpace")));
2111
2112         // PDF support.
2113         // * Hyperref manual: "Make sure it comes last of your loaded
2114         //   packages, to give it a fighting chance of not being over-written,
2115         //   since its job is to redefine many LaTeX commands."
2116         // * Email from Heiko Oberdiek: "It is usually better to load babel
2117         //   before hyperref. Then hyperref has a chance to detect babel.
2118         // * Has to be loaded before the "LyX specific LaTeX commands" to
2119         //   avoid errors with algorithm floats.
2120         // use hyperref explicitly if it is required
2121         if (features.isRequired("hyperref")) {
2122                 OutputParams tmp_params = features.runparams();
2123                 pdfoptions().writeLaTeX(tmp_params, os,
2124                                         features.isProvided("hyperref"));
2125                 // correctly break URLs with hyperref and dvi/ps output
2126                 if (features.runparams().hyperref_driver == "dvips"
2127                     && features.isAvailable("breakurl"))
2128                         os << "\\usepackage{breakurl}\n";
2129         } else if (features.isRequired("nameref"))
2130                 // hyperref loads this automatically
2131                 os << "\\usepackage{nameref}\n";
2132
2133         if (use_lineno){
2134                 os << "\\usepackage";
2135                 if (!lineno_opts.empty())
2136                         os << "[" << lineno_opts << "]";
2137                 os << "{lineno}\n";
2138                 os << "\\linenumbers\n";
2139         }
2140
2141         // bibtopic needs to be loaded after hyperref.
2142         // the dot provides the aux file naming which LyX can detect.
2143         if (features.mustProvide("bibtopic"))
2144                 os << "\\usepackage[dot]{bibtopic}\n";
2145
2146         // Will be surrounded by \makeatletter and \makeatother when not empty
2147         otexstringstream atlyxpreamble;
2148
2149         // Some macros LyX will need
2150         {
2151                 TexString tmppreamble = features.getMacros();
2152                 if (!tmppreamble.str.empty())
2153                         atlyxpreamble << "\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
2154                                          "LyX specific LaTeX commands.\n"
2155                                       << move(tmppreamble)
2156                                       << '\n';
2157         }
2158         // the text class specific preamble
2159         {
2160                 docstring tmppreamble = features.getTClassPreamble();
2161                 if (!tmppreamble.empty())
2162                         atlyxpreamble << "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
2163                                          "Textclass specific LaTeX commands.\n"
2164                                       << tmppreamble
2165                                       << '\n';
2166         }
2167         // suppress date if selected
2168         // use \@ifundefined because we cannot be sure that every document class
2169         // has a \date command
2170         if (suppress_date)
2171                 atlyxpreamble << "\\@ifundefined{date}{}{\\date{}}\n";
2172
2173         /* the user-defined preamble */
2174         if (!containsOnly(preamble, " \n\t")) {
2175                 // FIXME UNICODE
2176                 atlyxpreamble << "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
2177                                  "User specified LaTeX commands.\n";
2178
2179                 // Check if the user preamble contains uncodable glyphs
2180                 odocstringstream user_preamble;
2181                 docstring uncodable_glyphs;
2182                 Encoding const * const enc = features.runparams().encoding;
2183                 if (enc) {
2184                         for (char_type c : preamble) {
2185                                 if (!enc->encodable(c)) {
2186                                         docstring const glyph(1, c);
2187                                         LYXERR0("Uncodable character '"
2188                                                 << glyph
2189                                                 << "' in user preamble!");
2190                                         uncodable_glyphs += glyph;
2191                                         if (features.runparams().dryrun) {
2192                                                 user_preamble << "<" << _("LyX Warning: ")
2193                                                    << _("uncodable character") << " '";
2194                                                 user_preamble.put(c);
2195                                                 user_preamble << "'>";
2196                                         }
2197                                 } else
2198                                         user_preamble.put(c);
2199                         }
2200                 } else
2201                         user_preamble << preamble;
2202
2203                 // On BUFFER_VIEW|UPDATE, warn user if we found uncodable glyphs
2204                 if (!features.runparams().dryrun && !uncodable_glyphs.empty()) {
2205                         frontend::Alert::warning(
2206                                 _("Uncodable character in user preamble"),
2207                                 support::bformat(
2208                                   _("The user preamble of your document contains glyphs "
2209                                     "that are unknown in the current document encoding "
2210                                     "(namely %1$s).\nThese glyphs are omitted "
2211                                     " from the output, which may result in "
2212                                     "incomplete output."
2213                                     "\n\nPlease select an appropriate "
2214                                     "document encoding\n"
2215                                     "(such as utf8) or change the "
2216                                     "preamble code accordingly."),
2217                                   uncodable_glyphs));
2218                 }
2219                 atlyxpreamble << user_preamble.str() << '\n';
2220         }
2221
2222         // footmisc must be loaded after setspace
2223         // Load it here to avoid clashes with footmisc loaded in the user
2224         // preamble. For that reason we also pass the options via
2225         // \PassOptionsToPackage in getPreamble() and not here.
2226         if (features.mustProvide("footmisc"))
2227                 atlyxpreamble << "\\usepackage{footmisc}\n";
2228
2229         // subfig loads internally the LaTeX package "caption". As
2230         // caption is a very popular package, users will load it in
2231         // the preamble. Therefore we must load subfig behind the
2232         // user-defined preamble and check if the caption package was
2233         // loaded or not. For the case that caption is loaded before
2234         // subfig, there is the subfig option "caption=false". This
2235         // option also works when a koma-script class is used and
2236         // koma's own caption commands are used instead of caption. We
2237         // use \PassOptionsToPackage here because the user could have
2238         // already loaded subfig in the preamble.
2239         if (features.mustProvide("subfig"))
2240                 atlyxpreamble << "\\@ifundefined{showcaptionsetup}{}{%\n"
2241                                  " \\PassOptionsToPackage{caption=false}{subfig}}\n"
2242                                  "\\usepackage{subfig}\n";
2243
2244         // Itemize bullet settings need to be last in case the user
2245         // defines their own bullets that use a package included
2246         // in the user-defined preamble -- ARRae
2247         // Actually it has to be done much later than that
2248         // since some packages like frenchb make modifications
2249         // at \begin{document} time -- JMarc
2250         docstring bullets_def;
2251         for (int i = 0; i < 4; ++i) {
2252                 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
2253                         if (bullets_def.empty())
2254                                 bullets_def += "\\AtBeginDocument{\n";
2255                         bullets_def += "  \\def\\labelitemi";
2256                         switch (i) {
2257                                 // `i' is one less than the item to modify
2258                         case 0:
2259                                 break;
2260                         case 1:
2261                                 bullets_def += 'i';
2262                                 break;
2263                         case 2:
2264                                 bullets_def += "ii";
2265                                 break;
2266                         case 3:
2267                                 bullets_def += 'v';
2268                                 break;
2269                         }
2270                         bullets_def += '{' +
2271                                 user_defined_bullet(i).getText()
2272                                 + "}\n";
2273                 }
2274         }
2275
2276         if (!bullets_def.empty())
2277                 atlyxpreamble << bullets_def << "}\n\n";
2278
2279         if (!atlyxpreamble.empty())
2280                 os << "\n\\makeatletter\n"
2281                    << atlyxpreamble.release()
2282                    << "\\makeatother\n\n";
2283
2284         // We try to load babel late, in case it interferes with other packages.
2285         // Jurabib, hyperref, varioref, bicaption, menukeys and listings (bug 8995)
2286         // have to be called after babel, though.
2287         if (use_babel && !features.isRequired("jurabib")
2288             && !features.isRequired("hyperref")
2289             && !features.isRequired("varioref")
2290             && !features.isRequired("japanese")) {
2291                 os << features.getBabelPresettings();
2292                 // FIXME UNICODE
2293                 os << from_utf8(babelCall(language_options.str(),
2294                                           !lyxrc.language_global_options)) + '\n';
2295                 os << features.getBabelPostsettings();
2296         }
2297         // In documents containing text in Thai language, 
2298         // we must load inputenc after babel (see lib/languages).
2299         if (contains(features.getBabelPostsettings(), from_ascii("thai.ldf")))
2300                 writeEncodingPreamble(os, features);
2301
2302         // font selection must be done after babel with non-TeX fonts
2303         if (!fonts.empty() && features.useBabel() && useNonTeXFonts)
2304                 os << from_utf8(fonts);
2305
2306         if (features.isRequired("bicaption"))
2307                 os << "\\usepackage{bicaption}\n";
2308         if (!listings_params.empty()
2309             || features.mustProvide("listings")
2310             || features.mustProvide("minted")) {
2311                 if (use_minted)
2312                         os << "\\usepackage{minted}\n";
2313                 else
2314                         os << "\\usepackage{listings}\n";
2315         }
2316         string lst_params = listings_params;
2317         // If minted, do not output the language option (bug 11203)
2318         if (use_minted && contains(lst_params, "language=")) {
2319                 vector<string> opts =
2320                         getVectorFromString(lst_params, ",", false);
2321                 for (size_t i = 0; i < opts.size(); ++i) {
2322                         if (prefixIs(opts[i], "language="))
2323                                 opts.erase(opts.begin() + i--);
2324                 }
2325                 lst_params = getStringFromVector(opts, ",");
2326         }
2327         if (!lst_params.empty()) {
2328                 if (use_minted)
2329                         os << "\\setminted{";
2330                 else
2331                         os << "\\lstset{";
2332                 // do not test validity because listings_params is
2333                 // supposed to be valid
2334                 string par =
2335                         InsetListingsParams(lst_params).separatedParams(true);
2336                 os << from_utf8(par);
2337                 os << "}\n";
2338         }
2339
2340         // xunicode only needs to be loaded if tipa is used
2341         // (the rest is obsoleted by the new TU encoding).
2342         // It needs to be loaded at least after amsmath, amssymb,
2343         // esint and the other packages that provide special glyphs
2344         if (features.mustProvide("tipa") && useNonTeXFonts
2345             && !features.isProvided("xunicode")) {
2346                 // The `xunicode` package officially only supports XeTeX,
2347                 //  but also works with LuaTeX. We work around its XeTeX test.
2348                 if (features.runparams().flavor != OutputParams::XETEX) {
2349                         os << "% Pretend to xunicode that we are XeTeX\n"
2350                            << "\\def\\XeTeXpicfile{}\n";
2351                 }
2352                 os << "\\usepackage{xunicode}\n";
2353         }
2354
2355         // covington must be loaded after beamerarticle
2356         if (features.isRequired("covington"))
2357             os << "\\usepackage{covington}\n";
2358
2359         // Polyglossia must be loaded last ...
2360         if (use_polyglossia) {
2361                 // call the package
2362                 os << "\\usepackage{polyglossia}\n";
2363                 // set the main language
2364                 os << "\\setdefaultlanguage";
2365                 if (!language->polyglossiaOpts().empty())
2366                         os << "[" << from_ascii(language->polyglossiaOpts()) << "]";
2367                 os << "{" << from_ascii(language->polyglossia()) << "}\n";
2368                 // now setup the other languages
2369                 set<string> const polylangs =
2370                         features.getPolyglossiaLanguages();
2371                 for (auto const & pl : polylangs) {
2372                         // We do not output the options here; they are output in
2373                         // the language switch commands. This is safer if multiple
2374                         // varieties are used.
2375                         if (pl == language->polyglossia())
2376                                 continue;
2377                         os << "\\setotherlanguage";
2378                         os << "{" << from_ascii(pl) << "}\n";
2379                 }
2380         }
2381
2382         // ... but before biblatex (see #7065)
2383         if ((features.mustProvide("biblatex")
2384              || features.isRequired("biblatex-chicago"))
2385             && !features.isProvided("biblatex-chicago")
2386             && !features.isProvided("biblatex-natbib")
2387             && !features.isProvided("natbib-internal")
2388             && !features.isProvided("natbib")
2389             && !features.isProvided("jurabib")) {
2390                 // The biblatex-chicago package has a differing interface
2391                 // it uses a wrapper package and loads styles via fixed options
2392                 bool const chicago = features.isRequired("biblatex-chicago");
2393                 string delim = "";
2394                 string opts;
2395                 os << "\\usepackage";
2396                 if (!biblatex_bibstyle.empty()
2397                     && (biblatex_bibstyle == biblatex_citestyle)
2398                     && !chicago) {
2399                         opts = "style=" + biblatex_bibstyle;
2400                         delim = ",";
2401                 } else if (!chicago) {
2402                         if (!biblatex_bibstyle.empty()) {
2403                                 opts = "bibstyle=" + biblatex_bibstyle;
2404                                 delim = ",";
2405                         }
2406                         if (!biblatex_citestyle.empty()) {
2407                                 opts += delim + "citestyle=" + biblatex_citestyle;
2408                                 delim = ",";
2409                         }
2410                 }
2411                 if (!multibib.empty() && multibib != "child") {
2412                         opts += delim + "refsection=" + multibib;
2413                         delim = ",";
2414                 }
2415                 if (bibtexCommand() == "bibtex8"
2416                     || prefixIs(bibtexCommand(), "bibtex8 ")) {
2417                         opts += delim + "backend=bibtex8";
2418                         delim = ",";
2419                 } else if (bibtexCommand() == "bibtex"
2420                            || prefixIs(bibtexCommand(), "bibtex ")) {
2421                         opts += delim + "backend=bibtex";
2422                         delim = ",";
2423                 }
2424                 if (!bib_encoding.empty() && encodings.fromLyXName(bib_encoding)) {
2425                         opts += delim + "bibencoding="
2426                                 + encodings.fromLyXName(bib_encoding)->latexName();
2427                         delim = ",";
2428                 }
2429                 if (!biblio_opts.empty())
2430                         opts += delim + biblio_opts;
2431                 if (!opts.empty())
2432                         os << "[" << opts << "]";
2433                 if (chicago)
2434                         os << "{biblatex-chicago}\n";
2435                 else
2436                         os << "{biblatex}\n";
2437         }
2438
2439
2440         // Load custom language package here
2441         if (features.langPackage() == LaTeXFeatures::LANG_PACK_CUSTOM) {
2442                 if (lang_package == "default")
2443                         os << from_utf8(lyxrc.language_custom_package);
2444                 else
2445                         os << from_utf8(lang_package);
2446                 os << '\n';
2447         }
2448
2449         // Since menukeys uses catoptions, which does some heavy changes on key-value options,
2450         // it is recommended to load menukeys as the last package (even after hyperref)
2451         if (features.isRequired("menukeys"))
2452                 os << "\\usepackage{menukeys}\n";
2453
2454         docstring const i18npreamble =
2455                 features.getTClassI18nPreamble(use_babel, use_polyglossia,
2456                                                use_minted);
2457         if (!i18npreamble.empty())
2458                 os << i18npreamble + '\n';
2459
2460         return use_babel;
2461 }
2462
2463
2464 void BufferParams::useClassDefaults()
2465 {
2466         DocumentClass const & tclass = documentClass();
2467
2468         sides = tclass.sides();
2469         columns = tclass.columns();
2470         pagestyle = tclass.pagestyle();
2471         tablestyle = tclass.tablestyle();
2472         use_default_options = true;
2473         // Only if class has a ToC hierarchy
2474         if (tclass.hasTocLevels()) {
2475                 secnumdepth = tclass.secnumdepth();
2476                 tocdepth = tclass.tocdepth();
2477         }
2478 }
2479
2480
2481 bool BufferParams::hasClassDefaults() const
2482 {
2483         DocumentClass const & tclass = documentClass();
2484
2485         return sides == tclass.sides()
2486                 && columns == tclass.columns()
2487                 && pagestyle == tclass.pagestyle()
2488                 && tablestyle == tclass.tablestyle()
2489                 && use_default_options
2490                 && secnumdepth == tclass.secnumdepth()
2491                 && tocdepth == tclass.tocdepth();
2492 }
2493
2494
2495 DocumentClass const & BufferParams::documentClass() const
2496 {
2497         return *doc_class_;
2498 }
2499
2500
2501 DocumentClassConstPtr BufferParams::documentClassPtr() const
2502 {
2503         return doc_class_;
2504 }
2505
2506
2507 void BufferParams::setDocumentClass(DocumentClassConstPtr tc)
2508 {
2509         // evil, but this function is evil
2510         doc_class_ = const_pointer_cast<DocumentClass>(tc);
2511         invalidateConverterCache();
2512 }
2513
2514
2515 bool BufferParams::setBaseClass(string const & classname, string const & path)
2516 {
2517         LYXERR(Debug::TCLASS, "setBaseClass: " << classname);
2518         LayoutFileList & bcl = LayoutFileList::get();
2519         if (!bcl.haveClass(classname)) {
2520                 docstring s =
2521                         bformat(_("The layout file:\n"
2522                                 "%1$s\n"
2523                                 "could not be found. A default textclass with default\n"
2524                                 "layouts will be used. LyX will not be able to produce\n"
2525                                 "correct output."),
2526                         from_utf8(classname));
2527                 frontend::Alert::error(_("Document class not found"), s);
2528                 bcl.addEmptyClass(classname);
2529         }
2530
2531         bool const success = bcl[classname].load(path);
2532         if (!success) {
2533                 docstring s =
2534                         bformat(_("Due to some error in it, the layout file:\n"
2535                                 "%1$s\n"
2536                                 "could not be loaded. A default textclass with default\n"
2537                                 "layouts will be used. LyX will not be able to produce\n"
2538                                 "correct output."),
2539                         from_utf8(classname));
2540                 frontend::Alert::error(_("Could not load class"), s);
2541                 bcl.addEmptyClass(classname);
2542         }
2543
2544         pimpl_->baseClass_ = classname;
2545         layout_modules_.adaptToBaseClass(baseClass(), removed_modules_);
2546         return true;
2547 }
2548
2549
2550 LayoutFile const * BufferParams::baseClass() const
2551 {
2552         if (LayoutFileList::get().haveClass(pimpl_->baseClass_))
2553                 return &(LayoutFileList::get()[pimpl_->baseClass_]);
2554
2555         return nullptr;
2556 }
2557
2558
2559 LayoutFileIndex const & BufferParams::baseClassID() const
2560 {
2561         return pimpl_->baseClass_;
2562 }
2563
2564
2565 void BufferParams::makeDocumentClass(bool const clone)
2566 {
2567         if (!baseClass())
2568                 return;
2569
2570         invalidateConverterCache();
2571         LayoutModuleList mods;
2572         for (auto const & mod : layout_modules_)
2573                 mods.push_back(mod);
2574
2575         doc_class_ = getDocumentClass(*baseClass(), mods, cite_engine_, clone);
2576
2577         TextClass::ReturnValues success = TextClass::OK;
2578         if (!forced_local_layout_.empty())
2579                 success = doc_class_->read(to_utf8(forced_local_layout_),
2580                                            TextClass::MODULE);
2581         if (!local_layout_.empty() &&
2582             (success == TextClass::OK || success == TextClass::OK_OLDFORMAT))
2583                 success = doc_class_->read(to_utf8(local_layout_), TextClass::MODULE);
2584         if (success != TextClass::OK && success != TextClass::OK_OLDFORMAT) {
2585                 docstring const msg = _("Error reading internal layout information");
2586                 frontend::Alert::warning(_("Read Error"), msg);
2587         }
2588 }
2589
2590
2591 bool BufferParams::layoutModuleCanBeAdded(string const & modName) const
2592 {
2593         return layout_modules_.moduleCanBeAdded(modName, baseClass());
2594 }
2595
2596
2597 docstring BufferParams::getLocalLayout(bool forced) const
2598 {
2599         if (forced)
2600                 return from_utf8(doc_class_->forcedLayouts());
2601         else
2602                 return local_layout_;
2603 }
2604
2605
2606 void BufferParams::setLocalLayout(docstring const & layout, bool forced)
2607 {
2608         if (forced)
2609                 forced_local_layout_ = layout;
2610         else
2611                 local_layout_ = layout;
2612 }
2613
2614
2615 bool BufferParams::addLayoutModule(string const & modName)
2616 {
2617         for (auto const & mod : layout_modules_)
2618                 if (mod == modName)
2619                         return false;
2620         layout_modules_.push_back(modName);
2621         return true;
2622 }
2623
2624
2625 string BufferParams::bufferFormat() const
2626 {
2627         return documentClass().outputFormat();
2628 }
2629
2630
2631 bool BufferParams::isExportable(string const & format, bool need_viewable) const
2632 {
2633         FormatList const & formats = exportableFormats(need_viewable);
2634         for (auto const & fmt : formats) {
2635                 if (fmt->name() == format)
2636                         return true;
2637         }
2638         return false;
2639 }
2640
2641
2642 FormatList const & BufferParams::exportableFormats(bool only_viewable) const
2643 {
2644         FormatList & cached = only_viewable ?
2645                         pimpl_->viewableFormatList : pimpl_->exportableFormatList;
2646         bool & valid = only_viewable ?
2647                         pimpl_->isViewCacheValid : pimpl_->isExportCacheValid;
2648         if (valid)
2649                 return cached;
2650
2651         vector<string> const backs = backends();
2652         set<string> excludes;
2653         if (useNonTeXFonts) {
2654                 excludes.insert("latex");
2655                 excludes.insert("pdflatex");
2656         } else if (inputenc != "ascii" && inputenc != "utf8-plain") {
2657                   // XeTeX with TeX fonts requires input encoding ascii (#10600).
2658                   excludes.insert("xetex");
2659         }
2660
2661         FormatList result =
2662                 theConverters().getReachable(backs[0], only_viewable, true, excludes);
2663         vector<string>::const_iterator it = backs.begin() + 1;
2664         for (; it != backs.end(); ++it) {
2665                 FormatList r = theConverters().getReachable(*it, only_viewable,
2666                                                                                                         false, excludes);
2667                 result.insert(result.end(), r.begin(), r.end());
2668         }
2669         sort(result.begin(), result.end(), Format::formatSorter);
2670         cached = result;
2671         valid = true;
2672         return cached;
2673 }
2674
2675
2676 vector<string> BufferParams::backends() const
2677 {
2678         vector<string> v;
2679         string const buffmt = bufferFormat();
2680
2681         // FIXME: Don't hardcode format names here, but use a flag
2682         if (buffmt == "latex") {
2683                 if (encoding().package() == Encoding::japanese)
2684                         v.push_back("platex");
2685                 else {
2686                         if (!useNonTeXFonts) {
2687                                 v.push_back("pdflatex");
2688                                 v.push_back("latex");
2689                         }
2690                         if (useNonTeXFonts 
2691                                 || inputenc == "ascii" || inputenc == "utf8-plain")
2692                                 v.push_back("xetex");
2693                         v.push_back("luatex");
2694                         v.push_back("dviluatex");
2695                 }
2696         } else {
2697                 string rbuffmt = buffmt;
2698                 // If we use an OutputFormat in Japanese docs,
2699                 // we need special format in order to get the path
2700                 // via pLaTeX (#8823)
2701                 if (documentClass().hasOutputFormat()
2702                     && encoding().package() == Encoding::japanese)
2703                         rbuffmt += "-ja";
2704                 v.push_back(rbuffmt);
2705         }
2706
2707         v.push_back("xhtml");
2708         v.push_back("docbook5");
2709         v.push_back("text");
2710         v.push_back("lyx");
2711         return v;
2712 }
2713
2714
2715 OutputParams::FLAVOR BufferParams::getOutputFlavor(string const & format) const
2716 {
2717         string const dformat = (format.empty() || format == "default") ?
2718                 getDefaultOutputFormat() : format;
2719         DefaultFlavorCache::const_iterator it =
2720                 default_flavors_.find(dformat);
2721
2722         if (it != default_flavors_.end())
2723                 return it->second;
2724
2725         OutputParams::FLAVOR result = OutputParams::LATEX;
2726
2727         // FIXME It'd be better not to hardcode this, but to do
2728         //       something with formats.
2729         if (dformat == "xhtml")
2730                 result = OutputParams::HTML;
2731         else if (dformat == "docbook5")
2732                 result = OutputParams::DOCBOOK5;
2733         else if (dformat == "text")
2734                 result = OutputParams::TEXT;
2735         else if (dformat == "lyx")
2736                 result = OutputParams::LYX;
2737         else if (dformat == "pdflatex")
2738                 result = OutputParams::PDFLATEX;
2739         else if (dformat == "xetex")
2740                 result = OutputParams::XETEX;
2741         else if (dformat == "luatex")
2742                 result = OutputParams::LUATEX;
2743         else if (dformat == "dviluatex")
2744                 result = OutputParams::DVILUATEX;
2745         else {
2746                 // Try to determine flavor of default output format
2747                 vector<string> backs = backends();
2748                 if (find(backs.begin(), backs.end(), dformat) == backs.end()) {
2749                         // Get shortest path to format
2750                         Graph::EdgePath path;
2751                         for (auto const & bvar : backs) {
2752                                 Graph::EdgePath p = theConverters().getPath(bvar, dformat);
2753                                 if (!p.empty() && (path.empty() || p.size() < path.size())) {
2754                                         path = p;
2755                                 }
2756                         }
2757                         if (!path.empty())
2758                                 result = theConverters().getFlavor(path);
2759                 }
2760         }
2761         // cache this flavor
2762         default_flavors_[dformat] = result;
2763         return result;
2764 }
2765
2766
2767 string BufferParams::getDefaultOutputFormat() const
2768 {
2769         if (!default_output_format.empty()
2770             && default_output_format != "default")
2771                 return default_output_format;
2772         if (encoding().package() == Encoding::japanese)
2773                 return lyxrc.default_platex_view_format;
2774         if (useNonTeXFonts)
2775                 return lyxrc.default_otf_view_format;
2776         return lyxrc.default_view_format;
2777 }
2778
2779 Font const BufferParams::getFont() const
2780 {
2781         FontInfo f = documentClass().defaultfont();
2782         if (fonts_default_family == "rmdefault")
2783                 f.setFamily(ROMAN_FAMILY);
2784         else if (fonts_default_family == "sfdefault")
2785                 f.setFamily(SANS_FAMILY);
2786         else if (fonts_default_family == "ttdefault")
2787                 f.setFamily(TYPEWRITER_FAMILY);
2788         return Font(f, language);
2789 }
2790
2791
2792 InsetQuotesParams::QuoteStyle BufferParams::getQuoteStyle(string const & qs) const
2793 {
2794         return quotesstyletranslator().find(qs);
2795 }
2796
2797
2798 bool BufferParams::isLatex() const
2799 {
2800         return documentClass().outputType() == LATEX;
2801 }
2802
2803
2804 bool BufferParams::isLiterate() const
2805 {
2806         return documentClass().outputType() == LITERATE;
2807 }
2808
2809
2810 void BufferParams::readPreamble(Lexer & lex)
2811 {
2812         if (lex.getString() != "\\begin_preamble")
2813                 lyxerr << "Error (BufferParams::readPreamble):"
2814                         "consistency check failed." << endl;
2815
2816         preamble = lex.getLongString(from_ascii("\\end_preamble"));
2817 }
2818
2819
2820 void BufferParams::readLocalLayout(Lexer & lex, bool forced)
2821 {
2822         string const expected = forced ? "\\begin_forced_local_layout" :
2823                                          "\\begin_local_layout";
2824         if (lex.getString() != expected)
2825                 lyxerr << "Error (BufferParams::readLocalLayout):"
2826                         "consistency check failed." << endl;
2827
2828         if (forced)
2829                 forced_local_layout_ =
2830                         lex.getLongString(from_ascii("\\end_forced_local_layout"));
2831         else
2832                 local_layout_ = lex.getLongString(from_ascii("\\end_local_layout"));
2833 }
2834
2835
2836 bool BufferParams::setLanguage(string const & lang)
2837 {
2838         Language const *new_language = languages.getLanguage(lang);
2839         if (!new_language) {
2840                 // Language lang was not found
2841                 return false;
2842         }
2843         language = new_language;
2844         return true;
2845 }
2846
2847
2848 void BufferParams::readLanguage(Lexer & lex)
2849 {
2850         if (!lex.next()) return;
2851
2852         string const tmptok = lex.getString();
2853
2854         // check if tmptok is part of tex_babel in tex-defs.h
2855         if (!setLanguage(tmptok)) {
2856                 // Language tmptok was not found
2857                 language = default_language;
2858                 lyxerr << "Warning: Setting language `"
2859                        << tmptok << "' to `" << language->lang()
2860                        << "'." << endl;
2861         }
2862 }
2863
2864
2865 void BufferParams::readGraphicsDriver(Lexer & lex)
2866 {
2867         if (!lex.next())
2868                 return;
2869
2870         string const tmptok = lex.getString();
2871         // check if tmptok is part of tex_graphics in tex_defs.h
2872         int n = 0;
2873         while (true) {
2874                 string const test = tex_graphics[n++];
2875
2876                 if (test == tmptok) {
2877                         graphics_driver = tmptok;
2878                         break;
2879                 }
2880                 if (test.empty()) {
2881                         lex.printError(
2882                                 "Warning: graphics driver `$$Token' not recognized!\n"
2883                                 "         Setting graphics driver to `default'.\n");
2884                         graphics_driver = "default";
2885                         break;
2886                 }
2887         }
2888 }
2889
2890
2891 void BufferParams::readBullets(Lexer & lex)
2892 {
2893         if (!lex.next())
2894                 return;
2895
2896         int const index = lex.getInteger();
2897         lex.next();
2898         int temp_int = lex.getInteger();
2899         user_defined_bullet(index).setFont(temp_int);
2900         temp_bullet(index).setFont(temp_int);
2901         lex >> temp_int;
2902         user_defined_bullet(index).setCharacter(temp_int);
2903         temp_bullet(index).setCharacter(temp_int);
2904         lex >> temp_int;
2905         user_defined_bullet(index).setSize(temp_int);
2906         temp_bullet(index).setSize(temp_int);
2907 }
2908
2909
2910 void BufferParams::readBulletsLaTeX(Lexer & lex)
2911 {
2912         // The bullet class should be able to read this.
2913         if (!lex.next())
2914                 return;
2915         int const index = lex.getInteger();
2916         lex.next(true);
2917         docstring const temp_str = lex.getDocString();
2918
2919         user_defined_bullet(index).setText(temp_str);
2920         temp_bullet(index).setText(temp_str);
2921 }
2922
2923
2924 void BufferParams::readModules(Lexer & lex)
2925 {
2926         if (!lex.eatLine()) {
2927                 lyxerr << "Error (BufferParams::readModules):"
2928                                 "Unexpected end of input." << endl;
2929                 return;
2930         }
2931         while (true) {
2932                 string mod = lex.getString();
2933                 if (mod == "\\end_modules")
2934                         break;
2935                 addLayoutModule(mod);
2936                 lex.eatLine();
2937         }
2938 }
2939
2940
2941 void BufferParams::readRemovedModules(Lexer & lex)
2942 {
2943         if (!lex.eatLine()) {
2944                 lyxerr << "Error (BufferParams::readRemovedModules):"
2945                                 "Unexpected end of input." << endl;
2946                 return;
2947         }
2948         while (true) {
2949                 string mod = lex.getString();
2950                 if (mod == "\\end_removed_modules")
2951                         break;
2952                 removed_modules_.push_back(mod);
2953                 lex.eatLine();
2954         }
2955         // now we want to remove any removed modules that were previously
2956         // added. normally, that will be because default modules were added in
2957         // setBaseClass(), which gets called when \textclass is read at the
2958         // start of the read.
2959         for (auto const & rm : removed_modules_) {
2960                 LayoutModuleList::iterator const mit = layout_modules_.begin();
2961                 LayoutModuleList::iterator const men = layout_modules_.end();
2962                 LayoutModuleList::iterator found = find(mit, men, rm);
2963                 if (found == men)
2964                         continue;
2965                 layout_modules_.erase(found);
2966         }
2967 }
2968
2969
2970 void BufferParams::readIncludeonly(Lexer & lex)
2971 {
2972         if (!lex.eatLine()) {
2973                 lyxerr << "Error (BufferParams::readIncludeonly):"
2974                                 "Unexpected end of input." << endl;
2975                 return;
2976         }
2977         while (true) {
2978                 string child = lex.getString();
2979                 if (child == "\\end_includeonly")
2980                         break;
2981                 included_children_.push_back(child);
2982                 lex.eatLine();
2983         }
2984 }
2985
2986
2987 string BufferParams::paperSizeName(PapersizePurpose purpose, string const & psize) const
2988 {
2989         PAPER_SIZE ppsize = psize.empty() ? papersize : papersizetranslator().find(psize);
2990         switch (ppsize) {
2991         case PAPER_DEFAULT:
2992                 if (documentClass().pagesize() == "default")
2993                         // could be anything, so don't guess
2994                         return string();
2995                 return paperSizeName(purpose, documentClass().pagesize());
2996         case PAPER_CUSTOM: {
2997                 if (purpose == XDVI && !paperwidth.empty() &&
2998                     !paperheight.empty()) {
2999                         // heightxwidth<unit>
3000                         string first = paperwidth;
3001                         string second = paperheight;
3002                         if (orientation == ORIENTATION_LANDSCAPE)
3003                                 first.swap(second);
3004                         // cut off unit.
3005                         return first.erase(first.length() - 2)
3006                                 + "x" + second;
3007                 }
3008                 return string();
3009         }
3010         case PAPER_A0:
3011                 // dvips and dvipdfm do not know this
3012                 if (purpose == DVIPS || purpose == DVIPDFM)
3013                         return string();
3014                 return "a0";
3015         case PAPER_A1:
3016                 if (purpose == DVIPS || purpose == DVIPDFM)
3017                         return string();
3018                 return "a1";
3019         case PAPER_A2:
3020                 if (purpose == DVIPS || purpose == DVIPDFM)
3021                         return string();
3022                 return "a2";
3023         case PAPER_A3:
3024                 return "a3";
3025         case PAPER_A4:
3026                 return "a4";
3027         case PAPER_A5:
3028                 return "a5";
3029         case PAPER_A6:
3030                 if (purpose == DVIPS || purpose == DVIPDFM)
3031                         return string();
3032                 return "a6";
3033         case PAPER_B0:
3034                 if (purpose == DVIPS || purpose == DVIPDFM)
3035                         return string();
3036                 return "b0";
3037         case PAPER_B1:
3038                 if (purpose == DVIPS || purpose == DVIPDFM)
3039                         return string();
3040                 return "b1";
3041         case PAPER_B2:
3042                 if (purpose == DVIPS || purpose == DVIPDFM)
3043                         return string();
3044                 return "b2";
3045         case PAPER_B3:
3046                 if (purpose == DVIPS || purpose == DVIPDFM)
3047                         return string();
3048                 return "b3";
3049         case PAPER_B4:
3050                 // dvipdfm does not know this
3051                 if (purpose == DVIPDFM)
3052                         return string();
3053                 return "b4";
3054         case PAPER_B5:
3055                 if (purpose == DVIPDFM)
3056                         return string();
3057                 return "b5";
3058         case PAPER_B6:
3059                 if (purpose == DVIPS || purpose == DVIPDFM)
3060                         return string();
3061                 return "b6";
3062         case PAPER_C0:
3063                 if (purpose == DVIPS || purpose == DVIPDFM)
3064                         return string();
3065                 return "c0";
3066         case PAPER_C1:
3067                 if (purpose == DVIPS || purpose == DVIPDFM)
3068                         return string();
3069                 return "c1";
3070         case PAPER_C2:
3071                 if (purpose == DVIPS || purpose == DVIPDFM)
3072                         return string();
3073                 return "c2";
3074         case PAPER_C3:
3075                 if (purpose == DVIPS || purpose == DVIPDFM)
3076                         return string();
3077                 return "c3";
3078         case PAPER_C4:
3079                 if (purpose == DVIPS || purpose == DVIPDFM)
3080                         return string();
3081                 return "c4";
3082         case PAPER_C5:
3083                 if (purpose == DVIPS || purpose == DVIPDFM)
3084                         return string();
3085                 return "c5";
3086         case PAPER_C6:
3087                 if (purpose == DVIPS || purpose == DVIPDFM)
3088                         return string();
3089                 return "c6";
3090         case PAPER_JISB0:
3091                 if (purpose == DVIPS || purpose == DVIPDFM)
3092                         return string();
3093                 return "jisb0";
3094         case PAPER_JISB1:
3095                 if (purpose == DVIPS || purpose == DVIPDFM)
3096                         return string();
3097                 return "jisb1";
3098         case PAPER_JISB2:
3099                 if (purpose == DVIPS || purpose == DVIPDFM)
3100                         return string();
3101                 return "jisb2";
3102         case PAPER_JISB3:
3103                 if (purpose == DVIPS || purpose == DVIPDFM)
3104                         return string();
3105                 return "jisb3";
3106         case PAPER_JISB4:
3107                 if (purpose == DVIPS || purpose == DVIPDFM)
3108                         return string();
3109                 return "jisb4";
3110         case PAPER_JISB5:
3111                 if (purpose == DVIPS || purpose == DVIPDFM)
3112                         return string();
3113                 return "jisb5";
3114         case PAPER_JISB6:
3115                 if (purpose == DVIPS || purpose == DVIPDFM)
3116                         return string();
3117                 return "jisb6";
3118         case PAPER_USEXECUTIVE:
3119                 // dvipdfm does not know this
3120                 if (purpose == DVIPDFM)
3121                         return string();
3122                 return "foolscap";
3123         case PAPER_USLEGAL:
3124                 return "legal";
3125         case PAPER_USLETTER:
3126         default:
3127                 if (purpose == XDVI)
3128                         return "us";
3129                 return "letter";
3130         }
3131 }
3132
3133
3134 string const BufferParams::dvips_options() const
3135 {
3136         string result;
3137
3138         // If the class loads the geometry package, we do not know which
3139         // paper size is used, since we do not set it (bug 7013).
3140         // Therefore we must not specify any argument here.
3141         // dvips gets the correct paper size via DVI specials in this case
3142         // (if the class uses the geometry package correctly).
3143         if (documentClass().provides("geometry"))
3144                 return result;
3145
3146         if (use_geometry
3147             && papersize == PAPER_CUSTOM
3148             && !lyxrc.print_paper_dimension_flag.empty()
3149             && !paperwidth.empty()
3150             && !paperheight.empty()) {
3151                 // using a custom papersize
3152                 result = lyxrc.print_paper_dimension_flag;
3153                 result += ' ' + paperwidth;
3154                 result += ',' + paperheight;
3155         } else {
3156                 string const paper_option = paperSizeName(DVIPS);
3157                 if (!paper_option.empty() && (paper_option != "letter" ||
3158                     orientation != ORIENTATION_LANDSCAPE)) {
3159                         // dvips won't accept -t letter -t landscape.
3160                         // In all other cases, include the paper size
3161                         // explicitly.
3162                         result = lyxrc.print_paper_flag;
3163                         result += ' ' + paper_option;
3164                 }
3165         }
3166         if (orientation == ORIENTATION_LANDSCAPE &&
3167             papersize != PAPER_CUSTOM)
3168                 result += ' ' + lyxrc.print_landscape_flag;
3169         return result;
3170 }
3171
3172
3173 string const BufferParams::main_font_encoding() const
3174 {
3175         if (font_encodings().empty()) {
3176                 if (ascii_lowercase(language->fontenc(*this)) == "none")
3177                         return "none";
3178                 return "default";
3179         }
3180         return font_encodings().back();
3181 }
3182
3183
3184 vector<string> const BufferParams::font_encodings() const
3185 {
3186         string doc_fontenc = (fontenc == "auto") ? string() : fontenc;
3187
3188         vector<string> fontencs;
3189
3190         // "default" means "no explicit font encoding"
3191         if (doc_fontenc != "default") {
3192                 if (!doc_fontenc.empty())
3193                         // If we have a custom setting, we use only that!
3194                         return getVectorFromString(doc_fontenc);
3195                 if (!language->fontenc(*this).empty()
3196                     && ascii_lowercase(language->fontenc(*this)) != "none") {
3197                         vector<string> fencs = getVectorFromString(language->fontenc(*this));
3198                         for (auto & fe : fencs) {
3199                                 if (find(fontencs.begin(), fontencs.end(), fe) == fontencs.end())
3200                                         fontencs.push_back(fe);
3201                         }
3202                 }
3203         }
3204
3205         return fontencs;
3206 }
3207
3208
3209 string BufferParams::babelCall(string const & lang_opts, bool const langoptions) const
3210 {
3211         // suppress the babel call if there is no BabelName defined
3212         // for the document language in the lib/languages file and if no
3213         // other languages are used (lang_opts is then empty)
3214         if (lang_opts.empty())
3215                 return string();
3216         // The prefs may require the languages to
3217         // be submitted to babel itself (not the class).
3218         if (langoptions)
3219                 return "\\usepackage[" + lang_opts + "]{babel}";
3220         return "\\usepackage{babel}";
3221 }
3222
3223
3224 docstring BufferParams::getGraphicsDriver(string const & package) const
3225 {
3226         docstring result;
3227
3228         if (package == "geometry") {
3229                 if (graphics_driver == "dvips"
3230                     || graphics_driver == "dvipdfm"
3231                     || graphics_driver == "pdftex"
3232                     || graphics_driver == "vtex")
3233                         result = from_ascii(graphics_driver);
3234                 else if (graphics_driver == "dvipdfmx")
3235                         result = from_ascii("dvipdfm");
3236         }
3237
3238         return result;
3239 }
3240
3241
3242 void BufferParams::writeEncodingPreamble(otexstream & os,
3243                                          LaTeXFeatures & features) const
3244 {
3245         // With no-TeX fonts we use utf8-plain without encoding package.
3246         if (useNonTeXFonts)
3247                 return;
3248
3249         if (inputenc == "auto-legacy") {
3250                 string const doc_encoding =
3251                         language->encoding()->latexName();
3252                 Encoding::Package const package =
3253                         language->encoding()->package();
3254
3255                 // Create list of inputenc options:
3256                 set<string> encoding_set;
3257                 // luainputenc fails with more than one encoding
3258                 if (features.runparams().flavor != OutputParams::LUATEX
3259                         && features.runparams().flavor != OutputParams::DVILUATEX)
3260                         // list all input encodings used in the document
3261                         encoding_set = features.getEncodingSet(doc_encoding);
3262
3263                 // The "japanese" babel-language requires  the pLaTeX engine
3264                 // which conflicts with "inputenc".
3265                 // See http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129680.html
3266                 if ((!encoding_set.empty() || package == Encoding::inputenc)
3267                     && !features.isRequired("japanese")
3268                     && !features.isProvided("inputenc")) {
3269                         os << "\\usepackage[";
3270                         set<string>::const_iterator it = encoding_set.begin();
3271                         set<string>::const_iterator const end = encoding_set.end();
3272                         if (it != end) {
3273                                 os << from_ascii(*it);
3274                                 ++it;
3275                         }
3276                         for (; it != end; ++it)
3277                                 os << ',' << from_ascii(*it);
3278                         if (package == Encoding::inputenc) {
3279                                 if (!encoding_set.empty())
3280                                         os << ',';
3281                                 os << from_ascii(doc_encoding);
3282                         }
3283                         if (features.runparams().flavor == OutputParams::LUATEX
3284                             || features.runparams().flavor == OutputParams::DVILUATEX)
3285                                 os << "]{luainputenc}\n";
3286                         else
3287                                 os << "]{inputenc}\n";
3288                 }
3289         } else if (inputenc != "auto-legacy-plain") {
3290                 switch (encoding().package()) {
3291                 case Encoding::none:
3292                 case Encoding::CJK:
3293                 case Encoding::japanese:
3294                         if (encoding().iconvName() != "UTF-8"
3295                                 && !features.runparams().isFullUnicode())
3296                           // don't default to [utf8]{inputenc} with TeXLive >= 18
3297                           os << "\\ifdefined\\UseRawInputEncoding\n"
3298                                  << "  \\UseRawInputEncoding\\fi\n";
3299                         break;
3300                 case Encoding::inputenc:
3301                         // do not load inputenc if japanese is used
3302                         // or if the class provides inputenc
3303                         if (features.isRequired("japanese")
3304                             || features.isProvided("inputenc"))
3305                                 break;
3306                         os << "\\usepackage[" << from_ascii(encoding().latexName());
3307                         if (features.runparams().flavor == OutputParams::LUATEX
3308                             || features.runparams().flavor == OutputParams::DVILUATEX)
3309                                 os << "]{luainputenc}\n";
3310                         else
3311                                 os << "]{inputenc}\n";
3312                         break;
3313                 }
3314         }
3315         if (inputenc == "auto-legacy-plain" || features.isRequired("japanese")) {
3316                 // don't default to [utf8]{inputenc} with TeXLive >= 18
3317                 os << "\\ifdefined\\UseRawInputEncoding\n";
3318                 os << "  \\UseRawInputEncoding\\fi\n";
3319         }
3320 }
3321
3322
3323 string const BufferParams::parseFontName(string const & name) const
3324 {
3325         string mangled = name;
3326         size_t const idx = mangled.find('[');
3327         if (idx == string::npos || idx == 0)
3328                 return mangled;
3329         else
3330                 return mangled.substr(0, idx - 1);
3331 }
3332
3333
3334 string const BufferParams::loadFonts(LaTeXFeatures & features) const
3335 {
3336         if (fontsRoman() == "default" && fontsSans() == "default"
3337             && fontsTypewriter() == "default"
3338             && (fontsMath() == "default" || fontsMath() == "auto"))
3339                 //nothing to do
3340                 return string();
3341
3342         ostringstream os;
3343
3344         /* Fontspec (XeTeX, LuaTeX): we provide GUI support for oldstyle
3345          * numbers (Numbers=OldStyle) and sf/tt scaling. The Ligatures=TeX/
3346          * Mapping=tex-text option assures TeX ligatures (such as "--")
3347          * are resolved. Note that tt does not use these ligatures.
3348          * TODO:
3349          *    -- add more GUI options?
3350          *    -- add more fonts (fonts for other scripts)
3351          *    -- if there's a way to find out if a font really supports
3352          *       OldStyle, enable/disable the widget accordingly.
3353         */
3354         if (useNonTeXFonts && features.isAvailable("fontspec")) {
3355                 // "Mapping=tex-text" and "Ligatures=TeX" are equivalent.
3356                 // However, until v.2 (2010/07/11) fontspec only knew
3357                 // Mapping=tex-text (for XeTeX only); then "Ligatures=TeX"
3358                 // was introduced for both XeTeX and LuaTeX (LuaTeX
3359                 // didn't understand "Mapping=tex-text", while XeTeX
3360                 // understood both. With most recent versions, both
3361                 // variants are understood by both engines. However,
3362                 // we want to provide support for at least TeXLive 2009
3363                 // (for XeTeX; LuaTeX is only supported as of v.2)
3364                 // As of 2017/11/03, Babel has its own higher-level
3365                 // interface on top of fontspec that is to be used.
3366                 bool const babelfonts = features.useBabel()
3367                                 && features.isAvailable("babel-2017/11/03");
3368                 string const texmapping =
3369                         (features.runparams().flavor == OutputParams::XETEX) ?
3370                         "Mapping=tex-text" : "Ligatures=TeX";
3371                 if (fontsRoman() != "default") {
3372                         if (babelfonts)
3373                                 os << "\\babelfont{rm}[";
3374                         else
3375                                 os << "\\setmainfont[";
3376                         if (!font_roman_opts.empty())
3377                                 os << font_roman_opts << ',';
3378                         os << texmapping;
3379                         if (fonts_roman_osf)
3380                                 os << ",Numbers=OldStyle";
3381                         os << "]{" << parseFontName(fontsRoman()) << "}\n";
3382                 }
3383                 if (fontsSans() != "default") {
3384                         string const sans = parseFontName(fontsSans());
3385                         if (fontsSansScale() != 100) {
3386                                 if (babelfonts)
3387                                         os << "\\babelfont{sf}";
3388                                 else
3389                                         os << "\\setsansfont";
3390                                 os << "[Scale="
3391                                    << float(fontsSansScale()) / 100 << ',';
3392                                 if (fonts_sans_osf)
3393                                         os << "Numbers=OldStyle,";
3394                                 if (!font_sans_opts.empty())
3395                                         os << font_sans_opts << ',';
3396                                 os << texmapping << "]{"
3397                                    << sans << "}\n";
3398                         } else {
3399                                 if (babelfonts)
3400                                         os << "\\babelfont{sf}[";
3401                                 else
3402                                         os << "\\setsansfont[";
3403                                 if (fonts_sans_osf)
3404                                         os << "Numbers=OldStyle,";
3405                                 if (!font_sans_opts.empty())
3406                                         os << font_sans_opts << ',';
3407                                 os << texmapping << "]{"
3408                                    << sans << "}\n";
3409                         }
3410                 }
3411                 if (fontsTypewriter() != "default") {
3412                         string const mono = parseFontName(fontsTypewriter());
3413                         if (fontsTypewriterScale() != 100) {
3414                                 if (babelfonts)
3415                                         os << "\\babelfont{tt}";
3416                                 else
3417                                         os << "\\setmonofont";
3418                                 os << "[Scale="
3419                                    << float(fontsTypewriterScale()) / 100;
3420                                 if (fonts_typewriter_osf)
3421                                         os << ",Numbers=OldStyle";
3422                                 if (!font_typewriter_opts.empty())
3423                                         os << ',' << font_typewriter_opts;
3424                                 os << "]{"
3425                                    << mono << "}\n";
3426                         } else {
3427                                 if (babelfonts)
3428                                         os << "\\babelfont{tt}";
3429                                 else
3430                                         os << "\\setmonofont";
3431                                 if (!font_typewriter_opts.empty() || fonts_typewriter_osf) {
3432                                         os << '[';
3433                                         if (fonts_typewriter_osf)
3434                                                 os << "Numbers=OldStyle";
3435                                         if (!font_typewriter_opts.empty()) {
3436                                                 if (fonts_typewriter_osf)
3437                                                         os << ',';
3438                                                 os << font_typewriter_opts;
3439                                         }
3440                                         os << ']';
3441                                 }
3442                                 os << '{' << mono << "}\n";
3443                         }
3444                 }
3445                 return os.str();
3446         }
3447
3448         // Tex Fonts
3449         bool const ot1 = (main_font_encoding() == "default" || main_font_encoding() == "OT1");
3450         bool const dryrun = features.runparams().dryrun;
3451         bool const complete = (fontsSans() == "default" && fontsTypewriter() == "default");
3452         bool const nomath = (fontsMath() == "default");
3453
3454         // ROMAN FONTS
3455         os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsRoman())).getLaTeXCode(
3456                 dryrun, ot1, complete, fonts_expert_sc, fonts_roman_osf,
3457                 nomath, font_roman_opts);
3458
3459         // SANS SERIF
3460         os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsSans())).getLaTeXCode(
3461                 dryrun, ot1, complete, fonts_expert_sc, fonts_sans_osf,
3462                 nomath, font_sans_opts, fontsSansScale());
3463
3464         // MONOSPACED/TYPEWRITER
3465         os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsTypewriter())).getLaTeXCode(
3466                 dryrun, ot1, complete, fonts_expert_sc, fonts_typewriter_osf,
3467                 nomath, font_typewriter_opts, fontsTypewriterScale());
3468
3469         // MATH
3470         os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsMath())).getLaTeXCode(
3471                 dryrun, ot1, complete, fonts_expert_sc, fonts_roman_osf,
3472                 nomath);
3473
3474         return os.str();
3475 }
3476
3477
3478 Encoding const & BufferParams::encoding() const
3479 {
3480         // Main encoding for LaTeX output.
3481         if (useNonTeXFonts)
3482                 return *(encodings.fromLyXName("utf8-plain"));
3483         if (inputenc == "auto-legacy" || inputenc == "auto-legacy-plain")
3484                 return *language->encoding();
3485         if (inputenc == "utf8" && language->lang() == "japanese")
3486                 return *(encodings.fromLyXName("utf8-platex"));
3487         Encoding const * const enc = encodings.fromLyXName(inputenc);
3488         if (enc)
3489                 return *enc;
3490         LYXERR0("Unknown inputenc value `" << inputenc
3491                << "'. Using `auto' instead.");
3492         return *language->encoding();
3493 }
3494
3495
3496 string const & BufferParams::defaultBiblioStyle() const
3497 {
3498         if (!biblio_style.empty())
3499                 return biblio_style;
3500
3501         map<string, string> const & bs = documentClass().defaultBiblioStyle();
3502         auto cit = bs.find(theCiteEnginesList.getTypeAsString(citeEngineType()));
3503         if (cit != bs.end())
3504                 return cit->second;
3505         else
3506                 return empty_string();
3507 }
3508
3509
3510 bool BufferParams::fullAuthorList() const
3511 {
3512         return documentClass().fullAuthorList();
3513 }
3514
3515
3516 string BufferParams::getCiteAlias(string const & s) const
3517 {
3518         vector<string> commands =
3519                 documentClass().citeCommands(citeEngineType());
3520         // If it is a real command, don't treat it as an alias
3521         if (find(commands.begin(), commands.end(), s) != commands.end())
3522                 return string();
3523         map<string,string> aliases = documentClass().citeCommandAliases();
3524         if (aliases.find(s) != aliases.end())
3525                 return aliases[s];
3526         return string();
3527 }
3528
3529
3530 vector<string> BufferParams::citeCommands() const
3531 {
3532         static CitationStyle const default_style;
3533         vector<string> commands =
3534                 documentClass().citeCommands(citeEngineType());
3535         if (commands.empty())
3536                 commands.push_back(default_style.name);
3537         return commands;
3538 }
3539
3540
3541 vector<CitationStyle> BufferParams::citeStyles() const
3542 {
3543         static CitationStyle const default_style;
3544         vector<CitationStyle> styles =
3545                 documentClass().citeStyles(citeEngineType());
3546         if (styles.empty())
3547                 styles.push_back(default_style);
3548         return styles;
3549 }
3550
3551
3552 string const BufferParams::bibtexCommand() const
3553 {
3554         // Return document-specific setting if available
3555         if (bibtex_command != "default")
3556                 return bibtex_command;
3557
3558         // If we have "default" in document settings, consult the prefs
3559         // 1. Japanese (uses a specific processor)
3560         if (encoding().package() == Encoding::japanese) {
3561                 if (lyxrc.jbibtex_command != "automatic")
3562                         // Return the specified program, if "automatic" is not set
3563                         return lyxrc.jbibtex_command;
3564                 else if (!useBiblatex()) {
3565                         // With classic BibTeX, return pbibtex, jbibtex, bibtex
3566                         if (lyxrc.jbibtex_alternatives.find("pbibtex") != lyxrc.jbibtex_alternatives.end())
3567                                 return "pbibtex";
3568                         if (lyxrc.jbibtex_alternatives.find("jbibtex") != lyxrc.jbibtex_alternatives.end())
3569                                 return "jbibtex";
3570                         return "bibtex";
3571                 }
3572         }
3573         // 2. All other languages
3574         else if (lyxrc.bibtex_command != "automatic")
3575                 // Return the specified program, if "automatic" is not set
3576                 return lyxrc.bibtex_command;
3577
3578         // 3. Automatic: find the most suitable for the current cite framework
3579         if (useBiblatex()) {
3580                 // For Biblatex, we prefer biber (also for Japanese)
3581                 // and fall back to bibtex8 and, as last resort, bibtex
3582                 if (lyxrc.bibtex_alternatives.find("biber") != lyxrc.bibtex_alternatives.end())
3583                         return "biber";
3584                 else if (lyxrc.bibtex_alternatives.find("bibtex8") != lyxrc.bibtex_alternatives.end())
3585                         return "bibtex8";
3586         }
3587         return "bibtex";
3588 }
3589
3590
3591 bool BufferParams::useBiblatex() const
3592 {
3593         return theCiteEnginesList[citeEngine()]->getCiteFramework() == "biblatex";
3594 }
3595
3596
3597 void BufferParams::invalidateConverterCache() const
3598 {
3599         pimpl_->isExportCacheValid = false;
3600         pimpl_->isViewCacheValid = false;
3601 }
3602
3603
3604 // We shouldn't need to reset the params here, since anything
3605 // we need will be recopied.
3606 void BufferParams::copyForAdvFR(const BufferParams & bp)
3607 {
3608         string const & lang = bp.language->lang();
3609         setLanguage(lang);
3610         layout_modules_ = bp.layout_modules_;
3611         string const & doc_class = bp.documentClass().name();
3612         setBaseClass(doc_class);
3613 }
3614
3615
3616 void BufferParams::setBibFileEncoding(string const & file, string const & enc)
3617 {
3618         bib_encodings[file] = enc;
3619 }
3620
3621
3622 string const BufferParams::bibFileEncoding(string const & file) const
3623 {
3624         if (bib_encodings.find(file) == bib_encodings.end())
3625                 return string();
3626         return bib_encodings.find(file)->second;
3627 }
3628
3629
3630
3631 } // namespace lyx