X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2FCursor.cpp;h=41cf26ec1758fa0b1caa72d2994616f03aba556a;hb=7441172d4d9a26eb4824bb8bee003f457ef34f1c;hp=3f5bff854cfabe9c5506ca6637658748f8168539;hpb=02028c0b12ba94093e4e77494e7158a58f1631e5;p=lyx.git diff --git a/src/Cursor.cpp b/src/Cursor.cpp index 3f5bff854c..41cf26ec17 100644 --- a/src/Cursor.cpp +++ b/src/Cursor.cpp @@ -22,6 +22,7 @@ #include "DispatchResult.h" #include "FuncCode.h" #include "FuncRequest.h" +#include "Language.h" #include "Layout.h" #include "LyXAction.h" #include "LyXRC.h" @@ -51,6 +52,8 @@ #include "mathed/MathFactory.h" #include "mathed/InsetMathMacro.h" +#include "frontends/Application.h" + #include #include #include @@ -121,19 +124,19 @@ DocIterator bruteFind(Cursor const & c, int x, int y) CursorData::CursorData() : DocIterator(), anchor_(), selection_(false), mark_(false), - word_selection_(false), current_font(inherit_font), autocorrect_(false) + word_selection_(false), current_font(inherit_font) {} CursorData::CursorData(Buffer * buffer) : DocIterator(buffer), anchor_(), selection_(false), mark_(false), - word_selection_(false), current_font(inherit_font), autocorrect_(false) + word_selection_(false), current_font(inherit_font) {} CursorData::CursorData(DocIterator const & dit) : DocIterator(dit), anchor_(), selection_(false), mark_(false), - word_selection_(false), current_font(inherit_font), autocorrect_(false) + word_selection_(false), current_font(inherit_font) {} @@ -330,6 +333,8 @@ namespace { docstring parbreak(CursorData const * cur) { + if (cur->inset().getLayout().parbreakIgnored()) + return docstring(); odocstringstream os; os << '\n'; // only add blank line if we're not in a ParbreakIsNewline situation @@ -342,7 +347,7 @@ docstring parbreak(CursorData const * cur) } -docstring CursorData::selectionAsString(bool with_label) const +docstring CursorData::selectionAsString(bool const with_label, bool const skipdelete) const { if (!selection()) return docstring(); @@ -350,8 +355,12 @@ docstring CursorData::selectionAsString(bool with_label) const if (inMathed()) return cap::grabSelection(*this); - int const label = with_label + int label = with_label ? AS_STR_LABEL | AS_STR_INSETS : AS_STR_INSETS; + if (skipdelete) + label = with_label + ? AS_STR_LABEL | AS_STR_INSETS | AS_STR_SKIPDELETE + : AS_STR_INSETS | AS_STR_SKIPDELETE; idx_type const startidx = selBegin().idx(); idx_type const endidx = selEnd().idx(); @@ -457,34 +466,32 @@ void CursorData::checkNewWordPosition() { if (!lyxrc.spellcheck_continuously || new_word_.empty()) return ; - if (!inTexted()) - clearNewWordPosition(); - else { - // forget the position of the current new word if - // 1) the paragraph changes or - // 2) the count of nested insets changes or - // 3) the cursor pos is out of paragraph bound - if (pit() != new_word_.pit() || - depth() != new_word_.depth() || - new_word_.pos() > new_word_.lastpos()) { + // forget the position of the current new word if + // 1) or the remembered position was "broken" + // 2) or the count of nested insets changed + // 3) the top-level inset is not the same anymore + // 4) the cell index changed + // 5) or the paragraph changed + // 6) or the cursor pos is out of paragraph bound + if (new_word_.fixIfBroken() + || depth() != new_word_.depth() + || &inset() != &new_word_.inset() + || pit() != new_word_.pit() + || idx() != new_word_.idx() + || new_word_.pos() > new_word_.lastpos()) clearNewWordPosition(); - } else if (new_word_.fixIfBroken()) - // 4) or the remembered position was "broken" - clearNewWordPosition(); - else { - FontSpan nw = locateWord(WHOLE_WORD); - if (!nw.empty()) { - FontSpan ow = new_word_.locateWord(WHOLE_WORD); - if (nw.intersect(ow).empty()) - clearNewWordPosition(); - else - LYXERR(Debug::DEBUG, "new word: " - << " par: " << pit() - << " pos: " << nw.first << ".." << nw.last); - } else { + else { + FontSpan nw = locateWord(WHOLE_WORD); + if (!nw.empty()) { + FontSpan ow = new_word_.locateWord(WHOLE_WORD); + if (nw.intersect(ow).empty()) clearNewWordPosition(); - } - } + else + LYXERR(Debug::DEBUG, "new word: " + << " par: " << pit() + << " pos: " << nw.first << ".." << nw.last); + } else + clearNewWordPosition(); } } @@ -498,6 +505,56 @@ void CursorData::clearSelection() } +int CursorData::countInsetsInSelection(InsetCode const & inset_code) +{ + if (!selection_) + return 0; + + DocIterator from, to; + from = selectionBegin(); + to = selectionEnd(); + + int count = 0; + + if (!from.nextInset()) //move to closest inset + from.forwardInset(); + + while (!from.empty() && from < to) { + Inset * inset = from.nextInset(); + if (!inset) + break; + if (inset->lyxCode() == inset_code) + count ++; + from.forwardInset(); + } + return count; +} + + +bool CursorData::insetInSelection(InsetCode const & inset_code) +{ + if (!selection_) + return false; + + DocIterator from, to; + from = selectionBegin(); + to = selectionEnd(); + + if (!from.nextInset()) //move to closest inset + from.forwardInset(); + + while (!from.empty() && from < to) { + Inset * inset = from.nextInset(); + if (!inset) + break; + if (inset->lyxCode() == inset_code) + return true; + from.forwardInset(); + } + return false; +} + + bool CursorData::fixIfBroken() { bool const broken_cursor = DocIterator::fixIfBroken(); @@ -515,6 +572,7 @@ bool CursorData::fixIfBroken() void CursorData::sanitize() { DocIterator::sanitize(); + new_word_.sanitize(); if (selection()) anchor_.sanitize(); else @@ -522,38 +580,18 @@ void CursorData::sanitize() } -bool CursorData::isInside(Inset const * p) const -{ - for (size_t i = 0; i != depth(); ++i) - if (&operator[](i).inset() == p) - return true; - return false; -} - - -void CursorData::leaveInset(Inset const & inset) -{ - for (size_t i = 0; i != depth(); ++i) { - if (&operator[](i).inset() == &inset) { - resize(i); - return; - } - } -} - - -bool CursorData::textUndo() +bool CursorData::undoAction() { - if (!buffer()->undo().textUndo(*this)) + if (!buffer()->undo().undoAction(*this)) return false; sanitize(); return true; } -bool CursorData::textRedo() +bool CursorData::redoAction() { - if (!buffer()->undo().textRedo(*this)) + if (!buffer()->undo().redoAction(*this)) return false; sanitize(); return true; @@ -578,6 +616,12 @@ void CursorData::endUndoGroup() const } +void CursorData::splitUndoGroup() const +{ + buffer()->undo().splitUndoGroup(*this); +} + + void CursorData::recordUndo(pit_type from, pit_type to) const { buffer()->undo().recordUndo(*this, from, to); @@ -872,6 +916,31 @@ void Cursor::pushBackward(Inset & p) } +void Cursor::editInsertedInset() +{ + LASSERT(!empty(), return); + if (pos() == 0) + return; + + InsetMath &p = prevMath(); + if (!p.isActive()) + return; + + posBackward(); + push(p); + p.idxFirst(*this); + // this could be a while() loop, but only one cell is not empty in + // cases we are interested in. The cell is not empty because we + // have inserted the selection in there. + if (!cell().empty()) { + // if it is not empty, move to the next one. + if (!inset().idxNext(*this)) + // If there is no next one, exit the inset. + popForward(); + } +} + + bool Cursor::popBackward() { LASSERT(!empty(), return false); @@ -1388,9 +1457,9 @@ bool Cursor::openable(MathAtom const & t) const return true; // we can't move into anything new during selection - if (depth() >= anchor_.depth()) + if (depth() >= realAnchor().depth()) return false; - if (t.nucleus() != &anchor_[depth()].inset()) + if (t.nucleus() != &realAnchor()[depth()].inset()) return false; return true; @@ -1492,14 +1561,11 @@ void Cursor::niceInsert(MathAtom const & t) plainInsert(t); // If possible, enter the new inset and move the contents of the selection if (t->isActive()) { - posBackward(); - // be careful here: don't use 'pushBackward(t)' as this we need to - // push the clone, not the original - pushBackward(*nextInset()); - // We may not use niceInsert here (recursion) + idx_type const idx = prevMath().asNestInset()->firstIdx(); MathData ar(buffer()); asArray(safe, ar); - insert(ar); + prevMath().cell(idx).insert(0, ar); + editInsertedInset(); } else if (t->asMacro() && !safe.empty()) { MathData ar(buffer()); asArray(safe, ar); @@ -1636,14 +1702,14 @@ bool Cursor::down() } -void Cursor::handleNest(MathAtom const & a, int c) +void Cursor::handleNest(MathAtom const & a) { - //lyxerr << "Cursor::handleNest: " << c << endl; + idx_type const idx = a.nucleus()->asNestInset()->firstIdx(); + //lyxerr << "Cursor::handleNest: " << idx << endl; MathAtom t = a; - asArray(cap::grabAndEraseSelection(*this), t.nucleus()->cell(c)); + asArray(cap::grabAndEraseSelection(*this), t.nucleus()->cell(idx)); insert(t); - posBackward(); - pushBackward(*nextInset()); + editInsertedInset(); } @@ -1673,7 +1739,7 @@ void Cursor::setTargetX() } -bool Cursor::macroModeClose() +bool Cursor::macroModeClose(bool cancel) { if (!inMacroMode()) return false; @@ -1685,14 +1751,15 @@ bool Cursor::macroModeClose() --pos(); cell().erase(pos()); - // do nothing if the macro name is empty - if (s == "\\") - return false; - // trigger updates of macros, at least, if no full // updates take place anyway screenUpdateFlags(Update::Force); + // do nothing if the macro name is empty + if (s == "\\" || cancel) { + return false; + } + docstring const name = s.substr(1); InsetMathNest * const in = inset().asInsetMath()->asNestInset(); if (in && in->interpretString(*this, s)) @@ -1704,12 +1771,13 @@ bool Cursor::macroModeClose() // try to put argument into macro, if we just inserted a macro bool macroArg = false; InsetMathMacro * atomAsMacro = atom.nucleus()->asMacro(); + InsetMathNest * atomAsNest = atom.nucleus()->asNestInset(); if (atomAsMacro) { // macros here are still unfolded (in init mode in fact). So // we have to resolve the macro here manually and check its arity // to put the selection behind it if arity > 0. MacroData const * data = buffer()->getMacro(atomAsMacro->name()); - if (!selection.empty() && data && data->numargs() - data->optionals() > 0) { + if (!selection.empty() && data && data->numargs()) { macroArg = true; atomAsMacro->setDisplayMode(InsetMathMacro::DISPLAY_INTERACTIVE_INIT, 1); } else @@ -1718,8 +1786,8 @@ bool Cursor::macroModeClose() } // insert remembered selection into first argument of a non-macro - else if (atom.nucleus()->nargs() > 0) - atom.nucleus()->cell(0).append(selection); + else if (atomAsNest && atomAsNest->nargs() > 0) + atomAsNest->cell(atomAsNest->firstIdx()).append(selection); MathWordList const & words = mathedWordList(); MathWordList::const_iterator it = words.find(name); @@ -1771,13 +1839,13 @@ bool Cursor::inMacroMode() const InsetMathUnknown * Cursor::activeMacro() { - return inMacroMode() ? prevAtom().nucleus()->asUnknownInset() : 0; + return inMacroMode() ? prevAtom().nucleus()->asUnknownInset() : nullptr; } InsetMathUnknown const * Cursor::activeMacro() const { - return inMacroMode() ? prevAtom().nucleus()->asUnknownInset() : 0; + return inMacroMode() ? prevAtom().nucleus()->asUnknownInset() : nullptr; } @@ -2105,15 +2173,15 @@ bool Cursor::upDownInText(bool up, bool & updateNeeded) // with and without selection are handled differently if (!selection()) { - int yo = bv().getPos(*this).y_; + int yo1 = bv().getPos(*this).y_; Cursor old = *this; // To next/previous row // FIXME: the y position is often guessed wrongly across styles and // insets, which leads to weird behaviour. if (up) - tm.editXY(*this, xo, yo - textRow().ascent() - 1); + tm.editXY(*this, xo, yo1 - textRow().ascent() - 1); else - tm.editXY(*this, xo, yo + textRow().descent() + 1); + tm.editXY(*this, xo, yo1 + textRow().descent() + 1); x_target_ = old.x_target_; clearSelection(); @@ -2141,10 +2209,10 @@ bool Cursor::upDownInText(bool up, bool & updateNeeded) --next_row; } else if (pit() > 0) { --pit(); - TextMetrics & tm = bv_->textMetrics(text()); - if (!tm.contains(pit())) - tm.newParMetricsUp(); - ParagraphMetrics const & pmcur = tm.parMetrics(pit()); + TextMetrics & tm2 = bv_->textMetrics(text()); + if (!tm2.contains(pit())) + tm2.newParMetricsUp(); + ParagraphMetrics const & pmcur = tm2.parMetrics(pit()); next_row = pmcur.rows().size() - 1; } } else { @@ -2152,9 +2220,9 @@ bool Cursor::upDownInText(bool up, bool & updateNeeded) ++next_row; } else if (pit() + 1 < int(text()->paragraphs().size())) { ++pit(); - TextMetrics & tm = bv_->textMetrics(text()); - if (!tm.contains(pit())) - tm.newParMetricsDown(); + TextMetrics & tm2 = bv_->textMetrics(text()); + if (!tm2.contains(pit())) + tm2.newParMetricsDown(); next_row = 0; } } @@ -2232,6 +2300,12 @@ void Cursor::screenUpdateFlags(Update::flags f) const } +void Cursor::noScreenUpdate() const +{ + disp_.screenUpdate(Update::None); +} + + void Cursor::forceBufferUpdate() const { disp_.forceBufferUpdate(); @@ -2250,12 +2324,6 @@ bool Cursor::needBufferUpdate() const } -void Cursor::noScreenUpdate() const -{ - disp_.screenUpdate(Update::None); -} - - Font Cursor::getFont() const { // The logic here should more or less match to the @@ -2293,9 +2361,8 @@ Font Cursor::getFont() const void Cursor::sanitize() { - setBuffer(buffer()); + setBuffer(&bv_->buffer()); CursorData::sanitize(); - new_word_.sanitize(); } @@ -2336,6 +2403,20 @@ bool notifyCursorLeavesOrEnters(Cursor const & old, Cursor & cur) } +void Cursor::setLanguageFromInput() +{ + if (!lyxrc.respect_os_kbd_language) + return; + string const & code = theApp()->inputLanguageCode(); + Language const * lang = languages.getFromCode(code, buffer()->getLanguages()); + if (lang) { + current_font.setLanguage(lang); + real_current_font.setLanguage(lang); + } else + LYXERR0("setLanguageFromCode: unknown language code " << code); +} + + void Cursor::setCurrentFont() { CursorSlice const & cs = innerTextSlice(); @@ -2369,6 +2450,9 @@ void Cursor::setCurrentFont() current_font = par.getFontSettings(bufparams, cpos); real_current_font = tm.displayFont(cpit, cpos); + // set language to input language + setLanguageFromInput(); + // special case for paragraph end if (cs.pos() == lastpos() && tm.isRTLBoundary(cpit, cs.pos()) @@ -2390,12 +2474,6 @@ void Cursor::checkBufferStructure() // In case the master has no gui associated with it, // the TocItem is not updated (part of bug 5699). buffer()->tocBackend().updateItem(*this); - - // If the last tracked change of the paragraph has just been - // deleted, then we need to recompute the buffer flag - // tracked_changes_present_. - if (inTexted() && paragraph().isChangeUpdateRequired()) - disp_.forceChangesUpdate(); }