File indexing completed on 2024-05-12 11:58:35
0001 /* 0002 SPDX-FileCopyrightText: 2008 Erlend Hamberg <ehamberg@gmail.com> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 #include "katedocument.h" 0007 #include "kateviinputmode.h" 0008 0009 #include <utils/kateconfig.h> 0010 #include <view/kateviewinternal.h> 0011 #include <vimode/emulatedcommandbar/emulatedcommandbar.h> 0012 #include <vimode/inputmodemanager.h> 0013 #include <vimode/marks.h> 0014 #include <vimode/modes/replacevimode.h> 0015 0016 using namespace KateVi; 0017 0018 ReplaceViMode::ReplaceViMode(InputModeManager *viInputModeManager, KTextEditor::ViewPrivate *view, KateViewInternal *viewInternal) 0019 : ModeBase() 0020 { 0021 m_view = view; 0022 m_viewInternal = viewInternal; 0023 m_viInputModeManager = viInputModeManager; 0024 m_count = 1; 0025 } 0026 0027 bool ReplaceViMode::commandInsertFromLine(int offset) 0028 { 0029 KTextEditor::Cursor c(m_view->cursorPosition()); 0030 0031 if (c.line() + offset >= doc()->lines() || c.line() + offset < 0) { 0032 return false; 0033 } 0034 0035 // Fetch the new character from the specified line. 0036 KTextEditor::Cursor target(c.line() + offset, c.column()); 0037 QChar ch = doc()->characterAt(target); 0038 if (ch == QChar::Null) { 0039 return false; 0040 } 0041 0042 // The cursor is at the end of the line: just append the char. 0043 if (c.column() == doc()->lineLength(c.line())) { 0044 return doc()->insertText(c, ch); 0045 } 0046 0047 // We can replace the current one with the fetched character. 0048 KTextEditor::Cursor next(c.line(), c.column() + 1); 0049 QChar removed = doc()->line(c.line()).at(c.column()); 0050 if (doc()->replaceText(KTextEditor::Range(c, next), ch)) { 0051 overwrittenChar(removed); 0052 return true; 0053 } 0054 return false; 0055 } 0056 0057 bool ReplaceViMode::commandMoveOneWordLeft() 0058 { 0059 KTextEditor::Cursor c(m_view->cursorPosition()); 0060 c = findPrevWordStart(c.line(), c.column()); 0061 0062 if (!c.isValid()) { 0063 c = KTextEditor::Cursor(0, 0); 0064 } 0065 0066 updateCursor(c); 0067 return true; 0068 } 0069 0070 bool ReplaceViMode::commandMoveOneWordRight() 0071 { 0072 KTextEditor::Cursor c(m_view->cursorPosition()); 0073 c = findNextWordStart(c.line(), c.column()); 0074 0075 if (!c.isValid()) { 0076 c = doc()->documentEnd(); 0077 } 0078 0079 updateCursor(c); 0080 return true; 0081 } 0082 0083 bool ReplaceViMode::handleKeypress(const QKeyEvent *e) 0084 { 0085 // backspace should work even if the shift key is down 0086 if (e->modifiers() != CONTROL_MODIFIER && e->key() == Qt::Key_Backspace) { 0087 backspace(); 0088 return true; 0089 } 0090 0091 // on macOS the KeypadModifier is set for the arrow keys too 0092 if (e->modifiers() == Qt::NoModifier || e->modifiers() == Qt::KeypadModifier) { 0093 switch (e->key()) { 0094 case Qt::Key_Escape: 0095 m_overwritten.clear(); 0096 leaveReplaceMode(); 0097 return true; 0098 case Qt::Key_Left: 0099 m_overwritten.clear(); 0100 m_view->cursorLeft(); 0101 return true; 0102 case Qt::Key_Right: 0103 m_overwritten.clear(); 0104 m_view->cursorRight(); 0105 return true; 0106 case Qt::Key_Up: 0107 m_overwritten.clear(); 0108 m_view->up(); 0109 return true; 0110 case Qt::Key_Down: 0111 m_overwritten.clear(); 0112 m_view->down(); 0113 return true; 0114 case Qt::Key_Home: 0115 m_overwritten.clear(); 0116 m_view->home(); 0117 return true; 0118 case Qt::Key_End: 0119 m_overwritten.clear(); 0120 m_view->end(); 0121 return true; 0122 case Qt::Key_PageUp: 0123 m_overwritten.clear(); 0124 m_view->pageUp(); 0125 return true; 0126 case Qt::Key_PageDown: 0127 m_overwritten.clear(); 0128 m_view->pageDown(); 0129 return true; 0130 case Qt::Key_Delete: 0131 m_view->keyDelete(); 0132 return true; 0133 case Qt::Key_Insert: 0134 startInsertMode(); 0135 return true; 0136 case Qt::Key_Enter: 0137 case Qt::Key_Return: 0138 if (m_viInputModeManager->inputAdapter()->viModeEmulatedCommandBar()->isSendingSyntheticSearchCompletedKeypress()) { 0139 // BUG #451076, Do not record/send return for a newline when doing a search via Ctrl+F/Edit->Find menu 0140 m_viInputModeManager->doNotLogCurrentKeypress(); 0141 return true; 0142 } 0143 Q_FALLTHROUGH(); 0144 default: 0145 return false; 0146 } 0147 } else if (e->modifiers() == CONTROL_MODIFIER) { 0148 switch (e->key()) { 0149 case Qt::Key_BracketLeft: 0150 case Qt::Key_C: 0151 startNormalMode(); 0152 return true; 0153 case Qt::Key_E: 0154 commandInsertFromLine(1); 0155 return true; 0156 case Qt::Key_Y: 0157 commandInsertFromLine(-1); 0158 return true; 0159 case Qt::Key_W: 0160 commandBackWord(); 0161 return true; 0162 case Qt::Key_U: 0163 commandBackLine(); 0164 return true; 0165 case Qt::Key_Left: 0166 m_overwritten.clear(); 0167 commandMoveOneWordLeft(); 0168 return true; 0169 case Qt::Key_Right: 0170 m_overwritten.clear(); 0171 commandMoveOneWordRight(); 0172 return true; 0173 default: 0174 return false; 0175 } 0176 } 0177 0178 return false; 0179 } 0180 0181 void ReplaceViMode::backspace() 0182 { 0183 KTextEditor::Cursor c1(m_view->cursorPosition()); 0184 KTextEditor::Cursor c2(c1.line(), c1.column() - 1); 0185 0186 if (c1.column() > 0) { 0187 if (!m_overwritten.isEmpty()) { 0188 doc()->removeText(KTextEditor::Range(c1.line(), c1.column() - 1, c1.line(), c1.column())); 0189 doc()->insertText(c2, m_overwritten.right(1)); 0190 m_overwritten.remove(m_overwritten.length() - 1, 1); 0191 } 0192 updateCursor(c2); 0193 } 0194 } 0195 0196 void ReplaceViMode::commandBackWord() 0197 { 0198 KTextEditor::Cursor current(m_view->cursorPosition()); 0199 KTextEditor::Cursor to(findPrevWordStart(current.line(), current.column())); 0200 0201 if (!to.isValid()) { 0202 return; 0203 } 0204 0205 while (current.isValid() && current != to) { 0206 backspace(); 0207 current = m_view->cursorPosition(); 0208 } 0209 } 0210 0211 void ReplaceViMode::commandBackLine() 0212 { 0213 const int column = m_view->cursorPosition().column(); 0214 0215 for (int i = column; i >= 0 && !m_overwritten.isEmpty(); i--) { 0216 backspace(); 0217 } 0218 } 0219 0220 void ReplaceViMode::leaveReplaceMode() 0221 { 0222 // Redo replacement operation <count> times 0223 m_view->abortCompletion(); 0224 0225 if (m_count > 1) { 0226 // Look at added text so that we can repeat the addition 0227 const QString added = doc()->text(KTextEditor::Range(m_viInputModeManager->marks()->getStartEditYanked(), m_view->cursorPosition())); 0228 for (unsigned int i = 0; i < m_count - 1; i++) { 0229 KTextEditor::Cursor c(m_view->cursorPosition()); 0230 KTextEditor::Cursor c2(c.line(), c.column() + added.length()); 0231 doc()->replaceText(KTextEditor::Range(c, c2), added); 0232 } 0233 } 0234 0235 startNormalMode(); 0236 }