]> git.lyx.org Git - features.git/commitdiff
texstring and otexstringstream
authorGuillaume Munch <gm@lyx.org>
Sun, 4 Sep 2016 02:21:19 +0000 (03:21 +0100)
committerGuillaume Munch <gm@lyx.org>
Sun, 16 Oct 2016 22:16:59 +0000 (00:16 +0200)
texstring is a pair of a docstring and a corresponding TexRow. The row count in
the TexRow has to match the number of lines in the docstring.

otexstringstream is an output string stream that can be used to create
texstrings (i.e. it's an odocstringstream that records the TexRow information
and let us extract a texstring from it).

texstrings can be passed around and output to otexstream and otexrowstream,
which produces an accurate TexRow information by concatenating TexRows.

src/Paragraph.cpp
src/TexRow.cpp
src/TexRow.h
src/insets/InsetFloat.cpp
src/texstream.cpp
src/texstream.h

index 3bdb4cc7bdbc49f15df849956967573d8a26ec6a..3bae5bc1da7a3b518955d8433ce5379d81868cbf 100644 (file)
@@ -1118,7 +1118,7 @@ void Paragraph::Private::latexInset(BufferParams const & bparams,
                }
        }
 
-       int prev_rows = os.texrow().rows();
+       size_t const previous_row_count = os.texrow().rows();
 
        try {
                runparams.lastid = id_;
@@ -1138,7 +1138,7 @@ void Paragraph::Private::latexInset(BufferParams const & bparams,
                                os << '}';
        }
 
-       if (os.texrow().rows() > prev_rows) {
+       if (os.texrow().rows() > previous_row_count) {
                os.texrow().start(owner_->id(), i + 1);
                column = 0;
        } else {
index 6f0e8046c9a445393289b1ca66822b294df6b64e..49712a955c2eaf7af4ff408fc7c8f726f1aeaf3b 100644 (file)
@@ -34,13 +34,27 @@ using namespace std;
 namespace lyx {
 
 
+void TexString::validate()
+{
+       size_t lines = 1 + count(str.begin(), str.end(), '\n');
+       size_t rows = texrow.rows();
+       bool valid = lines == rows;
+       if (!valid)
+               LYXERR0("TexString has " << lines << " lines but " << rows << " rows." );
+       // Assert in devel mode.  This is important to catch bugs early, otherwise
+       // they might be hard to notice and find.  Recover gracefully in release
+       // mode.
+       LASSERT(valid, texrow.setRows(lines));
+}
+
+
 bool TexRow::RowEntryList::addEntry(RowEntry entry)
 {
        if (!entry.is_math) {
-               if (!isNone(text_entry_))
-                       return false;
-               else
+               if (isNone(text_entry_))
                        text_entry_ = entry.text;
+               else if (!v_.empty() && TexRow::sameParOrInsetMath(v_.back(), entry))
+                       return false;
        }
        forceAddEntry(entry);
        return true;
@@ -499,12 +513,18 @@ pair<int,int> TexRow::rowFromCursor(Cursor const & cur) const
 }
 
 
-int TexRow::rows() const
+size_t TexRow::rows() const
 {
        return rowlist_.size();
 }
 
 
+void TexRow::setRows(size_t r)
+{
+       rowlist_.resize(r, RowEntryList());
+}
+
+
 // debugging functions
 
 ///
@@ -544,7 +564,7 @@ void TexRow::prepend(docstring_list & tex) const
 LyXErr & operator<<(LyXErr & l, TexRow const & texrow)
 {
        if (l.enabled()) {
-               for (int i = 0; i < texrow.rows(); i++) {
+               for (size_t i = 0; i < texrow.rows(); i++) {
                        int id,pos;
                        if (texrow.getIdFromRow(i+1,id,pos) && id>0)
                                l << i+1 << ":" << id << ":" << pos << "\n";
index 4969f3a1d59c01204f725ac2f344cd29ccda6676..3ca51724f871aaac21f73d264aa0bb06c58e6d9b 100644 (file)
@@ -89,6 +89,14 @@ public:
        ///
        TexRow();
 
+       /// Copy can be expensive and is not usually useful for TexRow.
+       /// Force explicit copy, prefer move instead. This also prevents
+       /// move()s from being converted into copy silently.
+       explicit TexRow(TexRow const & other) = default;
+       TexRow(TexRow && other) = default;
+       TexRow & operator=(TexRow const & other) = default;
+       TexRow & operator=(TexRow && other) = default;
+
        /// Clears structure.
        void reset();
 
@@ -164,7 +172,9 @@ public:
        std::pair<int,int> rowFromCursor(Cursor const & dit) const;
 
        /// Returns the number of rows contained
-       int rows() const;
+       size_t rows() const;
+       /// Fill or trim to reach the row count \param r
+       void setRows(size_t r);
 
        /// appends texrow. the final line of this is merged with the first line of
        /// texrow.
@@ -183,6 +193,31 @@ private:
 };
 
 
+/// TexString : dumb struct to pass around docstrings with TexRow information.
+/// 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
+/// assert in devel mode when outputting to a otexstream.
+struct TexString {
+       ///
+       docstring str;
+       ///
+       TexRow texrow;
+       /// Copy can be expensive and is not usually useful for TexString.
+       /// Force explicit copy, prefer move instead. This also prevents
+       /// move()s from being converted into copy silently.
+       explicit TexString(TexString const &) = default;
+       TexString(TexString && other) = default;
+       TexString & operator=(TexString const & other) = default;
+       TexString & operator=(TexString && other) = default;
+       ///
+       TexString() = default;
+       /// ensure that the string and the TexRow have as many newlines.
+       void validate();
+};
+
+
 // Standard container needs a complete type
 class TexRow::RowEntryList {
        // For each row we store a list of one special TextEntry and several
index 49fd3bb00844692b4b24aa830582704330581f49..5d966af31ff992ee3208e17be0cd5ad6c90c4c94 100644 (file)
@@ -516,14 +516,14 @@ void InsetFloat::getCaption(otexstream & os,
        ins->getArgs(os, runparams);
 
        os << '[';
-       odocstringstream ods;
-       otexstream oss(ods);
-       ins->getArgument(oss, runparams);
-       docstring arg = ods.str();
+       otexstringstream os2;
+       ins->getArgument(os2, runparams);
+       TexString ts = os2.release();
+       docstring & arg = ts.str;
        // Protect ']'
        if (arg.find(']') != docstring::npos)
                arg = '{' + arg + '}';
-       os.append(arg, move(oss.texrow()));
+       os << move(ts);
        os << ']';
 }
 
index e312d2cdbc8354a4f01f2530ef174ba72791c9af..be1168a7e815e5536bdda3f5b083830060b6d660 100644 (file)
@@ -49,13 +49,6 @@ unique_ptr<TexRow> otexrowstream::releaseTexRow()
 }
 
 
-void otexrowstream::append(docstring const & str, TexRow texrow)
-{
-       os_ << str;
-       texrow_->append(move(texrow));
-}
-
-
 void otexrowstream::put(char_type const & c)
 {
        os_.put(c);
@@ -76,6 +69,22 @@ void otexstream::put(char_type const & c)
 }
 
 
+size_t otexstringstream::length()
+{
+       auto pos = ods_.tellp();
+       return (pos >= 0) ? size_t(pos) : 0;
+}
+
+
+TexString otexstringstream::release()
+{
+       TexString ts{ods_.str(), TexRow()};
+       swap(ts.texrow, texrow());
+       ods_ = odocstringstream();
+       return ts;
+}
+
+
 BreakLine breakln;
 SafeBreakLine safebreakln;
 
@@ -112,6 +121,7 @@ otexrowstream & operator<<(otexrowstream & ots, odocstream_manip pf)
        return ots;
 }
 
+
 otexstream & operator<<(otexstream & ots, odocstream_manip pf)
 {
        otexrowstream & otrs = ots;
@@ -123,6 +133,38 @@ otexstream & operator<<(otexstream & ots, odocstream_manip pf)
 }
 
 
+otexrowstream & operator<<(otexrowstream & ots, TexString ts)
+{
+       ts.validate();
+       ots.os() << move(ts.str);
+       ots.texrow().append(move(ts.texrow));
+       return ots;
+}
+
+
+otexstream & operator<<(otexstream & ots, TexString ts)
+{
+       size_t const len = ts.str.length();
+       // Check whether there is something to output
+       if (len == 0)
+               return ots;
+
+       otexrowstream & otrs = ots;
+       if (ots.protectSpace()) {
+               if (!ots.canBreakLine() && ts.str[0] == ' ')
+                       otrs << "{}";
+               ots.protectSpace(false);
+       }
+
+       if (len > 1)
+               ots.canBreakLine(ts.str[len - 2] != '\n');
+       ots.lastChar(ts.str[len - 1]);
+
+       otrs << move(ts);
+       return ots;
+}
+
+
 otexrowstream & operator<<(otexrowstream & ots, docstring const & s)
 {
        ots.os() << s;
index 53040d1b7f4745c036e3ed213ee4aef4a2a87e06..9c882b9d8914100a045bdf89b6762a63b57121f8 100644 (file)
 namespace lyx {
 
 class TexRow;
+class TexString;
 
 
-// declared below
-class otexstringstream;
-
 /** Wrapper class for odocstream.
     This class is used to automatically count the lines of the exported latex
     code.
@@ -43,7 +41,7 @@ public:
        ///
        void put(char_type const & c);
        ///
-       void append(docstring const & str, TexRow texrow);
+       void append(TexString ts);
 private:
        ///
        odocstream & os_;
@@ -54,6 +52,8 @@ private:
 ///
 otexrowstream & operator<<(otexrowstream &, odocstream_manip);
 ///
+otexrowstream & operator<<(otexrowstream &, TexString);
+///
 otexrowstream & operator<<(otexrowstream &, docstring const &);
 ///
 otexrowstream & operator<<(otexrowstream &, std::string const &);
@@ -85,6 +85,8 @@ public:
        ///
        void put(char_type const & c);
        ///
+       void append(TexString ts);
+       ///
        void canBreakLine(bool breakline) { canbreakline_ = breakline; }
        ///
        bool canBreakLine() const { return canbreakline_; }
@@ -114,6 +116,25 @@ private:
        char_type lastchar_;
 };
 
+
+/// because we need to pass ods_ to the base class
+struct otexstringstream_helper { odocstringstream ods_; };
+
+/// otexstringstream : a odocstringstream with tex/row correspondence
+class otexstringstream : otexstringstream_helper, public otexstream {
+public:
+       otexstringstream() : otexstringstream_helper(), otexstream(ods_) {}
+       ///
+       docstring str() const { return ods_.str(); }
+       ///
+       size_t length();
+       ///
+       bool empty() { return 0 == length(); }
+       /// move-returns the contents and reset the texstream
+       TexString release();
+};
+
+
 /// Helper structs for breaking a line
 struct BreakLine {
        char n;
@@ -133,6 +154,8 @@ otexstream & operator<<(otexstream &, SafeBreakLine);
 ///
 otexstream & operator<<(otexstream &, odocstream_manip);
 ///
+otexstream & operator<<(otexstream &, TexString);
+///
 otexstream & operator<<(otexstream &, docstring const &);
 ///
 otexstream & operator<<(otexstream &, std::string const &);