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;
48 connect(doc(), &KTextEditor::DocumentPrivate::textInsertedRange,
this, &InsertViMode::textInserted);
51InsertViMode::~InsertViMode() =
default;
53bool InsertViMode::commandInsertFromAbove()
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()
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()
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()
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()
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()
169bool InsertViMode::commandUnindent()
176bool InsertViMode::commandToFirstCharacterInFile()
183bool InsertViMode::commandToLastCharacterInFile()
185 int lines = doc()->lines() - 1;
191bool InsertViMode::commandMoveOneWordLeft()
194 c = findPrevWordStart(c.line(), c.column());
204bool InsertViMode::commandMoveOneWordRight()
207 c = findNextWordStart(c.line(), c.column());
210 c = doc()->documentEnd();
217bool InsertViMode::commandCompleteNext()
219 if (m_view->completionWidget()->isCompletionActive()) {
221 m_view->completionWidget()->cursorDown();
223 if (newCompletionItem == oldCompletionItem) {
225 m_view->completionWidget()->top();
228 m_view->userInvokedCompletion();
233bool InsertViMode::commandCompletePrevious()
235 if (m_view->completionWidget()->isCompletionActive()) {
237 m_view->completionWidget()->cursorUp();
239 if (newCompletionItem == oldCompletionItem) {
241 m_view->completionWidget()->bottom();
244 m_view->userInvokedCompletion();
245 m_view->completionWidget()->bottom();
250bool InsertViMode::commandInsertContentOfRegister()
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()));
275 doc()->insertText(c, textToInsert, m == Block);
277 updateCursor(cAfter);
283bool InsertViMode::commandSwitchToNormalModeForJustOneCommand()
285 m_viInputModeManager->setTemporaryNormalMode(
true);
286 m_viInputModeManager->changeViMode(ViMode::NormalMode);
292 m_viInputModeManager->inputAdapter()->setCaretStyle(KTextEditor::caretStyles::Block);
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;
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()) {
490 switch (m_blockInsert) {
493 if (m_blockInsert == Append) {
494 start = m_blockRange.endColumn + 1;
496 start = m_blockRange.startColumn;
503 for (
int i = m_blockRange.startLine + 1; i <= m_blockRange.endLine; i++) {
505 doc()->insertText(c, added);
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;
574 completionType = Completion::FunctionWithoutArgs;
576 m_viInputModeManager->completionRecorder()->logCompletionEvent(
577 Completion(m_textInsertedByCompletion, KateViewConfig::global()->wordCompletionRemoveTail(), completionType));
582 if (m_isExecutingCompletion) {
583 m_textInsertedByCompletion += document->
text(range);
584 m_textInsertedByCompletionEndPos = range.
end();
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.
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.
A KParts derived class representing a text document.
virtual QString text() const =0
Get the document content.
An object representing a section of text, from one Cursor to another.
constexpr Cursor end() const noexcept
Get the end position of this range.
void viewModeChanged(KTextEditor::View *view, KTextEditor::View::ViewMode mode)
This signal is emitted whenever the view mode of view changes.
Q_SCRIPTABLE Q_NOREPLY void start()
QString i18n(const char *text, const TYPE &arg...)
QItemSelectionModel * selectionModel() const const
char32_t toLower(char32_t ucs4)
QModelIndex currentIndex() const const
Qt::KeyboardModifiers modifiers() const const
UseUnicodePropertiesOption
bool endsWith(QChar c, Qt::CaseSensitivity cs) const const
qsizetype indexOf(QChar ch, qsizetype from, Qt::CaseSensitivity cs) const const
bool isEmpty() const const
bool isNull() const const
qsizetype length() const const
QString mid(qsizetype position, qsizetype n) const const
QString & prepend(QChar ch)
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)