This fixes a crash in undo when creatin redo information. Already in CVS.
Andre'
Index: undo.C =================================================================== RCS file: /usr/local/lyx/cvsroot/lyx-devel/src/undo.C,v retrieving revision 1.56 retrieving revision 1.57 diff -u -p -r1.56 -r1.57 --- undo.C 23 Oct 2004 11:04:41 -0000 1.56 +++ undo.C 5 Nov 2004 06:12:21 -0000 1.57 @@ -42,28 +42,30 @@ bool undo_finished; std::ostream & operator<<(std::ostream & os, Undo const & undo) { return os << " from: " << undo.from << " end: " << undo.end + << " cell:\n" << undo.cell << " cursor:\n" << undo.cursor; } void recordUndo(Undo::undo_kind kind, - LCursor & cur, par_type first_par, par_type last_par, + DocIterator & cell, + par_type first_par, par_type last_par, + DocIterator & cur, limited_stack<Undo> & stack) { - BOOST_ASSERT(first_par <= cur.lastpar()); - BOOST_ASSERT(last_par <= cur.lastpar()); - if (first_par > last_par) std::swap(first_par, last_par); // create the position information of the Undo entry Undo undo; undo.kind = kind; - undo.cursor = StableDocIterator(cur); + undo.cell = cell; + undo.cursor = cur; lyxerr << "recordUndo: cur: " << cur << endl; - lyxerr << "recordUndo: undo.cursor: " << undo.cursor << endl; + lyxerr << "recordUndo: pos: " << cur.pos() << endl; + //lyxerr << "recordUndo: cell: " << cell << endl; undo.from = first_par; - undo.end = cur.lastpar() - last_par; + undo.end = cell.lastpar() - last_par; // Undo::ATOMIC are always recorded (no overlapping there). // As nobody wants all removed character appear one by one when undoing, @@ -71,21 +73,21 @@ void recordUndo(Undo::undo_kind kind, if (!undo_finished && kind != Undo::ATOMIC && !stack.empty() - && stack.top().cursor.size() == undo.cursor.size() + && stack.top().cell.size() == undo.cell.size() && stack.top().kind == undo.kind && stack.top().from == undo.from && stack.top().end == undo.end) return; // fill in the real data to be saved - if (cur.inMathed()) { + if (cell.inMathed()) { // simply use the whole cell - undo.array = asString(cur.cell()); + undo.array = asString(cell.cell()); } else { // some more effort needed here as 'the whole cell' of the // main LyXText _is_ the whole document. // record the relevant paragraphs - LyXText * text = cur.text(); + LyXText * text = cell.text(); BOOST_ASSERT(text); ParagraphList & plist = text->paragraphs(); ParagraphList::iterator first = plist.begin(); @@ -103,22 +105,29 @@ void recordUndo(Undo::undo_kind kind, undo_finished = false; } +void recordUndo(Undo::undo_kind kind, + LCursor & cur, par_type first_par, par_type last_par, + limited_stack<Undo> & stack) +{ + BOOST_ASSERT(first_par <= cur.lastpar()); + BOOST_ASSERT(last_par <= cur.lastpar()); + + recordUndo(kind, cur, first_par, last_par, cur, stack); +} + void performUndoOrRedo(BufferView & bv, Undo const & undo) { - LCursor & cur = bv.cursor(); - lyxerr << "undo, performing: " << undo << std::endl; - cur.setCursor(undo.cursor.asDocIterator(&bv.buffer()->inset())); - cur.selection() = false; - - if (cur.inMathed()) { + //lyxerr << "undo, performing: " << undo << std::endl; + DocIterator dit = undo.cell.asDocIterator(&bv.buffer()->inset()); + if (dit.inMathed()) { // We stored the full cell here as there is not much to be // gained by storing just 'a few' paragraphs (most if not // all math inset cells have just one paragraph!) - asArray(undo.array, cur.cell()); + asArray(undo.array, dit.cell()); } else { // Some finer machinery is needed here. - LyXText * text = cur.text(); + LyXText * text = dit.text(); BOOST_ASSERT(text); ParagraphList & plist = text->paragraphs(); @@ -135,6 +144,9 @@ void performUndoOrRedo(BufferView & bv, plist.insert(first, undo.pars.begin(), undo.pars.end()); } + LCursor & cur = bv.cursor(); + cur.setCursor(undo.cursor.asDocIterator(&bv.buffer()->inset())); + cur.selection() = false; cur.resetAnchor(); finishUndo(); } @@ -150,40 +162,52 @@ bool textUndoOrRedo(BufferView & bv, return false; } + // + // Adjust undo stack and get hold of current undo data. + // Undo undo = stack.top(); stack.pop(); finishUndo(); - // This implements redo - otherstack.push(undo); - // FIXME: This triggers the error in dociterator.C +454 - // could the reason be that we rebuild the dit _before_ the - // contents is actually 'undone'? - // I.e. state now is 'A', state on undo stack is 'B'. - // dit is created according to positions from undo.cursor, i.e. B - // but current buffer contents is more likely 'A'. - DocIterator dit = undo.cursor.asDocIterator(&bv.buffer()->inset()); - if (dit.inMathed()) { - // Easy way out: store a full cell. - otherstack.top().array = asString(dit.cell()); - } else { - // As cells might be too large in texted, store just a part - // of the paragraph list. - otherstack.top().pars.clear(); - LyXText * text = dit.text(); - BOOST_ASSERT(text); - ParagraphList & plist = text->paragraphs(); - if (undo.from + undo.end <= int(plist.size())) { - ParagraphList::iterator first = plist.begin(); - advance(first, undo.from); - ParagraphList::iterator last = plist.begin(); - advance(last, plist.size() - undo.end); - otherstack.top().pars.insert(otherstack.top().pars.begin(), first, last); - } + + // + // This implements redo. + // + + // The cursor will be placed at cur_dit after + // the ongoing undo operation. + DocIterator cur_dit = + undo.cursor.asDocIterator(&bv.buffer()->inset()); + + // This is the place the cursor is currently located. + LCursor & cur = bv.cursor(); + DocIterator cell_dit = cur; + + // If both places have the same depth we stay in the same + // cell and store paragraphs from this cell. Otherwise we + // will drop slices from the more nested iterator and + // create an undo item from a single paragraph of the common + // ancestor. + DocIterator ancestor_dit = cur_dit; + while (ancestor_dit.size() > cur.size()) + ancestor_dit.pop_back(); + + if (cur_dit.size() == cell_dit.size()) { + recordUndo(Undo::ATOMIC, cell_dit, + cell_dit.par(), cur_dit.par(), + cur_dit, otherstack); } - otherstack.top().cursor = bv.cursor(); - //lyxerr << " undo other: " << otherstack.top() << std::endl; + else { + recordUndo(Undo::ATOMIC, ancestor_dit, + ancestor_dit.par(), + ancestor_dit.par(), + cur_dit, otherstack); + } + + // + // This does the actual undo. + // performUndoOrRedo(bv, undo); return true; } @@ -218,9 +242,9 @@ void recordUndo(Undo::undo_kind kind, Buffer * buf = cur.bv().buffer(); recordUndo(kind, cur, first, last, buf->undostack()); buf->redostack().clear(); - lyxerr << "undostack:\n"; - for (size_t i = 0, n = buf->undostack().size(); i != n && i < 6; ++i) - lyxerr << " " << i << ": " << buf->undostack()[i] << std::endl; + //lyxerr << "undostack:\n"; + //for (size_t i = 0, n = buf->undostack().size(); i != n && i < 6; ++i) + // lyxerr << " " << i << ": " << buf->undostack()[i] << std::endl; } Index: undo.h =================================================================== RCS file: /usr/local/lyx/cvsroot/lyx-devel/src/undo.h,v retrieving revision 1.36 retrieving revision 1.37 diff -u -p -r1.36 -r1.37 --- undo.h 18 Apr 2004 19:41:40 -0000 1.36 +++ undo.h 5 Nov 2004 06:12:21 -0000 1.37 @@ -28,10 +28,27 @@ class BufferView; /** - * These are the elements put on the undo stack. Each object - * contains complete paragraphs and sufficient information - * to restore the state. - */ +These are the elements put on the undo stack. Each object contains complete +paragraphs from some cell and sufficient information to restore the cursor +state. + +The cell is given by a DocIterator pointing to this cell, the 'interesting' +range of paragraphs by counting them from begin and end of cell, +respectively. + +The cursor is also given as DocIterator and should point to some place in +the stored paragraph range. In case of math, we simply store the whole +cell, as there usually is just a simple paragraph in a cell. + +The idea is to store the contents of 'interesting' paragraphs in some +structure ('Undo') _before_ it is changed in some edit operation. +Obviously, the stored ranged should be as small as possible. However, it +there is a lower limit: The StableDocIterator pointing stored in the undo +struct must be valid after the changes, too, as it will used as a pointer +where to insert the stored bits when performining undo. + +*/ + struct Undo { /// This is used to combine consecutive undo recordings of the same kind. enum undo_kind { @@ -53,22 +70,24 @@ struct Undo { undo_kind kind; /// the position of the cursor StableDocIterator cursor; - /// counted from begin of buffer + /// the position of the cell described + StableDocIterator cell; + /// counted from begin of cell lyx::par_type from; /// complement to end of this cell lyx::par_type end; - /// the contents of the saved paragraphs (for texted) + /// the contents of the saved Paragraphs (for texted) ParagraphList pars; - /// the contents of the saved matharray (for mathed) + /// the stringified contents of the saved MathArray (for mathed) std::string array; }; /// this will undo the last action - returns false if no undo possible -bool textUndo(BufferView &); +bool textUndo(BufferView & bv); /// this will redo the last undo - returns false if no redo possible -bool textRedo(BufferView &); +bool textRedo(BufferView & bv); /// makes sure the next operation will be stored void finishUndo();