mirror of
https://git.lyx.org/repos/lyx.git
synced 2024-11-25 19:07:45 +00:00
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.
This commit is contained in:
parent
d5a5fbb8ee
commit
afed7d06fa
@ -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;
|
||||
|
@ -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)
|
||||
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
|
||||
|
29
src/TexRow.h
29
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
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
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_row;
|
||||
next_end_row = texrow->getRowFromIdPos(beg_par, beg_pos + 1);
|
||||
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)
|
||||
}
|
||||
|
||||
|
||||
|
@ -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());
|
||||
|
@ -24,7 +24,6 @@
|
||||
#include "Paragraph.h"
|
||||
#include "ParagraphParameters.h"
|
||||
#include "TextClass.h"
|
||||
#include "TexRow.h"
|
||||
|
||||
#include "insets/InsetBibitem.h"
|
||||
#include "insets/InsetArgument.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.
|
||||
|
Loading…
Reference in New Issue
Block a user