1 | /* |
2 | SPDX-FileCopyrightText: 2008-2009 Erlend Hamberg <ehamberg@gmail.com> |
3 | SPDX-FileCopyrightText: 2009 Paul Gideon Dann <pdgiddie@gmail.com> |
4 | SPDX-FileCopyrightText: 2011 Svyatoslav Kuzmich <svatoslav1@gmail.com> |
5 | SPDX-FileCopyrightText: 2012-2013 Simon St James <kdedevel@etotheipiplusone.com> |
6 | |
7 | SPDX-License-Identifier: LGPL-2.0-or-later |
8 | */ |
9 | |
10 | #ifndef KATEVI_NORMAL_VI_MODE_H |
11 | #define KATEVI_NORMAL_VI_MODE_H |
12 | |
13 | #include <vimode/command.h> |
14 | #include <vimode/modes/modebase.h> |
15 | #include <vimode/motion.h> |
16 | #include <vimode/range.h> |
17 | |
18 | #include <QHash> |
19 | #include <QList> |
20 | #include <QRegularExpression> |
21 | #include <QStack> |
22 | |
23 | #include <vector> |
24 | |
25 | #include <ktexteditor/range.h> |
26 | |
27 | class QKeyEvent; |
28 | class KateViInputMode; |
29 | |
30 | namespace KateVi |
31 | { |
32 | class KeyParser; |
33 | class InputModeManager; |
34 | |
35 | /** |
36 | * Commands for the vi normal mode |
37 | */ |
38 | class NormalViMode : public ModeBase |
39 | { |
40 | friend KateViInputMode; |
41 | |
42 | public: |
43 | explicit NormalViMode(InputModeManager *viInputModeManager, KTextEditor::ViewPrivate *view, KateViewInternal *viewInternal); |
44 | ~NormalViMode() override; |
45 | |
46 | bool handleKeypress(const QKeyEvent *e) override; |
47 | |
48 | bool commandEnterInsertMode(); |
49 | bool commandEnterInsertModeAppend(); |
50 | bool commandEnterInsertModeAppendEOL(); |
51 | bool commandEnterInsertModeBeforeFirstNonBlankInLine(); |
52 | bool commandEnterInsertModeLast(); |
53 | |
54 | bool commandEnterVisualMode(); |
55 | bool commandEnterVisualLineMode(); |
56 | bool commandEnterVisualBlockMode(); |
57 | bool commandReselectVisual(); |
58 | bool commandToOtherEnd(); |
59 | |
60 | bool commandEnterReplaceMode(); |
61 | |
62 | bool commandDelete(); |
63 | bool commandDeleteToEOL(); |
64 | bool commandDeleteLine(); |
65 | |
66 | bool commandMakeLowercase(); |
67 | bool commandMakeLowercaseLine(); |
68 | bool commandMakeUppercase(); |
69 | bool commandMakeUppercaseLine(); |
70 | bool commandChangeCase(); |
71 | bool commandChangeCaseRange(); |
72 | bool commandChangeCaseLine(); |
73 | |
74 | bool commandOpenNewLineUnder(); |
75 | bool commandOpenNewLineOver(); |
76 | |
77 | bool commandJoinLines(); |
78 | |
79 | bool commandChange(); |
80 | bool commandChangeLine(); |
81 | bool commandChangeToEOL(); |
82 | bool commandSubstituteChar(); |
83 | bool commandSubstituteLine(); |
84 | |
85 | bool commandYank(); |
86 | bool commandYankLine(); |
87 | bool commandYankToEOL(); |
88 | |
89 | bool commandPaste(); |
90 | bool commandPasteBefore(); |
91 | |
92 | bool commandgPaste(); |
93 | bool commandgPasteBefore(); |
94 | |
95 | bool commandIndentedPaste(); |
96 | bool commandIndentedPasteBefore(); |
97 | |
98 | bool commandDeleteChar(); |
99 | bool commandDeleteCharBackward(); |
100 | |
101 | bool commandReplaceCharacter(); |
102 | |
103 | bool commandSwitchToCmdLine(); |
104 | bool commandSearchBackward(); |
105 | bool commandSearchForward(); |
106 | bool commandUndo(); |
107 | bool commandRedo(); |
108 | |
109 | bool commandSetMark(); |
110 | |
111 | bool commandIndentLine(); |
112 | bool commandUnindentLine(); |
113 | bool commandIndentLines(); |
114 | bool commandUnindentLines(); |
115 | |
116 | bool commandScrollPageDown(); |
117 | bool commandScrollPageUp(); |
118 | bool commandScrollHalfPageUp(); |
119 | bool commandScrollHalfPageDown(); |
120 | |
121 | bool commandCenterView(bool onFirst); |
122 | bool commandCenterViewOnNonBlank(); |
123 | bool commandCenterViewOnCursor(); |
124 | bool commandTopView(bool onFirst); |
125 | bool commandTopViewOnNonBlank(); |
126 | bool commandTopViewOnCursor(); |
127 | bool commandBottomView(bool onFirst); |
128 | bool commandBottomViewOnNonBlank(); |
129 | bool commandBottomViewOnCursor(); |
130 | |
131 | bool commandAbort(); |
132 | |
133 | bool commandPrintCharacterCode(); |
134 | |
135 | bool commandRepeatLastChange(); |
136 | |
137 | bool commandAlignLine(); |
138 | bool commandAlignLines(); |
139 | |
140 | bool commandAddToNumber(); |
141 | bool commandSubtractFromNumber(); |
142 | |
143 | bool commandPrependToBlock(); |
144 | bool commandAppendToBlock(); |
145 | |
146 | bool commandGoToNextJump(); |
147 | bool commandGoToPrevJump(); |
148 | |
149 | bool commandSwitchToLeftView(); |
150 | bool commandSwitchToUpView(); |
151 | bool commandSwitchToDownView(); |
152 | bool commandSwitchToRightView(); |
153 | bool commandSwitchToNextView(); |
154 | |
155 | bool commandSplitHoriz(); |
156 | bool commandSplitVert(); |
157 | bool commandCloseView(); |
158 | |
159 | bool commandSwitchToNextTab(); |
160 | bool commandSwitchToPrevTab(); |
161 | |
162 | bool commandFormatLine(); |
163 | bool commandFormatLines(); |
164 | |
165 | bool commandCollapseToplevelNodes(); |
166 | bool commandCollapseLocal(); |
167 | bool commandExpandAll(); |
168 | bool commandExpandLocal(); |
169 | bool commandToggleRegionVisibility(); |
170 | |
171 | bool commandStartRecordingMacro(); |
172 | bool commandReplayMacro(); |
173 | |
174 | bool commandCloseWrite(); |
175 | bool commandCloseNocheck(); |
176 | |
177 | // MOTIONS |
178 | |
179 | Range motionLeft(); |
180 | Range motionRight(); |
181 | Range motionDown(); |
182 | Range motionUp(); |
183 | |
184 | Range motionPageDown(); |
185 | Range motionPageUp(); |
186 | Range motionHalfPageDown(); |
187 | Range motionHalfPageUp(); |
188 | |
189 | Range motionUpToFirstNonBlank(); |
190 | Range motionDownToFirstNonBlank(); |
191 | |
192 | Range motionWordForward(); |
193 | Range motionWordBackward(); |
194 | Range motionWORDForward(); |
195 | Range motionWORDBackward(); |
196 | |
197 | Range motionToEndOfWord(); |
198 | Range motionToEndOfWORD(); |
199 | Range motionToEndOfPrevWord(); |
200 | Range motionToEndOfPrevWORD(); |
201 | |
202 | Range motionFindChar(); |
203 | Range motionFindCharBackward(); |
204 | Range motionToChar(); |
205 | Range motionToCharBackward(); |
206 | Range motionRepeatlastTF(); |
207 | Range motionRepeatlastTFBackward(); |
208 | |
209 | Range motionToEOL(); |
210 | Range motionToLastNonBlank(); |
211 | Range motionToColumn0(); |
212 | Range motionToFirstCharacterOfLine(); |
213 | |
214 | Range motionToLineFirst(); |
215 | Range motionToLineLast(); |
216 | |
217 | Range motionToScreenColumn(); |
218 | |
219 | Range motionToMark(); |
220 | Range motionToMarkLine(); |
221 | |
222 | Range motionToMatchingItem(); |
223 | |
224 | Range motionToPreviousBraceBlockStart(); |
225 | Range motionToNextBraceBlockStart(); |
226 | Range motionToPreviousBraceBlockEnd(); |
227 | Range motionToNextBraceBlockEnd(); |
228 | |
229 | Range motionToNextOccurrence(); |
230 | Range motionToPrevOccurrence(); |
231 | |
232 | Range motionToFirstLineOfWindow(); |
233 | Range motionToMiddleLineOfWindow(); |
234 | Range motionToLastLineOfWindow(); |
235 | |
236 | Range motionToNextVisualLine(); |
237 | Range motionToPrevVisualLine(); |
238 | |
239 | Range motionToPreviousSentence(); |
240 | Range motionToNextSentence(); |
241 | |
242 | Range motionToBeforeParagraph(); |
243 | Range motionToAfterParagraph(); |
244 | |
245 | Range motionToIncrementalSearchMatch(); |
246 | |
247 | // TEXT OBJECTS |
248 | |
249 | Range textObjectAWord(); |
250 | Range textObjectInnerWord(); |
251 | Range textObjectAWORD(); |
252 | Range textObjectInnerWORD(); |
253 | |
254 | Range textObjectInnerSentence(); |
255 | Range textObjectASentence(); |
256 | |
257 | Range textObjectInnerParagraph(); |
258 | Range textObjectAParagraph(); |
259 | |
260 | Range textObjectAQuoteDouble(); |
261 | Range textObjectInnerQuoteDouble(); |
262 | |
263 | Range textObjectAQuoteSingle(); |
264 | Range textObjectInnerQuoteSingle(); |
265 | |
266 | Range textObjectABackQuote(); |
267 | Range textObjectInnerBackQuote(); |
268 | |
269 | Range textObjectAParen(); |
270 | Range textObjectInnerParen(); |
271 | |
272 | Range textObjectABracket(); |
273 | Range textObjectInnerBracket(); |
274 | |
275 | Range textObjectACurlyBracket(); |
276 | Range textObjectInnerCurlyBracket(); |
277 | |
278 | Range textObjectAInequalitySign(); |
279 | Range textObjectInnerInequalitySign(); |
280 | |
281 | Range textObjectAComma(); |
282 | Range textObjectInnerComma(); |
283 | |
284 | virtual void reset(); |
285 | |
286 | void beginMonitoringDocumentChanges(); |
287 | |
288 | protected: |
289 | void resetParser(); |
290 | QRegularExpression generateMatchingItemRegex() const; |
291 | void executeCommand(const Command *cmd); |
292 | OperationMode getOperationMode() const; |
293 | |
294 | void highlightYank(const Range &range, const OperationMode mode = CharWise); |
295 | void addHighlightYank(KTextEditor::Range range); |
296 | |
297 | bool motionWillBeUsedWithCommand() const |
298 | { |
299 | return !m_awaitingMotionOrTextObject.isEmpty(); |
300 | }; |
301 | |
302 | void joinLines(unsigned int from, unsigned int to) const; |
303 | void reformatLines(unsigned int from, unsigned int to) const; |
304 | bool executeKateCommand(const QString &command); |
305 | |
306 | /** |
307 | * Get the index of the first non-blank character from the given line. |
308 | * |
309 | * @param line The line to be picked. The current line will picked instead |
310 | * if this parameter is set to a negative value. |
311 | * @returns the index of the first non-blank character from the given line. |
312 | * If a non-space character cannot be found, the 0 is returned. |
313 | */ |
314 | int getFirstNonBlank(int line = -1) const; |
315 | |
316 | Range textObjectComma(bool inner) const; |
317 | void shrinkRangeAroundCursor(Range &toShrink, const Range &rangeToShrinkTo) const; |
318 | KTextEditor::Cursor findSentenceStart(); |
319 | KTextEditor::Cursor findSentenceEnd(); |
320 | KTextEditor::Cursor findParagraphStart(); |
321 | KTextEditor::Cursor findParagraphEnd(); |
322 | |
323 | /** |
324 | * Return commands available for this mode. |
325 | * Overwritten in sub classes to replace them, must be a stable reference! |
326 | */ |
327 | virtual const std::vector<Command> &commands(); |
328 | |
329 | /** |
330 | * Return motions available for this mode. |
331 | * Overwritten in sub classes to replace them, must be a stable reference! |
332 | */ |
333 | virtual const std::vector<Motion> &motions(); |
334 | |
335 | protected: |
336 | // The 'current position' is the current cursor position for non-linewise pastes, and the current |
337 | // line for linewise. |
338 | enum PasteLocation { AtCurrentPosition, AfterCurrentPosition }; |
339 | bool paste(NormalViMode::PasteLocation pasteLocation, bool isgPaste, bool isIndentedPaste); |
340 | static KTextEditor::Cursor cursorPosAtEndOfPaste(const KTextEditor::Cursor pasteLocation, const QString &pastedText); |
341 | |
342 | // set sticky column to a ridiculously high value so that the cursor will stick to EOL, |
343 | // but only if it's a regular motion |
344 | void stickStickyColumnToEOL(); |
345 | |
346 | protected: |
347 | QString m_keys; |
348 | QString m_lastTFcommand; // holds the last t/T/f/F command so that it can be repeated with ;/, |
349 | |
350 | unsigned int m_countTemp; |
351 | int m_motionOperatorIndex; |
352 | int m_scroll_count_limit; |
353 | |
354 | QList<int> m_matchingCommands; |
355 | QList<int> m_matchingMotions; |
356 | QStack<int> m_awaitingMotionOrTextObject; |
357 | |
358 | bool m_findWaitingForChar; |
359 | bool m_isRepeatedTFcommand; |
360 | bool m_linewiseCommand; |
361 | bool m_commandWithMotion; |
362 | bool m_lastMotionWasLinewiseInnerBlock; |
363 | bool m_motionCanChangeWholeVisualModeSelection; |
364 | bool m_commandShouldKeepSelection; |
365 | bool m_deleteCommand; |
366 | // Ctrl-c or ESC have been pressed, leading to a call to reset(). |
367 | bool m_pendingResetIsDueToExit; |
368 | bool m_isUndo; |
369 | bool waitingForRegisterOrCharToSearch(); |
370 | |
371 | // item matching ('%' motion) |
372 | QHash<QString, QString> m_matchingItems; |
373 | QRegularExpression m_matchItemRegex; |
374 | |
375 | KeyParser *m_keyParser; |
376 | |
377 | KTextEditor::Attribute::Ptr m_highlightYankAttribute; |
378 | QSet<KTextEditor::MovingRange *> m_highlightedYanks; |
379 | QSet<KTextEditor::MovingRange *> &highlightedYankForDocument(); |
380 | |
381 | KTextEditor::Cursor m_currentChangeEndMarker; |
382 | KTextEditor::Cursor m_positionWhenIncrementalSearchBegan; |
383 | |
384 | private: |
385 | void textInserted(KTextEditor::Document *document, KTextEditor::Range range); |
386 | void textRemoved(KTextEditor::Document *, KTextEditor::Range); |
387 | void undoBeginning(); |
388 | void undoEnded(); |
389 | |
390 | void updateYankHighlightAttrib(); |
391 | void clearYankHighlight(); |
392 | void aboutToDeleteMovingInterfaceContent(); |
393 | }; |
394 | } |
395 | |
396 | #endif /* KATEVI_NORMAL_VI_MODE_H */ |
397 | |