commit 1f6c451ee3e41f31464cabcdabceb23045443175
Author: Guillaume Munch <g...@lyx.org>
Date:   Sun Sep 25 12:38:53 2016 +0200

    TexRow for InPreamble
    
    This enables error reporting for the preamble, provided the preamble is 
written
    using the new InPreamble layouts.
    
    In the future, I find it preferable to deprecate the usual preamble in 
favour of
    InPreamble layouts rather than implementing error reporting for the usual
    preamble. This requires some improvements to code editing in the buffer view
    first (line breaking behaviour, syntax highlighting).
---
 src/Buffer.cpp        |    4 +--
 src/BufferParams.cpp  |   57 +++++++++++++++--------------
 src/LaTeXFeatures.cpp |   96 ++++++++++++++++++++++++++++--------------------
 src/LaTeXFeatures.h   |   13 ++++---
 src/Paragraph.cpp     |   13 ++++---
 src/TexRow.cpp        |   14 +++++++
 src/TexRow.h          |   10 ++++--
 src/texstream.cpp     |    5 ++-
 8 files changed, 125 insertions(+), 87 deletions(-)

diff --git a/src/Buffer.cpp b/src/Buffer.cpp
index 196d23d..2dcdefe 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<!-- Text Class Preamble -->\n" << styles << 
'\n';
 
-               styles = features.getPreambleSnippets();
+               styles = features.getPreambleSnippets().str;
                if (!styles.empty())
                        os << "\n<!-- Preamble Snippets -->\n" << styles << 
'\n';
 
diff --git a/src/BufferParams.cpp b/src/BufferParams.cpp
index 775468c..85a8cbb 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 c33b912..cab81ca 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<TexString> & 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<TexString> 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
-{
-       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
+TexString 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 8216b9b..4179856 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<string>.  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<docstring> SnippetList;
+       typedef std::list<TexString> SnippetList;
        ///
        SnippetList preamble_snippets_;
        ///
diff --git a/src/Paragraph.cpp b/src/Paragraph.cpp
index 8986d38..ce84dad 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 49712a9..b3b1bd4 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 382d566..7ce048e 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 eb1834b..5b0e927 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;

Reply via email to