File indexing completed on 2024-05-05 03:58:02

0001 /*
0002     SPDX-FileCopyrightText: KDE Developers
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "kateviinputmode.h"
0008 #include "kateconfig.h"
0009 #include "katedocument.h"
0010 #include "katerenderer.h"
0011 #include "kateview.h"
0012 #include "kateviewinternal.h"
0013 #include <vimode/emulatedcommandbar/emulatedcommandbar.h>
0014 #include <vimode/macrorecorder.h>
0015 #include <vimode/marks.h>
0016 #include <vimode/modes/replacevimode.h>
0017 #include <vimode/modes/visualvimode.h>
0018 #include <vimode/searcher.h>
0019 
0020 #include <KLocalizedString>
0021 
0022 #include <QCoreApplication>
0023 
0024 namespace
0025 {
0026 QString viModeToString(KateVi::ViMode mode)
0027 {
0028     QString modeStr;
0029     switch (mode) {
0030     case KateVi::InsertMode:
0031         modeStr = i18n("VI: INSERT MODE");
0032         break;
0033     case KateVi::NormalMode:
0034         modeStr = i18n("VI: NORMAL MODE");
0035         break;
0036     case KateVi::VisualMode:
0037         modeStr = i18n("VI: VISUAL");
0038         break;
0039     case KateVi::VisualBlockMode:
0040         modeStr = i18n("VI: VISUAL BLOCK");
0041         break;
0042     case KateVi::VisualLineMode:
0043         modeStr = i18n("VI: VISUAL LINE");
0044         break;
0045     case KateVi::ReplaceMode:
0046         modeStr = i18n("VI: REPLACE");
0047         break;
0048     }
0049 
0050     return modeStr;
0051 }
0052 }
0053 
0054 KateViInputMode::KateViInputMode(KateViewInternal *viewInternal, KateVi::GlobalState *global)
0055     : KateAbstractInputMode(viewInternal)
0056     , m_viModeEmulatedCommandBar(nullptr)
0057     , m_viGlobal(global)
0058     , m_caret(KTextEditor::caretStyles::Block)
0059     , m_nextKeypressIsOverriddenShortCut(false)
0060     , m_relLineNumbers(KateViewConfig::global()->viRelativeLineNumbers())
0061     , m_activated(false)
0062     , m_viModeManager(new KateVi::InputModeManager(this, view(), viewInternal))
0063 {
0064 }
0065 
0066 void KateViInputMode::activate()
0067 {
0068     m_activated = true;
0069     setCaretStyle(KTextEditor::caretStyles::Block); // TODO: can we end up in insert mode?
0070     reset(); // TODO: is this necessary? (well, not anymore I guess)
0071 
0072     if (view()->selection()) {
0073         m_viModeManager->changeViMode(KateVi::VisualMode);
0074         view()->setCursorPosition(KTextEditor::Cursor(view()->selectionRange().end().line(), view()->selectionRange().end().column() - 1));
0075         m_viModeManager->m_viVisualMode->updateSelection();
0076     }
0077     viewInternal()->iconBorder()->setRelLineNumbersOn(m_relLineNumbers);
0078 }
0079 
0080 void KateViInputMode::deactivate()
0081 {
0082     if (m_viModeEmulatedCommandBar) {
0083         m_viModeEmulatedCommandBar->hideMe();
0084     }
0085 
0086     // make sure to turn off edits merging when leaving vi input mode
0087     view()->doc()->setUndoMergeAllEdits(false);
0088     m_activated = false;
0089     viewInternal()->iconBorder()->setRelLineNumbersOn(false);
0090     m_viModeManager->searcher()->enableHighlightSearch(false);
0091 }
0092 
0093 void KateViInputMode::reset()
0094 {
0095     if (m_viModeEmulatedCommandBar) {
0096         m_viModeEmulatedCommandBar->hideMe();
0097     }
0098 
0099     // ensure first the old stuff is deleted and then the new manager is constructed
0100     m_viModeManager.reset();
0101     m_viModeManager.reset(new KateVi::InputModeManager(this, view(), viewInternal()));
0102 
0103     if (m_viModeEmulatedCommandBar) {
0104         m_viModeEmulatedCommandBar->setViInputModeManager(m_viModeManager.get());
0105     }
0106 }
0107 
0108 bool KateViInputMode::overwrite() const
0109 {
0110     return m_viModeManager->getCurrentViMode() == KateVi::ViMode::ReplaceMode;
0111 }
0112 
0113 void KateViInputMode::overwrittenChar(const QChar &c)
0114 {
0115     m_viModeManager->getViReplaceMode()->overwrittenChar(c);
0116 }
0117 
0118 void KateViInputMode::clearSelection()
0119 {
0120     // do nothing, handled elsewhere
0121 }
0122 
0123 bool KateViInputMode::stealKey(QKeyEvent *k)
0124 {
0125     if (!KateViewConfig::global()->viInputModeStealKeys()) {
0126         return false;
0127     }
0128 
0129     // Actually see if we can make use of this key - if so, we've stolen it; if not,
0130     // let Qt's shortcut handling system deal with it.
0131     const bool stolen = keyPress(k);
0132     if (stolen) {
0133         // Qt will replay this QKeyEvent, next time as an ordinary KeyPress.
0134         m_nextKeypressIsOverriddenShortCut = true;
0135     }
0136     return stolen;
0137 }
0138 
0139 KTextEditor::View::InputMode KateViInputMode::viewInputMode() const
0140 {
0141     return KTextEditor::View::ViInputMode;
0142 }
0143 
0144 QString KateViInputMode::viewInputModeHuman() const
0145 {
0146     return i18n("vi-mode");
0147 }
0148 
0149 KTextEditor::View::ViewMode KateViInputMode::viewMode() const
0150 {
0151     return m_viModeManager->getCurrentViewMode();
0152 }
0153 
0154 QString KateViInputMode::viewModeHuman() const
0155 {
0156     QString currentMode = viModeToString(m_viModeManager->getCurrentViMode());
0157 
0158     if (m_viModeManager->macroRecorder()->isRecording()) {
0159         currentMode.prepend(QLatin1Char('(') + i18n("recording") + QLatin1String(") "));
0160     }
0161 
0162     QString cmd = m_viModeManager->getVerbatimKeys();
0163     if (!cmd.isEmpty()) {
0164         currentMode.prepend(QStringLiteral("%1 ").arg(cmd));
0165     }
0166 
0167     return currentMode;
0168 }
0169 
0170 void KateViInputMode::gotFocus()
0171 {
0172     // nothing to do
0173 }
0174 
0175 void KateViInputMode::lostFocus()
0176 {
0177     // nothing to do
0178 }
0179 
0180 void KateViInputMode::readSessionConfig(const KConfigGroup &config)
0181 {
0182     // restore vi registers and jump list
0183     m_viModeManager->readSessionConfig(config);
0184 }
0185 
0186 void KateViInputMode::writeSessionConfig(KConfigGroup &config)
0187 {
0188     // save vi registers and jump list
0189     m_viModeManager->writeSessionConfig(config);
0190 }
0191 
0192 void KateViInputMode::updateConfig()
0193 {
0194     KateViewConfig *cfg = view()->config();
0195 
0196     // whether relative line numbers should be used or not.
0197     m_relLineNumbers = cfg->viRelativeLineNumbers();
0198 
0199     if (m_activated) {
0200         viewInternal()->iconBorder()->setRelLineNumbersOn(m_relLineNumbers);
0201     }
0202 }
0203 
0204 void KateViInputMode::readWriteChanged(bool)
0205 {
0206     // nothing todo
0207 }
0208 
0209 void KateViInputMode::find()
0210 {
0211     showViModeEmulatedCommandBar();
0212     viModeEmulatedCommandBar()->init(KateVi::EmulatedCommandBar::SearchForward);
0213 }
0214 
0215 void KateViInputMode::findSelectedForwards()
0216 {
0217     m_viModeManager->searcher()->findNext();
0218 }
0219 
0220 void KateViInputMode::findSelectedBackwards()
0221 {
0222     m_viModeManager->searcher()->findPrevious();
0223 }
0224 
0225 void KateViInputMode::findReplace()
0226 {
0227     showViModeEmulatedCommandBar();
0228     viModeEmulatedCommandBar()->init(KateVi::EmulatedCommandBar::SearchForward);
0229 }
0230 
0231 void KateViInputMode::findNext()
0232 {
0233     m_viModeManager->searcher()->findNext();
0234 }
0235 
0236 void KateViInputMode::findPrevious()
0237 {
0238     m_viModeManager->searcher()->findPrevious();
0239 }
0240 
0241 void KateViInputMode::activateCommandLine()
0242 {
0243     showViModeEmulatedCommandBar();
0244     viModeEmulatedCommandBar()->init(KateVi::EmulatedCommandBar::Command);
0245 }
0246 
0247 void KateViInputMode::showViModeEmulatedCommandBar()
0248 {
0249     view()->bottomViewBar()->addBarWidget(viModeEmulatedCommandBar());
0250     view()->bottomViewBar()->showBarWidget(viModeEmulatedCommandBar());
0251 }
0252 
0253 KateVi::EmulatedCommandBar *KateViInputMode::viModeEmulatedCommandBar()
0254 {
0255     if (!m_viModeEmulatedCommandBar) {
0256         m_viModeEmulatedCommandBar = new KateVi::EmulatedCommandBar(this, m_viModeManager.get(), view());
0257         m_viModeEmulatedCommandBar->hide();
0258     }
0259 
0260     return m_viModeEmulatedCommandBar;
0261 }
0262 
0263 void KateViInputMode::updateRendererConfig()
0264 {
0265     m_viModeManager->searcher()->updateHighlightColors();
0266 }
0267 
0268 bool KateViInputMode::keyPress(QKeyEvent *e)
0269 {
0270     if (m_nextKeypressIsOverriddenShortCut) {
0271         // This is just the replay of a shortcut that we stole, this time as a QKeyEvent.
0272         // Ignore it, as we'll have already handled it via stealKey()!
0273         m_nextKeypressIsOverriddenShortCut = false;
0274         return true;
0275     }
0276 
0277     if (m_viModeManager->handleKeypress(e)) {
0278         Q_EMIT view()->viewModeChanged(view(), viewMode());
0279         return true;
0280     }
0281 
0282     return false;
0283 }
0284 
0285 bool KateViInputMode::blinkCaret() const
0286 {
0287     return false;
0288 }
0289 
0290 KTextEditor::caretStyles KateViInputMode::caretStyle() const
0291 {
0292     return m_caret;
0293 }
0294 
0295 void KateViInputMode::toggleInsert()
0296 {
0297     // do nothing
0298 }
0299 
0300 void KateViInputMode::launchInteractiveCommand(const QString &)
0301 {
0302     // do nothing so far
0303 }
0304 
0305 QString KateViInputMode::bookmarkLabel(int line) const
0306 {
0307     return m_viModeManager->marks()->getMarksOnTheLine(line);
0308 }
0309 
0310 void KateViInputMode::setCaretStyle(const KTextEditor::caretStyles caret)
0311 {
0312     if (m_caret != caret) {
0313         m_caret = caret;
0314 
0315         view()->renderer()->setCaretStyle(m_caret);
0316         view()->renderer()->setDrawCaret(true);
0317         viewInternal()->paintCursor();
0318     }
0319 }