diff --git a/src/Buffer.cpp b/src/Buffer.cpp index 196d23d25e..2dcdefec53 100644 --- a/src/Buffer.cpp +++ b/src/Buffer.cpp @@ -1902,8 +1902,6 @@ void Buffer::writeLaTeXSource(otexstream & os, } // output_preamble - os.texrow().start(paragraphs().begin()->id(), 0); - LYXERR(Debug::INFO, "preamble finished, now the body."); // the real stuff @@ -2088,7 +2086,7 @@ void Buffer::writeLyXHTMLSource(odocstream & os, if (!styles.empty()) os << "\n\n" << styles << '\n'; - styles = features.getPreambleSnippets(); + styles = features.getPreambleSnippets().str; if (!styles.empty()) os << "\n\n" << styles << '\n'; diff --git a/src/BufferParams.cpp b/src/BufferParams.cpp index 775468ca44..85a8cbb663 100644 --- a/src/BufferParams.cpp +++ b/src/BufferParams.cpp @@ -1994,34 +1994,37 @@ bool BufferParams::writeLaTeX(otexstream & os, LaTeXFeatures & features, os << "\\usepackage[dot]{bibtopic}\n"; // Will be surrounded by \makeatletter and \makeatother when not empty - docstring atlyxpreamble; + otexstringstream atlyxpreamble; // Some macros LyX will need - docstring tmppreamble(features.getMacros()); - - if (!tmppreamble.empty()) - atlyxpreamble += "\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% " - "LyX specific LaTeX commands.\n" - + tmppreamble + '\n'; - + { + TexString tmppreamble = features.getMacros(); + if (!tmppreamble.str.empty()) + atlyxpreamble << "\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% " + "LyX specific LaTeX commands.\n" + << move(tmppreamble) + << '\n'; + } // the text class specific preamble - tmppreamble = features.getTClassPreamble(); - if (!tmppreamble.empty()) - atlyxpreamble += "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% " - "Textclass specific LaTeX commands.\n" - + tmppreamble + '\n'; - + { + docstring tmppreamble = features.getTClassPreamble(); + if (!tmppreamble.empty()) + atlyxpreamble << "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% " + "Textclass specific LaTeX commands.\n" + << tmppreamble + << '\n'; + } // suppress date if selected // use \@ifundefined because we cannot be sure that every document class // has a \date command if (suppress_date) - atlyxpreamble += "\\@ifundefined{date}{}{\\date{}}\n"; + atlyxpreamble << "\\@ifundefined{date}{}{\\date{}}\n"; /* the user-defined preamble */ if (!containsOnly(preamble, " \n\t")) { // FIXME UNICODE - atlyxpreamble += "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% " - "User specified LaTeX commands.\n"; + atlyxpreamble << "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% " + "User specified LaTeX commands.\n"; // Check if the user preamble contains uncodable glyphs odocstringstream user_preamble; @@ -2064,7 +2067,7 @@ bool BufferParams::writeLaTeX(otexstream & os, LaTeXFeatures & features, "preamble code accordingly."), uncodable_glyphs)); } - atlyxpreamble += user_preamble.str() + '\n'; + atlyxpreamble << user_preamble.str() << '\n'; } // footmisc must be loaded after setspace @@ -2072,7 +2075,7 @@ bool BufferParams::writeLaTeX(otexstream & os, LaTeXFeatures & features, // preamble. For that reason we also pass the options via // \PassOptionsToPackage in getPreamble() and not here. if (features.mustProvide("footmisc")) - atlyxpreamble += "\\usepackage{footmisc}\n"; + atlyxpreamble << "\\usepackage{footmisc}\n"; // subfig loads internally the LaTeX package "caption". As // caption is a very popular package, users will load it in @@ -2084,11 +2087,10 @@ bool BufferParams::writeLaTeX(otexstream & os, LaTeXFeatures & features, // koma's own caption commands are used instead of caption. We // use \PassOptionsToPackage here because the user could have // already loaded subfig in the preamble. - if (features.mustProvide("subfig")) { - atlyxpreamble += "\\@ifundefined{showcaptionsetup}{}{%\n" - " \\PassOptionsToPackage{caption=false}{subfig}}\n" - "\\usepackage{subfig}\n"; - } + if (features.mustProvide("subfig")) + atlyxpreamble << "\\@ifundefined{showcaptionsetup}{}{%\n" + " \\PassOptionsToPackage{caption=false}{subfig}}\n" + "\\usepackage{subfig}\n"; // Itemize bullet settings need to be last in case the user // defines their own bullets that use a package included @@ -2123,13 +2125,12 @@ bool BufferParams::writeLaTeX(otexstream & os, LaTeXFeatures & features, } if (!bullets_def.empty()) - atlyxpreamble += bullets_def + "}\n\n"; + atlyxpreamble << bullets_def << "}\n\n"; - if (!atlyxpreamble.empty()) { + if (!atlyxpreamble.empty()) os << "\n\\makeatletter\n" - << atlyxpreamble + << atlyxpreamble.release() << "\\makeatother\n\n"; - } // We try to load babel late, in case it interferes with other packages. // Jurabib, hyperref, varioref, bicaption and listings (bug 8995) have to be diff --git a/src/LaTeXFeatures.cpp b/src/LaTeXFeatures.cpp index c33b9121a3..cab81caadd 100644 --- a/src/LaTeXFeatures.cpp +++ b/src/LaTeXFeatures.cpp @@ -30,6 +30,8 @@ #include "Lexer.h" #include "LyXRC.h" #include "TextClass.h" +#include "TexRow.h" +#include "texstream.h" #include "insets/InsetLayout.h" @@ -586,26 +588,62 @@ bool LaTeXFeatures::isAvailable(string const & name) } -void LaTeXFeatures::addPreambleSnippet(docstring const & preamble, - bool allowdupes) +namespace { + +void addSnippet(std::list & list, TexString ts, bool allow_dupes) { - SnippetList::const_iterator begin = preamble_snippets_.begin(); - SnippetList::const_iterator end = preamble_snippets_.end(); - if (allowdupes || find(begin, end, preamble) == end) - preamble_snippets_.push_back(preamble); + if (allow_dupes || + // test the absense of duplicates, i.e. elements with same str + none_of(list.begin(), list.end(), [&](TexString const & ts2){ + return ts.str == ts2.str; + }) + ) + list.push_back(move(ts)); +} + + +TexString getSnippets(std::list const & list) +{ + otexstringstream snip; + for (TexString const & ts : list) + snip << TexString(ts) << '\n'; + return snip.release(); +} + +} //anon namespace + + +void LaTeXFeatures::addPreambleSnippet(TexString ts, bool allow_dupes) +{ + addSnippet(preamble_snippets_, move(ts), allow_dupes); +} + + +void LaTeXFeatures::addPreambleSnippet(docstring const & str, bool allow_dupes) +{ + addSnippet(preamble_snippets_, TexString(str), allow_dupes); } void LaTeXFeatures::addCSSSnippet(std::string const & snippet) { - docstring const u_snippet = from_ascii(snippet); - SnippetList::const_iterator begin = css_snippets_.begin(); - SnippetList::const_iterator end = css_snippets_.end(); - if (find(begin, end, u_snippet) == end) - css_snippets_.push_back(u_snippet); + addSnippet(css_snippets_, TexString(from_ascii(snippet)), false); } +TexString LaTeXFeatures::getPreambleSnippets() const +{ + return getSnippets(preamble_snippets_); +} + + +docstring LaTeXFeatures::getCSSSnippets() const +{ + return getSnippets(css_snippets_).str; +} + + + void LaTeXFeatures::useFloat(string const & name, bool subfloat) { if (!usedFloats_[name]) @@ -1151,31 +1189,9 @@ string const LaTeXFeatures::getPackages() const } -docstring LaTeXFeatures::getPreambleSnippets() const +TexString LaTeXFeatures::getMacros() const { - odocstringstream snip; - SnippetList::const_iterator pit = preamble_snippets_.begin(); - SnippetList::const_iterator pend = preamble_snippets_.end(); - for (; pit != pend; ++pit) - snip << *pit << '\n'; - return snip.str(); -} - - -docstring LaTeXFeatures::getCSSSnippets() const -{ - odocstringstream snip; - SnippetList::const_iterator pit = css_snippets_.begin(); - SnippetList::const_iterator pend = css_snippets_.end(); - for (; pit != pend; ++pit) - snip << *pit << '\n'; - return snip.str(); -} - - -docstring const LaTeXFeatures::getMacros() const -{ - odocstringstream macros; + otexstringstream macros; if (!preamble_snippets_.empty()) { macros << '\n'; @@ -1319,7 +1335,7 @@ docstring const LaTeXFeatures::getMacros() const macros << changetracking_dvipost_def; if (mustProvide("ct-xcolor-ulem")) { - streamsize const prec = macros.precision(2); + streamsize const prec = macros.os().precision(2); RGBColor cadd = rgbFromHexName(lcolor.getX11Name(Color_addedtext)); macros << "\\providecolor{lyxadded}{rgb}{" @@ -1329,7 +1345,7 @@ docstring const LaTeXFeatures::getMacros() const macros << "\\providecolor{lyxdeleted}{rgb}{" << cdel.r / 255.0 << ',' << cdel.g / 255.0 << ',' << cdel.b / 255.0 << "}\n"; - macros.precision(prec); + macros.os().precision(prec); if (isRequired("hyperref")) macros << changetracking_xcolor_ulem_hyperref_def; @@ -1343,7 +1359,7 @@ docstring const LaTeXFeatures::getMacros() const if (mustProvide("rtloutputdblcol")) macros << rtloutputdblcol_def; - return macros.str(); + return macros.release(); } @@ -1755,7 +1771,7 @@ void LaTeXFeatures::showStruct() const { lyxerr << "LyX needs the following commands when LaTeXing:" << "\n***** Packages:" << getPackages() - << "\n***** Macros:" << to_utf8(getMacros()) + << "\n***** Macros:" << to_utf8(getMacros().str) << "\n***** Textclass stuff:" << to_utf8(getTClassPreamble()) << "\n***** done." << endl; } @@ -1779,7 +1795,7 @@ BufferParams const & LaTeXFeatures::bufferParams() const } -void LaTeXFeatures::getFloatDefinitions(odocstream & os) const +void LaTeXFeatures::getFloatDefinitions(otexstream & os) const { FloatList const & floats = params_.documentClass().floats(); diff --git a/src/LaTeXFeatures.h b/src/LaTeXFeatures.h index 8216b9b462..4179856ae9 100644 --- a/src/LaTeXFeatures.h +++ b/src/LaTeXFeatures.h @@ -27,6 +27,7 @@ class Buffer; class BufferParams; class InsetLayout; class Language; +class TexString; /** The packages and commands that a buffer needs. This class * contains a list. Each of the LaTeX packages that a buffer needs @@ -60,7 +61,7 @@ public: /// The packages needed by the document std::string const getPackages() const; /// The macros definitions needed by the document - docstring const getMacros() const; + TexString getMacros() const; /// Extra preamble code before babel is called docstring const getBabelPresettings() const; /// Extra preamble code after babel is called @@ -84,13 +85,15 @@ public: /// Include a file for use with the SGML entities void includeFile(docstring const & key, std::string const & name); /// The float definitions. - void getFloatDefinitions(odocstream & os) const; + void getFloatDefinitions(otexstream & os) const; /// Print requirements to lyxerr void showStruct() const; - /// + /// Add preamble snippet with TexRow information + void addPreambleSnippet(TexString snippet, bool allowdupes = false); + /// Add preamble snippet without TexRow information void addPreambleSnippet(docstring const & snippet, bool allowdupes = false); /// - docstring getPreambleSnippets() const; + TexString getPreambleSnippets() const; /// void addCSSSnippet(std::string const &); /// @@ -174,7 +177,7 @@ private: /// Features features_; /// Static preamble bits, from external templates, or anywhere else - typedef std::list SnippetList; + typedef std::list SnippetList; /// SnippetList preamble_snippets_; /// diff --git a/src/Paragraph.cpp b/src/Paragraph.cpp index 8986d38c49..ce84dad177 100644 --- a/src/Paragraph.cpp +++ b/src/Paragraph.cpp @@ -1386,8 +1386,7 @@ void Paragraph::Private::validate(LaTeXFeatures & features) const // switching machinery of odocstream. Therefore the // output is wrong if this paragraph contains content // that needs to switch encoding. - odocstringstream ods; - otexstream os(ods); + otexstringstream os; if (is_command) { os << '\\' << from_ascii(layout_->latexname()); // we have to provide all the optional arguments here, even though @@ -1400,19 +1399,21 @@ void Paragraph::Private::validate(LaTeXFeatures & features) const } os << from_ascii(layout_->latexparam()); } - docstring::size_type const length = ods.str().length(); + size_t const length = os.length(); // this will output "{" at the beginning, but not at the end owner_->latex(bp, f, os, features.runparams(), 0, -1, true); - if (ods.str().length() > length) { + if (os.length() > length) { if (is_command) { - ods << '}'; + // FIXME: why does it has to be os.os() (equivalent to ods + // before)? + os.os() << '}'; if (!layout_->postcommandargs().empty()) { OutputParams rp = features.runparams(); rp.local_font = &owner_->getFirstFontSettings(bp); latexArgInsets(*owner_, os, rp, layout_->postcommandargs(), "post:"); } } - features.addPreambleSnippet(ods.str(), true); + features.addPreambleSnippet(os.release(), true); } } diff --git a/src/TexRow.cpp b/src/TexRow.cpp index 49712a955c..b3b1bd4938 100644 --- a/src/TexRow.cpp +++ b/src/TexRow.cpp @@ -34,6 +34,20 @@ using namespace std; namespace lyx { +TexString::TexString(docstring s) + : str(move(s)), texrow(TexRow()) +{ + texrow.setRows(1 + count(str.begin(), str.end(), '\n')); +} + + +TexString::TexString(docstring s, TexRow t) + : str(move(s)), texrow(move(t)) +{ + validate(); +} + + void TexString::validate() { size_t lines = 1 + count(str.begin(), str.end(), '\n'); diff --git a/src/TexRow.h b/src/TexRow.h index 382d566a76..7ce048e30b 100644 --- a/src/TexRow.h +++ b/src/TexRow.h @@ -199,7 +199,7 @@ private: /// TexString : dumb struct to pass around docstrings with TexRow information. -/// They are best created using oTexStringstream. +/// They are best created using otexstringstream. /// They can be output to otexrowstreams and otexstreams. /// A valid TexString has as many newlines in str as in texrow. Be careful not /// to introduce a mismatch between the line and the row counts, as this will @@ -221,9 +221,13 @@ struct TexString { //for gcc 4.6, nothing to do: it's enough to disable implicit copy during // dev with more recent versions of gcc. #endif - /// + /// Empty TexString TexString() = default; - /// ensure that the string and the TexRow have as many newlines. + /// Texstring containing str and TexRow with enough lines which are empty + explicit TexString(docstring str); + /// Texstring containing str and texrow. Must be valid. + TexString(docstring str, TexRow texrow); + /// Ensure that the string and the TexRow have as many newlines. void validate(); }; diff --git a/src/texstream.cpp b/src/texstream.cpp index eb1834b5de..5b0e927591 100644 --- a/src/texstream.cpp +++ b/src/texstream.cpp @@ -78,8 +78,9 @@ size_t otexstringstream::length() TexString otexstringstream::release() { - TexString ts{ods_.str(), TexRow()}; - swap(ts.texrow, texrow()); + TexString ts(ods_.str(), move(texrow())); + // reset this + texrow() = TexRow(); ods_.clear(); ods_.str(docstring()); return ts;