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