10#include "kateconfig.h"
11#include "katedocument.h"
12#include "kateglobal.h"
13#include "katelayoutcache.h"
14#include "kateviinputmode.h"
15#include "ktexteditor/message.h"
16#include <vimode/globalstate.h>
17#include <vimode/inputmodemanager.h>
18#include <vimode/jumps.h>
19#include <vimode/lastchangerecorder.h>
20#include <vimode/marks.h>
21#include <vimode/modes/modebase.h>
22#include <vimode/modes/normalvimode.h>
23#include <vimode/modes/replacevimode.h>
24#include <vimode/modes/visualvimode.h>
25#include <vimode/registers.h>
26#include <vimode/searcher.h>
28#include <KLocalizedString>
29#include <QRegularExpression>
32using namespace KateVi;
44void ModeBase::yankToClipBoard(
QChar chosen_register,
const QString &text)
48 if ((chosen_register == QLatin1Char(
'0') || chosen_register == QLatin1Char(
'-') || chosen_register == PrependNumberedRegister) && text.
length() > 1
54bool ModeBase::deleteRange(Range &r, OperationMode mode,
bool addToRegister)
58 const QString removedText = getRange(r, mode);
60 if (mode == LineWise) {
62 for (
int i = 0; i < r.endLine - r.startLine + 1; i++) {
63 res = doc()->removeLine(r.startLine);
67 res = doc()->removeText(r.toEditorRange(), mode == Block);
72 QChar chosenRegister = getChosenRegister(UnnamedRegister);
74 fillRegister(chosenRegister, removedText, mode);
77 const QChar lastChar = removedText.
size() > 0 ? removedText.
back() : QLatin1Char(
'\0');
78 if (chosenRegister != BlackHoleRegister && (r.startLine != r.endLine || lastChar == QLatin1Char(
'\n') || lastChar == QLatin1Char(
'\r'))) {
80 fillRegister(PrependNumberedRegister, removedText, mode);
81 chosenRegister = PrependNumberedRegister;
82 }
else if (chosenRegister == UnnamedRegister) {
84 fillRegister(SmallDeleteRegister, removedText, mode);
85 chosenRegister = SmallDeleteRegister;
87 yankToClipBoard(chosenRegister, removedText);
92const QString ModeBase::getRange(Range &r, OperationMode mode)
const
97 if (mode == LineWise) {
99 r.endColumn = getLine(r.endLine).length();
102 if (r.motionType == InclusiveMotion) {
106 KTextEditor::Range range = r.toEditorRange();
107 if (mode == LineWise) {
108 s = doc()->textLines(range).join(QLatin1Char(
'\n'));
109 s.
append(QLatin1Char(
'\n'));
110 }
else if (mode == Block) {
111 s = doc()->text(range,
true);
113 s = doc()->text(range);
119const QString ModeBase::getLine(
int line)
const
121 return (line < 0) ? m_view->doc()->line(m_view->cursorPosition().line()) : doc()->line(line);
124const QChar ModeBase::getCharUnderCursor()
const
126 KTextEditor::Cursor c(m_view->cursorPosition());
128 QString line = getLine(c.line());
130 if (line.
length() == 0 && c.column() >= line.
length()) {
134 return line.
at(c.column());
137const QString ModeBase::getWordUnderCursor()
const
139 return doc()->text(getWordRangeUnderCursor());
142const KTextEditor::Range ModeBase::getWordRangeUnderCursor()
const
144 KTextEditor::Cursor c(m_view->cursorPosition());
147 QChar ch = doc()->characterAt(c);
149 while (!ch.
isLetterOrNumber() && !ch.
isMark() && ch != QLatin1Char(
'_') && m_extraWordCharacters.indexOf(ch) == -1) {
151 c.setColumn(c.column() + 1);
152 if (c.column() > doc()->lineLength(c.line())) {
154 c.setLine(c.line() + 1);
155 if (c.line() == doc()->lines()) {
160 ch = doc()->characterAt(c);
168 KTextEditor::Cursor c1 = findPrevWordStart(c.line(), c.column() + 1 + i,
true);
169 KTextEditor::Cursor c2 = findWordEnd(c1.
line(), c1.
column() + i - 1,
true);
172 return KTextEditor::Range(c1, c2);
175KTextEditor::Cursor ModeBase::findNextWordStart(
int fromLine,
int fromColumn,
bool onlyCurrentLine)
const
177 QString line = getLine(fromLine);
180 QString startOfWordPattern = QStringLiteral(
"\\b(\\w");
181 if (m_extraWordCharacters.length() > 0) {
182 startOfWordPattern.
append(QLatin1String(
"|[") + m_extraWordCharacters + QLatin1Char(
']'));
184 startOfWordPattern.
append(QLatin1Char(
')'));
188 static const QRegularExpression nonWordAfterWord(
189 QStringLiteral(
"\\b(?!\\s)\\W"),
198 int c1 = line.
indexOf(startOfWord, c + 1);
199 int c2 = line.
indexOf(nonSpaceAfterSpace, c);
200 int c3 = line.
indexOf(nonWordAfterWord, c + 1);
202 if (c1 == -1 && c2 == -1 && c3 == -1) {
203 if (onlyCurrentLine) {
205 }
else if (l >= doc()->lines() - 1) {
206 c = qMax(line.
length() - 1, 0);
234 c = qMin(c1, qMin(c2, c3));
239 return KTextEditor::Cursor(l, c);
242KTextEditor::Cursor ModeBase::findNextWORDStart(
int fromLine,
int fromColumn,
bool onlyCurrentLine)
const
244 QString line = getLine();
253 c = line.
indexOf(startOfWORD, c);
256 if (onlyCurrentLine) {
257 return KTextEditor::Cursor(l, c);
258 }
else if (l >= doc()->lines() - 1) {
279 return KTextEditor::Cursor(l, c);
282KTextEditor::Cursor ModeBase::findPrevWordEnd(
int fromLine,
int fromColumn,
bool onlyCurrentLine)
const
284 QString line = getLine(fromLine);
286 QString endOfWordPattern = QStringLiteral(
"\\S\\s|\\S$|\\S\\b|\\w\\W|^$");
288 if (m_extraWordCharacters.length() > 0) {
289 endOfWordPattern.
append(QLatin1String(
"|[") + m_extraWordCharacters + QLatin1String(
"][^") + m_extraWordCharacters + QLatin1Char(
']'));
302 if (c1 != -1 && c - 1 != -1) {
306 if (onlyCurrentLine) {
319 return KTextEditor::Cursor(l, c);
322KTextEditor::Cursor ModeBase::findPrevWORDEnd(
int fromLine,
int fromColumn,
bool onlyCurrentLine)
const
324 QString line = getLine(fromLine);
334 int c1 = line.
lastIndexOf(endOfWORDPattern, c - 1);
336 if (c1 != -1 && c - 1 != -1) {
340 if (onlyCurrentLine) {
354 return KTextEditor::Cursor(l, c);
357KTextEditor::Cursor ModeBase::findPrevWordStart(
int fromLine,
int fromColumn,
bool onlyCurrentLine)
const
359 QString line = getLine(fromLine);
362 QString startOfWordPattern = QStringLiteral(
"\\b(\\w");
363 if (m_extraWordCharacters.length() > 0) {
364 startOfWordPattern.
append(QLatin1String(
"|[") + m_extraWordCharacters + QLatin1Char(
']'));
366 startOfWordPattern.
append(QLatin1Char(
')'));
370 static const QRegularExpression nonWordAfterWord(
371 QStringLiteral(
"\\b(?!\\s)\\W"),
381 int c1 = (c > 0) ? line.
lastIndexOf(startOfWord, c - 1) : -1;
382 int c2 = (c > 1) ? line.
lastIndexOf(nonSpaceAfterSpace, c - 2) : -1;
383 int c3 = (c > 0) ? line.
lastIndexOf(nonWordAfterWord, c - 1) : -1;
384 int c4 = (c > 0) ? line.
lastIndexOf(startOfLine, c - 1) : -1;
386 if (c1 == -1 && c2 == -1 && c3 == -1 && c4 == -1) {
387 if (onlyCurrentLine) {
419 c = qMax(c1, qMax(c2, qMax(c3, c4)));
424 return KTextEditor::Cursor(l, c);
427KTextEditor::Cursor ModeBase::findPrevWORDStart(
int fromLine,
int fromColumn,
bool onlyCurrentLine)
const
429 QString line = getLine(fromLine);
440 int c1 = (c > 1) ? line.
lastIndexOf(startOfWORD, c - 2) : -1;
441 int c2 = (c > 0) ? line.
lastIndexOf(startOfLineWORD, c - 1) : -1;
443 if (c1 == -1 && c2 == -1) {
444 if (onlyCurrentLine) {
472 return KTextEditor::Cursor(l, c);
475KTextEditor::Cursor ModeBase::findWordEnd(
int fromLine,
int fromColumn,
bool onlyCurrentLine)
const
477 QString line = getLine(fromLine);
479 QString endOfWordPattern = QStringLiteral(
"\\S\\s|\\S$|\\w\\W|\\S\\b");
481 if (m_extraWordCharacters.length() > 0) {
482 endOfWordPattern.
append(QLatin1String(
"|[") + m_extraWordCharacters + QLatin1String(
"][^") + m_extraWordCharacters + QLatin1Char(
']'));
493 int c1 = line.
indexOf(endOfWORD, c + 1);
499 if (onlyCurrentLine) {
501 }
else if (l >= doc()->lines() - 1) {
513 return KTextEditor::Cursor(l, c);
516KTextEditor::Cursor ModeBase::findWORDEnd(
int fromLine,
int fromColumn,
bool onlyCurrentLine)
const
518 QString line = getLine(fromLine);
528 int c1 = line.
indexOf(endOfWORD, c + 1);
534 if (onlyCurrentLine) {
536 }
else if (l >= doc()->lines() - 1) {
548 return KTextEditor::Cursor(l, c);
551Range innerRange(Range range,
bool inner)
556 const int columnDistance = qAbs(r.startColumn - r.endColumn);
557 if ((r.startLine == r.endLine) && columnDistance == 1) {
559 return Range::invalid();
568Range ModeBase::findSurroundingQuotes(
const QChar &c,
bool inner)
const
570 KTextEditor::Cursor cursor(m_view->cursorPosition());
572 r.startLine = cursor.line();
573 r.endLine = cursor.line();
575 QString line = doc()->line(cursor.line());
578 if (line.
at(cursor.column()) == c) {
579 int attribute = m_view->doc()->kateTextLine(cursor.line()).attribute(cursor.column());
582 if (doc()->kateTextLine(cursor.line()).attribute(cursor.column() + 1) == attribute
583 && doc()->kateTextLine(cursor.line()).attribute(cursor.column() - 1) != attribute) {
584 r.startColumn = cursor.column();
585 r.endColumn = line.
indexOf(c, cursor.column() + 1);
587 return innerRange(r, inner);
591 if (doc()->kateTextLine(cursor.line()).attribute(cursor.column() + 1) != attribute
592 && doc()->kateTextLine(cursor.line()).attribute(cursor.column() - 1) == attribute) {
593 r.startColumn = line.
lastIndexOf(c, cursor.column() - 1);
594 r.endColumn = cursor.column();
596 return innerRange(r, inner);
599 int c1 = line.
indexOf(c, cursor.column() + 1);
601 r.startColumn = cursor.column();
604 return innerRange(r, inner);
611 r.endColumn = cursor.column();
613 return innerRange(r, inner);
620 r.startColumn = line.
lastIndexOf(c, cursor.column());
621 r.endColumn = line.
indexOf(c, cursor.column());
623 if (r.startColumn == -1 || r.endColumn == -1 || r.startColumn > r.endColumn) {
627 return innerRange(r, inner);
630Range ModeBase::findSurroundingBrackets(
const QChar &c1,
const QChar &c2,
bool inner,
const QChar &nested1,
const QChar &nested2)
const
632 KTextEditor::Cursor cursor(m_view->cursorPosition());
633 Range r(cursor, InclusiveMotion);
634 int line = cursor.line();
635 int column = cursor.column();
641 const QString &l = m_view->doc()->line(line);
642 if (column < l.
size() && l.
at(column) == c2) {
644 r.endColumn = column;
646 if (column < l.
size() && l.
at(column) == c1) {
650 for (catalan = 1; line < m_view->doc()->lines(); line++) {
651 const QString &l = m_view->doc()->line(line);
653 for (; column < l.
size(); column++) {
654 const QChar &c = l.
at(column);
658 }
else if (c == nested2) {
675 r.endColumn = column;
679 line = cursor.line();
680 column = cursor.column();
682 if (column < l.
size() && l.
at(column) == c1) {
684 r.startColumn = column;
686 if (column < l.
size() && l.
at(column) == c2) {
690 for (catalan = 1; line >= 0; line--) {
691 const QString &l = m_view->doc()->line(line);
693 for (; column >= 0; column--) {
694 const QChar &c = l.
at(column);
698 }
else if (c == nested2) {
705 if (!catalan || !line) {
708 column = m_view->doc()->line(line - 1).size() - 1;
713 r.startColumn = column;
717 return innerRange(r, inner);
720Range ModeBase::findSurrounding(
const QRegularExpression &c1,
const QRegularExpression &c2,
bool inner)
const
722 KTextEditor::Cursor cursor(m_view->cursorPosition());
723 QString line = getLine();
726 int col2 = line.
indexOf(c2, cursor.column());
728 Range r(cursor.line(), col1, cursor.line(), col2, InclusiveMotion);
730 if (col1 == -1 || col2 == -1 || col1 > col2) {
742int ModeBase::findLineStartingWitchChar(
const QChar &c,
int count,
bool forward)
const
744 int line = m_view->cursorPosition().line();
745 int lines = doc()->lines();
754 while (line < lines && line >= 0 && hits < count) {
755 QString l = getLine(line);
756 if (l.
length() > 0 && l.
at(0) == c) {
768 if (hits == getCount()) {
775void ModeBase::updateCursor(
const KTextEditor::Cursor c)
const
777 m_viInputModeManager->updateCursor(c);
783QChar ModeBase::getChosenRegister(
const QChar &defaultReg)
const
785 return (m_register !=
QChar::Null) ? m_register : defaultReg;
788QString ModeBase::getRegisterContent(
const QChar ®)
790 QString r = m_viInputModeManager->globalState()->registers()->getContent(reg);
793 error(
i18n(
"Nothing in register %1", reg.
toLower()));
799OperationMode ModeBase::getRegisterFlag(
const QChar ®)
const
801 return m_viInputModeManager->globalState()->registers()->getFlag(reg);
804void ModeBase::fillRegister(
const QChar ®,
const QString &text, OperationMode flag)
806 m_viInputModeManager->globalState()->registers()->set(reg, text, flag);
809KTextEditor::Cursor ModeBase::getNextJump(KTextEditor::Cursor cursor)
const
811 return m_viInputModeManager->jumps()->next(cursor);
814KTextEditor::Cursor ModeBase::getPrevJump(KTextEditor::Cursor cursor)
const
816 return m_viInputModeManager->jumps()->prev(cursor);
819Range ModeBase::goLineDown()
821 return goLineUpDown(getCount());
824Range ModeBase::goLineUp()
826 return goLineUpDown(-getCount());
833Range ModeBase::goLineUpDown(
int lines)
835 KTextEditor::Cursor c(m_view->cursorPosition());
836 Range r(c, InclusiveMotion);
837 int tabstop = doc()->config()->tabWidth();
849 }
else if (r.endLine > doc()->lines() - 1) {
850 r.endLine = doc()->lines() - 1;
853 Kate::TextLine startLine = doc()->plainKateTextLine(c.
line());
854 Kate::TextLine endLine = doc()->plainKateTextLine(r.endLine);
856 int endLineLen = doc()->lineLength(r.endLine) - 1;
858 if (endLineLen < 0) {
866 if (m_stickyColumn == -1) {
868 m_stickyColumn = virtColumnStart;
875 if (r.endColumn > endLineLen) {
876 r.endColumn = endLineLen;
880 if (virtColumnStart > endLineLenVirt) {
881 r.endColumn = endLineLen;
887Range ModeBase::goVisualLineUpDown(
int lines)
889 KTextEditor::Cursor c(m_view->cursorPosition());
890 Range r(c, InclusiveMotion);
891 int tabstop = doc()->config()->tabWidth();
898 KateLayoutCache *cache = m_viInputModeManager->inputAdapter()->layoutCache();
902 int finishVisualLine = cache->
viewLine(m_view->cursorPosition());
903 int finishRealLine = m_view->cursorPosition().line();
904 int count = qAbs(lines);
905 bool invalidPos =
false;
910 const KateLineLayout *lineLayout = cache->
line(finishRealLine);
911 if (lineLayout && finishVisualLine >= lineLayout->viewLineCount()) {
913 finishVisualLine = 0;
915 if (finishRealLine >= doc()->lines()) {
925 if (finishVisualLine < 0) {
927 if (finishRealLine < 0) {
931 const auto lineLayout = cache->
line(finishRealLine);
933 finishVisualLine = 0;
936 finishVisualLine = lineLayout->viewLineCount() - 1;
948 r.endLine = finishRealLine;
951 if (m_stickyColumn == -1 || !m_lastMotionWasVisualLineUpOrDown) {
953 int startVisualLine = cache->
viewLine(m_view->cursorPosition());
954 int startRealLine = m_view->cursorPosition().line();
955 const Kate::TextLine startLine = doc()->plainKateTextLine(c.
line());
958 const bool isWrappedContinuation = (cache->
textLayout(startRealLine, startVisualLine).lineLayout().lineNumber() != 0);
959 const int numInvisibleIndentChars = [&] {
960 if (isWrappedContinuation) {
961 auto l = doc()->plainKateTextLine(startRealLine);
967 const int realLineStartColumn = cache->
textLayout(startRealLine, startVisualLine).startCol();
968 const int lineStartVirtualColumn = startLine.
toVirtualColumn(realLineStartColumn, tabstop);
969 const int visualColumnNoInvisibleIndent = startLine.
toVirtualColumn(c.
column(), tabstop) - lineStartVirtualColumn;
970 m_stickyColumn = visualColumnNoInvisibleIndent + numInvisibleIndentChars;
971 Q_ASSERT(m_stickyColumn >= 0);
976 const int realLineStartColumn = cache->
textLayout(finishRealLine, finishVisualLine).startCol();
977 const Kate::TextLine endLine = doc()->plainKateTextLine(r.endLine);
980 const bool isWrappedContinuation = (cache->
textLayout(finishRealLine, finishVisualLine).lineLayout().lineNumber() != 0);
981 const int numInvisibleIndentChars = [&] {
982 if (isWrappedContinuation) {
983 auto l = doc()->plainKateTextLine(finishRealLine);
988 if (m_stickyColumn == (
unsigned int)KateVi::EOL) {
989 const int visualEndColumn = cache->
textLayout(finishRealLine, finishVisualLine).lineLayout().
textLength() - 1;
990 r.endColumn = endLine.
fromVirtualColumn(visualEndColumn + realLineStartColumn - numInvisibleIndentChars, tabstop);
994 int realOffsetToVisualStickyColumn = 0;
995 const int lineStartVirtualColumn = endLine.
toVirtualColumn(realLineStartColumn, tabstop);
997 const int visualColumn =
998 endLine.
toVirtualColumn(realLineStartColumn + realOffsetToVisualStickyColumn, tabstop) - lineStartVirtualColumn + numInvisibleIndentChars;
999 if (visualColumn >= m_stickyColumn) {
1002 realOffsetToVisualStickyColumn++;
1004 r.endColumn = realLineStartColumn + realOffsetToVisualStickyColumn;
1006 m_currentMotionWasVisualLineUpOrDown =
true;
1011bool ModeBase::startNormalMode()
1017 if (!(m_viInputModeManager->isAnyVisualMode() || m_viInputModeManager->lastChangeRecorder()->isReplaying())) {
1018 m_viInputModeManager->storeLastChangeCommand();
1019 m_viInputModeManager->clearCurrentChangeLog();
1022 m_viInputModeManager->viEnterNormalMode();
1023 m_view->doc()->setUndoMergeAllEdits(
false);
1024 Q_EMIT m_view->viewModeChanged(m_view, m_view->viewMode());
1029bool ModeBase::startInsertMode()
1031 m_viInputModeManager->viEnterInsertMode();
1032 m_view->doc()->setUndoMergeAllEdits(
true);
1033 Q_EMIT m_view->viewModeChanged(m_view, m_view->viewMode());
1038bool ModeBase::startReplaceMode()
1040 m_view->doc()->setUndoMergeAllEdits(
true);
1041 m_viInputModeManager->viEnterReplaceMode();
1042 Q_EMIT m_view->viewModeChanged(m_view, m_view->viewMode());
1047bool ModeBase::startVisualMode()
1049 if (m_viInputModeManager->getCurrentViMode() == ViMode::VisualLineMode) {
1050 m_viInputModeManager->getViVisualMode()->setVisualModeType(ViMode::VisualMode);
1051 m_viInputModeManager->changeViMode(ViMode::VisualMode);
1052 }
else if (m_viInputModeManager->getCurrentViMode() == ViMode::VisualBlockMode) {
1053 m_viInputModeManager->getViVisualMode()->setVisualModeType(ViMode::VisualMode);
1054 m_viInputModeManager->changeViMode(ViMode::VisualMode);
1056 m_viInputModeManager->viEnterVisualMode();
1059 Q_EMIT m_view->viewModeChanged(m_view, m_view->viewMode());
1064bool ModeBase::startVisualBlockMode()
1066 if (m_viInputModeManager->getCurrentViMode() == ViMode::VisualMode) {
1067 m_viInputModeManager->getViVisualMode()->setVisualModeType(ViMode::VisualBlockMode);
1068 m_viInputModeManager->changeViMode(ViMode::VisualBlockMode);
1070 m_viInputModeManager->viEnterVisualMode(ViMode::VisualBlockMode);
1073 Q_EMIT m_view->viewModeChanged(m_view, m_view->viewMode());
1078bool ModeBase::startVisualLineMode()
1080 if (m_viInputModeManager->getCurrentViMode() == ViMode::VisualMode) {
1081 m_viInputModeManager->getViVisualMode()->setVisualModeType(ViMode::VisualLineMode);
1082 m_viInputModeManager->changeViMode(ViMode::VisualLineMode);
1084 m_viInputModeManager->viEnterVisualMode(ViMode::VisualLineMode);
1087 Q_EMIT m_view->viewModeChanged(m_view, m_view->viewMode());
1092void ModeBase::error(
const QString &errorMsg)
1094 delete m_infoMessage;
1098 m_infoMessage->setAutoHide(2000);
1099 m_infoMessage->setView(m_view);
1101 m_view->doc()->postMessage(m_infoMessage);
1104void ModeBase::message(
const QString &msg)
1106 delete m_infoMessage;
1110 m_infoMessage->setAutoHide(2000);
1111 m_infoMessage->setView(m_view);
1113 m_view->doc()->postMessage(m_infoMessage);
1116QString ModeBase::getVerbatimKeys()
const
1118 return m_keysVerbatim;
1121const QChar ModeBase::getCharAtVirtualColumn(
const QString &line,
int virtualColumn,
int tabWidth)
1127 if (line.
length() == 0) {
1131 while (tempCol < virtualColumn) {
1132 if (line.
at(column) == QLatin1Char(
'\t')) {
1133 tempCol += tabWidth - (tempCol % tabWidth);
1138 if (tempCol <= virtualColumn) {
1141 if (column >= line.
length()) {
1147 if (line.
length() > column) {
1148 return line.
at(column);
1154void ModeBase::addToNumberUnderCursor(
int count)
1156 KTextEditor::Cursor c(m_view->cursorPosition());
1157 QString line = getLine();
1163 const int cursorColumn = c.
column();
1164 const int cursorLine = c.
line();
1165 const KTextEditor::Cursor prevWordStart = findPrevWordStart(cursorLine, cursorColumn);
1166 int wordStartPos = prevWordStart.
column();
1167 if (prevWordStart.
line() < cursorLine) {
1171 if (wordStartPos > 0 && line.
at(wordStartPos - 1) == QLatin1Char(
'-')) {
1175 int numberStartPos = -1;
1176 QString numberAsString;
1177 static const QRegularExpression numberRegex(QStringLiteral(
"0x[0-9a-fA-F]+|\\-?\\d+"));
1178 auto numberMatchIter = numberRegex.globalMatch(line, wordStartPos);
1179 while (numberMatchIter.hasNext()) {
1180 const auto numberMatch = numberMatchIter.next();
1181 const bool numberEndedBeforeCursor = (numberMatch.capturedStart() + numberMatch.capturedLength() <= cursorColumn);
1182 if (!numberEndedBeforeCursor) {
1184 numberStartPos = numberMatch.capturedStart();
1185 numberAsString = numberMatch.captured();
1190 if (numberStartPos == -1) {
1195 bool parsedNumberSuccessfully =
false;
1196 int base = numberAsString.
startsWith(QLatin1String(
"0x")) ? 16 : 10;
1197 if (base != 16 && numberAsString.
startsWith(QLatin1Char(
'0')) && numberAsString.
length() > 1) {
1200 numberAsString.
toInt(&parsedNumberSuccessfully, 8);
1201 if (parsedNumberSuccessfully) {
1205 const int originalNumber = numberAsString.
toInt(&parsedNumberSuccessfully, base);
1207 if (!parsedNumberSuccessfully) {
1214 basePrefix = QStringLiteral(
"0x");
1215 }
else if (base == 8) {
1216 basePrefix = QStringLiteral(
"0");
1219 const int withoutBaseLength = numberAsString.
length() - basePrefix.
length();
1221 const int newNumber = originalNumber + count;
1225 const QString newNumberPadded =
1226 (base == 10) ? QStringLiteral(
"%1").arg(newNumber, 0, base) : QStringLiteral(
"%1").arg(newNumber, withoutBaseLength, base, QLatin1Char(
'0'));
1227 const QString newNumberText = basePrefix + newNumberPadded;
1231 doc()->removeText(KTextEditor::Range(cursorLine, numberStartPos, cursorLine, numberStartPos + numberAsString.
length()));
1232 doc()->insertText(KTextEditor::Cursor(cursorLine, numberStartPos), newNumberText);
1234 updateCursor(KTextEditor::Cursor(m_view->cursorPosition().line(), numberStartPos + newNumberText.
length() - 1));
1237void ModeBase::switchView(Direction direction)
1239 std::vector<KTextEditor::ViewPrivate *> visible_views;
1241 if (view->isVisible()) {
1242 visible_views.push_back(view);
1246 QPoint current_point = m_view->mapToGlobal(m_view->pos());
1247 int curr_x1 = current_point.
x();
1248 int curr_x2 = current_point.
x() + m_view->width();
1249 int curr_y1 = current_point.
y();
1250 int curr_y2 = current_point.
y() + m_view->height();
1251 const KTextEditor::Cursor cursorPos = m_view->cursorPosition();
1252 const QPoint globalPos = m_view->mapToGlobal(m_view->cursorToCoordinate(cursorPos));
1253 int curr_cursor_y = globalPos.
y();
1254 int curr_cursor_x = globalPos.
x();
1256 KTextEditor::ViewPrivate *bestview =
nullptr;
1261 int best_center_y = -1;
1262 int best_center_x = -1;
1264 if (direction == Next && visible_views.size() != 1) {
1265 for (
size_t i = 0; i < visible_views.size(); i++) {
1266 if (visible_views.at(i) == m_view) {
1267 if (i != visible_views.size() - 1) {
1268 bestview = visible_views.at(i + 1);
1270 bestview = visible_views.at(0);
1275 for (KTextEditor::ViewPrivate *view : visible_views) {
1276 QPoint point = view->mapToGlobal(view->pos());
1278 int x2 = point.
x() + view->width();
1280 int y2 = point.
y() + m_view->height();
1281 int center_y = (y1 + y2) / 2;
1282 int center_x = (x1 + x2) / 2;
1284 switch (direction) {
1286 if (view != m_view && x2 <= curr_x1
1287 && (x2 > best_x2 || (x2 == best_x2 && qAbs(curr_cursor_y - center_y) < qAbs(curr_cursor_y - best_center_y)) || bestview ==
nullptr)) {
1290 best_center_y = center_y;
1294 if (view != m_view && x1 >= curr_x2
1295 && (x1 < best_x1 || (x1 == best_x1 && qAbs(curr_cursor_y - center_y) < qAbs(curr_cursor_y - best_center_y)) || bestview ==
nullptr)) {
1298 best_center_y = center_y;
1302 if (view != m_view && y1 >= curr_y2
1303 && (y1 < best_y1 || (y1 == best_y1 && qAbs(curr_cursor_x - center_x) < qAbs(curr_cursor_x - best_center_x)) || bestview ==
nullptr)) {
1306 best_center_x = center_x;
1310 if (view != m_view && y2 <= curr_y1
1311 && (y2 > best_y2 || (y2 == best_y2 && qAbs(curr_cursor_x - center_x) < qAbs(curr_cursor_x - best_center_x)) || bestview ==
nullptr)) {
1314 best_center_x = center_x;
1322 if (bestview !=
nullptr) {
1328Range ModeBase::motionFindPrev()
1330 Searcher *searcher = m_viInputModeManager->searcher();
1331 Range match = searcher->motionFindPrev(getCount());
1332 if (searcher->lastSearchWrapped()) {
1333 m_view->showSearchWrappedHint(
true);
1339Range ModeBase::motionFindNext()
1341 Searcher *searcher = m_viInputModeManager->searcher();
1342 Range match = searcher->motionFindNext(getCount());
1343 if (searcher->lastSearchWrapped()) {
1344 m_view->showSearchWrappedHint(
false);
1350void ModeBase::goToPos(
const Range &r)
1352 KTextEditor::Cursor c;
1361 m_viInputModeManager->jumps()->add(m_view->cursorPosition());
1364 if (c.
line() >= doc()->lines()) {
1365 c.
setLine(doc()->lines() - 1);
1371unsigned int ModeBase::linesDisplayed()
const
1373 return m_viInputModeManager->inputAdapter()->linesDisplayed();
1376void ModeBase::scrollViewLines(
int l)
1378 m_viInputModeManager->inputAdapter()->scrollViewLines(l);
1381int ModeBase::getCount()
const
1383 if (m_oneTimeCountOverride != -1) {
1384 return m_oneTimeCountOverride;
1386 return (m_count > 0) ? m_count : 1;
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.
void copyToClipboard(const QString &text, const QString &fileName)
Copy text to clipboard an remember it in the history.
static KTextEditor::EditorPrivate * self()
Kate Part Internal stuff ;)
@ BottomInView
show message as view overlay in the bottom right corner.
@ Error
error message type
@ Positive
positive information message
static constexpr Range invalid() noexcept
Returns an invalid range.
KateTextLayout & viewLine(int viewLine)
Returns the layout of the corresponding line in the view.
KateLineLayout * line(int realLine, int virtualLine=-1)
Returns the KateLineLayout for the specified line.
KateTextLayout textLayout(const KTextEditor::Cursor realCursor)
Returns the layout describing the text line which is occupied by realCursor.
int toVirtualColumn(int column, int tabWidth) const
Returns the column with each tab expanded into tabWidth characters.
int fromVirtualColumn(int column, int tabWidth) const
Returns the "real" column where each tab only counts one character.
static constexpr Range invalid() noexcept
Returns an invalid range.
QString i18n(const char *text, const TYPE &arg...)
KCOREADDONS_EXPORT Result match(QStringView pattern, QStringView str)
bool isLetterOrNumber(char32_t ucs4)
bool isMark(char32_t ucs4)
bool isSpace(char32_t ucs4)
char32_t toLower(char32_t ucs4)
UseUnicodePropertiesOption
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
bool isNull() const const
qsizetype lastIndexOf(QChar ch, Qt::CaseSensitivity cs) const const
qsizetype length() const const
qsizetype size() const const
bool startsWith(QChar c, Qt::CaseSensitivity cs) const const
int toInt(bool *ok, int base) const const
QString trimmed() const const
int textLength() const const