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