7#include <vimode/emulatedcommandbar/emulatedcommandbar.h>
9#include "../commandrangeexpressionparser.h"
10#include "../globalstate.h"
11#include "commandmode.h"
12#include "interactivesedreplacemode.h"
13#include "katedocument.h"
14#include "kateglobal.h"
16#include "matchhighlighter.h"
17#include "searchmode.h"
18#include <inputmode/kateviinputmode.h>
19#include <vimode/inputmodemanager.h>
20#include <vimode/keyparser.h>
21#include <vimode/modes/normalvimode.h>
23#include "../registers.h"
25#include <QApplication>
30using namespace KateVi;
38QString escapedForSearchingAsLiteral(
const QString &originalQtRegex)
40 QString escapedForSearchingAsLiteral = originalQtRegex;
50 return escapedForSearchingAsLiteral;
54EmulatedCommandBar::EmulatedCommandBar(KateViInputMode *viInputMode, InputModeManager *viInputModeManager,
QWidget *parent)
55 : KateViewBarWidget(false, parent)
56 , m_viInputMode(viInputMode)
57 , m_viInputModeManager(viInputModeManager)
58 , m_view(viInputModeManager->view())
63 createAndAddBarTypeIndicator(layout);
64 createAndAddEditWidget(layout);
65 createAndAddExitStatusMessageDisplay(layout);
66 createAndInitExitStatusMessageDisplayTimer();
67 createAndAddWaitingForRegisterIndicator(layout);
69 m_matchHighligher.reset(
new MatchHighlighter(m_view));
71 m_completer.reset(
new Completer(
this, m_view, m_edit));
73 m_interactiveSedReplaceMode.reset(
new InteractiveSedReplaceMode(
this, m_matchHighligher.get(), m_viInputModeManager, m_view));
74 layout->
addWidget(m_interactiveSedReplaceMode->label());
75 m_searchMode.reset(
new SearchMode(
this, m_matchHighligher.get(), m_viInputModeManager, m_view, m_edit));
77 new CommandMode(
this, m_matchHighligher.get(), m_viInputModeManager, m_view, m_edit, m_interactiveSedReplaceMode.get(), m_completer.get()));
79 m_edit->installEventFilter(
this);
83EmulatedCommandBar::~EmulatedCommandBar() =
default;
85void EmulatedCommandBar::init(EmulatedCommandBar::Mode mode,
const QString &initialText)
91 showBarTypeIndicator(mode);
93 if (mode == KateVi::EmulatedCommandBar::SearchBackward || mode == SearchForward) {
94 switchToMode(m_searchMode.get());
95 m_searchMode->init(mode == SearchBackward ? SearchMode::SearchDirection::Backward : SearchMode::SearchDirection::Forward);
97 switchToMode(m_commandMode.get());
101 m_edit->setText(initialText);
104 m_exitStatusMessageDisplay->hide();
105 m_exitStatusMessageDisplayHideTimer->stop();
114bool EmulatedCommandBar::isActive()
const
119void EmulatedCommandBar::setCommandResponseMessageTimeout(
long int commandResponseMessageTimeOutMS)
121 m_exitStatusMessageHideTimeOutMS = commandResponseMessageTimeOutMS;
124void EmulatedCommandBar::closed()
127 m_completer->deactivateCompletion();
131 m_currentMode->deactivate(m_wasAborted);
132 m_currentMode =
nullptr;
136void EmulatedCommandBar::switchToMode(ActiveMode *newMode)
138 if (newMode == m_currentMode) {
142 m_currentMode->deactivate(
false);
144 m_currentMode = newMode;
145 m_completer->setCurrentMode(newMode);
148bool EmulatedCommandBar::barHandledKeypress(
const QKeyEvent *keyEvent)
151 if (m_edit->text().isEmpty()) {
157 if (
keyEvent->modifiers() != CONTROL_MODIFIER) {
161 m_edit->setCursorPosition(0);
164 m_edit->setCursorPosition(m_edit->text().length());
167 deleteSpacesToLeftOfCursor();
168 if (!deleteNonWordCharsToLeftOfCursor()) {
169 deleteWordCharsToLeftOfCursor();
173 m_waitingForRegister =
true;
174 m_waitingForRegisterIndicator->setVisible(
true);
176 m_insertedTextShouldBeEscapedForSearchingAsLiteral =
true;
183void EmulatedCommandBar::insertRegisterContents(
const QKeyEvent *keyEvent)
186 const QChar key = KeyParser::self()->KeyEventToQChar(*keyEvent).toLower();
188 const int oldCursorPosition = m_edit->cursorPosition();
189 QString textToInsert;
191 textToInsert = m_view->doc()->wordAt(m_view->cursorPosition());
193 textToInsert = m_viInputModeManager->globalState()->registers()->getContent(key);
195 if (m_insertedTextShouldBeEscapedForSearchingAsLiteral) {
196 textToInsert = escapedForSearchingAsLiteral(textToInsert);
197 m_insertedTextShouldBeEscapedForSearchingAsLiteral =
false;
199 m_edit->setText(m_edit->text().insert(m_edit->cursorPosition(), textToInsert));
200 m_edit->setCursorPosition(oldCursorPosition + textToInsert.
length());
201 m_waitingForRegister =
false;
202 m_waitingForRegisterIndicator->setVisible(
false);
206bool EmulatedCommandBar::eventFilter(QObject *
object, QEvent *event)
209 if (m_suspendEditEventFiltering) {
216 return m_viInputMode->keyPress(
static_cast<QKeyEvent *
>(
event));
221void EmulatedCommandBar::deleteSpacesToLeftOfCursor()
223 while (m_edit->cursorPosition() != 0 && m_edit->text().at(m_edit->cursorPosition() - 1) == QLatin1Char(
' ')) {
228void EmulatedCommandBar::deleteWordCharsToLeftOfCursor()
230 while (m_edit->cursorPosition() != 0) {
231 const QChar charToTheLeftOfCursor = m_edit->text().at(m_edit->cursorPosition() - 1);
232 if (!charToTheLeftOfCursor.
isLetterOrNumber() && charToTheLeftOfCursor != QLatin1Char(
'_')) {
240bool EmulatedCommandBar::deleteNonWordCharsToLeftOfCursor()
242 bool deletionsMade =
false;
243 while (m_edit->cursorPosition() != 0) {
244 const QChar charToTheLeftOfCursor = m_edit->text().at(m_edit->cursorPosition() - 1);
245 if (charToTheLeftOfCursor.
isLetterOrNumber() || charToTheLeftOfCursor == QLatin1Char(
'_') || charToTheLeftOfCursor == QLatin1Char(
' ')) {
250 deletionsMade =
true;
252 return deletionsMade;
255bool EmulatedCommandBar::handleKeyPress(
const QKeyEvent *keyEvent)
257 if (m_waitingForRegister) {
258 insertRegisterContents(keyEvent);
261 const bool completerHandled = m_completer->completerHandledKeypress(keyEvent);
262 if (completerHandled) {
272 const bool barHandled = barHandledKeypress(keyEvent);
278 const bool currentModeHandled = m_currentMode->handleKeyPress(keyEvent);
279 if (currentModeHandled) {
290 if (m_edit->isVisible()) {
291 if (m_suspendEditEventFiltering) {
294 m_suspendEditEventFiltering =
true;
296 qApp->notify(m_edit, &keyEventCopy);
297 m_suspendEditEventFiltering =
false;
302bool EmulatedCommandBar::isSendingSyntheticSearchCompletedKeypress()
304 return m_searchMode->isSendingSyntheticSearchCompletedKeypress();
307void EmulatedCommandBar::startInteractiveSearchAndReplace(std::shared_ptr<SedReplace::InteractiveSedReplacer> interactiveSedReplace)
309 Q_ASSERT_X(interactiveSedReplace->currentMatch().isValid(),
310 "startInteractiveSearchAndReplace",
311 "KateCommands shouldn't initiate an interactive sed replace with no initial match");
312 switchToMode(m_interactiveSedReplaceMode.get());
313 m_interactiveSedReplaceMode->activate(interactiveSedReplace);
316void EmulatedCommandBar::showBarTypeIndicator(EmulatedCommandBar::Mode mode)
321 barTypeIndicator = QLatin1Char(
'/');
324 barTypeIndicator = QLatin1Char(
'?');
327 barTypeIndicator = QLatin1Char(
':');
330 Q_ASSERT(
false &&
"Unknown mode!");
332 m_barTypeIndicator->setText(barTypeIndicator);
333 m_barTypeIndicator->show();
336QString EmulatedCommandBar::executeCommand(
const QString &commandToExecute)
338 return m_commandMode->executeCommand(commandToExecute);
341void EmulatedCommandBar::closeWithStatusMessage(
const QString &exitStatusMessage)
346 m_exitStatusMessageDisplay->show();
347 m_exitStatusMessageDisplay->setText(exitStatusMessage);
348 hideAllWidgetsExcept(m_exitStatusMessageDisplay);
350 m_exitStatusMessageDisplayHideTimer->start(m_exitStatusMessageHideTimeOutMS);
353void EmulatedCommandBar::editTextChanged(
const QString &newText)
355 Q_ASSERT(!m_interactiveSedReplaceMode->isActive());
356 m_currentMode->editTextChanged(newText);
357 m_completer->editTextChanged(newText);
360void EmulatedCommandBar::startHideExitStatusMessageTimer()
362 if (m_exitStatusMessageDisplay->isVisible() && !m_exitStatusMessageDisplayHideTimer->isActive()) {
363 m_exitStatusMessageDisplayHideTimer->start(m_exitStatusMessageHideTimeOutMS);
367void EmulatedCommandBar::setViInputModeManager(InputModeManager *viInputModeManager)
369 m_viInputModeManager = viInputModeManager;
370 m_searchMode->setViInputModeManager(viInputModeManager);
371 m_commandMode->setViInputModeManager(viInputModeManager);
372 m_interactiveSedReplaceMode->setViInputModeManager(viInputModeManager);
375void EmulatedCommandBar::hideAllWidgetsExcept(QWidget *widgetToKeepVisible)
377 const QList<QWidget *> widgets = centralWidget()->findChildren<
QWidget *>();
378 for (
QWidget *widget : widgets) {
379 if (widget != widgetToKeepVisible) {
385void EmulatedCommandBar::createAndAddBarTypeIndicator(QLayout *layout)
387 m_barTypeIndicator =
new QLabel(
this);
388 m_barTypeIndicator->setObjectName(QStringLiteral(
"bartypeindicator"));
389 layout->addWidget(m_barTypeIndicator);
392void EmulatedCommandBar::createAndAddEditWidget(QLayout *layout)
394 m_edit =
new QLineEdit(
this);
395 m_edit->setObjectName(QStringLiteral(
"commandtext"));
396 layout->addWidget(m_edit);
399void EmulatedCommandBar::createAndAddExitStatusMessageDisplay(QLayout *layout)
401 m_exitStatusMessageDisplay =
new QLabel(
this);
402 m_exitStatusMessageDisplay->setObjectName(QStringLiteral(
"commandresponsemessage"));
404 layout->addWidget(m_exitStatusMessageDisplay);
407void EmulatedCommandBar::createAndInitExitStatusMessageDisplayTimer()
409 m_exitStatusMessageDisplayHideTimer =
new QTimer(
this);
410 m_exitStatusMessageDisplayHideTimer->setSingleShot(
true);
420void EmulatedCommandBar::createAndAddWaitingForRegisterIndicator(QLayout *layout)
422 m_waitingForRegisterIndicator =
new QLabel(
this);
423 m_waitingForRegisterIndicator->setObjectName(QStringLiteral(
"waitingforregisterindicator"));
424 m_waitingForRegisterIndicator->setVisible(
false);
425 m_waitingForRegisterIndicator->setText(QStringLiteral(
"\""));
426 layout->addWidget(m_waitingForRegisterIndicator);
static constexpr Range invalid() noexcept
Returns an invalid range.
void focusOut(KTextEditor::View *view)
This signal is emitted whenever the view loses the focus.
void focusIn(KTextEditor::View *view)
This signal is emitted whenever the view gets the focus.
bool isLetterOrNumber(char32_t ucs4)
void processEvents(QEventLoop::ProcessEventsFlags flags)
void setContentsMargins(const QMargins &margins)
void textChanged(const QString &text)
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
virtual bool event(QEvent *e)
qsizetype length() const const
QString & replace(QChar before, QChar after, Qt::CaseSensitivity cs)
void keyEvent(KeyAction action, QWidget *widget, Qt::Key key, Qt::KeyboardModifiers modifier, int delay)