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