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