3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
9 * Full author contact details are available in file CREDITS.
20 #include "LayoutFile.h"
23 #include "TextClass.h"
26 #include "support/convert.h"
27 #include "support/FileName.h"
28 #include "support/filetools.h"
29 #include "support/lstrings.h"
31 #include "support/regex.h"
37 using namespace lyx::support;
46 // CJK languages are handled in text.cpp, polyglossia languages are listed
49 * known babel language names (including synonyms)
50 * not in standard babel: arabic, arabtex, armenian, belarusian, serbian-latin, thai
51 * please keep this in sync with known_coded_languages line by line!
53 const char * const known_languages[] = {"acadian", "afrikaans", "albanian",
54 "american", "arabic", "arabtex", "australian", "austrian", "bahasa", "bahasai",
55 "bahasam", "basque", "belarusian", "bosnian", "brazil", "brazilian", "breton", "british",
56 "bulgarian", "canadian", "canadien", "catalan", "croatian", "czech", "danish",
57 "dutch", "english", "esperanto", "estonian", "farsi", "finnish", "francais",
58 "french", "frenchb", "frenchle", "frenchpro", "friulan", "galician", "german", "germanb",
59 "georgian", "greek", "hebrew", "hungarian", "icelandic", "indon", "indonesian",
60 "interlingua", "irish", "italian", "japanese", "kazakh", "kurmanji", "latin",
61 "latvian", "lithuanian", "lowersorbian", "lsorbian", "macedonian", "magyar", "malay", "meyalu",
62 "mongolian", "naustrian", "newzealand", "ngerman", "ngermanb", "norsk", "nswissgerman",
63 "nynorsk", "piedmontese", "polutonikogreek", "polish", "portuges", "portuguese",
64 "romanian", "romansh", "russian", "russianb", "samin", "scottish", "serbian", "serbian-latin",
65 "slovak", "slovene", "spanish", "swedish", "swissgerman", "thai", "turkish", "turkmen",
66 "ukraineb", "ukrainian", "uppersorbian", "UKenglish", "USenglish", "usorbian",
71 * the same as known_languages with .lyx names
72 * please keep this in sync with known_languages line by line!
74 const char * const known_coded_languages[] = {"french", "afrikaans", "albanian",
75 "american", "arabic_arabi", "arabic_arabtex", "australian", "austrian", "bahasa", "bahasa",
76 "bahasam", "basque", "belarusian", "bosnian", "brazilian", "brazilian", "breton", "british",
77 "bulgarian", "canadian", "canadien", "catalan", "croatian", "czech", "danish",
78 "dutch", "english", "esperanto", "estonian", "farsi", "finnish", "french",
79 "french", "french", "french", "french", "friulan", "galician", "german", "german",
80 "georgian", "greek", "hebrew", "magyar", "icelandic", "bahasa", "bahasa",
81 "interlingua", "irish", "italian", "japanese", "kazakh", "kurmanji", "latin",
82 "latvian", "lithuanian", "lowersorbian", "lowersorbian", "macedonian", "magyar", "bahasam", "bahasam",
83 "mongolian", "naustrian", "newzealand", "ngerman", "ngerman", "norsk", "german-ch",
84 "nynorsk", "piedmontese", "polutonikogreek", "polish", "portuguese", "portuguese",
85 "romanian", "romansh", "russian", "russian", "samin", "scottish", "serbian", "serbian-latin",
86 "slovak", "slovene", "spanish", "swedish", "german-ch-old", "thai", "turkish", "turkmen",
87 "ukrainian", "ukrainian", "uppersorbian", "english", "english", "uppersorbian",
88 "vietnamese", "welsh",
91 /// languages with british quotes (.lyx names)
92 const char * const known_british_quotes_languages[] = {"british", "welsh", 0};
94 /// languages with cjk quotes (.lyx names)
95 const char * const known_cjk_quotes_languages[] = {"chinese-traditional",
96 "japanese", "japanese-cjk", 0};
98 /// languages with cjk-angle quotes (.lyx names)
99 const char * const known_cjkangle_quotes_languages[] = {"korean", 0};
101 /// languages with danish quotes (.lyx names)
102 const char * const known_danish_quotes_languages[] = {"danish", 0};
104 /// languages with english quotes (.lyx names)
105 const char * const known_english_quotes_languages[] = {"american", "australian",
106 "bahasa", "bahasam", "brazilian", "canadian", "chinese-simplified", "english",
107 "esperanto", "farsi", "interlingua", "irish", "newzealand", "scottish",
108 "thai", "turkish", "vietnamese", 0};
110 /// languages with french quotes (.lyx names)
111 const char * const known_french_quotes_languages[] = {"ancientgreek",
112 "arabic_arabi", "arabic_arabtex", "asturian", "belarusian", "breton",
113 "canadien", "catalan", "french", "friulan", "galician", "italian", "occitan",
114 "piedmontese", "portuguese", "spanish", "spanish-mexico", 0};
116 /// languages with german quotes (.lyx names)
117 const char * const known_german_quotes_languages[] = {"austrian", "bulgarian",
118 "czech", "estonian", "georgian", "german", "icelandic", "latvian", "lithuanian",
119 "lowersorbian", "macedonian", "naustrian", "ngerman", "romansh", "slovak", "slovene",
122 /// languages with polish quotes (.lyx names)
123 const char * const known_polish_quotes_languages[] = {"afrikaans", "bosnian", "croatian",
124 "dutch", "magyar", "polish", "romanian", "serbian", "serbian-latin", 0};
126 /// languages with russian quotes (.lyx names)
127 const char * const known_russian_quotes_languages[] = {"russian", "ukrainian", 0};
129 /// languages with swedish quotes (.lyx names)
130 const char * const known_swedish_quotes_languages[] = {"finnish", "swedish", 0};
132 /// languages with swiss quotes (.lyx names)
133 const char * const known_swiss_quotes_languages[] = {"albanian",
134 "armenian", "basque", "german-ch", "german-ch-old",
135 "norsk", "nynorsk", "turkmen", "ukrainian", "vietnamese", 0};
137 /// known language packages from the times before babel
138 const char * const known_old_language_packages[] = {"french", "frenchle",
139 "frenchpro", "german", "ngerman", "pmfrench", 0};
141 char const * const known_fontsizes[] = { "10pt", "11pt", "12pt", 0 };
143 const char * const known_roman_fonts[] = { "ae", "beraserif", "bookman",
144 "ccfonts", "chancery", "charter", "cmr", "cochineal", "crimson", "fourier",
145 "garamondx", "libertine", "libertineRoman", "libertine-type1", "lmodern", "mathdesign", "mathpazo",
146 "mathptmx", "MinionPro", "newcent", "NotoSerif-TLF", "PTSerif-TLF", "tgbonum", "tgchorus",
147 "tgpagella", "tgschola", "tgtermes", "utopia", "xcharter", 0 };
149 const char * const known_sans_fonts[] = { "avant", "berasans", "biolinum",
150 "biolinum-type1", "cmbr", "cmss", "helvet", "iwona", "iwonac", "iwonal", "iwonalc",
151 "kurier", "kurierc", "kurierl", "kurierlc", "lmss", "NotoSans-TLF", "PTSans-TLF",
152 "tgadventor", "tgheros", "uop", 0 };
154 const char * const known_typewriter_fonts[] = { "beramono", "cmtl", "cmtt",
155 "courier", "lmtt", "luximono", "fourier", "libertineMono", "libertineMono-type1", "lmodern",
156 "mathpazo", "mathptmx", "newcent", "NotoMono-TLF", "PTMono-TLF", "tgcursor", "txtt", 0 };
158 const char * const known_math_fonts[] = { "eulervm", "newtxmath", 0};
160 const char * const known_paper_sizes[] = { "a0paper", "b0paper", "c0paper",
161 "a1paper", "b1paper", "c1paper", "a2paper", "b2paper", "c2paper", "a3paper",
162 "b3paper", "c3paper", "a4paper", "b4paper", "c4paper", "a5paper", "b5paper",
163 "c5paper", "a6paper", "b6paper", "c6paper", "executivepaper", "legalpaper",
164 "letterpaper", "b0j", "b1j", "b2j", "b3j", "b4j", "b5j", "b6j", 0};
166 const char * const known_class_paper_sizes[] = { "a4paper", "a5paper",
167 "executivepaper", "legalpaper", "letterpaper", 0};
169 const char * const known_paper_margins[] = { "lmargin", "tmargin", "rmargin",
170 "bmargin", "headheight", "headsep", "footskip", "columnsep", 0};
172 const char * const known_coded_paper_margins[] = { "leftmargin", "topmargin",
173 "rightmargin", "bottommargin", "headheight", "headsep", "footskip",
176 /// commands that can start an \if...\else...\endif sequence
177 const char * const known_if_commands[] = {"if", "ifarydshln", "ifbraket",
178 "ifcancel", "ifcolortbl", "ifeurosym", "ifmarginnote", "ifmmode", "ifpdf",
179 "ifsidecap", "ifupgreek", 0};
181 const char * const known_basic_colors[] = {"black", "blue", "brown", "cyan",
182 "darkgray", "gray", "green", "lightgray", "lime", "magenta", "orange", "olive",
183 "pink", "purple", "red", "teal", "violet", "white", "yellow", 0};
185 const char * const known_basic_color_codes[] = {"#000000", "#0000ff", "#964B00", "#00ffff",
186 "#a9a9a9", "#808080", "#00ff00", "#d3d3d3", "#bfff00", "#ff00ff", "#ff7f00", "#808000",
187 "#ffc0cb", "#800080", "#ff0000", "#008080", "#8f00ff", "#ffffff", "#ffff00", 0};
189 /// conditional commands with three arguments like \@ifundefined{}{}{}
190 const char * const known_if_3arg_commands[] = {"@ifundefined", "IfFileExists",
194 * Known file extensions for TeX files as used by \\includeonly
196 char const * const known_tex_extensions[] = {"tex", 0};
198 /// packages that work only in xetex
199 /// polyglossia is handled separately
200 const char * const known_xetex_packages[] = {"arabxetex", "fixlatvian",
201 "fontbook", "fontwrap", "mathspec", "philokalia", "unisugar",
202 "xeCJK", "xecolor", "xecyr", "xeindex", "xepersian", "xunicode", 0};
204 /// packages that are automatically skipped if loaded by LyX
205 const char * const known_lyx_packages[] = {"amsbsy", "amsmath", "amssymb",
206 "amstext", "amsthm", "array", "babel", "booktabs", "calc", "CJK", "color",
207 "float", "fontspec", "framed", "graphicx", "hhline", "ifthen", "longtable",
208 "makeidx", "minted", "multirow", "nomencl", "pdfpages", "prettyref", "refstyle",
209 "rotating", "rotfloat", "splitidx", "setspace", "subscript", "textcomp", "tipa",
210 "tipx", "tone", "ulem", "url", "varioref", "verbatim", "wrapfig", "xcolor",
213 // codes used to remove packages that are loaded automatically by LyX.
214 // Syntax: package_beg_sep<name>package_mid_sep<package loading code>package_end_sep
215 const char package_beg_sep = '\001';
216 const char package_mid_sep = '\002';
217 const char package_end_sep = '\003';
220 // returns true if at least one of the options in what has been found
221 bool handle_opt(vector<string> & opts, char const * const * what, string & target)
227 // the last language option is the document language (for babel and LyX)
228 // the last size option is the document font size
229 vector<string>::iterator it;
230 vector<string>::iterator position = opts.begin();
231 for (; *what; ++what) {
232 it = find(opts.begin(), opts.end(), *what);
233 if (it != opts.end()) {
234 if (it >= position) {
245 void delete_opt(vector<string> & opts, char const * const * what)
250 // remove found options from the list
251 // do this after handle_opt to avoid potential memory leaks
252 vector<string>::iterator it;
253 for (; *what; ++what) {
254 it = find(opts.begin(), opts.end(), *what);
255 if (it != opts.end())
262 * Split a package options string (keyval format) into a vector.
264 * authorformat=smallcaps,
266 * titleformat=colonsep,
267 * bibformat={tabular,ibidem,numbered}
269 vector<string> split_options(string const & input)
271 vector<string> options;
275 Token const & t = p.get_token();
276 if (t.asInput() == ",") {
277 options.push_back(trimSpaceAndEol(option));
279 } else if (t.asInput() == "=") {
282 if (p.next_token().asInput() == "{")
283 option += '{' + p.getArg('{', '}') + '}';
284 } else if (t.cat() != catSpace && t.cat() != catComment)
285 option += t.asInput();
289 options.push_back(trimSpaceAndEol(option));
296 * Retrieve a keyval option "name={value with=sign}" named \p name from
297 * \p options and return the value.
298 * The found option is also removed from \p options.
300 string process_keyval_opt(vector<string> & options, string name)
302 for (size_t i = 0; i < options.size(); ++i) {
303 vector<string> option;
304 split(options[i], option, '=');
305 if (option.size() < 2)
307 if (option[0] == name) {
308 options.erase(options.begin() + i);
309 option.erase(option.begin());
310 return join(option, "=");
316 } // anonymous namespace
320 * known polyglossia language names (including variants)
321 * FIXME: support spelling=old for german variants (german vs. ngerman LyX names etc)
323 const char * const Preamble::polyglossia_languages[] = {
324 "albanian", "american", "amharic", "ancient", "arabic", "armenian", "asturian", "australian",
325 "bahasai", "bahasam", "basque", "bengali", "brazil", "brazilian", "breton", "british", "bulgarian",
326 "catalan", "coptic", "croatian", "czech", "danish", "divehi", "dutch",
327 "english", "esperanto", "estonian", "farsi", "finnish", "french", "friulan",
328 "galician", "greek", "monotonic", "hebrew", "hindi",
329 "icelandic", "interlingua", "irish", "italian", "kannada", "khmer",
330 "lao", "latin", "latvian", "lithuanian", "lsorbian", "magyar", "malayalam", "marathi",
331 "austrian", "newzealand", "german", "norsk", "nynorsk", "occitan",
332 "piedmontese", "polish", "polytonic", "portuges", "romanian", "romansh", "russian",
333 "samin", "sanskrit", "scottish", "serbian", "slovak", "slovenian", "spanish", "swedish", "syriac",
334 "tamil", "telugu", "thai", "tibetan", "turkish", "turkmen",
335 "ukrainian", "urdu", "usorbian", "vietnamese", "welsh", 0};
336 // not yet supported by LyX: "korean", "nko"
339 * the same as polyglossia_languages with .lyx names
340 * please keep this in sync with polyglossia_languages line by line!
342 const char * const Preamble::coded_polyglossia_languages[] = {
343 "albanian", "american", "amharic", "ancientgreek", "arabic_arabi", "armenian", "asturian", "australian",
344 "bahasa", "bahasam", "basque", "bengali", "brazilian", "brazilian", "breton", "british", "bulgarian",
345 "catalan", "coptic", "croatian", "czech", "danish", "divehi", "dutch",
346 "english", "esperanto", "estonian", "farsi", "finnish", "french", "friulan",
347 "galician", "greek", "greek", "hebrew", "hindi",
348 "icelandic", "interlingua", "irish", "italian", "kannada", "khmer",
349 "lao", "latin", "latvian", "lithuanian", "lowersorbian", "magyar", "malayalam", "marathi",
350 "naustrian","newzealand", "ngerman", "norsk", "nynorsk", "occitan",
351 "piedmontese", "polish", "polutonikogreek", "portuges", "romanian", "romansh", "russian",
352 "samin", "sanskrit", "scottish", "serbian", "slovak", "slovene", "spanish", "swedish", "syriac",
353 "tamil", "telugu", "thai", "tibetan", "turkish", "turkmen",
354 "ukrainian", "urdu", "uppersorbian", "vietnamese", "welsh", 0};
355 // not yet supported by LyX: "korean-polyglossia", "nko"
358 bool Preamble::usePolyglossia() const
360 return h_use_non_tex_fonts && h_language_package == "default";
364 bool Preamble::indentParagraphs() const
366 return h_paragraph_separation == "indent";
370 bool Preamble::isPackageUsed(string const & package) const
372 return used_packages.find(package) != used_packages.end();
376 vector<string> Preamble::getPackageOptions(string const & package) const
378 map<string, vector<string> >::const_iterator it = used_packages.find(package);
379 if (it != used_packages.end())
381 return vector<string>();
385 void Preamble::registerAutomaticallyLoadedPackage(std::string const & package)
387 auto_packages.insert(package);
391 void Preamble::addModule(string const & module)
393 used_modules.push_back(module);
397 void Preamble::suppressDate(bool suppress)
400 h_suppress_date = "true";
402 h_suppress_date = "false";
406 void Preamble::registerAuthor(std::string const & name)
408 Author author(from_utf8(name), empty_docstring());
409 author.setUsed(true);
410 authors_.record(author);
411 h_tracking_changes = "true";
412 h_output_changes = "true";
416 Author const & Preamble::getAuthor(std::string const & name) const
418 Author author(from_utf8(name), empty_docstring());
419 for (AuthorList::Authors::const_iterator it = authors_.begin();
420 it != authors_.end(); ++it)
423 static Author const dummy;
428 int Preamble::getSpecialTableColumnArguments(char c) const
430 map<char, int>::const_iterator it = special_columns_.find(c);
431 if (it == special_columns_.end())
437 void Preamble::add_package(string const & name, vector<string> & options)
439 // every package inherits the global options
440 if (used_packages.find(name) == used_packages.end())
441 used_packages[name] = split_options(h_options);
443 // Insert options passed via PassOptionsToPackage
444 for (auto const & p : extra_package_options_) {
445 if (p.first == name) {
446 vector<string> eo = getVectorFromString(p.second);
447 for (auto const & eoi : eo)
448 options.push_back(eoi);
452 vector<string> & v = used_packages[name];
453 v.insert(v.end(), options.begin(), options.end());
454 if (name == "jurabib") {
455 // Don't output the order argument (see the cite command
456 // handling code in text.cpp).
457 vector<string>::iterator end =
458 remove(options.begin(), options.end(), "natbiborder");
459 end = remove(options.begin(), end, "jurabiborder");
460 options.erase(end, options.end());
467 // Given is a string like "scaled=0.9" or "Scale=0.9", return 0.9 * 100
468 bool scale_as_percentage(string const & scale, string & percentage)
470 string::size_type pos = scale.find('=');
471 if (pos != string::npos) {
472 string value = scale.substr(pos + 1);
473 if (isStrDbl(value)) {
474 percentage = convert<string>(
475 static_cast<int>(100 * convert<double>(value)));
483 string remove_braces(string const & value)
487 if (value[0] == '{' && value[value.length()-1] == '}')
488 return value.substr(1, value.length()-2);
492 } // anonymous namespace
495 Preamble::Preamble() : one_language(true), explicit_babel(false),
496 title_layout_found(false), index_number(0), h_font_cjk_set(false),
497 h_use_microtype("false")
501 h_biblio_style = "plain";
502 h_bibtex_command = "default";
503 h_cite_engine = "basic";
504 h_cite_engine_type = "default";
506 h_defskip = "medskip";
507 h_dynamic_quotes = false;
510 h_fontencoding = "default";
511 h_font_roman[0] = "default";
512 h_font_roman[1] = "default";
513 h_font_sans[0] = "default";
514 h_font_sans[1] = "default";
515 h_font_typewriter[0] = "default";
516 h_font_typewriter[1] = "default";
517 h_font_math[0] = "auto";
518 h_font_math[1] = "auto";
519 h_font_default_family = "default";
520 h_use_non_tex_fonts = false;
522 h_font_osf = "false";
523 h_font_sf_scale[0] = "100";
524 h_font_sf_scale[1] = "100";
525 h_font_tt_scale[0] = "100";
526 h_font_tt_scale[1] = "100";
528 h_is_mathindent = "0";
529 h_math_numbering_side = "default";
530 h_graphics = "default";
531 h_default_output_format = "default";
532 h_html_be_strict = "false";
533 h_html_css_as_file = "0";
534 h_html_math_output = "0";
535 h_index[0] = "Index";
536 h_index_command = "default";
537 h_inputencoding = "auto";
538 h_justification = "true";
539 h_language = "english";
540 h_language_package = "none";
542 h_maintain_unincluded_children = "false";
546 h_output_changes = "false";
548 //h_output_sync_macro
549 h_papercolumns = "1";
550 h_paperfontsize = "default";
551 h_paperorientation = "portrait";
552 h_paperpagestyle = "default";
554 h_papersize = "default";
555 h_paragraph_indentation = "default";
556 h_paragraph_separation = "indent";
561 h_pdf_bookmarks = "0";
562 h_pdf_bookmarksnumbered = "0";
563 h_pdf_bookmarksopen = "0";
564 h_pdf_bookmarksopenlevel = "1";
565 h_pdf_breaklinks = "0";
566 h_pdf_pdfborder = "0";
567 h_pdf_colorlinks = "0";
568 h_pdf_backref = "section";
569 h_pdf_pdfusetitle = "0";
571 //h_pdf_quoted_options;
572 h_quotes_style = "english";
574 h_shortcut[0] = "idx";
575 h_spacing = "single";
576 h_save_transient_properties = "true";
577 h_suppress_date = "false";
578 h_textclass = "article";
580 h_tracking_changes = "false";
581 h_use_bibtopic = "false";
582 h_use_dash_ligatures = "true";
583 h_use_indices = "false";
584 h_use_geometry = "false";
585 h_use_default_options = "false";
586 h_use_hyperref = "false";
587 h_use_microtype = "false";
588 h_use_refstyle = false;
589 h_use_minted = false;
590 h_use_packages["amsmath"] = "1";
591 h_use_packages["amssymb"] = "0";
592 h_use_packages["cancel"] = "0";
593 h_use_packages["esint"] = "1";
594 h_use_packages["mhchem"] = "0";
595 h_use_packages["mathdots"] = "0";
596 h_use_packages["mathtools"] = "0";
597 h_use_packages["stackrel"] = "0";
598 h_use_packages["stmaryrd"] = "0";
599 h_use_packages["undertilde"] = "0";
603 void Preamble::handle_hyperref(vector<string> & options)
605 // FIXME swallow inputencoding changes that might surround the
606 // hyperref setup if it was written by LyX
607 h_use_hyperref = "true";
608 // swallow "unicode=true", since LyX does always write that
609 vector<string>::iterator it =
610 find(options.begin(), options.end(), "unicode=true");
611 if (it != options.end())
613 it = find(options.begin(), options.end(), "pdfusetitle");
614 if (it != options.end()) {
615 h_pdf_pdfusetitle = "1";
618 string bookmarks = process_keyval_opt(options, "bookmarks");
619 if (bookmarks == "true")
620 h_pdf_bookmarks = "1";
621 else if (bookmarks == "false")
622 h_pdf_bookmarks = "0";
623 if (h_pdf_bookmarks == "1") {
624 string bookmarksnumbered =
625 process_keyval_opt(options, "bookmarksnumbered");
626 if (bookmarksnumbered == "true")
627 h_pdf_bookmarksnumbered = "1";
628 else if (bookmarksnumbered == "false")
629 h_pdf_bookmarksnumbered = "0";
630 string bookmarksopen =
631 process_keyval_opt(options, "bookmarksopen");
632 if (bookmarksopen == "true")
633 h_pdf_bookmarksopen = "1";
634 else if (bookmarksopen == "false")
635 h_pdf_bookmarksopen = "0";
636 if (h_pdf_bookmarksopen == "1") {
637 string bookmarksopenlevel =
638 process_keyval_opt(options, "bookmarksopenlevel");
639 if (!bookmarksopenlevel.empty())
640 h_pdf_bookmarksopenlevel = bookmarksopenlevel;
643 string breaklinks = process_keyval_opt(options, "breaklinks");
644 if (breaklinks == "true")
645 h_pdf_breaklinks = "1";
646 else if (breaklinks == "false")
647 h_pdf_breaklinks = "0";
648 string pdfborder = process_keyval_opt(options, "pdfborder");
649 if (pdfborder == "{0 0 0}")
650 h_pdf_pdfborder = "1";
651 else if (pdfborder == "{0 0 1}")
652 h_pdf_pdfborder = "0";
653 string backref = process_keyval_opt(options, "backref");
654 if (!backref.empty())
655 h_pdf_backref = backref;
656 string colorlinks = process_keyval_opt(options, "colorlinks");
657 if (colorlinks == "true")
658 h_pdf_colorlinks = "1";
659 else if (colorlinks == "false")
660 h_pdf_colorlinks = "0";
661 string pdfpagemode = process_keyval_opt(options, "pdfpagemode");
662 if (!pdfpagemode.empty())
663 h_pdf_pagemode = pdfpagemode;
664 string pdftitle = process_keyval_opt(options, "pdftitle");
665 if (!pdftitle.empty()) {
666 h_pdf_title = remove_braces(pdftitle);
668 string pdfauthor = process_keyval_opt(options, "pdfauthor");
669 if (!pdfauthor.empty()) {
670 h_pdf_author = remove_braces(pdfauthor);
672 string pdfsubject = process_keyval_opt(options, "pdfsubject");
673 if (!pdfsubject.empty())
674 h_pdf_subject = remove_braces(pdfsubject);
675 string pdfkeywords = process_keyval_opt(options, "pdfkeywords");
676 if (!pdfkeywords.empty())
677 h_pdf_keywords = remove_braces(pdfkeywords);
678 if (!options.empty()) {
679 if (!h_pdf_quoted_options.empty())
680 h_pdf_quoted_options += ',';
681 h_pdf_quoted_options += join(options, ",");
687 void Preamble::handle_geometry(vector<string> & options)
689 h_use_geometry = "true";
690 vector<string>::iterator it;
692 if ((it = find(options.begin(), options.end(), "landscape")) != options.end()) {
693 h_paperorientation = "landscape";
697 // keyval version: "paper=letter"
698 string paper = process_keyval_opt(options, "paper");
700 h_papersize = paper + "paper";
701 // alternative version: "letterpaper"
702 handle_opt(options, known_paper_sizes, h_papersize);
703 delete_opt(options, known_paper_sizes);
705 char const * const * margin = known_paper_margins;
706 for (; *margin; ++margin) {
707 string value = process_keyval_opt(options, *margin);
708 if (!value.empty()) {
709 int k = margin - known_paper_margins;
710 string name = known_coded_paper_margins[k];
711 h_margins += '\\' + name + ' ' + value + '\n';
717 void Preamble::handle_package(Parser &p, string const & name,
718 string const & opts, bool in_lyx_preamble,
721 vector<string> options = split_options(opts);
722 add_package(name, options);
724 if (is_known(name, known_xetex_packages)) {
726 h_use_non_tex_fonts = true;
727 registerAutomaticallyLoadedPackage("fontspec");
728 if (h_inputencoding == "auto")
729 p.setEncoding("UTF-8");
733 if (is_known(name, known_roman_fonts))
734 h_font_roman[0] = name;
736 if (name == "fourier") {
737 h_font_roman[0] = "utopia";
738 // when font uses real small capitals
739 if (opts == "expert")
743 if (name == "garamondx") {
744 h_font_roman[0] = "garamondx";
749 if (name == "libertine") {
750 h_font_roman[0] = "libertine";
751 // this automatically invokes biolinum
752 h_font_sans[0] = "biolinum";
753 // as well as libertineMono
754 h_font_typewriter[0] = "libertine-mono";
757 else if (opts == "lining")
758 h_font_osf = "false";
761 if (name == "libertineRoman" || name == "libertine-type1") {
762 h_font_roman[0] = "libertine";
763 // NOTE: contrary to libertine.sty, libertineRoman
764 // and libertine-type1 do not automatically invoke
765 // biolinum and libertineMono
766 if (opts == "lining")
767 h_font_osf = "false";
768 else if (opts == "osf")
772 if (name == "MinionPro") {
773 h_font_roman[0] = "minionpro";
774 if (opts.find("lf") != string::npos)
775 h_font_osf = "false";
778 if (opts.find("onlytext") != string::npos)
779 h_font_math[0] = "default";
781 h_font_math[0] = "auto";
784 if (name == "mathdesign") {
785 if (opts.find("charter") != string::npos)
786 h_font_roman[0] = "md-charter";
787 if (opts.find("garamond") != string::npos)
788 h_font_roman[0] = "md-garamond";
789 if (opts.find("utopia") != string::npos)
790 h_font_roman[0] = "md-utopia";
791 if (opts.find("expert") != string::npos) {
797 else if (name == "mathpazo")
798 h_font_roman[0] = "palatino";
800 else if (name == "mathptmx")
801 h_font_roman[0] = "times";
803 if (name == "crimson")
804 h_font_roman[0] = "cochineal";
806 if (name == "cochineal") {
807 h_font_roman[0] = "cochineal";
808 // cochineal can have several options, e.g. [proportional,osf]
809 string::size_type pos = opts.find("osf");
810 if (pos != string::npos)
814 if (name == "noto") {
815 // noto can have several options
817 h_font_roman[0] = "NotoSerif-TLF";
818 string::size_type pos = opts.find("rm");
819 if (pos != string::npos)
820 h_font_roman[0] = "NotoSerif-TLF";
821 pos = opts.find("sf");
822 if (pos != string::npos)
823 h_font_sans[0] = "NotoSans-TLF";
824 pos = opts.find("nott");
825 if (pos != string::npos) {
826 h_font_roman[0] = "NotoSerif-TLF";
827 h_font_sans[0] = "NotoSans-TLF";
829 // noto as typewriter is handled in handling of \ttdefault
830 // special cases are handled in handling of \rmdefault and \sfdefault
833 if (name == "paratype") {
834 // in this case all fonts are ParaType
835 h_font_roman[0] = "PTSerif-TLF";
836 h_font_sans[0] = "default";
837 h_font_typewriter[0] = "default";
840 if (name == "PTSerif")
841 h_font_roman[0] = "PTSerif-TLF";
843 if (name == "XCharter") {
844 h_font_roman[0] = "xcharter";
850 if (is_known(name, known_sans_fonts)) {
851 h_font_sans[0] = name;
852 if (options.size() >= 1) {
853 if (scale_as_percentage(opts, h_font_sf_scale[0]))
858 if (name == "biolinum" || name == "biolinum-type1") {
859 h_font_sans[0] = "biolinum";
860 // biolinum can have several options, e.g. [osf,scaled=0.97]
861 string::size_type pos = opts.find("osf");
862 if (pos != string::npos)
866 if (name == "PTSans") {
867 h_font_sans[0] = "PTSans-TLF";
868 if (options.size() >= 1) {
869 if (scale_as_percentage(opts, h_font_sf_scale[0]))
875 if (is_known(name, known_typewriter_fonts)) {
876 // fourier can be set as roman font _only_
877 // fourier as typewriter is handled in handling of \ttdefault
878 if (name != "fourier") {
879 h_font_typewriter[0] = name;
880 if (options.size() >= 1) {
881 if (scale_as_percentage(opts, h_font_tt_scale[0]))
887 if (name == "libertineMono" || name == "libertineMono-type1")
888 h_font_typewriter[0] = "libertine-mono";
890 if (name == "PTMono") {
891 h_font_typewriter[0] = "PTMono-TLF";
892 if (options.size() >= 1) {
893 if (scale_as_percentage(opts, h_font_tt_scale[0]))
898 // font uses old-style figure
903 if (is_known(name, known_math_fonts))
904 h_font_math[0] = name;
906 if (name == "newtxmath") {
908 h_font_math[0] = "newtxmath";
909 else if (opts == "garamondx")
910 h_font_math[0] = "garamondx-ntxm";
911 else if (opts == "libertine")
912 h_font_math[0] = "libertine-ntxm";
913 else if (opts == "minion")
914 h_font_math[0] = "minion-ntxm";
915 else if (opts == "cochineal")
916 h_font_math[0] = "cochineal-ntxm";
921 h_font_math[0] = "iwona-math";
923 if (name == "kurier")
925 h_font_math[0] = "kurier-math";
927 // after the detection and handling of special cases, we can remove the
928 // fonts, otherwise they would appear in the preamble, see bug #7856
929 if (is_known(name, known_roman_fonts) || is_known(name, known_sans_fonts)
930 || is_known(name, known_typewriter_fonts) || is_known(name, known_math_fonts))
932 //"On". See the enum Package in BufferParams.h if you thought that "2" should have been "42"
933 else if (name == "amsmath" || name == "amssymb" || name == "cancel" ||
934 name == "esint" || name == "mhchem" || name == "mathdots" ||
935 name == "mathtools" || name == "stackrel" ||
936 name == "stmaryrd" || name == "undertilde")
937 h_use_packages[name] = "2";
939 else if (name == "babel") {
940 h_language_package = "default";
941 // One might think we would have to do nothing if babel is loaded
942 // without any options to prevent pollution of the preamble with this
943 // babel call in every roundtrip.
944 // But the user could have defined babel-specific things afterwards. So
945 // we need to keep it in the preamble to prevent cases like bug #7861.
947 // check if more than one option was used - used later for inputenc
948 if (options.begin() != options.end() - 1)
949 one_language = false;
950 // babel takes the last language of the option of its \usepackage
951 // call as document language. If there is no such language option, the
952 // last language in the documentclass options is used.
953 handle_opt(options, known_languages, h_language);
954 // translate the babel name to a LyX name
955 h_language = babel2lyx(h_language);
956 if (h_language == "japanese") {
957 // For Japanese, the encoding isn't indicated in the source
958 // file, and there's really not much we can do. We could
959 // 1) offer a list of possible encodings to choose from, or
960 // 2) determine the encoding of the file by inspecting it.
961 // For the time being, we leave the encoding alone so that
962 // we don't get iconv errors when making a wrong guess, and
963 // we will output a note at the top of the document
964 // explaining what to do.
965 Encoding const * const enc = encodings.fromIconvName(
966 p.getEncoding(), Encoding::japanese, false);
968 h_inputencoding = enc->name();
969 is_nonCJKJapanese = true;
970 // in this case babel can be removed from the preamble
971 registerAutomaticallyLoadedPackage("babel");
973 // If babel is called with options, LyX puts them by default into the
974 // document class options. This works for most languages, except
975 // for Latvian, Lithuanian, Mongolian, Turkmen and Vietnamese and
976 // perhaps in future others.
977 // Therefore keep the babel call as it is as the user might have
979 h_preamble << "\\usepackage[" << opts << "]{babel}\n";
981 delete_opt(options, known_languages);
983 h_preamble << "\\usepackage{babel}\n";
984 explicit_babel = true;
988 else if (name == "polyglossia") {
989 h_language_package = "default";
990 h_default_output_format = "pdf4";
991 h_use_non_tex_fonts = true;
993 registerAutomaticallyLoadedPackage("xunicode");
994 if (h_inputencoding == "auto")
995 p.setEncoding("UTF-8");
998 else if (name == "CJK") {
999 // set the encoding to "auto" because it might be set to "default" by the babel handling
1000 // and this would not be correct for CJK
1001 if (h_inputencoding == "default")
1002 h_inputencoding = "auto";
1003 registerAutomaticallyLoadedPackage("CJK");
1006 else if (name == "CJKutf8") {
1007 h_inputencoding = "utf8-cjk";
1008 p.setEncoding("UTF-8");
1009 registerAutomaticallyLoadedPackage("CJKutf8");
1012 else if (name == "fontenc") {
1013 h_fontencoding = getStringFromVector(options, ",");
1014 /* We could do the following for better round trip support,
1015 * but this makes the document less portable, so I skip it:
1016 if (h_fontencoding == lyxrc.fontenc)
1017 h_fontencoding = "global";
1022 else if (name == "inputenc" || name == "luainputenc") {
1023 // h_inputencoding is only set when there is not more than one
1024 // inputenc option because otherwise h_inputencoding must be
1025 // set to "auto" (the default encoding of the document language)
1026 // Therefore check that exactly one option is passed to inputenc.
1027 // It is also only set when there is not more than one babel
1029 if (!options.empty()) {
1030 string const encoding = options.back();
1031 Encoding const * const enc = encodings.fromLaTeXName(
1032 encoding, Encoding::inputenc, true);
1034 if (!detectEncoding)
1035 cerr << "Unknown encoding " << encoding
1036 << ". Ignoring." << std::endl;
1038 if (!enc->unsafe() && options.size() == 1 && one_language == true)
1039 h_inputencoding = enc->name();
1040 p.setEncoding(enc->iconvName());
1046 else if (name == "srcltx") {
1047 h_output_sync = "1";
1048 if (!opts.empty()) {
1049 h_output_sync_macro = "\\usepackage[" + opts + "]{srcltx}";
1052 h_output_sync_macro = "\\usepackage{srcltx}";
1055 else if (is_known(name, known_old_language_packages)) {
1056 // known language packages from the times before babel
1057 // if they are found and not also babel, they will be used as
1058 // custom language package
1059 h_language_package = "\\usepackage{" + name + "}";
1062 else if (name == "lyxskak") {
1063 // ignore this and its options
1064 const char * const o[] = {"ps", "mover", 0};
1065 delete_opt(options, o);
1068 else if (is_known(name, known_lyx_packages) && options.empty()) {
1069 if (name == "splitidx")
1070 h_use_indices = "true";
1071 else if (name == "minted")
1072 h_use_minted = true;
1073 else if (name == "refstyle")
1074 h_use_refstyle = true;
1075 else if (name == "prettyref")
1076 h_use_refstyle = false;
1077 if (!in_lyx_preamble) {
1078 h_preamble << package_beg_sep << name
1079 << package_mid_sep << "\\usepackage{"
1081 if (p.next_token().cat() == catNewline ||
1082 (p.next_token().cat() == catSpace &&
1083 p.next_next_token().cat() == catNewline))
1085 h_preamble << package_end_sep;
1089 else if (name == "geometry")
1090 handle_geometry(options);
1092 else if (name == "subfig")
1093 ; // ignore this FIXME: Use the package separator mechanism instead
1095 else if (char const * const * where = is_known(name, known_languages))
1096 h_language = known_coded_languages[where - known_languages];
1098 else if (name == "natbib") {
1099 h_biblio_style = "plainnat";
1100 h_cite_engine = "natbib";
1101 h_cite_engine_type = "authoryear";
1102 vector<string>::iterator it =
1103 find(options.begin(), options.end(), "authoryear");
1104 if (it != options.end())
1107 it = find(options.begin(), options.end(), "numbers");
1108 if (it != options.end()) {
1109 h_cite_engine_type = "numerical";
1113 if (!options.empty())
1114 h_biblio_options = join(options, ",");
1117 else if (name == "biblatex") {
1118 h_biblio_style = "plainnat";
1119 h_cite_engine = "biblatex";
1120 h_cite_engine_type = "authoryear";
1122 vector<string>::iterator it =
1123 find(options.begin(), options.end(), "natbib");
1124 if (it != options.end()) {
1126 h_cite_engine = "biblatex-natbib";
1128 opt = process_keyval_opt(options, "natbib");
1130 h_cite_engine = "biblatex-natbib";
1132 opt = process_keyval_opt(options, "style");
1134 h_biblatex_citestyle = opt;
1135 h_biblatex_bibstyle = opt;
1137 opt = process_keyval_opt(options, "citestyle");
1139 h_biblatex_citestyle = opt;
1140 opt = process_keyval_opt(options, "bibstyle");
1142 h_biblatex_bibstyle = opt;
1144 opt = process_keyval_opt(options, "refsection");
1146 if (opt == "none" || opt == "part"
1147 || opt == "chapter" || opt == "section"
1148 || opt == "subsection")
1151 cerr << "Ignoring unkown refesection value '"
1154 if (!options.empty()) {
1155 h_biblio_options = join(options, ",");
1160 else if (name == "jurabib") {
1161 h_biblio_style = "jurabib";
1162 h_cite_engine = "jurabib";
1163 h_cite_engine_type = "authoryear";
1164 if (!options.empty())
1165 h_biblio_options = join(options, ",");
1168 else if (name == "bibtopic")
1169 h_use_bibtopic = "true";
1171 else if (name == "chapterbib")
1172 h_multibib = "child";
1174 else if (name == "hyperref")
1175 handle_hyperref(options);
1177 else if (name == "algorithm2e") {
1178 // Load "algorithm2e" module
1179 addModule("algorithm2e");
1180 // Add the package options to the global document options
1181 if (!options.empty()) {
1182 if (h_options.empty())
1183 h_options = join(options, ",");
1185 h_options += ',' + join(options, ",");
1188 else if (name == "microtype") {
1189 //we internally support only microtype without params
1190 if (options.empty())
1191 h_use_microtype = "true";
1193 h_preamble << "\\usepackage[" << opts << "]{microtype}";
1196 else if (!in_lyx_preamble) {
1197 if (options.empty())
1198 h_preamble << "\\usepackage{" << name << '}';
1200 h_preamble << "\\usepackage[" << opts << "]{"
1204 if (p.next_token().cat() == catNewline ||
1205 (p.next_token().cat() == catSpace &&
1206 p.next_next_token().cat() == catNewline))
1210 // We need to do something with the options...
1211 if (!options.empty() && !detectEncoding)
1212 cerr << "Ignoring options '" << join(options, ",")
1213 << "' of package " << name << '.' << endl;
1215 // remove the whitespace
1220 void Preamble::handle_if(Parser & p, bool in_lyx_preamble)
1223 Token t = p.get_token();
1224 if (t.cat() == catEscape &&
1225 is_known(t.cs(), known_if_commands))
1226 handle_if(p, in_lyx_preamble);
1228 if (!in_lyx_preamble)
1229 h_preamble << t.asInput();
1230 if (t.cat() == catEscape && t.cs() == "fi")
1237 bool Preamble::writeLyXHeader(ostream & os, bool subdoc, string const & outfiledir)
1239 if (contains(h_float_placement, "H"))
1240 registerAutomaticallyLoadedPackage("float");
1241 if (h_spacing != "single" && h_spacing != "default")
1242 registerAutomaticallyLoadedPackage("setspace");
1243 if (h_use_packages["amsmath"] == "2") {
1244 // amsbsy and amstext are already provided by amsmath
1245 registerAutomaticallyLoadedPackage("amsbsy");
1246 registerAutomaticallyLoadedPackage("amstext");
1249 // output the LyX file settings
1250 // Important: Keep the version formatting in sync with LyX and
1251 // lyx2lyx (bug 7951)
1252 string const origin = roundtripMode() ? "roundtrip" : outfiledir;
1253 os << "#LyX file created by tex2lyx " << lyx_version_major << '.'
1254 << lyx_version_minor << '\n'
1255 << "\\lyxformat " << LYX_FORMAT << '\n'
1256 << "\\begin_document\n"
1257 << "\\begin_header\n"
1258 << "\\save_transient_properties " << h_save_transient_properties << "\n"
1259 << "\\origin " << origin << "\n"
1260 << "\\textclass " << h_textclass << "\n";
1261 string const raw = subdoc ? empty_string() : h_preamble.str();
1263 os << "\\begin_preamble\n";
1264 for (string::size_type i = 0; i < raw.size(); ++i) {
1265 if (raw[i] == package_beg_sep) {
1266 // Here follows some package loading code that
1267 // must be skipped if the package is loaded
1269 string::size_type j = raw.find(package_mid_sep, i);
1270 if (j == string::npos)
1272 string::size_type k = raw.find(package_end_sep, j);
1273 if (k == string::npos)
1275 string const package = raw.substr(i + 1, j - i - 1);
1276 string const replacement = raw.substr(j + 1, k - j - 1);
1277 if (auto_packages.find(package) == auto_packages.end())
1283 os << "\n\\end_preamble\n";
1285 if (!h_options.empty())
1286 os << "\\options " << h_options << "\n";
1287 os << "\\use_default_options " << h_use_default_options << "\n";
1288 if (!used_modules.empty()) {
1289 os << "\\begin_modules\n";
1290 vector<string>::const_iterator const end = used_modules.end();
1291 vector<string>::const_iterator it = used_modules.begin();
1292 for (; it != end; ++it)
1294 os << "\\end_modules\n";
1296 if (!h_includeonlys.empty()) {
1297 os << "\\begin_includeonly\n";
1298 for (auto const & iofile : h_includeonlys)
1299 os << iofile << '\n';
1300 os << "\\end_includeonly\n";
1302 os << "\\maintain_unincluded_children " << h_maintain_unincluded_children << "\n"
1303 << "\\language " << h_language << "\n"
1304 << "\\language_package " << h_language_package << "\n"
1305 << "\\inputencoding " << h_inputencoding << "\n"
1306 << "\\fontencoding " << h_fontencoding << "\n"
1307 << "\\font_roman \"" << h_font_roman[0]
1308 << "\" \"" << h_font_roman[1] << "\"\n"
1309 << "\\font_sans \"" << h_font_sans[0] << "\" \"" << h_font_sans[1] << "\"\n"
1310 << "\\font_typewriter \"" << h_font_typewriter[0]
1311 << "\" \"" << h_font_typewriter[1] << "\"\n"
1312 << "\\font_math \"" << h_font_math[0] << "\" \"" << h_font_math[1] << "\"\n"
1313 << "\\font_default_family " << h_font_default_family << "\n"
1314 << "\\use_non_tex_fonts " << (h_use_non_tex_fonts ? "true" : "false") << '\n'
1315 << "\\font_sc " << h_font_sc << "\n"
1316 << "\\font_osf " << h_font_osf << "\n"
1317 << "\\font_sf_scale " << h_font_sf_scale[0]
1318 << ' ' << h_font_sf_scale[1] << '\n'
1319 << "\\font_tt_scale " << h_font_tt_scale[0]
1320 << ' ' << h_font_tt_scale[1] << '\n';
1321 if (!h_font_cjk.empty())
1322 os << "\\font_cjk " << h_font_cjk << '\n';
1323 os << "\\use_microtype " << h_use_microtype << '\n'
1324 << "\\use_dash_ligatures " << h_use_dash_ligatures << '\n'
1325 << "\\graphics " << h_graphics << '\n'
1326 << "\\default_output_format " << h_default_output_format << "\n"
1327 << "\\output_sync " << h_output_sync << "\n";
1328 if (h_output_sync == "1")
1329 os << "\\output_sync_macro \"" << h_output_sync_macro << "\"\n";
1330 os << "\\bibtex_command " << h_bibtex_command << "\n"
1331 << "\\index_command " << h_index_command << "\n";
1332 if (!h_float_placement.empty())
1333 os << "\\float_placement " << h_float_placement << "\n";
1334 os << "\\paperfontsize " << h_paperfontsize << "\n"
1335 << "\\spacing " << h_spacing << "\n"
1336 << "\\use_hyperref " << h_use_hyperref << '\n';
1337 if (h_use_hyperref == "true") {
1338 if (!h_pdf_title.empty())
1339 os << "\\pdf_title " << Lexer::quoteString(h_pdf_title) << '\n';
1340 if (!h_pdf_author.empty())
1341 os << "\\pdf_author " << Lexer::quoteString(h_pdf_author) << '\n';
1342 if (!h_pdf_subject.empty())
1343 os << "\\pdf_subject " << Lexer::quoteString(h_pdf_subject) << '\n';
1344 if (!h_pdf_keywords.empty())
1345 os << "\\pdf_keywords " << Lexer::quoteString(h_pdf_keywords) << '\n';
1346 os << "\\pdf_bookmarks " << h_pdf_bookmarks << "\n"
1347 "\\pdf_bookmarksnumbered " << h_pdf_bookmarksnumbered << "\n"
1348 "\\pdf_bookmarksopen " << h_pdf_bookmarksopen << "\n"
1349 "\\pdf_bookmarksopenlevel " << h_pdf_bookmarksopenlevel << "\n"
1350 "\\pdf_breaklinks " << h_pdf_breaklinks << "\n"
1351 "\\pdf_pdfborder " << h_pdf_pdfborder << "\n"
1352 "\\pdf_colorlinks " << h_pdf_colorlinks << "\n"
1353 "\\pdf_backref " << h_pdf_backref << "\n"
1354 "\\pdf_pdfusetitle " << h_pdf_pdfusetitle << '\n';
1355 if (!h_pdf_pagemode.empty())
1356 os << "\\pdf_pagemode " << h_pdf_pagemode << '\n';
1357 if (!h_pdf_quoted_options.empty())
1358 os << "\\pdf_quoted_options " << Lexer::quoteString(h_pdf_quoted_options) << '\n';
1360 os << "\\papersize " << h_papersize << "\n"
1361 << "\\use_geometry " << h_use_geometry << '\n';
1362 for (map<string, string>::const_iterator it = h_use_packages.begin();
1363 it != h_use_packages.end(); ++it)
1364 os << "\\use_package " << it->first << ' ' << it->second << '\n';
1365 os << "\\cite_engine " << h_cite_engine << '\n'
1366 << "\\cite_engine_type " << h_cite_engine_type << '\n'
1367 << "\\biblio_style " << h_biblio_style << "\n"
1368 << "\\use_bibtopic " << h_use_bibtopic << "\n";
1369 if (!h_biblio_options.empty())
1370 os << "\\biblio_options " << h_biblio_options << "\n";
1371 if (!h_biblatex_bibstyle.empty())
1372 os << "\\biblatex_bibstyle " << h_biblatex_bibstyle << "\n";
1373 if (!h_biblatex_citestyle.empty())
1374 os << "\\biblatex_citestyle " << h_biblatex_citestyle << "\n";
1375 if (!h_multibib.empty())
1376 os << "\\multibib " << h_multibib << "\n";
1377 os << "\\use_indices " << h_use_indices << "\n"
1378 << "\\paperorientation " << h_paperorientation << '\n'
1379 << "\\suppress_date " << h_suppress_date << '\n'
1380 << "\\justification " << h_justification << '\n'
1381 << "\\use_refstyle " << h_use_refstyle << '\n'
1382 << "\\use_minted " << h_use_minted << '\n';
1383 if (!h_fontcolor.empty())
1384 os << "\\fontcolor " << h_fontcolor << '\n';
1385 if (!h_notefontcolor.empty())
1386 os << "\\notefontcolor " << h_notefontcolor << '\n';
1387 if (!h_backgroundcolor.empty())
1388 os << "\\backgroundcolor " << h_backgroundcolor << '\n';
1389 if (!h_boxbgcolor.empty())
1390 os << "\\boxbgcolor " << h_boxbgcolor << '\n';
1391 if (index_number != 0)
1392 for (int i = 0; i < index_number; i++) {
1393 os << "\\index " << h_index[i] << '\n'
1394 << "\\shortcut " << h_shortcut[i] << '\n'
1395 << "\\color " << h_color << '\n'
1399 os << "\\index " << h_index[0] << '\n'
1400 << "\\shortcut " << h_shortcut[0] << '\n'
1401 << "\\color " << h_color << '\n'
1405 << "\\secnumdepth " << h_secnumdepth << "\n"
1406 << "\\tocdepth " << h_tocdepth << "\n"
1407 << "\\paragraph_separation " << h_paragraph_separation << "\n";
1408 if (h_paragraph_separation == "skip")
1409 os << "\\defskip " << h_defskip << "\n";
1411 os << "\\paragraph_indentation " << h_paragraph_indentation << "\n";
1412 os << "\\is_math_indent " << h_is_mathindent << "\n";
1413 if (!h_mathindentation.empty())
1414 os << "\\math_indentation " << h_mathindentation << "\n";
1415 os << "\\math_numbering_side " << h_math_numbering_side << "\n";
1416 os << "\\quotes_style " << h_quotes_style << "\n"
1417 << "\\dynamic_quotes " << h_dynamic_quotes << "\n"
1418 << "\\papercolumns " << h_papercolumns << "\n"
1419 << "\\papersides " << h_papersides << "\n"
1420 << "\\paperpagestyle " << h_paperpagestyle << "\n";
1421 if (!h_listings_params.empty())
1422 os << "\\listings_params " << h_listings_params << "\n";
1423 os << "\\tracking_changes " << h_tracking_changes << "\n"
1424 << "\\output_changes " << h_output_changes << "\n"
1425 << "\\html_math_output " << h_html_math_output << "\n"
1426 << "\\html_css_as_file " << h_html_css_as_file << "\n"
1427 << "\\html_be_strict " << h_html_be_strict << "\n"
1429 << "\\end_header\n\n"
1430 << "\\begin_body\n";
1435 void Preamble::parse(Parser & p, string const & forceclass,
1436 TeX2LyXDocClass & tc)
1438 // initialize fixed types
1439 special_columns_['D'] = 3;
1440 parse(p, forceclass, false, tc);
1444 void Preamble::parse(Parser & p, string const & forceclass,
1445 bool detectEncoding, TeX2LyXDocClass & tc)
1447 bool is_full_document = false;
1448 bool is_lyx_file = false;
1449 bool in_lyx_preamble = false;
1451 // determine whether this is a full document or a fragment for inclusion
1453 Token const & t = p.get_token();
1455 if (t.cat() == catEscape && t.cs() == "documentclass") {
1456 is_full_document = true;
1462 if (detectEncoding && !is_full_document)
1465 while (is_full_document && p.good()) {
1466 if (detectEncoding && h_inputencoding != "auto" &&
1467 h_inputencoding != "default")
1470 Token const & t = p.get_token();
1473 if (!detectEncoding)
1474 cerr << "t: " << t << '\n';
1480 if (!in_lyx_preamble &&
1481 (t.cat() == catLetter ||
1482 t.cat() == catSuper ||
1483 t.cat() == catSub ||
1484 t.cat() == catOther ||
1485 t.cat() == catMath ||
1486 t.cat() == catActive ||
1487 t.cat() == catBegin ||
1488 t.cat() == catEnd ||
1489 t.cat() == catAlign ||
1490 t.cat() == catParameter)) {
1491 h_preamble << t.cs();
1495 if (!in_lyx_preamble &&
1496 (t.cat() == catSpace || t.cat() == catNewline)) {
1497 h_preamble << t.asInput();
1501 if (t.cat() == catComment) {
1502 static regex const islyxfile("%% LyX .* created this file");
1503 static regex const usercommands("User specified LaTeX commands");
1505 string const comment = t.asInput();
1507 // magically switch encoding default if it looks like XeLaTeX
1508 static string const magicXeLaTeX =
1509 "% This document must be compiled with XeLaTeX ";
1510 if (comment.size() > magicXeLaTeX.size()
1511 && comment.substr(0, magicXeLaTeX.size()) == magicXeLaTeX
1512 && h_inputencoding == "auto") {
1513 if (!detectEncoding)
1514 cerr << "XeLaTeX comment found, switching to UTF8\n";
1515 h_inputencoding = "utf8";
1518 if (regex_search(comment, sub, islyxfile)) {
1520 in_lyx_preamble = true;
1521 } else if (is_lyx_file
1522 && regex_search(comment, sub, usercommands))
1523 in_lyx_preamble = false;
1524 else if (!in_lyx_preamble)
1525 h_preamble << t.asInput();
1529 if (t.cs() == "PassOptionsToPackage") {
1530 string const poptions = p.getArg('{', '}');
1531 string const package = p.verbatim_item();
1532 extra_package_options_.insert(make_pair(package, poptions));
1536 if (t.cs() == "pagestyle") {
1537 h_paperpagestyle = p.verbatim_item();
1541 if (t.cs() == "setdefaultlanguage") {
1543 // We don't yet care about non-language variant options
1544 // because LyX doesn't support this yet, see bug #8214
1546 string langopts = p.getOpt();
1547 // check if the option contains a variant, if yes, extract it
1548 string::size_type pos_var = langopts.find("variant");
1549 string::size_type i = langopts.find(',', pos_var);
1550 string::size_type k = langopts.find('=', pos_var);
1551 if (pos_var != string::npos){
1553 if (i == string::npos)
1554 variant = langopts.substr(k + 1, langopts.length() - k - 2);
1556 variant = langopts.substr(k + 1, i - k - 1);
1557 h_language = variant;
1561 h_language = p.verbatim_item();
1562 //finally translate the poyglossia name to a LyX name
1563 h_language = polyglossia2lyx(h_language);
1567 if (t.cs() == "setotherlanguage") {
1568 // We don't yet care about the option because LyX doesn't
1569 // support this yet, see bug #8214
1570 p.hasOpt() ? p.getOpt() : string();
1575 if (t.cs() == "setmainfont") {
1576 // we don't care about the option
1577 p.hasOpt() ? p.getOpt() : string();
1578 h_font_roman[1] = p.getArg('{', '}');
1582 if (t.cs() == "setsansfont" || t.cs() == "setmonofont") {
1583 // LyX currently only supports the scale option
1586 string fontopts = p.getArg('[', ']');
1587 // check if the option contains a scaling, if yes, extract it
1588 string::size_type pos = fontopts.find("Scale");
1589 if (pos != string::npos) {
1590 string::size_type i = fontopts.find(',', pos);
1591 if (i == string::npos)
1592 scale_as_percentage(fontopts.substr(pos + 1), scale);
1594 scale_as_percentage(fontopts.substr(pos, i - pos), scale);
1597 if (t.cs() == "setsansfont") {
1599 h_font_sf_scale[1] = scale;
1600 h_font_sans[1] = p.getArg('{', '}');
1603 h_font_tt_scale[1] = scale;
1604 h_font_typewriter[1] = p.getArg('{', '}');
1609 if (t.cs() == "date") {
1610 string argument = p.getArg('{', '}');
1611 if (argument.empty())
1612 h_suppress_date = "true";
1614 h_preamble << t.asInput() << '{' << argument << '}';
1618 if (t.cs() == "color") {
1619 string const space =
1620 (p.hasOpt() ? p.getOpt() : string());
1621 string argument = p.getArg('{', '}');
1622 // check the case that a standard color is used
1623 if (space.empty() && is_known(argument, known_basic_colors)) {
1624 h_fontcolor = rgbcolor2code(argument);
1625 registerAutomaticallyLoadedPackage("color");
1626 } else if (space.empty() && argument == "document_fontcolor")
1627 registerAutomaticallyLoadedPackage("color");
1628 // check the case that LyX's document_fontcolor is defined
1629 // but not used for \color
1631 h_preamble << t.asInput();
1633 h_preamble << space;
1634 h_preamble << '{' << argument << '}';
1635 // the color might already be set because \definecolor
1636 // is parsed before this
1642 if (t.cs() == "pagecolor") {
1643 string argument = p.getArg('{', '}');
1644 // check the case that a standard color is used
1645 if (is_known(argument, known_basic_colors)) {
1646 h_backgroundcolor = rgbcolor2code(argument);
1647 } else if (argument == "page_backgroundcolor")
1648 registerAutomaticallyLoadedPackage("color");
1649 // check the case that LyX's page_backgroundcolor is defined
1650 // but not used for \pagecolor
1652 h_preamble << t.asInput() << '{' << argument << '}';
1653 // the color might already be set because \definecolor
1654 // is parsed before this
1655 h_backgroundcolor = "";
1660 if (t.cs() == "makeatletter") {
1661 // LyX takes care of this
1662 p.setCatcode('@', catLetter);
1666 if (t.cs() == "makeatother") {
1667 // LyX takes care of this
1668 p.setCatcode('@', catOther);
1672 if (t.cs() == "makeindex") {
1673 // LyX will re-add this if a print index command is found
1678 if (t.cs() == "newindex") {
1679 string const indexname = p.getArg('[', ']');
1680 string const shortcut = p.verbatim_item();
1681 if (!indexname.empty())
1682 h_index[index_number] = indexname;
1684 h_index[index_number] = shortcut;
1685 h_shortcut[index_number] = shortcut;
1691 if (t.cs() == "addbibresource") {
1692 biblatex_bibliographies.push_back(removeExtension(p.getArg('{', '}')));
1696 if (t.cs() == "bibliography") {
1697 vector<string> bibs = getVectorFromString(p.getArg('{', '}'));
1698 biblatex_bibliographies.insert(biblatex_bibliographies.end(), bibs.begin(), bibs.end());
1702 if (t.cs() == "RS@ifundefined") {
1703 string const name = p.verbatim_item();
1704 string const body1 = p.verbatim_item();
1705 string const body2 = p.verbatim_item();
1706 // only non-lyxspecific stuff
1707 if (in_lyx_preamble &&
1708 (name == "subsecref" || name == "thmref" || name == "lemref"))
1712 ss << '\\' << t.cs();
1713 ss << '{' << name << '}'
1714 << '{' << body1 << '}'
1715 << '{' << body2 << '}';
1716 h_preamble << ss.str();
1721 if (t.cs() == "AtBeginDocument") {
1722 string const name = p.verbatim_item();
1723 // only non-lyxspecific stuff
1724 if (in_lyx_preamble &&
1725 (name == "\\providecommand\\partref[1]{\\ref{part:#1}}"
1726 || name == "\\providecommand\\chapref[1]{\\ref{chap:#1}}"
1727 || name == "\\providecommand\\secref[1]{\\ref{sec:#1}}"
1728 || name == "\\providecommand\\subsecref[1]{\\ref{subsec:#1}}"
1729 || name == "\\providecommand\\parref[1]{\\ref{par:#1}}"
1730 || name == "\\providecommand\\figref[1]{\\ref{fig:#1}}"
1731 || name == "\\providecommand\\tabref[1]{\\ref{tab:#1}}"
1732 || name == "\\providecommand\\algref[1]{\\ref{alg:#1}}"
1733 || name == "\\providecommand\\fnref[1]{\\ref{fn:#1}}"
1734 || name == "\\providecommand\\enuref[1]{\\ref{enu:#1}}"
1735 || name == "\\providecommand\\eqref[1]{\\ref{eq:#1}}"
1736 || name == "\\providecommand\\lemref[1]{\\ref{lem:#1}}"
1737 || name == "\\providecommand\\thmref[1]{\\ref{thm:#1}}"
1738 || name == "\\providecommand\\corref[1]{\\ref{cor:#1}}"
1739 || name == "\\providecommand\\propref[1]{\\ref{prop:#1}}"))
1743 ss << '\\' << t.cs();
1744 ss << '{' << name << '}';
1745 h_preamble << ss.str();
1750 if (t.cs() == "newcommand" || t.cs() == "newcommandx"
1751 || t.cs() == "renewcommand" || t.cs() == "renewcommandx"
1752 || t.cs() == "providecommand" || t.cs() == "providecommandx"
1753 || t.cs() == "DeclareRobustCommand"
1754 || t.cs() == "DeclareRobustCommandx"
1755 || t.cs() == "ProvideTextCommandDefault"
1756 || t.cs() == "DeclareMathAccent") {
1758 if (p.next_token().character() == '*') {
1762 string const name = p.verbatim_item();
1763 string const opt1 = p.getFullOpt();
1764 string const opt2 = p.getFullOpt();
1765 string const body = p.verbatim_item();
1766 // store the in_lyx_preamble setting
1767 bool const was_in_lyx_preamble = in_lyx_preamble;
1769 if (name == "\\rmdefault")
1770 if (is_known(body, known_roman_fonts)) {
1771 h_font_roman[0] = body;
1773 in_lyx_preamble = true;
1775 if (name == "\\sfdefault")
1776 if (is_known(body, known_sans_fonts)) {
1777 h_font_sans[0] = body;
1779 in_lyx_preamble = true;
1781 if (name == "\\ttdefault")
1782 if (is_known(body, known_typewriter_fonts)) {
1783 h_font_typewriter[0] = body;
1785 in_lyx_preamble = true;
1787 if (name == "\\familydefault") {
1788 string family = body;
1789 // remove leading "\"
1790 h_font_default_family = family.erase(0,1);
1792 in_lyx_preamble = true;
1795 // remove LyX-specific definitions that are re-added by LyX
1797 // \lyxline is an ancient command that is converted by tex2lyx into
1798 // a \rule therefore remove its preamble code
1799 if (name == "\\lyxdot" || name == "\\lyxarrow"
1800 || name == "\\lyxline" || name == "\\LyX") {
1802 in_lyx_preamble = true;
1805 // Add the command to the known commands
1806 add_known_command(name, opt1, !opt2.empty(), from_utf8(body));
1808 // only non-lyxspecific stuff
1809 if (!in_lyx_preamble) {
1811 ss << '\\' << t.cs();
1814 ss << '{' << name << '}' << opt1 << opt2
1815 << '{' << body << "}";
1816 h_preamble << ss.str();
1818 ostream & out = in_preamble ? h_preamble : os;
1819 out << "\\" << t.cs() << "{" << name << "}"
1820 << opts << "{" << body << "}";
1823 // restore the in_lyx_preamble setting
1824 in_lyx_preamble = was_in_lyx_preamble;
1828 if (t.cs() == "documentclass") {
1829 vector<string>::iterator it;
1830 vector<string> opts = split_options(p.getArg('[', ']'));
1831 handle_opt(opts, known_fontsizes, h_paperfontsize);
1832 delete_opt(opts, known_fontsizes);
1833 // delete "pt" at the end
1834 string::size_type i = h_paperfontsize.find("pt");
1835 if (i != string::npos)
1836 h_paperfontsize.erase(i);
1837 // The documentclass options are always parsed before the options
1838 // of the babel call so that a language cannot overwrite the babel
1840 handle_opt(opts, known_languages, h_language);
1841 delete_opt(opts, known_languages);
1844 if ((it = find(opts.begin(), opts.end(), "fleqn"))
1846 h_is_mathindent = "1";
1849 // formula numbering side
1850 if ((it = find(opts.begin(), opts.end(), "leqno"))
1852 h_math_numbering_side = "left";
1855 else if ((it = find(opts.begin(), opts.end(), "reqno"))
1857 h_math_numbering_side = "right";
1861 // paper orientation
1862 if ((it = find(opts.begin(), opts.end(), "landscape")) != opts.end()) {
1863 h_paperorientation = "landscape";
1867 if ((it = find(opts.begin(), opts.end(), "oneside"))
1872 if ((it = find(opts.begin(), opts.end(), "twoside"))
1878 if ((it = find(opts.begin(), opts.end(), "onecolumn"))
1880 h_papercolumns = "1";
1883 if ((it = find(opts.begin(), opts.end(), "twocolumn"))
1885 h_papercolumns = "2";
1889 // some size options are known to any document classes, other sizes
1890 // are handled by the \geometry command of the geometry package
1891 handle_opt(opts, known_class_paper_sizes, h_papersize);
1892 delete_opt(opts, known_class_paper_sizes);
1893 // the remaining options
1894 h_options = join(opts, ",");
1895 // FIXME This does not work for classes that have a
1896 // different name in LyX than in LaTeX
1897 h_textclass = p.getArg('{', '}');
1902 if (t.cs() == "usepackage") {
1903 string const options = p.getArg('[', ']');
1904 string const name = p.getArg('{', '}');
1905 vector<string> vecnames;
1906 split(name, vecnames, ',');
1907 vector<string>::const_iterator it = vecnames.begin();
1908 vector<string>::const_iterator end = vecnames.end();
1909 for (; it != end; ++it)
1910 handle_package(p, trimSpaceAndEol(*it), options,
1911 in_lyx_preamble, detectEncoding);
1915 if (t.cs() == "inputencoding") {
1916 string const encoding = p.getArg('{','}');
1917 Encoding const * const enc = encodings.fromLaTeXName(
1918 encoding, Encoding::inputenc, true);
1920 if (!detectEncoding)
1921 cerr << "Unknown encoding " << encoding
1922 << ". Ignoring." << std::endl;
1925 h_inputencoding = enc->name();
1926 p.setEncoding(enc->iconvName());
1931 if (t.cs() == "newenvironment") {
1932 string const name = p.getArg('{', '}');
1933 string const opt1 = p.getFullOpt();
1934 string const opt2 = p.getFullOpt();
1935 string const beg = p.verbatim_item();
1936 string const end = p.verbatim_item();
1937 if (!in_lyx_preamble) {
1938 h_preamble << "\\newenvironment{" << name
1939 << '}' << opt1 << opt2 << '{'
1940 << beg << "}{" << end << '}';
1942 add_known_environment(name, opt1, !opt2.empty(),
1943 from_utf8(beg), from_utf8(end));
1947 if (t.cs() == "newtheorem") {
1949 if (p.next_token().character() == '*') {
1953 string const name = p.getArg('{', '}');
1954 string const opt1 = p.getFullOpt();
1955 string const opt2 = p.getFullOpt();
1956 string const body = p.verbatim_item();
1957 string const opt3 = p.getFullOpt();
1958 string const cmd = star ? "\\newtheorem*" : "\\newtheorem";
1960 string const complete = cmd + "{" + name + '}' +
1961 opt1 + opt2 + '{' + body + '}' + opt3;
1963 add_known_theorem(name, opt1, !opt2.empty(), from_utf8(complete));
1965 if (!in_lyx_preamble)
1966 h_preamble << complete;
1970 if (t.cs() == "def") {
1971 string name = p.get_token().cs();
1972 // In fact, name may be more than the name:
1973 // In the test case of bug 8116
1974 // name == "csname SF@gobble@opt \endcsname".
1975 // Therefore, we need to use asInput() instead of cs().
1976 while (p.next_token().cat() != catBegin)
1977 name += p.get_token().asInput();
1978 if (!in_lyx_preamble)
1979 h_preamble << "\\def\\" << name << '{'
1980 << p.verbatim_item() << "}";
1984 if (t.cs() == "newcolumntype") {
1985 string const name = p.getArg('{', '}');
1986 trimSpaceAndEol(name);
1988 string opts = p.getOpt();
1989 if (!opts.empty()) {
1990 istringstream is(string(opts, 1));
1993 special_columns_[name[0]] = nargs;
1994 h_preamble << "\\newcolumntype{" << name << "}";
1996 h_preamble << "[" << nargs << "]";
1997 h_preamble << "{" << p.verbatim_item() << "}";
2001 if (t.cs() == "setcounter") {
2002 string const name = p.getArg('{', '}');
2003 string const content = p.getArg('{', '}');
2004 if (name == "secnumdepth")
2005 h_secnumdepth = content;
2006 else if (name == "tocdepth")
2007 h_tocdepth = content;
2009 h_preamble << "\\setcounter{" << name << "}{" << content << "}";
2013 if (t.cs() == "setlength") {
2014 string const name = p.verbatim_item();
2015 string const content = p.verbatim_item();
2016 // the paragraphs are only not indented when \parindent is set to zero
2017 if (name == "\\parindent" && content != "") {
2018 if (content[0] == '0')
2019 h_paragraph_separation = "skip";
2021 h_paragraph_indentation = translate_len(content);
2022 } else if (name == "\\parskip") {
2023 if (content == "\\smallskipamount")
2024 h_defskip = "smallskip";
2025 else if (content == "\\medskipamount")
2026 h_defskip = "medskip";
2027 else if (content == "\\bigskipamount")
2028 h_defskip = "bigskip";
2030 h_defskip = translate_len(content);
2031 } else if (name == "\\mathindent") {
2032 h_mathindentation = translate_len(content);
2034 h_preamble << "\\setlength{" << name << "}{" << content << "}";
2038 if (t.cs() == "onehalfspacing") {
2039 h_spacing = "onehalf";
2043 if (t.cs() == "doublespacing") {
2044 h_spacing = "double";
2048 if (t.cs() == "setstretch") {
2049 h_spacing = "other " + p.verbatim_item();
2053 if (t.cs() == "synctex") {
2054 // the scheme is \synctex=value
2055 // where value can only be "1" or "-1"
2056 h_output_sync = "1";
2057 // there can be any character behind the value (e.g. a linebreak or a '\'
2058 // therefore we extract it char by char
2060 string value = p.get_token().asInput();
2062 value += p.get_token().asInput();
2063 h_output_sync_macro = "\\synctex=" + value;
2067 if (t.cs() == "begin") {
2068 string const name = p.getArg('{', '}');
2069 if (name == "document")
2071 h_preamble << "\\begin{" << name << "}";
2075 if (t.cs() == "geometry") {
2076 vector<string> opts = split_options(p.getArg('{', '}'));
2077 handle_geometry(opts);
2081 if (t.cs() == "definecolor") {
2082 string const color = p.getArg('{', '}');
2083 string const space = p.getArg('{', '}');
2084 string const value = p.getArg('{', '}');
2085 if (color == "document_fontcolor" && space == "rgb") {
2086 RGBColor c(RGBColorFromLaTeX(value));
2087 h_fontcolor = X11hexname(c);
2088 } else if (color == "note_fontcolor" && space == "rgb") {
2089 RGBColor c(RGBColorFromLaTeX(value));
2090 h_notefontcolor = X11hexname(c);
2091 } else if (color == "page_backgroundcolor" && space == "rgb") {
2092 RGBColor c(RGBColorFromLaTeX(value));
2093 h_backgroundcolor = X11hexname(c);
2094 } else if (color == "shadecolor" && space == "rgb") {
2095 RGBColor c(RGBColorFromLaTeX(value));
2096 h_boxbgcolor = X11hexname(c);
2098 h_preamble << "\\definecolor{" << color
2099 << "}{" << space << "}{" << value
2105 if (t.cs() == "bibliographystyle") {
2106 h_biblio_style = p.verbatim_item();
2110 if (t.cs() == "jurabibsetup") {
2111 // FIXME p.getArg('{', '}') is most probably wrong (it
2112 // does not handle nested braces).
2113 // Use p.verbatim_item() instead.
2114 vector<string> jurabibsetup =
2115 split_options(p.getArg('{', '}'));
2116 // add jurabibsetup to the jurabib package options
2117 add_package("jurabib", jurabibsetup);
2118 if (!jurabibsetup.empty()) {
2119 h_preamble << "\\jurabibsetup{"
2120 << join(jurabibsetup, ",") << '}';
2125 if (t.cs() == "hypersetup") {
2126 vector<string> hypersetup =
2127 split_options(p.verbatim_item());
2128 // add hypersetup to the hyperref package options
2129 handle_hyperref(hypersetup);
2130 if (!hypersetup.empty()) {
2131 h_preamble << "\\hypersetup{"
2132 << join(hypersetup, ",") << '}';
2137 if (t.cs() == "includeonly") {
2138 vector<string> includeonlys = getVectorFromString(p.getArg('{', '}'));
2139 for (auto & iofile : includeonlys) {
2140 string filename(normalize_filename(iofile));
2141 string const path = getMasterFilePath(true);
2142 // We want to preserve relative/absolute filenames,
2143 // therefore path is only used for testing
2144 if (!makeAbsPath(filename, path).exists()) {
2145 // The file extension is probably missing.
2146 // Now try to find it out.
2147 string const tex_name =
2148 find_file(filename, path,
2149 known_tex_extensions);
2150 if (!tex_name.empty())
2151 filename = tex_name;
2154 if (makeAbsPath(filename, path).exists())
2155 fix_child_filename(filename);
2157 cerr << "Warning: Could not find included file '"
2158 << filename << "'." << endl;
2159 outname = changeExtension(filename, "lyx");
2160 h_includeonlys.push_back(outname);
2165 if (is_known(t.cs(), known_if_3arg_commands)) {
2166 // prevent misparsing of \usepackage if it is used
2167 // as an argument (see e.g. our own output of
2168 // \@ifundefined above)
2169 string const arg1 = p.verbatim_item();
2170 string const arg2 = p.verbatim_item();
2171 string const arg3 = p.verbatim_item();
2172 // test case \@ifundefined{date}{}{\date{}}
2173 if (t.cs() == "@ifundefined" && arg1 == "date" &&
2174 arg2.empty() && arg3 == "\\date{}") {
2175 h_suppress_date = "true";
2176 // older tex2lyx versions did output
2177 // \@ifundefined{definecolor}{\usepackage{color}}{}
2178 } else if (t.cs() == "@ifundefined" &&
2179 arg1 == "definecolor" &&
2180 arg2 == "\\usepackage{color}" &&
2182 if (!in_lyx_preamble)
2183 h_preamble << package_beg_sep
2186 << "\\@ifundefined{definecolor}{color}{}"
2189 //\@ifundefined{showcaptionsetup}{}{%
2190 // \PassOptionsToPackage{caption=false}{subfig}}
2191 // that LyX uses for subfloats
2192 } else if (t.cs() == "@ifundefined" &&
2193 arg1 == "showcaptionsetup" && arg2.empty()
2194 && arg3 == "%\n \\PassOptionsToPackage{caption=false}{subfig}") {
2196 } else if (!in_lyx_preamble) {
2197 h_preamble << t.asInput()
2198 << '{' << arg1 << '}'
2199 << '{' << arg2 << '}'
2200 << '{' << arg3 << '}';
2205 if (is_known(t.cs(), known_if_commands)) {
2206 // must not parse anything in conditional code, since
2207 // LyX would output the parsed contents unconditionally
2208 if (!in_lyx_preamble)
2209 h_preamble << t.asInput();
2210 handle_if(p, in_lyx_preamble);
2214 if (!t.cs().empty() && !in_lyx_preamble) {
2215 h_preamble << '\\' << t.cs();
2220 // remove the whitespace
2223 // Force textclass if the user wanted it
2224 if (!forceclass.empty())
2225 h_textclass = forceclass;
2226 tc.setName(h_textclass);
2227 if (!LayoutFileList::get().haveClass(h_textclass) || !tc.load()) {
2228 cerr << "Error: Could not read layout file for textclass \"" << h_textclass << "\"." << endl;
2231 if (h_papersides.empty()) {
2234 h_papersides = ss.str();
2237 // If the CJK package is used we cannot set the document language from
2238 // the babel options. Instead, we guess which language is used most
2239 // and set this one.
2240 default_language = h_language;
2241 if (is_full_document &&
2242 (auto_packages.find("CJK") != auto_packages.end() ||
2243 auto_packages.find("CJKutf8") != auto_packages.end())) {
2245 h_language = guessLanguage(p, default_language);
2247 if (explicit_babel && h_language != default_language) {
2248 // We set the document language to a CJK language,
2249 // but babel is explicitly called in the user preamble
2250 // without options. LyX will not add the default
2251 // language to the document options if it is either
2252 // english, or no text is set as default language.
2253 // Therefore we need to add a language option explicitly.
2254 // FIXME: It would be better to remove all babel calls
2255 // from the user preamble, but this is difficult
2256 // without re-introducing bug 7861.
2257 if (h_options.empty())
2258 h_options = lyx2babel(default_language);
2260 h_options += ',' + lyx2babel(default_language);
2264 // Finally, set the quote style.
2265 // LyX knows the following quotes styles:
2266 // british, cjk, cjkangle, danish, english, french, german,
2267 // polish, russian, swedish and swiss
2268 // conversion list taken from
2269 // https://en.wikipedia.org/wiki/Quotation_mark,_non-English_usage
2270 // (quotes for kazakh are unknown)
2272 if (is_known(h_language, known_british_quotes_languages))
2273 h_quotes_style = "british";
2275 else if (is_known(h_language, known_cjk_quotes_languages))
2276 h_quotes_style = "cjk";
2278 else if (is_known(h_language, known_cjkangle_quotes_languages))
2279 h_quotes_style = "cjkangle";
2281 else if (is_known(h_language, known_danish_quotes_languages))
2282 h_quotes_style = "danish";
2284 else if (is_known(h_language, known_french_quotes_languages))
2285 h_quotes_style = "french";
2287 else if (is_known(h_language, known_german_quotes_languages))
2288 h_quotes_style = "german";
2290 else if (is_known(h_language, known_polish_quotes_languages))
2291 h_quotes_style = "polish";
2293 else if (is_known(h_language, known_russian_quotes_languages))
2294 h_quotes_style = "russian";
2296 else if (is_known(h_language, known_swedish_quotes_languages))
2297 h_quotes_style = "swedish";
2299 else if (is_known(h_language, known_swiss_quotes_languages))
2300 h_quotes_style = "swiss";
2302 else if (is_known(h_language, known_english_quotes_languages))
2303 h_quotes_style = "english";
2307 string Preamble::parseEncoding(Parser & p, string const & forceclass)
2309 TeX2LyXDocClass dummy;
2310 parse(p, forceclass, true, dummy);
2311 if (h_inputencoding != "auto" && h_inputencoding != "default")
2312 return h_inputencoding;
2317 string babel2lyx(string const & language)
2319 char const * const * where = is_known(language, known_languages);
2321 return known_coded_languages[where - known_languages];
2326 string lyx2babel(string const & language)
2328 char const * const * where = is_known(language, known_coded_languages);
2330 return known_languages[where - known_coded_languages];
2335 string Preamble::polyglossia2lyx(string const & language)
2337 char const * const * where = is_known(language, polyglossia_languages);
2339 return coded_polyglossia_languages[where - polyglossia_languages];
2344 string rgbcolor2code(string const & name)
2346 char const * const * where = is_known(name, known_basic_colors);
2348 // "red", "green" etc
2349 return known_basic_color_codes[where - known_basic_colors];
2351 // "255,0,0", "0,255,0" etc
2352 RGBColor c(RGBColorFromLaTeX(name));
2353 return X11hexname(c);