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