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.
This commit is contained in:
Guillaume Munch 2016-09-04 03:21:19 +01:00
parent 79fd549621
commit f3256ee2cd
6 changed files with 144 additions and 24 deletions

View 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 {

View 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";

View 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

View 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 << ']';
}

View 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;

View File

@ -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 &);