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