X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2FText2.cpp;h=ed4b133ff53f4fc34fe994bf16264615979815e0;hb=7470305720d7733a27e9c6e5ef13a0774f5d0f77;hp=d8a9114576d7b6bca6ce69fa8c81aec9beec01dc;hpb=20976e81fb25899ee8d3ec5ed941fda6b453f59f;p=lyx.git diff --git a/src/Text2.cpp b/src/Text2.cpp index d8a9114576..ed4b133ff5 100644 --- a/src/Text2.cpp +++ b/src/Text2.cpp @@ -182,10 +182,16 @@ void Text::setLayout(pit_type start, pit_type end, for (pit_type pit = start; pit != end; ++pit) { Paragraph & par = pars_[pit]; - par.applyLayout(lyxlayout); + // Is this a separating paragraph? If so, + // this needs to be standard layout + bool const is_separator = par.size() == 1 + && par.isEnvSeparator(0); + par.applyLayout(is_separator ? bp.documentClass().defaultLayout() : lyxlayout); if (lyxlayout.margintype == MARGIN_MANUAL) par.setLabelWidthString(par.expandLabel(lyxlayout, bp)); } + + deleteEmptyParagraphMechanism(start, end - 1, bp.track_changes); } @@ -198,6 +204,7 @@ void Text::setLayout(Cursor & cur, docstring const & layout) pit_type end = cur.selEnd().pit() + 1; cur.recordUndoSelection(); setLayout(start, end, layout); + cur.fixIfBroken(); cur.setCurrentFont(); cur.forceBufferUpdate(); } @@ -480,7 +487,7 @@ void Text::setLabelWidthStringToSequence(Cursor const & cur, } -void Text::setParagraphs(Cursor & cur, docstring arg, bool merge) +void Text::setParagraphs(Cursor & cur, docstring const & arg, bool merge) { LBUFERR(cur.text()); @@ -600,7 +607,7 @@ bool Text::checkAndActivateInsetVisual(Cursor & cur, bool movingForward, bool mo if (cur.pos() == cur.lastpos()) return false; Paragraph & par = cur.paragraph(); - Inset * inset = par.isInset(cur.pos()) ? par.getInset(cur.pos()) : 0; + Inset * inset = par.isInset(cur.pos()) ? par.getInset(cur.pos()) : nullptr; if (!inset || !inset->editable()) return false; if (cur.selection() && cur.realAnchor().find(inset) == -1) @@ -779,26 +786,33 @@ bool Text::cursorDownParagraph(Cursor & cur) return updated; } - namespace { -// fix the cursor `cur' after characters has been deleted at `where' -// position. Called by deleteEmptyParagraphMechanism -void fixCursorAfterDelete(CursorSlice & cur, CursorSlice const & where, - pos_type from, pos_type to) -{ - // Do nothing if cursor is not in the paragraph where the - // deletion occurred, - if (cur.pit() != where.pit()) - return; - // If cursor position is after the deletion place update it - if (cur.pos() > from) - cur.pos() = max(from, cur.pos() - (to - from)); +/** delete num_spaces characters between from and to. Return the + * number of spaces that got physically deleted (not marked as + * deleted) */ +int deleteSpaces(Paragraph & par, pos_type const from, pos_type to, + int num_spaces, bool const trackChanges) +{ + if (num_spaces <= 0) + return 0; + + // First, delete spaces marked as inserted + int pos = from; + while (pos < to && num_spaces > 0) { + Change const & change = par.lookupChange(pos); + if (change.inserted() && change.currentAuthor()) { + par.eraseChar(pos, trackChanges); + --num_spaces; + --to; + } else + ++pos; + } - // Check also if we don't want to set the cursor on a spot behind the - // pagragraph because we erased the last character. - if (cur.pos() > cur.lastpos()) - cur.pos() = cur.lastpos(); + // Then remove remaining spaces + int const psize = par.size(); + par.eraseChars(from, from + num_spaces, trackChanges); + return psize - par.size(); } } @@ -810,123 +824,124 @@ bool Text::deleteEmptyParagraphMechanism(Cursor & cur, //LYXERR(Debug::DEBUG, "DEPM: cur:\n" << cur << "old:\n" << old); Paragraph & oldpar = old.paragraph(); + bool const trackChanges = cur.buffer()->params().track_changes; + bool result = false; + + // We do nothing if cursor did not move + if (cur.top() == old.top()) + return false; + + // We do not do anything on read-only documents + if (cur.buffer()->isReadonly()) + return false; // We allow all kinds of "mumbo-jumbo" when freespacing. if (oldpar.isFreeSpacing()) return false; - /* Ok I'll put some comments here about what is missing. - There are still some small problems that can lead to + // Whether a common inset is found and whether the cursor is still in + // the same paragraph (possibly nested). + int const depth = cur.find(&old.inset()); + bool const same_par = depth != -1 && old.idx() == cur[depth].idx() + && old.pit() == cur[depth].pit(); + + /* + * (1) If the chars around the old cursor were spaces, delete some of + * them, but only if the cursor has really moved. + */ + + /* There are still some small problems that can lead to double spaces stored in the document file or space at the beginning of paragraphs(). This happens if you have - the cursor between to spaces and then save. Or if you - cut and paste and the selection have a space at the + the cursor between two spaces and then save. Or if you + cut and paste and the selection has a space at the beginning and then save right after the paste. (Lgb) */ - // If old.pos() == 0 and old.pos()(1) == LineSeparator - // delete the LineSeparator. - // MISSING - - // If old.pos() == 1 and old.pos()(0) == LineSeparator - // delete the LineSeparator. - // MISSING - - // Find a common inset and the corresponding depth. - size_t depth = 0; - for (; depth < cur.depth(); ++depth) - if (&old.inset() == &cur[depth].inset()) - break; - - // Whether a common inset is found and whether the cursor is still in - // the same paragraph (possibly nested). - bool const same_par = depth < cur.depth() && old.pit() == cur[depth].pit(); - bool const same_par_pos = depth == cur.depth() - 1 && same_par - && old.pos() == cur[depth].pos(); - - // If the chars around the old cursor were spaces, delete some of - // them , but only if the cursor has really moved. - if (!same_par_pos) { - // find range of spaces around cursors - int from = old.pos(); - while (from > 0 - && oldpar.isLineSeparator(from - 1) - && !oldpar.isDeleted(from - 1)) - --from; - int to = old.pos(); - while (to < oldpar.size() - 1 - && oldpar.isLineSeparator(to) - && !oldpar.isDeleted(to)) - ++to; - - // If we are not at the extremity of the paragraph, keep one space - if (from != to && from > 0 && to < oldpar.size()) - ++from; - - // Remove spaces and adapt cursor. - if (from < to) { - oldpar.eraseChars(from, to, cur.buffer()->params().track_changes); -// FIXME: This will not work anymore when we have multiple views of the same buffer -// In this case, we will have to correct also the cursors held by -// other bufferviews. It will probably be easier to do that in a more -// automated way in CursorSlice code. (JMarc 26/09/2001) - // correct all cursor parts - if (same_par) { - fixCursorAfterDelete(cur[depth], old.top(), from, to); - need_anchor_change = true; - } - return true; + // find range of spaces around cursors + pos_type from = old.pos(); + while (from > 0 + && oldpar.isLineSeparator(from - 1) + && !oldpar.isDeleted(from - 1)) + --from; + pos_type to = old.pos(); + while (to < old.lastpos() + && oldpar.isLineSeparator(to) + && !oldpar.isDeleted(to)) + ++to; + + int num_spaces = to - from; + // If we are not at the start of the paragraph, keep one space + if (from != to && from > 0) + --num_spaces; + + // If cursor is inside range, keep one additional space + if (same_par && cur.pos() > from && cur.pos() < to) + --num_spaces; + + // Remove spaces and adapt cursor. + if (num_spaces > 0) { + old.recordUndo(); + int const deleted = + deleteSpaces(oldpar, from, to, num_spaces, trackChanges); + // correct cur position + // FIXME: there can be other cursors pointing there, we should update them + if (same_par) { + if (cur[depth].pos() >= to) + cur[depth].pos() -= deleted; + else if (cur[depth].pos() > from) + cur[depth].pos() = min(from + 1, old.lastpos()); + need_anchor_change = true; } + result = true; } - // only do our magic if we changed paragraph + /* + * (2) If the paragraph where the cursor was is empty, delete it + */ + + // only do our other magic if we changed paragraph if (same_par) - return false; + return result; + + // only do our magic if the paragraph is empty + if (!oldpar.empty()) + return result; // don't delete anything if this is the ONLY paragraph! if (old.lastpit() == 0) - return false; + return result; // Do not delete empty paragraphs with keepempty set. if (oldpar.allowEmpty()) - return false; - - if (oldpar.empty() || (oldpar.size() == 1 && oldpar.isLineSeparator(0))) { - // Delete old par. - old.recordUndo(max(old.pit() - 1, pit_type(0)), - min(old.pit() + 1, old.lastpit())); - ParagraphList & plist = old.text()->paragraphs(); - bool const soa = oldpar.params().startOfAppendix(); - plist.erase(lyx::next(plist.begin(), old.pit())); - // do not lose start of appendix marker (bug 4212) - if (soa && old.pit() < pit_type(plist.size())) - plist[old.pit()].params().startOfAppendix(true); - - // see #warning (FIXME?) above - if (cur.depth() >= old.depth()) { - CursorSlice & curslice = cur[old.depth() - 1]; - if (&curslice.inset() == &old.inset() - && curslice.pit() > old.pit()) { - --curslice.pit(); - // since a paragraph has been deleted, all the - // insets after `old' have been copied and - // their address has changed. Therefore we - // need to `regenerate' cur. (JMarc) - cur.updateInsets(&(cur.bottom().inset())); - need_anchor_change = true; - } + return result; + + // Delete old par. + old.recordUndo(max(old.pit() - 1, pit_type(0)), + min(old.pit() + 1, old.lastpit())); + ParagraphList & plist = old.text()->paragraphs(); + bool const soa = oldpar.params().startOfAppendix(); + plist.erase(plist.iterator_at(old.pit())); + // do not lose start of appendix marker (bug 4212) + if (soa && old.pit() < pit_type(plist.size())) + plist[old.pit()].params().startOfAppendix(true); + + // see #warning (FIXME?) above + if (cur.depth() >= old.depth()) { + CursorSlice & curslice = cur[old.depth() - 1]; + if (&curslice.inset() == &old.inset() + && curslice.pit() > old.pit()) { + --curslice.pit(); + // since a paragraph has been deleted, all the + // insets after `old' have been copied and + // their address has changed. Therefore we + // need to `regenerate' cur. (JMarc) + cur.updateInsets(&(cur.bottom().inset())); + need_anchor_change = true; } - return true; } - if (oldpar.stripLeadingSpaces(cur.buffer()->params().track_changes)) { - need_anchor_change = true; - // We return true here because the Paragraph contents changed and - // we need a redraw before further action is processed. - return true; - } - - return false; + return true; } @@ -947,22 +962,24 @@ void Text::deleteEmptyParagraphMechanism(pit_type first, pit_type last, bool tra while (from < par.size() && (!par.isLineSeparator(from) || par.isDeleted(from))) ++from; - LYXERR0("from=" << from); // find string of spaces pos_type to = from; while (to < par.size() && par.isLineSeparator(to) && !par.isDeleted(to)) ++to; - LYXERR0("to=" << to); // empty? We are done if (from == to) break; - // if inside the line, keep one space - if (from > 0 && to < par.size()) - ++from; - // remove the extra spaces - if (from < to) - par.eraseChars(from, to, trackChanges); + + int num_spaces = to - from; + + // If we are not at the extremity of the paragraph, keep one space + if (from != to && from > 0 && to < par.size()) + --num_spaces; + + // Remove spaces if needed + int const deleted = deleteSpaces(par, from , to, num_spaces, trackChanges); + from = to - deleted; } // don't delete anything if this is the only remaining paragraph @@ -976,13 +993,11 @@ void Text::deleteEmptyParagraphMechanism(pit_type first, pit_type last, bool tra continue; if (par.empty() || (par.size() == 1 && par.isLineSeparator(0))) { - pars_.erase(lyx::next(pars_.begin(), pit)); + pars_.erase(pars_.iterator_at(pit)); --pit; --last; continue; } - - par.stripLeadingSpaces(trackChanges); } }