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