9#include "katecompletiontree.h"
10#include "katecompletionwidget.h"
11#include "kateconfig.h"
12#include "katedocument.h"
13#include "kateglobal.h"
14#include "katepartdebug.h"
15#include "katerenderer.h"
17#include "kateviewinternal.h"
18#include "kateviinputmode.h"
19#include <vimode/completionrecorder.h>
20#include <vimode/completionreplayer.h>
21#include <vimode/emulatedcommandbar/emulatedcommandbar.h>
22#include <vimode/inputmodemanager.h>
23#include <vimode/keyparser.h>
24#include <vimode/lastchangerecorder.h>
25#include <vimode/macrorecorder.h>
26#include <vimode/marks.h>
27#include <vimode/modes/insertvimode.h>
29#include <KLocalizedString>
31using namespace KateVi;
33InsertViMode::InsertViMode(InputModeManager *viInputModeManager, KTextEditor::ViewPrivate *view, KateViewInternal *viewInternal)
37 m_viewInternal = viewInternal;
38 m_viInputModeManager = viInputModeManager;
40 m_waitingRegister =
false;
44 m_countedRepeatsBeginOnNewLine =
false;
46 m_isExecutingCompletion =
false;
51InsertViMode::~InsertViMode() =
default;
53bool InsertViMode::commandInsertFromAbove()
55 KTextEditor::Cursor c(m_view->cursorPosition());
61 QString line = doc()->line(c.line() - 1);
62 int tabWidth = doc()->config()->tabWidth();
63 QChar ch = getCharAtVirtualColumn(line, m_view->virtualCursorColumn(), tabWidth);
69 return doc()->insertText(c, ch);
72bool InsertViMode::commandInsertFromBelow()
74 KTextEditor::Cursor c(m_view->cursorPosition());
76 if (c.line() >= doc()->lines() - 1) {
80 QString line = doc()->line(c.line() + 1);
81 int tabWidth = doc()->config()->tabWidth();
82 QChar ch = getCharAtVirtualColumn(line, m_view->virtualCursorColumn(), tabWidth);
88 return doc()->insertText(c, ch);
91bool InsertViMode::commandDeleteWord()
93 KTextEditor::Cursor c1(m_view->cursorPosition());
94 KTextEditor::Cursor c2;
96 c2 = findPrevWordStart(c1.line(), c1.column());
98 if (c2.
line() != c1.line()) {
99 if (c1.column() == 0) {
107 Range r(c2, c1, ExclusiveMotion);
108 return deleteRange(r, CharWise,
false);
111bool InsertViMode::commandDeleteLine()
113 KTextEditor::Cursor c(m_view->cursorPosition());
114 Range r(c.line(), 0, c.line(), c.column(), ExclusiveMotion);
116 if (c.column() == 0) {
121 r.startColumn = doc()->line(c.line() - 1).length();
130 r.startColumn = getLine().indexOf(nonSpace);
131 if (r.startColumn == -1 || r.startColumn >= c.column()) {
135 return deleteRange(r, CharWise,
false);
138bool InsertViMode::commandDeleteCharBackward()
140 KTextEditor::Cursor c(m_view->cursorPosition());
142 Range r(c.line(), c.column() - getCount(), c.line(), c.column(), ExclusiveMotion);
144 if (c.column() == 0) {
148 r.startColumn = doc()->line(c.line() - 1).length();
153 return deleteRange(r, CharWise);
156bool InsertViMode::commandNewLine()
158 doc()->newLine(m_view);
162bool InsertViMode::commandIndent()
164 KTextEditor::Cursor c(m_view->cursorPosition());
165 doc()->indent(KTextEditor::Range(c.line(), 0, c.line(), 0), 1);
169bool InsertViMode::commandUnindent()
171 KTextEditor::Cursor c(m_view->cursorPosition());
172 doc()->indent(KTextEditor::Range(c.line(), 0, c.line(), 0), -1);
176bool InsertViMode::commandToFirstCharacterInFile()
178 KTextEditor::Cursor c(0, 0);
183bool InsertViMode::commandToLastCharacterInFile()
185 int lines = doc()->lines() - 1;
186 KTextEditor::Cursor c(lines, doc()->line(lines).length());
191bool InsertViMode::commandMoveOneWordLeft()
193 KTextEditor::Cursor c(m_view->cursorPosition());
194 c = findPrevWordStart(c.line(), c.column());
197 c = KTextEditor::Cursor(0, 0);
204bool InsertViMode::commandMoveOneWordRight()
206 KTextEditor::Cursor c(m_view->cursorPosition());
207 c = findNextWordStart(c.line(), c.column());
210 c = doc()->documentEnd();
217bool InsertViMode::commandCompleteNext()
219 if (m_view->completionWidget()->isCompletionActive()) {
220 const QModelIndex oldCompletionItem = m_view->completionWidget()->treeView()->selectionModel()->currentIndex();
221 m_view->completionWidget()->cursorDown();
222 const QModelIndex newCompletionItem = m_view->completionWidget()->treeView()->selectionModel()->currentIndex();
223 if (newCompletionItem == oldCompletionItem) {
225 m_view->completionWidget()->top();
228 m_view->userInvokedCompletion();
233bool InsertViMode::commandCompletePrevious()
235 if (m_view->completionWidget()->isCompletionActive()) {
236 const QModelIndex oldCompletionItem = m_view->completionWidget()->treeView()->selectionModel()->currentIndex();
237 m_view->completionWidget()->cursorUp();
238 const QModelIndex newCompletionItem = m_view->completionWidget()->treeView()->selectionModel()->currentIndex();
239 if (newCompletionItem == oldCompletionItem) {
241 m_view->completionWidget()->bottom();
244 m_view->userInvokedCompletion();
245 m_view->completionWidget()->bottom();
250bool InsertViMode::commandInsertContentOfRegister()
252 KTextEditor::Cursor c(m_view->cursorPosition());
253 KTextEditor::Cursor cAfter = c;
254 QChar reg = getChosenRegister(m_register);
256 OperationMode m = getRegisterFlag(reg);
257 QString textToInsert = getRegisterContent(reg);
259 if (textToInsert.
isNull()) {
260 error(
i18n(
"Nothing in register %1", reg));
265 textToInsert.
chop(1);
266 c.setColumn(doc()->lineLength(c.line()));
267 textToInsert.
prepend(QLatin1Char(
'\n'));
275 doc()->insertText(c, textToInsert, m == Block);
277 updateCursor(cAfter);
283bool InsertViMode::commandSwitchToNormalModeForJustOneCommand()
285 m_viInputModeManager->setTemporaryNormalMode(
true);
286 m_viInputModeManager->changeViMode(ViMode::NormalMode);
287 const KTextEditor::Cursor cursorPos = m_view->cursorPosition();
290 m_view->setCursorPosition(KTextEditor::Cursor(cursorPos.
line(), cursorPos.
column() - 1));
292 m_viInputModeManager->inputAdapter()->setCaretStyle(KTextEditor::caretStyles::Block);
293 Q_EMIT m_view->viewModeChanged(m_view, m_view->viewMode());
294 m_viewInternal->repaint();
302bool InsertViMode::handleKeypress(
const QKeyEvent *e)
310 if (m_keys.isEmpty() && !m_waitingRegister) {
318 m_view->cursorLeft();
321 m_view->cursorRight();
350 if (m_view->completionWidget()->isCompletionActive() && !m_viInputModeManager->macroRecorder()->isReplaying()
351 && !m_viInputModeManager->lastChangeRecorder()->isReplaying()) {
352 m_isExecutingCompletion =
true;
353 m_textInsertedByCompletion.clear();
354 const bool success = m_view->completionWidget()->execute();
355 m_isExecutingCompletion =
false;
360 m_viInputModeManager->doNotLogCurrentKeypress();
361 completionFinished();
364 }
else if (m_viInputModeManager->inputAdapter()->viModeEmulatedCommandBar()->isSendingSyntheticSearchCompletedKeypress()) {
366 m_viInputModeManager->doNotLogCurrentKeypress();
373 }
else if (e->
modifiers() == CONTROL_MODIFIER) {
382 if (!m_viInputModeManager->macroRecorder()->isReplaying() && !m_viInputModeManager->lastChangeRecorder()->isReplaying()) {
383 commandCompleteNext();
385 m_viInputModeManager->doNotLogCurrentKeypress();
387 m_viInputModeManager->completionReplayer()->replay();
391 leaveInsertMode(
true);
397 commandInsertFromBelow();
400 if (!m_viInputModeManager->macroRecorder()->isReplaying()) {
401 commandCompleteNext();
405 if (!m_viInputModeManager->macroRecorder()->isReplaying()) {
406 commandCompletePrevious();
416 return commandDeleteLine();
421 commandDeleteCharBackward();
424 commandInsertFromAbove();
427 commandSwitchToNormalModeForJustOneCommand();
430 commandToFirstCharacterInFile();
433 m_waitingRegister =
true;
436 commandToLastCharacterInFile();
439 commandMoveOneWordLeft();
442 commandMoveOneWordRight();
450 }
else if (m_waitingRegister) {
456 QChar key = KeyParser::self()->KeyEventToQChar(*e);
458 m_waitingRegister =
false;
462 if ((key >= QLatin1Char(
'0') && key <= QLatin1Char(
'9')) || (key >= QLatin1Char(
'a') && key <= QLatin1Char(
'z')) || key == QLatin1Char(
'_')
463 || key == QLatin1Char(
'-') || key == QLatin1Char(
'+') || key == QLatin1Char(
'*') || key == QLatin1Char(
'"')) {
468 commandInsertContentOfRegister();
477void InsertViMode::leaveInsertMode(
bool force)
479 m_view->abortCompletion();
481 if (m_blockInsert != None) {
484 if (m_blockRange.startLine == m_view->cursorPosition().line()) {
488 KTextEditor::Cursor c;
490 switch (m_blockInsert) {
493 if (m_blockInsert == Append) {
494 start = m_blockRange.endColumn + 1;
496 start = m_blockRange.startColumn;
499 len = m_view->cursorPosition().column() -
start;
502 c = KTextEditor::Cursor(m_blockRange.startLine,
start);
503 for (
int i = m_blockRange.startLine + 1; i <= m_blockRange.endLine; i++) {
505 doc()->insertText(c, added);
510 len = m_view->cursorPosition().column() -
start;
513 c = KTextEditor::Cursor(m_blockRange.startLine,
start);
514 for (
int i = m_blockRange.startLine + 1; i <= m_blockRange.endLine; i++) {
517 doc()->insertText(c, added);
521 error(QStringLiteral(
"not supported"));
525 m_blockInsert =
None;
527 const QString added = doc()->text(KTextEditor::Range(m_viInputModeManager->marks()->getStartEditYanked(), m_view->cursorPosition()));
530 for (
unsigned int i = 0; i < m_count - 1; i++) {
531 if (m_countedRepeatsBeginOnNewLine) {
532 doc()->newLine(m_view);
534 doc()->insertText(m_view->cursorPosition(), added);
539 m_countedRepeatsBeginOnNewLine =
false;
543void InsertViMode::setBlockPrependMode(Range blockRange)
546 if (blockRange.startLine != blockRange.endLine) {
547 m_blockInsert = Prepend;
548 m_blockRange = blockRange;
552void InsertViMode::setBlockAppendMode(Range blockRange, BlockInsert b)
554 Q_ASSERT(b == Append || b == AppendEOL);
557 if (blockRange.startLine != blockRange.endLine) {
558 m_blockRange = blockRange;
560 if (b == AppendEOL) {
561 m_eolPos = doc()->lineLength(m_blockRange.startLine);
564 qCDebug(LOG_KTE) <<
"cursor moved. ignoring block append/prepend";
568void InsertViMode::completionFinished()
570 Completion::CompletionType completionType = Completion::PlainText;
571 if (m_view->cursorPosition() != m_textInsertedByCompletionEndPos) {
572 completionType = Completion::FunctionWithArgs;
573 }
else if (m_textInsertedByCompletion.endsWith(QLatin1String(
"()")) || m_textInsertedByCompletion.endsWith(QLatin1String(
"();"))) {
574 completionType = Completion::FunctionWithoutArgs;
576 m_viInputModeManager->completionRecorder()->logCompletionEvent(
577 Completion(m_textInsertedByCompletion, KateViewConfig::global()->wordCompletionRemoveTail(), completionType));
580void InsertViMode::textInserted(KTextEditor::Document *document, KTextEditor::Range range)
582 if (m_isExecutingCompletion) {
583 m_textInsertedByCompletion += document->
text(range);
584 m_textInsertedByCompletionEndPos = range.
end();
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.
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.
void textInsertedRange(KTextEditor::Document *document, KTextEditor::Range range)
The document emits this signal whenever text was inserted.
virtual QString text() const =0
Get the document content.
constexpr Cursor end() const noexcept
Get the end position of this range.
Q_SCRIPTABLE Q_NOREPLY void start()
QString i18n(const char *text, const TYPE &arg...)
char32_t toLower(char32_t ucs4)
Qt::KeyboardModifiers modifiers() const const
UseUnicodePropertiesOption
bool isNull() const const
qsizetype length() const const
QString mid(qsizetype position, qsizetype n) const const
QString & prepend(QChar ch)