From: Guillaume Munch Date: Sun, 4 Sep 2016 02:21:19 +0000 (+0100) Subject: texstring and otexstringstream X-Git-Tag: 2.3.0alpha1~880 X-Git-Url: https://git.lyx.org/gitweb/?a=commitdiff_plain;h=f3256ee2cddabbe8d763013525c3e27f6ad0b3dc;p=features.git texstring and otexstringstream 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. --- diff --git a/src/Paragraph.cpp b/src/Paragraph.cpp index 3bdb4cc7bd..3bae5bc1da 100644 --- a/src/Paragraph.cpp +++ b/src/Paragraph.cpp @@ -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 { diff --git a/src/TexRow.cpp b/src/TexRow.cpp index 6f0e8046c9..49712a955c 100644 --- a/src/TexRow.cpp +++ b/src/TexRow.cpp @@ -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 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"; diff --git a/src/TexRow.h b/src/TexRow.h index 4969f3a1d5..3ca51724f8 100644 --- a/src/TexRow.h +++ b/src/TexRow.h @@ -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 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 diff --git a/src/insets/InsetFloat.cpp b/src/insets/InsetFloat.cpp index 49fd3bb008..5d966af31f 100644 --- a/src/insets/InsetFloat.cpp +++ b/src/insets/InsetFloat.cpp @@ -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 << ']'; } diff --git a/src/texstream.cpp b/src/texstream.cpp index e312d2cdbc..be1168a7e8 100644 --- a/src/texstream.cpp +++ b/src/texstream.cpp @@ -49,13 +49,6 @@ unique_ptr 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; diff --git a/src/texstream.h b/src/texstream.h index 53040d1b7f..9c882b9d89 100644 --- a/src/texstream.h +++ b/src/texstream.h @@ -18,11 +18,9 @@ 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 &);