KTextEditor

cmds.cpp
1/*
2 SPDX-FileCopyrightText: 2003-2005 Anders Lund <anders@alweb.dk>
3 SPDX-FileCopyrightText: 2001-2010 Christoph Cullmann <cullmann@kde.org>
4 SPDX-FileCopyrightText: 2001 Charles Samuels <charles@kde.org>
5
6 SPDX-License-Identifier: LGPL-2.0-or-later
7*/
8
9#include <vimode/cmds.h>
10
11#include "globalstate.h"
12#include "katecmd.h"
13#include "kateview.h"
14#include "kateviinputmode.h"
15#include "marks.h"
16#include <vimode/emulatedcommandbar/emulatedcommandbar.h>
17#include <vimode/inputmodemanager.h>
18#include <vimode/modes/normalvimode.h>
19#include <vimode/searcher.h>
20
21#include <KLocalizedString>
22
23#include <QRegularExpression>
24
25using namespace KateVi;
26
27// BEGIN ViCommands
28Commands *Commands::m_instance = nullptr;
29
30bool Commands::exec(KTextEditor::View *view, const QString &_cmd, QString &msg, const KTextEditor::Range &range)
31{
32 Q_UNUSED(range)
33 // cast it hardcore, we know that it is really a kateview :)
34 KTextEditor::ViewPrivate *v = static_cast<KTextEditor::ViewPrivate *>(view);
35
36 if (!v) {
37 msg = i18n("Could not access view");
38 return false;
39 }
40
41 // create a list of args
42 QStringList args(_cmd.split(QRegularExpression(QStringLiteral("\\s+")), Qt::SkipEmptyParts));
43 QString cmd(args.takeFirst());
44
45 // ALL commands that takes no arguments.
46 if (mappingCommands().contains(cmd)) {
47 if (cmd.endsWith(QLatin1String("unmap"))) {
48 if (args.count() == 1) {
49 m_viInputModeManager->globalState()->mappings()->remove(modeForMapCommand(cmd), args.at(0));
50 return true;
51 } else {
52 msg = i18n("Missing argument. Usage: %1 <from>", cmd);
53 return false;
54 }
55 } else if (cmd == QLatin1String("nohlsearch") || cmd == QLatin1String("noh")) {
56 m_viInputModeManager->searcher()->hideCurrentHighlight();
57 return true;
58 } else if (cmd == QLatin1String("set-hlsearch") || cmd == QLatin1String("set-hls")) {
59 m_viInputModeManager->searcher()->enableHighlightSearch(true);
60 return true;
61 } else if (cmd == QLatin1String("set-nohlsearch") || cmd == QLatin1String("set-nohls")) {
62 m_viInputModeManager->searcher()->enableHighlightSearch(false);
63 return true;
64 }
65 if (args.count() == 1) {
66 msg = m_viInputModeManager->globalState()->mappings()->get(modeForMapCommand(cmd), args.at(0), true);
67 if (msg.isEmpty()) {
68 msg = i18n("No mapping found for \"%1\"", args.at(0));
69 return false;
70 } else {
71 msg = i18n("\"%1\" is mapped to \"%2\"", args.at(0), msg);
72 }
73 } else if (args.count() == 2) {
74 Mappings::MappingRecursion mappingRecursion = (isMapCommandRecursive(cmd)) ? Mappings::Recursive : Mappings::NonRecursive;
75 m_viInputModeManager->globalState()->mappings()->add(modeForMapCommand(cmd), args.at(0), args.at(1), mappingRecursion);
76 } else {
77 msg = i18n("Missing argument(s). Usage: %1 <from> [<to>]", cmd);
78 return false;
79 }
80
81 return true;
82 }
83
84 NormalViMode *nm = m_viInputModeManager->getViNormalMode();
85
86 if (cmd == QLatin1String("d") || cmd == QLatin1String("delete") || cmd == QLatin1String("j") || cmd == QLatin1String("c") || cmd == QLatin1String("change")
87 || cmd == QLatin1String("<") || cmd == QLatin1String(">") || cmd == QLatin1String("y") || cmd == QLatin1String("yank")) {
88 KTextEditor::Cursor start_cursor_position = v->cursorPosition();
89
90 int count = 1;
91 if (range.isValid()) {
92 count = qAbs(range.end().line() - range.start().line()) + 1;
93 v->setCursorPosition(KTextEditor::Cursor(qMin(range.start().line(), range.end().line()), 0));
94 }
95
96 static const QRegularExpression number(QStringLiteral("^(\\d+)$"));
97 for (int i = 0; i < args.count(); i++) {
98 auto match = number.match(args.at(i));
99 if (match.hasMatch()) {
100 count += match.captured(0).toInt() - 1;
101 }
102
103 QChar r = args.at(i).at(0);
104 if (args.at(i).size() == 1
105 && ((r >= QLatin1Char('a') && r <= QLatin1Char('z')) || r == QLatin1Char('_') || r == QLatin1Char('-') || r == QLatin1Char('+')
106 || r == QLatin1Char('*'))) {
107 nm->setRegister(r);
108 }
109 }
110
111 nm->setCount(count);
112
113 if (cmd == QLatin1String("d") || cmd == QLatin1String("delete")) {
114 nm->commandDeleteLine();
115 }
116 if (cmd == QLatin1String("j")) {
117 nm->commandJoinLines();
118 }
119 if (cmd == QLatin1String("c") || cmd == QLatin1String("change")) {
120 nm->commandChangeLine();
121 }
122 if (cmd == QLatin1String("<")) {
123 nm->commandUnindentLine();
124 }
125 if (cmd == QLatin1String(">")) {
126 nm->commandIndentLine();
127 }
128 if (cmd == QLatin1String("y") || cmd == QLatin1String("yank")) {
129 nm->commandYankLine();
130 v->setCursorPosition(start_cursor_position);
131 }
132
133 // TODO - should we resetParser, here? We'd have to make it public, if so.
134 // Or maybe synthesise a KateViCommand to execute instead ... ?
135 nm->setCount(0);
136
137 return true;
138 }
139
140 if (cmd == QLatin1String("mark") || cmd == QLatin1String("ma") || cmd == QLatin1String("k")) {
141 if (args.count() == 0) {
142 if (cmd == QLatin1String("mark")) {
143 // TODO: show up mark list;
144 } else {
145 msg = i18n("Wrong arguments");
146 return false;
147 }
148 } else if (args.count() == 1) {
149 QChar r = args.at(0).at(0);
150 int line;
151 if ((r >= QLatin1Char('a') && r <= QLatin1Char('z')) || r == QLatin1Char('_') || r == QLatin1Char('+') || r == QLatin1Char('*')) {
152 if (range.isValid()) {
153 line = qMax(range.end().line(), range.start().line());
154 } else {
155 line = v->cursorPosition().line();
156 }
157
158 m_viInputModeManager->marks()->setUserMark(r, KTextEditor::Cursor(line, 0));
159 }
160 } else {
161 msg = i18n("Wrong arguments");
162 return false;
163 }
164 return true;
165 }
166
167 // should not happen :)
168 msg = i18n("Unknown command '%1'", cmd);
169 return false;
170}
171
173{
174 static QStringList l;
175
176 if (l.isEmpty()) {
177 l << QStringLiteral("d") << QStringLiteral("delete") << QStringLiteral("j") << QStringLiteral("c") << QStringLiteral("change") << QStringLiteral("<")
178 << QStringLiteral(">") << QStringLiteral("y") << QStringLiteral("yank") << QStringLiteral("ma") << QStringLiteral("mark") << QStringLiteral("k");
179 }
180
181 return l.contains(range.split(QLatin1Char(' ')).at(0));
182}
183
185{
186 Q_UNUSED(view)
187
188 KTextEditor::ViewPrivate *v = static_cast<KTextEditor::ViewPrivate *>(view);
189
190 if (v && (cmd == QLatin1String("nn") || cmd == QLatin1String("nnoremap"))) {
191 QStringList l = m_viInputModeManager->globalState()->mappings()->getAll(Mappings::NormalModeMapping);
192
194 co->setItems(l);
195 co->setIgnoreCase(false);
196 return co;
197 }
198 return nullptr;
199}
200
201const QStringList &Commands::mappingCommands()
202{
203 static QStringList mappingsCommands;
204 if (mappingsCommands.isEmpty()) {
205 mappingsCommands << QStringLiteral("nmap") << QStringLiteral("nm") << QStringLiteral("noremap") << QStringLiteral("nnoremap") << QStringLiteral("nn")
206 << QStringLiteral("no") << QStringLiteral("vmap") << QStringLiteral("vm") << QStringLiteral("vnoremap") << QStringLiteral("vn")
207 << QStringLiteral("imap") << QStringLiteral("im") << QStringLiteral("inoremap") << QStringLiteral("ino") << QStringLiteral("cmap")
208 << QStringLiteral("cm") << QStringLiteral("cnoremap") << QStringLiteral("cno");
209
210 mappingsCommands << QStringLiteral("nunmap") << QStringLiteral("vunmap") << QStringLiteral("iunmap") << QStringLiteral("cunmap");
211
212 mappingsCommands << QStringLiteral("nohlsearch") << QStringLiteral("noh") << QStringLiteral("set-hlsearch") << QStringLiteral("set-hls")
213 << QStringLiteral("set-nohlsearch") << QStringLiteral("set-nohls");
214 }
215 return mappingsCommands;
216}
217
218Mappings::MappingMode Commands::modeForMapCommand(const QString &mapCommand)
219{
220 if (mapCommand.startsWith(u'v')) {
221 if (mapCommand == u"vmap" || mapCommand == u"vm" || mapCommand == u"vn" || mapCommand == u"vnoremap" || mapCommand == u"vunmap") {
222 return Mappings::VisualModeMapping;
223 }
224 }
225
226 if (mapCommand.startsWith(u'i')) {
227 if (mapCommand == u"imap" || mapCommand == u"im" || mapCommand == u"ino" || mapCommand == u"inoremap" || mapCommand == u"iunmap") {
228 return Mappings::InsertModeMapping;
229 }
230 }
231
232 if (mapCommand.startsWith(u'c')) {
233 if (mapCommand == u"cmap" || mapCommand == u"cm" || mapCommand == u"cno" || mapCommand == u"cnoremap" || mapCommand == u"cunmap") {
234 return Mappings::CommandModeMapping;
235 }
236 }
237
238 // if (mapCommand == u"nunmap") {
239 // return Mappings::NormalModeMapping;
240 // }
241 return Mappings::NormalModeMapping;
242}
243
244bool Commands::isMapCommandRecursive(const QString &mapCommand)
245{
246 return mapCommand == u"nmap" || mapCommand == u"nm" //
247 || mapCommand == u"vmap" || mapCommand == u"vm" //
248 || mapCommand == u"imap" || mapCommand == u"im" //
249 || mapCommand == u"cmap" || mapCommand == u"cm";
250}
251
252// END ViCommands
253
254// BEGIN SedReplace
255SedReplace *SedReplace::m_instance = nullptr;
256
257bool SedReplace::interactiveSedReplace(KTextEditor::ViewPrivate *, std::shared_ptr<InteractiveSedReplacer> interactiveSedReplace)
258{
259 EmulatedCommandBar *emulatedCommandBar = m_viInputModeManager->inputAdapter()->viModeEmulatedCommandBar();
260 emulatedCommandBar->startInteractiveSearchAndReplace(interactiveSedReplace);
261 return true;
262}
263// END SedReplace
virtual void setIgnoreCase(bool ignoreCase)
virtual void setItems(const QStringList &itemList)
The Cursor represents a position in a Document.
Definition cursor.h:75
constexpr int line() const noexcept
Retrieve the line on which this cursor is situated.
Definition cursor.h:174
An object representing a section of text, from one Cursor to another.
constexpr Cursor end() const noexcept
Get the end position of this range.
constexpr Cursor start() const noexcept
Get the start position of this range.
constexpr bool isValid() const noexcept
Validity check.
A text widget with KXMLGUIClient that represents a Document.
Definition view.h:244
A KCompletion object that completes last ?unquoted? word in the string passed.
Definition katecmd.h:58
This KTextEditor::Command provides vi 'ex' commands.
Definition cmds.h:31
KCompletion * completionObject(KTextEditor::View *, const QString &) override
Reimplement from KTextEditor::Command.
Definition cmds.cpp:184
bool exec(class KTextEditor::View *view, const QString &cmd, QString &msg, const KTextEditor::Range &range=KTextEditor::Range(-1, -0, -1, 0)) override
execute command on given range
Definition cmds.cpp:30
bool supportsRange(const QString &range) override
Find out if a given command can act on a range.
Definition cmds.cpp:172
A KateViewBarWidget that attempts to emulate some of the features of Vim's own command bar,...
Commands for the vi normal mode.
Support vim/sed style search and replace.
Definition cmds.h:95
QString i18n(const char *text, const TYPE &arg...)
const_reference at(qsizetype i) const const
qsizetype count() const const
bool isEmpty() const const
value_type takeFirst()
bool endsWith(QChar c, Qt::CaseSensitivity cs) const const
bool isEmpty() const const
QStringList split(QChar sep, Qt::SplitBehavior behavior, Qt::CaseSensitivity cs) const const
bool startsWith(QChar c, Qt::CaseSensitivity cs) const const
bool contains(QLatin1StringView str, Qt::CaseSensitivity cs) const const
SkipEmptyParts
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Mon Nov 18 2024 12:11:27 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.