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