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