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