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.

Reply via email to