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.
19 #include "LayoutFile.h"
22 #include "TextClass.h"
24 #include "support/convert.h"
25 #include "support/FileName.h"
26 #include "support/filetools.h"
27 #include "support/lstrings.h"
29 #include "support/regex.h"
35 using namespace lyx::support;
40 // special columntypes
41 extern map<char, int> special_columns;
47 //add this to known_languages when updating to lyxformat 266:
48 // "armenian" (needs special handling since not supported by standard babel)
49 //add these to known_languages when updating to lyxformat 268:
50 //"chinese-simplified", "chinese-traditional", "japanese", "korean"
51 // Both changes require first that support for non-babel languages (CJK,
54 * known babel language names (including synonyms)
55 * not in standard babel: arabic, arabtex, armenian, belarusian, serbian-latin, thai
56 * not yet supported by LyX: kurmanji
57 * please keep this in sync with known_coded_languages line by line!
59 const char * const known_languages[] = {"acadian", "afrikaans", "albanian",
60 "american", "arabic", "arabtex", "australian", "austrian", "bahasa", "bahasai",
61 "bahasam", "basque", "belarusian", "brazil", "brazilian", "breton", "british",
62 "bulgarian", "canadian", "canadien", "catalan", "croatian", "czech", "danish",
63 "dutch", "english", "esperanto", "estonian", "farsi", "finnish", "francais",
64 "french", "frenchb", "frenchle", "frenchpro", "galician", "german", "germanb",
65 "greek", "hebrew", "hungarian", "icelandic", "indon", "indonesian", "interlingua",
66 "irish", "italian", "kazakh", "latin", "latvian", "lithuanian", "lowersorbian",
67 "lsorbian", "magyar", "malay", "meyalu", "mongolian", "naustrian", "newzealand",
68 "ngerman", "ngermanb", "norsk", "nynorsk", "polutonikogreek", "polish",
69 "portuges", "portuguese", "romanian", "russian", "russianb", "samin",
70 "scottish", "serbian", "serbian-latin", "slovak", "slovene", "spanish",
71 "swedish", "thai", "turkish", "turkmen", "ukraineb", "ukrainian",
72 "uppersorbian", "UKenglish", "USenglish", "usorbian", "vietnam", "welsh",
76 * the same as known_languages with .lyx names
77 * please keep this in sync with known_languages line by line!
79 const char * const known_coded_languages[] = {"french", "afrikaans", "albanian",
80 "american", "arabic_arabi", "arabic_arabtex", "australian", "austrian", "bahasa", "bahasa",
81 "bahasam", "basque", "belarusian", "brazilian", "brazilian", "breton", "british",
82 "bulgarian", "canadian", "canadien", "catalan", "croatian", "czech", "danish",
83 "dutch", "english", "esperanto", "estonian", "farsi", "finnish", "french",
84 "french", "french", "french", "french", "galician", "german", "german",
85 "greek", "hebrew", "magyar", "icelandic", "bahasa", "bahasa", "interlingua",
86 "irish", "italian", "kazakh", "latin", "latvian", "lithuanian", "lowersorbian",
87 "lowersorbian", "magyar", "bahasam", "bahasam", "mongolian", "naustrian", "newzealand",
88 "ngerman", "ngerman", "norsk", "nynorsk", "polutonikogreek", "polish",
89 "portuguese", "portuguese", "romanian", "russian", "russian", "samin",
90 "scottish", "serbian", "serbian-latin", "slovak", "slovene", "spanish",
91 "swedish", "thai", "turkish", "turkmen", "ukrainian", "ukrainian",
92 "uppersorbian", "uppersorbian", "english", "english", "vietnamese", "welsh",
95 /// languages with english quotes (.lyx names)
96 const char * const known_english_quotes_languages[] = {"american", "australian",
97 "bahasa", "bahasam", "brazilian", "canadian", "chinese-simplified", "english",
98 "esperanto", "hebrew", "irish", "korean", "newzealand", "portuguese", "scottish",
101 /// languages with french quotes (.lyx names)
102 const char * const known_french_quotes_languages[] = {"albanian",
103 "arabic_arabi", "arabic_arabtex", "basque", "canadien", "catalan", "french",
104 "galician", "greek", "italian", "norsk", "nynorsk", "polutonikogreek",
105 "russian", "spanish", "spanish-mexico", "turkish", "turkmen", "ukrainian",
108 /// languages with german quotes (.lyx names)
109 const char * const known_german_quotes_languages[] = {"austrian", "bulgarian",
110 "czech", "german", "icelandic", "lithuanian", "lowersorbian", "naustrian",
111 "ngerman", "serbian", "serbian-latin", "slovak", "slovene", "uppersorbian", 0};
113 /// languages with polish quotes (.lyx names)
114 const char * const known_polish_quotes_languages[] = {"afrikaans", "croatian",
115 "dutch", "estonian", "magyar", "polish", "romanian", 0};
117 /// languages with swedish quotes (.lyx names)
118 const char * const known_swedish_quotes_languages[] = {"finnish",
121 /// known language packages from the times before babel
122 const char * const known_old_language_packages[] = {"french", "frenchle",
123 "frenchpro", "german", "ngerman", "pmfrench", 0};
125 char const * const known_fontsizes[] = { "10pt", "11pt", "12pt", 0 };
127 const char * const known_roman_fonts[] = { "ae", "beraserif", "bookman",
128 "ccfonts", "chancery", "charter", "cmr", "fourier", "lmodern", "mathpazo",
129 "mathptmx", "newcent", "utopia", 0};
131 const char * const known_sans_fonts[] = { "avant", "berasans", "cmbr", "cmss",
132 "helvet", "lmss", 0};
134 const char * const known_typewriter_fonts[] = { "beramono", "cmtl", "cmtt",
135 "courier", "lmtt", "luximono", "fourier", "lmodern", "mathpazo", "mathptmx",
138 const char * const known_paper_sizes[] = { "a0paper", "b0paper", "c0paper",
139 "a1paper", "b1paper", "c1paper", "a2paper", "b2paper", "c2paper", "a3paper",
140 "b3paper", "c3paper", "a4paper", "b4paper", "c4paper", "a5paper", "b5paper",
141 "c5paper", "a6paper", "b6paper", "c6paper", "executivepaper", "legalpaper",
142 "letterpaper", "b0j", "b1j", "b2j", "b3j", "b4j", "b5j", "b6j", 0};
144 const char * const known_class_paper_sizes[] = { "a4paper", "a5paper",
145 "executivepaper", "legalpaper", "letterpaper", 0};
147 const char * const known_paper_margins[] = { "lmargin", "tmargin", "rmargin",
148 "bmargin", "headheight", "headsep", "footskip", "columnsep", 0};
150 const char * const known_coded_paper_margins[] = { "leftmargin", "topmargin",
151 "rightmargin", "bottommargin", "headheight", "headsep", "footskip",
154 /// commands that can start an \if...\else...\endif sequence
155 const char * const known_if_commands[] = {"if", "ifarydshln", "ifbraket",
156 "ifcancel", "ifcolortbl", "ifeurosym", "ifmarginnote", "ifmmode", "ifpdf",
157 "ifsidecap", "ifupgreek", 0};
159 const char * const known_basic_colors[] = {"blue", "black", "cyan", "green",
160 "magenta", "red", "white", "yellow", 0};
162 const char * const known_basic_color_codes[] = {"#0000ff", "#000000", "#00ffff", "#00ff00",
163 "#ff00ff", "#ff0000", "#ffffff", "#ffff00", 0};
165 /// conditional commands with three arguments like \@ifundefined{}{}{}
166 const char * const known_if_3arg_commands[] = {"@ifundefined", "IfFileExists",
169 /// packages that work only in xetex
170 /// polyglossia is handled separately
171 const char * const known_xetex_packages[] = {"arabxetex", "fixlatvian",
172 "fontbook", "fontwrap", "mathspec", "philokalia", "unisugar",
173 "xeCJK", "xecolor", "xecyr", "xeindex", "xepersian", "xunicode", 0};
175 /// packages that are automatically skipped if loaded by LyX
176 const char * const known_lyx_packages[] = {"amsbsy", "amsmath", "amssymb",
177 "amstext", "amsthm", "array", "booktabs", "calc", "color", "float",
178 "graphicx", "hhline", "ifthen", "longtable", "makeidx", "multirow",
179 "nomencl", "pdfpages", "rotating", "rotfloat", "splitidx", "setspace",
180 "subscript", "textcomp", "ulem", "url", "varioref", "verbatim", "wrapfig", 0};
182 // codes used to remove packages that are loaded automatically by LyX.
183 // Syntax: package_beg_sep<name>package_mid_sep<package loading code>package_end_sep
184 const char package_beg_sep = '\001';
185 const char package_mid_sep = '\002';
186 const char package_end_sep = '\003';
189 // returns true if at least one of the options in what has been found
190 bool handle_opt(vector<string> & opts, char const * const * what, string & target)
196 // the last language option is the document language (for babel and LyX)
197 // the last size option is the document font size
198 vector<string>::iterator it;
199 vector<string>::iterator position = opts.begin();
200 for (; *what; ++what) {
201 it = find(opts.begin(), opts.end(), *what);
202 if (it != opts.end()) {
203 if (it >= position) {
214 void delete_opt(vector<string> & opts, char const * const * what)
219 // remove found options from the list
220 // do this after handle_opt to avoid potential memory leaks
221 vector<string>::iterator it;
222 for (; *what; ++what) {
223 it = find(opts.begin(), opts.end(), *what);
224 if (it != opts.end())
231 * Split a package options string (keyval format) into a vector.
233 * authorformat=smallcaps,
235 * titleformat=colonsep,
236 * bibformat={tabular,ibidem,numbered}
238 vector<string> split_options(string const & input)
240 vector<string> options;
244 Token const & t = p.get_token();
245 if (t.asInput() == ",") {
246 options.push_back(trimSpaceAndEol(option));
248 } else if (t.asInput() == "=") {
251 if (p.next_token().asInput() == "{")
252 option += '{' + p.getArg('{', '}') + '}';
253 } else if (t.cat() != catSpace)
254 option += t.asInput();
258 options.push_back(trimSpaceAndEol(option));
265 * Retrieve a keyval option "name={value with=sign}" named \p name from
266 * \p options and return the value.
267 * The found option is also removed from \p options.
269 string process_keyval_opt(vector<string> & options, string name)
271 for (size_t i = 0; i < options.size(); ++i) {
272 vector<string> option;
273 split(options[i], option, '=');
274 if (option.size() < 2)
276 if (option[0] == name) {
277 options.erase(options.begin() + i);
278 option.erase(option.begin());
279 return join(option, "=");
285 } // anonymous namespace
288 bool Preamble::indentParagraphs() const
290 return h_paragraph_separation == "indent";
294 bool Preamble::isPackageUsed(string const & package) const
296 return used_packages.find(package) != used_packages.end();
300 vector<string> Preamble::getPackageOptions(string const & package) const
302 map<string, vector<string> >::const_iterator it = used_packages.find(package);
303 if (it != used_packages.end())
305 return vector<string>();
309 void Preamble::registerAutomaticallyLoadedPackage(std::string const & package)
311 auto_packages.insert(package);
315 void Preamble::addModule(string const & module)
317 used_modules.push_back(module);
321 void Preamble::suppressDate(bool suppress)
324 h_suppress_date = "true";
326 h_suppress_date = "false";
330 void Preamble::registerAuthor(std::string const & name)
332 Author author(from_utf8(name), empty_docstring());
333 author.setUsed(true);
334 authors_.record(author);
335 h_tracking_changes = "true";
336 h_output_changes = "true";
340 Author const & Preamble::getAuthor(std::string const & name) const
342 Author author(from_utf8(name), empty_docstring());
343 for (AuthorList::Authors::const_iterator it = authors_.begin();
344 it != authors_.end(); ++it)
347 static Author const dummy;
352 void Preamble::add_package(string const & name, vector<string> & options)
354 // every package inherits the global options
355 if (used_packages.find(name) == used_packages.end())
356 used_packages[name] = split_options(h_options);
358 vector<string> & v = used_packages[name];
359 v.insert(v.end(), options.begin(), options.end());
360 if (name == "jurabib") {
361 // Don't output the order argument (see the cite command
362 // handling code in text.cpp).
363 vector<string>::iterator end =
364 remove(options.begin(), options.end(), "natbiborder");
365 end = remove(options.begin(), end, "jurabiborder");
366 options.erase(end, options.end());
373 // Given is a string like "scaled=0.9", return 0.9 * 100
374 string const scale_as_percentage(string const & scale)
376 string::size_type pos = scale.find('=');
377 if (pos != string::npos) {
378 string value = scale.substr(pos + 1);
380 return convert<string>(100 * convert<double>(value));
382 // If the input string didn't match our expectations.
383 // return the default value "100"
388 string remove_braces(string const & value)
392 if (value[0] == '{' && value[value.length()-1] == '}')
393 return value.substr(1, value.length()-2);
397 } // anonymous namespace
400 Preamble::Preamble() : one_language(true), title_layout_found(false)
404 h_biblio_style = "plain";
405 h_cite_engine = "basic";
406 h_cite_engine_type = "numerical";
407 h_defskip = "medskip";
410 h_fontencoding = "default";
411 h_font_roman = "default";
412 h_font_sans = "default";
413 h_font_typewriter = "default";
414 h_font_default_family = "default";
415 h_use_non_tex_fonts = "false";
417 h_font_osf = "false";
418 h_font_sf_scale = "100";
419 h_font_tt_scale = "100";
420 h_graphics = "default";
421 h_default_output_format = "default";
422 h_html_be_strict = "false";
423 h_html_css_as_file = "0";
424 h_html_math_output = "0";
425 h_inputencoding = "auto";
426 h_justification = "true";
427 h_language = "english";
428 h_language_package = "none";
433 h_output_changes = "false";
434 h_papercolumns = "1";
435 h_paperfontsize = "default";
436 h_paperorientation = "portrait";
437 h_paperpagestyle = "default";
439 h_papersize = "default";
440 h_paragraph_indentation = "default";
441 h_paragraph_separation = "indent";
446 h_pdf_bookmarks = "1";
447 h_pdf_bookmarksnumbered = "0";
448 h_pdf_bookmarksopen = "0";
449 h_pdf_bookmarksopenlevel = "1";
450 h_pdf_breaklinks = "0";
451 h_pdf_pdfborder = "0";
452 h_pdf_colorlinks = "0";
453 h_pdf_backref = "section";
454 h_pdf_pdfusetitle = "1";
456 //h_pdf_quoted_options;
457 h_quotes_language = "english";
459 h_spacing = "single";
460 h_suppress_date = "false";
461 h_textclass = "article";
463 h_tracking_changes = "false";
464 h_use_bibtopic = "false";
465 h_use_indices = "false";
466 h_use_geometry = "false";
467 h_use_default_options = "false";
468 h_use_hyperref = "0";
469 h_use_refstyle = "0";
470 h_use_packages["amsmath"] = "1";
471 h_use_packages["amssymb"] = "0";
472 h_use_packages["esint"] = "1";
473 h_use_packages["mhchem"] = "0";
474 h_use_packages["mathdots"] = "0";
475 h_use_packages["mathtools"] = "0";
476 h_use_packages["undertilde"] = "0";
480 void Preamble::handle_hyperref(vector<string> & options)
482 // FIXME swallow inputencoding changes that might surround the
483 // hyperref setup if it was written by LyX
484 h_use_hyperref = "1";
485 // swallow "unicode=true", since LyX does always write that
486 vector<string>::iterator it =
487 find(options.begin(), options.end(), "unicode=true");
488 if (it != options.end())
490 it = find(options.begin(), options.end(), "pdfusetitle");
491 if (it != options.end()) {
492 h_pdf_pdfusetitle = "1";
495 string bookmarks = process_keyval_opt(options, "bookmarks");
496 if (bookmarks == "true")
497 h_pdf_bookmarks = "1";
498 else if (bookmarks == "false")
499 h_pdf_bookmarks = "0";
500 if (h_pdf_bookmarks == "1") {
501 string bookmarksnumbered =
502 process_keyval_opt(options, "bookmarksnumbered");
503 if (bookmarksnumbered == "true")
504 h_pdf_bookmarksnumbered = "1";
505 else if (bookmarksnumbered == "false")
506 h_pdf_bookmarksnumbered = "0";
507 string bookmarksopen =
508 process_keyval_opt(options, "bookmarksopen");
509 if (bookmarksopen == "true")
510 h_pdf_bookmarksopen = "1";
511 else if (bookmarksopen == "false")
512 h_pdf_bookmarksopen = "0";
513 if (h_pdf_bookmarksopen == "1") {
514 string bookmarksopenlevel =
515 process_keyval_opt(options, "bookmarksopenlevel");
516 if (!bookmarksopenlevel.empty())
517 h_pdf_bookmarksopenlevel = bookmarksopenlevel;
520 string breaklinks = process_keyval_opt(options, "breaklinks");
521 if (breaklinks == "true")
522 h_pdf_breaklinks = "1";
523 else if (breaklinks == "false")
524 h_pdf_breaklinks = "0";
525 string pdfborder = process_keyval_opt(options, "pdfborder");
526 if (pdfborder == "{0 0 0}")
527 h_pdf_pdfborder = "1";
528 else if (pdfborder == "{0 0 1}")
529 h_pdf_pdfborder = "0";
530 string backref = process_keyval_opt(options, "backref");
531 if (!backref.empty())
532 h_pdf_backref = backref;
533 string colorlinks = process_keyval_opt(options, "colorlinks");
534 if (colorlinks == "true")
535 h_pdf_colorlinks = "1";
536 else if (colorlinks == "false")
537 h_pdf_colorlinks = "0";
538 string pdfpagemode = process_keyval_opt(options, "pdfpagemode");
539 if (!pdfpagemode.empty())
540 h_pdf_pagemode = pdfpagemode;
541 string pdftitle = process_keyval_opt(options, "pdftitle");
542 if (!pdftitle.empty()) {
543 h_pdf_title = remove_braces(pdftitle);
545 string pdfauthor = process_keyval_opt(options, "pdfauthor");
546 if (!pdfauthor.empty()) {
547 h_pdf_author = remove_braces(pdfauthor);
549 string pdfsubject = process_keyval_opt(options, "pdfsubject");
550 if (!pdfsubject.empty())
551 h_pdf_subject = remove_braces(pdfsubject);
552 string pdfkeywords = process_keyval_opt(options, "pdfkeywords");
553 if (!pdfkeywords.empty())
554 h_pdf_keywords = remove_braces(pdfkeywords);
555 if (!options.empty()) {
556 if (!h_pdf_quoted_options.empty())
557 h_pdf_quoted_options += ',';
558 h_pdf_quoted_options += join(options, ",");
564 void Preamble::handle_geometry(vector<string> & options)
566 h_use_geometry = "true";
567 vector<string>::iterator it;
569 if ((it = find(options.begin(), options.end(), "landscape")) != options.end()) {
570 h_paperorientation = "landscape";
574 // keyval version: "paper=letter"
575 string paper = process_keyval_opt(options, "paper");
577 h_papersize = paper + "paper";
578 // alternative version: "letterpaper"
579 handle_opt(options, known_paper_sizes, h_papersize);
580 delete_opt(options, known_paper_sizes);
582 char const * const * margin = known_paper_margins;
583 for (; *margin; ++margin) {
584 string value = process_keyval_opt(options, *margin);
585 if (!value.empty()) {
586 int k = margin - known_paper_margins;
587 string name = known_coded_paper_margins[k];
588 h_margins += '\\' + name + ' ' + value + '\n';
594 void Preamble::handle_package(Parser &p, string const & name,
595 string const & opts, bool in_lyx_preamble)
597 vector<string> options = split_options(opts);
598 add_package(name, options);
601 if (is_known(name, known_xetex_packages)) {
603 h_use_non_tex_fonts = "true";
604 if (h_inputencoding == "auto")
605 p.setEncoding("utf8");
609 if (is_known(name, known_roman_fonts)) {
614 if (name == "fourier") {
615 h_font_roman = "utopia";
616 // when font uses real small capitals
617 if (opts == "expert")
621 else if (name == "mathpazo")
622 h_font_roman = "palatino";
624 else if (name == "mathptmx")
625 h_font_roman = "times";
628 if (is_known(name, known_sans_fonts)) {
632 h_font_sf_scale = scale_as_percentage(scale);
637 if (is_known(name, known_typewriter_fonts)) {
638 // fourier can be set as roman font _only_
639 // fourier as typewriter is handled in handling of \ttdefault
640 if (name != "fourier") {
641 h_font_typewriter = name;
644 h_font_tt_scale = scale_as_percentage(scale);
649 // font uses old-style figure
653 // after the detection and handling of special cases, we can remove the
654 // fonts, otherwise they would appear in the preamble, see bug #7856
655 if (is_known(name, known_roman_fonts) || is_known(name, known_sans_fonts)
656 || is_known(name, known_typewriter_fonts))
659 else if (name == "amsmath" || name == "amssymb" ||
660 name == "esint" || name == "mhchem" || name == "mathdots" ||
661 name == "mathtools" || name == "undertilde")
662 h_use_packages[name] = "2";
664 else if (name == "babel") {
665 h_language_package = "default";
666 // One might think we would have to do nothing if babel is loaded
667 // without any options to prevent pollution of the preamble with this
668 // babel call in every roundtrip.
669 // But the user could have defined babel-specific things afterwards. So
670 // we need to keep it in the preamble to prevent cases like bug #7861.
672 // check if more than one option was used - used later for inputenc
673 if (options.begin() != options.end() - 1)
674 one_language = false;
675 // babel takes the last language of the option of its \usepackage
676 // call as document language. If there is no such language option, the
677 // last language in the documentclass options is used.
678 handle_opt(options, known_languages, h_language);
679 // If babel is called with options, LyX puts them by default into the
680 // document class options. This works for most languages, except
681 // for Latvian, Lithuanian, Mongolian, Turkmen and Vietnamese and
682 // perhaps in future others.
683 // Therefore keep the babel call as it is as the user might have
685 h_preamble << "\\usepackage[" << opts << "]{babel}\n";
686 delete_opt(options, known_languages);
689 h_preamble << "\\usepackage{babel}\n";
692 else if (name == "polyglossia") {
693 h_language_package = "default";
694 h_default_output_format = "pdf4";
695 h_use_non_tex_fonts = "true";
697 if (h_inputencoding == "auto")
698 p.setEncoding("utf8");
701 else if (name == "fontenc") {
702 h_fontencoding = getStringFromVector(options, ",");
703 /* We could do the following for better round trip support,
704 * but this makes the document less portable, so I skip it:
705 if (h_fontencoding == lyxrc.fontenc)
706 h_fontencoding = "global";
711 else if (name == "inputenc" || name == "luainputenc") {
712 // h_inputencoding is only set when there is not more than one
713 // inputenc option because otherwise h_inputencoding must be
714 // set to "auto" (the default encoding of the document language)
715 // Therefore check for the "," character.
716 // It is also only set when there is not more than one babel
718 if (opts.find(",") == string::npos && one_language == true)
719 h_inputencoding = opts;
720 if (!options.empty())
721 p.setEncoding(options.back());
725 else if (is_known(name, known_old_language_packages)) {
726 // known language packages from the times before babel
727 // if they are found and not also babel, they will be used as
728 // custom language package
729 h_language_package = "\\usepackage{" + name + "}";
732 else if (name == "prettyref")
733 ; // ignore this FIXME: Use the package separator mechanism instead
735 else if (name == "lyxskak") {
736 // ignore this and its options
737 const char * const o[] = {"ps", "mover", 0};
738 delete_opt(options, o);
741 else if (is_known(name, known_lyx_packages) && options.empty()) {
742 if (name == "splitidx")
743 h_use_indices = "true";
744 if (!in_lyx_preamble)
745 h_preamble << package_beg_sep << name
746 << package_mid_sep << "\\usepackage{"
747 << name << "}\n" << package_end_sep;
750 else if (name == "geometry")
751 handle_geometry(options);
753 else if (name == "subfig")
754 ; // ignore this FIXME: Use the package separator mechanism instead
756 else if (is_known(name, known_languages))
759 else if (name == "natbib") {
760 h_biblio_style = "plainnat";
761 h_cite_engine = "natbib";
762 h_cite_engine_type = "authoryear";
763 vector<string>::iterator it =
764 find(options.begin(), options.end(), "authoryear");
765 if (it != options.end())
768 it = find(options.begin(), options.end(), "numbers");
769 if (it != options.end()) {
770 h_cite_engine_type = "numerical";
776 else if (name == "jurabib") {
777 h_biblio_style = "jurabib";
778 h_cite_engine = "jurabib";
779 h_cite_engine_type = "authoryear";
782 else if (name == "hyperref")
783 handle_hyperref(options);
785 else if (!in_lyx_preamble) {
787 h_preamble << "\\usepackage{" << name << "}\n";
789 h_preamble << "\\usepackage[" << opts << "]{"
795 // We need to do something with the options...
796 if (!options.empty())
797 cerr << "Ignoring options '" << join(options, ",")
798 << "' of package " << name << '.' << endl;
800 // remove the whitespace
805 void Preamble::handle_if(Parser & p, bool in_lyx_preamble)
808 Token t = p.get_token();
809 if (t.cat() == catEscape &&
810 is_known(t.cs(), known_if_commands))
811 handle_if(p, in_lyx_preamble);
813 if (!in_lyx_preamble)
814 h_preamble << t.asInput();
815 if (t.cat() == catEscape && t.cs() == "fi")
822 bool Preamble::writeLyXHeader(ostream & os, bool subdoc)
824 // translate from babel to LyX names
825 h_language = babel2lyx(h_language);
827 // set the quote language
828 // LyX only knows the following quotes languages:
829 // english, swedish, german, polish, french and danish
830 // (quotes for "japanese" and "chinese-traditional" are missing because
831 // they wouldn't be useful: http://www.lyx.org/trac/ticket/6383)
832 // conversion list taken from
833 // http://en.wikipedia.org/wiki/Quotation_mark,_non-English_usage
834 // (quotes for kazakh and interlingua are unknown)
836 if (h_language == "danish")
837 h_quotes_language = "danish";
839 else if (is_known(h_language, known_french_quotes_languages))
840 h_quotes_language = "french";
842 else if (is_known(h_language, known_german_quotes_languages))
843 h_quotes_language = "german";
845 else if (is_known(h_language, known_polish_quotes_languages))
846 h_quotes_language = "polish";
848 else if (is_known(h_language, known_swedish_quotes_languages))
849 h_quotes_language = "swedish";
851 else if (is_known(h_language, known_english_quotes_languages))
852 h_quotes_language = "english";
854 if (contains(h_float_placement, "H"))
855 registerAutomaticallyLoadedPackage("float");
856 if (h_spacing != "single" && h_spacing != "default")
857 registerAutomaticallyLoadedPackage("setspace");
858 if (h_use_packages["amsmath"] == "2") {
859 // amsbsy and amstext are already provided by amsmath
860 registerAutomaticallyLoadedPackage("amsbsy");
861 registerAutomaticallyLoadedPackage("amstext");
864 // output the LyX file settings
865 os << "#LyX file created by tex2lyx " << PACKAGE_VERSION << "\n"
866 << "\\lyxformat " << LYX_FORMAT << '\n'
867 << "\\begin_document\n"
868 << "\\begin_header\n"
869 << "\\textclass " << h_textclass << "\n";
870 string const raw = subdoc ? empty_string() : h_preamble.str();
872 os << "\\begin_preamble\n";
873 for (string::size_type i = 0; i < raw.size(); ++i) {
874 if (raw[i] == package_beg_sep) {
875 // Here follows some package loading code that
876 // must be skipped if the package is loaded
878 string::size_type j = raw.find(package_mid_sep, i);
879 if (j == string::npos)
881 string::size_type k = raw.find(package_end_sep, j);
882 if (k == string::npos)
884 string const package = raw.substr(i + 1, j - i - 1);
885 string const replacement = raw.substr(j + 1, k - j - 1);
886 if (auto_packages.find(package) == auto_packages.end())
892 os << "\n\\end_preamble\n";
894 if (!h_options.empty())
895 os << "\\options " << h_options << "\n";
896 os << "\\use_default_options " << h_use_default_options << "\n";
897 if (!used_modules.empty()) {
898 os << "\\begin_modules\n";
899 vector<string>::const_iterator const end = used_modules.end();
900 vector<string>::const_iterator it = used_modules.begin();
901 for (; it != end; ++it)
903 os << "\\end_modules\n";
905 os << "\\language " << h_language << "\n"
906 << "\\language_package " << h_language_package << "\n"
907 << "\\inputencoding " << h_inputencoding << "\n"
908 << "\\fontencoding " << h_fontencoding << "\n"
909 << "\\font_roman " << h_font_roman << "\n"
910 << "\\font_sans " << h_font_sans << "\n"
911 << "\\font_typewriter " << h_font_typewriter << "\n"
912 << "\\font_default_family " << h_font_default_family << "\n"
913 << "\\use_non_tex_fonts " << h_use_non_tex_fonts << "\n"
914 << "\\font_sc " << h_font_sc << "\n"
915 << "\\font_osf " << h_font_osf << "\n"
916 << "\\font_sf_scale " << h_font_sf_scale << "\n"
917 << "\\font_tt_scale " << h_font_tt_scale << "\n"
918 << "\\graphics " << h_graphics << "\n"
919 << "\\default_output_format " << h_default_output_format << "\n";
920 if (!h_float_placement.empty())
921 os << "\\float_placement " << h_float_placement << "\n";
922 os << "\\paperfontsize " << h_paperfontsize << "\n"
923 << "\\spacing " << h_spacing << "\n"
924 << "\\use_hyperref " << h_use_hyperref << '\n';
925 if (h_use_hyperref == "1") {
926 if (!h_pdf_title.empty())
927 os << "\\pdf_title \"" << h_pdf_title << "\"\n";
928 if (!h_pdf_author.empty())
929 os << "\\pdf_author \"" << h_pdf_author << "\"\n";
930 if (!h_pdf_subject.empty())
931 os << "\\pdf_subject \"" << h_pdf_subject << "\"\n";
932 if (!h_pdf_keywords.empty())
933 os << "\\pdf_keywords \"" << h_pdf_keywords << "\"\n";
934 os << "\\pdf_bookmarks " << h_pdf_bookmarks << "\n"
935 "\\pdf_bookmarksnumbered " << h_pdf_bookmarksnumbered << "\n"
936 "\\pdf_bookmarksopen " << h_pdf_bookmarksopen << "\n"
937 "\\pdf_bookmarksopenlevel " << h_pdf_bookmarksopenlevel << "\n"
938 "\\pdf_breaklinks " << h_pdf_breaklinks << "\n"
939 "\\pdf_pdfborder " << h_pdf_pdfborder << "\n"
940 "\\pdf_colorlinks " << h_pdf_colorlinks << "\n"
941 "\\pdf_backref " << h_pdf_backref << "\n"
942 "\\pdf_pdfusetitle " << h_pdf_pdfusetitle << '\n';
943 if (!h_pdf_pagemode.empty())
944 os << "\\pdf_pagemode " << h_pdf_pagemode << '\n';
945 if (!h_pdf_quoted_options.empty())
946 os << "\\pdf_quoted_options \"" << h_pdf_quoted_options << "\"\n";
948 os << "\\papersize " << h_papersize << "\n"
949 << "\\use_geometry " << h_use_geometry << '\n';
950 for (map<string, string>::const_iterator it = h_use_packages.begin();
951 it != h_use_packages.end(); ++it)
952 os << "\\use_package " << it->first << ' ' << it->second << '\n';
953 os << "\\cite_engine " << h_cite_engine << '\n'
954 << "\\cite_engine_type " << h_cite_engine_type << '\n'
955 << "\\biblio_style " << h_biblio_style << "\n"
956 << "\\use_bibtopic " << h_use_bibtopic << "\n"
957 << "\\use_indices " << h_use_indices << "\n"
958 << "\\paperorientation " << h_paperorientation << '\n'
959 << "\\suppress_date " << h_suppress_date << '\n'
960 << "\\justification " << h_justification << '\n'
961 << "\\use_refstyle " << h_use_refstyle << '\n';
962 if (!h_fontcolor.empty())
963 os << "\\fontcolor " << h_fontcolor << '\n';
964 if (!h_notefontcolor.empty())
965 os << "\\notefontcolor " << h_notefontcolor << '\n';
966 if (!h_backgroundcolor.empty())
967 os << "\\backgroundcolor " << h_backgroundcolor << '\n';
968 if (!h_boxbgcolor.empty())
969 os << "\\boxbgcolor " << h_boxbgcolor << '\n';
971 << "\\secnumdepth " << h_secnumdepth << "\n"
972 << "\\tocdepth " << h_tocdepth << "\n"
973 << "\\paragraph_separation " << h_paragraph_separation << "\n";
974 if (h_paragraph_separation == "skip")
975 os << "\\defskip " << h_defskip << "\n";
977 os << "\\paragraph_indentation " << h_paragraph_indentation << "\n";
978 os << "\\quotes_language " << h_quotes_language << "\n"
979 << "\\papercolumns " << h_papercolumns << "\n"
980 << "\\papersides " << h_papersides << "\n"
981 << "\\paperpagestyle " << h_paperpagestyle << "\n";
982 if (!h_listings_params.empty())
983 os << "\\listings_params " << h_listings_params << "\n";
984 os << "\\tracking_changes " << h_tracking_changes << "\n"
985 << "\\output_changes " << h_output_changes << "\n"
986 << "\\html_math_output " << h_html_math_output << "\n"
987 << "\\html_css_as_file " << h_html_css_as_file << "\n"
988 << "\\html_be_strict " << h_html_be_strict << "\n"
990 << "\\end_header\n\n"
996 void Preamble::parse(Parser & p, string const & forceclass,
997 TeX2LyXDocClass & tc)
999 // initialize fixed types
1000 special_columns['D'] = 3;
1001 bool is_full_document = false;
1002 bool is_lyx_file = false;
1003 bool in_lyx_preamble = false;
1005 // determine whether this is a full document or a fragment for inclusion
1007 Token const & t = p.get_token();
1009 if (t.cat() == catEscape && t.cs() == "documentclass") {
1010 is_full_document = true;
1016 while (is_full_document && p.good()) {
1017 Token const & t = p.get_token();
1020 cerr << "t: " << t << "\n";
1026 if (!in_lyx_preamble &&
1027 (t.cat() == catLetter ||
1028 t.cat() == catSuper ||
1029 t.cat() == catSub ||
1030 t.cat() == catOther ||
1031 t.cat() == catMath ||
1032 t.cat() == catActive ||
1033 t.cat() == catBegin ||
1034 t.cat() == catEnd ||
1035 t.cat() == catAlign ||
1036 t.cat() == catParameter))
1037 h_preamble << t.cs();
1039 else if (!in_lyx_preamble &&
1040 (t.cat() == catSpace || t.cat() == catNewline))
1041 h_preamble << t.asInput();
1043 else if (t.cat() == catComment) {
1044 static regex const islyxfile("%% LyX .* created this file");
1045 static regex const usercommands("User specified LaTeX commands");
1047 string const comment = t.asInput();
1049 // magically switch encoding default if it looks like XeLaTeX
1050 static string const magicXeLaTeX =
1051 "% This document must be compiled with XeLaTeX ";
1052 if (comment.size() > magicXeLaTeX.size()
1053 && comment.substr(0, magicXeLaTeX.size()) == magicXeLaTeX
1054 && h_inputencoding == "auto") {
1055 cerr << "XeLaTeX comment found, switching to UTF8\n";
1056 h_inputencoding = "utf8";
1059 if (regex_search(comment, sub, islyxfile)) {
1061 in_lyx_preamble = true;
1062 } else if (is_lyx_file
1063 && regex_search(comment, sub, usercommands))
1064 in_lyx_preamble = false;
1065 else if (!in_lyx_preamble)
1066 h_preamble << t.asInput();
1069 else if (t.cs() == "pagestyle")
1070 h_paperpagestyle = p.verbatim_item();
1072 else if (t.cs() == "setdefaultlanguage")
1073 h_language = p.verbatim_item();
1075 else if (t.cs() == "setotherlanguage")
1078 else if (t.cs() == "setmainfont") {
1079 // we don't care about the option
1080 p.hasOpt() ? p.getOpt() : string();
1081 h_font_roman = p.getArg('{', '}');
1084 else if (t.cs() == "setsansfont") {
1085 // we don't care about the option
1086 p.hasOpt() ? p.getOpt() : string();
1087 h_font_sans = p.getArg('{', '}');
1090 else if (t.cs() == "setmonofont") {
1091 // we don't care about the option
1092 p.hasOpt() ? p.getOpt() : string();
1093 h_font_typewriter = p.getArg('{', '}');
1096 else if (t.cs() == "date") {
1097 string argument = p.getArg('{', '}');
1098 if (argument.empty())
1099 h_suppress_date = "true";
1101 h_preamble << t.asInput() << '{' << argument << '}';
1104 else if (t.cs() == "color") {
1105 string const space =
1106 (p.hasOpt() ? p.getOpt() : string());
1107 string argument = p.getArg('{', '}');
1108 // check the case that a standard color is used
1109 if (space.empty() && is_known(argument, known_basic_colors)) {
1110 h_fontcolor = rgbcolor2code(argument);
1111 preamble.registerAutomaticallyLoadedPackage("color");
1112 } else if (space.empty() && argument == "document_fontcolor")
1113 preamble.registerAutomaticallyLoadedPackage("color");
1114 // check the case that LyX's document_fontcolor is defined
1115 // but not used for \color
1117 h_preamble << t.asInput();
1119 h_preamble << space;
1120 h_preamble << '{' << argument << '}';
1121 // the color might already be set because \definecolor
1122 // is parsed before this
1127 else if (t.cs() == "pagecolor") {
1128 string argument = p.getArg('{', '}');
1129 // check the case that a standard color is used
1130 if (is_known(argument, known_basic_colors)) {
1131 h_backgroundcolor = rgbcolor2code(argument);
1132 } else if (argument == "page_backgroundcolor")
1133 preamble.registerAutomaticallyLoadedPackage("color");
1134 // check the case that LyX's page_backgroundcolor is defined
1135 // but not used for \pagecolor
1137 h_preamble << t.asInput() << '{' << argument << '}';
1138 // the color might already be set because \definecolor
1139 // is parsed before this
1140 h_backgroundcolor = "";
1144 else if (t.cs() == "makeatletter") {
1145 // LyX takes care of this
1146 p.setCatCode('@', catLetter);
1149 else if (t.cs() == "makeatother") {
1150 // LyX takes care of this
1151 p.setCatCode('@', catOther);
1154 else if (t.cs() == "newcommand" || t.cs() == "newcommandx"
1155 || t.cs() == "renewcommand" || t.cs() == "renewcommandx"
1156 || t.cs() == "providecommand" || t.cs() == "providecommandx"
1157 || t.cs() == "DeclareRobustCommand"
1158 || t.cs() == "DeclareRobustCommandx"
1159 || t.cs() == "ProvideTextCommandDefault"
1160 || t.cs() == "DeclareMathAccent") {
1162 if (p.next_token().character() == '*') {
1166 string const name = p.verbatim_item();
1167 string const opt1 = p.getFullOpt();
1168 string const opt2 = p.getFullOpt();
1169 string const body = p.verbatim_item();
1171 if (name == "\\rmdefault")
1172 if (is_known(body, known_roman_fonts))
1173 h_font_roman = body;
1174 if (name == "\\sfdefault")
1175 if (is_known(body, known_sans_fonts))
1177 if (name == "\\ttdefault")
1178 if (is_known(body, known_typewriter_fonts))
1179 h_font_typewriter = body;
1180 if (name == "\\familydefault") {
1181 string family = body;
1182 // remove leading "\"
1183 h_font_default_family = family.erase(0,1);
1186 // remove the lyxdot definition that is re-added by LyX
1188 if (name == "\\lyxdot")
1189 in_lyx_preamble = true;
1191 // Add the command to the known commands
1192 add_known_command(name, opt1, !opt2.empty(), from_utf8(body));
1194 // only non-lyxspecific stuff
1195 if (!in_lyx_preamble) {
1197 ss << '\\' << t.cs();
1200 ss << '{' << name << '}' << opt1 << opt2
1201 << '{' << body << "}";
1202 h_preamble << ss.str();
1204 ostream & out = in_preamble ? h_preamble : os;
1205 out << "\\" << t.cs() << "{" << name << "}"
1206 << opts << "{" << body << "}";
1211 else if (t.cs() == "documentclass") {
1212 vector<string>::iterator it;
1213 vector<string> opts = split_options(p.getArg('[', ']'));
1214 handle_opt(opts, known_fontsizes, h_paperfontsize);
1215 delete_opt(opts, known_fontsizes);
1216 // delete "pt" at the end
1217 string::size_type i = h_paperfontsize.find("pt");
1218 if (i != string::npos)
1219 h_paperfontsize.erase(i);
1220 // The documentclass options are always parsed before the options
1221 // of the babel call so that a language cannot overwrite the babel
1223 handle_opt(opts, known_languages, h_language);
1224 delete_opt(opts, known_languages);
1226 // paper orientation
1227 if ((it = find(opts.begin(), opts.end(), "landscape")) != opts.end()) {
1228 h_paperorientation = "landscape";
1232 if ((it = find(opts.begin(), opts.end(), "oneside"))
1237 if ((it = find(opts.begin(), opts.end(), "twoside"))
1243 if ((it = find(opts.begin(), opts.end(), "onecolumn"))
1245 h_papercolumns = "1";
1248 if ((it = find(opts.begin(), opts.end(), "twocolumn"))
1250 h_papercolumns = "2";
1254 // some size options are known to any document classes, other sizes
1255 // are handled by the \geometry command of the geometry package
1256 handle_opt(opts, known_class_paper_sizes, h_papersize);
1257 delete_opt(opts, known_class_paper_sizes);
1258 // the remaining options
1259 h_options = join(opts, ",");
1260 // FIXME This does not work for classes that have a
1261 // different name in LyX than in LaTeX
1262 h_textclass = p.getArg('{', '}');
1265 else if (t.cs() == "usepackage") {
1266 string const options = p.getArg('[', ']');
1267 string const name = p.getArg('{', '}');
1268 vector<string> vecnames;
1269 split(name, vecnames, ',');
1270 vector<string>::const_iterator it = vecnames.begin();
1271 vector<string>::const_iterator end = vecnames.end();
1272 for (; it != end; ++it)
1273 handle_package(p, trimSpaceAndEol(*it), options,
1277 else if (t.cs() == "inputencoding") {
1278 string const encoding = p.getArg('{','}');
1279 h_inputencoding = encoding;
1280 p.setEncoding(encoding);
1283 else if (t.cs() == "newenvironment") {
1284 string const name = p.getArg('{', '}');
1285 string const opt1 = p.getFullOpt();
1286 string const opt2 = p.getFullOpt();
1287 string const beg = p.verbatim_item();
1288 string const end = p.verbatim_item();
1289 if (!in_lyx_preamble) {
1290 h_preamble << "\\newenvironment{" << name
1291 << '}' << opt1 << opt2 << '{'
1292 << beg << "}{" << end << '}';
1294 add_known_environment(name, opt1, !opt2.empty(),
1295 from_utf8(beg), from_utf8(end));
1299 else if (t.cs() == "def") {
1300 string name = p.get_token().cs();
1301 // In fact, name may be more than the name:
1302 // In the test case of bug 8116
1303 // name == "csname SF@gobble@opt \endcsname".
1304 // Therefore, we need to use asInput() instead of cs().
1305 while (p.next_token().cat() != catBegin)
1306 name += p.get_token().asInput();
1307 if (!in_lyx_preamble)
1308 h_preamble << "\\def\\" << name << '{'
1309 << p.verbatim_item() << "}";
1312 else if (t.cs() == "newcolumntype") {
1313 string const name = p.getArg('{', '}');
1314 trimSpaceAndEol(name);
1316 string opts = p.getOpt();
1317 if (!opts.empty()) {
1318 istringstream is(string(opts, 1));
1321 special_columns[name[0]] = nargs;
1322 h_preamble << "\\newcolumntype{" << name << "}";
1324 h_preamble << "[" << nargs << "]";
1325 h_preamble << "{" << p.verbatim_item() << "}";
1328 else if (t.cs() == "setcounter") {
1329 string const name = p.getArg('{', '}');
1330 string const content = p.getArg('{', '}');
1331 if (name == "secnumdepth")
1332 h_secnumdepth = content;
1333 else if (name == "tocdepth")
1334 h_tocdepth = content;
1336 h_preamble << "\\setcounter{" << name << "}{" << content << "}";
1339 else if (t.cs() == "setlength") {
1340 string const name = p.verbatim_item();
1341 string const content = p.verbatim_item();
1342 // the paragraphs are only not indented when \parindent is set to zero
1343 if (name == "\\parindent" && content != "") {
1344 if (content[0] == '0')
1345 h_paragraph_separation = "skip";
1347 h_paragraph_indentation = translate_len(content);
1348 } else if (name == "\\parskip") {
1349 if (content == "\\smallskipamount")
1350 h_defskip = "smallskip";
1351 else if (content == "\\medskipamount")
1352 h_defskip = "medskip";
1353 else if (content == "\\bigskipamount")
1354 h_defskip = "bigskip";
1356 h_defskip = content;
1358 h_preamble << "\\setlength{" << name << "}{" << content << "}";
1361 else if (t.cs() == "onehalfspacing")
1362 h_spacing = "onehalf";
1364 else if (t.cs() == "doublespacing")
1365 h_spacing = "double";
1367 else if (t.cs() == "setstretch")
1368 h_spacing = "other " + p.verbatim_item();
1370 else if (t.cs() == "begin") {
1371 string const name = p.getArg('{', '}');
1372 if (name == "document")
1374 h_preamble << "\\begin{" << name << "}";
1377 else if (t.cs() == "geometry") {
1378 vector<string> opts = split_options(p.getArg('{', '}'));
1379 handle_geometry(opts);
1382 else if (t.cs() == "definecolor") {
1383 string const color = p.getArg('{', '}');
1384 string const space = p.getArg('{', '}');
1385 string const value = p.getArg('{', '}');
1386 if (color == "document_fontcolor" && space == "rgb") {
1387 RGBColor c(RGBColorFromLaTeX(value));
1388 h_fontcolor = X11hexname(c);
1389 } else if (color == "note_fontcolor" && space == "rgb") {
1390 RGBColor c(RGBColorFromLaTeX(value));
1391 h_notefontcolor = X11hexname(c);
1392 } else if (color == "page_backgroundcolor" && space == "rgb") {
1393 RGBColor c(RGBColorFromLaTeX(value));
1394 h_backgroundcolor = X11hexname(c);
1395 } else if (color == "shadecolor" && space == "rgb") {
1396 RGBColor c(RGBColorFromLaTeX(value));
1397 h_boxbgcolor = X11hexname(c);
1399 h_preamble << "\\definecolor{" << color
1400 << "}{" << space << "}{" << value
1405 else if (t.cs() == "bibliographystyle")
1406 h_biblio_style = p.verbatim_item();
1408 else if (t.cs() == "jurabibsetup") {
1409 // FIXME p.getArg('{', '}') is most probably wrong (it
1410 // does not handle nested braces).
1411 // Use p.verbatim_item() instead.
1412 vector<string> jurabibsetup =
1413 split_options(p.getArg('{', '}'));
1414 // add jurabibsetup to the jurabib package options
1415 add_package("jurabib", jurabibsetup);
1416 if (!jurabibsetup.empty()) {
1417 h_preamble << "\\jurabibsetup{"
1418 << join(jurabibsetup, ",") << '}';
1422 else if (t.cs() == "hypersetup") {
1423 vector<string> hypersetup =
1424 split_options(p.verbatim_item());
1425 // add hypersetup to the hyperref package options
1426 handle_hyperref(hypersetup);
1427 if (!hypersetup.empty()) {
1428 h_preamble << "\\hypersetup{"
1429 << join(hypersetup, ",") << '}';
1433 else if (is_known(t.cs(), known_if_3arg_commands)) {
1434 // prevent misparsing of \usepackage if it is used
1435 // as an argument (see e.g. our own output of
1436 // \@ifundefined above)
1437 string const arg1 = p.verbatim_item();
1438 string const arg2 = p.verbatim_item();
1439 string const arg3 = p.verbatim_item();
1440 // test case \@ifundefined{date}{}{\date{}}
1441 if (t.cs() == "@ifundefined" && arg1 == "date" &&
1442 arg2.empty() && arg3 == "\\date{}") {
1443 h_suppress_date = "true";
1444 // older tex2lyx versions did output
1445 // \@ifundefined{definecolor}{\usepackage{color}}{}
1446 } else if (t.cs() == "@ifundefined" &&
1447 arg1 == "definecolor" &&
1448 arg2 == "\\usepackage{color}" &&
1450 if (!in_lyx_preamble)
1451 h_preamble << package_beg_sep
1454 << "\\@ifundefined{definecolor}{color}{}"
1457 //\@ifundefined{showcaptionsetup}{}{%
1458 // \PassOptionsToPackage{caption=false}{subfig}}
1459 // that LyX uses for subfloats
1460 } else if (t.cs() == "@ifundefined" &&
1461 arg1 == "showcaptionsetup" && arg2.empty()
1462 && arg3 == "%\n \\PassOptionsToPackage{caption=false}{subfig}") {
1464 } else if (!in_lyx_preamble) {
1465 h_preamble << t.asInput()
1466 << '{' << arg1 << '}'
1467 << '{' << arg2 << '}'
1468 << '{' << arg3 << '}';
1472 else if (is_known(t.cs(), known_if_commands)) {
1473 // must not parse anything in conditional code, since
1474 // LyX would output the parsed contents unconditionally
1475 if (!in_lyx_preamble)
1476 h_preamble << t.asInput();
1477 handle_if(p, in_lyx_preamble);
1480 else if (!t.cs().empty() && !in_lyx_preamble)
1481 h_preamble << '\\' << t.cs();
1484 // remove the whitespace
1487 // Force textclass if the user wanted it
1488 if (!forceclass.empty())
1489 h_textclass = forceclass;
1490 if (noweb_mode && !prefixIs(h_textclass, "literate-"))
1491 h_textclass.insert(0, "literate-");
1492 tc.setName(h_textclass);
1494 cerr << "Error: Could not read layout file for textclass \"" << h_textclass << "\"." << endl;
1497 if (h_papersides.empty()) {
1500 h_papersides = ss.str();
1505 string babel2lyx(string const & language)
1507 char const * const * where = is_known(language, known_languages);
1509 return known_coded_languages[where - known_languages];
1514 string rgbcolor2code(string const & name)
1516 char const * const * where = is_known(name, known_basic_colors);
1518 // "red", "green" etc
1519 return known_basic_color_codes[where - known_basic_colors];
1521 // "255,0,0", "0,255,0" etc
1522 RGBColor c(RGBColorFromLaTeX(name));
1523 return X11hexname(c);