diff --git a/src/Cursor.cpp b/src/Cursor.cpp index 378a138da6..05389d9845 100644 --- a/src/Cursor.cpp +++ b/src/Cursor.cpp @@ -551,24 +551,6 @@ void Cursor::checkNewWordPosition() } -bool Cursor::posBackward() -{ - if (pos() == 0) - return false; - --pos(); - return true; -} - - -bool Cursor::posForward() -{ - if (pos() == lastpos()) - return false; - ++pos(); - return true; -} - - bool Cursor::posVisRight(bool skip_inset) { Cursor new_cur = *this; // where we will move to @@ -1301,7 +1283,7 @@ void Cursor::insert(MathData const & ar) } -bool Cursor::backspace() +bool Cursor::backspace(bool const force) { if (selection()) { cap::eraseSelection(*this); @@ -1337,7 +1319,7 @@ bool Cursor::backspace() } } - if (pos() != 0 && prevAtom()->nargs() > 0) { + if (pos() != 0 && !force && prevAtom()->confirmDeletion()) { // let's require two backspaces for 'big stuff' and // highlight on the first resetAnchor(); @@ -1351,7 +1333,7 @@ bool Cursor::backspace() } -bool Cursor::erase() +bool Cursor::erase(bool const force) { if (inMacroMode()) return true; @@ -1386,7 +1368,7 @@ bool Cursor::erase() } // 'clever' UI hack: only erase large items if previously slected - if (pos() != lastpos() && nextAtom()->nargs() > 0) { + if (pos() != lastpos() && !force && nextAtom()->confirmDeletion()) { resetAnchor(); selection(true); ++pos(); @@ -2436,4 +2418,21 @@ void Cursor::checkBufferStructure() } +bool Cursor::confirmDeletion(bool const before) const +{ + if (!selection()) { + if (Inset const * inset = before ? prevInset() : nextInset()) + return inset->confirmDeletion(); + } else { + DocIterator dit = selectionBegin(); + DocIterator const sel_end = selectionEnd(); + for (; dit < sel_end; dit.posForward()) + if (Inset const * inset = dit.nextInset()) + if (inset->confirmDeletion()) + return true; + } + return false; +} + + } // namespace lyx diff --git a/src/Cursor.h b/src/Cursor.h index f5f1322ce8..dbdd1569b8 100644 --- a/src/Cursor.h +++ b/src/Cursor.h @@ -232,10 +232,6 @@ public: // // common part // - /// move one step backwards - bool posBackward(); - /// move one step forward - bool posForward(); /// move visually one step to the right /** * @note: This method may move into an inset unless skip_inset == true. @@ -398,6 +394,11 @@ public: /// and after leaving the word the result is empty. DocIterator newWord() const { return new_word_; } + /// Return true if the next or previous inset has confirmDeletion depending + /// on the boolean before. If there is a selection, return true if at least + /// one inset in the selection has confirmDeletion. + bool confirmDeletion(bool before = false) const; + public: //private: @@ -454,9 +455,10 @@ public: /// void insert(MathData const &); /// return false for empty math insets - bool erase(); - /// return false for empty math insets - bool backspace(); + /// Use force to skip the confirmDeletion check. + bool erase(bool force = false); + bool backspace(bool force = false); + /// move the cursor up by sending an internal LFUN_UP /// return true if fullscreen update is needed bool up(); diff --git a/src/DocIterator.cpp b/src/DocIterator.cpp index fdb61876d6..51b44d88ef 100644 --- a/src/DocIterator.cpp +++ b/src/DocIterator.cpp @@ -318,6 +318,24 @@ Inset * DocIterator::innerInsetOfType(int code) const } +bool DocIterator::posBackward() +{ + if (pos() == 0) + return false; + --pos(); + return true; +} + + +bool DocIterator::posForward() +{ + if (pos() == lastpos()) + return false; + ++pos(); + return true; +} + + // This duplicates code above, but is in the critical path. // So please think twice before adding stuff void DocIterator::forwardPos() diff --git a/src/DocIterator.h b/src/DocIterator.h index 425bfa4f68..cde876cd86 100644 --- a/src/DocIterator.h +++ b/src/DocIterator.h @@ -184,6 +184,10 @@ public: // // elementary moving // + /// move one step backwards + bool posBackward(); + /// move one step forward + bool posForward(); /** * move on one logical position, descend into nested insets * including collapsed insets diff --git a/src/LyXAction.cpp b/src/LyXAction.cpp index 9171e1c8b8..77cf3ea4f1 100644 --- a/src/LyXAction.cpp +++ b/src/LyXAction.cpp @@ -1080,7 +1080,8 @@ void LyXAction::init() /*! * \var lyx::FuncCode lyx::LFUN_CHAR_DELETE_BACKWARD * \li Action: Deletes one character in the backward direction (usually the "BackSpace" key). - * \li Syntax: char-delete-backward + * \li Syntax: char-delete-backward [force] + * \li Params: force: Delete big insets, do no only select them. * \endvar */ { LFUN_CHAR_DELETE_BACKWARD, "char-delete-backward", SingleParUpdate, Edit }, @@ -1088,7 +1089,8 @@ void LyXAction::init() /*! * \var lyx::FuncCode lyx::LFUN_CHAR_DELETE_FORWARD * \li Action: Deletes one character in the backward direction (usually the "Delete" key). - * \li Syntax: char-delete-forward + * \li Syntax: char-delete-forward [force] + * \li Params: force: Delete big insets, do no only select them. * \endvar */ { LFUN_CHAR_DELETE_FORWARD, "char-delete-forward", SingleParUpdate, Edit }, @@ -4007,7 +4009,8 @@ void LyXAction::init() /*! * \var lyx::FuncCode lyx::LFUN_WORD_DELETE_BACKWARD * \li Action: Deletes characters to the beginning of the word (usually the "C+BackSpace" key). - * \li Syntax: word-delete-backward + * \li Syntax: word-delete-backward [force] + * \li Params: force: Delete big insets, do no only select them. * \endvar */ { LFUN_WORD_DELETE_BACKWARD, "word-delete-backward", Noop, Edit }, @@ -4015,7 +4018,8 @@ void LyXAction::init() /*! * \var lyx::FuncCode lyx::LFUN_WORD_DELETE_FORWARD * \li Action: Deletes characters to the end of the word (usually the "C+Delete" key). - * \li Syntax: word-delete-forward + * \li Syntax: word-delete-forward [force] + * \li Params: force: Delete big insets, do no only select them. * \endvar */ { LFUN_WORD_DELETE_FORWARD, "word-delete-forward", Noop, Edit }, diff --git a/src/Text.cpp b/src/Text.cpp index 8d08baa473..c1af0948a9 100644 --- a/src/Text.cpp +++ b/src/Text.cpp @@ -1466,7 +1466,7 @@ void Text::rejectChanges() } -void Text::deleteWordForward(Cursor & cur) +void Text::deleteWordForward(Cursor & cur, bool const force) { LBUFERR(this == cur.text()); if (cur.lastpos() == 0) @@ -1476,13 +1476,15 @@ void Text::deleteWordForward(Cursor & cur) cur.selection(true); cursorForwardOneWord(cur); cur.setSelection(); - cutSelection(cur, true, false); - cur.checkBufferStructure(); + if (force || !cur.confirmDeletion()) { + cutSelection(cur, true, false); + cur.checkBufferStructure(); + } } } -void Text::deleteWordBackward(Cursor & cur) +void Text::deleteWordBackward(Cursor & cur, bool const force) { LBUFERR(this == cur.text()); if (cur.lastpos() == 0) @@ -1492,8 +1494,10 @@ void Text::deleteWordBackward(Cursor & cur) cur.selection(true); cursorBackwardOneWord(cur); cur.setSelection(); - cutSelection(cur, true, false); - cur.checkBufferStructure(); + if (force || !cur.confirmDeletion()) { + cutSelection(cur, true, false); + cur.checkBufferStructure(); + } } } diff --git a/src/Text.h b/src/Text.h index f49c8e2d91..2174984b23 100644 --- a/src/Text.h +++ b/src/Text.h @@ -223,9 +223,10 @@ public: /// bool cursorVisRightOneWord(Cursor & cur); /// Delete from cursor up to the end of the current or next word. - void deleteWordForward(Cursor & cur); + /// Use force to skip the confirmDeletion check. + void deleteWordForward(Cursor & cur, bool force = false); /// Delete from cursor to start of current or prior word. - void deleteWordBackward(Cursor & cur); + void deleteWordBackward(Cursor & cur, bool force = false); /// bool cursorUpParagraph(Cursor & cur); /// diff --git a/src/Text3.cpp b/src/Text3.cpp index 3e6fdf0e14..cb5f0b5760 100644 --- a/src/Text3.cpp +++ b/src/Text3.cpp @@ -586,7 +586,7 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd) if (cur.selection()) cutSelection(cur, true, false); else - deleteWordForward(cur); + deleteWordForward(cur, cmd.getArg(0) == "force"); finishChange(cur, false); break; @@ -594,7 +594,7 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd) if (cur.selection()) cutSelection(cur, true, false); else - deleteWordBackward(cur); + deleteWordBackward(cur, cmd.getArg(0) == "force"); finishChange(cur, false); break; @@ -1054,6 +1054,13 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd) if (cur.pos() == cur.paragraph().size()) // Par boundary, force full-screen update singleParUpdate = false; + else if (cmd.getArg(0) != "force" && cur.confirmDeletion()) { + cur.resetAnchor(); + cur.selection(true); + cur.posForward(); + cur.setSelection(); + break; + } needsUpdate |= erase(cur); cur.resetAnchor(); } else { @@ -1071,6 +1078,13 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd) // Par boundary, full-screen update if (par_boundary) singleParUpdate = false; + else if (cmd.getArg(0) != "force" && cur.confirmDeletion(true)) { + cur.resetAnchor(); + cur.selection(true); + cur.posBackward(); + cur.setSelection(); + break; + } needsUpdate |= backspace(cur); cur.resetAnchor(); if (par_boundary && !first_par && cur.pos() > 0 diff --git a/src/insets/Inset.h b/src/insets/Inset.h index 29c4395c38..3395e254a2 100644 --- a/src/insets/Inset.h +++ b/src/insets/Inset.h @@ -581,6 +581,10 @@ public: // enum { TEXT_TO_INSET_OFFSET = 4 }; + /// Determine the action of backspace and delete: do we select instead of + /// deleting if not already selected? + virtual bool confirmDeletion() const { return false; } + protected: /// Constructors Inset(Buffer * buf) : buffer_(buf) {} diff --git a/src/insets/InsetText.h b/src/insets/InsetText.h index d8dbc43616..eb52bc81b6 100644 --- a/src/insets/InsetText.h +++ b/src/insets/InsetText.h @@ -219,6 +219,10 @@ public: std::string contextMenuName() const; /// void doDispatch(Cursor & cur, FuncRequest & cmd); + + /// + bool confirmDeletion() const { return !text().empty(); } + protected: /// void iterateForToc(DocIterator const & cdit, bool output_active, diff --git a/src/mathed/InsetMathHull.h b/src/mathed/InsetMathHull.h index e04d68e918..bc574b9650 100644 --- a/src/mathed/InsetMathHull.h +++ b/src/mathed/InsetMathHull.h @@ -189,6 +189,8 @@ public: InsetCode lyxCode() const { return MATH_HULL_CODE; } /// bool canPaintChange(BufferView const &) const; + /// + bool confirmDeletion() const { return nargs() != 1 || !cell(0).empty(); } protected: InsetMathHull(InsetMathHull const &); diff --git a/src/mathed/InsetMathNest.cpp b/src/mathed/InsetMathNest.cpp index bdcd8a9a4c..ceec393ee6 100644 --- a/src/mathed/InsetMathNest.cpp +++ b/src/mathed/InsetMathNest.cpp @@ -862,8 +862,8 @@ void InsetMathNest::doDispatch(Cursor & cur, FuncRequest & cmd) else if (!cur.inMacroMode()) cur.recordUndoSelection(); // if the inset can not be removed from within, delete it - if (!cur.backspace()) { - FuncRequest cmd = FuncRequest(LFUN_CHAR_DELETE_FORWARD); + if (!cur.backspace(cmd.getArg(0) == "force")) { + FuncRequest cmd = FuncRequest(LFUN_CHAR_DELETE_FORWARD, "force"); cur.innerText()->dispatch(cur, cmd); } break; @@ -876,8 +876,8 @@ void InsetMathNest::doDispatch(Cursor & cur, FuncRequest & cmd) else cur.recordUndoSelection(); // if the inset can not be removed from within, delete it - if (!cur.erase()) { - FuncRequest cmd = FuncRequest(LFUN_CHAR_DELETE_FORWARD); + if (!cur.erase(cmd.getArg(0) == "force")) { + FuncRequest cmd = FuncRequest(LFUN_CHAR_DELETE_FORWARD, "force"); cur.innerText()->dispatch(cur, cmd); } break; diff --git a/src/mathed/InsetMathNest.h b/src/mathed/InsetMathNest.h index f1426350c3..f1cfdd8beb 100644 --- a/src/mathed/InsetMathNest.h +++ b/src/mathed/InsetMathNest.h @@ -131,6 +131,9 @@ public: /// InsetCode lyxCode() const { return MATH_NEST_CODE; } + /// + bool confirmDeletion() const { return nargs() > 0; } + protected: /// InsetMathNest(InsetMathNest const & inset);