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