int KateViInsertMode::findNextMergeableBracketPos(const Cursor& startPos) { const QString lineAfterCursor = doc()->text(Range(startPos, Cursor(startPos.line(), doc()->lineLength(startPos.line())))); QRegExp whitespaceThenOpeningBracket("^\\s*(\\()"); int nextMergableBracketAfterCursorPos = -1; if (lineAfterCursor.contains(whitespaceThenOpeningBracket)) { nextMergableBracketAfterCursorPos = whitespaceThenOpeningBracket.pos(1); } return nextMergableBracketAfterCursorPos; }
bool KateViInsertMode::commandMoveOneWordLeft() { Cursor c( m_view->cursorPosition() ); c = findPrevWordStart( c.line(), c.column() ); if (!c.isValid()) { c = Cursor(0,0); } updateCursor( c ); return true; }
void RangeTest::testRangeStringConversion() { using KTextEditor::Cursor; using KTextEditor::Range; KTextEditor::Range r; QCOMPARE(r.start(), Cursor(0, 0)); QCOMPARE(r.end(), Cursor(0, 0)); QCOMPARE(r.toString(), QStringLiteral("[(0, 0), (0, 0)]")); r = Range::fromString(QStringLiteral("[(0, 0), (0, 0)]")); QCOMPARE(r.toString(), QStringLiteral("[(0, 0), (0, 0)]")); r = Range::fromString(QStringLiteral("[(0,0),(0,0)]")); QCOMPARE(r.toString(), QStringLiteral("[(0, 0), (0, 0)]")); r = Range::fromString(QStringLiteral("[(-1, -1), (-1, -1)]")); QCOMPARE(r.toString(), QStringLiteral("[(-1, -1), (-1, -1)]")); r = Range::fromString(QStringLiteral("[(-1, -1), (0, 0)]")); QCOMPARE(r.toString(), QStringLiteral("[(-1, -1), (0, 0)]")); r = Range::fromString(QStringLiteral("[(0, 0), (-1, -1)]")); QCOMPARE(r.toString(), QStringLiteral("[(-1, -1), (0, 0)]")); // start > end -> swap r = Range::fromString(QStringLiteral("[(0, 0), (12, 42)]")); QCOMPARE(r.toString(), QStringLiteral("[(0, 0), (12, 42)]")); r = Range::fromString(QStringLiteral("[(12, 42), (0, 0)]")); QCOMPARE(r.toString(), QStringLiteral("[(0, 0), (12, 42)]")); // start > end -> swap r = Range::fromString(QStringLiteral("[(12,42),(0,0)]")); QCOMPARE(r.toString(), QStringLiteral("[(0, 0), (12, 42)]")); // start > end -> swap r = Range::fromString(QStringLiteral("[(-12, -42), (0, 0)]")); QCOMPARE(r.toString(), QStringLiteral("[(-12, -42), (0, 0)]")); r = Range::fromString(QStringLiteral("[(0, 0), (-12, -42)]")); QCOMPARE(r.toString(), QStringLiteral("[(-12, -42), (0, 0)]")); // start > end -> swap // invalid input r = Range::fromString(QStringLiteral("[(0:0)(-12:-42)]")); QCOMPARE(r.toString(), QStringLiteral("[(-1, -1), (-1, -1)]")); r = Range::fromString(QStringLiteral("[0,1]")); QCOMPARE(r.toString(), QStringLiteral("[(-1, -1), (-1, -1)]")); }
// Start Normal mode just for one command and return to Insert mode bool KateViInsertMode::commandSwitchToNormalModeForJustOneCommand(){ m_viInputModeManager->setTemporaryNormalMode(true); m_viInputModeManager->changeViMode(NormalMode); const Cursor cursorPos = m_view->cursorPosition(); // If we're at end of the line, move the cursor back one step, as in Vim. if (doc()->line(cursorPos.line()).length() == cursorPos.column()) { m_view->setCursorPosition(Cursor(cursorPos.line(), cursorPos.column() - 1)); } m_view->setCaretStyle( KateRenderer::Block, true ); m_view->updateViModeBarMode(); m_viewInternal->repaint(); return true; }
void KateViInsertMode::replayCompletion() { const KateViInputModeManager::Completion completion = m_viInputModeManager->nextLoggedCompletion(); // Find beginning of the word. Cursor cursorPos = m_view->cursorPosition(); Cursor wordStart = Cursor::invalid(); if (!doc()->character(cursorPos).isLetterOrNumber() && doc()->character(cursorPos) != '_') { cursorPos.setColumn(cursorPos.column() - 1); } while (cursorPos.column() >= 0 && (doc()->character(cursorPos).isLetterOrNumber() || doc()->character(cursorPos) == '_')) { wordStart = cursorPos; cursorPos.setColumn(cursorPos.column() - 1); } // Find end of current word. cursorPos = m_view->cursorPosition(); Cursor wordEnd = Cursor(cursorPos.line(), cursorPos.column() - 1); while (cursorPos.column() < doc()->lineLength(cursorPos.line()) && (doc()->character(cursorPos).isLetterOrNumber() || doc()->character(cursorPos) == '_')) { wordEnd = cursorPos; cursorPos.setColumn(cursorPos.column() + 1); } QString completionText = completion.completedText(); const Range currentWord = Range(wordStart, Cursor(wordEnd.line(), wordEnd.column() + 1)); // Should we merge opening brackets? Yes, if completion is a function with arguments and after the cursor // there is (optional whitespace) followed by an open bracket. int offsetFinalCursorPosBy = 0; if (completion.completionType() == KateViInputModeManager::Completion::FunctionWithArgs) { const int nextMergableBracketAfterCursorPos = findNextMergeableBracketPos(currentWord.end()); if (nextMergableBracketAfterCursorPos != -1) { if (completionText.endsWith("()")) { // Strip "()". completionText = completionText.left(completionText.length() - 2); } else if (completionText.endsWith("();")) { // Strip "();". completionText = completionText.left(completionText.length() - 3); } // Ensure cursor ends up after the merged open bracket. offsetFinalCursorPosBy = nextMergableBracketAfterCursorPos + 1; } else { if (!completionText.endsWith("()") && !completionText.endsWith("();")) { // Original completion merged with an opening bracket; we'll have to add our own brackets. completionText.append("()"); } // Position cursor correctly i.e. we'll have added "functionname()" or "functionname();"; need to step back by // one or two to be after the opening bracket. offsetFinalCursorPosBy = completionText.endsWith(';') ? -2 : -1; } } Cursor deleteEnd = completion.removeTail() ? currentWord.end() : Cursor(m_view->cursorPosition().line(), m_view->cursorPosition().column() + 0); if (currentWord.isValid()) { doc()->removeText(Range(currentWord.start(), deleteEnd)); doc()->insertText(currentWord.start(), completionText); } else { doc()->insertText(m_view->cursorPosition(), completionText); } if (offsetFinalCursorPosBy != 0) { m_view->setCursorPosition(Cursor(m_view->cursorPosition().line(), m_view->cursorPosition().column() + offsetFinalCursorPosBy)); } if (!m_viInputModeManager->isReplayingLastChange()) { Q_ASSERT(m_viInputModeManager->isReplayingMacro()); // Post the completion back: it needs to be added to the "last change" list ... m_viInputModeManager->logCompletionEvent(completion); // ... but don't log the ctrl-space that led to this call to replayCompletion(), as // a synthetic ctrl-space was just added to the last change keypresses by logCompletionEvent(), and we don't // want to duplicate them! m_viInputModeManager->doNotLogCurrentKeypress(); } }
// leave insert mode when esc, etc, is pressed. if leaving block // prepend/append, the inserted text will be added to all block lines. if // ctrl-c is used to exit insert mode this is not done. void KateViInsertMode::leaveInsertMode( bool force ) { m_view->abortCompletion(); if ( !force ) { if ( m_blockInsert != None ) { // block append/prepend // make sure cursor haven't been moved if ( m_blockRange.startLine == m_view->cursorPosition().line() ) { int start, len; QString added; Cursor c; switch ( m_blockInsert ) { case Append: case Prepend: if ( m_blockInsert == Append ) { start = m_blockRange.endColumn+1; } else { start = m_blockRange.startColumn; } len = m_view->cursorPosition().column()-start; added = getLine().mid( start, len ); c = Cursor( m_blockRange.startLine, start ); for ( int i = m_blockRange.startLine+1; i <= m_blockRange.endLine; i++ ) { c.setLine( i ); doc()->insertText( c, added ); } break; case AppendEOL: start = m_eolPos; len = m_view->cursorPosition().column()-start; added = getLine().mid( start, len ); c = Cursor( m_blockRange.startLine, start ); for ( int i = m_blockRange.startLine+1; i <= m_blockRange.endLine; i++ ) { c.setLine( i ); c.setColumn( doc()->lineLength( i ) ); doc()->insertText( c, added ); } break; default: error("not supported"); } } m_blockInsert = None; } else { const QString added = doc()->text(Range(m_viInputModeManager->getMarkPosition('^'), m_view->cursorPosition())); if (m_count > 1) { for (unsigned int i = 0; i < m_count - 1; i++) { if (m_countedRepeatsBeginOnNewLine) { doc()->newLine(m_view); } doc()->insertText( m_view->cursorPosition(), added ); } } } } m_countedRepeatsBeginOnNewLine = false; startNormalMode(); }