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