diff --git a/src/buffer/katetextblock.cpp b/src/buffer/katetextblock.cpp --- a/src/buffer/katetextblock.cpp +++ b/src/buffer/katetextblock.cpp @@ -418,13 +418,13 @@ cursor->m_column = textOfLine.size(); } - // remember range, if any - if (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())) { changedRanges.insert(cursor->kateRange()); } } - // check validity of all ranges, might invalidate them... + // we might need to invalidate ranges or notify about their changes foreach (TextRange *range, changedRanges) { range->checkValidity(); } @@ -487,13 +487,13 @@ cursor->m_column -= (range.end().column() - range.start().column()); } - // remember range, if any - if (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())) { changedRanges.insert(cursor->kateRange()); } } - // check validity of all ranges, might invalidate them... + // we might need to invalidate ranges or notify about their changes foreach (TextRange *range, changedRanges) { range->checkValidity(); } diff --git a/src/document/katedocument.cpp b/src/document/katedocument.cpp --- a/src/document/katedocument.cpp +++ b/src/document/katedocument.cpp @@ -352,16 +352,36 @@ 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)); + + // try to be clever: reuse existing cursors if possible + QSharedPointer mc; + + // we might pop last one: reuse that if (!m_editingStack.isEmpty() && c.line() == m_editingStack.top()->line()) { - m_editingStack.pop(); + 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! + if (m_editingStack.size() >= s_editingStackSizeLimit) { + if (mc) { + m_editingStack.removeFirst(); + } else { + mc = m_editingStack.takeFirst(); + } } + + // new cursor needed? or adjust existing one? + if (mc) { + mc->setPosition(c); + } else { + mc = QSharedPointer (newMovingCursor(c)); + } + + // add new one as top of stack + m_editingStack.push(mc); m_editingStackPosition = m_editingStack.size() - 1; } @@ -728,22 +748,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 +773,9 @@ } currentLine++; - l = plainKateTextLine(currentLine); if (block) { + auto l = plainKateTextLine(currentLine); if (currentLine == lastLine() + 1) { editInsertLine(currentLine, QString()); } @@ -768,9 +786,6 @@ } currentLineStart = pos + 1; - if (l) { - insertColumnExpanded = l->toVirtualColumn(insertColumn, tabWidth); - } } } diff --git a/src/search/katesearchbar.cpp b/src/search/katesearchbar.cpp --- a/src/search/katesearchbar.cpp +++ b/src/search/katesearchbar.cpp @@ -811,6 +811,7 @@ int line = inputRange.start().line(); do { if (block) { + delete workingRange; workingRange = m_view->doc()->newMovingRange(m_view->doc()->rangeOnLine(inputRange, line)); } 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)