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::commandToggleComment()
1067 doc()->comment(m_view, m_view->cursorPosition().line(), m_view->cursorPosition().column(), KTextEditor::DocumentPrivate::ToggleComment);
1071bool NormalViMode::commandChange()
1073 KTextEditor::Cursor c(m_view->cursorPosition());
1075 OperationMode m = getOperationMode();
1077 doc()->setUndoMergeAllEdits(
true);
1081 if (m == LineWise) {
1083 doc()->insertLine(m_commandRange.startLine, QString());
1084 c.
setLine(m_commandRange.startLine);
1086 }
else if (m == Block) {
1089 return commandPrependToBlock();
1091 if (m_commandRange.startLine < m_commandRange.endLine) {
1092 c.
setLine(m_commandRange.startLine);
1094 c.
setColumn(m_commandRange.startColumn);
1102 if (m == LineWise) {
1106 m_deleteCommand =
true;
1110bool NormalViMode::commandChangeToEOL()
1112 commandDeleteToEOL();
1114 if (getOperationMode() == Block) {
1115 return commandPrependToBlock();
1118 m_deleteCommand =
true;
1122bool NormalViMode::commandChangeLine()
1124 m_deleteCommand =
true;
1125 KTextEditor::Cursor c(m_view->cursorPosition());
1129 doc()->setUndoMergeAllEdits(
true);
1132 if (getCount() >= 2) {
1133 Range r(c.
line(), 0, c.
line() + getCount() - 2, 0, InclusiveMotion);
1139 deleteRange(r, CharWise,
true);
1142 if (getOperationMode() == Block) {
1143 return commandPrependToBlock();
1153bool NormalViMode::commandSubstituteChar()
1155 if (commandDeleteChar()) {
1161 m_deleteCommand =
true;
1165bool NormalViMode::commandSubstituteLine()
1167 m_deleteCommand =
true;
1168 return commandChangeLine();
1171bool NormalViMode::commandYank()
1176 OperationMode m = getOperationMode();
1177 yankedText = getRange(m_commandRange, m);
1179 highlightYank(m_commandRange, m);
1181 QChar chosen_register = getChosenRegister(ZeroRegister);
1182 fillRegister(chosen_register, yankedText, m);
1183 yankToClipBoard(chosen_register, yankedText);
1188bool NormalViMode::commandYankLine()
1190 KTextEditor::Cursor c(m_view->cursorPosition());
1192 int linenum = c.
line();
1194 for (
int i = 0; i < getCount(); i++) {
1195 lines.
append(getLine(linenum + i) + QLatin1Char(
'\n'));
1198 Range yankRange(linenum, 0, linenum + getCount() - 1, getLine(linenum + getCount() - 1).length(), InclusiveMotion);
1199 highlightYank(yankRange);
1201 QChar chosen_register = getChosenRegister(ZeroRegister);
1202 fillRegister(chosen_register, lines, LineWise);
1203 yankToClipBoard(chosen_register, lines);
1208bool NormalViMode::commandYankToEOL()
1210 OperationMode m = CharWise;
1211 KTextEditor::Cursor c(m_view->cursorPosition());
1213 MotionType motion = m_commandRange.motionType;
1214 m_commandRange.endLine = c.
line() + getCount() - 1;
1215 m_commandRange.endColumn = doc()->lineLength(m_commandRange.endLine) - 1;
1216 m_commandRange.motionType = InclusiveMotion;
1218 switch (m_viInputModeManager->getCurrentViMode()) {
1219 case ViMode::NormalMode:
1220 m_commandRange.startLine = c.
line();
1221 m_commandRange.startColumn = c.
column();
1223 case ViMode::VisualMode:
1224 case ViMode::VisualLineMode:
1227 VisualViMode *visual =
static_cast<VisualViMode *
>(
this);
1228 visual->setStart(KTextEditor::Cursor(visual->getStart().
line(), 0));
1231 case ViMode::VisualBlockMode:
1239 const QString &yankedText = getRange(m_commandRange, m);
1240 m_commandRange.motionType = motion;
1241 highlightYank(m_commandRange);
1243 QChar chosen_register = getChosenRegister(ZeroRegister);
1244 fillRegister(chosen_register, yankedText, m);
1245 yankToClipBoard(chosen_register, yankedText);
1256bool NormalViMode::commandPaste()
1258 return paste(AfterCurrentPosition,
false,
false);
1262bool NormalViMode::commandPasteBefore()
1264 return paste(AtCurrentPosition,
false,
false);
1272bool NormalViMode::commandgPaste()
1274 return paste(AfterCurrentPosition,
true,
false);
1279bool NormalViMode::commandgPasteBefore()
1281 return paste(AtCurrentPosition,
true,
false);
1284bool NormalViMode::commandIndentedPaste()
1286 return paste(AfterCurrentPosition,
false,
true);
1289bool NormalViMode::commandIndentedPasteBefore()
1291 return paste(AtCurrentPosition,
false,
true);
1294bool NormalViMode::commandDeleteChar()
1296 KTextEditor::Cursor c(m_view->cursorPosition());
1299 if (m_commandRange.startLine != -1 && m_commandRange.startColumn != -1) {
1302 if (r.endColumn > doc()->lineLength(r.startLine)) {
1303 r.endColumn = doc()->lineLength(r.startLine);
1308 OperationMode m = CharWise;
1309 if (m_viInputModeManager->getCurrentViMode() == VisualLineMode) {
1311 }
else if (m_viInputModeManager->getCurrentViMode() == VisualBlockMode) {
1315 m_deleteCommand =
true;
1316 return deleteRange(r, m);
1319bool NormalViMode::commandDeleteCharBackward()
1321 KTextEditor::Cursor c(m_view->cursorPosition());
1325 if (m_commandRange.startLine != -1 && m_commandRange.startColumn != -1) {
1328 if (r.startColumn < 0) {
1334 OperationMode m = CharWise;
1335 if (m_viInputModeManager->getCurrentViMode() == VisualLineMode) {
1337 }
else if (m_viInputModeManager->getCurrentViMode() == VisualBlockMode) {
1341 m_deleteCommand =
true;
1342 return deleteRange(r, m);
1345bool NormalViMode::commandReplaceCharacter()
1347 QString key = KeyParser::self()->decodeKeySequence(m_keys.right(1));
1350 const int keyCode = KeyParser::self()->encoded2qt(m_keys.right(1));
1367 key = QStringLiteral(
"\n");
1371 if (m_viInputModeManager->isAnyVisualMode()) {
1372 OperationMode m = getOperationMode();
1373 QString text = getRange(m_commandRange, m);
1375 if (m == LineWise) {
1379 static const QRegularExpression nonNewlineRegex(QStringLiteral(
"[^\n]"));
1380 text.
replace(nonNewlineRegex, key);
1382 m_commandRange.normalize();
1383 KTextEditor::Cursor
start(m_commandRange.startLine, m_commandRange.startColumn);
1384 KTextEditor::Cursor
end(m_commandRange.endLine, m_commandRange.endColumn);
1385 KTextEditor::Range range(
start, end);
1387 r = doc()->replaceText(range, text, m == Block);
1390 KTextEditor::Cursor c1(m_view->cursorPosition());
1391 KTextEditor::Cursor c2(m_view->cursorPosition());
1395 if (c2.
column() > doc()->lineLength(m_view->cursorPosition().line())) {
1399 r = doc()->replaceText(KTextEditor::Range(c1, c2), key.
repeated(getCount()));
1405bool NormalViMode::commandSwitchToCmdLine()
1407 QString initialText;
1408 if (m_viInputModeManager->isAnyVisualMode()) {
1410 m_viInputModeManager->getViVisualMode()->saveRangeMarks();
1411 initialText = QStringLiteral(
"'<,'>");
1412 }
else if (getCount() != 1) {
1415 initialText = QLatin1String(
".,.+") +
QString::number(getCount() - 1);
1418 m_viInputModeManager->inputAdapter()->showViModeEmulatedCommandBar();
1419 m_viInputModeManager->inputAdapter()->viModeEmulatedCommandBar()->init(EmulatedCommandBar::Command, initialText);
1421 m_commandShouldKeepSelection =
true;
1426bool NormalViMode::commandSearchBackward()
1428 m_viInputModeManager->inputAdapter()->showViModeEmulatedCommandBar();
1429 m_viInputModeManager->inputAdapter()->viModeEmulatedCommandBar()->init(EmulatedCommandBar::SearchBackward);
1433bool NormalViMode::commandSearchForward()
1435 m_viInputModeManager->inputAdapter()->showViModeEmulatedCommandBar();
1436 m_viInputModeManager->inputAdapter()->viModeEmulatedCommandBar()->init(EmulatedCommandBar::SearchForward);
1440bool NormalViMode::commandUndo()
1443 m_viInputModeManager->clearCurrentChangeLog();
1445 if (doc()->undoCount() > 0) {
1446 const bool mapped = m_viInputModeManager->keyMapper()->isExecutingMapping();
1455 if (m_viInputModeManager->isAnyVisualMode()) {
1456 m_viInputModeManager->getViVisualMode()->setStart(KTextEditor::Cursor(-1, -1));
1457 m_view->clearSelection();
1465bool NormalViMode::commandRedo()
1467 if (doc()->redoCount() > 0) {
1468 const bool mapped = m_viInputModeManager->keyMapper()->isExecutingMapping();
1477 if (m_viInputModeManager->isAnyVisualMode()) {
1478 m_viInputModeManager->getViVisualMode()->setStart(KTextEditor::Cursor(-1, -1));
1479 m_view->clearSelection();
1487bool NormalViMode::commandSetMark()
1489 KTextEditor::Cursor c(m_view->cursorPosition());
1491 QChar mark = m_keys.at(m_keys.size() - 1);
1492 m_viInputModeManager->marks()->setUserMark(mark, c);
1497bool NormalViMode::commandIndentLine()
1499 KTextEditor::Cursor c(m_view->cursorPosition());
1501 doc()->indent(KTextEditor::Range(c.
line(), 0, c.
line() + getCount(), 0), 1);
1506bool NormalViMode::commandUnindentLine()
1508 KTextEditor::Cursor c(m_view->cursorPosition());
1510 doc()->indent(KTextEditor::Range(c.
line(), 0, c.
line() + getCount(), 0), -1);
1515bool NormalViMode::commandIndentLines()
1517 const bool downwards = m_commandRange.startLine < m_commandRange.endLine;
1519 m_commandRange.normalize();
1521 int line1 = m_commandRange.startLine;
1522 int line2 = m_commandRange.endLine;
1523 int col = getLine(line2).length();
1524 doc()->indent(KTextEditor::Range(line1, 0, line2, col), getCount());
1527 updateCursor(KTextEditor::Cursor(m_commandRange.startLine, m_commandRange.startColumn));
1529 updateCursor(KTextEditor::Cursor(m_commandRange.endLine, m_commandRange.endColumn));
1534bool NormalViMode::commandUnindentLines()
1536 const bool downwards = m_commandRange.startLine < m_commandRange.endLine;
1538 m_commandRange.normalize();
1540 int line1 = m_commandRange.startLine;
1541 int line2 = m_commandRange.endLine;
1543 doc()->indent(KTextEditor::Range(line1, 0, line2, doc()->lineLength(line2)), -getCount());
1546 updateCursor(KTextEditor::Cursor(m_commandRange.startLine, m_commandRange.startColumn));
1548 updateCursor(KTextEditor::Cursor(m_commandRange.endLine, m_commandRange.endColumn));
1553bool NormalViMode::commandScrollPageDown()
1555 if (getCount() < m_scroll_count_limit) {
1556 for (
int i = 0; i < getCount(); i++) {
1563bool NormalViMode::commandScrollPageUp()
1565 if (getCount() < m_scroll_count_limit) {
1566 for (
int i = 0; i < getCount(); i++) {
1573bool NormalViMode::commandScrollHalfPageUp()
1575 if (getCount() < m_scroll_count_limit) {
1576 for (
int i = 0; i < getCount(); i++) {
1577 m_viewInternal->pageUp(
false,
true);
1583bool NormalViMode::commandScrollHalfPageDown()
1585 if (getCount() < m_scroll_count_limit) {
1586 for (
int i = 0; i < getCount(); i++) {
1587 m_viewInternal->pageDown(
false,
true);
1593bool NormalViMode::commandCenterView(
bool onFirst)
1595 KTextEditor::Cursor c(m_view->cursorPosition());
1596 const int virtualCenterLine = m_viewInternal->startLine() + linesDisplayed() / 2;
1597 const int virtualCursorLine = m_view->textFolding().lineToVisibleLine(c.
line());
1599 scrollViewLines(virtualCursorLine - virtualCenterLine);
1607bool NormalViMode::commandCenterViewOnNonBlank()
1609 return commandCenterView(
true);
1612bool NormalViMode::commandCenterViewOnCursor()
1614 return commandCenterView(
false);
1617bool NormalViMode::commandTopView(
bool onFirst)
1619 KTextEditor::Cursor c(m_view->cursorPosition());
1620 const int virtualCenterLine = m_viewInternal->startLine();
1621 const int virtualCursorLine = m_view->textFolding().lineToVisibleLine(c.
line());
1623 scrollViewLines(virtualCursorLine - virtualCenterLine);
1631bool NormalViMode::commandTopViewOnNonBlank()
1633 return commandTopView(
true);
1636bool NormalViMode::commandTopViewOnCursor()
1638 return commandTopView(
false);
1641bool NormalViMode::commandBottomView(
bool onFirst)
1643 KTextEditor::Cursor c(m_view->cursorPosition());
1644 const int virtualCenterLine = m_viewInternal->endLine();
1645 const int virtualCursorLine = m_view->textFolding().lineToVisibleLine(c.
line());
1647 scrollViewLines(virtualCursorLine - virtualCenterLine);
1655bool NormalViMode::commandBottomViewOnNonBlank()
1657 return commandBottomView(
true);
1660bool NormalViMode::commandBottomViewOnCursor()
1662 return commandBottomView(
false);
1665bool NormalViMode::commandAbort()
1667 m_pendingResetIsDueToExit =
true;
1672bool NormalViMode::commandPrintCharacterCode()
1674 QChar ch = getCharUnderCursor();
1677 message(QStringLiteral(
"NUL"));
1684 if (
oct.length() < 3) {
1685 oct.prepend(QLatin1Char(
'0'));
1687 if (code > 0x80 && code < 0x1000) {
1688 hex.prepend((code < 0x100 ? QLatin1String(
"00") : QLatin1String(
"0")));
1690 message(
i18n(
"'%1' %2, Hex %3, Octal %4", ch, dec, hex, oct));
1696bool NormalViMode::commandRepeatLastChange()
1698 const int repeatCount = getCount();
1700 if (repeatCount > 1) {
1701 m_oneTimeCountOverride = repeatCount;
1704 m_viInputModeManager->repeatLastChange();
1710bool NormalViMode::commandAlignLine()
1712 const int line = m_view->cursorPosition().line();
1713 KTextEditor::Range alignRange(KTextEditor::Cursor(line, 0), KTextEditor::Cursor(line, 0));
1715 doc()->align(m_view, alignRange);
1720bool NormalViMode::commandAlignLines()
1722 m_commandRange.normalize();
1724 KTextEditor::Cursor
start(m_commandRange.startLine, 0);
1725 KTextEditor::Cursor
end(m_commandRange.endLine, 0);
1727 doc()->align(m_view, KTextEditor::Range(
start, end));
1732bool NormalViMode::commandAddToNumber()
1734 addToNumberUnderCursor(getCount());
1739bool NormalViMode::commandSubtractFromNumber()
1741 addToNumberUnderCursor(-getCount());
1746bool NormalViMode::commandPrependToBlock()
1748 KTextEditor::Cursor c(m_view->cursorPosition());
1751 m_commandRange.normalize();
1752 c.
setColumn(m_commandRange.startColumn);
1753 c.
setLine(m_commandRange.startLine);
1756 m_stickyColumn = -1;
1757 m_viInputModeManager->getViInsertMode()->setBlockPrependMode(m_commandRange);
1758 return startInsertMode();
1761bool NormalViMode::commandAppendToBlock()
1763 KTextEditor::Cursor c(m_view->cursorPosition());
1765 m_commandRange.normalize();
1766 if (m_stickyColumn == (
unsigned int)KateVi::EOL) {
1768 c.
setLine(m_commandRange.startLine);
1771 m_viInputModeManager->getViInsertMode()->setBlockAppendMode(m_commandRange, AppendEOL);
1773 m_viInputModeManager->getViInsertMode()->setBlockAppendMode(m_commandRange, Append);
1775 c.
setColumn(m_commandRange.endColumn + 1);
1776 c.
setLine(m_commandRange.startLine);
1780 m_stickyColumn = -1;
1782 return startInsertMode();
1785bool NormalViMode::commandGoToNextJump()
1787 KTextEditor::Cursor c = getNextJump(m_view->cursorPosition());
1793bool NormalViMode::commandGoToPrevJump()
1795 KTextEditor::Cursor c = getPrevJump(m_view->cursorPosition());
1801bool NormalViMode::commandSwitchToLeftView()
1807bool NormalViMode::commandSwitchToDownView()
1813bool NormalViMode::commandSwitchToUpView()
1819bool NormalViMode::commandSwitchToRightView()
1825bool NormalViMode::commandSwitchToNextView()
1831bool NormalViMode::commandSplitHoriz()
1833 return executeKateCommand(QStringLiteral(
"split"));
1836bool NormalViMode::commandSplitVert()
1838 return executeKateCommand(QStringLiteral(
"vsplit"));
1841bool NormalViMode::commandCloseView()
1843 return executeKateCommand(QStringLiteral(
"close"));
1846bool NormalViMode::commandSwitchToNextTab()
1848 QString command = QStringLiteral(
"bn");
1854 return executeKateCommand(command);
1857bool NormalViMode::commandSwitchToPrevTab()
1859 QString command = QStringLiteral(
"bp");
1865 return executeKateCommand(command);
1868bool NormalViMode::commandFormatLine()
1870 KTextEditor::Cursor c(m_view->cursorPosition());
1872 reformatLines(c.
line(), c.
line() + getCount() - 1);
1877bool NormalViMode::commandFormatLines()
1879 reformatLines(m_commandRange.startLine, m_commandRange.endLine);
1883bool NormalViMode::commandCollapseToplevelNodes()
1885 m_view->slotFoldToplevelNodes();
1889bool NormalViMode::commandStartRecordingMacro()
1891 const QChar reg = m_keys[m_keys.size() - 1];
1892 m_viInputModeManager->macroRecorder()->start(reg);
1896bool NormalViMode::commandReplayMacro()
1901 m_viInputModeManager->clearCurrentChangeLog();
1902 const QChar reg = m_keys[m_keys.size() - 1];
1903 const unsigned int count = getCount();
1906 for (
unsigned int i = 0; i < count; i++) {
1907 m_viInputModeManager->macroRecorder()->replay(reg);
1913bool NormalViMode::commandCloseNocheck()
1915 return executeKateCommand(QStringLiteral(
"q!"));
1918bool NormalViMode::commandCloseWrite()
1920 return executeKateCommand(QStringLiteral(
"wq"));
1923bool NormalViMode::commandCollapseLocal()
1925 int line = m_view->cursorPosition().line();
1926 bool actionDone =
false;
1927 while (!actionDone && line > -1) {
1928 actionDone = m_view->foldLine(line--).isValid();
1933bool NormalViMode::commandExpandAll()
1936 m_view->slotExpandToplevelNodes();
1940bool NormalViMode::commandExpandLocal()
1942 int line = m_view->cursorPosition().line();
1943 return m_view->unfoldLine(line);
1946bool NormalViMode::commandToggleRegionVisibility()
1949 m_view->slotToggleFolding();
1957Range NormalViMode::motionDown()
1959 return goLineDown();
1962Range NormalViMode::motionUp()
1967Range NormalViMode::motionLeft()
1969 KTextEditor::Cursor cursor(m_view->cursorPosition());
1970 m_stickyColumn = -1;
1971 Range r(cursor, ExclusiveMotion);
1972 r.endColumn -= getCount();
1974 if (r.endColumn < 0) {
1981Range NormalViMode::motionRight()
1983 KTextEditor::Cursor cursor(m_view->cursorPosition());
1984 m_stickyColumn = -1;
1985 Range r(cursor, ExclusiveMotion);
1986 r.endColumn += getCount();
1989 if (r.endColumn > doc()->lineLength(r.endLine)) {
1990 r.endColumn = doc()->lineLength(r.endLine);
1996Range NormalViMode::motionPageDown()
1998 KTextEditor::Cursor c(m_view->cursorPosition());
1999 Range r(c, InclusiveMotion);
2000 r.endLine += linesDisplayed();
2002 if (r.endLine >= doc()->lines()) {
2003 r.endLine = doc()->lines() - 1;
2008Range NormalViMode::motionPageUp()
2010 KTextEditor::Cursor c(m_view->cursorPosition());
2011 Range r(c, InclusiveMotion);
2012 r.endLine -= linesDisplayed();
2014 if (r.endLine < 0) {
2020Range NormalViMode::motionHalfPageDown()
2022 if (commandScrollHalfPageDown()) {
2023 KTextEditor::Cursor c = m_view->cursorPosition();
2024 m_commandRange.endLine = c.
line();
2025 m_commandRange.endColumn = c.
column();
2026 return m_commandRange;
2031Range NormalViMode::motionHalfPageUp()
2033 if (commandScrollHalfPageUp()) {
2034 KTextEditor::Cursor c = m_view->cursorPosition();
2035 m_commandRange.endLine = c.
line();
2036 m_commandRange.endColumn = c.
column();
2037 return m_commandRange;
2042Range NormalViMode::motionDownToFirstNonBlank()
2044 Range r = goLineDown();
2049Range NormalViMode::motionUpToFirstNonBlank()
2051 Range r = goLineUp();
2056Range NormalViMode::motionWordForward()
2058 KTextEditor::Cursor c(m_view->cursorPosition());
2059 Range r(c, ExclusiveMotion);
2061 m_stickyColumn = -1;
2065 if (c.
line() == doc()->lines() - 1 && c.
column() == doc()->lineLength(c.
line()) - 1) {
2066 r.motionType = InclusiveMotion;
2068 for (
int i = 0; i < getCount(); i++) {
2073 c = doc()->documentEnd();
2076 if (i < getCount()) {
2077 r.motionType = InclusiveMotion;
2084 r.endColumn = c.
column();
2085 r.endLine = c.
line();
2090Range NormalViMode::motionWordBackward()
2092 KTextEditor::Cursor c(m_view->cursorPosition());
2093 Range r(c, ExclusiveMotion);
2095 m_stickyColumn = -1;
2097 for (
int i = 0; i < getCount(); i++) {
2101 c = KTextEditor::Cursor(0, 0);
2106 r.endColumn = c.
column();
2107 r.endLine = c.
line();
2112Range NormalViMode::motionWORDForward()
2114 KTextEditor::Cursor c(m_view->cursorPosition());
2115 Range r(c, ExclusiveMotion);
2117 m_stickyColumn = -1;
2119 for (
int i = 0; i < getCount(); i++) {
2123 if (c.
line() == doc()->lines() - 1 && c.
column() == doc()->lineLength(c.
line()) - 1) {
2128 r.endColumn = c.
column();
2129 r.endLine = c.
line();
2134Range NormalViMode::motionWORDBackward()
2136 KTextEditor::Cursor c(m_view->cursorPosition());
2137 Range r(c, ExclusiveMotion);
2139 m_stickyColumn = -1;
2141 for (
int i = 0; i < getCount(); i++) {
2145 c = KTextEditor::Cursor(0, 0);
2149 r.endColumn = c.
column();
2150 r.endLine = c.
line();
2155Range NormalViMode::motionToEndOfWord()
2157 KTextEditor::Cursor c(m_view->cursorPosition());
2158 Range r(c, InclusiveMotion);
2160 m_stickyColumn = -1;
2162 for (
int i = 0; i < getCount(); i++) {
2167 c = doc()->documentEnd();
2170 r.endColumn = c.
column();
2171 r.endLine = c.
line();
2176Range NormalViMode::motionToEndOfWORD()
2178 KTextEditor::Cursor c(m_view->cursorPosition());
2179 Range r(c, InclusiveMotion);
2181 m_stickyColumn = -1;
2183 for (
int i = 0; i < getCount(); i++) {
2188 c = doc()->documentEnd();
2191 r.endColumn = c.
column();
2192 r.endLine = c.
line();
2197Range NormalViMode::motionToEndOfPrevWord()
2199 KTextEditor::Cursor c(m_view->cursorPosition());
2200 Range r(c, InclusiveMotion);
2202 m_stickyColumn = -1;
2204 for (
int i = 0; i < getCount(); i++) {
2208 r.endColumn = c.
column();
2209 r.endLine = c.
line();
2220Range NormalViMode::motionToEndOfPrevWORD()
2222 KTextEditor::Cursor c(m_view->cursorPosition());
2223 Range r(c, InclusiveMotion);
2225 m_stickyColumn = -1;
2227 for (
int i = 0; i < getCount(); i++) {
2231 r.endColumn = c.
column();
2232 r.endLine = c.
line();
2243void NormalViMode::stickStickyColumnToEOL()
2245 if (m_keys.size() == 1) {
2246 m_stickyColumn = KateVi::EOL;
2250Range NormalViMode::motionToEOL()
2252 KTextEditor::Cursor c(m_view->cursorPosition());
2254 stickStickyColumnToEOL();
2256 unsigned int line = c.
line() + (getCount() - 1);
2257 Range r(line, doc()->lineLength(line) - 1, InclusiveMotion);
2261Range NormalViMode::motionToLastNonBlank()
2263 KTextEditor::Cursor c(m_view->cursorPosition());
2265 stickStickyColumnToEOL();
2267 unsigned int line = c.
line() + (getCount() - 1);
2269 const auto text_line = doc()->plainKateTextLine(line);
2270 Range r(line, text_line.previousNonSpaceChar(text_line.length()), InclusiveMotion);
2274Range NormalViMode::motionToColumn0()
2276 m_stickyColumn = -1;
2277 KTextEditor::Cursor cursor(m_view->cursorPosition());
2278 Range r(cursor.line(), 0, ExclusiveMotion);
2283Range NormalViMode::motionToFirstCharacterOfLine()
2285 m_stickyColumn = -1;
2287 KTextEditor::Cursor cursor(m_view->cursorPosition());
2290 Range r(cursor.line(), c, ExclusiveMotion);
2295Range NormalViMode::motionFindChar()
2297 m_lastTFcommand = m_keys;
2298 KTextEditor::Cursor cursor(m_view->cursorPosition());
2299 QString line = getLine();
2301 m_stickyColumn = -1;
2303 int matchColumn = cursor.column();
2305 for (
int i = 0; i < getCount(); i++) {
2306 matchColumn = line.
indexOf(QStringView(m_keys).
right(1), matchColumn + 1);
2307 if (matchColumn == -1) {
2314 if (matchColumn != -1) {
2315 r.endColumn = matchColumn;
2316 r.endLine = cursor.line();
2324Range NormalViMode::motionFindCharBackward()
2326 m_lastTFcommand = m_keys;
2327 KTextEditor::Cursor cursor(m_view->cursorPosition());
2328 QString line = getLine();
2330 m_stickyColumn = -1;
2332 int matchColumn = -1;
2335 int i = cursor.column() - 1;
2337 while (hits != getCount() && i >= 0) {
2338 if (line.
at(i) == m_keys.at(m_keys.size() - 1)) {
2342 if (hits == getCount()) {
2349 Range r(cursor, ExclusiveMotion);
2351 if (matchColumn != -1) {
2352 r.endColumn = matchColumn;
2353 r.endLine = cursor.line();
2361Range NormalViMode::motionToChar()
2363 m_lastTFcommand = m_keys;
2364 KTextEditor::Cursor cursor(m_view->cursorPosition());
2365 QString line = getLine();
2367 m_stickyColumn = -1;
2372 int matchColumn = cursor.column() + (m_isRepeatedTFcommand ? 2 : 1);
2374 for (
int i = 0; i < getCount(); i++) {
2375 const int lastColumn = matchColumn;
2376 matchColumn = line.
indexOf(m_keys.right(1), matchColumn + ((i > 0) ? 1 : 0));
2377 if (matchColumn == -1) {
2378 if (m_isRepeatedTFcommand) {
2379 matchColumn = lastColumn;
2387 r.endColumn = matchColumn - 1;
2388 r.endLine = cursor.line();
2390 m_isRepeatedTFcommand =
false;
2394Range NormalViMode::motionToCharBackward()
2396 m_lastTFcommand = m_keys;
2397 KTextEditor::Cursor cursor(m_view->cursorPosition());
2398 QString line = getLine();
2400 const int originalColumn = cursor.column();
2401 m_stickyColumn = -1;
2403 int matchColumn = originalColumn - 1;
2406 int i = cursor.column() - (m_isRepeatedTFcommand ? 2 : 1);
2408 Range r(cursor, ExclusiveMotion);
2410 while (hits != getCount() && i >= 0) {
2411 if (line.
at(i) == m_keys.at(m_keys.size() - 1)) {
2415 if (hits == getCount()) {
2422 if (hits == getCount()) {
2423 r.endColumn = matchColumn + 1;
2424 r.endLine = cursor.line();
2429 m_isRepeatedTFcommand =
false;
2434Range NormalViMode::motionRepeatlastTF()
2436 if (!m_lastTFcommand.isEmpty()) {
2437 m_isRepeatedTFcommand =
true;
2438 m_keys = m_lastTFcommand;
2439 if (m_keys.at(0) == QLatin1Char(
'f')) {
2440 return motionFindChar();
2441 }
else if (m_keys.at(0) == QLatin1Char(
'F')) {
2442 return motionFindCharBackward();
2443 }
else if (m_keys.at(0) == QLatin1Char(
't')) {
2444 return motionToChar();
2445 }
else if (m_keys.at(0) == QLatin1Char(
'T')) {
2446 return motionToCharBackward();
2454Range NormalViMode::motionRepeatlastTFBackward()
2456 if (!m_lastTFcommand.isEmpty()) {
2457 m_isRepeatedTFcommand =
true;
2458 m_keys = m_lastTFcommand;
2459 if (m_keys.at(0) == QLatin1Char(
'f')) {
2460 return motionFindCharBackward();
2461 }
else if (m_keys.at(0) == QLatin1Char(
'F')) {
2462 return motionFindChar();
2463 }
else if (m_keys.at(0) == QLatin1Char(
't')) {
2464 return motionToCharBackward();
2465 }
else if (m_keys.at(0) == QLatin1Char(
'T')) {
2466 return motionToChar();
2474Range NormalViMode::motionToLineFirst()
2476 Range r(getCount() - 1, 0, InclusiveMotion);
2477 m_stickyColumn = -1;
2479 if (r.endLine > doc()->lines() - 1) {
2480 r.endLine = doc()->lines() - 1;
2487Range NormalViMode::motionToLineLast()
2489 Range r(doc()->lines() - 1, 0, InclusiveMotion);
2490 m_stickyColumn = -1;
2494 r.endLine = m_count - 1;
2497 if (r.endLine > doc()->lines() - 1) {
2498 r.endLine = doc()->lines() - 1;
2505Range NormalViMode::motionToScreenColumn()
2507 m_stickyColumn = -1;
2509 KTextEditor::Cursor c(m_view->cursorPosition());
2511 int column = getCount() - 1;
2513 if (doc()->lineLength(c.
line()) - 1 < (
int)getCount() - 1) {
2514 column = doc()->lineLength(c.
line()) - 1;
2517 return Range(c.
line(), column, ExclusiveMotion);
2520Range NormalViMode::motionToMark()
2524 m_stickyColumn = -1;
2526 QChar reg = m_keys.at(m_keys.size() - 1);
2528 KTextEditor::Cursor c = m_viInputModeManager->marks()->getMarkPosition(reg);
2530 r.endLine = c.
line();
2531 r.endColumn = c.
column();
2533 error(
i18n(
"Mark not set: %1", m_keys.right(1)));
2542Range NormalViMode::motionToMarkLine()
2544 Range r = motionToMark();
2547 m_stickyColumn = -1;
2551Range NormalViMode::motionToMatchingItem()
2554 int lines = doc()->lines();
2559 int count = getCount();
2563 r.endLine = qRound(lines * count / 100.0) - 1;
2568 KTextEditor::Cursor c(m_view->cursorPosition());
2570 QString l = getLine();
2573 m_stickyColumn = -1;
2579 const auto bracketChar = l.
at(n1);
2581 if (bracketChar == QLatin1Char(
'(') || bracketChar == QLatin1Char(
')') || bracketChar == QLatin1Char(
'{') || bracketChar == QLatin1Char(
'}')
2582 || bracketChar == QLatin1Char(
'[') || bracketChar == QLatin1Char(
']')) {
2588 const KTextEditor::Cursor oldCursorPos = m_view->cursorPosition();
2592 c = m_viewInternal->findMatchingBracket();
2593 if (c > m_view->cursorPosition()) {
2596 m_view->setCursorPosition(oldCursorPos);
2600 const int n2 = l.
indexOf(boundaryRegex, n1);
2601 QString item = l.
mid(n1, n2 - n1);
2602 QString matchingItem = m_matchingItems[item];
2605 int line = c.
line();
2606 int column = n2 - item.
length();
2607 bool reverse =
false;
2609 if (matchingItem.
startsWith(QLatin1Char(
'-'))) {
2610 matchingItem.
remove(0, 1);
2615 if (column == 0 && reverse) {
2622 while (toFind > 0) {
2625 matchItemIdx = l.
lastIndexOf(matchingItem, column - 1);
2627 if (itemIdx != -1 && (matchItemIdx == -1 || itemIdx > matchItemIdx)) {
2631 itemIdx = l.
indexOf(item, column);
2632 matchItemIdx = l.
indexOf(matchingItem, column);
2634 if (itemIdx != -1 && (matchItemIdx == -1 || itemIdx < matchItemIdx)) {
2639 if (matchItemIdx != -1 || itemIdx != -1) {
2641 column = qMin((
unsigned int)itemIdx, (
unsigned int)matchItemIdx);
2643 column = qMax(itemIdx, matchItemIdx);
2647 if (matchItemIdx != -1) {
2648 if (matchItemIdx == column) {
2654 (reverse) ? --line : ++line;
2657 if ((!reverse && line >= lines) || (reverse && line < 0)) {
2667 r.endLine = c.
line();
2668 r.endColumn = c.
column();
2674Range NormalViMode::motionToNextBraceBlockStart()
2678 m_stickyColumn = -1;
2680 int line = findLineStartingWitchChar(QLatin1Char(
'{'), getCount());
2690 if (motionWillBeUsedWithCommand()) {
2693 r.motionType = ExclusiveMotion;
2694 if (m_view->cursorPosition().column() != 0) {
2696 r.endColumn = doc()->lineLength(r.endLine);
2703Range NormalViMode::motionToPreviousBraceBlockStart()
2707 m_stickyColumn = -1;
2709 int line = findLineStartingWitchChar(QLatin1Char(
'{'), getCount(),
false);
2719 if (motionWillBeUsedWithCommand()) {
2721 r.motionType = ExclusiveMotion;
2727Range NormalViMode::motionToNextBraceBlockEnd()
2731 m_stickyColumn = -1;
2733 int line = findLineStartingWitchChar(QLatin1Char(
'}'), getCount());
2743 if (motionWillBeUsedWithCommand()) {
2746 r.motionType = ExclusiveMotion;
2747 if (m_view->cursorPosition().column() != 0) {
2749 r.endColumn = doc()->lineLength(r.endLine);
2756Range NormalViMode::motionToPreviousBraceBlockEnd()
2760 m_stickyColumn = -1;
2762 int line = findLineStartingWitchChar(QLatin1Char(
'}'), getCount(),
false);
2772 if (motionWillBeUsedWithCommand()) {
2773 r.motionType = ExclusiveMotion;
2779Range NormalViMode::motionToNextOccurrence()
2781 const QString word = getWordUnderCursor();
2782 Searcher *searcher = m_viInputModeManager->searcher();
2783 const Range match = searcher->findWordForMotion(word,
false, getWordRangeUnderCursor().
start(), getCount());
2784 if (searcher->lastSearchWrapped()) {
2785 m_view->showSearchWrappedHint(
false);
2791Range NormalViMode::motionToPrevOccurrence()
2793 const QString word = getWordUnderCursor();
2794 Searcher *searcher = m_viInputModeManager->searcher();
2795 const Range match = searcher->findWordForMotion(word,
true, getWordRangeUnderCursor().
start(), getCount());
2796 if (searcher->lastSearchWrapped()) {
2797 m_view->showSearchWrappedHint(
true);
2803Range NormalViMode::motionToFirstLineOfWindow()
2806 if (linesDisplayed() <= (
unsigned int)m_viewInternal->endLine()) {
2807 lines_to_go = m_viewInternal->endLine() - linesDisplayed() - m_view->cursorPosition().line() + 1;
2809 lines_to_go = -m_view->cursorPosition().line();
2812 Range r = goLineUpDown(lines_to_go);
2817Range NormalViMode::motionToMiddleLineOfWindow()
2820 if (linesDisplayed() <= (
unsigned int)m_viewInternal->endLine()) {
2821 lines_to_go = m_viewInternal->endLine() - linesDisplayed() / 2 - m_view->cursorPosition().line();
2823 lines_to_go = m_viewInternal->endLine() / 2 - m_view->cursorPosition().line();
2826 Range r = goLineUpDown(lines_to_go);
2831Range NormalViMode::motionToLastLineOfWindow()
2834 if (linesDisplayed() <= (
unsigned int)m_viewInternal->endLine()) {
2835 lines_to_go = m_viewInternal->endLine() - m_view->cursorPosition().line();
2837 lines_to_go = m_viewInternal->endLine() - m_view->cursorPosition().line();
2840 Range r = goLineUpDown(lines_to_go);
2845Range NormalViMode::motionToNextVisualLine()
2847 return goVisualLineUpDown(getCount());
2850Range NormalViMode::motionToPrevVisualLine()
2852 return goVisualLineUpDown(-getCount());
2855Range NormalViMode::motionToPreviousSentence()
2857 KTextEditor::Cursor c = findSentenceStart();
2858 int linenum = c.
line();
2860 const bool skipSpaces = doc()->line(linenum).isEmpty();
2865 column = doc()->line(linenum).size() - 1;
2869 for (
int i = linenum; i >= 0; i--) {
2870 const QString &line = doc()->line(i);
2872 if (line.
isEmpty() && !skipSpaces) {
2873 return Range(i, 0, InclusiveMotion);
2876 if (column < 0 && !line.
isEmpty()) {
2877 column = line.
size() - 1;
2880 for (
int j = column; j >= 0; j--) {
2881 if (skipSpaces || QStringLiteral(
".?!").indexOf(line.
at(j)) != -1) {
2885 c = findSentenceStart();
2886 return Range(c, InclusiveMotion);
2889 column = line.
size() - 1;
2891 return Range(0, 0, InclusiveMotion);
2894Range NormalViMode::motionToNextSentence()
2896 KTextEditor::Cursor c = findSentenceEnd();
2897 int linenum = c.
line();
2898 int column = c.
column() + 1;
2899 const bool skipSpaces = doc()->line(linenum).isEmpty();
2901 for (
int i = linenum; i < doc()->lines(); i++) {
2902 const QString &line = doc()->line(i);
2904 if (line.
isEmpty() && !skipSpaces) {
2905 return Range(i, 0, InclusiveMotion);
2908 for (
int j = column; j < line.
size(); j++) {
2910 return Range(i, j, InclusiveMotion);
2916 c = doc()->documentEnd();
2917 return Range(c, InclusiveMotion);
2920Range NormalViMode::motionToBeforeParagraph()
2922 KTextEditor::Cursor c(m_view->cursorPosition());
2924 int line = c.
line();
2926 m_stickyColumn = -1;
2928 for (
int i = 0; i < getCount(); i++) {
2933 }
while (line >= 0 && getLine(line + 1).length() == 0);
2934 while (line > 0 && getLine(line).length() != 0) {
2943 Range r(line, 0, InclusiveMotion);
2948Range NormalViMode::motionToAfterParagraph()
2950 KTextEditor::Cursor c(m_view->cursorPosition());
2952 int line = c.
line();
2954 m_stickyColumn = -1;
2956 for (
int i = 0; i < getCount(); i++) {
2961 }
while (line <= doc()->lines() - 1 && getLine(line - 1).length() == 0);
2962 while (line < doc()->lines() - 1 && getLine(line).length() != 0) {
2967 if (line >= doc()->lines()) {
2968 line = doc()->lines() - 1;
2972 int column = (line == doc()->lines() - 1) ? qMax(getLine(line).length() - 1, 0) : 0;
2974 return Range(line, column, InclusiveMotion);
2977Range NormalViMode::motionToIncrementalSearchMatch()
2979 return Range(m_positionWhenIncrementalSearchBegan.line(),
2980 m_positionWhenIncrementalSearchBegan.column(),
2981 m_view->cursorPosition().line(),
2982 m_view->cursorPosition().column(),
2990Range NormalViMode::textObjectAWord()
2992 KTextEditor::Cursor c(m_view->cursorPosition());
2994 KTextEditor::Cursor c1 = c;
2996 bool startedOnSpace =
false;
2997 if (doc()->characterAt(c).isSpace()) {
2998 startedOnSpace =
true;
3000 c1 = findPrevWordStart(c.
line(), c.
column() + 1,
true);
3002 c1 = KTextEditor::Cursor(0, 0);
3005 KTextEditor::Cursor c2 = KTextEditor::Cursor(c.
line(), c.
column() - 1);
3006 for (
int i = 1; i <= getCount(); i++) {
3014 const KTextEditor::Cursor nextWordStart = findNextWordStart(c2.
line(), c2.
column());
3016 if (!startedOnSpace) {
3017 c2 = KTextEditor::Cursor(nextWordStart.
line(), nextWordStart.
column() - 1);
3020 c2 = KTextEditor::Cursor(c2.
line(), doc()->lineLength(c2.
line()) - 1);
3022 bool swallowCarriageReturnAtEndOfLine =
false;
3025 c2 = KTextEditor::Cursor(c2.
line() + 1, 0);
3026 swallowCarriageReturnAtEndOfLine =
true;
3028 const bool swallowPrecedingSpaces =
3029 (c2.
column() == doc()->lineLength(c2.
line()) - 1 && !doc()->characterAt(c2).isSpace()) || startedOnSpace || swallowCarriageReturnAtEndOfLine;
3030 if (swallowPrecedingSpaces) {
3032 const KTextEditor::Cursor previousNonSpace = findPrevWordEnd(c.
line(), c.
column());
3033 if (previousNonSpace.
isValid() && previousNonSpace.
line() == c1.
line()) {
3034 c1 = KTextEditor::Cursor(previousNonSpace.
line(), previousNonSpace.
column() + 1);
3035 }
else if (startedOnSpace || swallowCarriageReturnAtEndOfLine) {
3036 c1 = KTextEditor::Cursor(c1.
line(), 0);
3041 return Range(c1, c2, !swallowCarriageReturnAtEndOfLine ? InclusiveMotion : ExclusiveMotion);
3044Range NormalViMode::textObjectInnerWord()
3046 KTextEditor::Cursor c(m_view->cursorPosition());
3048 KTextEditor::Cursor c1 = findPrevWordStart(c.
line(), c.
column() + 1,
true);
3050 c1 = KTextEditor::Cursor(0, 0);
3053 KTextEditor::Cursor c2(c.
line(), c.
column() - 1);
3055 for (
int i = 0; i < getCount(); i++) {
3056 c2 = findWordEnd(c2.
line(), c2.
column(),
true);
3060 c2 = doc()->documentEnd();
3067 return Range(c1, c2, InclusiveMotion);
3070Range NormalViMode::textObjectAWORD()
3072 KTextEditor::Cursor c(m_view->cursorPosition());
3074 KTextEditor::Cursor c1 = c;
3076 bool startedOnSpace =
false;
3077 if (doc()->characterAt(c).isSpace()) {
3078 startedOnSpace =
true;
3080 c1 = findPrevWORDStart(c.
line(), c.
column() + 1,
true);
3082 c1 = KTextEditor::Cursor(0, 0);
3085 KTextEditor::Cursor c2 = KTextEditor::Cursor(c.
line(), c.
column() - 1);
3086 for (
int i = 1; i <= getCount(); i++) {
3094 const KTextEditor::Cursor nextWordStart = findNextWordStart(c2.
line(), c2.
column());
3096 if (!startedOnSpace) {
3097 c2 = KTextEditor::Cursor(nextWordStart.
line(), nextWordStart.
column() - 1);
3100 c2 = KTextEditor::Cursor(c2.
line(), doc()->lineLength(c2.
line()) - 1);
3102 bool swallowCarriageReturnAtEndOfLine =
false;
3105 c2 = KTextEditor::Cursor(c2.
line() + 1, 0);
3106 swallowCarriageReturnAtEndOfLine =
true;
3108 const bool swallowPrecedingSpaces =
3109 (c2.
column() == doc()->lineLength(c2.
line()) - 1 && !doc()->characterAt(c2).isSpace()) || startedOnSpace || swallowCarriageReturnAtEndOfLine;
3110 if (swallowPrecedingSpaces) {
3112 const KTextEditor::Cursor previousNonSpace = findPrevWORDEnd(c.
line(), c.
column());
3113 if (previousNonSpace.
isValid() && previousNonSpace.
line() == c1.
line()) {
3114 c1 = KTextEditor::Cursor(previousNonSpace.
line(), previousNonSpace.
column() + 1);
3115 }
else if (startedOnSpace || swallowCarriageReturnAtEndOfLine) {
3116 c1 = KTextEditor::Cursor(c1.
line(), 0);
3121 return Range(c1, c2, !swallowCarriageReturnAtEndOfLine ? InclusiveMotion : ExclusiveMotion);
3124Range NormalViMode::textObjectInnerWORD()
3126 KTextEditor::Cursor c(m_view->cursorPosition());
3128 KTextEditor::Cursor c1 = findPrevWORDStart(c.
line(), c.
column() + 1,
true);
3130 c1 = KTextEditor::Cursor(0, 0);
3132 KTextEditor::Cursor c2(c);
3134 for (
int i = 0; i < getCount(); i++) {
3135 c2 = findWORDEnd(c2.
line(), c2.
column(),
true);
3139 c2 = doc()->documentEnd();
3146 return Range(c1, c2, InclusiveMotion);
3149KTextEditor::Cursor NormalViMode::findSentenceStart()
3151 KTextEditor::Cursor c(m_view->cursorPosition());
3152 int linenum = c.
line();
3156 for (
int i = linenum; i >= 0; i--) {
3157 const QString &line = doc()->line(i);
3158 const int lineLength = line.
size();
3160 column = lineLength;
3165 return KTextEditor::Cursor((i != linenum) ? i + 1 : i, prev);
3169 for (
int j = column; j >= 0; j--) {
3170 if (j == lineLength || line.
at(j).
isSpace()) {
3171 int lastSpace = j--;
3172 for (; j >= 0 && QStringLiteral(
"\"')]").indexOf(line.
at(j)) != -1; j--) {
3176 if (j >= 0 && QStringLiteral(
".!?").indexOf(line.
at(j)) != -1) {
3177 if (lastSpace == lineLength) {
3179 return KTextEditor::Cursor(i + 1, 0);
3182 return KTextEditor::Cursor(i, prev);
3191 return KTextEditor::Cursor(0, 0);
3194KTextEditor::Cursor NormalViMode::findSentenceEnd()
3196 KTextEditor::Cursor c(m_view->cursorPosition());
3197 int linenum = c.
line();
3202 for (
int i = linenum; i < doc()->lines(); i++) {
3203 const QString &line = doc()->line(i);
3207 return KTextEditor::Cursor(linenum, j);
3211 for (j = column; j < line.
size(); j++) {
3212 if (QStringLiteral(
".!?").indexOf(line.
at(j)) != -1) {
3215 for (; j < line.
size() && QStringLiteral(
"\"')]").indexOf(line.
at(j)) != -1; j++) {
3219 if (j >= line.
size()) {
3220 return KTextEditor::Cursor(i, j - 1);
3225 return KTextEditor::Cursor(i, j - 1);
3235 return KTextEditor::Cursor(linenum, j - 1);
3238KTextEditor::Cursor NormalViMode::findParagraphStart()
3240 KTextEditor::Cursor c(m_view->cursorPosition());
3241 const bool firstBlank = doc()->line(c.
line()).isEmpty();
3242 int prev = c.
line();
3244 for (
int i = prev; i >= 0; i--) {
3245 if (doc()->line(i).isEmpty()) {
3253 for (; i >= 0 && doc()->line(i).isEmpty(); i--, prev--) {
3257 return KTextEditor::Cursor(prev, 0);
3260 return KTextEditor::Cursor(0, 0);
3263KTextEditor::Cursor NormalViMode::findParagraphEnd()
3265 KTextEditor::Cursor c(m_view->cursorPosition());
3266 int prev = c.
line();
3267 int lines = doc()->lines();
3268 const bool firstBlank = doc()->line(prev).isEmpty();
3270 for (
int i = prev; i < lines; i++) {
3271 if (doc()->line(i).isEmpty()) {
3279 for (; i < lines && doc()->line(i).isEmpty(); i++, prev++) {
3283 int length = doc()->lineLength(prev);
3284 return KTextEditor::Cursor(prev, (length <= 0) ? 0 : length - 1);
3287 return doc()->documentEnd();
3290Range NormalViMode::textObjectInnerSentence()
3293 KTextEditor::Cursor c1 = findSentenceStart();
3294 KTextEditor::Cursor c2 = findSentenceEnd();
3297 r.startLine = c1.
line();
3298 r.startColumn = c1.
column();
3299 r.endLine = c2.
line();
3300 r.endColumn = c2.
column();
3304Range NormalViMode::textObjectASentence()
3307 Range r = textObjectInnerSentence();
3308 const QString &line = doc()->line(r.endLine);
3311 for (i = r.endColumn + 1; i < line.
size(); i++) {
3316 r.endColumn = i - 1;
3319 if (r.startColumn != 0) {
3320 if (r.endColumn == line.
size() - 1 && !line.
at(r.endColumn).
isSpace()) {
3321 const QString &line = doc()->line(r.startLine);
3322 for (i = r.startColumn - 1; i >= 0; i--) {
3327 r.startColumn = i + 1;
3333Range NormalViMode::textObjectInnerParagraph()
3336 KTextEditor::Cursor c1 = findParagraphStart();
3337 KTextEditor::Cursor c2 = findParagraphEnd();
3340 r.startLine = c1.
line();
3341 r.startColumn = c1.
column();
3342 r.endLine = c2.
line();
3343 r.endColumn = c2.
column();
3347Range NormalViMode::textObjectAParagraph()
3349 Range r = textObjectInnerParagraph();
3350 int lines = doc()->lines();
3352 if (r.endLine + 1 < lines) {
3355 if (doc()->line(r.endLine + 1).
isEmpty()) {
3356 for (
int i = r.endLine + 1; i < lines && doc()->line(i).isEmpty(); i++) {
3361 KTextEditor::Cursor prev = m_view->cursorPosition();
3362 KTextEditor::Cursor c(r.endLine + 1, 0);
3364 c = findParagraphEnd();
3366 r.endLine = c.
line();
3367 r.endColumn = c.
column();
3369 }
else if (doc()->lineLength(r.startLine) > 0) {
3371 for (
int i = r.startLine - 1; i >= 0 && doc()->line(i).isEmpty(); i--) {
3375 updateCursor(KTextEditor::Cursor(r.startLine, r.startColumn));
3383Range NormalViMode::textObjectAQuoteDouble()
3385 return findSurroundingQuotes(QLatin1Char(
'"'),
false);
3388Range NormalViMode::textObjectInnerQuoteDouble()
3390 return findSurroundingQuotes(QLatin1Char(
'"'),
true);
3393Range NormalViMode::textObjectAQuoteSingle()
3395 return findSurroundingQuotes(QLatin1Char(
'\''),
false);
3398Range NormalViMode::textObjectInnerQuoteSingle()
3400 return findSurroundingQuotes(QLatin1Char(
'\''),
true);
3403Range NormalViMode::textObjectABackQuote()
3405 return findSurroundingQuotes(QLatin1Char(
'`'),
false);
3408Range NormalViMode::textObjectInnerBackQuote()
3410 return findSurroundingQuotes(QLatin1Char(
'`'),
true);
3413Range NormalViMode::textObjectAParen()
3415 return findSurroundingBrackets(QLatin1Char(
'('), QLatin1Char(
')'),
false, QLatin1Char(
'('), QLatin1Char(
')'));
3418Range NormalViMode::textObjectInnerParen()
3420 return findSurroundingBrackets(QLatin1Char(
'('), QLatin1Char(
')'),
true, QLatin1Char(
'('), QLatin1Char(
')'));
3423Range NormalViMode::textObjectABracket()
3425 return findSurroundingBrackets(QLatin1Char(
'['), QLatin1Char(
']'),
false, QLatin1Char(
'['), QLatin1Char(
']'));
3428Range NormalViMode::textObjectInnerBracket()
3430 return findSurroundingBrackets(QLatin1Char(
'['), QLatin1Char(
']'),
true, QLatin1Char(
'['), QLatin1Char(
']'));
3433Range NormalViMode::textObjectACurlyBracket()
3435 return findSurroundingBrackets(QLatin1Char(
'{'), QLatin1Char(
'}'),
false, QLatin1Char(
'{'), QLatin1Char(
'}'));
3438Range NormalViMode::textObjectInnerCurlyBracket()
3440 const Range allBetweenCurlyBrackets = findSurroundingBrackets(QLatin1Char(
'{'), QLatin1Char(
'}'),
true, QLatin1Char(
'{'), QLatin1Char(
'}'));
3443 Range innerCurlyBracket(allBetweenCurlyBrackets);
3445 if (innerCurlyBracket.startLine != innerCurlyBracket.endLine) {
3446 const bool openingBraceIsLastCharOnLine = innerCurlyBracket.startColumn == doc()->line(innerCurlyBracket.startLine).length();
3447 const bool stuffToDeleteIsAllOnEndLine = openingBraceIsLastCharOnLine && innerCurlyBracket.endLine == innerCurlyBracket.startLine + 1;
3448 const QString textLeadingClosingBracket = doc()->line(innerCurlyBracket.endLine).mid(0, innerCurlyBracket.endColumn + 1);
3449 const bool closingBracketHasLeadingNonWhitespace = !textLeadingClosingBracket.
trimmed().
isEmpty();
3450 if (stuffToDeleteIsAllOnEndLine) {
3451 if (!closingBracketHasLeadingNonWhitespace) {
3456 innerCurlyBracket.startLine++;
3457 innerCurlyBracket.startColumn = 0;
3460 if (openingBraceIsLastCharOnLine && !closingBracketHasLeadingNonWhitespace) {
3461 innerCurlyBracket.startLine++;
3462 innerCurlyBracket.startColumn = 0;
3463 m_lastMotionWasLinewiseInnerBlock =
true;
3468 if (!closingBracketHasLeadingNonWhitespace) {
3471 innerCurlyBracket.endLine--;
3472 innerCurlyBracket.endColumn = doc()->line(innerCurlyBracket.endLine).length();
3477 return innerCurlyBracket;
3480Range NormalViMode::textObjectAInequalitySign()
3482 return findSurroundingBrackets(QLatin1Char(
'<'), QLatin1Char(
'>'),
false, QLatin1Char(
'<'), QLatin1Char(
'>'));
3485Range NormalViMode::textObjectInnerInequalitySign()
3487 return findSurroundingBrackets(QLatin1Char(
'<'), QLatin1Char(
'>'),
true, QLatin1Char(
'<'), QLatin1Char(
'>'));
3490Range NormalViMode::textObjectAComma()
3492 return textObjectComma(
false);
3495Range NormalViMode::textObjectInnerComma()
3497 return textObjectComma(
true);
3500QRegularExpression NormalViMode::generateMatchingItemRegex()
const
3502 QString pattern(QStringLiteral(
"\\[|\\]|\\{|\\}|\\(|\\)|"));
3504 for (QString s : std::as_const(m_matchingItems)) {
3505 if (s.startsWith(QLatin1Char(
'-'))) {
3508 s.replace(QLatin1Char(
'*'), QStringLiteral(
"\\*"));
3509 s.replace(QLatin1Char(
'+'), QStringLiteral(
"\\+"));
3510 s.replace(QLatin1Char(
'['), QStringLiteral(
"\\["));
3511 s.replace(QLatin1Char(
']'), QStringLiteral(
"\\]"));
3512 s.replace(QLatin1Char(
'('), QStringLiteral(
"\\("));
3513 s.replace(QLatin1Char(
')'), QStringLiteral(
"\\)"));
3514 s.replace(QLatin1Char(
'{'), QStringLiteral(
"\\{"));
3515 s.replace(QLatin1Char(
'}'), QStringLiteral(
"\\}"));
3517 s.append(QLatin1Char(
'|'));
3531OperationMode NormalViMode::getOperationMode()
const
3533 OperationMode m = CharWise;
3535 if (m_viInputModeManager->getCurrentViMode() == ViMode::VisualBlockMode) {
3537 }
else if (m_viInputModeManager->getCurrentViMode() == ViMode::VisualLineMode
3538 || (m_commandRange.startLine != m_commandRange.endLine && m_viInputModeManager->getCurrentViMode() != ViMode::VisualMode)) {
3542 if (m_commandWithMotion && !m_linewiseCommand) {
3546 if (m_lastMotionWasLinewiseInnerBlock) {
3553bool NormalViMode::paste(PasteLocation pasteLocation,
bool isgPaste,
bool isIndentedPaste)
3555 KTextEditor::Cursor pasteAt(m_view->cursorPosition());
3556 KTextEditor::Cursor cursorAfterPaste = pasteAt;
3557 QChar reg = getChosenRegister(UnnamedRegister);
3559 OperationMode m = getRegisterFlag(reg);
3560 QString textToInsert = getRegisterContent(reg);
3561 const bool isTextMultiLine = textToInsert.
count(QLatin1Char(
'\n')) > 0;
3564 isgPaste |= m_viInputModeManager->getTemporaryNormalMode();
3567 error(
i18n(
"Nothing in register %1", reg.
toLower()));
3571 if (getCount() > 1) {
3572 textToInsert = textToInsert.
repeated(getCount());
3575 if (m == LineWise) {
3576 pasteAt.setColumn(0);
3577 if (isIndentedPaste) {
3580 static const QRegularExpression nonWhitespaceRegex(QStringLiteral(
"[^\\s]"));
3581 const QString pasteLineString = doc()->line(pasteAt.line());
3582 const QString leadingWhiteSpaceOnCurrentLine = pasteLineString.
mid(0, pasteLineString.
indexOf(nonWhitespaceRegex));
3583 const QString leadingWhiteSpaceOnFirstPastedLine = textToInsert.
mid(0, textToInsert.
indexOf(nonWhitespaceRegex));
3585 while (textToInsert[0].isSpace()) {
3586 textToInsert = textToInsert.
mid(1);
3588 textToInsert.
prepend(leadingWhiteSpaceOnCurrentLine);
3591 textToInsert.
chop(1);
3592 textToInsert.
replace(QLatin1Char(
'\n') + leadingWhiteSpaceOnFirstPastedLine, QLatin1Char(
'\n') + leadingWhiteSpaceOnCurrentLine);
3593 textToInsert.
append(QLatin1Char(
'\n'));
3595 if (pasteLocation == AfterCurrentPosition) {
3596 textToInsert.
chop(1);
3597 pasteAt.setColumn(doc()->lineLength(pasteAt.line()));
3598 textToInsert.
prepend(QLatin1Char(
'\n'));
3600 cursorAfterPaste.
setLine(cursorAfterPaste.
line() + 1);
3603 cursorAfterPaste.
setLine(cursorAfterPaste.
line() + textToInsert.
count(QLatin1Char(
'\n')));
3606 if (pasteLocation == AfterCurrentPosition) {
3609 if (getLine(pasteAt.line()).length() > 0) {
3610 pasteAt.setColumn(pasteAt.column() + 1);
3612 cursorAfterPaste = pasteAt;
3614 const bool leaveCursorAtStartOfPaste = isTextMultiLine && !isgPaste;
3615 if (!leaveCursorAtStartOfPaste) {
3616 cursorAfterPaste = cursorPosAtEndOfPaste(pasteAt, textToInsert);
3624 if (m_view->selection()) {
3625 pasteAt = m_view->selectionRange().start();
3626 doc()->removeText(m_view->selectionRange());
3628 doc()->insertText(pasteAt, textToInsert, m == Block);
3631 if (cursorAfterPaste.
line() >= doc()->lines()) {
3632 cursorAfterPaste.
setLine(doc()->lines() - 1);
3634 updateCursor(cursorAfterPaste);
3639KTextEditor::Cursor NormalViMode::cursorPosAtEndOfPaste(
const KTextEditor::Cursor pasteLocation,
const QString &pastedText)
3641 KTextEditor::Cursor cAfter = pasteLocation;
3642 const int lineCount = pastedText.
count(QLatin1Char(
'\n')) + 1;
3643 if (lineCount == 1) {
3646 const int lastLineLength = pastedText.
size() - (pastedText.
lastIndexOf(QLatin1Char(
'\n')) + 1);
3653void NormalViMode::joinLines(
unsigned int from,
unsigned int to)
const
3656 if (to >= (
unsigned int)(doc()->lines())) {
3657 to = doc()->lines() - 1;
3665 doc()->joinLines(from, to);
3668void NormalViMode::reformatLines(
unsigned int from,
unsigned int to)
const
3671 KTextEditor::DocumentPrivate *document = doc();
3672 auto isNonEmptyLine = [](QStringView text) {
3673 for (
int i = 0; i < text.
length(); ++i) {
3681 for (; from < to; ++from) {
3682 if (isNonEmptyLine(document->
line(from))) {
3686 for (; to > from; --to) {
3687 if (isNonEmptyLine(document->
line(to))) {
3693 joinLines(from, to);
3701 line = m_view->cursorPosition().line();
3707 return (c < 0) ? 0 : c;
3711void NormalViMode::shrinkRangeAroundCursor(Range &toShrink,
const Range &rangeToShrinkTo)
const
3713 if (!toShrink.valid || !rangeToShrinkTo.valid) {
3717 if (rangeToShrinkTo.startLine >= cursorPos.
line()) {
3718 if (rangeToShrinkTo.startLine > cursorPos.
line()) {
3722 Q_ASSERT(rangeToShrinkTo.startLine == cursorPos.
line());
3723 if (rangeToShrinkTo.startColumn > cursorPos.
column()) {
3728 if (rangeToShrinkTo.endLine <= cursorPos.
line()) {
3729 if (rangeToShrinkTo.endLine < cursorPos.
line()) {
3733 Q_ASSERT(rangeToShrinkTo.endLine == cursorPos.
line());
3734 if (rangeToShrinkTo.endColumn < cursorPos.
column()) {
3740 if (toShrink.startLine <= rangeToShrinkTo.startLine) {
3741 if (toShrink.startLine < rangeToShrinkTo.startLine) {
3742 toShrink.startLine = rangeToShrinkTo.startLine;
3743 toShrink.startColumn = rangeToShrinkTo.startColumn;
3745 Q_ASSERT(toShrink.startLine == rangeToShrinkTo.startLine);
3746 if (toShrink.startColumn < rangeToShrinkTo.startColumn) {
3747 toShrink.startColumn = rangeToShrinkTo.startColumn;
3750 if (toShrink.endLine >= rangeToShrinkTo.endLine) {
3751 if (toShrink.endLine > rangeToShrinkTo.endLine) {
3752 toShrink.endLine = rangeToShrinkTo.endLine;
3753 toShrink.endColumn = rangeToShrinkTo.endColumn;
3755 Q_ASSERT(toShrink.endLine == rangeToShrinkTo.endLine);
3756 if (toShrink.endColumn > rangeToShrinkTo.endColumn) {
3757 toShrink.endColumn = rangeToShrinkTo.endColumn;
3762Range NormalViMode::textObjectComma(
bool inner)
const
3767 Range r(0, 0, m_view->doc()->lines(), m_view->doc()->line(m_view->doc()->lastLine()).length(), InclusiveMotion);
3769 shrinkRangeAroundCursor(r, findSurroundingQuotes(QLatin1Char(
','), inner));
3770 shrinkRangeAroundCursor(r, findSurroundingBrackets(QLatin1Char(
'('), QLatin1Char(
')'), inner, QLatin1Char(
'('), QLatin1Char(
')')));
3771 shrinkRangeAroundCursor(r, findSurroundingBrackets(QLatin1Char(
'{'), QLatin1Char(
'}'), inner, QLatin1Char(
'{'), QLatin1Char(
'}')));
3772 shrinkRangeAroundCursor(r, findSurroundingBrackets(QLatin1Char(
','), QLatin1Char(
')'), inner, QLatin1Char(
'('), QLatin1Char(
')')));
3773 shrinkRangeAroundCursor(r, findSurroundingBrackets(QLatin1Char(
','), QLatin1Char(
']'), inner, QLatin1Char(
'['), QLatin1Char(
']')));
3774 shrinkRangeAroundCursor(r, findSurroundingBrackets(QLatin1Char(
','), QLatin1Char(
'}'), inner, QLatin1Char(
'{'), QLatin1Char(
'}')));
3775 shrinkRangeAroundCursor(r, findSurroundingBrackets(QLatin1Char(
'('), QLatin1Char(
','), inner, QLatin1Char(
'('), QLatin1Char(
')')));
3776 shrinkRangeAroundCursor(r, findSurroundingBrackets(QLatin1Char(
'['), QLatin1Char(
','), inner, QLatin1Char(
'['), QLatin1Char(
']')));
3777 shrinkRangeAroundCursor(r, findSurroundingBrackets(QLatin1Char(
'{'), QLatin1Char(
','), inner, QLatin1Char(
'{'), QLatin1Char(
'}')));
3781void NormalViMode::updateYankHighlightAttrib()
3783 if (!m_highlightYankAttribute) {
3784 m_highlightYankAttribute =
new KTextEditor::Attribute;
3786 const QColor &yankedColor = m_view->rendererConfig()->savedLineColor();
3787 m_highlightYankAttribute->setBackground(yankedColor);
3789 mouseInAttribute->setFontBold(
true);
3794void NormalViMode::highlightYank(
const Range &range,
const OperationMode mode)
3796 clearYankHighlight();
3800 if (mode == Block) {
3801 for (
int i = range.startLine; i <= range.endLine; i++) {
3802 addHighlightYank(KTextEditor::Range(i, range.startColumn, i, range.endColumn));
3805 addHighlightYank(KTextEditor::Range(range.startLine, range.startColumn, range.endLine, range.endColumn));
3809void NormalViMode::addHighlightYank(KTextEditor::Range yankRange)
3812 highlightedYank->
setView(m_view);
3816 highlightedYank->
setAttribute(m_highlightYankAttribute);
3818 highlightedYankForDocument().insert(highlightedYank);
3821void NormalViMode::clearYankHighlight()
3823 QSet<KTextEditor::MovingRange *> &pHighlightedYanks = highlightedYankForDocument();
3824 qDeleteAll(pHighlightedYanks);
3825 pHighlightedYanks.
clear();
3828QSet<KTextEditor::MovingRange *> &NormalViMode::highlightedYankForDocument()
3832 return m_viInputModeManager->getViNormalMode()->m_highlightedYanks;
3835bool NormalViMode::waitingForRegisterOrCharToSearch()
3840 const int keysSize = m_keys.size();
3847 QChar cPrefix = m_keys[0];
3848 if (keysSize == 2) {
3850 if (cPrefix != QLatin1Char(
'c') && cPrefix != QLatin1Char(
'd') && cPrefix != QLatin1Char(
'y') && cPrefix != QLatin1Char(
'=')
3851 && cPrefix != QLatin1Char(
'>') && cPrefix != QLatin1Char(
'<')) {
3854 }
else if (keysSize == 3) {
3856 QChar cNextfix = m_keys[1];
3857 if (cPrefix != QLatin1Char(
'g')
3858 || (cNextfix != QLatin1Char(
'U') && cNextfix != QLatin1Char(
'u') && cNextfix != QLatin1Char(
'~') && cNextfix != QLatin1Char(
'q')
3859 && cNextfix != QLatin1Char(
'w') && cNextfix != QLatin1Char(
'@'))) {
3867 QChar ch = m_keys[keysSize - 1];
3868 return (ch == QLatin1Char(
'f') || ch == QLatin1Char(
't') || ch == QLatin1Char(
'F')
3869 || ch == QLatin1Char(
'T')
3871 || (keysSize == 1 && (ch == QLatin1Char(
'r') || ch == QLatin1Char(
'q') || ch == QLatin1Char(
'@'))));
3874void NormalViMode::textInserted(KTextEditor::Document *document, KTextEditor::Range range)
3881 const bool isInsertReplaceMode =
3882 (m_viInputModeManager->getCurrentViMode() == ViMode::InsertMode || m_viInputModeManager->getCurrentViMode() == ViMode::ReplaceMode);
3883 const bool continuesInsertion = range.
start().
line() == m_currentChangeEndMarker.line() && range.
start().
column() == m_currentChangeEndMarker.column();
3884 const bool beginsWithNewline = doc()->text(range).at(0) == QLatin1Char(
'\n');
3885 if (!continuesInsertion) {
3886 KTextEditor::Cursor newBeginMarkerPos = range.
start();
3887 if (beginsWithNewline && !isInsertReplaceMode) {
3889 newBeginMarkerPos = KTextEditor::Cursor(newBeginMarkerPos.
line() + 1, 0);
3891 m_viInputModeManager->marks()->setStartEditYanked(newBeginMarkerPos);
3893 m_viInputModeManager->marks()->setLastChange(range.
start());
3894 KTextEditor::Cursor editEndMarker = range.
end();
3895 if (!isInsertReplaceMode) {
3898 m_viInputModeManager->marks()->setFinishEditYanked(editEndMarker);
3899 m_currentChangeEndMarker = range.
end();
3902 m_viInputModeManager->marks()->setStartEditYanked(KTextEditor::Cursor(m_viInputModeManager->marks()->getStartEditYanked().line(), 0));
3903 if (addsMultipleLines) {
3904 m_viInputModeManager->marks()->setFinishEditYanked(KTextEditor::Cursor(m_viInputModeManager->marks()->getFinishEditYanked().line() + 1, 0));
3905 m_viInputModeManager->marks()->setLastChange(KTextEditor::Cursor(m_viInputModeManager->marks()->getLastChange().line() + 1, 0));
3907 m_viInputModeManager->marks()->setFinishEditYanked(KTextEditor::Cursor(m_viInputModeManager->marks()->getFinishEditYanked().line(), 0));
3908 m_viInputModeManager->marks()->setLastChange(KTextEditor::Cursor(m_viInputModeManager->marks()->getLastChange().line(), 0));
3913void NormalViMode::textRemoved(KTextEditor::Document *document, KTextEditor::Range range)
3920 const bool isInsertReplaceMode =
3921 (m_viInputModeManager->getCurrentViMode() == ViMode::InsertMode || m_viInputModeManager->getCurrentViMode() == ViMode::ReplaceMode);
3922 m_viInputModeManager->marks()->setLastChange(range.
start());
3923 if (!isInsertReplaceMode) {
3925 m_viInputModeManager->marks()->setStartEditYanked(range.
start());
3928 m_currentChangeEndMarker = range.
start();
3930 m_viInputModeManager->marks()->setFinishEditYanked(range.
start());
3935 const int markerLineAdjustment = (range.
start().line() != range.
end().
line()) ? 1 : 0;
3936 m_viInputModeManager->marks()->setStartEditYanked(
3937 KTextEditor::Cursor(m_viInputModeManager->marks()->getStartEditYanked().line() + markerLineAdjustment, 0));
3938 m_viInputModeManager->marks()->setFinishEditYanked(
3939 KTextEditor::Cursor(m_viInputModeManager->marks()->getFinishEditYanked().line() + markerLineAdjustment, 0));
3940 m_viInputModeManager->marks()->setLastChange(KTextEditor::Cursor(m_viInputModeManager->marks()->getLastChange().line() + markerLineAdjustment, 0));
3944void NormalViMode::undoBeginning()
3949void NormalViMode::undoEnded()
3954bool NormalViMode::executeKateCommand(
const QString &command)
3956 KTextEditor::Command *p = KateCmd::self()->queryCommand(command);
3963 return p->
exec(m_view, command, msg);
3966#define ADDCMD(STR, FUNC, FLGS) Command(QStringLiteral(STR), &NormalViMode::FUNC, FLGS)
3968#define ADDMOTION(STR, FUNC, FLGS) Motion(QStringLiteral(STR), &NormalViMode::FUNC, FLGS)
3973 static const std::vector<Command> global{
3978 ADDCMD(
"I", commandEnterInsertModeBeforeFirstNonBlankInLine, IS_CHANGE),
3980 ADDCMD(
"v", commandEnterVisualMode, 0),
3981 ADDCMD(
"V", commandEnterVisualLineMode, 0),
3982 ADDCMD(
"<c-v>", commandEnterVisualBlockMode, 0),
3983 ADDCMD(
"gv", commandReselectVisual, SHOULD_NOT_RESET),
3984 ADDCMD(
"o", commandOpenNewLineUnder, IS_CHANGE),
3985 ADDCMD(
"O", commandOpenNewLineOver, IS_CHANGE),
3986 ADDCMD(
"J", commandJoinLines, IS_CHANGE),
3987 ADDCMD(
"c", commandChange, IS_CHANGE | NEEDS_MOTION),
3988 ADDCMD(
"C", commandChangeToEOL, IS_CHANGE),
3989 ADDCMD(
"cc", commandChangeLine, IS_CHANGE),
3990 ADDCMD(
"s", commandSubstituteChar, IS_CHANGE),
3991 ADDCMD(
"S", commandSubstituteLine, IS_CHANGE),
3992 ADDCMD(
"dd", commandDeleteLine, IS_CHANGE),
3993 ADDCMD(
"d", commandDelete, IS_CHANGE | NEEDS_MOTION),
3994 ADDCMD(
"D", commandDeleteToEOL, IS_CHANGE),
3995 ADDCMD(
"x", commandDeleteChar, IS_CHANGE),
3996 ADDCMD(
"<delete>", commandDeleteChar, IS_CHANGE),
3997 ADDCMD(
"X", commandDeleteCharBackward, IS_CHANGE),
3998 ADDCMD(
"gu", commandMakeLowercase, IS_CHANGE | NEEDS_MOTION),
3999 ADDCMD(
"guu", commandMakeLowercaseLine, IS_CHANGE),
4000 ADDCMD(
"gU", commandMakeUppercase, IS_CHANGE | NEEDS_MOTION),
4001 ADDCMD(
"gUU", commandMakeUppercaseLine, IS_CHANGE),
4002 ADDCMD(
"y", commandYank, NEEDS_MOTION),
4003 ADDCMD(
"yy", commandYankLine, 0),
4004 ADDCMD(
"Y", commandYankToEOL, 0),
4005 ADDCMD(
"p", commandPaste, IS_CHANGE),
4006 ADDCMD(
"P", commandPasteBefore, IS_CHANGE),
4007 ADDCMD(
"gp", commandgPaste, IS_CHANGE),
4008 ADDCMD(
"gP", commandgPasteBefore, IS_CHANGE),
4009 ADDCMD(
"]p", commandIndentedPaste, IS_CHANGE),
4010 ADDCMD(
"[p", commandIndentedPasteBefore, IS_CHANGE),
4011 ADDCMD(
"r.", commandReplaceCharacter, IS_CHANGE | REGEX_PATTERN),
4012 ADDCMD(
"R", commandEnterReplaceMode, IS_CHANGE),
4013 ADDCMD(
":", commandSwitchToCmdLine, 0),
4014 ADDCMD(
"u", commandUndo, 0),
4015 ADDCMD(
"<c-r>", commandRedo, 0),
4016 ADDCMD(
"U", commandRedo, 0),
4017 ADDCMD(
"m.", commandSetMark, REGEX_PATTERN),
4018 ADDCMD(
">>", commandIndentLine, IS_CHANGE),
4019 ADDCMD(
"<<", commandUnindentLine, IS_CHANGE),
4020 ADDCMD(
">", commandIndentLines, IS_CHANGE | NEEDS_MOTION),
4021 ADDCMD(
"<", commandUnindentLines, IS_CHANGE | NEEDS_MOTION),
4022 ADDCMD(
"<c-f>", commandScrollPageDown, 0),
4023 ADDCMD(
"<pagedown>", commandScrollPageDown, 0),
4024 ADDCMD(
"<c-b>", commandScrollPageUp, 0),
4025 ADDCMD(
"<pageup>", commandScrollPageUp, 0),
4026 ADDCMD(
"<c-u>", commandScrollHalfPageUp, 0),
4027 ADDCMD(
"<c-d>", commandScrollHalfPageDown, 0),
4028 ADDCMD(
"z.", commandCenterViewOnNonBlank, 0),
4029 ADDCMD(
"zz", commandCenterViewOnCursor, 0),
4030 ADDCMD(
"z<return>", commandTopViewOnNonBlank, 0),
4031 ADDCMD(
"zt", commandTopViewOnCursor, 0),
4032 ADDCMD(
"z-", commandBottomViewOnNonBlank, 0),
4033 ADDCMD(
"zb", commandBottomViewOnCursor, 0),
4034 ADDCMD(
"ga", commandPrintCharacterCode, SHOULD_NOT_RESET),
4035 ADDCMD(
".", commandRepeatLastChange, 0),
4036 ADDCMD(
"==", commandAlignLine, IS_CHANGE),
4037 ADDCMD(
"=", commandAlignLines, IS_CHANGE | NEEDS_MOTION),
4038 ADDCMD(
"~", commandChangeCase, IS_CHANGE),
4039 ADDCMD(
"g~", commandChangeCaseRange, IS_CHANGE | NEEDS_MOTION),
4040 ADDCMD(
"g~~", commandChangeCaseLine, IS_CHANGE),
4041 ADDCMD(
"<c-a>", commandAddToNumber, IS_CHANGE),
4042 ADDCMD(
"<c-x>", commandSubtractFromNumber, IS_CHANGE),
4043 ADDCMD(
"<c-o>", commandGoToPrevJump, CAN_LAND_INSIDE_FOLDING_RANGE),
4044 ADDCMD(
"<c-i>", commandGoToNextJump, CAN_LAND_INSIDE_FOLDING_RANGE),
4046 ADDCMD(
"<c-w>h", commandSwitchToLeftView, 0),
4047 ADDCMD(
"<c-w><c-h>", commandSwitchToLeftView, 0),
4048 ADDCMD(
"<c-w><left>", commandSwitchToLeftView, 0),
4049 ADDCMD(
"<c-w>j", commandSwitchToDownView, 0),
4050 ADDCMD(
"<c-w><c-j>", commandSwitchToDownView, 0),
4051 ADDCMD(
"<c-w><down>", commandSwitchToDownView, 0),
4052 ADDCMD(
"<c-w>k", commandSwitchToUpView, 0),
4053 ADDCMD(
"<c-w><c-k>", commandSwitchToUpView, 0),
4054 ADDCMD(
"<c-w><up>", commandSwitchToUpView, 0),
4055 ADDCMD(
"<c-w>l", commandSwitchToRightView, 0),
4056 ADDCMD(
"<c-w><c-l>", commandSwitchToRightView, 0),
4057 ADDCMD(
"<c-w><right>", commandSwitchToRightView, 0),
4058 ADDCMD(
"<c-w>w", commandSwitchToNextView, 0),
4059 ADDCMD(
"<c-w><c-w>", commandSwitchToNextView, 0),
4061 ADDCMD(
"<c-w>s", commandSplitHoriz, 0),
4062 ADDCMD(
"<c-w>S", commandSplitHoriz, 0),
4063 ADDCMD(
"<c-w><c-s>", commandSplitHoriz, 0),
4064 ADDCMD(
"<c-w>v", commandSplitVert, 0),
4065 ADDCMD(
"<c-w><c-v>", commandSplitVert, 0),
4066 ADDCMD(
"<c-w>c", commandCloseView, 0),
4068 ADDCMD(
"gt", commandSwitchToNextTab, 0),
4069 ADDCMD(
"gT", commandSwitchToPrevTab, 0),
4071 ADDCMD(
"gqq", commandFormatLine, IS_CHANGE),
4072 ADDCMD(
"gq", commandFormatLines, IS_CHANGE | NEEDS_MOTION),
4074 ADDCMD(
"zo", commandExpandLocal, 0),
4075 ADDCMD(
"zc", commandCollapseLocal, 0),
4076 ADDCMD(
"za", commandToggleRegionVisibility, 0),
4077 ADDCMD(
"zr", commandExpandAll, 0),
4078 ADDCMD(
"zm", commandCollapseToplevelNodes, 0),
4080 ADDCMD(
"q.", commandStartRecordingMacro, REGEX_PATTERN),
4081 ADDCMD(
"@.", commandReplayMacro, REGEX_PATTERN),
4083 ADDCMD(
"ZZ", commandCloseWrite, 0),
4084 ADDCMD(
"ZQ", commandCloseNocheck, 0),
4092 static const std::vector<Motion> global{
4094 ADDMOTION(
"h", motionLeft, 0),
4095 ADDMOTION(
"<left>", motionLeft, 0),
4096 ADDMOTION(
"<backspace>", motionLeft, 0),
4097 ADDMOTION(
"j", motionDown, 0),
4098 ADDMOTION(
"<down>", motionDown, 0),
4099 ADDMOTION(
"<enter>", motionDownToFirstNonBlank, 0),
4100 ADDMOTION(
"<return>", motionDownToFirstNonBlank, 0),
4101 ADDMOTION(
"k", motionUp, 0),
4102 ADDMOTION(
"<up>", motionUp, 0),
4103 ADDMOTION(
"-", motionUpToFirstNonBlank, 0),
4104 ADDMOTION(
"+", motionDownToFirstNonBlank, 0),
4105 ADDMOTION(
"l", motionRight, 0),
4106 ADDMOTION(
"<right>", motionRight, 0),
4107 ADDMOTION(
" ", motionRight, 0),
4108 ADDMOTION(
"$", motionToEOL, 0),
4109 ADDMOTION(
"g_", motionToLastNonBlank, 0),
4110 ADDMOTION(
"<end>", motionToEOL, 0),
4111 ADDMOTION(
"0", motionToColumn0, 0),
4112 ADDMOTION(
"<home>", motionToColumn0, 0),
4113 ADDMOTION(
"^", motionToFirstCharacterOfLine, 0),
4114 ADDMOTION(
"f.", motionFindChar, REGEX_PATTERN | CAN_LAND_INSIDE_FOLDING_RANGE),
4115 ADDMOTION(
"F.", motionFindCharBackward, REGEX_PATTERN | CAN_LAND_INSIDE_FOLDING_RANGE),
4116 ADDMOTION(
"t.", motionToChar, REGEX_PATTERN | CAN_LAND_INSIDE_FOLDING_RANGE),
4117 ADDMOTION(
"T.", motionToCharBackward, REGEX_PATTERN | CAN_LAND_INSIDE_FOLDING_RANGE),
4118 ADDMOTION(
";", motionRepeatlastTF, CAN_LAND_INSIDE_FOLDING_RANGE),
4119 ADDMOTION(
",", motionRepeatlastTFBackward, CAN_LAND_INSIDE_FOLDING_RANGE),
4120 ADDMOTION(
"n", motionFindNext, CAN_LAND_INSIDE_FOLDING_RANGE),
4121 ADDMOTION(
"N", motionFindPrev, CAN_LAND_INSIDE_FOLDING_RANGE),
4122 ADDMOTION(
"gg", motionToLineFirst, 0),
4123 ADDMOTION(
"G", motionToLineLast, 0),
4124 ADDMOTION(
"w", motionWordForward, IS_NOT_LINEWISE | CAN_LAND_INSIDE_FOLDING_RANGE),
4125 ADDMOTION(
"W", motionWORDForward, IS_NOT_LINEWISE | CAN_LAND_INSIDE_FOLDING_RANGE),
4126 ADDMOTION(
"<c-right>", motionWordForward, IS_NOT_LINEWISE | CAN_LAND_INSIDE_FOLDING_RANGE),
4127 ADDMOTION(
"<c-left>", motionWordBackward, IS_NOT_LINEWISE | CAN_LAND_INSIDE_FOLDING_RANGE),
4128 ADDMOTION(
"b", motionWordBackward, CAN_LAND_INSIDE_FOLDING_RANGE),
4129 ADDMOTION(
"B", motionWORDBackward, CAN_LAND_INSIDE_FOLDING_RANGE),
4130 ADDMOTION(
"e", motionToEndOfWord, CAN_LAND_INSIDE_FOLDING_RANGE),
4131 ADDMOTION(
"E", motionToEndOfWORD, CAN_LAND_INSIDE_FOLDING_RANGE),
4132 ADDMOTION(
"ge", motionToEndOfPrevWord, CAN_LAND_INSIDE_FOLDING_RANGE),
4133 ADDMOTION(
"gE", motionToEndOfPrevWORD, CAN_LAND_INSIDE_FOLDING_RANGE),
4134 ADDMOTION(
"|", motionToScreenColumn, 0),
4135 ADDMOTION(
"%", motionToMatchingItem, IS_NOT_LINEWISE | CAN_LAND_INSIDE_FOLDING_RANGE),
4136 ADDMOTION(
"`[a-zA-Z^><\\.\\[\\]]", motionToMark, REGEX_PATTERN | CAN_LAND_INSIDE_FOLDING_RANGE),
4137 ADDMOTION(
"'[a-zA-Z^><]", motionToMarkLine, REGEX_PATTERN | CAN_LAND_INSIDE_FOLDING_RANGE),
4138 ADDMOTION(
"[[", motionToPreviousBraceBlockStart, IS_NOT_LINEWISE | CAN_LAND_INSIDE_FOLDING_RANGE),
4139 ADDMOTION(
"]]", motionToNextBraceBlockStart, IS_NOT_LINEWISE | CAN_LAND_INSIDE_FOLDING_RANGE),
4140 ADDMOTION(
"[]", motionToPreviousBraceBlockEnd, IS_NOT_LINEWISE | CAN_LAND_INSIDE_FOLDING_RANGE),
4141 ADDMOTION(
"][", motionToNextBraceBlockEnd, IS_NOT_LINEWISE | CAN_LAND_INSIDE_FOLDING_RANGE),
4142 ADDMOTION(
"*", motionToNextOccurrence, CAN_LAND_INSIDE_FOLDING_RANGE),
4143 ADDMOTION(
"#", motionToPrevOccurrence, CAN_LAND_INSIDE_FOLDING_RANGE),
4144 ADDMOTION(
"H", motionToFirstLineOfWindow, 0),
4145 ADDMOTION(
"M", motionToMiddleLineOfWindow, 0),
4146 ADDMOTION(
"L", motionToLastLineOfWindow, 0),
4147 ADDMOTION(
"gj", motionToNextVisualLine, 0),
4148 ADDMOTION(
"g<down>", motionToNextVisualLine, 0),
4149 ADDMOTION(
"gk", motionToPrevVisualLine, 0),
4150 ADDMOTION(
"g<up>", motionToPrevVisualLine, 0),
4151 ADDMOTION(
"(", motionToPreviousSentence, CAN_LAND_INSIDE_FOLDING_RANGE),
4152 ADDMOTION(
")", motionToNextSentence, CAN_LAND_INSIDE_FOLDING_RANGE),
4153 ADDMOTION(
"{", motionToBeforeParagraph, CAN_LAND_INSIDE_FOLDING_RANGE),
4154 ADDMOTION(
"}", motionToAfterParagraph, CAN_LAND_INSIDE_FOLDING_RANGE),
4157 ADDMOTION(
"iw", textObjectInnerWord, 0),
4158 ADDMOTION(
"aw", textObjectAWord, IS_NOT_LINEWISE),
4159 ADDMOTION(
"iW", textObjectInnerWORD, 0),
4160 ADDMOTION(
"aW", textObjectAWORD, IS_NOT_LINEWISE),
4161 ADDMOTION(
"is", textObjectInnerSentence, IS_NOT_LINEWISE | CAN_LAND_INSIDE_FOLDING_RANGE),
4162 ADDMOTION(
"as", textObjectASentence, IS_NOT_LINEWISE | CAN_LAND_INSIDE_FOLDING_RANGE),
4163 ADDMOTION(
"ip", textObjectInnerParagraph, IS_NOT_LINEWISE | CAN_LAND_INSIDE_FOLDING_RANGE),
4164 ADDMOTION(
"ap", textObjectAParagraph, IS_NOT_LINEWISE | CAN_LAND_INSIDE_FOLDING_RANGE),
4165 ADDMOTION(
"i\"", textObjectInnerQuoteDouble, IS_NOT_LINEWISE | CAN_LAND_INSIDE_FOLDING_RANGE),
4166 ADDMOTION(
"a\"", textObjectAQuoteDouble, IS_NOT_LINEWISE | CAN_LAND_INSIDE_FOLDING_RANGE),
4167 ADDMOTION(
"i'", textObjectInnerQuoteSingle, IS_NOT_LINEWISE | CAN_LAND_INSIDE_FOLDING_RANGE),
4168 ADDMOTION(
"a'", textObjectAQuoteSingle, IS_NOT_LINEWISE | CAN_LAND_INSIDE_FOLDING_RANGE),
4169 ADDMOTION(
"i`", textObjectInnerBackQuote, IS_NOT_LINEWISE | CAN_LAND_INSIDE_FOLDING_RANGE),
4170 ADDMOTION(
"a`", textObjectABackQuote, IS_NOT_LINEWISE | CAN_LAND_INSIDE_FOLDING_RANGE),
4171 ADDMOTION(
"i[()b]", textObjectInnerParen, REGEX_PATTERN | IS_NOT_LINEWISE | CAN_LAND_INSIDE_FOLDING_RANGE),
4172 ADDMOTION(
"a[()b]", textObjectAParen, REGEX_PATTERN | IS_NOT_LINEWISE | CAN_LAND_INSIDE_FOLDING_RANGE),
4173 ADDMOTION(
"i[{}B]", textObjectInnerCurlyBracket, REGEX_PATTERN | IS_NOT_LINEWISE | CAN_LAND_INSIDE_FOLDING_RANGE),
4174 ADDMOTION(
"a[{}B]", textObjectACurlyBracket, REGEX_PATTERN | IS_NOT_LINEWISE | CAN_LAND_INSIDE_FOLDING_RANGE),
4175 ADDMOTION(
"i[><]", textObjectInnerInequalitySign, REGEX_PATTERN | IS_NOT_LINEWISE | CAN_LAND_INSIDE_FOLDING_RANGE),
4176 ADDMOTION(
"a[><]", textObjectAInequalitySign, REGEX_PATTERN | IS_NOT_LINEWISE | CAN_LAND_INSIDE_FOLDING_RANGE),
4177 ADDMOTION(
"i[\\[\\]]", textObjectInnerBracket, REGEX_PATTERN | IS_NOT_LINEWISE | CAN_LAND_INSIDE_FOLDING_RANGE),
4178 ADDMOTION(
"a[\\[\\]]", textObjectABracket, REGEX_PATTERN | IS_NOT_LINEWISE | CAN_LAND_INSIDE_FOLDING_RANGE),
4179 ADDMOTION(
"i,", textObjectInnerComma, IS_NOT_LINEWISE | CAN_LAND_INSIDE_FOLDING_RANGE),
4180 ADDMOTION(
"a,", textObjectAComma, IS_NOT_LINEWISE | CAN_LAND_INSIDE_FOLDING_RANGE),
4182 ADDMOTION(
"/<enter>", motionToIncrementalSearchMatch, IS_NOT_LINEWISE | CAN_LAND_INSIDE_FOLDING_RANGE),
4183 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)
QAction * end(const QObject *recvr, const char *slot, QObject *parent)
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)