diff --git a/src/buffer/katetextblock.h b/src/buffer/katetextblock.h --- a/src/buffer/katetextblock.h +++ b/src/buffer/katetextblock.h @@ -21,6 +21,8 @@ #ifndef KATE_TEXTBLOCK_H #define KATE_TEXTBLOCK_H +#include + #include #include diff --git a/src/buffer/katetextblock.cpp b/src/buffer/katetextblock.cpp --- a/src/buffer/katetextblock.cpp +++ b/src/buffer/katetextblock.cpp @@ -150,7 +150,7 @@ // move all cursors on the line which has the text inserted // remember all ranges modified - QSet changedRanges; + std::vector changedRanges; foreach (TextCursor *cursor, m_cursors) { // skip cursors on lines in front of the wrapped one! if (cursor->lineInBlock() < line) { @@ -183,13 +183,17 @@ // remember range, if any if (cursor->kateRange()) { - changedRanges.insert(cursor->kateRange()); + cursor->kateRange()->m_isCheckValidityRequired = true; + changedRanges.push_back(cursor->kateRange()); } } - // check validity of all ranges, might invalidate them... - foreach (TextRange *range, changedRanges) { - range->checkValidity(); + // we might need to invalidate ranges or notify about their changes + for (TextRange *range : changedRanges) { + if (range->m_isCheckValidityRequired) { + range->checkValidity(); + range->m_isCheckValidityRequired = false; + } } } @@ -246,16 +250,17 @@ // move all cursors because of the unwrapped line // remember all ranges modified - QSet changedRanges; + std::vector changedRanges; foreach (TextCursor *cursor, m_cursors) { // this is the unwrapped line if (cursor->lineInBlock() == 0) { // patch column cursor->m_column += oldSizeOfPreviousLine; // remember range, if any if (cursor->kateRange()) { - changedRanges.insert(cursor->kateRange()); + cursor->kateRange()->m_isCheckValidityRequired = true; + changedRanges.push_back(cursor->kateRange()); } } } @@ -270,24 +275,27 @@ // remember range, if any if (cursor->kateRange()) { - changedRanges.insert(cursor->kateRange()); + cursor->kateRange()->m_isCheckValidityRequired = true; + changedRanges.push_back(cursor->kateRange()); } } else { newPreviousCursors.insert(cursor); } } previousBlock->m_cursors = newPreviousCursors; // fixup the ranges that might be effected, because they moved from last line to this block - foreach (TextRange *range, changedRanges) { - // update both blocks - updateRange(range); - previousBlock->updateRange(range); - } - - // check validity of all ranges, might invalidate them... - foreach (TextRange *range, changedRanges) { - range->checkValidity(); + // we might need to invalidate ranges or notify about their changes + for (TextRange *range : changedRanges) { + if (range->m_isCheckValidityRequired) { + // update both blocks + updateRange(range); + previousBlock->updateRange(range); + + // afterwards check validity + range->checkValidity(); + range->m_isCheckValidityRequired = false; + } } // be done @@ -333,7 +341,7 @@ // move all cursors because of the unwrapped line // remember all ranges modified - QSet changedRanges; + std::vector changedRanges; foreach (TextCursor *cursor, m_cursors) { // skip cursors in lines in front of removed one if (cursor->lineInBlock() < line) { @@ -350,14 +358,18 @@ cursor->m_line--; // remember range, if any - if (cursor->kateRange()) { - changedRanges.insert(cursor->kateRange()); + if (cursor->kateRange()) { + cursor->kateRange()->m_isCheckValidityRequired = true; + changedRanges.push_back(cursor->kateRange()); } } - // check validity of all ranges, might invalidate them... - foreach (TextRange *range, changedRanges) { - range->checkValidity(); + // we might need to invalidate ranges or notify about their changes + for (TextRange *range : changedRanges) { + if (range->m_isCheckValidityRequired) { + range->checkValidity(); + range->m_isCheckValidityRequired = false; + } } } @@ -394,7 +406,7 @@ // move all cursors on the line which has the text inserted // remember all ranges modified - QSet changedRanges; + std::vector changedRanges; foreach (TextCursor *cursor, m_cursors) { // skip cursors not on this line! if (cursor->lineInBlock() != line) { @@ -418,15 +430,19 @@ cursor->m_column = textOfLine.size(); } - // remember range, if any - if (cursor->kateRange()) { - changedRanges.insert(cursor->kateRange()); + // we only need to trigger checkValidity later if the range has feedback or might be invalidated + if (cursor->kateRange() && (cursor->kateRange()->feedback() || cursor->kateRange()->start().line() == cursor->kateRange()->end().line())) { + cursor->kateRange()->m_isCheckValidityRequired = true; + changedRanges.push_back(cursor->kateRange()); } } - // check validity of all ranges, might invalidate them... - foreach (TextRange *range, changedRanges) { - range->checkValidity(); + // we might need to invalidate ranges or notify about their changes + for (TextRange *range : changedRanges) { + if (range->m_isCheckValidityRequired) { + range->checkValidity(); + range->m_isCheckValidityRequired = false; + } } } @@ -468,7 +484,7 @@ // move all cursors on the line which has the text removed // remember all ranges modified - QSet changedRanges; + std::vector changedRanges; foreach (TextCursor *cursor, m_cursors) { // skip cursors not on this line! if (cursor->lineInBlock() != line) { @@ -487,15 +503,19 @@ cursor->m_column -= (range.end().column() - range.start().column()); } - // remember range, if any - if (cursor->kateRange()) { - changedRanges.insert(cursor->kateRange()); + // we only need to trigger checkValidity later if the range has feedback or might be invalidated + if (cursor->kateRange() && (cursor->kateRange()->feedback() || cursor->kateRange()->start().line() == cursor->kateRange()->end().line())) { + cursor->kateRange()->m_isCheckValidityRequired = true; + changedRanges.push_back(cursor->kateRange()); } } - // check validity of all ranges, might invalidate them... - foreach (TextRange *range, changedRanges) { - range->checkValidity(); + // we might need to invalidate ranges or notify about their changes + for (TextRange *range : changedRanges) { + if (range->m_isCheckValidityRequired) { + range->checkValidity(); + range->m_isCheckValidityRequired = false; + } } } diff --git a/src/buffer/katetextcursor.cpp b/src/buffer/katetextcursor.cpp --- a/src/buffer/katetextcursor.cpp +++ b/src/buffer/katetextcursor.cpp @@ -82,8 +82,18 @@ void TextCursor::setPosition(const KTextEditor::Cursor &position, bool init) { // any change or init? else do nothing - if (!init && position.line() == line() && position.column() == m_column) { - return; + if (!init && position.line() == line()) { + // simple case: 1:1 equal + if (position.column() == m_column) + return; + + // ok, too: both old and new column are valid, we can just adjust the column and be done + if (position.column() >= 0 && m_column >= 0) { + m_column = position.column(); + return; + } + + // else: we need to handle the change in a more complex way, new or old column are not valid! } // remove cursor from old block in any case diff --git a/src/buffer/katetextrange.h b/src/buffer/katetextrange.h --- a/src/buffer/katetextrange.h +++ b/src/buffer/katetextrange.h @@ -356,6 +356,12 @@ * Will this range invalidate itself if it becomes empty? */ bool m_invalidateIfEmpty; + + /** + * Should this range be validated? + * Used by KateTextBlock to avoid double updates without costly hashing. + */ + bool m_isCheckValidityRequired = false; }; } diff --git a/src/document/katedocument.h b/src/document/katedocument.h --- a/src/document/katedocument.h +++ b/src/document/katedocument.h @@ -360,9 +360,9 @@ QStack editStateStack; bool editIsRunning = false; bool m_undoMergeAllEdits = false; + KTextEditor::Cursor m_editLastChangeStartCursor = KTextEditor::Cursor::invalid(); QStack> m_editingStack; int m_editingStackPosition = -1; - static const int s_editingStackSizeLimit = 32; // // KTextEditor::UndoInterface stuff @@ -381,7 +381,7 @@ * If the consecutive editings happens in the same line, then remove * the previous and add the new one with updated column no. */ - void saveEditingPositions(KTextEditor::Document *, const KTextEditor::Range &range); + void saveEditingPositions(const KTextEditor::Cursor &cursor); public: uint undoCount() const; diff --git a/src/document/katedocument.cpp b/src/document/katedocument.cpp --- a/src/document/katedocument.cpp +++ b/src/document/katedocument.cpp @@ -295,8 +295,6 @@ connect(this, SIGNAL(sigQueryClose(bool*,bool*)), this, SLOT(slotQueryClose_save(bool*,bool*))); - connect(this, &KTextEditor::DocumentPrivate::textRemoved, this, &KTextEditor::DocumentPrivate::saveEditingPositions); - connect(this, &KTextEditor::DocumentPrivate::textInserted, this, &KTextEditor::DocumentPrivate::saveEditingPositions); connect(this, SIGNAL(aboutToInvalidateMovingInterfaceContent(KTextEditor::Document*)), this, SLOT(clearEditingPosStack())); onTheFlySpellCheckingEnabled(config()->onTheFlySpellCheck()); } @@ -347,21 +345,40 @@ } //END -void KTextEditor::DocumentPrivate::saveEditingPositions(KTextEditor::Document *, const KTextEditor::Range &range) +void KTextEditor::DocumentPrivate::saveEditingPositions(const KTextEditor::Cursor &cursor) { if (m_editingStackPosition != m_editingStack.size() - 1) { m_editingStack.resize(m_editingStackPosition); } - KTextEditor::MovingInterface *moving = qobject_cast(this); - const auto c = range.start(); - QSharedPointer mc (moving->newMovingCursor(c)); - if (!m_editingStack.isEmpty() && c.line() == m_editingStack.top()->line()) { - m_editingStack.pop(); + + // try to be clever: reuse existing cursors if possible + QSharedPointer mc; + + // we might pop last one: reuse that + if (!m_editingStack.isEmpty() && cursor.line() == m_editingStack.top()->line()) { + mc = m_editingStack.pop(); } - m_editingStack.push(mc); - if (m_editingStack.size() > s_editingStackSizeLimit) { - m_editingStack.removeFirst(); + + // we might expire oldest one, reuse that one, if not already one there + // we prefer the other one for reuse, as already on the right line aka in the right block! + const int editingStackSizeLimit = 32; + if (m_editingStack.size() >= editingStackSizeLimit) { + if (mc) { + m_editingStack.removeFirst(); + } else { + mc = m_editingStack.takeFirst(); + } } + + // new cursor needed? or adjust existing one? + if (mc) { + mc->setPosition(cursor); + } else { + mc = QSharedPointer (newMovingCursor(cursor)); + } + + // add new one as top of stack + m_editingStack.push(mc); m_editingStackPosition = m_editingStack.size() - 1; } @@ -728,22 +745,20 @@ } } + // compute expanded column for block mode + int positionColumnExpanded = insertColumn; const int tabWidth = config()->tabWidth(); - - static const QChar newLineChar(QLatin1Char('\n')); - - int insertColumnExpanded = insertColumn; - Kate::TextLine l = plainKateTextLine(currentLine); - if (l) { - insertColumnExpanded = l->toVirtualColumn(insertColumn, tabWidth); + if (block) { + if (auto l = plainKateTextLine(currentLine)) { + positionColumnExpanded = l->toVirtualColumn(insertColumn, tabWidth); + } } - int positionColumnExpanded = insertColumnExpanded; int pos = 0; for (; pos < totalLength; pos++) { const QChar &ch = text.at(pos); - if (ch == newLineChar) { + if (ch == QLatin1Char('\n')) { // Only perform the text insert if there is text to insert if (currentLineStart < pos) { editInsertText(currentLine, insertColumn, text.mid(currentLineStart, pos - currentLineStart)); @@ -755,9 +770,9 @@ } currentLine++; - l = plainKateTextLine(currentLine); if (block) { + auto l = plainKateTextLine(currentLine); if (currentLine == lastLine() + 1) { editInsertLine(currentLine, QString()); } @@ -768,9 +783,6 @@ } currentLineStart = pos + 1; - if (l) { - insertColumnExpanded = l->toVirtualColumn(insertColumn, tabWidth); - } } } @@ -990,6 +1002,9 @@ editIsRunning = true; + // no last change cursor at start + m_editLastChangeStartCursor = KTextEditor::Cursor::invalid(); + m_undoManager->editStart(); foreach (KTextEditor::ViewPrivate *view, m_views) { @@ -1038,6 +1053,12 @@ emit textChanged(this); } + // remember last change position in the stack, if any + // this avoid costly updates for longer editing transactions + // before we did that on textInsert/Removed + if (m_editLastChangeStartCursor.isValid()) + saveEditingPositions(m_editLastChangeStartCursor); + editIsRunning = false; return true; } @@ -1228,8 +1249,11 @@ m_undoManager->slotTextInserted(line, col2, s2); + // remember last change cursor + m_editLastChangeStartCursor = KTextEditor::Cursor(line, col2); + // insert text into line - m_buffer->insertText(KTextEditor::Cursor(line, col2), s2); + m_buffer->insertText(m_editLastChangeStartCursor, s2); emit textInserted(this, KTextEditor::Range(line, col2, line, col2 + s2.length())); @@ -1276,8 +1300,11 @@ m_undoManager->slotTextRemoved(line, col, oldText); + // remember last change cursor + m_editLastChangeStartCursor = KTextEditor::Cursor(line, col); + // remove text from line - m_buffer->removeText(KTextEditor::Range(KTextEditor::Cursor(line, col), KTextEditor::Cursor(line, col + len))); + m_buffer->removeText(KTextEditor::Range(m_editLastChangeStartCursor, KTextEditor::Cursor(line, col + len))); emit textRemoved(this, KTextEditor::Range(line, col, line, col + len), oldText); @@ -1381,6 +1408,9 @@ } } + // remember last change cursor + m_editLastChangeStartCursor = KTextEditor::Cursor(line, col); + emit textInserted(this, KTextEditor::Range(line, col, line + 1, 0)); editEnd(); @@ -1449,6 +1479,9 @@ emit marksChanged(this); } + // remember last change cursor + m_editLastChangeStartCursor = KTextEditor::Cursor(line, col); + emit textRemoved(this, KTextEditor::Range(line, col, line + 1, 0), QStringLiteral("\n")); editEnd(); @@ -1519,6 +1552,9 @@ rangeInserted.setEnd(KTextEditor::Cursor(line + 1, 0)); } + // remember last change cursor + m_editLastChangeStartCursor = rangeInserted.start(); + emit textInserted(this, rangeInserted); editEnd(); @@ -1612,6 +1648,9 @@ } } + // remember last change cursor + m_editLastChangeStartCursor = rangeRemoved.start(); + emit textRemoved(this, rangeRemoved, oldText.join(QStringLiteral("\n")) + QLatin1Char('\n')); editEnd(); diff --git a/src/search/katematch.h b/src/search/katematch.h --- a/src/search/katematch.h +++ b/src/search/katematch.h @@ -22,7 +22,10 @@ #ifndef KATE_MATCH_H #define KATE_MATCH_H +#include + #include +#include namespace KTextEditor { class DocumentPrivate; } @@ -46,6 +49,12 @@ KTextEditor::DocumentPrivate *const m_document; const KTextEditor::SearchOptions m_options; QVector m_resultRanges; + + /** + * moving range to track replace changes + * kept for later reuse + */ + std::unique_ptr m_afterReplaceRange; }; #endif // KATE_MATCH_H diff --git a/src/search/katematch.cpp b/src/search/katematch.cpp --- a/src/search/katematch.cpp +++ b/src/search/katematch.cpp @@ -22,7 +22,6 @@ #include "kateregexpsearch.h" #include "katedocument.h" -#include KateMatch::KateMatch(KTextEditor::DocumentPrivate *document, KTextEditor::SearchOptions options) : m_document(document) @@ -41,22 +40,24 @@ KTextEditor::Range KateMatch::replace(const QString &replacement, bool blockMode, int replacementCounter) { // Placeholders depending on search mode - const bool usePlaceholders = m_options.testFlag(KTextEditor::Regex) || - m_options.testFlag(KTextEditor::EscapeSequences); + // skip place-holder stuff if we have no \ at all inside the replacement, the buildReplacement is expensive + const bool usePlaceholders = (m_options.testFlag(KTextEditor::Regex) || + m_options.testFlag(KTextEditor::EscapeSequences)) + && replacement.contains(QLatin1Char('\\')); const QString finalReplacement = usePlaceholders ? buildReplacement(replacement, blockMode, replacementCounter) : replacement; - // Track replacement operation - KTextEditor::MovingRange *const afterReplace = m_document->newMovingRange(range(), KTextEditor::MovingRange::ExpandLeft | KTextEditor::MovingRange::ExpandRight); - - blockMode = blockMode && !range().onSingleLine(); - m_document->replaceText(range(), finalReplacement, blockMode); - - const KTextEditor::Range result = *afterReplace; - delete afterReplace; + // Track replacement operation, reuse range if already there + if (m_afterReplaceRange) { + m_afterReplaceRange->setRange(range()); + } else { + m_afterReplaceRange.reset(m_document->newMovingRange(range(), KTextEditor::MovingRange::ExpandLeft | KTextEditor::MovingRange::ExpandRight)); + } - return result; + // replace and return results range + m_document->replaceText(range(), finalReplacement, blockMode && !range().onSingleLine()); + return m_afterReplaceRange->toRange(); } KTextEditor::Range KateMatch::range() const diff --git a/src/search/katesearchbar.cpp b/src/search/katesearchbar.cpp --- a/src/search/katesearchbar.cpp +++ b/src/search/katesearchbar.cpp @@ -49,6 +49,9 @@ #include #include +#include +#include + // Turn debug messages on/off here // #define FAST_DEBUG_ENABLE @@ -803,49 +806,58 @@ const bool regexMode = enabledOptions.testFlag(Regex); const bool multiLinePattern = regexMode ? KateRegExp(searchPattern()).isMultiLine() : false; - KTextEditor::MovingRange *workingRange = m_view->doc()->newMovingRange(inputRange); - QList highlightRanges; + std::unique_ptr workingRange(m_view->doc()->newMovingRange(inputRange)); int matchCounter = 0; + // we highlight all ranges of a replace, up to some hard limit + // e.g. if you replace 100000 things, rendering will break down otherwise ;=) + const int maxHighlightings = 65536; + std::vector highlightRanges; + + // reuse match object to avoid massive moving range creation + KateMatch match(m_view->doc(), enabledOptions); + bool block = m_view->selection() && m_view->blockSelection(); int line = inputRange.start().line(); do { if (block) { - workingRange = m_view->doc()->newMovingRange(m_view->doc()->rangeOnLine(inputRange, line)); + workingRange.reset(m_view->doc()->newMovingRange(m_view->doc()->rangeOnLine(inputRange, line))); } for (;;) { - KateMatch match(m_view->doc(), enabledOptions); match.searchText(*workingRange, searchPattern()); if (!match.isValid()) { break; } bool const originalMatchEmpty = match.isEmpty(); // Work with the match + Range lastRange; if (replacement != nullptr) { if (matchCounter == 0) { static_cast(m_view->document())->startEditing(); } // Replace - const Range afterReplace = match.replace(*replacement, false, ++matchCounter); + lastRange = match.replace(*replacement, false, ++matchCounter); + } else { + lastRange = match.range(); + ++matchCounter; + } - // Highlight and continue after adjusted match - //highlightReplacement(*afterReplace); - highlightRanges << afterReplace; + // remember ranges if limit not reached + if (matchCounter < maxHighlightings) { + highlightRanges.push_back(lastRange); } else { - // Highlight and continue after original match - //highlightMatch(match); - highlightRanges << match.range(); - matchCounter++; + highlightRanges.clear(); } // Continue after match - if (highlightRanges.last().end() >= workingRange->end()) { + if (lastRange.end() >= workingRange->end()) { break; } - KTextEditor::DocumentCursor workingStart(m_view->doc(), highlightRanges.last().end()); + + KTextEditor::DocumentCursor workingStart(m_view->doc(), lastRange.end()); if (originalMatchEmpty) { // Can happen for regex patterns like "^". // If we don't advance here we will loop forever... @@ -873,26 +885,27 @@ } // Add ScrollBarMarks - KTextEditor::MarkInterface* iface = qobject_cast(m_view->document()); - if (iface) { - iface->setMarkDescription(KTextEditor::MarkInterface::SearchMatch, i18n("SearchHighLight")); - iface->setMarkPixmap(KTextEditor::MarkInterface::SearchMatch, QIcon().pixmap(0,0)); - foreach (Range r, highlightRanges) { - iface->addMark(r.start().line(), KTextEditor::MarkInterface::SearchMatch); + if (!highlightRanges.empty()) { + KTextEditor::MarkInterface* iface = qobject_cast(m_view->document()); + if (iface) { + iface->setMarkDescription(KTextEditor::MarkInterface::SearchMatch, i18n("SearchHighLight")); + iface->setMarkPixmap(KTextEditor::MarkInterface::SearchMatch, QIcon().pixmap(0,0)); + for (const Range &r : highlightRanges) { + iface->addMark(r.start().line(), KTextEditor::MarkInterface::SearchMatch); + } } } // Add highlights - if (replacement == nullptr) - foreach (Range r, highlightRanges) { + if (replacement == nullptr) { + for (const Range &r : highlightRanges) { highlightMatch(r); } - else - foreach (Range r, highlightRanges) { + } else { + for (const Range &r : highlightRanges) { highlightReplacement(r); } - - delete workingRange; + } // restore connection connect(m_view, SIGNAL(selectionChanged(KTextEditor::View*)), this, SLOT(updateSelectionOnly())); diff --git a/src/utils/documentcursor.cpp b/src/utils/documentcursor.cpp --- a/src/utils/documentcursor.cpp +++ b/src/utils/documentcursor.cpp @@ -117,7 +117,10 @@ bool DocumentCursor::atEndOfDocument() const { - return m_cursor == document()->documentEnd(); + // avoid costly lineLength computation if we are not in the last line + // this is called often e.g. during search & replace, >> 2% of the total costs + const auto lastLine = document()->lines() - 1; + return line() == lastLine && column() == document()->lineLength(lastLine); } bool DocumentCursor::gotoNextLine() @@ -166,7 +169,7 @@ if (wrapBehavior == Wrap && c.column() > lineLength) { c.setColumn(lineLength); } - + while (chars != 0) { if (wrapBehavior == Wrap) { const int advance = qMin(lineLength - c.column(), chars); @@ -190,7 +193,7 @@ chars = 0; } } - } + } // backwards? else { diff --git a/src/vimode/marks.h b/src/vimode/marks.h --- a/src/vimode/marks.h +++ b/src/vimode/marks.h @@ -69,7 +69,7 @@ void syncViMarksAndBookmarks(); bool isShowable(const QChar &mark); - void setMark(const QChar &mark, const KTextEditor::Cursor &pos, const bool moveoninsert = true); + void setMark(const QChar &mark, const KTextEditor::Cursor &pos); private Q_SLOTS: void markChanged(KTextEditor::Document *doc, diff --git a/src/vimode/marks.cpp b/src/vimode/marks.cpp --- a/src/vimode/marks.cpp +++ b/src/vimode/marks.cpp @@ -79,44 +79,50 @@ config.writeEntry("ViMarks", l); } -void Marks::setMark(const QChar &_mark, const KTextEditor::Cursor &pos, const bool moveoninsert) +void Marks::setMark(const QChar &_mark, const KTextEditor::Cursor &pos) { + // move on insert is type based, this allows to reuse cursors! + // reuse is important for editing intensive things like replace-all + const bool moveoninsert = _mark != BeginEditYanked; + m_settingMark = true; - uint marktype = m_doc->mark(pos.line()); // ` and ' is the same register (position before jump) const QChar mark = (_mark == BeforeJumpAlter) ? BeforeJump : _mark; - // delete old cursor if any + // if we have already a cursor for this type: adjust it + bool needToAdjustVisibleMark = true; if (KTextEditor::MovingCursor *oldCursor = m_marks.value(mark)) { - - int number_of_marks = 0; - - foreach (QChar c, m_marks.keys()) { - if (m_marks.value(c)->line() == oldCursor->line()) { - number_of_marks++; + // cleanup mark display only if line changes + needToAdjustVisibleMark = oldCursor->line() != pos.line(); + if (needToAdjustVisibleMark) { + int number_of_marks = 0; + foreach (QChar c, m_marks.keys()) { + if (m_marks.value(c)->line() == oldCursor->line()) { + number_of_marks++; + } + } + if (number_of_marks == 1) { + m_doc->removeMark(oldCursor->line(), KTextEditor::MarkInterface::markType01); } } - if (number_of_marks == 1 && pos.line() != oldCursor->line()) { - m_doc->removeMark(oldCursor->line(), KTextEditor::MarkInterface::markType01); - } - - delete oldCursor; + // adjust position + oldCursor->setPosition(pos); + } else { + // if no old mark of that type, create new one + const KTextEditor::MovingCursor::InsertBehavior behavior = moveoninsert ? KTextEditor::MovingCursor::MoveOnInsert : KTextEditor::MovingCursor::StayOnInsert; + m_marks.insert(mark, m_doc->newMovingCursor(pos, behavior)); } - KTextEditor::MovingCursor::InsertBehavior behavior = moveoninsert ? KTextEditor::MovingCursor::MoveOnInsert : KTextEditor::MovingCursor::StayOnInsert; - // create and remember new one - m_marks.insert(mark, m_doc->newMovingCursor(pos, behavior)); - - // Showing what mark we set: + // Showing what mark we set, can be skipped if we did not change the line if (isShowable(mark)) { - if (!(marktype & KTextEditor::MarkInterface::markType01)) { + if (needToAdjustVisibleMark && !(m_doc->mark(pos.line()) & KTextEditor::MarkInterface::markType01)) { m_doc->addMark(pos.line(), KTextEditor::MarkInterface::markType01); } // only show message for active view - if ( m_inputModeManager->view()->viewInputMode() == KTextEditor::View::ViInputMode ) { + if (m_inputModeManager->view()->viewInputMode() == KTextEditor::View::ViInputMode) { if (m_doc->activeView() == m_inputModeManager->view()) { m_inputModeManager->getViNormalMode()->message(i18n("Mark set: %1", mark)); } @@ -244,7 +250,7 @@ void Marks::setStartEditYanked(const KTextEditor::Cursor &pos) { - setMark(BeginEditYanked, pos, false); + setMark(BeginEditYanked, pos); } void Marks::setFinishEditYanked(const KTextEditor::Cursor &pos)