11#include "katebuffer.h"
13#include "katecompletionwidget.h"
14#include "kateconfig.h"
15#include "katedocument.h"
16#include "kateglobal.h"
17#include "katepartdebug.h"
18#include "katerenderer.h"
19#include "kateundomanager.h"
20#include "kateviewhelpers.h"
21#include "kateviewinternal.h"
22#include "kateviinputmode.h"
23#include <ktexteditor/attribute.h>
24#include <vimode/emulatedcommandbar/emulatedcommandbar.h>
25#include <vimode/globalstate.h>
26#include <vimode/history.h>
27#include <vimode/inputmodemanager.h>
28#include <vimode/keymapper.h>
29#include <vimode/keyparser.h>
30#include <vimode/lastchangerecorder.h>
31#include <vimode/macrorecorder.h>
32#include <vimode/marks.h>
33#include <vimode/modes/insertvimode.h>
34#include <vimode/modes/normalvimode.h>
35#include <vimode/modes/replacevimode.h>
36#include <vimode/modes/visualvimode.h>
37#include <vimode/registers.h>
38#include <vimode/searcher.h>
40#include <KLocalizedString>
41#include <QApplication>
44using namespace KateVi;
46NormalViMode::NormalViMode(InputModeManager *viInputModeManager, KTextEditor::ViewPrivate *view, KateViewInternal *viewInternal)
50 m_viewInternal = viewInternal;
51 m_viInputModeManager = viInputModeManager;
53 m_lastMotionWasVisualLineUpOrDown =
false;
54 m_currentMotionWasVisualLineUpOrDown =
false;
57 m_extraWordCharacters =
QString();
58 m_matchingItems[QStringLiteral(
"/*")] = QStringLiteral(
"*/");
59 m_matchingItems[QStringLiteral(
"*/")] = QStringLiteral(
"-/*");
61 m_matchItemRegex = generateMatchingItemRegex();
63 m_scroll_count_limit = 1000;
65 m_pendingResetIsDueToExit =
false;
66 m_isRepeatedTFcommand =
false;
67 m_lastMotionWasLinewiseInnerBlock =
false;
68 m_motionCanChangeWholeVisualModeSelection =
false;
72 connect(doc()->undoManager(), &KateUndoManager::undoStart,
this, &NormalViMode::undoBeginning);
73 connect(doc()->undoManager(), &KateUndoManager::undoEnd,
this, &NormalViMode::undoEnded);
75 updateYankHighlightAttrib();
80NormalViMode::~NormalViMode()
82 qDeleteAll(m_highlightedYanks);
91 const int keyCode = e->
key();
102 m_viInputModeManager->inputAdapter()->setCaretStyle(KTextEditor::caretStyles::Block);
103 m_pendingResetIsDueToExit =
true;
107 m_viInputModeManager->setTemporaryNormalMode(
false);
112 const QChar key = KeyParser::self()->KeyEventToQChar(*e);
114 const QChar lastChar = m_keys.isEmpty() ?
QChar::Null : m_keys.at(m_keys.size() - 1);
115 const bool waitingForRegisterOrCharToSearch = this->waitingForRegisterOrCharToSearch();
118 if (key ==
QLatin1Char(
'r') && !waitingForRegisterOrCharToSearch) {
119 m_viInputModeManager->inputAdapter()->setCaretStyle(KTextEditor::caretStyles::Underline);
122 m_keysVerbatim.append(KeyParser::self()->decodeKeySequence(key));
126 && (m_countTemp != 0 || keyCode !=
Qt::Key_0)
127 && (!waitingForRegisterOrCharToSearch)
132 }
else if (m_countTemp != 0) {
133 m_count = getCount() * m_countTemp;
140 if (m_viInputModeManager->macroRecorder()->isRecording() && key ==
QLatin1Char(
'q')) {
143 m_viInputModeManager->macroRecorder()->stop();
156 m_positionWhenIncrementalSearchBegan = m_view->cursorPosition();
158 commandSearchForward();
160 commandSearchBackward();
171 const bool isWORD = (m_keys.at(1) ==
QLatin1Char(
'W'));
174 : findWordEnd(currentPosition.
line(), currentPosition.
column() - 1,
true));
176 if (currentPosition == endOfWordOrWORD) {
177 m_keys = QStringLiteral(
"cl");
180 m_keys = QStringLiteral(
"cE");
182 m_keys = QStringLiteral(
"ce");
188 if (m_keys.size() < 2) {
195 m_register = m_keys[1];
206 if (!m_matchingCommands.isEmpty()) {
207 int n = m_matchingCommands.size() - 1;
210 for (
int i = n; i >= 0; i--) {
211 if (!
commands().at(m_matchingCommands.at(i)).matches(m_keys)) {
212 if (
commands().at(m_matchingCommands.at(i)).needsMotion()) {
214 m_motionOperatorIndex = m_matchingCommands.at(i);
216 m_matchingCommands.remove(i);
223 for (
int i = 0; i < m_matchingCommands.size(); i++) {
224 if (
commands().at(m_matchingCommands.at(i)).needsMotion()) {
225 m_awaitingMotionOrTextObject.push(m_keys.size());
231 for (
size_t i = 0; i <
commands().size(); i++) {
232 if (
commands().at(i).matches(m_keys)) {
233 m_matchingCommands.push_back(i);
234 if (
commands().at(i).needsMotion() &&
commands().at(i).pattern().length() == m_keys.size()) {
235 m_awaitingMotionOrTextObject.push(m_keys.size());
242 int checkFrom = (m_awaitingMotionOrTextObject.isEmpty() ? 0 : m_awaitingMotionOrTextObject.top());
247 if (m_viInputModeManager->getCurrentViMode() == ViMode::NormalMode && !m_awaitingMotionOrTextObject.isEmpty()) {
248 m_viInputModeManager->inputAdapter()->setCaretStyle(KTextEditor::caretStyles::Half);
254 bool motionExecuted =
false;
255 if (checkFrom < m_keys.size()) {
256 for (
size_t i = 0; i <
motions().size(); i++) {
258 if (
motions().at(i).matches(motion)) {
259 m_lastMotionWasLinewiseInnerBlock =
false;
260 m_matchingMotions.push_back(i);
263 if (
motions().at(i).matchesExact(motion)) {
264 m_currentMotionWasVisualLineUpOrDown =
false;
265 motionExecuted =
true;
266 if (checkFrom == 0) {
269 Range r =
motions().at(i).execute(
this);
270 m_motionCanChangeWholeVisualModeSelection =
motions().at(i).canChangeWholeVisualModeSelection();
272 if (!
motions().at(i).canLandInsideFoldingRange()) {
275 int currLine = m_view->cursorPosition().line();
276 int delta = r.endLine - currLine;
277 int vline = m_view->textFolding().lineToVisibleLine(currLine);
278 r.endLine = m_view->textFolding().visibleLineToLine(qMax(vline + delta, 0) );
281 if (r.endLine >= doc()->lines()) {
282 r.endLine = doc()->lines() - 1;
287 if (r.valid && r.endLine >= 0 && (r.endLine == 0 || r.endLine <= doc()->lines() - 1) && r.endColumn >= 0) {
288 if (r.endColumn >= doc()->lineLength(r.endLine) && doc()->lineLength(r.endLine) > 0) {
289 r.endColumn = doc()->lineLength(r.endLine) - 1;
295 if (!m_viInputModeManager->isAnyVisualMode()) {
296 m_viInputModeManager->clearCurrentChangeLog();
299 qCDebug(LOG_KTE) <<
"Invalid position: (" << r.endLine <<
"," << r.endColumn <<
")";
306 if (m_viInputModeManager->getTemporaryNormalMode()) {
308 m_viewInternal->repaint();
311 m_lastMotionWasVisualLineUpOrDown = m_currentMotionWasVisualLineUpOrDown;
318 m_commandRange =
motions().at(i).execute(
this);
319 m_linewiseCommand =
motions().at(i).isLineWise();
322 if (m_commandRange.startLine == -1) {
324 m_commandRange.startLine = c.
line();
325 m_commandRange.startColumn = c.
column();
332 if (m_commandRange.endLine != m_commandRange.startLine && m_commandRange.endColumn ==
getFirstNonBlank(m_commandRange.endLine)) {
333 m_commandRange.endLine--;
334 m_commandRange.endColumn = doc()->lineLength(m_commandRange.endLine);
338 m_commandWithMotion =
true;
340 if (m_commandRange.valid) {
341 executeCommand(&
commands().at(m_motionOperatorIndex));
343 qCDebug(LOG_KTE) <<
"Invalid range: "
344 <<
"from (" << m_commandRange.startLine <<
"," << m_commandRange.startColumn <<
")"
345 <<
"to (" << m_commandRange.endLine <<
"," << m_commandRange.endColumn <<
")";
348 if (m_viInputModeManager->getCurrentViMode() == ViMode::NormalMode) {
349 m_viInputModeManager->inputAdapter()->setCaretStyle(KTextEditor::caretStyles::Block);
351 m_commandWithMotion =
false;
360 if (this->waitingForRegisterOrCharToSearch()) {
365 m_viInputModeManager->keyMapper()->setDoNotMapNextKeypress();
368 if (motionExecuted) {
374 if (m_matchingCommands.size() == 1) {
375 if (
commands().at(m_matchingCommands.at(0)).matchesExact(m_keys) && !
commands().at(m_matchingCommands.at(0)).needsMotion()) {
376 if (m_viInputModeManager->getCurrentViMode() == ViMode::NormalMode) {
377 m_viInputModeManager->inputAdapter()->setCaretStyle(KTextEditor::caretStyles::Block);
380 const Command &cmd =
commands().at(m_matchingCommands.at(0));
381 executeCommand(&cmd);
384 if (cmd.shouldReset()) {
386 m_view->setBlockSelection(
false);
392 }
else if (m_matchingCommands.size() == 0 && m_matchingMotions.size() == 0) {
402 m_matchingMotions.clear();
413 m_keysVerbatim.clear();
415 m_oneTimeCountOverride = -1;
419 m_findWaitingForChar =
false;
420 m_matchingCommands.clear();
421 m_matchingMotions.clear();
422 m_awaitingMotionOrTextObject.clear();
423 m_motionOperatorIndex = 0;
425 m_commandWithMotion =
false;
426 m_linewiseCommand =
true;
427 m_deleteCommand =
false;
429 m_commandShouldKeepSelection =
false;
433 if (m_viInputModeManager->getCurrentViMode() == ViMode::NormalMode) {
434 m_viInputModeManager->inputAdapter()->setCaretStyle(KTextEditor::caretStyles::Block);
439void NormalViMode::reset()
442 m_commandRange.startLine = -1;
443 m_commandRange.startColumn = -1;
446void NormalViMode::beginMonitoringDocumentChanges()
452void NormalViMode::executeCommand(
const Command *cmd)
454 const ViMode originalViMode = m_viInputModeManager->getCurrentViMode();
460 if (m_viInputModeManager->getTemporaryNormalMode()) {
462 m_viewInternal->repaint();
467 if (m_viInputModeManager->getCurrentViMode() != ViMode::InsertMode && m_viInputModeManager->getCurrentViMode() != ViMode::ReplaceMode) {
468 if (cmd->isChange() && !m_viInputModeManager->lastChangeRecorder()->isReplaying()) {
469 m_viInputModeManager->storeLastChangeCommand();
474 const bool commandSwitchedToVisualMode = ((originalViMode == ViMode::NormalMode) && m_viInputModeManager->isAnyVisualMode());
475 if (!commandSwitchedToVisualMode) {
476 m_viInputModeManager->clearCurrentChangeLog();
481 KTextEditor::Cursor c(m_view->cursorPosition());
482 if (m_viInputModeManager->getCurrentViMode() == ViMode::NormalMode) {
483 int lineLength = doc()->lineLength(c.line());
485 if (c.column() >= lineLength) {
486 if (lineLength == 0) {
489 c.setColumn(lineLength - 1);
507 m_viInputModeManager->getViInsertMode()->setCount(getCount());
508 return startInsertMode();
521 if (doc()->lineLength(c.
line()) == 0) {
526 if (c.
column() > doc()->lineLength(c.
line())) {
533 m_viInputModeManager->getViInsertMode()->setCount(getCount());
534 return startInsertMode();
548 m_viInputModeManager->getViInsertMode()->setCount(getCount());
549 return startInsertMode();
552bool NormalViMode::commandEnterInsertModeBeforeFirstNonBlankInLine()
558 updateCursor(cursor);
561 m_viInputModeManager->getViInsertMode()->setCount(getCount());
562 return startInsertMode();
577 return startInsertMode();
580bool NormalViMode::commandEnterVisualLineMode()
582 if (m_viInputModeManager->getCurrentViMode() == VisualLineMode) {
587 return startVisualLineMode();
590bool NormalViMode::commandEnterVisualBlockMode()
592 if (m_viInputModeManager->getCurrentViMode() == VisualBlockMode) {
597 return startVisualBlockMode();
600bool NormalViMode::commandReselectVisual()
603 KTextEditor::Cursor c1 = m_viInputModeManager->marks()->getSelectionStart();
604 KTextEditor::Cursor c2 = m_viInputModeManager->marks()->getSelectionFinish();
610 m_viInputModeManager->getViVisualMode()->setStart(c1);
611 bool returnValue =
false;
613 switch (m_viInputModeManager->getViVisualMode()->getLastVisualMode()) {
614 case ViMode::VisualMode:
615 returnValue = commandEnterVisualMode();
617 case ViMode::VisualLineMode:
618 returnValue = commandEnterVisualLineMode();
620 case ViMode::VisualBlockMode:
621 returnValue = commandEnterVisualBlockMode();
624 Q_ASSERT(
"invalid visual mode");
626 m_viInputModeManager->getViVisualMode()->goToPos(c2);
629 error(QStringLiteral(
"No previous visual selection"));
635bool NormalViMode::commandEnterVisualMode()
637 if (m_viInputModeManager->getCurrentViMode() == ViMode::VisualMode) {
642 return startVisualMode();
645bool NormalViMode::commandToOtherEnd()
647 if (m_viInputModeManager->isAnyVisualMode()) {
648 m_viInputModeManager->getViVisualMode()->switchStartEnd();
655bool NormalViMode::commandEnterReplaceMode()
658 m_viInputModeManager->getViReplaceMode()->setCount(getCount());
659 return startReplaceMode();
662bool NormalViMode::commandDeleteLine()
664 KTextEditor::Cursor c(m_view->cursorPosition());
668 r.startLine = c.line();
669 r.endLine = c.line() + getCount() - 1;
671 int column = c.column();
673 bool ret = deleteRange(r, LineWise);
675 c = m_view->cursorPosition();
676 if (column > doc()->lineLength(c.line()) - 1) {
677 column = doc()->lineLength(c.line()) - 1;
683 if (c.line() > doc()->lines() - 1) {
684 c.setLine(doc()->lines() - 1);
691 m_deleteCommand =
true;
695bool NormalViMode::commandDelete()
697 m_deleteCommand =
true;
698 return deleteRange(m_commandRange, getOperationMode());
701bool NormalViMode::commandDeleteToEOL()
703 KTextEditor::Cursor c(m_view->cursorPosition());
704 OperationMode m = CharWise;
706 m_commandRange.endColumn = KateVi::EOL;
707 switch (m_viInputModeManager->getCurrentViMode()) {
708 case ViMode::NormalMode:
709 m_commandRange.startLine = c.line();
710 m_commandRange.startColumn = c.column();
711 m_commandRange.endLine = c.line() + getCount() - 1;
713 case ViMode::VisualMode:
714 case ViMode::VisualLineMode:
717 case ViMode::VisualBlockMode:
718 m_commandRange.normalize();
726 bool r = deleteRange(m_commandRange, m);
730 c.setColumn(doc()->lineLength(c.line()) - 1);
733 c.setLine(m_commandRange.startLine);
734 c.setColumn(
getFirstNonBlank(qMin(doc()->lastLine(), m_commandRange.startLine)));
737 c.setLine(m_commandRange.startLine);
738 c.setColumn(m_commandRange.startColumn - 1);
746 if (c.line() > doc()->lastLine()) {
747 c.setLine(doc()->lastLine());
749 if (c.column() > doc()->lineLength(c.line()) - 1) {
750 c.setColumn(doc()->lineLength(c.line()) - 1);
752 if (c.column() < 0) {
758 m_deleteCommand =
true;
762bool NormalViMode::commandMakeLowercase()
764 KTextEditor::Cursor c = m_view->cursorPosition();
766 OperationMode m = getOperationMode();
767 QString text = getRange(m_commandRange, m);
771 QString lowerCase = text.
toLower();
773 m_commandRange.normalize();
774 KTextEditor::Cursor
start(m_commandRange.startLine, m_commandRange.startColumn);
775 KTextEditor::Cursor
end(m_commandRange.endLine, m_commandRange.endColumn);
776 KTextEditor::Range range(
start, end);
778 doc()->replaceText(range, lowerCase, m == Block);
780 if (m_viInputModeManager->getCurrentViMode() == ViMode::NormalMode) {
789bool NormalViMode::commandMakeLowercaseLine()
791 KTextEditor::Cursor c(m_view->cursorPosition());
793 if (doc()->lineLength(c.
line()) == 0) {
798 m_commandRange.startLine = c.
line();
799 m_commandRange.endLine = c.
line() + getCount() - 1;
800 m_commandRange.startColumn = 0;
801 m_commandRange.endColumn = doc()->lineLength(c.
line()) - 1;
803 return commandMakeLowercase();
806bool NormalViMode::commandMakeUppercase()
808 if (!m_commandRange.valid) {
811 KTextEditor::Cursor c = m_view->cursorPosition();
812 OperationMode m = getOperationMode();
813 QString text = getRange(m_commandRange, m);
817 QString upperCase = text.
toUpper();
819 m_commandRange.normalize();
820 KTextEditor::Cursor
start(m_commandRange.startLine, m_commandRange.startColumn);
821 KTextEditor::Cursor
end(m_commandRange.endLine, m_commandRange.endColumn);
822 KTextEditor::Range range(
start, end);
824 doc()->replaceText(range, upperCase, m == Block);
825 if (m_viInputModeManager->getCurrentViMode() == ViMode::NormalMode) {
834bool NormalViMode::commandMakeUppercaseLine()
836 KTextEditor::Cursor c(m_view->cursorPosition());
838 if (doc()->lineLength(c.
line()) == 0) {
843 m_commandRange.startLine = c.
line();
844 m_commandRange.endLine = c.
line() + getCount() - 1;
845 m_commandRange.startColumn = 0;
846 m_commandRange.endColumn = doc()->lineLength(c.
line()) - 1;
848 return commandMakeUppercase();
851bool NormalViMode::commandChangeCase()
854 KTextEditor::Range range;
855 KTextEditor::Cursor c(m_view->cursorPosition());
858 if (m_viInputModeManager->getCurrentViMode() == ViMode::VisualMode || m_viInputModeManager->getCurrentViMode() == ViMode::VisualBlockMode) {
859 KTextEditor::Cursor c2 = m_viInputModeManager->getViVisualMode()->getStart();
870 }
else if (m_viInputModeManager->getCurrentViMode() == ViMode::VisualLineMode) {
871 KTextEditor::Cursor c2 = m_viInputModeManager->getViVisualMode()->getStart();
885 KTextEditor::Cursor c2 = c;
888 if (c2.
column() > doc()->lineLength(c.
line())) {
895 bool block = m_viInputModeManager->getCurrentViMode() == ViMode::VisualBlockMode;
898 text = doc()->text(range, block);
901 for (
int i = 0; i < text.
length(); i++) {
910 doc()->replaceText(range, text, block);
914 if (m_viInputModeManager->getCurrentViMode() == ViMode::NormalMode) {
915 updateCursor(range.
end());
917 updateCursor(range.
start());
923bool NormalViMode::commandChangeCaseRange()
925 OperationMode m = getOperationMode();
926 QString changedCase = getRange(m_commandRange, m);
930 KTextEditor::Range range = KTextEditor::Range(m_commandRange.startLine, m_commandRange.startColumn, m_commandRange.endLine, m_commandRange.endColumn);
933 for (
int i = 0; i < changedCase.
length(); i++) {
935 changedCase[i] = changedCase.
at(i).
toLower();
936 }
else if (changedCase.
at(i).
isLower()) {
937 changedCase[i] = changedCase.
at(i).
toUpper();
940 doc()->replaceText(range, changedCase, m == Block);
944bool NormalViMode::commandChangeCaseLine()
946 KTextEditor::Cursor c(m_view->cursorPosition());
948 if (doc()->lineLength(c.
line()) == 0) {
953 m_commandRange.startLine = c.
line();
954 m_commandRange.endLine = c.
line() + getCount() - 1;
955 m_commandRange.startColumn = 0;
956 m_commandRange.endColumn = doc()->lineLength(c.
line()) - 1;
958 if (!commandChangeCaseRange()) {
962 KTextEditor::Cursor
start(m_commandRange.startLine, m_commandRange.startColumn);
963 if (getCount() > 1) {
971bool NormalViMode::commandOpenNewLineUnder()
973 doc()->setUndoMergeAllEdits(
true);
975 KTextEditor::Cursor c(m_view->cursorPosition());
980 doc()->newLine(m_view);
984 m_viInputModeManager->getViInsertMode()->setCount(getCount());
985 m_viInputModeManager->getViInsertMode()->setCountedRepeatsBeginOnNewLine(
true);
990bool NormalViMode::commandOpenNewLineOver()
992 doc()->setUndoMergeAllEdits(
true);
994 KTextEditor::Cursor c(m_view->cursorPosition());
997 doc()->insertLine(0, QString());
1005 doc()->newLine(m_view);
1008 m_stickyColumn = -1;
1010 m_viInputModeManager->getViInsertMode()->setCount(getCount());
1011 m_viInputModeManager->getViInsertMode()->setCountedRepeatsBeginOnNewLine(
true);
1016bool NormalViMode::commandJoinLines()
1018 KTextEditor::Cursor c(m_view->cursorPosition());
1020 unsigned int from = c.
line();
1021 unsigned int to = c.
line() + ((getCount() == 1) ? 1 : getCount() - 1);
1024 if (m_commandRange.startLine != -1 && m_commandRange.endLine != -1) {
1025 m_commandRange.normalize();
1026 c.
setLine(m_commandRange.startLine);
1027 from = m_commandRange.startLine;
1028 to = m_commandRange.endLine;
1031 if (to >= (
unsigned int)doc()->lines()) {
1035 bool nonEmptyLineFound =
false;
1036 for (
unsigned int lineNum = from; lineNum <= to; lineNum++) {
1037 if (!doc()->line(lineNum).isEmpty()) {
1038 nonEmptyLineFound =
true;
1042 const int firstNonWhitespaceOnLastLine = doc()->kateTextLine(to).firstChar();
1043 QString leftTrimmedLastLine;
1044 if (firstNonWhitespaceOnLastLine != -1) {
1045 leftTrimmedLastLine = doc()->line(to).
mid(firstNonWhitespaceOnLastLine);
1048 joinLines(from, to);
1050 if (nonEmptyLineFound && leftTrimmedLastLine.
isEmpty()) {
1052 doc()->insertText(KTextEditor::Cursor(from, doc()->lineLength(from)), QStringLiteral(
" "));
1056 c.
setColumn(doc()->lineLength(from) - leftTrimmedLastLine.
length() - 1);
1061 m_deleteCommand =
true;
1065bool NormalViMode::commandChange()
1067 KTextEditor::Cursor c(m_view->cursorPosition());
1069 OperationMode m = getOperationMode();
1071 doc()->setUndoMergeAllEdits(
true);
1075 if (m == LineWise) {
1077 doc()->insertLine(m_commandRange.startLine, QString());
1078 c.
setLine(m_commandRange.startLine);
1080 }
else if (m == Block) {
1083 return commandPrependToBlock();
1085 if (m_commandRange.startLine < m_commandRange.endLine) {
1086 c.
setLine(m_commandRange.startLine);
1088 c.
setColumn(m_commandRange.startColumn);
1096 if (m == LineWise) {
1100 m_deleteCommand =
true;
1104bool NormalViMode::commandChangeToEOL()
1106 commandDeleteToEOL();
1108 if (getOperationMode() == Block) {
1109 return commandPrependToBlock();
1112 m_deleteCommand =
true;
1116bool NormalViMode::commandChangeLine()
1118 m_deleteCommand =
true;
1119 KTextEditor::Cursor c(m_view->cursorPosition());
1123 doc()->setUndoMergeAllEdits(
true);
1126 if (getCount() >= 2) {
1127 Range r(c.
line(), 0, c.
line() + getCount() - 2, 0, InclusiveMotion);
1133 deleteRange(r, CharWise,
true);
1136 if (getOperationMode() == Block) {
1137 return commandPrependToBlock();
1147bool NormalViMode::commandSubstituteChar()
1149 if (commandDeleteChar()) {
1155 m_deleteCommand =
true;
1159bool NormalViMode::commandSubstituteLine()
1161 m_deleteCommand =
true;
1162 return commandChangeLine();
1165bool NormalViMode::commandYank()
1170 OperationMode m = getOperationMode();
1171 yankedText = getRange(m_commandRange, m);
1173 highlightYank(m_commandRange, m);
1175 QChar chosen_register = getChosenRegister(ZeroRegister);
1176 fillRegister(chosen_register, yankedText, m);
1177 yankToClipBoard(chosen_register, yankedText);
1182bool NormalViMode::commandYankLine()
1184 KTextEditor::Cursor c(m_view->cursorPosition());
1186 int linenum = c.
line();
1188 for (
int i = 0; i < getCount(); i++) {
1189 lines.
append(getLine(linenum + i) + QLatin1Char(
'\n'));
1192 Range yankRange(linenum, 0, linenum + getCount() - 1, getLine(linenum + getCount() - 1).length(), InclusiveMotion);
1193 highlightYank(yankRange);
1195 QChar chosen_register = getChosenRegister(ZeroRegister);
1196 fillRegister(chosen_register, lines, LineWise);
1197 yankToClipBoard(chosen_register, lines);
1202bool NormalViMode::commandYankToEOL()
1204 OperationMode m = CharWise;
1205 KTextEditor::Cursor c(m_view->cursorPosition());
1207 MotionType motion = m_commandRange.motionType;
1208 m_commandRange.endLine = c.
line() + getCount() - 1;
1209 m_commandRange.endColumn = doc()->lineLength(m_commandRange.endLine) - 1;
1210 m_commandRange.motionType = InclusiveMotion;
1212 switch (m_viInputModeManager->getCurrentViMode()) {
1213 case ViMode::NormalMode:
1214 m_commandRange.startLine = c.
line();
1215 m_commandRange.startColumn = c.
column();
1217 case ViMode::VisualMode:
1218 case ViMode::VisualLineMode:
1221 VisualViMode *visual =
static_cast<VisualViMode *
>(
this);
1222 visual->setStart(KTextEditor::Cursor(visual->getStart().
line(), 0));
1225 case ViMode::VisualBlockMode:
1233 const QString &yankedText = getRange(m_commandRange, m);
1234 m_commandRange.motionType = motion;
1235 highlightYank(m_commandRange);
1237 QChar chosen_register = getChosenRegister(ZeroRegister);
1238 fillRegister(chosen_register, yankedText, m);
1239 yankToClipBoard(chosen_register, yankedText);
1250bool NormalViMode::commandPaste()
1252 return paste(AfterCurrentPosition,
false,
false);
1256bool NormalViMode::commandPasteBefore()
1258 return paste(AtCurrentPosition,
false,
false);
1266bool NormalViMode::commandgPaste()
1268 return paste(AfterCurrentPosition,
true,
false);
1273bool NormalViMode::commandgPasteBefore()
1275 return paste(AtCurrentPosition,
true,
false);
1278bool NormalViMode::commandIndentedPaste()
1280 return paste(AfterCurrentPosition,
false,
true);
1283bool NormalViMode::commandIndentedPasteBefore()
1285 return paste(AtCurrentPosition,
false,
true);
1288bool NormalViMode::commandDeleteChar()
1290 KTextEditor::Cursor c(m_view->cursorPosition());
1293 if (m_commandRange.startLine != -1 && m_commandRange.startColumn != -1) {
1296 if (r.endColumn > doc()->lineLength(r.startLine)) {
1297 r.endColumn = doc()->lineLength(r.startLine);
1302 OperationMode m = CharWise;
1303 if (m_viInputModeManager->getCurrentViMode() == VisualLineMode) {
1305 }
else if (m_viInputModeManager->getCurrentViMode() == VisualBlockMode) {
1309 m_deleteCommand =
true;
1310 return deleteRange(r, m);
1313bool NormalViMode::commandDeleteCharBackward()
1315 KTextEditor::Cursor c(m_view->cursorPosition());
1319 if (m_commandRange.startLine != -1 && m_commandRange.startColumn != -1) {
1322 if (r.startColumn < 0) {
1328 OperationMode m = CharWise;
1329 if (m_viInputModeManager->getCurrentViMode() == VisualLineMode) {
1331 }
else if (m_viInputModeManager->getCurrentViMode() == VisualBlockMode) {
1335 m_deleteCommand =
true;
1336 return deleteRange(r, m);
1339bool NormalViMode::commandReplaceCharacter()
1341 QString key = KeyParser::self()->decodeKeySequence(m_keys.right(1));
1344 const int keyCode = KeyParser::self()->encoded2qt(m_keys.right(1));
1361 key = QStringLiteral(
"\n");
1365 if (m_viInputModeManager->isAnyVisualMode()) {
1366 OperationMode m = getOperationMode();
1367 QString text = getRange(m_commandRange, m);
1369 if (m == LineWise) {
1373 static const QRegularExpression nonNewlineRegex(QStringLiteral(
"[^\n]"));
1374 text.
replace(nonNewlineRegex, key);
1376 m_commandRange.normalize();
1377 KTextEditor::Cursor
start(m_commandRange.startLine, m_commandRange.startColumn);
1378 KTextEditor::Cursor
end(m_commandRange.endLine, m_commandRange.endColumn);
1379 KTextEditor::Range range(
start, end);
1381 r = doc()->replaceText(range, text, m == Block);
1384 KTextEditor::Cursor c1(m_view->cursorPosition());
1385 KTextEditor::Cursor c2(m_view->cursorPosition());
1389 if (c2.
column() > doc()->lineLength(m_view->cursorPosition().line())) {
1393 r = doc()->replaceText(KTextEditor::Range(c1, c2), key.
repeated(getCount()));
1399bool NormalViMode::commandSwitchToCmdLine()
1401 QString initialText;
1402 if (m_viInputModeManager->isAnyVisualMode()) {
1404 m_viInputModeManager->getViVisualMode()->saveRangeMarks();
1405 initialText = QStringLiteral(
"'<,'>");
1406 }
else if (getCount() != 1) {
1409 initialText = QLatin1String(
".,.+") +
QString::number(getCount() - 1);
1412 m_viInputModeManager->inputAdapter()->showViModeEmulatedCommandBar();
1413 m_viInputModeManager->inputAdapter()->viModeEmulatedCommandBar()->init(EmulatedCommandBar::Command, initialText);
1415 m_commandShouldKeepSelection =
true;
1420bool NormalViMode::commandSearchBackward()
1422 m_viInputModeManager->inputAdapter()->showViModeEmulatedCommandBar();
1423 m_viInputModeManager->inputAdapter()->viModeEmulatedCommandBar()->init(EmulatedCommandBar::SearchBackward);
1427bool NormalViMode::commandSearchForward()
1429 m_viInputModeManager->inputAdapter()->showViModeEmulatedCommandBar();
1430 m_viInputModeManager->inputAdapter()->viModeEmulatedCommandBar()->init(EmulatedCommandBar::SearchForward);
1434bool NormalViMode::commandUndo()
1437 m_viInputModeManager->clearCurrentChangeLog();
1439 if (doc()->undoCount() > 0) {
1440 const bool mapped = m_viInputModeManager->keyMapper()->isExecutingMapping();
1449 if (m_viInputModeManager->isAnyVisualMode()) {
1450 m_viInputModeManager->getViVisualMode()->setStart(KTextEditor::Cursor(-1, -1));
1451 m_view->clearSelection();
1459bool NormalViMode::commandRedo()
1461 if (doc()->redoCount() > 0) {
1462 const bool mapped = m_viInputModeManager->keyMapper()->isExecutingMapping();
1471 if (m_viInputModeManager->isAnyVisualMode()) {
1472 m_viInputModeManager->getViVisualMode()->setStart(KTextEditor::Cursor(-1, -1));
1473 m_view->clearSelection();
1481bool NormalViMode::commandSetMark()
1483 KTextEditor::Cursor c(m_view->cursorPosition());
1485 QChar mark = m_keys.at(m_keys.size() - 1);
1486 m_viInputModeManager->marks()->setUserMark(mark, c);
1491bool NormalViMode::commandIndentLine()
1493 KTextEditor::Cursor c(m_view->cursorPosition());
1495 doc()->indent(KTextEditor::Range(c.
line(), 0, c.
line() + getCount(), 0), 1);
1500bool NormalViMode::commandUnindentLine()
1502 KTextEditor::Cursor c(m_view->cursorPosition());
1504 doc()->indent(KTextEditor::Range(c.
line(), 0, c.
line() + getCount(), 0), -1);
1509bool NormalViMode::commandIndentLines()
1511 const bool downwards = m_commandRange.startLine < m_commandRange.endLine;
1513 m_commandRange.normalize();
1515 int line1 = m_commandRange.startLine;
1516 int line2 = m_commandRange.endLine;
1517 int col = getLine(line2).length();
1518 doc()->indent(KTextEditor::Range(line1, 0, line2, col), getCount());
1521 updateCursor(KTextEditor::Cursor(m_commandRange.startLine, m_commandRange.startColumn));
1523 updateCursor(KTextEditor::Cursor(m_commandRange.endLine, m_commandRange.endColumn));
1528bool NormalViMode::commandUnindentLines()
1530 const bool downwards = m_commandRange.startLine < m_commandRange.endLine;
1532 m_commandRange.normalize();
1534 int line1 = m_commandRange.startLine;
1535 int line2 = m_commandRange.endLine;
1537 doc()->indent(KTextEditor::Range(line1, 0, line2, doc()->lineLength(line2)), -getCount());
1540 updateCursor(KTextEditor::Cursor(m_commandRange.startLine, m_commandRange.startColumn));
1542 updateCursor(KTextEditor::Cursor(m_commandRange.endLine, m_commandRange.endColumn));
1547bool NormalViMode::commandScrollPageDown()
1549 if (getCount() < m_scroll_count_limit) {
1550 for (
int i = 0; i < getCount(); i++) {
1557bool NormalViMode::commandScrollPageUp()
1559 if (getCount() < m_scroll_count_limit) {
1560 for (
int i = 0; i < getCount(); i++) {
1567bool NormalViMode::commandScrollHalfPageUp()
1569 if (getCount() < m_scroll_count_limit) {
1570 for (
int i = 0; i < getCount(); i++) {
1571 m_viewInternal->pageUp(
false,
true);
1577bool NormalViMode::commandScrollHalfPageDown()
1579 if (getCount() < m_scroll_count_limit) {
1580 for (
int i = 0; i < getCount(); i++) {
1581 m_viewInternal->pageDown(
false,
true);
1587bool NormalViMode::commandCenterView(
bool onFirst)
1589 KTextEditor::Cursor c(m_view->cursorPosition());
1590 const int virtualCenterLine = m_viewInternal->startLine() + linesDisplayed() / 2;
1591 const int virtualCursorLine = m_view->textFolding().lineToVisibleLine(c.
line());
1593 scrollViewLines(virtualCursorLine - virtualCenterLine);
1601bool NormalViMode::commandCenterViewOnNonBlank()
1603 return commandCenterView(
true);
1606bool NormalViMode::commandCenterViewOnCursor()
1608 return commandCenterView(
false);
1611bool NormalViMode::commandTopView(
bool onFirst)
1613 KTextEditor::Cursor c(m_view->cursorPosition());
1614 const int virtualCenterLine = m_viewInternal->startLine();
1615 const int virtualCursorLine = m_view->textFolding().lineToVisibleLine(c.
line());
1617 scrollViewLines(virtualCursorLine - virtualCenterLine);
1625bool NormalViMode::commandTopViewOnNonBlank()
1627 return commandTopView(
true);
1630bool NormalViMode::commandTopViewOnCursor()
1632 return commandTopView(
false);
1635bool NormalViMode::commandBottomView(
bool onFirst)
1637 KTextEditor::Cursor c(m_view->cursorPosition());
1638 const int virtualCenterLine = m_viewInternal->endLine();
1639 const int virtualCursorLine = m_view->textFolding().lineToVisibleLine(c.
line());
1641 scrollViewLines(virtualCursorLine - virtualCenterLine);
1649bool NormalViMode::commandBottomViewOnNonBlank()
1651 return commandBottomView(
true);
1654bool NormalViMode::commandBottomViewOnCursor()
1656 return commandBottomView(
false);
1659bool NormalViMode::commandAbort()
1661 m_pendingResetIsDueToExit =
true;
1666bool NormalViMode::commandPrintCharacterCode()
1668 QChar ch = getCharUnderCursor();
1671 message(QStringLiteral(
"NUL"));
1678 if (
oct.length() < 3) {
1679 oct.prepend(QLatin1Char(
'0'));
1681 if (code > 0x80 && code < 0x1000) {
1682 hex.prepend((code < 0x100 ? QLatin1String(
"00") : QLatin1String(
"0")));
1684 message(
i18n(
"'%1' %2, Hex %3, Octal %4", ch, dec, hex, oct));
1690bool NormalViMode::commandRepeatLastChange()
1692 const int repeatCount = getCount();
1694 if (repeatCount > 1) {
1695 m_oneTimeCountOverride = repeatCount;
1698 m_viInputModeManager->repeatLastChange();
1704bool NormalViMode::commandAlignLine()
1706 const int line = m_view->cursorPosition().line();
1707 KTextEditor::Range alignRange(KTextEditor::Cursor(line, 0), KTextEditor::Cursor(line, 0));
1709 doc()->align(m_view, alignRange);
1714bool NormalViMode::commandAlignLines()
1716 m_commandRange.normalize();
1718 KTextEditor::Cursor
start(m_commandRange.startLine, 0);
1719 KTextEditor::Cursor
end(m_commandRange.endLine, 0);
1721 doc()->align(m_view, KTextEditor::Range(
start, end));
1726bool NormalViMode::commandAddToNumber()
1728 addToNumberUnderCursor(getCount());
1733bool NormalViMode::commandSubtractFromNumber()
1735 addToNumberUnderCursor(-getCount());
1740bool NormalViMode::commandPrependToBlock()
1742 KTextEditor::Cursor c(m_view->cursorPosition());
1745 m_commandRange.normalize();
1746 c.
setColumn(m_commandRange.startColumn);
1747 c.
setLine(m_commandRange.startLine);
1750 m_stickyColumn = -1;
1751 m_viInputModeManager->getViInsertMode()->setBlockPrependMode(m_commandRange);
1752 return startInsertMode();
1755bool NormalViMode::commandAppendToBlock()
1757 KTextEditor::Cursor c(m_view->cursorPosition());
1759 m_commandRange.normalize();
1760 if (m_stickyColumn == (
unsigned int)KateVi::EOL) {
1762 c.
setLine(m_commandRange.startLine);
1765 m_viInputModeManager->getViInsertMode()->setBlockAppendMode(m_commandRange, AppendEOL);
1767 m_viInputModeManager->getViInsertMode()->setBlockAppendMode(m_commandRange, Append);
1769 c.
setColumn(m_commandRange.endColumn + 1);
1770 c.
setLine(m_commandRange.startLine);
1774 m_stickyColumn = -1;
1776 return startInsertMode();
1779bool NormalViMode::commandGoToNextJump()
1781 KTextEditor::Cursor c = getNextJump(m_view->cursorPosition());
1787bool NormalViMode::commandGoToPrevJump()
1789 KTextEditor::Cursor c = getPrevJump(m_view->cursorPosition());
1795bool NormalViMode::commandSwitchToLeftView()
1801bool NormalViMode::commandSwitchToDownView()
1807bool NormalViMode::commandSwitchToUpView()
1813bool NormalViMode::commandSwitchToRightView()
1819bool NormalViMode::commandSwitchToNextView()
1825bool NormalViMode::commandSplitHoriz()
1827 return executeKateCommand(QStringLiteral(
"split"));
1830bool NormalViMode::commandSplitVert()
1832 return executeKateCommand(QStringLiteral(
"vsplit"));
1835bool NormalViMode::commandCloseView()
1837 return executeKateCommand(QStringLiteral(
"close"));
1840bool NormalViMode::commandSwitchToNextTab()
1842 QString command = QStringLiteral(
"bn");
1848 return executeKateCommand(command);
1851bool NormalViMode::commandSwitchToPrevTab()
1853 QString command = QStringLiteral(
"bp");
1859 return executeKateCommand(command);
1862bool NormalViMode::commandFormatLine()
1864 KTextEditor::Cursor c(m_view->cursorPosition());
1866 reformatLines(c.
line(), c.
line() + getCount() - 1);
1871bool NormalViMode::commandFormatLines()
1873 reformatLines(m_commandRange.startLine, m_commandRange.endLine);
1877bool NormalViMode::commandCollapseToplevelNodes()
1879 m_view->slotFoldToplevelNodes();
1883bool NormalViMode::commandStartRecordingMacro()
1885 const QChar reg = m_keys[m_keys.size() - 1];
1886 m_viInputModeManager->macroRecorder()->start(reg);
1890bool NormalViMode::commandReplayMacro()
1895 m_viInputModeManager->clearCurrentChangeLog();
1896 const QChar reg = m_keys[m_keys.size() - 1];
1897 const unsigned int count = getCount();
1900 for (
unsigned int i = 0; i < count; i++) {
1901 m_viInputModeManager->macroRecorder()->replay(reg);
1907bool NormalViMode::commandCloseNocheck()
1909 return executeKateCommand(QStringLiteral(
"q!"));
1912bool NormalViMode::commandCloseWrite()
1914 return executeKateCommand(QStringLiteral(
"wq"));
1917bool NormalViMode::commandCollapseLocal()
1919 int line = m_view->cursorPosition().line();
1920 bool actionDone =
false;
1921 while (!actionDone && line > -1) {
1922 actionDone = m_view->foldLine(line--).isValid();
1927bool NormalViMode::commandExpandAll()
1930 m_view->slotExpandToplevelNodes();
1934bool NormalViMode::commandExpandLocal()
1936 int line = m_view->cursorPosition().line();
1937 return m_view->unfoldLine(line);
1940bool NormalViMode::commandToggleRegionVisibility()
1943 m_view->slotToggleFolding();
1951Range NormalViMode::motionDown()
1953 return goLineDown();
1956Range NormalViMode::motionUp()
1961Range NormalViMode::motionLeft()
1963 KTextEditor::Cursor cursor(m_view->cursorPosition());
1964 m_stickyColumn = -1;
1965 Range r(cursor, ExclusiveMotion);
1966 r.endColumn -= getCount();
1968 if (r.endColumn < 0) {
1975Range NormalViMode::motionRight()
1977 KTextEditor::Cursor cursor(m_view->cursorPosition());
1978 m_stickyColumn = -1;
1979 Range r(cursor, ExclusiveMotion);
1980 r.endColumn += getCount();
1983 if (r.endColumn > doc()->lineLength(r.endLine)) {
1984 r.endColumn = doc()->lineLength(r.endLine);
1990Range NormalViMode::motionPageDown()
1992 KTextEditor::Cursor c(m_view->cursorPosition());
1993 Range r(c, InclusiveMotion);
1994 r.endLine += linesDisplayed();
1996 if (r.endLine >= doc()->lines()) {
1997 r.endLine = doc()->lines() - 1;
2002Range NormalViMode::motionPageUp()
2004 KTextEditor::Cursor c(m_view->cursorPosition());
2005 Range r(c, InclusiveMotion);
2006 r.endLine -= linesDisplayed();
2008 if (r.endLine < 0) {
2014Range NormalViMode::motionHalfPageDown()
2016 if (commandScrollHalfPageDown()) {
2017 KTextEditor::Cursor c = m_view->cursorPosition();
2018 m_commandRange.endLine = c.
line();
2019 m_commandRange.endColumn = c.
column();
2020 return m_commandRange;
2025Range NormalViMode::motionHalfPageUp()
2027 if (commandScrollHalfPageUp()) {
2028 KTextEditor::Cursor c = m_view->cursorPosition();
2029 m_commandRange.endLine = c.
line();
2030 m_commandRange.endColumn = c.
column();
2031 return m_commandRange;
2036Range NormalViMode::motionDownToFirstNonBlank()
2038 Range r = goLineDown();
2043Range NormalViMode::motionUpToFirstNonBlank()
2045 Range r = goLineUp();
2050Range NormalViMode::motionWordForward()
2052 KTextEditor::Cursor c(m_view->cursorPosition());
2053 Range r(c, ExclusiveMotion);
2055 m_stickyColumn = -1;
2059 if (c.
line() == doc()->lines() - 1 && c.
column() == doc()->lineLength(c.
line()) - 1) {
2060 r.motionType = InclusiveMotion;
2062 for (
int i = 0; i < getCount(); i++) {
2067 c = doc()->documentEnd();
2070 if (i < getCount()) {
2071 r.motionType = InclusiveMotion;
2078 r.endColumn = c.
column();
2079 r.endLine = c.
line();
2084Range NormalViMode::motionWordBackward()
2086 KTextEditor::Cursor c(m_view->cursorPosition());
2087 Range r(c, ExclusiveMotion);
2089 m_stickyColumn = -1;
2091 for (
int i = 0; i < getCount(); i++) {
2095 c = KTextEditor::Cursor(0, 0);
2100 r.endColumn = c.
column();
2101 r.endLine = c.
line();
2106Range NormalViMode::motionWORDForward()
2108 KTextEditor::Cursor c(m_view->cursorPosition());
2109 Range r(c, ExclusiveMotion);
2111 m_stickyColumn = -1;
2113 for (
int i = 0; i < getCount(); i++) {
2117 if (c.
line() == doc()->lines() - 1 && c.
column() == doc()->lineLength(c.
line()) - 1) {
2122 r.endColumn = c.
column();
2123 r.endLine = c.
line();
2128Range NormalViMode::motionWORDBackward()
2130 KTextEditor::Cursor c(m_view->cursorPosition());
2131 Range r(c, ExclusiveMotion);
2133 m_stickyColumn = -1;
2135 for (
int i = 0; i < getCount(); i++) {
2139 c = KTextEditor::Cursor(0, 0);
2143 r.endColumn = c.
column();
2144 r.endLine = c.
line();
2149Range NormalViMode::motionToEndOfWord()
2151 KTextEditor::Cursor c(m_view->cursorPosition());
2152 Range r(c, InclusiveMotion);
2154 m_stickyColumn = -1;
2156 for (
int i = 0; i < getCount(); i++) {
2161 c = doc()->documentEnd();
2164 r.endColumn = c.
column();
2165 r.endLine = c.
line();
2170Range NormalViMode::motionToEndOfWORD()
2172 KTextEditor::Cursor c(m_view->cursorPosition());
2173 Range r(c, InclusiveMotion);
2175 m_stickyColumn = -1;
2177 for (
int i = 0; i < getCount(); i++) {
2182 c = doc()->documentEnd();
2185 r.endColumn = c.
column();
2186 r.endLine = c.
line();
2191Range NormalViMode::motionToEndOfPrevWord()
2193 KTextEditor::Cursor c(m_view->cursorPosition());
2194 Range r(c, InclusiveMotion);
2196 m_stickyColumn = -1;
2198 for (
int i = 0; i < getCount(); i++) {
2202 r.endColumn = c.
column();
2203 r.endLine = c.
line();
2214Range NormalViMode::motionToEndOfPrevWORD()
2216 KTextEditor::Cursor c(m_view->cursorPosition());
2217 Range r(c, InclusiveMotion);
2219 m_stickyColumn = -1;
2221 for (
int i = 0; i < getCount(); i++) {
2225 r.endColumn = c.
column();
2226 r.endLine = c.
line();
2237void NormalViMode::stickStickyColumnToEOL()
2239 if (m_keys.size() == 1) {
2240 m_stickyColumn = KateVi::EOL;
2244Range NormalViMode::motionToEOL()
2246 KTextEditor::Cursor c(m_view->cursorPosition());
2248 stickStickyColumnToEOL();
2250 unsigned int line = c.
line() + (getCount() - 1);
2251 Range r(line, doc()->lineLength(line) - 1, InclusiveMotion);
2255Range NormalViMode::motionToLastNonBlank()
2257 KTextEditor::Cursor c(m_view->cursorPosition());
2259 stickStickyColumnToEOL();
2261 unsigned int line = c.
line() + (getCount() - 1);
2263 const auto text_line = doc()->plainKateTextLine(line);
2264 Range r(line, text_line.previousNonSpaceChar(text_line.length()), InclusiveMotion);
2268Range NormalViMode::motionToColumn0()
2270 m_stickyColumn = -1;
2271 KTextEditor::Cursor cursor(m_view->cursorPosition());
2272 Range r(cursor.line(), 0, ExclusiveMotion);
2277Range NormalViMode::motionToFirstCharacterOfLine()
2279 m_stickyColumn = -1;
2281 KTextEditor::Cursor cursor(m_view->cursorPosition());
2284 Range r(cursor.line(), c, ExclusiveMotion);
2289Range NormalViMode::motionFindChar()
2291 m_lastTFcommand = m_keys;
2292 KTextEditor::Cursor cursor(m_view->cursorPosition());
2293 QString line = getLine();
2295 m_stickyColumn = -1;
2297 int matchColumn = cursor.column();
2299 for (
int i = 0; i < getCount(); i++) {
2300 matchColumn = line.
indexOf(QStringView(m_keys).
right(1), matchColumn + 1);
2301 if (matchColumn == -1) {
2308 if (matchColumn != -1) {
2309 r.endColumn = matchColumn;
2310 r.endLine = cursor.line();
2318Range NormalViMode::motionFindCharBackward()
2320 m_lastTFcommand = m_keys;
2321 KTextEditor::Cursor cursor(m_view->cursorPosition());
2322 QString line = getLine();
2324 m_stickyColumn = -1;
2326 int matchColumn = -1;
2329 int i = cursor.column() - 1;
2331 while (hits != getCount() && i >= 0) {
2332 if (line.
at(i) == m_keys.at(m_keys.size() - 1)) {
2336 if (hits == getCount()) {
2343 Range r(cursor, ExclusiveMotion);
2345 if (matchColumn != -1) {
2346 r.endColumn = matchColumn;
2347 r.endLine = cursor.line();
2355Range NormalViMode::motionToChar()
2357 m_lastTFcommand = m_keys;
2358 KTextEditor::Cursor cursor(m_view->cursorPosition());
2359 QString line = getLine();
2361 m_stickyColumn = -1;
2366 int matchColumn = cursor.column() + (m_isRepeatedTFcommand ? 2 : 1);
2368 for (
int i = 0; i < getCount(); i++) {
2369 const int lastColumn = matchColumn;
2370 matchColumn = line.
indexOf(m_keys.right(1), matchColumn + ((i > 0) ? 1 : 0));
2371 if (matchColumn == -1) {
2372 if (m_isRepeatedTFcommand) {
2373 matchColumn = lastColumn;
2381 r.endColumn = matchColumn - 1;
2382 r.endLine = cursor.line();
2384 m_isRepeatedTFcommand =
false;
2388Range NormalViMode::motionToCharBackward()
2390 m_lastTFcommand = m_keys;
2391 KTextEditor::Cursor cursor(m_view->cursorPosition());
2392 QString line = getLine();
2394 const int originalColumn = cursor.column();
2395 m_stickyColumn = -1;
2397 int matchColumn = originalColumn - 1;
2400 int i = cursor.column() - (m_isRepeatedTFcommand ? 2 : 1);
2402 Range r(cursor, ExclusiveMotion);
2404 while (hits != getCount() && i >= 0) {
2405 if (line.
at(i) == m_keys.at(m_keys.size() - 1)) {
2409 if (hits == getCount()) {
2416 if (hits == getCount()) {
2417 r.endColumn = matchColumn + 1;
2418 r.endLine = cursor.line();
2423 m_isRepeatedTFcommand =
false;
2428Range NormalViMode::motionRepeatlastTF()
2430 if (!m_lastTFcommand.isEmpty()) {
2431 m_isRepeatedTFcommand =
true;
2432 m_keys = m_lastTFcommand;
2433 if (m_keys.at(0) == QLatin1Char(
'f')) {
2434 return motionFindChar();
2435 }
else if (m_keys.at(0) == QLatin1Char(
'F')) {
2436 return motionFindCharBackward();
2437 }
else if (m_keys.at(0) == QLatin1Char(
't')) {
2438 return motionToChar();
2439 }
else if (m_keys.at(0) == QLatin1Char(
'T')) {
2440 return motionToCharBackward();
2448Range NormalViMode::motionRepeatlastTFBackward()
2450 if (!m_lastTFcommand.isEmpty()) {
2451 m_isRepeatedTFcommand =
true;
2452 m_keys = m_lastTFcommand;
2453 if (m_keys.at(0) == QLatin1Char(
'f')) {
2454 return motionFindCharBackward();
2455 }
else if (m_keys.at(0) == QLatin1Char(
'F')) {
2456 return motionFindChar();
2457 }
else if (m_keys.at(0) == QLatin1Char(
't')) {
2458 return motionToCharBackward();
2459 }
else if (m_keys.at(0) == QLatin1Char(
'T')) {
2460 return motionToChar();
2468Range NormalViMode::motionToLineFirst()
2470 Range r(getCount() - 1, 0, InclusiveMotion);
2471 m_stickyColumn = -1;
2473 if (r.endLine > doc()->lines() - 1) {
2474 r.endLine = doc()->lines() - 1;
2481Range NormalViMode::motionToLineLast()
2483 Range r(doc()->lines() - 1, 0, InclusiveMotion);
2484 m_stickyColumn = -1;
2488 r.endLine = m_count - 1;
2491 if (r.endLine > doc()->lines() - 1) {
2492 r.endLine = doc()->lines() - 1;
2499Range NormalViMode::motionToScreenColumn()
2501 m_stickyColumn = -1;
2503 KTextEditor::Cursor c(m_view->cursorPosition());
2505 int column = getCount() - 1;
2507 if (doc()->lineLength(c.
line()) - 1 < (
int)getCount() - 1) {
2508 column = doc()->lineLength(c.
line()) - 1;
2511 return Range(c.
line(), column, ExclusiveMotion);
2514Range NormalViMode::motionToMark()
2518 m_stickyColumn = -1;
2520 QChar reg = m_keys.at(m_keys.size() - 1);
2522 KTextEditor::Cursor c = m_viInputModeManager->marks()->getMarkPosition(reg);
2524 r.endLine = c.
line();
2525 r.endColumn = c.
column();
2527 error(
i18n(
"Mark not set: %1", m_keys.right(1)));
2536Range NormalViMode::motionToMarkLine()
2538 Range r = motionToMark();
2541 m_stickyColumn = -1;
2545Range NormalViMode::motionToMatchingItem()
2548 int lines = doc()->lines();
2553 int count = getCount();
2557 r.endLine = qRound(lines * count / 100.0) - 1;
2562 KTextEditor::Cursor c(m_view->cursorPosition());
2564 QString l = getLine();
2567 m_stickyColumn = -1;
2573 const auto bracketChar = l.
at(n1);
2575 if (bracketChar == QLatin1Char(
'(') || bracketChar == QLatin1Char(
')') || bracketChar == QLatin1Char(
'{') || bracketChar == QLatin1Char(
'}')
2576 || bracketChar == QLatin1Char(
'[') || bracketChar == QLatin1Char(
']')) {
2582 const KTextEditor::Cursor oldCursorPos = m_view->cursorPosition();
2586 c = m_viewInternal->findMatchingBracket();
2587 if (c > m_view->cursorPosition()) {
2590 m_view->setCursorPosition(oldCursorPos);
2594 const int n2 = l.
indexOf(boundaryRegex, n1);
2595 QString item = l.
mid(n1, n2 - n1);
2596 QString matchingItem = m_matchingItems[item];
2599 int line = c.
line();
2600 int column = n2 - item.
length();
2601 bool reverse =
false;
2603 if (matchingItem.
startsWith(QLatin1Char(
'-'))) {
2604 matchingItem.
remove(0, 1);
2609 if (column == 0 && reverse) {
2616 while (toFind > 0) {
2619 matchItemIdx = l.
lastIndexOf(matchingItem, column - 1);
2621 if (itemIdx != -1 && (matchItemIdx == -1 || itemIdx > matchItemIdx)) {
2625 itemIdx = l.
indexOf(item, column);
2626 matchItemIdx = l.
indexOf(matchingItem, column);
2628 if (itemIdx != -1 && (matchItemIdx == -1 || itemIdx < matchItemIdx)) {
2633 if (matchItemIdx != -1 || itemIdx != -1) {
2635 column = qMin((
unsigned int)itemIdx, (
unsigned int)matchItemIdx);
2637 column = qMax(itemIdx, matchItemIdx);
2641 if (matchItemIdx != -1) {
2642 if (matchItemIdx == column) {
2648 (reverse) ? --line : ++line;
2651 if ((!reverse && line >= lines) || (reverse && line < 0)) {
2661 r.endLine = c.
line();
2662 r.endColumn = c.
column();
2668Range NormalViMode::motionToNextBraceBlockStart()
2672 m_stickyColumn = -1;
2674 int line = findLineStartingWitchChar(QLatin1Char(
'{'), getCount());
2684 if (motionWillBeUsedWithCommand()) {
2687 r.motionType = ExclusiveMotion;
2688 if (m_view->cursorPosition().column() != 0) {
2690 r.endColumn = doc()->lineLength(r.endLine);
2697Range NormalViMode::motionToPreviousBraceBlockStart()
2701 m_stickyColumn = -1;
2703 int line = findLineStartingWitchChar(QLatin1Char(
'{'), getCount(),
false);
2713 if (motionWillBeUsedWithCommand()) {
2715 r.motionType = ExclusiveMotion;
2721Range NormalViMode::motionToNextBraceBlockEnd()
2725 m_stickyColumn = -1;
2727 int line = findLineStartingWitchChar(QLatin1Char(
'}'), getCount());
2737 if (motionWillBeUsedWithCommand()) {
2740 r.motionType = ExclusiveMotion;
2741 if (m_view->cursorPosition().column() != 0) {
2743 r.endColumn = doc()->lineLength(r.endLine);
2750Range NormalViMode::motionToPreviousBraceBlockEnd()
2754 m_stickyColumn = -1;
2756 int line = findLineStartingWitchChar(QLatin1Char(
'}'), getCount(),
false);
2766 if (motionWillBeUsedWithCommand()) {
2767 r.motionType = ExclusiveMotion;
2773Range NormalViMode::motionToNextOccurrence()
2775 const QString word = getWordUnderCursor();
2776 Searcher *searcher = m_viInputModeManager->searcher();
2777 const Range match = searcher->findWordForMotion(word,
false, getWordRangeUnderCursor().
start(), getCount());
2778 if (searcher->lastSearchWrapped()) {
2779 m_view->showSearchWrappedHint(
false);
2785Range NormalViMode::motionToPrevOccurrence()
2787 const QString word = getWordUnderCursor();
2788 Searcher *searcher = m_viInputModeManager->searcher();
2789 const Range match = searcher->findWordForMotion(word,
true, getWordRangeUnderCursor().
start(), getCount());
2790 if (searcher->lastSearchWrapped()) {
2791 m_view->showSearchWrappedHint(
true);
2797Range NormalViMode::motionToFirstLineOfWindow()
2800 if (linesDisplayed() <= (
unsigned int)m_viewInternal->endLine()) {
2801 lines_to_go = m_viewInternal->endLine() - linesDisplayed() - m_view->cursorPosition().line() + 1;
2803 lines_to_go = -m_view->cursorPosition().line();
2806 Range r = goLineUpDown(lines_to_go);
2811Range NormalViMode::motionToMiddleLineOfWindow()
2814 if (linesDisplayed() <= (
unsigned int)m_viewInternal->endLine()) {
2815 lines_to_go = m_viewInternal->endLine() - linesDisplayed() / 2 - m_view->cursorPosition().line();
2817 lines_to_go = m_viewInternal->endLine() / 2 - m_view->cursorPosition().line();
2820 Range r = goLineUpDown(lines_to_go);
2825Range NormalViMode::motionToLastLineOfWindow()
2828 if (linesDisplayed() <= (
unsigned int)m_viewInternal->endLine()) {
2829 lines_to_go = m_viewInternal->endLine() - m_view->cursorPosition().line();
2831 lines_to_go = m_viewInternal->endLine() - m_view->cursorPosition().line();
2834 Range r = goLineUpDown(lines_to_go);
2839Range NormalViMode::motionToNextVisualLine()
2841 return goVisualLineUpDown(getCount());
2844Range NormalViMode::motionToPrevVisualLine()
2846 return goVisualLineUpDown(-getCount());
2849Range NormalViMode::motionToPreviousSentence()
2851 KTextEditor::Cursor c = findSentenceStart();
2852 int linenum = c.
line();
2854 const bool skipSpaces = doc()->line(linenum).isEmpty();
2859 column = doc()->line(linenum).size() - 1;
2863 for (
int i = linenum; i >= 0; i--) {
2864 const QString &line = doc()->line(i);
2866 if (line.
isEmpty() && !skipSpaces) {
2867 return Range(i, 0, InclusiveMotion);
2870 if (column < 0 && !line.
isEmpty()) {
2871 column = line.
size() - 1;
2874 for (
int j = column; j >= 0; j--) {
2875 if (skipSpaces || QStringLiteral(
".?!").indexOf(line.
at(j)) != -1) {
2879 c = findSentenceStart();
2880 return Range(c, InclusiveMotion);
2883 column = line.
size() - 1;
2885 return Range(0, 0, InclusiveMotion);
2888Range NormalViMode::motionToNextSentence()
2890 KTextEditor::Cursor c = findSentenceEnd();
2891 int linenum = c.
line();
2892 int column = c.
column() + 1;
2893 const bool skipSpaces = doc()->line(linenum).isEmpty();
2895 for (
int i = linenum; i < doc()->lines(); i++) {
2896 const QString &line = doc()->line(i);
2898 if (line.
isEmpty() && !skipSpaces) {
2899 return Range(i, 0, InclusiveMotion);
2902 for (
int j = column; j < line.
size(); j++) {
2904 return Range(i, j, InclusiveMotion);
2910 c = doc()->documentEnd();
2911 return Range(c, InclusiveMotion);
2914Range NormalViMode::motionToBeforeParagraph()
2916 KTextEditor::Cursor c(m_view->cursorPosition());
2918 int line = c.
line();
2920 m_stickyColumn = -1;
2922 for (
int i = 0; i < getCount(); i++) {
2927 }
while (line >= 0 && getLine(line + 1).length() == 0);
2928 while (line > 0 && getLine(line).length() != 0) {
2937 Range r(line, 0, InclusiveMotion);
2942Range NormalViMode::motionToAfterParagraph()
2944 KTextEditor::Cursor c(m_view->cursorPosition());
2946 int line = c.
line();
2948 m_stickyColumn = -1;
2950 for (
int i = 0; i < getCount(); i++) {
2955 }
while (line <= doc()->lines() - 1 && getLine(line - 1).length() == 0);
2956 while (line < doc()->lines() - 1 && getLine(line).length() != 0) {
2961 if (line >= doc()->lines()) {
2962 line = doc()->lines() - 1;
2966 int column = (line == doc()->lines() - 1) ? qMax(getLine(line).length() - 1, 0) : 0;
2968 return Range(line, column, InclusiveMotion);
2971Range NormalViMode::motionToIncrementalSearchMatch()
2973 return Range(m_positionWhenIncrementalSearchBegan.line(),
2974 m_positionWhenIncrementalSearchBegan.column(),
2975 m_view->cursorPosition().line(),
2976 m_view->cursorPosition().column(),
2984Range NormalViMode::textObjectAWord()
2986 KTextEditor::Cursor c(m_view->cursorPosition());
2988 KTextEditor::Cursor c1 = c;
2990 bool startedOnSpace =
false;
2991 if (doc()->characterAt(c).isSpace()) {
2992 startedOnSpace =
true;
2994 c1 = findPrevWordStart(c.
line(), c.
column() + 1,
true);
2996 c1 = KTextEditor::Cursor(0, 0);
2999 KTextEditor::Cursor c2 = KTextEditor::Cursor(c.
line(), c.
column() - 1);
3000 for (
int i = 1; i <= getCount(); i++) {
3008 const KTextEditor::Cursor nextWordStart = findNextWordStart(c2.
line(), c2.
column());
3010 if (!startedOnSpace) {
3011 c2 = KTextEditor::Cursor(nextWordStart.
line(), nextWordStart.
column() - 1);
3014 c2 = KTextEditor::Cursor(c2.
line(), doc()->lineLength(c2.
line()) - 1);
3016 bool swallowCarriageReturnAtEndOfLine =
false;
3019 c2 = KTextEditor::Cursor(c2.
line() + 1, 0);
3020 swallowCarriageReturnAtEndOfLine =
true;
3022 const bool swallowPrecedingSpaces =
3023 (c2.
column() == doc()->lineLength(c2.
line()) - 1 && !doc()->characterAt(c2).isSpace()) || startedOnSpace || swallowCarriageReturnAtEndOfLine;
3024 if (swallowPrecedingSpaces) {
3026 const KTextEditor::Cursor previousNonSpace = findPrevWordEnd(c.
line(), c.
column());
3027 if (previousNonSpace.
isValid() && previousNonSpace.
line() == c1.
line()) {
3028 c1 = KTextEditor::Cursor(previousNonSpace.
line(), previousNonSpace.
column() + 1);
3029 }
else if (startedOnSpace || swallowCarriageReturnAtEndOfLine) {
3030 c1 = KTextEditor::Cursor(c1.
line(), 0);
3035 return Range(c1, c2, !swallowCarriageReturnAtEndOfLine ? InclusiveMotion : ExclusiveMotion);
3038Range NormalViMode::textObjectInnerWord()
3040 KTextEditor::Cursor c(m_view->cursorPosition());
3042 KTextEditor::Cursor c1 = findPrevWordStart(c.
line(), c.
column() + 1,
true);
3044 c1 = KTextEditor::Cursor(0, 0);
3047 KTextEditor::Cursor c2(c.
line(), c.
column() - 1);
3049 for (
int i = 0; i < getCount(); i++) {
3050 c2 = findWordEnd(c2.
line(), c2.
column(),
true);
3054 c2 = doc()->documentEnd();
3061 return Range(c1, c2, InclusiveMotion);
3064Range NormalViMode::textObjectAWORD()
3066 KTextEditor::Cursor c(m_view->cursorPosition());
3068 KTextEditor::Cursor c1 = c;
3070 bool startedOnSpace =
false;
3071 if (doc()->characterAt(c).isSpace()) {
3072 startedOnSpace =
true;
3074 c1 = findPrevWORDStart(c.
line(), c.
column() + 1,
true);
3076 c1 = KTextEditor::Cursor(0, 0);
3079 KTextEditor::Cursor c2 = KTextEditor::Cursor(c.
line(), c.
column() - 1);
3080 for (
int i = 1; i <= getCount(); i++) {
3088 const KTextEditor::Cursor nextWordStart = findNextWordStart(c2.
line(), c2.
column());
3090 if (!startedOnSpace) {
3091 c2 = KTextEditor::Cursor(nextWordStart.
line(), nextWordStart.
column() - 1);
3094 c2 = KTextEditor::Cursor(c2.
line(), doc()->lineLength(c2.
line()) - 1);
3096 bool swallowCarriageReturnAtEndOfLine =
false;
3099 c2 = KTextEditor::Cursor(c2.
line() + 1, 0);
3100 swallowCarriageReturnAtEndOfLine =
true;
3102 const bool swallowPrecedingSpaces =
3103 (c2.
column() == doc()->lineLength(c2.
line()) - 1 && !doc()->characterAt(c2).isSpace()) || startedOnSpace || swallowCarriageReturnAtEndOfLine;
3104 if (swallowPrecedingSpaces) {
3106 const KTextEditor::Cursor previousNonSpace = findPrevWORDEnd(c.
line(), c.
column());
3107 if (previousNonSpace.
isValid() && previousNonSpace.
line() == c1.
line()) {
3108 c1 = KTextEditor::Cursor(previousNonSpace.
line(), previousNonSpace.
column() + 1);
3109 }
else if (startedOnSpace || swallowCarriageReturnAtEndOfLine) {
3110 c1 = KTextEditor::Cursor(c1.
line(), 0);
3115 return Range(c1, c2, !swallowCarriageReturnAtEndOfLine ? InclusiveMotion : ExclusiveMotion);
3118Range NormalViMode::textObjectInnerWORD()
3120 KTextEditor::Cursor c(m_view->cursorPosition());
3122 KTextEditor::Cursor c1 = findPrevWORDStart(c.
line(), c.
column() + 1,
true);
3124 c1 = KTextEditor::Cursor(0, 0);
3126 KTextEditor::Cursor c2(c);
3128 for (
int i = 0; i < getCount(); i++) {
3129 c2 = findWORDEnd(c2.
line(), c2.
column(),
true);
3133 c2 = doc()->documentEnd();
3140 return Range(c1, c2, InclusiveMotion);
3143KTextEditor::Cursor NormalViMode::findSentenceStart()
3145 KTextEditor::Cursor c(m_view->cursorPosition());
3146 int linenum = c.
line();
3150 for (
int i = linenum; i >= 0; i--) {
3151 const QString &line = doc()->line(i);
3152 const int lineLength = line.
size();
3154 column = lineLength;
3159 return KTextEditor::Cursor((i != linenum) ? i + 1 : i, prev);
3163 for (
int j = column; j >= 0; j--) {
3164 if (j == lineLength || line.
at(j).
isSpace()) {
3165 int lastSpace = j--;
3166 for (; j >= 0 && QStringLiteral(
"\"')]").indexOf(line.
at(j)) != -1; j--) {
3170 if (j >= 0 && QStringLiteral(
".!?").indexOf(line.
at(j)) != -1) {
3171 if (lastSpace == lineLength) {
3173 return KTextEditor::Cursor(i + 1, 0);
3176 return KTextEditor::Cursor(i, prev);
3185 return KTextEditor::Cursor(0, 0);
3188KTextEditor::Cursor NormalViMode::findSentenceEnd()
3190 KTextEditor::Cursor c(m_view->cursorPosition());
3191 int linenum = c.
line();
3196 for (
int i = linenum; i < doc()->lines(); i++) {
3197 const QString &line = doc()->line(i);
3201 return KTextEditor::Cursor(linenum, j);
3205 for (j = column; j < line.
size(); j++) {
3206 if (QStringLiteral(
".!?").indexOf(line.
at(j)) != -1) {
3209 for (; j < line.
size() && QStringLiteral(
"\"')]").indexOf(line.
at(j)) != -1; j++) {
3213 if (j >= line.
size()) {
3214 return KTextEditor::Cursor(i, j - 1);
3219 return KTextEditor::Cursor(i, j - 1);
3229 return KTextEditor::Cursor(linenum, j - 1);
3232KTextEditor::Cursor NormalViMode::findParagraphStart()
3234 KTextEditor::Cursor c(m_view->cursorPosition());
3235 const bool firstBlank = doc()->line(c.
line()).isEmpty();
3236 int prev = c.
line();
3238 for (
int i = prev; i >= 0; i--) {
3239 if (doc()->line(i).isEmpty()) {
3247 for (; i >= 0 && doc()->line(i).isEmpty(); i--, prev--) {
3251 return KTextEditor::Cursor(prev, 0);
3254 return KTextEditor::Cursor(0, 0);
3257KTextEditor::Cursor NormalViMode::findParagraphEnd()
3259 KTextEditor::Cursor c(m_view->cursorPosition());
3260 int prev = c.
line();
3261 int lines = doc()->lines();
3262 const bool firstBlank = doc()->line(prev).isEmpty();
3264 for (
int i = prev; i < lines; i++) {
3265 if (doc()->line(i).isEmpty()) {
3273 for (; i < lines && doc()->line(i).isEmpty(); i++, prev++) {
3277 int length = doc()->lineLength(prev);
3278 return KTextEditor::Cursor(prev, (length <= 0) ? 0 : length - 1);
3281 return doc()->documentEnd();
3284Range NormalViMode::textObjectInnerSentence()
3287 KTextEditor::Cursor c1 = findSentenceStart();
3288 KTextEditor::Cursor c2 = findSentenceEnd();
3291 r.startLine = c1.
line();
3292 r.startColumn = c1.
column();
3293 r.endLine = c2.
line();
3294 r.endColumn = c2.
column();
3298Range NormalViMode::textObjectASentence()
3301 Range r = textObjectInnerSentence();
3302 const QString &line = doc()->line(r.endLine);
3305 for (i = r.endColumn + 1; i < line.
size(); i++) {
3310 r.endColumn = i - 1;
3313 if (r.startColumn != 0) {
3314 if (r.endColumn == line.
size() - 1 && !line.
at(r.endColumn).
isSpace()) {
3315 const QString &line = doc()->line(r.startLine);
3316 for (i = r.startColumn - 1; i >= 0; i--) {
3321 r.startColumn = i + 1;
3327Range NormalViMode::textObjectInnerParagraph()
3330 KTextEditor::Cursor c1 = findParagraphStart();
3331 KTextEditor::Cursor c2 = findParagraphEnd();
3334 r.startLine = c1.
line();
3335 r.startColumn = c1.
column();
3336 r.endLine = c2.
line();
3337 r.endColumn = c2.
column();
3341Range NormalViMode::textObjectAParagraph()
3343 Range r = textObjectInnerParagraph();
3344 int lines = doc()->lines();
3346 if (r.endLine + 1 < lines) {
3349 if (doc()->line(r.endLine + 1).
isEmpty()) {
3350 for (
int i = r.endLine + 1; i < lines && doc()->line(i).isEmpty(); i++) {
3355 KTextEditor::Cursor prev = m_view->cursorPosition();
3356 KTextEditor::Cursor c(r.endLine + 1, 0);
3358 c = findParagraphEnd();
3360 r.endLine = c.
line();
3361 r.endColumn = c.
column();
3363 }
else if (doc()->lineLength(r.startLine) > 0) {
3365 for (
int i = r.startLine - 1; i >= 0 && doc()->line(i).isEmpty(); i--) {
3369 updateCursor(KTextEditor::Cursor(r.startLine, r.startColumn));
3377Range NormalViMode::textObjectAQuoteDouble()
3379 return findSurroundingQuotes(QLatin1Char(
'"'),
false);
3382Range NormalViMode::textObjectInnerQuoteDouble()
3384 return findSurroundingQuotes(QLatin1Char(
'"'),
true);
3387Range NormalViMode::textObjectAQuoteSingle()
3389 return findSurroundingQuotes(QLatin1Char(
'\''),
false);
3392Range NormalViMode::textObjectInnerQuoteSingle()
3394 return findSurroundingQuotes(QLatin1Char(
'\''),
true);
3397Range NormalViMode::textObjectABackQuote()
3399 return findSurroundingQuotes(QLatin1Char(
'`'),
false);
3402Range NormalViMode::textObjectInnerBackQuote()
3404 return findSurroundingQuotes(QLatin1Char(
'`'),
true);
3407Range NormalViMode::textObjectAParen()
3409 return findSurroundingBrackets(QLatin1Char(
'('), QLatin1Char(
')'),
false, QLatin1Char(
'('), QLatin1Char(
')'));
3412Range NormalViMode::textObjectInnerParen()
3414 return findSurroundingBrackets(QLatin1Char(
'('), QLatin1Char(
')'),
true, QLatin1Char(
'('), QLatin1Char(
')'));
3417Range NormalViMode::textObjectABracket()
3419 return findSurroundingBrackets(QLatin1Char(
'['), QLatin1Char(
']'),
false, QLatin1Char(
'['), QLatin1Char(
']'));
3422Range NormalViMode::textObjectInnerBracket()
3424 return findSurroundingBrackets(QLatin1Char(
'['), QLatin1Char(
']'),
true, QLatin1Char(
'['), QLatin1Char(
']'));
3427Range NormalViMode::textObjectACurlyBracket()
3429 return findSurroundingBrackets(QLatin1Char(
'{'), QLatin1Char(
'}'),
false, QLatin1Char(
'{'), QLatin1Char(
'}'));
3432Range NormalViMode::textObjectInnerCurlyBracket()
3434 const Range allBetweenCurlyBrackets = findSurroundingBrackets(QLatin1Char(
'{'), QLatin1Char(
'}'),
true, QLatin1Char(
'{'), QLatin1Char(
'}'));
3437 Range innerCurlyBracket(allBetweenCurlyBrackets);
3439 if (innerCurlyBracket.startLine != innerCurlyBracket.endLine) {
3440 const bool openingBraceIsLastCharOnLine = innerCurlyBracket.startColumn == doc()->line(innerCurlyBracket.startLine).length();
3441 const bool stuffToDeleteIsAllOnEndLine = openingBraceIsLastCharOnLine && innerCurlyBracket.endLine == innerCurlyBracket.startLine + 1;
3442 const QString textLeadingClosingBracket = doc()->line(innerCurlyBracket.endLine).mid(0, innerCurlyBracket.endColumn + 1);
3443 const bool closingBracketHasLeadingNonWhitespace = !textLeadingClosingBracket.
trimmed().
isEmpty();
3444 if (stuffToDeleteIsAllOnEndLine) {
3445 if (!closingBracketHasLeadingNonWhitespace) {
3450 innerCurlyBracket.startLine++;
3451 innerCurlyBracket.startColumn = 0;
3454 if (openingBraceIsLastCharOnLine && !closingBracketHasLeadingNonWhitespace) {
3455 innerCurlyBracket.startLine++;
3456 innerCurlyBracket.startColumn = 0;
3457 m_lastMotionWasLinewiseInnerBlock =
true;
3462 if (!closingBracketHasLeadingNonWhitespace) {
3465 innerCurlyBracket.endLine--;
3466 innerCurlyBracket.endColumn = doc()->line(innerCurlyBracket.endLine).length();
3471 return innerCurlyBracket;
3474Range NormalViMode::textObjectAInequalitySign()
3476 return findSurroundingBrackets(QLatin1Char(
'<'), QLatin1Char(
'>'),
false, QLatin1Char(
'<'), QLatin1Char(
'>'));
3479Range NormalViMode::textObjectInnerInequalitySign()
3481 return findSurroundingBrackets(QLatin1Char(
'<'), QLatin1Char(
'>'),
true, QLatin1Char(
'<'), QLatin1Char(
'>'));
3484Range NormalViMode::textObjectAComma()
3486 return textObjectComma(
false);
3489Range NormalViMode::textObjectInnerComma()
3491 return textObjectComma(
true);
3494QRegularExpression NormalViMode::generateMatchingItemRegex()
const
3496 QString pattern(QStringLiteral(
"\\[|\\]|\\{|\\}|\\(|\\)|"));
3498 for (QString s : std::as_const(m_matchingItems)) {
3499 if (s.startsWith(QLatin1Char(
'-'))) {
3502 s.replace(QLatin1Char(
'*'), QStringLiteral(
"\\*"));
3503 s.replace(QLatin1Char(
'+'), QStringLiteral(
"\\+"));
3504 s.replace(QLatin1Char(
'['), QStringLiteral(
"\\["));
3505 s.replace(QLatin1Char(
']'), QStringLiteral(
"\\]"));
3506 s.replace(QLatin1Char(
'('), QStringLiteral(
"\\("));
3507 s.replace(QLatin1Char(
')'), QStringLiteral(
"\\)"));
3508 s.replace(QLatin1Char(
'{'), QStringLiteral(
"\\{"));
3509 s.replace(QLatin1Char(
'}'), QStringLiteral(
"\\}"));
3511 s.append(QLatin1Char(
'|'));
3525OperationMode NormalViMode::getOperationMode()
const
3527 OperationMode m = CharWise;
3529 if (m_viInputModeManager->getCurrentViMode() == ViMode::VisualBlockMode) {
3531 }
else if (m_viInputModeManager->getCurrentViMode() == ViMode::VisualLineMode
3532 || (m_commandRange.startLine != m_commandRange.endLine && m_viInputModeManager->getCurrentViMode() != ViMode::VisualMode)) {
3536 if (m_commandWithMotion && !m_linewiseCommand) {
3540 if (m_lastMotionWasLinewiseInnerBlock) {
3547bool NormalViMode::paste(PasteLocation pasteLocation,
bool isgPaste,
bool isIndentedPaste)
3549 KTextEditor::Cursor pasteAt(m_view->cursorPosition());
3550 KTextEditor::Cursor cursorAfterPaste = pasteAt;
3551 QChar reg = getChosenRegister(UnnamedRegister);
3553 OperationMode m = getRegisterFlag(reg);
3554 QString textToInsert = getRegisterContent(reg);
3555 const bool isTextMultiLine = textToInsert.
count(QLatin1Char(
'\n')) > 0;
3558 isgPaste |= m_viInputModeManager->getTemporaryNormalMode();
3561 error(
i18n(
"Nothing in register %1", reg.
toLower()));
3565 if (getCount() > 1) {
3566 textToInsert = textToInsert.
repeated(getCount());
3569 if (m == LineWise) {
3570 pasteAt.setColumn(0);
3571 if (isIndentedPaste) {
3574 static const QRegularExpression nonWhitespaceRegex(QStringLiteral(
"[^\\s]"));
3575 const QString pasteLineString = doc()->line(pasteAt.line());
3576 const QString leadingWhiteSpaceOnCurrentLine = pasteLineString.
mid(0, pasteLineString.
indexOf(nonWhitespaceRegex));
3577 const QString leadingWhiteSpaceOnFirstPastedLine = textToInsert.
mid(0, textToInsert.
indexOf(nonWhitespaceRegex));
3579 while (textToInsert[0].isSpace()) {
3580 textToInsert = textToInsert.
mid(1);
3582 textToInsert.
prepend(leadingWhiteSpaceOnCurrentLine);
3585 textToInsert.
chop(1);
3586 textToInsert.
replace(QLatin1Char(
'\n') + leadingWhiteSpaceOnFirstPastedLine, QLatin1Char(
'\n') + leadingWhiteSpaceOnCurrentLine);
3587 textToInsert.
append(QLatin1Char(
'\n'));
3589 if (pasteLocation == AfterCurrentPosition) {
3590 textToInsert.
chop(1);
3591 pasteAt.setColumn(doc()->lineLength(pasteAt.line()));
3592 textToInsert.
prepend(QLatin1Char(
'\n'));
3594 cursorAfterPaste.
setLine(cursorAfterPaste.
line() + 1);
3597 cursorAfterPaste.
setLine(cursorAfterPaste.
line() + textToInsert.
count(QLatin1Char(
'\n')));
3600 if (pasteLocation == AfterCurrentPosition) {
3603 if (getLine(pasteAt.line()).length() > 0) {
3604 pasteAt.setColumn(pasteAt.column() + 1);
3606 cursorAfterPaste = pasteAt;
3608 const bool leaveCursorAtStartOfPaste = isTextMultiLine && !isgPaste;
3609 if (!leaveCursorAtStartOfPaste) {
3610 cursorAfterPaste = cursorPosAtEndOfPaste(pasteAt, textToInsert);
3618 if (m_view->selection()) {
3619 pasteAt = m_view->selectionRange().start();
3620 doc()->removeText(m_view->selectionRange());
3622 doc()->insertText(pasteAt, textToInsert, m == Block);
3625 if (cursorAfterPaste.
line() >= doc()->lines()) {
3626 cursorAfterPaste.
setLine(doc()->lines() - 1);
3628 updateCursor(cursorAfterPaste);
3633KTextEditor::Cursor NormalViMode::cursorPosAtEndOfPaste(
const KTextEditor::Cursor pasteLocation,
const QString &pastedText)
3635 KTextEditor::Cursor cAfter = pasteLocation;
3636 const int lineCount = pastedText.
count(QLatin1Char(
'\n')) + 1;
3637 if (lineCount == 1) {
3640 const int lastLineLength = pastedText.
size() - (pastedText.
lastIndexOf(QLatin1Char(
'\n')) + 1);
3647void NormalViMode::joinLines(
unsigned int from,
unsigned int to)
const
3650 if (to >= (
unsigned int)(doc()->lines())) {
3651 to = doc()->lines() - 1;
3659 doc()->joinLines(from, to);
3662void NormalViMode::reformatLines(
unsigned int from,
unsigned int to)
const
3665 KTextEditor::DocumentPrivate *document = doc();
3666 auto isNonEmptyLine = [](QStringView text) {
3667 for (
int i = 0; i < text.
length(); ++i) {
3675 for (; from < to; ++from) {
3676 if (isNonEmptyLine(document->
line(from))) {
3680 for (; to > from; --to) {
3681 if (isNonEmptyLine(document->
line(to))) {
3687 joinLines(from, to);
3695 line = m_view->cursorPosition().line();
3701 return (c < 0) ? 0 : c;
3705void NormalViMode::shrinkRangeAroundCursor(Range &toShrink,
const Range &rangeToShrinkTo)
const
3707 if (!toShrink.valid || !rangeToShrinkTo.valid) {
3711 if (rangeToShrinkTo.startLine >= cursorPos.
line()) {
3712 if (rangeToShrinkTo.startLine > cursorPos.
line()) {
3716 Q_ASSERT(rangeToShrinkTo.startLine == cursorPos.
line());
3717 if (rangeToShrinkTo.startColumn > cursorPos.
column()) {
3722 if (rangeToShrinkTo.endLine <= cursorPos.
line()) {
3723 if (rangeToShrinkTo.endLine < cursorPos.
line()) {
3727 Q_ASSERT(rangeToShrinkTo.endLine == cursorPos.
line());
3728 if (rangeToShrinkTo.endColumn < cursorPos.
column()) {
3734 if (toShrink.startLine <= rangeToShrinkTo.startLine) {
3735 if (toShrink.startLine < rangeToShrinkTo.startLine) {
3736 toShrink.startLine = rangeToShrinkTo.startLine;
3737 toShrink.startColumn = rangeToShrinkTo.startColumn;
3739 Q_ASSERT(toShrink.startLine == rangeToShrinkTo.startLine);
3740 if (toShrink.startColumn < rangeToShrinkTo.startColumn) {
3741 toShrink.startColumn = rangeToShrinkTo.startColumn;
3744 if (toShrink.endLine >= rangeToShrinkTo.endLine) {
3745 if (toShrink.endLine > rangeToShrinkTo.endLine) {
3746 toShrink.endLine = rangeToShrinkTo.endLine;
3747 toShrink.endColumn = rangeToShrinkTo.endColumn;
3749 Q_ASSERT(toShrink.endLine == rangeToShrinkTo.endLine);
3750 if (toShrink.endColumn > rangeToShrinkTo.endColumn) {
3751 toShrink.endColumn = rangeToShrinkTo.endColumn;
3756Range NormalViMode::textObjectComma(
bool inner)
const
3761 Range r(0, 0, m_view->doc()->lines(), m_view->doc()->line(m_view->doc()->lastLine()).length(), InclusiveMotion);
3763 shrinkRangeAroundCursor(r, findSurroundingQuotes(QLatin1Char(
','), inner));
3764 shrinkRangeAroundCursor(r, findSurroundingBrackets(QLatin1Char(
'('), QLatin1Char(
')'), inner, QLatin1Char(
'('), QLatin1Char(
')')));
3765 shrinkRangeAroundCursor(r, findSurroundingBrackets(QLatin1Char(
'{'), QLatin1Char(
'}'), inner, QLatin1Char(
'{'), QLatin1Char(
'}')));
3766 shrinkRangeAroundCursor(r, findSurroundingBrackets(QLatin1Char(
','), QLatin1Char(
')'), inner, QLatin1Char(
'('), QLatin1Char(
')')));
3767 shrinkRangeAroundCursor(r, findSurroundingBrackets(QLatin1Char(
','), QLatin1Char(
']'), inner, QLatin1Char(
'['), QLatin1Char(
']')));
3768 shrinkRangeAroundCursor(r, findSurroundingBrackets(QLatin1Char(
','), QLatin1Char(
'}'), inner, QLatin1Char(
'{'), QLatin1Char(
'}')));
3769 shrinkRangeAroundCursor(r, findSurroundingBrackets(QLatin1Char(
'('), QLatin1Char(
','), inner, QLatin1Char(
'('), QLatin1Char(
')')));
3770 shrinkRangeAroundCursor(r, findSurroundingBrackets(QLatin1Char(
'['), QLatin1Char(
','), inner, QLatin1Char(
'['), QLatin1Char(
']')));
3771 shrinkRangeAroundCursor(r, findSurroundingBrackets(QLatin1Char(
'{'), QLatin1Char(
','), inner, QLatin1Char(
'{'), QLatin1Char(
'}')));
3775void NormalViMode::updateYankHighlightAttrib()
3777 if (!m_highlightYankAttribute) {
3778 m_highlightYankAttribute =
new KTextEditor::Attribute;
3780 const QColor &yankedColor = m_view->rendererConfig()->savedLineColor();
3781 m_highlightYankAttribute->setBackground(yankedColor);
3783 mouseInAttribute->setFontBold(
true);
3788void NormalViMode::highlightYank(
const Range &range,
const OperationMode mode)
3790 clearYankHighlight();
3794 if (mode == Block) {
3795 for (
int i = range.startLine; i <= range.endLine; i++) {
3796 addHighlightYank(KTextEditor::Range(i, range.startColumn, i, range.endColumn));
3799 addHighlightYank(KTextEditor::Range(range.startLine, range.startColumn, range.endLine, range.endColumn));
3803void NormalViMode::addHighlightYank(KTextEditor::Range yankRange)
3806 highlightedYank->
setView(m_view);
3810 highlightedYank->
setAttribute(m_highlightYankAttribute);
3812 highlightedYankForDocument().insert(highlightedYank);
3815void NormalViMode::clearYankHighlight()
3817 QSet<KTextEditor::MovingRange *> &pHighlightedYanks = highlightedYankForDocument();
3818 qDeleteAll(pHighlightedYanks);
3819 pHighlightedYanks.
clear();
3822QSet<KTextEditor::MovingRange *> &NormalViMode::highlightedYankForDocument()
3826 return m_viInputModeManager->getViNormalMode()->m_highlightedYanks;
3829bool NormalViMode::waitingForRegisterOrCharToSearch()
3834 const int keysSize = m_keys.size();
3841 QChar cPrefix = m_keys[0];
3842 if (keysSize == 2) {
3844 if (cPrefix != QLatin1Char(
'c') && cPrefix != QLatin1Char(
'd') && cPrefix != QLatin1Char(
'y') && cPrefix != QLatin1Char(
'=')
3845 && cPrefix != QLatin1Char(
'>') && cPrefix != QLatin1Char(
'<')) {
3848 }
else if (keysSize == 3) {
3850 QChar cNextfix = m_keys[1];
3851 if (cPrefix != QLatin1Char(
'g')
3852 || (cNextfix != QLatin1Char(
'U') && cNextfix != QLatin1Char(
'u') && cNextfix != QLatin1Char(
'~') && cNextfix != QLatin1Char(
'q')
3853 && cNextfix != QLatin1Char(
'w') && cNextfix != QLatin1Char(
'@'))) {
3861 QChar ch = m_keys[keysSize - 1];
3862 return (ch == QLatin1Char(
'f') || ch == QLatin1Char(
't') || ch == QLatin1Char(
'F')
3863 || ch == QLatin1Char(
'T')
3865 || (keysSize == 1 && (ch == QLatin1Char(
'r') || ch == QLatin1Char(
'q') || ch == QLatin1Char(
'@'))));
3868void NormalViMode::textInserted(KTextEditor::Document *document, KTextEditor::Range range)
3875 const bool isInsertReplaceMode =
3876 (m_viInputModeManager->getCurrentViMode() == ViMode::InsertMode || m_viInputModeManager->getCurrentViMode() == ViMode::ReplaceMode);
3877 const bool continuesInsertion = range.
start().
line() == m_currentChangeEndMarker.line() && range.
start().
column() == m_currentChangeEndMarker.column();
3878 const bool beginsWithNewline = doc()->text(range).at(0) == QLatin1Char(
'\n');
3879 if (!continuesInsertion) {
3880 KTextEditor::Cursor newBeginMarkerPos = range.
start();
3881 if (beginsWithNewline && !isInsertReplaceMode) {
3883 newBeginMarkerPos = KTextEditor::Cursor(newBeginMarkerPos.
line() + 1, 0);
3885 m_viInputModeManager->marks()->setStartEditYanked(newBeginMarkerPos);
3887 m_viInputModeManager->marks()->setLastChange(range.
start());
3888 KTextEditor::Cursor editEndMarker = range.
end();
3889 if (!isInsertReplaceMode) {
3892 m_viInputModeManager->marks()->setFinishEditYanked(editEndMarker);
3893 m_currentChangeEndMarker = range.
end();
3896 m_viInputModeManager->marks()->setStartEditYanked(KTextEditor::Cursor(m_viInputModeManager->marks()->getStartEditYanked().line(), 0));
3897 if (addsMultipleLines) {
3898 m_viInputModeManager->marks()->setFinishEditYanked(KTextEditor::Cursor(m_viInputModeManager->marks()->getFinishEditYanked().line() + 1, 0));
3899 m_viInputModeManager->marks()->setLastChange(KTextEditor::Cursor(m_viInputModeManager->marks()->getLastChange().line() + 1, 0));
3901 m_viInputModeManager->marks()->setFinishEditYanked(KTextEditor::Cursor(m_viInputModeManager->marks()->getFinishEditYanked().line(), 0));
3902 m_viInputModeManager->marks()->setLastChange(KTextEditor::Cursor(m_viInputModeManager->marks()->getLastChange().line(), 0));
3907void NormalViMode::textRemoved(KTextEditor::Document *document, KTextEditor::Range range)
3914 const bool isInsertReplaceMode =
3915 (m_viInputModeManager->getCurrentViMode() == ViMode::InsertMode || m_viInputModeManager->getCurrentViMode() == ViMode::ReplaceMode);
3916 m_viInputModeManager->marks()->setLastChange(range.
start());
3917 if (!isInsertReplaceMode) {
3919 m_viInputModeManager->marks()->setStartEditYanked(range.
start());
3922 m_currentChangeEndMarker = range.
start();
3924 m_viInputModeManager->marks()->setFinishEditYanked(range.
start());
3929 const int markerLineAdjustment = (range.
start().line() != range.
end().
line()) ? 1 : 0;
3930 m_viInputModeManager->marks()->setStartEditYanked(
3931 KTextEditor::Cursor(m_viInputModeManager->marks()->getStartEditYanked().line() + markerLineAdjustment, 0));
3932 m_viInputModeManager->marks()->setFinishEditYanked(
3933 KTextEditor::Cursor(m_viInputModeManager->marks()->getFinishEditYanked().line() + markerLineAdjustment, 0));
3934 m_viInputModeManager->marks()->setLastChange(KTextEditor::Cursor(m_viInputModeManager->marks()->getLastChange().line() + markerLineAdjustment, 0));
3938void NormalViMode::undoBeginning()
3943void NormalViMode::undoEnded()
3948bool NormalViMode::executeKateCommand(
const QString &command)
3950 KTextEditor::Command *p = KateCmd::self()->queryCommand(command);
3957 return p->
exec(m_view, command, msg);
3960#define ADDCMD(STR, FUNC, FLGS) Command(QStringLiteral(STR), &NormalViMode::FUNC, FLGS)
3962#define ADDMOTION(STR, FUNC, FLGS) Motion(QStringLiteral(STR), &NormalViMode::FUNC, FLGS)
3967 static const std::vector<Command> global{
3972 ADDCMD(
"I", commandEnterInsertModeBeforeFirstNonBlankInLine, IS_CHANGE),
3974 ADDCMD(
"v", commandEnterVisualMode, 0),
3975 ADDCMD(
"V", commandEnterVisualLineMode, 0),
3976 ADDCMD(
"<c-v>", commandEnterVisualBlockMode, 0),
3977 ADDCMD(
"gv", commandReselectVisual, SHOULD_NOT_RESET),
3978 ADDCMD(
"o", commandOpenNewLineUnder, IS_CHANGE),
3979 ADDCMD(
"O", commandOpenNewLineOver, IS_CHANGE),
3980 ADDCMD(
"J", commandJoinLines, IS_CHANGE),
3981 ADDCMD(
"c", commandChange, IS_CHANGE | NEEDS_MOTION),
3982 ADDCMD(
"C", commandChangeToEOL, IS_CHANGE),
3983 ADDCMD(
"cc", commandChangeLine, IS_CHANGE),
3984 ADDCMD(
"s", commandSubstituteChar, IS_CHANGE),
3985 ADDCMD(
"S", commandSubstituteLine, IS_CHANGE),
3986 ADDCMD(
"dd", commandDeleteLine, IS_CHANGE),
3987 ADDCMD(
"d", commandDelete, IS_CHANGE | NEEDS_MOTION),
3988 ADDCMD(
"D", commandDeleteToEOL, IS_CHANGE),
3989 ADDCMD(
"x", commandDeleteChar, IS_CHANGE),
3990 ADDCMD(
"<delete>", commandDeleteChar, IS_CHANGE),
3991 ADDCMD(
"X", commandDeleteCharBackward, IS_CHANGE),
3992 ADDCMD(
"gu", commandMakeLowercase, IS_CHANGE | NEEDS_MOTION),
3993 ADDCMD(
"guu", commandMakeLowercaseLine, IS_CHANGE),
3994 ADDCMD(
"gU", commandMakeUppercase, IS_CHANGE | NEEDS_MOTION),
3995 ADDCMD(
"gUU", commandMakeUppercaseLine, IS_CHANGE),
3996 ADDCMD(
"y", commandYank, NEEDS_MOTION),
3997 ADDCMD(
"yy", commandYankLine, 0),
3998 ADDCMD(
"Y", commandYankToEOL, 0),
3999 ADDCMD(
"p", commandPaste, IS_CHANGE),
4000 ADDCMD(
"P", commandPasteBefore, IS_CHANGE),
4001 ADDCMD(
"gp", commandgPaste, IS_CHANGE),
4002 ADDCMD(
"gP", commandgPasteBefore, IS_CHANGE),
4003 ADDCMD(
"]p", commandIndentedPaste, IS_CHANGE),
4004 ADDCMD(
"[p", commandIndentedPasteBefore, IS_CHANGE),
4005 ADDCMD(
"r.", commandReplaceCharacter, IS_CHANGE | REGEX_PATTERN),
4006 ADDCMD(
"R", commandEnterReplaceMode, IS_CHANGE),
4007 ADDCMD(
":", commandSwitchToCmdLine, 0),
4008 ADDCMD(
"u", commandUndo, 0),
4009 ADDCMD(
"<c-r>", commandRedo, 0),
4010 ADDCMD(
"U", commandRedo, 0),
4011 ADDCMD(
"m.", commandSetMark, REGEX_PATTERN),
4012 ADDCMD(
">>", commandIndentLine, IS_CHANGE),
4013 ADDCMD(
"<<", commandUnindentLine, IS_CHANGE),
4014 ADDCMD(
">", commandIndentLines, IS_CHANGE | NEEDS_MOTION),
4015 ADDCMD(
"<", commandUnindentLines, IS_CHANGE | NEEDS_MOTION),
4016 ADDCMD(
"<c-f>", commandScrollPageDown, 0),
4017 ADDCMD(
"<pagedown>", commandScrollPageDown, 0),
4018 ADDCMD(
"<c-b>", commandScrollPageUp, 0),
4019 ADDCMD(
"<pageup>", commandScrollPageUp, 0),
4020 ADDCMD(
"<c-u>", commandScrollHalfPageUp, 0),
4021 ADDCMD(
"<c-d>", commandScrollHalfPageDown, 0),
4022 ADDCMD(
"z.", commandCenterViewOnNonBlank, 0),
4023 ADDCMD(
"zz", commandCenterViewOnCursor, 0),
4024 ADDCMD(
"z<return>", commandTopViewOnNonBlank, 0),
4025 ADDCMD(
"zt", commandTopViewOnCursor, 0),
4026 ADDCMD(
"z-", commandBottomViewOnNonBlank, 0),
4027 ADDCMD(
"zb", commandBottomViewOnCursor, 0),
4028 ADDCMD(
"ga", commandPrintCharacterCode, SHOULD_NOT_RESET),
4029 ADDCMD(
".", commandRepeatLastChange, 0),
4030 ADDCMD(
"==", commandAlignLine, IS_CHANGE),
4031 ADDCMD(
"=", commandAlignLines, IS_CHANGE | NEEDS_MOTION),
4032 ADDCMD(
"~", commandChangeCase, IS_CHANGE),
4033 ADDCMD(
"g~", commandChangeCaseRange, IS_CHANGE | NEEDS_MOTION),
4034 ADDCMD(
"g~~", commandChangeCaseLine, IS_CHANGE),
4035 ADDCMD(
"<c-a>", commandAddToNumber, IS_CHANGE),
4036 ADDCMD(
"<c-x>", commandSubtractFromNumber, IS_CHANGE),
4037 ADDCMD(
"<c-o>", commandGoToPrevJump, CAN_LAND_INSIDE_FOLDING_RANGE),
4038 ADDCMD(
"<c-i>", commandGoToNextJump, CAN_LAND_INSIDE_FOLDING_RANGE),
4040 ADDCMD(
"<c-w>h", commandSwitchToLeftView, 0),
4041 ADDCMD(
"<c-w><c-h>", commandSwitchToLeftView, 0),
4042 ADDCMD(
"<c-w><left>", commandSwitchToLeftView, 0),
4043 ADDCMD(
"<c-w>j", commandSwitchToDownView, 0),
4044 ADDCMD(
"<c-w><c-j>", commandSwitchToDownView, 0),
4045 ADDCMD(
"<c-w><down>", commandSwitchToDownView, 0),
4046 ADDCMD(
"<c-w>k", commandSwitchToUpView, 0),
4047 ADDCMD(
"<c-w><c-k>", commandSwitchToUpView, 0),
4048 ADDCMD(
"<c-w><up>", commandSwitchToUpView, 0),
4049 ADDCMD(
"<c-w>l", commandSwitchToRightView, 0),
4050 ADDCMD(
"<c-w><c-l>", commandSwitchToRightView, 0),
4051 ADDCMD(
"<c-w><right>", commandSwitchToRightView, 0),
4052 ADDCMD(
"<c-w>w", commandSwitchToNextView, 0),
4053 ADDCMD(
"<c-w><c-w>", commandSwitchToNextView, 0),
4055 ADDCMD(
"<c-w>s", commandSplitHoriz, 0),
4056 ADDCMD(
"<c-w>S", commandSplitHoriz, 0),
4057 ADDCMD(
"<c-w><c-s>", commandSplitHoriz, 0),
4058 ADDCMD(
"<c-w>v", commandSplitVert, 0),
4059 ADDCMD(
"<c-w><c-v>", commandSplitVert, 0),
4060 ADDCMD(
"<c-w>c", commandCloseView, 0),
4062 ADDCMD(
"gt", commandSwitchToNextTab, 0),
4063 ADDCMD(
"gT", commandSwitchToPrevTab, 0),
4065 ADDCMD(
"gqq", commandFormatLine, IS_CHANGE),
4066 ADDCMD(
"gq", commandFormatLines, IS_CHANGE | NEEDS_MOTION),
4068 ADDCMD(
"zo", commandExpandLocal, 0),
4069 ADDCMD(
"zc", commandCollapseLocal, 0),
4070 ADDCMD(
"za", commandToggleRegionVisibility, 0),
4071 ADDCMD(
"zr", commandExpandAll, 0),
4072 ADDCMD(
"zm", commandCollapseToplevelNodes, 0),
4074 ADDCMD(
"q.", commandStartRecordingMacro, REGEX_PATTERN),
4075 ADDCMD(
"@.", commandReplayMacro, REGEX_PATTERN),
4077 ADDCMD(
"ZZ", commandCloseWrite, 0),
4078 ADDCMD(
"ZQ", commandCloseNocheck, 0),
4086 static const std::vector<Motion> global{
4088 ADDMOTION(
"h", motionLeft, 0),
4089 ADDMOTION(
"<left>", motionLeft, 0),
4090 ADDMOTION(
"<backspace>", motionLeft, 0),
4091 ADDMOTION(
"j", motionDown, 0),
4092 ADDMOTION(
"<down>", motionDown, 0),
4093 ADDMOTION(
"<enter>", motionDownToFirstNonBlank, 0),
4094 ADDMOTION(
"<return>", motionDownToFirstNonBlank, 0),
4095 ADDMOTION(
"k", motionUp, 0),
4096 ADDMOTION(
"<up>", motionUp, 0),
4097 ADDMOTION(
"-", motionUpToFirstNonBlank, 0),
4098 ADDMOTION(
"+", motionDownToFirstNonBlank, 0),
4099 ADDMOTION(
"l", motionRight, 0),
4100 ADDMOTION(
"<right>", motionRight, 0),
4101 ADDMOTION(
" ", motionRight, 0),
4102 ADDMOTION(
"$", motionToEOL, 0),
4103 ADDMOTION(
"g_", motionToLastNonBlank, 0),
4104 ADDMOTION(
"<end>", motionToEOL, 0),
4105 ADDMOTION(
"0", motionToColumn0, 0),
4106 ADDMOTION(
"<home>", motionToColumn0, 0),
4107 ADDMOTION(
"^", motionToFirstCharacterOfLine, 0),
4108 ADDMOTION(
"f.", motionFindChar, REGEX_PATTERN | CAN_LAND_INSIDE_FOLDING_RANGE),
4109 ADDMOTION(
"F.", motionFindCharBackward, REGEX_PATTERN | CAN_LAND_INSIDE_FOLDING_RANGE),
4110 ADDMOTION(
"t.", motionToChar, REGEX_PATTERN | CAN_LAND_INSIDE_FOLDING_RANGE),
4111 ADDMOTION(
"T.", motionToCharBackward, REGEX_PATTERN | CAN_LAND_INSIDE_FOLDING_RANGE),
4112 ADDMOTION(
";", motionRepeatlastTF, CAN_LAND_INSIDE_FOLDING_RANGE),
4113 ADDMOTION(
",", motionRepeatlastTFBackward, CAN_LAND_INSIDE_FOLDING_RANGE),
4114 ADDMOTION(
"n", motionFindNext, CAN_LAND_INSIDE_FOLDING_RANGE),
4115 ADDMOTION(
"N", motionFindPrev, CAN_LAND_INSIDE_FOLDING_RANGE),
4116 ADDMOTION(
"gg", motionToLineFirst, 0),
4117 ADDMOTION(
"G", motionToLineLast, 0),
4118 ADDMOTION(
"w", motionWordForward, IS_NOT_LINEWISE | CAN_LAND_INSIDE_FOLDING_RANGE),
4119 ADDMOTION(
"W", motionWORDForward, IS_NOT_LINEWISE | CAN_LAND_INSIDE_FOLDING_RANGE),
4120 ADDMOTION(
"<c-right>", motionWordForward, IS_NOT_LINEWISE | CAN_LAND_INSIDE_FOLDING_RANGE),
4121 ADDMOTION(
"<c-left>", motionWordBackward, IS_NOT_LINEWISE | CAN_LAND_INSIDE_FOLDING_RANGE),
4122 ADDMOTION(
"b", motionWordBackward, CAN_LAND_INSIDE_FOLDING_RANGE),
4123 ADDMOTION(
"B", motionWORDBackward, CAN_LAND_INSIDE_FOLDING_RANGE),
4124 ADDMOTION(
"e", motionToEndOfWord, CAN_LAND_INSIDE_FOLDING_RANGE),
4125 ADDMOTION(
"E", motionToEndOfWORD, CAN_LAND_INSIDE_FOLDING_RANGE),
4126 ADDMOTION(
"ge", motionToEndOfPrevWord, CAN_LAND_INSIDE_FOLDING_RANGE),
4127 ADDMOTION(
"gE", motionToEndOfPrevWORD, CAN_LAND_INSIDE_FOLDING_RANGE),
4128 ADDMOTION(
"|", motionToScreenColumn, 0),
4129 ADDMOTION(
"%", motionToMatchingItem, IS_NOT_LINEWISE | CAN_LAND_INSIDE_FOLDING_RANGE),
4130 ADDMOTION(
"`[a-zA-Z^><\\.\\[\\]]", motionToMark, REGEX_PATTERN | CAN_LAND_INSIDE_FOLDING_RANGE),
4131 ADDMOTION(
"'[a-zA-Z^><]", motionToMarkLine, REGEX_PATTERN | CAN_LAND_INSIDE_FOLDING_RANGE),
4132 ADDMOTION(
"[[", motionToPreviousBraceBlockStart, IS_NOT_LINEWISE | CAN_LAND_INSIDE_FOLDING_RANGE),
4133 ADDMOTION(
"]]", motionToNextBraceBlockStart, IS_NOT_LINEWISE | CAN_LAND_INSIDE_FOLDING_RANGE),
4134 ADDMOTION(
"[]", motionToPreviousBraceBlockEnd, IS_NOT_LINEWISE | CAN_LAND_INSIDE_FOLDING_RANGE),
4135 ADDMOTION(
"][", motionToNextBraceBlockEnd, IS_NOT_LINEWISE | CAN_LAND_INSIDE_FOLDING_RANGE),
4136 ADDMOTION(
"*", motionToNextOccurrence, CAN_LAND_INSIDE_FOLDING_RANGE),
4137 ADDMOTION(
"#", motionToPrevOccurrence, CAN_LAND_INSIDE_FOLDING_RANGE),
4138 ADDMOTION(
"H", motionToFirstLineOfWindow, 0),
4139 ADDMOTION(
"M", motionToMiddleLineOfWindow, 0),
4140 ADDMOTION(
"L", motionToLastLineOfWindow, 0),
4141 ADDMOTION(
"gj", motionToNextVisualLine, 0),
4142 ADDMOTION(
"g<down>", motionToNextVisualLine, 0),
4143 ADDMOTION(
"gk", motionToPrevVisualLine, 0),
4144 ADDMOTION(
"g<up>", motionToPrevVisualLine, 0),
4145 ADDMOTION(
"(", motionToPreviousSentence, CAN_LAND_INSIDE_FOLDING_RANGE),
4146 ADDMOTION(
")", motionToNextSentence, CAN_LAND_INSIDE_FOLDING_RANGE),
4147 ADDMOTION(
"{", motionToBeforeParagraph, CAN_LAND_INSIDE_FOLDING_RANGE),
4148 ADDMOTION(
"}", motionToAfterParagraph, CAN_LAND_INSIDE_FOLDING_RANGE),
4151 ADDMOTION(
"iw", textObjectInnerWord, 0),
4152 ADDMOTION(
"aw", textObjectAWord, IS_NOT_LINEWISE),
4153 ADDMOTION(
"iW", textObjectInnerWORD, 0),
4154 ADDMOTION(
"aW", textObjectAWORD, IS_NOT_LINEWISE),
4155 ADDMOTION(
"is", textObjectInnerSentence, IS_NOT_LINEWISE | CAN_LAND_INSIDE_FOLDING_RANGE),
4156 ADDMOTION(
"as", textObjectASentence, IS_NOT_LINEWISE | CAN_LAND_INSIDE_FOLDING_RANGE),
4157 ADDMOTION(
"ip", textObjectInnerParagraph, IS_NOT_LINEWISE | CAN_LAND_INSIDE_FOLDING_RANGE),
4158 ADDMOTION(
"ap", textObjectAParagraph, IS_NOT_LINEWISE | CAN_LAND_INSIDE_FOLDING_RANGE),
4159 ADDMOTION(
"i\"", textObjectInnerQuoteDouble, IS_NOT_LINEWISE | CAN_LAND_INSIDE_FOLDING_RANGE),
4160 ADDMOTION(
"a\"", textObjectAQuoteDouble, IS_NOT_LINEWISE | CAN_LAND_INSIDE_FOLDING_RANGE),
4161 ADDMOTION(
"i'", textObjectInnerQuoteSingle, IS_NOT_LINEWISE | CAN_LAND_INSIDE_FOLDING_RANGE),
4162 ADDMOTION(
"a'", textObjectAQuoteSingle, IS_NOT_LINEWISE | CAN_LAND_INSIDE_FOLDING_RANGE),
4163 ADDMOTION(
"i`", textObjectInnerBackQuote, IS_NOT_LINEWISE | CAN_LAND_INSIDE_FOLDING_RANGE),
4164 ADDMOTION(
"a`", textObjectABackQuote, IS_NOT_LINEWISE | CAN_LAND_INSIDE_FOLDING_RANGE),
4165 ADDMOTION(
"i[()b]", textObjectInnerParen, REGEX_PATTERN | IS_NOT_LINEWISE | CAN_LAND_INSIDE_FOLDING_RANGE),
4166 ADDMOTION(
"a[()b]", textObjectAParen, REGEX_PATTERN | IS_NOT_LINEWISE | CAN_LAND_INSIDE_FOLDING_RANGE),
4167 ADDMOTION(
"i[{}B]", textObjectInnerCurlyBracket, REGEX_PATTERN | IS_NOT_LINEWISE | CAN_LAND_INSIDE_FOLDING_RANGE),
4168 ADDMOTION(
"a[{}B]", textObjectACurlyBracket, REGEX_PATTERN | IS_NOT_LINEWISE | CAN_LAND_INSIDE_FOLDING_RANGE),
4169 ADDMOTION(
"i[><]", textObjectInnerInequalitySign, REGEX_PATTERN | IS_NOT_LINEWISE | CAN_LAND_INSIDE_FOLDING_RANGE),
4170 ADDMOTION(
"a[><]", textObjectAInequalitySign, REGEX_PATTERN | IS_NOT_LINEWISE | CAN_LAND_INSIDE_FOLDING_RANGE),
4171 ADDMOTION(
"i[\\[\\]]", textObjectInnerBracket, REGEX_PATTERN | IS_NOT_LINEWISE | CAN_LAND_INSIDE_FOLDING_RANGE),
4172 ADDMOTION(
"a[\\[\\]]", textObjectABracket, REGEX_PATTERN | IS_NOT_LINEWISE | CAN_LAND_INSIDE_FOLDING_RANGE),
4173 ADDMOTION(
"i,", textObjectInnerComma, IS_NOT_LINEWISE | CAN_LAND_INSIDE_FOLDING_RANGE),
4174 ADDMOTION(
"a,", textObjectAComma, IS_NOT_LINEWISE | CAN_LAND_INSIDE_FOLDING_RANGE),
4176 ADDMOTION(
"/<enter>", motionToIncrementalSearchMatch, IS_NOT_LINEWISE | CAN_LAND_INSIDE_FOLDING_RANGE),
4177 ADDMOTION(
"?<enter>", motionToIncrementalSearchMatch, IS_NOT_LINEWISE | CAN_LAND_INSIDE_FOLDING_RANGE),
@ ActivateMouseIn
Activate attribute on mouse in.
QExplicitlySharedDataPointer< Attribute > Ptr
Shared data pointer for Attribute.
virtual bool exec(KTextEditor::View *view, const QString &cmd, QString &msg, const KTextEditor::Range &range=KTextEditor::Range::invalid())=0
Execute the command for the given view and cmd string.
The Cursor represents a position in a Document.
constexpr int column() const noexcept
Retrieve the column on which this cursor is situated.
void setColumn(int column) noexcept
Set the cursor column to column.
constexpr bool isValid() const noexcept
Returns whether the current position of this cursor is a valid position (line + column must both be >...
void setLine(int line) noexcept
Set the cursor line to line.
constexpr int line() const noexcept
Retrieve the line on which this cursor is situated.
static constexpr Cursor invalid() noexcept
Returns an invalid cursor.
QString line(int line) const override
Get a single text line.
void textRemoved(KTextEditor::Document *document, KTextEditor::Range range, const QString &oldText)
The document emits this signal whenever range was removed, i.e.
bool editStart()
Enclose editor actions with editStart() and editEnd() to group them.
bool wrapText(int startLine, int endLine)
Warp a line.
void textInsertedRange(KTextEditor::Document *document, KTextEditor::Range range)
The document emits this signal whenever text was inserted.
bool editEnd()
End a editor operation.
void aboutToInvalidateMovingInterfaceContent(KTextEditor::Document *document)
This signal is emitted before the ranges of a document are invalidated and the revisions are deleted ...
virtual void setAttribute(Attribute::Ptr attribute)=0
Sets the currently active attribute for this range.
virtual void setAttributeOnlyForViews(bool onlyForViews)=0
Set if this range's attribute is only visible in views, not for example prints.
virtual void setView(View *view)=0
Sets the currently active view for this range.
virtual void setZDepth(qreal zDepth)=0
Set the current Z-depth of this range.
@ DoNotExpand
Don't expand to encapsulate new characters in either direction. This is the default.
constexpr Cursor end() const noexcept
Get the end position of this range.
constexpr Cursor start() const noexcept
Get the start position of this range.
void setRange(Range range) noexcept
Set the start and end cursors to range.start() and range.end() respectively.
void configChanged(KTextEditor::View *view)
This signal is emitted whenever the current view configuration is changed.
bool handleKeypress(const QKeyEvent *e) override
parses a key stroke to check if it's a valid (part of) a command
virtual const std::vector< Command > & commands()
Return commands available for this mode.
bool commandEnterInsertModeLast()
enter insert mode at the last insert position
void resetParser()
(re)set to start configuration.
bool commandEnterInsertModeAppendEOL()
start insert mode after the last character of the line
bool commandEnterInsertMode()
enter insert mode at the cursor position
int getFirstNonBlank(int line=-1) const
Get the index of the first non-blank character from the given line.
virtual const std::vector< Motion > & motions()
Return motions available for this mode.
bool commandEnterInsertModeAppend()
enter insert mode after the current character
Class representing a single text line.
int firstChar() const
Returns the position of the first non-whitespace character.
static constexpr Range invalid() noexcept
Returns an invalid range.
Q_SCRIPTABLE Q_NOREPLY void start()
QString i18n(const char *text, const TYPE &arg...)
KCOREADDONS_EXPORT Result match(QStringView pattern, QStringView str)
const QList< QKeySequence > & end()
long long int skipSpaces(long long int i, const typename Trait::String &line)
bool isLower(char32_t ucs4)
bool isSpace(char32_t ucs4)
bool isUpper(char32_t ucs4)
char32_t toLower(char32_t ucs4)
char32_t toUpper(char32_t ucs4)
Qt::KeyboardModifiers modifiers() const const
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
UseUnicodePropertiesOption
qsizetype count() const const
QString & append(QChar ch)
const QChar at(qsizetype position) const const
qsizetype indexOf(QChar ch, qsizetype from, Qt::CaseSensitivity cs) const const
bool isEmpty() const const
qsizetype lastIndexOf(QChar ch, Qt::CaseSensitivity cs) const const
qsizetype length() const const
QString mid(qsizetype position, qsizetype n) const const
QString number(double n, char format, int precision)
QString & prepend(QChar ch)
QString & remove(QChar ch, Qt::CaseSensitivity cs)
QString repeated(qsizetype times) const const
QString & replace(QChar before, QChar after, Qt::CaseSensitivity cs)
qsizetype size() const const
bool startsWith(QChar c, Qt::CaseSensitivity cs) const const
QString toLower() const const
QString toUpper() const const
QString trimmed() const const
QTextStream & dec(QTextStream &stream)
QTextStream & hex(QTextStream &stream)
QTextStream & oct(QTextStream &stream)
QTextStream & right(QTextStream &stream)
QFuture< QtPrivate::MapResultType< Iterator, MapFunctor > > mapped(Iterator begin, Iterator end, MapFunctor &&function)