commit afed7d06fa6c932a1a1578b76371189a7e17825e
Author: Guillaume Munch <[email protected]>
Date: Tue Sep 15 05:56:01 2015 +0100
Improvements to cursor highlighting in the source panel
* TexRow now computes rows from a DocIterator. In practice, the cursor
highlighting is now correct inside insets, it is no longer restricted to
the
topmost level. It certainly also makes forward-search more precise.
* Added the option to disable a texrow when not needed, for perf.
* Fixed a bug where the last paragraph was not properly highlighted.
Limitations:
* TexRow still does not handle: math (e.g. multi-cell), sub-captions, inset
arguments.
diff --git a/src/Buffer.cpp b/src/Buffer.cpp
index 6eea29a..f7f12c8 100644
--- a/src/Buffer.cpp
+++ b/src/Buffer.cpp
@@ -1842,14 +1842,7 @@ void Buffer::writeLaTeXSource(otexstream & os,
}
runparams_in.encoding = runparams.encoding;
- // Just to be sure. (Asger)
- os.texrow().newline();
-
- //for (int i = 0; i<d->texrow.rows(); i++) {
- // int id,pos;
- // if (d->texrow.getIdFromRow(i+1,id,pos) && id>0)
- // lyxerr << i+1 << ":" << id << ":" <<
getParFromID(id).paragraph().asString()<<"\n";
- //}
+ os.texrow().finalize();
LYXERR(Debug::INFO, "Finished making LaTeX file.");
LYXERR(Debug::INFO, "Row count was " << os.texrow().rows() - 1 << '.');
@@ -1886,7 +1879,7 @@ void Buffer::writeDocBookSource(odocstream & os, string
const & fname,
LaTeXFeatures features(*this, params(), runparams);
validate(features);
- d->texrow.reset();
+ d->texrow.reset(false);
DocumentClass const & tclass = params().documentClass();
string const & top_element = tclass.latexname();
@@ -3570,7 +3563,6 @@ auto_ptr<TexRow> Buffer::getSourceCode(odocstream & os,
string const & format,
params().validate(features);
runparams.use_polyglossia = features.usePolyglossia();
texrow.reset(new TexRow());
- texrow->reset();
texrow->newline();
texrow->newline();
// latex or literate
@@ -3578,6 +3570,7 @@ auto_ptr<TexRow> Buffer::getSourceCode(odocstream & os,
string const & format,
// the real stuff
latexParagraphs(*this, text(), ots, runparams);
+ texrow->finalize();
// Restore the parenthood
if (!master)
@@ -3613,13 +3606,13 @@ auto_ptr<TexRow> Buffer::getSourceCode(odocstream & os,
string const & format,
} else {
// latex or literate
texrow.reset(new TexRow());
- texrow->reset();
texrow->newline();
texrow->newline();
otexstream ots(os, *texrow);
if (master)
runparams.is_child = true;
writeLaTeXSource(ots, string(), runparams, output);
+ texrow->finalize();
}
}
return texrow;
diff --git a/src/TexRow.cpp b/src/TexRow.cpp
index 780cd52..173634b 100644
--- a/src/TexRow.cpp
+++ b/src/TexRow.cpp
@@ -12,6 +12,8 @@
#include <config.h>
+#include "DocIterator.h"
+#include "Paragraph.h"
#include "TexRow.h"
#include "support/debug.h"
@@ -22,19 +24,19 @@
namespace lyx {
-void TexRow::reset()
+void TexRow::reset(bool enable)
{
rowlist.clear();
lastid = -1;
lastpos = -1;
+ enabled_ = enable;
}
void TexRow::start(int id, int pos)
{
- if (started)
+ if (!enabled_ || started)
return;
-
lastid = id;
lastpos = pos;
started = true;
@@ -43,19 +45,29 @@ void TexRow::start(int id, int pos)
void TexRow::newline()
{
- int const id = lastid;
- RowList::value_type tmp(id, lastpos);
+ if (!enabled_)
+ return;
+ RowList::value_type tmp(lastid, lastpos);
rowlist.push_back(tmp);
started = false;
}
void TexRow::newlines(int num_lines)
{
+ if (!enabled_)
+ return;
for (int i = 0; i < num_lines; ++i) {
newline();
}
}
+void TexRow::finalize()
+{
+ if (!enabled_)
+ return;
+ newline();
+}
+
bool TexRow::getIdFromRow(int row, int & id, int & pos) const
{
if (row <= 0 || row > int(rowlist.size())) {
@@ -70,27 +82,64 @@ bool TexRow::getIdFromRow(int row, int & id, int & pos)
const
}
-int TexRow::getRowFromIdPos(int id, int pos) const
+std::pair<int,int> TexRow::rowFromDocIterator(DocIterator const & dit) const
{
- bool foundid = false;
-
- // this loop finds the last *nonempty* row with the same id
- // and position <= pos
- RowList::const_iterator bestrow = rowlist.begin();
+ bool found = false;
+ size_t best_slice = 0;
+ size_t const n = dit.depth();
+ // this loop finds the last row of the topmost possible CursorSlice
+ RowList::const_iterator best_beg_row = rowlist.begin();
+ RowList::const_iterator best_end_row = rowlist.begin();
RowList::const_iterator it = rowlist.begin();
RowList::const_iterator const end = rowlist.end();
for (; it != end; ++it) {
- if (it->id() == id && it->pos() <= pos) {
- foundid = true;
- if (bestrow->id() != id || it->pos() > bestrow->pos())
- bestrow = it;
- } else if (foundid)
- break;
+ if (found) {
+ // Compute the best end row. It is the one that matches
pos+1.
+ CursorSlice const & best = dit[best_slice];
+ if (best.text()
+ && it->id() == best.paragraph().id()
+ && it->pos() == best.pos() + 1
+ && (best_end_row->id() != it->id()
+ || best_end_row->pos() < it->pos()))
+ best_end_row = it;
+ }
+ for (size_t i = best_slice; i < n && dit[i].text(); ++i) {
+ int const id = dit[i].paragraph().id();
+ if (it->id() == id) {
+ if (it->pos() <= dit[i].pos()
+ && (best_beg_row->id() != id
+ || it->pos() >
best_beg_row->pos())) {
+ found = true;
+ best_slice = i;
+ best_beg_row = best_end_row = it;
+ }
+ //found CursorSlice
+ break;
+ }
+ }
}
- if (!foundid)
- return rowlist.size();
- return distance(rowlist.begin(), bestrow) + 1;
+ if (!found)
+ return std::make_pair(-1,-1);
+ int const beg_i = distance(rowlist.begin(), best_beg_row) + 1;
+ // remove one to the end
+ int const end_i = std::max(beg_i,
+
(int)distance(rowlist.begin(), best_end_row));
+ return std::make_pair(beg_i,end_i);
}
+LyXErr & operator<<(LyXErr & l, TexRow & texrow)
+{
+ if (l.enabled()) {
+ for (int i = 0; i < texrow.rows(); i++) {
+ int id,pos;
+ if (texrow.getIdFromRow(i+1,id,pos) && id>0)
+ l << i+1 << ":" << id << ":" << pos << "\n";
+ }
+ }
+ return l;
+}
+
+
+
} // namespace lyx
diff --git a/src/TexRow.h b/src/TexRow.h
index a4edc6c..254f446 100644
--- a/src/TexRow.h
+++ b/src/TexRow.h
@@ -14,11 +14,14 @@
#ifndef TEXROW_H
#define TEXROW_H
-#include <vector>
+#include "support/debug.h"
+#include <vector>
namespace lyx {
+class LyXErr;
+class DocIterator;
/// Represents the correspondence between paragraphs and the generated
/// LaTeX file
@@ -26,10 +29,13 @@ namespace lyx {
class TexRow {
public:
///
- TexRow() : lastid(-1), lastpos(-1), started(false) {}
+ TexRow(bool enable = true)
+ : lastid(-1), lastpos(-1), started(false), enabled_(enable) {}
/// Clears structure
- void reset();
+ /// TexRow is often computed to be immediately discarded. Set enable to
+ /// false if texrow is not needed
+ void reset(bool enable = true);
/// Define what paragraph and position the next row will represent
void start(int id, int pos);
@@ -40,6 +46,9 @@ public:
/// Insert multiple nodes when zero or more lines are completed
void newlines(int num_lines);
+ /// Call when code generation is complete
+ void finalize();
+
/**
* getIdFromRow - find pid and position for a given row
* @param row row number to find
@@ -52,13 +61,9 @@ public:
*/
bool getIdFromRow(int row, int & id, int & pos) const;
- /**
- * getRowFromIdPos - find row containing a given id and pos
- * @param id of the paragraph
- * @param pos a given position in that paragraph
- * @return the row number within the rowlist
- */
- int getRowFromIdPos(int id, int pos) const;
+ /// Finds the best pair of rows for dit
+ /// returns (-1,-1) if not found.
+ std::pair<int,int> rowFromDocIterator(DocIterator const & dit) const;
/// Returns the number of rows contained
int rows() const { return rowlist.size(); }
@@ -92,8 +97,12 @@ private:
int lastpos;
/// Is id/pos already registered for current row?
bool started;
+ ///
+ bool enabled_;
};
+LyXErr & operator<<(LyXErr &, TexRow &);
+
} // namespace lyx
diff --git a/src/frontends/qt4/GuiView.cpp b/src/frontends/qt4/GuiView.cpp
index b3a697c..32a9a98 100644
--- a/src/frontends/qt4/GuiView.cpp
+++ b/src/frontends/qt4/GuiView.cpp
@@ -3976,15 +3976,11 @@ void GuiView::dispatch(FuncRequest const & cmd,
DispatchResult & dr)
command = lyxrc.forward_search_pdf;
}
- DocIterator tmpcur = bv->cursor();
- // Leave math first
- while (tmpcur.inMathed())
- tmpcur.pop_back();
- int row = tmpcur.inMathed() ? 0 :
doc_buffer->texrow().getRowFromIdPos(
-
tmpcur.paragraph().id(), tmpcur.pos());
+ DocIterator cur = bv->cursor();
+ int row =
doc_buffer->texrow().rowFromDocIterator(cur).first;
LYXERR(Debug::ACTION, "Forward search: row:" << row
- << " id:" << tmpcur.paragraph().id());
- if (!row || command.empty()) {
+ << " cur:" << cur);
+ if (row == -1 || command.empty()) {
dr.setMessage(_("Couldn't proceed."));
break;
}
diff --git a/src/frontends/qt4/GuiViewSource.cpp
b/src/frontends/qt4/GuiViewSource.cpp
index 799bf40..1695664 100644
--- a/src/frontends/qt4/GuiViewSource.cpp
+++ b/src/frontends/qt4/GuiViewSource.cpp
@@ -110,7 +110,8 @@ auto_ptr<TexRow> ViewSourceWidget::getContent(BufferView
const * view,
odocstringstream ostr;
auto_ptr<TexRow> texrow = view->buffer().getSourceCode(ostr, format,
par_begin,
par_end + 1, output, master);
- str = ostr.str();
+ //ensure that the last line can always be selected in its full width
+ str = ostr.str() + "\n";
return texrow;
}
@@ -229,35 +230,20 @@ void ViewSourceWidget::realUpdateView()
} else if (texrow.get()) {
// Use the available position-to-row conversion to highlight
// the current selection in the source
- //
- // FIXME:
- // * it is currently impossible to highlight the very last line
- // of a document, because TexRow gives the wrong data.
- // * we currently only compute the top-level position, which
- // makes it impossible to highlight inside an inset. It is not
- // a limitation of TexRow, but replacing bottom() with top()
- // works partially and causes segfaults with math. Solving
- // this could be seen as a solution to #4725.
- // * even if we keep computing the top-level position, the data
- // given by TexRow is false if there is e.g. a float of a
- // footnote in the paragraph
- CursorSlice beg = bv_->cursor().selectionBegin().bottom();
- CursorSlice end = bv_->cursor().selectionEnd().bottom();
- int const beg_par = beg.paragraph().id();
- int const end_par = end.paragraph().id();
- int const beg_pos = beg.pos();
- int const end_pos = end.pos();
- int const beg_row = texrow->getRowFromIdPos(beg_par, beg_pos);
- int end_row, next_end_row;
- if (beg_par != end_par || beg_pos != end_pos) {
- end_row = texrow->getRowFromIdPos(end_par, max(0,
end_pos - 1));
- next_end_row = texrow->getRowFromIdPos(end_par,
end_pos);
- } else {
- end_row = beg_row;
- next_end_row = texrow->getRowFromIdPos(beg_par, beg_pos
+ 1);
+ int beg_row, end_row;
+ {
+ DocIterator beg = bv_->cursor().selectionBegin();
+ DocIterator end = bv_->cursor().selectionEnd();
+ std::pair<int,int> beg_rows =
texrow->rowFromDocIterator(beg);
+ beg_row = beg_rows.first;
+ if (beg != end) {
+ end.backwardChar();
+ std::pair<int,int> end_rows =
texrow->rowFromDocIterator(end);
+ end_row = end_rows.second;
+ } else {
+ end_row = beg_rows.second;
+ }
}
- if (end_row != next_end_row)
- end_row = next_end_row - 1;
QTextCursor c = QTextCursor(viewSourceTV->document());
@@ -303,7 +289,7 @@ void ViewSourceWidget::realUpdateView()
c.clearSelection();
viewSourceTV->setTextCursor(c);
viewSourceTV->horizontalScrollBar()->setValue(h_scroll);
- }
+ } // else if (texrow)
}
diff --git a/src/lyxfind.cpp b/src/lyxfind.cpp
index 11aebd2..aedbc53 100644
--- a/src/lyxfind.cpp
+++ b/src/lyxfind.cpp
@@ -729,7 +729,7 @@ private:
static docstring buffer_to_latex(Buffer & buffer)
{
OutputParams runparams(&buffer.params().encoding());
- TexRow texrow;
+ TexRow texrow(false);
odocstringstream ods;
otexstream os(ods, texrow);
runparams.nice = true;
@@ -1051,7 +1051,7 @@ docstring latexifyFromCursor(DocIterator const & cur, int
len)
Buffer const & buf = *cur.buffer();
LBUFERR(buf.params().isLatex());
- TexRow texrow;
+ TexRow texrow(false);
odocstringstream ods;
otexstream os(ods, texrow);
OutputParams runparams(&buf.params().encoding());
@@ -1399,7 +1399,7 @@ static void findAdvReplace(BufferView * bv,
FindAndReplaceOptions const & opt, M
LYXERR(Debug::FIND, "After pasteParagraphList() cur=" << cur <<
endl);
sel_len = repl_buffer.paragraphs().begin()->size();
} else if (cur.inMathed()) {
- TexRow texrow;
+ TexRow texrow(false);
odocstringstream ods;
otexstream os(ods, texrow);
OutputParams runparams(&repl_buffer.params().encoding());
diff --git a/src/output_latex.cpp b/src/output_latex.cpp
index c14e8ee..feb51a0 100644
--- a/src/output_latex.cpp
+++ b/src/output_latex.cpp
@@ -24,7 +24,6 @@
#include "Paragraph.h"
#include "ParagraphParameters.h"
#include "TextClass.h"
-#include "TexRow.h"
#include "insets/InsetBibitem.h"
#include "insets/InsetArgument.h"
diff --git a/src/output_latex.h b/src/output_latex.h
index 1f3afff..8bfeb6a 100644
--- a/src/output_latex.h
+++ b/src/output_latex.h
@@ -27,7 +27,6 @@ class Encoding;
class Layout;
class Paragraph;
class OutputParams;
-class TexRow;
class Text;
/** Export optional and required arguments of the paragraph \p par.