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