X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Fdociterator.C;h=bb72fb6c2d71c669dffc61b936fc3a36c9e4beaa;hb=0da3d53269a49c66b24615d24e20e441dcf7c07e;hp=e1667ec91489f884a6c4a40aa6aa3ea6907b4f46;hpb=bddfd8ff662d7c9e750f6d7713e4b3d62f92efc4;p=lyx.git diff --git a/src/dociterator.C b/src/dociterator.C index e1667ec914..bb72fb6c2d 100644 --- a/src/dociterator.C +++ b/src/dociterator.C @@ -1,355 +1,526 @@ +/** + * \file dociterator.C + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author André Pönitz + * + * Full author contact details are available in file CREDITS. + */ + + +#include #include "dociterator.h" #include "debug.h" #include "lyxtext.h" -#include "lyxrow.h" #include "paragraph.h" -#include "mathed/math_data.h" -#include "mathed/math_inset.h" +#include "mathed/MathData.h" +#include "mathed/InsetMath.h" + +#include "insets/insettabular.h" #include +#include + + +namespace lyx { + +using std::endl; + + +// We could be able to get rid of this if only every BufferView were +// associated to a buffer on construction. +DocIterator::DocIterator() + : boundary_(false), inset_(0) +{} -DocumentIterator::DocumentIterator() +DocIterator::DocIterator(InsetBase & inset) + : boundary_(false), inset_(&inset) {} -DocumentIterator::DocumentIterator(InsetBase & inset) +DocIterator doc_iterator_begin(InsetBase & inset) { - push_back(CursorSlice(inset)); + DocIterator dit(inset); + dit.forwardPos(); + return dit; +} + + +DocIterator doc_iterator_end(InsetBase & inset) +{ + return DocIterator(inset); } -InsetBase * DocumentIterator::nextInset() +InsetBase * DocIterator::nextInset() { + BOOST_ASSERT(!empty()); if (pos() == lastpos()) return 0; - if (inMathed()) + if (pos() > lastpos()) { + lyxerr << "Should not happen, but it does. " << endl; + return 0; + } + if (inMathed()) return nextAtom().nucleus(); return paragraph().isInset(pos()) ? paragraph().getInset(pos()) : 0; } -InsetBase * DocumentIterator::prevInset() +InsetBase * DocIterator::prevInset() { + BOOST_ASSERT(!empty()); if (pos() == 0) return 0; - if (inMathed()) + if (inMathed()) return prevAtom().nucleus(); return paragraph().isInset(pos() - 1) ? paragraph().getInset(pos() - 1) : 0; } -InsetBase const * DocumentIterator::prevInset() const +InsetBase const * DocIterator::prevInset() const { + BOOST_ASSERT(!empty()); if (pos() == 0) return 0; - if (inMathed()) + if (inMathed()) return prevAtom().nucleus(); return paragraph().isInset(pos() - 1) ? paragraph().getInset(pos() - 1) : 0; } -MathAtom const & DocumentIterator::prevAtom() const +InsetBase * DocIterator::realInset() const { + BOOST_ASSERT(inTexted()); + // if we are in a tabular, we need the cell + if (inset().lyxCode() == InsetBase::TABULAR_CODE) { + InsetTabular & tabular = static_cast(inset()); + return tabular.cell(idx()).get(); + } + return &inset(); +} + + +MathAtom const & DocIterator::prevAtom() const +{ + BOOST_ASSERT(!empty()); BOOST_ASSERT(pos() > 0); return cell()[pos() - 1]; } -MathAtom & DocumentIterator::prevAtom() +MathAtom & DocIterator::prevAtom() { + BOOST_ASSERT(!empty()); BOOST_ASSERT(pos() > 0); return cell()[pos() - 1]; } -MathAtom const & DocumentIterator::nextAtom() const +MathAtom const & DocIterator::nextAtom() const { + BOOST_ASSERT(!empty()); + //lyxerr << "lastpos: " << lastpos() << " next atom:\n" << *this << endl; BOOST_ASSERT(pos() < lastpos()); return cell()[pos()]; } -MathAtom & DocumentIterator::nextAtom() +MathAtom & DocIterator::nextAtom() { + BOOST_ASSERT(!empty()); + //lyxerr << "lastpos: " << lastpos() << " next atom:\n" << *this << endl; BOOST_ASSERT(pos() < lastpos()); return cell()[pos()]; } -LyXText * DocumentIterator::text() const +LyXText * DocIterator::text() { + BOOST_ASSERT(!empty()); return top().text(); } - -Paragraph & DocumentIterator::paragraph() +LyXText const * DocIterator::text() const { - BOOST_ASSERT(inTexted()); - return top().paragraph(); + BOOST_ASSERT(!empty()); + return top().text(); } -Paragraph const & DocumentIterator::paragraph() const +Paragraph & DocIterator::paragraph() { + if (!inTexted()) + lyxerr << *this << endl; BOOST_ASSERT(inTexted()); return top().paragraph(); } -Row & DocumentIterator::textRow() +Paragraph const & DocIterator::paragraph() const { - return *paragraph().getRow(pos()); -} - - -Row const & DocumentIterator::textRow() const -{ - return *paragraph().getRow(pos()); + BOOST_ASSERT(inTexted()); + return top().paragraph(); } -DocumentIterator::par_type DocumentIterator::lastpar() const +pit_type DocIterator::lastpit() const { return inMathed() ? 0 : text()->paragraphs().size() - 1; } -DocumentIterator::pos_type DocumentIterator::lastpos() const +pos_type DocIterator::lastpos() const { return inMathed() ? cell().size() : paragraph().size(); } -DocumentIterator::row_type DocumentIterator::crow() const -{ - return paragraph().row(pos()); -} - - -DocumentIterator::row_type DocumentIterator::lastcrow() const -{ - return paragraph().rows.size(); -} - - -DocumentIterator::idx_type DocumentIterator::lastidx() const +DocIterator::idx_type DocIterator::lastidx() const { return top().lastidx(); } -size_t DocumentIterator::nargs() const +size_t DocIterator::nargs() const { // assume 1x1 grid for main text return top().nargs(); } -size_t DocumentIterator::ncols() const +size_t DocIterator::ncols() const { // assume 1x1 grid for main text return top().ncols(); } -size_t DocumentIterator::nrows() const +size_t DocIterator::nrows() const { // assume 1x1 grid for main text return top().nrows(); } -DocumentIterator::row_type DocumentIterator::row() const +DocIterator::row_type DocIterator::row() const { return top().row(); } -DocumentIterator::col_type DocumentIterator::col() const +DocIterator::col_type DocIterator::col() const { return top().col(); } -MathArray const & DocumentIterator::cell() const +MathArray const & DocIterator::cell() const { BOOST_ASSERT(inMathed()); return top().cell(); } -MathArray & DocumentIterator::cell() +MathArray & DocIterator::cell() { BOOST_ASSERT(inMathed()); return top().cell(); } -bool DocumentIterator::inMathed() const -{ - return !empty() && inset().inMathed(); -} - - -bool DocumentIterator::inTexted() const +LyXText * DocIterator::innerText() { - return !empty() && !inset().inMathed(); + BOOST_ASSERT(!empty()); + // Go up until first non-0 text is hit + // (innermost text is 0 in mathed) + for (int i = depth() - 1; i >= 0; --i) + if (slices_[i].text()) + return slices_[i].text(); + return 0; } - -LyXText * DocumentIterator::innerText() const +LyXText const * DocIterator::innerText() const { BOOST_ASSERT(!empty()); // go up until first non-0 text is hit // (innermost text is 0 in mathed) - for (int i = size() - 1; i >= 0; --i) - if (operator[](i).text()) - return operator[](i).text(); + for (int i = depth() - 1; i >= 0; --i) + if (slices_[i].text()) + return slices_[i].text(); return 0; } -InsetBase * DocumentIterator::innerInsetOfType(int code) const +InsetBase * DocIterator::innerInsetOfType(int code) const { - for (int i = size() - 1; i >= 0; --i) - if (operator[](i).inset_->lyxCode() == code) - return operator[](i).inset_; + for (int i = depth() - 1; i >= 0; --i) + if (slices_[i].inset_->lyxCode() == code) + return slices_[i].inset_; return 0; } -void DocumentIterator::forwardPos() +void DocIterator::forwardPos(bool ignorecollapsed) { - CursorSlice & top = back(); - //lyxerr << "XXX\n" << *this << std::endl; + //this dog bites his tail + if (empty()) { + push_back(CursorSlice(*inset_)); + return; + } + + InsetBase * const nextinset = nextInset(); + // jump over collapsables if they are collapsed + // FIXME: the check for asInsetMath() shouldn't be necessary + // but math insets do not return a sensible editable() state yet. + if (ignorecollapsed && nextinset && (!nextinset->asInsetMath() + && nextinset->editable() != InsetBase::HIGHLY_EDITABLE)) { + ++top().pos(); + return; + } + + CursorSlice & tip = top(); + //lyxerr << "XXX\n" << *this << endl; + + // this is used twice and shows up in the profiler! + pos_type const lastp = lastpos(); // move into an inset to the right if possible InsetBase * n = 0; - if (top.pos() != lastpos()) { + + if (tip.pos() != lastp) { // this is impossible for pos() == size() if (inMathed()) { - n = (top.cell().begin() + top.pos())->nucleus(); + n = (tip.cell().begin() + tip.pos())->nucleus(); } else { - if (paragraph().isInset(top.pos())) - n = paragraph().getInset(top.pos()); + if (paragraph().isInset(tip.pos())) + n = paragraph().getInset(tip.pos()); } } if (n && n->isActive()) { - //lyxerr << "... descend" << std::endl; + //lyxerr << "... descend" << endl; push_back(CursorSlice(*n)); return; } - // otherwise move on one cell back if possible - if (top.pos() < lastpos()) { - //lyxerr << "... next pos" << std::endl; - ++top.pos(); + // otherwise move on one position if possible + if (tip.pos() < lastp) { + //lyxerr << "... next pos" << endl; + ++tip.pos(); return; } - //lyxerr << "... no next pos" << std::endl; + //lyxerr << "... no next pos" << endl; - // otherwise move on one cell back if possible - if (top.par() < lastpar()) { - //lyxerr << "... next par" << std::endl; - ++top.par(); - top.pos() = 0; + // otherwise move on one paragraph if possible + if (tip.pit() < lastpit()) { + //lyxerr << "... next par" << endl; + ++tip.pit(); + tip.pos() = 0; return; } - //lyxerr << "... no next par" << std::endl; + //lyxerr << "... no next pit" << endl; // otherwise try to move on one cell if possible - // [stupid hack for necessary for MathScriptInset] - while (top.idx() < lastidx()) { - //lyxerr << "... next idx" << std::endl; - ++top.idx(); - top.par() = 0; - top.pos() = 0; - if (top.inset().validCell(top.idx())) { - //lyxerr << " ... ok" << std::endl; - return; - } + if (tip.idx() < lastidx()) { + //lyxerr << "... next idx" << endl; + ++tip.idx(); + tip.pit() = 0; + tip.pos() = 0; + return; } - //lyxerr << "... no next idx" << std::endl; + //lyxerr << "... no next idx" << endl; - // otherwise leave inset an jump over inset as a whole + // otherwise leave inset and jump over inset as a whole pop_back(); // 'top' is invalid now... - if (size()) - ++back().pos(); - //else - // lyxerr << "... no slice left" << std::endl; + if (!empty()) + ++top().pos(); } -void DocumentIterator::forwardPar() +void DocIterator::forwardPosNoDescend() { - CursorSlice & top = back(); - lyxerr << "XXX " << *this << std::endl; + CursorSlice & tip = top(); + pos_type const lastp = lastpos(); - // move into an inset to the right if possible - InsetBase * n = 0; - if (top.pos() != lastpos()) { - // this is impossible for pos() == size() - if (inMathed()) { - n = (top.cell().begin() + top.pos())->nucleus(); - } else { - if (paragraph().isInset(top.pos())) - n = paragraph().getInset(top.pos()); - } + // move on one position if possible + if (tip.pos() < lastp) { + //lyxerr << "... next pos" << endl; + ++tip.pos(); + return; } + //lyxerr << "... no next pos" << endl; - if (n && n->isActive()) { - lyxerr << "... descend" << std::endl; - push_back(CursorSlice(*n)); + // otherwise move on one paragraph if possible + if (tip.pit() < lastpit()) { + //lyxerr << "... next par" << endl; + ++tip.pit(); + tip.pos() = 0; return; } + //lyxerr << "... no next pit" << endl; - // otherwise move on one cell back if possible - if (top.pos() < lastpos()) { - lyxerr << "... next pos" << std::endl; - ++top.pos(); + // otherwise try to move on one cell if possible + if (tip.idx() < lastidx()) { + //lyxerr << "... next idx" << endl; + ++tip.idx(); + tip.pit() = 0; + tip.pos() = 0; return; } + //lyxerr << "... no next idx" << endl; - // otherwise move on one cell back if possible - if (top.par() < lastpar()) { - lyxerr << "... next par" << std::endl; - ++top.par(); - top.pos() = 0; - return; + // otherwise leave inset and jump over inset as a whole + pop_back(); + // 'top' is invalid now... + if (!empty()) + ++top().pos(); +} + + +void DocIterator::forwardPar() +{ + forwardPos(); + + while (!empty() && (!inTexted() || pos() != 0)) { + if (inTexted()) { + pos_type const lastp = lastpos(); + Paragraph const & par = paragraph(); + pos_type & pos = top().pos(); + if (par.insetlist.empty()) + pos = lastp; + else + while (pos < lastp && !par.isInset(pos)) + ++pos; + } + forwardPos(); } +} - // otherwise try to move on one cell if possible - // [stupid hack for necessary for MathScriptInset] - while (top.idx() < top.lastidx()) { - lyxerr << "... next idx" - << " was: " << top.idx() << " max: " << top.lastidx() << std::endl; - ++top.idx(); - top.par() = 0; - top.pos() = 0; - if (top.inset().validCell(top.idx())) { - lyxerr << " ... ok" << std::endl; - return; + +void DocIterator::forwardChar() +{ + forwardPos(); + while (!empty() && pos() == lastpos()) + forwardPos(); +} + + +void DocIterator::forwardInset() +{ + forwardPos(); + + while (!empty() && !nextInset()) { + if (inTexted()) { + pos_type const lastp = lastpos(); + Paragraph const & par = paragraph(); + pos_type & pos = top().pos(); + while (pos < lastp && !par.isInset(pos)) + ++pos; + if (pos < lastp) + break; } + forwardPos(); } +} - // otherwise leave inset an jump over inset as a whole - pop_back(); - // 'top' is invalid now... - if (size()) - ++back().pos(); + +void DocIterator::backwardChar() +{ + backwardPos(); + while (!empty() && pos() == lastpos()) + backwardPos(); } -std::ostream & operator<<(std::ostream & os, DocumentIterator const & dit) +void DocIterator::backwardPos() { - for (size_t i = 0, n = dit.size(); i != n; ++i) - os << " " << dit.operator[](i) << "\n"; + //this dog bites his tail + if (empty()) { + push_back(CursorSlice(*inset_)); + top().idx() = lastidx(); + top().pit() = lastpit(); + top().pos() = lastpos(); + return; + } + + CursorSlice & tip = top(); + + if (tip.pos() != 0) { + --tip.pos(); + } else if (tip.pit() != 0) { + --tip.pit(); + tip.pos() = lastpos(); + return; + } else if (tip.idx() != 0) { + --tip.idx(); + tip.pit() = lastpit(); + tip.pos() = lastpos(); + return; + } else { + pop_back(); + return; + } + + // move into an inset to the left if possible + InsetBase * n = 0; + + if (inMathed()) { + n = (tip.cell().begin() + tip.pos())->nucleus(); + } else { + if (paragraph().isInset(tip.pos())) + n = paragraph().getInset(tip.pos()); + } + + if (n && n->isActive()) { + push_back(CursorSlice(*n)); + top().idx() = lastidx(); + top().pit() = lastpit(); + top().pos() = lastpos(); + } +} + + +bool DocIterator::hasPart(DocIterator const & it) const +{ + // it can't be a part if it is larger + if (it.depth() > depth()) + return false; + + // as inset adresses are the 'last' level + return &it.top().inset() == &slices_[it.depth() - 1].inset(); +} + + +void DocIterator::updateInsets(InsetBase * inset) +{ + // this function re-creates the cache of inset pointers. + // code taken in part from StableDocIterator::asDocIterator. + //lyxerr << "converting:\n" << *this << endl; + DocIterator dit = DocIterator(*inset); + size_t const n = slices_.size(); + for (size_t i = 0 ; i < n; ++i) { + BOOST_ASSERT(inset); + dit.push_back(slices_[i]); + dit.top().inset_ = inset; + if (i + 1 != n) + inset = dit.nextInset(); + } + //lyxerr << "converted:\n" << *this << endl; + operator=(dit); +} + + +std::ostream & operator<<(std::ostream & os, DocIterator const & dit) +{ + for (size_t i = 0, n = dit.depth(); i != n; ++i) + os << " " << dit[i] << "\n"; return os; } @@ -357,35 +528,51 @@ std::ostream & operator<<(std::ostream & os, DocumentIterator const & dit) /////////////////////////////////////////////////////// -StableDocumentIterator::StableDocumentIterator(const DocumentIterator & dit) +StableDocIterator::StableDocIterator(DocIterator const & dit) { - data_ = dit; + data_ = dit.internalData(); for (size_t i = 0, n = data_.size(); i != n; ++i) data_[i].inset_ = 0; } -DocumentIterator -StableDocumentIterator::asDocumentIterator(InsetBase * inset) const +DocIterator StableDocIterator::asDocIterator(InsetBase * inset) const { // this function re-creates the cache of inset pointers - //lyxerr << "converting:\n" << *this << std::endl; - DocumentIterator dit; + //lyxerr << "converting:\n" << *this << endl; + DocIterator dit = DocIterator(*inset); for (size_t i = 0, n = data_.size(); i != n; ++i) { + if (inset == 0) { + // FIXME + lyxerr << BOOST_CURRENT_FUNCTION + << " Should not happen, but does e.g. after C-n C-l C-z S-C-z" + << '\n' << "dit: " << dit << '\n' + << " lastpos: " << dit.lastpos() << endl; + //break; + BOOST_ASSERT(false); + } dit.push_back(data_[i]); - dit.back().inset_ = inset; + dit.top().inset_ = inset; if (i + 1 != n) inset = dit.nextInset(); } - //lyxerr << "convert:\n" << *this << " to:\n" << dit << std::endl; + //lyxerr << "convert:\n" << *this << " to:\n" << dit << endl; return dit; } -std::ostream & operator<<(std::ostream & os, StableDocumentIterator const & dit) +std::ostream & operator<<(std::ostream & os, StableDocIterator const & dit) { for (size_t i = 0, n = dit.data_.size(); i != n; ++i) os << " " << dit.data_[i] << "\n"; return os; } + +bool operator==(StableDocIterator const & dit1, StableDocIterator const & dit2) +{ + return dit1.data_ == dit2.data_; +} + + +} // namespace lyx