From f8cc30a1f20de97425d17fc1779041d0f963f74a Mon Sep 17 00:00:00 2001 From: Georg Baum Date: Sun, 30 Oct 2011 18:12:49 +0000 Subject: [PATCH] Create mechanism to handle packages for which we only know after parsing the complete document whether LyX will load them or not. Use the mechanism for the color package (fixes the color part of bug #7845). git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@40095 a592a061-630c-0410-9148-cb99ea01b6c8 --- src/tex2lyx/Preamble.cpp | 104 +++++++++++++++++++++++++++++---------- src/tex2lyx/Preamble.h | 15 ++++-- src/tex2lyx/tex2lyx.cpp | 12 +++-- src/tex2lyx/tex2lyx.h | 4 +- src/tex2lyx/text.cpp | 10 +++- 5 files changed, 105 insertions(+), 40 deletions(-) diff --git a/src/tex2lyx/Preamble.cpp b/src/tex2lyx/Preamble.cpp index 01af65b1ef..ad472f89ec 100644 --- a/src/tex2lyx/Preamble.cpp +++ b/src/tex2lyx/Preamble.cpp @@ -165,6 +165,12 @@ const char * const known_basic_color_codes[] = {"#0000ff", "#000000", "#00ffff", const char * const known_if_3arg_commands[] = {"@ifundefined", "IfFileExists", 0}; +// codes used to remove packages that are loaded automatically by LyX. +// Syntax: package_beg_seppackage_mid_seppackage_end_sep +const char package_beg_sep = '\001'; +const char package_mid_sep = '\002'; +const char package_end_sep = '\003'; + // returns true if at least one of the options in what has been found bool handle_opt(vector & opts, char const * const * what, string & target) @@ -286,6 +292,12 @@ vector Preamble::getPackageOptions(string const & package) const } +void Preamble::registerAutomaticallyLoadedPackage(std::string const & package) +{ + auto_packages.insert(package); +} + + void Preamble::addModule(string const & module) { used_modules.push_back(module); @@ -349,7 +361,7 @@ string remove_braces(string const & value) } // anonymous namespace -Preamble::Preamble() : one_language(true), ifundefined_color_set(false) +Preamble::Preamble() : one_language(true) { //h_backgroundcolor; //h_boxbgcolor; @@ -663,11 +675,10 @@ void Preamble::handle_package(Parser &p, string const & name, ; // ignore this else if (name == "color") { - // with the following command this package is only loaded when needed for - // undefined colors, since we only support the predefined colors - // only add it if not yet added - if (!ifundefined_color_set) - h_preamble << "\\@ifundefined{definecolor}\n {\\usepackage{color}}{}\n"; + if (!in_lyx_preamble) + h_preamble << package_beg_sep << name + << package_mid_sep << "\\usepackage{" + << name << '}' << package_end_sep; } else if (name == "graphicx") @@ -757,7 +768,7 @@ void Preamble::handle_if(Parser & p, bool in_lyx_preamble) } -void Preamble::writeLyXHeader(ostream & os) +bool Preamble::writeLyXHeader(ostream & os) { // translate from babel to LyX names h_language = babel2lyx(h_language); @@ -795,8 +806,30 @@ void Preamble::writeLyXHeader(ostream & os) << "\\begin_document\n" << "\\begin_header\n" << "\\textclass " << h_textclass << "\n"; - if (!h_preamble.str().empty()) - os << "\\begin_preamble\n" << h_preamble.str() << "\n\\end_preamble\n"; + string const raw = h_preamble.str(); + if (!raw.empty()) { + os << "\\begin_preamble\n"; + for (string::size_type i = 0; i < raw.size(); ++i) { + if (raw[i] == package_beg_sep) { + // Here follows some package loading code that + // must be skipped if the package is loaded + // automatically. + string::size_type j = raw.find(package_mid_sep, i); + if (j == string::npos) + return false; + string::size_type k = raw.find(package_end_sep, j); + if (k == string::npos) + return false; + string const package = raw.substr(i + 1, j - i - 1); + string const replacement = raw.substr(j + 1, k - j - 1); + if (auto_packages.find(package) == auto_packages.end()) + os << replacement; + i = k; + } else + os.put(raw[i]); + } + os << "\n\\end_preamble\n"; + } if (!h_options.empty()) os << "\\options " << h_options << "\n"; os << "\\use_default_options " << h_use_default_options << "\n"; @@ -892,6 +925,7 @@ void Preamble::writeLyXHeader(ostream & os) << "\\begin_body\n"; // clear preamble for subdocuments h_preamble.str(""); + return true; } @@ -982,12 +1016,14 @@ void Preamble::parse(Parser & p, string const & forceclass, else if (t.cs() == "color") { string argument = p.getArg('{', '}'); // check the case that a standard color is used - if (is_known(argument, known_basic_colors)) - h_fontcolor = color2code(argument); + if (is_known(argument, known_basic_colors)) { + h_fontcolor = rgbcolor2code(argument); + preamble.registerAutomaticallyLoadedPackage("color"); + } else if (argument == "document_fontcolor") + preamble.registerAutomaticallyLoadedPackage("color"); // check the case that LyX's document_fontcolor is defined // but not used for \color - if (argument != "document_fontcolor" - && !is_known(argument, known_basic_colors)) { + else { h_preamble << t.asInput() << '{' << argument << '}'; // the color might already be set because \definecolor // is parsed before this @@ -998,12 +1034,13 @@ void Preamble::parse(Parser & p, string const & forceclass, else if (t.cs() == "pagecolor") { string argument = p.getArg('{', '}'); // check the case that a standard color is used - if (is_known(argument, known_basic_colors)) - h_backgroundcolor = color2code(argument); + if (is_known(argument, known_basic_colors)) { + h_backgroundcolor = rgbcolor2code(argument); + } else if (argument == "page_backgroundcolor") + preamble.registerAutomaticallyLoadedPackage("color"); // check the case that LyX's page_backgroundcolor is defined // but not used for \pagecolor - if (argument != "page_backgroundcolor" - && !is_known(argument, known_basic_colors)) { + else { h_preamble << t.asInput() << '{' << argument << '}'; // the color might already be set because \definecolor // is parsed before this @@ -1320,18 +1357,27 @@ void Preamble::parse(Parser & p, string const & forceclass, string const arg2 = p.verbatim_item(); string const arg3 = p.verbatim_item(); // test case \@ifundefined{date}{}{\date{}} - if (arg1 == "date" && arg2.empty() && arg3 == "\\date{}") { + if (t.cs() == "@ifundefined" && arg1 == "date" && + arg2.empty() && arg3 == "\\date{}") { h_suppress_date = "true"; - // test case \@ifundefined{definecolor}{\usepackage{color}}{} - // because we could pollute the preamble with it in roundtrips - } else if (arg1 == "definecolor" && arg2 == "\\usepackage{color}" - && arg3.empty()) { - ifundefined_color_set = true; + // older tex2lyx versions did output + // \@ifundefined{definecolor}{\usepackage{color}}{} + } else if (t.cs() == "@ifundefined" && + arg1 == "definecolor" && + arg2 == "\\usepackage{color}" && + arg3.empty()) { + if (!in_lyx_preamble) + h_preamble << package_beg_sep + << "color" + << package_mid_sep + << "\\@ifundefined{definecolor}{color}{}" + << package_end_sep; // test for case //\@ifundefined{showcaptionsetup}{}{% // \PassOptionsToPackage{caption=false}{subfig}} // that LyX uses for subfloats - } else if (arg1 == "showcaptionsetup" && arg2.empty() + } else if (t.cs() == "@ifundefined" && + arg1 == "showcaptionsetup" && arg2.empty() && arg3 == "%\n \\PassOptionsToPackage{caption=false}{subfig}") { ; // do nothing } else if (!in_lyx_preamble) { @@ -1384,12 +1430,16 @@ string babel2lyx(string const & language) } -string color2code(string const & name) +string rgbcolor2code(string const & name) { char const * const * where = is_known(name, known_basic_colors); - if (where) + if (where) { + // "red", "green" etc return known_basic_color_codes[where - known_basic_colors]; - return name; + } + // "255,0,0", "0,255,0" etc + RGBColor c(RGBColorFromLaTeX(name)); + return X11hexname(c); } // }]) diff --git a/src/tex2lyx/Preamble.h b/src/tex2lyx/Preamble.h index cc77f18b74..76d51758c7 100644 --- a/src/tex2lyx/Preamble.h +++ b/src/tex2lyx/Preamble.h @@ -18,6 +18,7 @@ #include #include #include +#include namespace lyx { @@ -33,12 +34,18 @@ public: /// std::string inputencoding() const { return h_inputencoding; } /// + std::string notefontcolor() const { return h_notefontcolor; } + /// bool indentParagraphs() const; /// bool isPackageUsed(std::string const & package) const; /// std::vector getPackageOptions(std::string const & package) const; + /// Tell that \p package will be loaded automatically by LyX. + /// This has only an effect if \p package is prepared for + /// autoloading in parse(). + void registerAutomaticallyLoadedPackage(std::string const & package); /// void addModule(std::string const & module); /// @@ -49,21 +56,19 @@ public: void parse(Parser & p, std::string const & forceclass, TeX2LyXDocClass & tc); /// Writes the LyX file header from internal data - void writeLyXHeader(std::ostream & os); + bool writeLyXHeader(std::ostream & os); private: /// std::map > used_packages; + /// Packages that will be loaded automatically by LyX + std::set auto_packages; /// std::vector used_modules; /// needed to handle encodings with babel bool one_language; - /// necessary to avoid that our preamble stuff is added at each - /// tex2lyx run which would pollute the preamble when doing roundtrips - bool ifundefined_color_set; - std::ostringstream h_preamble; std::string h_backgroundcolor; std::string h_boxbgcolor; diff --git a/src/tex2lyx/tex2lyx.cpp b/src/tex2lyx/tex2lyx.cpp index 5a2d299844..9697c41979 100644 --- a/src/tex2lyx/tex2lyx.cpp +++ b/src/tex2lyx/tex2lyx.cpp @@ -639,7 +639,7 @@ namespace { * You must ensure that \p parentFilePath is properly set before calling * this function! */ -void tex2lyx(idocstream & is, ostream & os, string encoding) +bool tex2lyx(idocstream & is, ostream & os, string encoding) { // Set a sensible default encoding. // This is used until an encoding command is found. @@ -677,7 +677,10 @@ void tex2lyx(idocstream & is, ostream & os, string encoding) for (; it != end; it++) preamble.addModule(*it); } - preamble.writeLyXHeader(os); + if (!preamble.writeLyXHeader(os)) { + cerr << "Could write LyX file header." << endl; + return false; + } ss.seekg(0); os << ss.str(); @@ -688,6 +691,7 @@ void tex2lyx(idocstream & is, ostream & os, string encoding) parsertest << p.get_token().asInput(); // and parsertest.tex should now have identical content #endif + return true; } @@ -705,9 +709,9 @@ bool tex2lyx(FileName const & infilename, ostream & os, string const & encoding) } string const oldParentFilePath = parentFilePath; parentFilePath = onlyPath(infilename.absFileName()); - tex2lyx(is, os, encoding); + bool retval = tex2lyx(is, os, encoding); parentFilePath = oldParentFilePath; - return true; + return retval; } } // anonymous namespace diff --git a/src/tex2lyx/tex2lyx.h b/src/tex2lyx/tex2lyx.h index 9bb47b56c3..f0ecf6173c 100644 --- a/src/tex2lyx/tex2lyx.h +++ b/src/tex2lyx/tex2lyx.h @@ -45,8 +45,8 @@ public: /// Translate babel language name to LyX language name extern std::string babel2lyx(std::string const & language); -/// translate color name to LyX color code -extern std::string color2code(std::string const & name); +/// Translate basic color name or RGB color in LaTeX syntax to LyX color code +extern std::string rgbcolor2code(std::string const & name); /// in text.cpp std::string translate_len(std::string const &); diff --git a/src/tex2lyx/text.cpp b/src/tex2lyx/text.cpp index 2def0865f4..15d5df2c2e 100644 --- a/src/tex2lyx/text.cpp +++ b/src/tex2lyx/text.cpp @@ -863,9 +863,10 @@ void parse_box(Parser & p, ostream & os, unsigned outer_flags, os << "Boxed\n"; else if (outer_type == "shadowbox") os << "Shadowbox\n"; - else if (outer_type == "shaded") + else if (outer_type == "shaded") { os << "Shaded\n"; - else if (outer_type == "doublebox") + preamble.registerAutomaticallyLoadedPackage("color"); + } else if (outer_type == "doublebox") os << "Doublebox\n"; else if (outer_type.empty()) os << "Frameless\n"; @@ -1166,6 +1167,8 @@ void parse_environment(Parser & p, ostream & os, bool outer, parse_text_in_inset(p, os, FLAG_END, outer, parent_context); end_inset(os); p.skip_spaces(); + if (!preamble.notefontcolor().empty()) + preamble.registerAutomaticallyLoadedPackage("color"); } else if (name == "framed" || name == "shaded") { @@ -1177,6 +1180,8 @@ void parse_environment(Parser & p, ostream & os, bool outer, else if (name == "lstlisting") { eat_whitespace(p, os, parent_context, false); // FIXME handle listings with parameters + // If this is added, don't forgot to handle the + // automatic color package loading if (p.hasOpt()) parse_unknown_environment(p, name, os, FLAG_END, outer, parent_context); @@ -2568,6 +2573,7 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, parse_text_snippet(p, os, FLAG_ITEM, outer, context); context.check_layout(os); os << "\n\\color inherit\n"; + preamble.registerAutomaticallyLoadedPackage("color"); } else // for custom defined colors handle_ert(os, t.asInput() + "{" + color + "}", context); -- 2.39.2