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