1/*
2 SPDX-FileCopyrightText: 2001-2010 Christoph Cullmann <cullmann@kde.org>
3
4 SPDX-License-Identifier: LGPL-2.0-or-later
5*/
6
7#include "katecmd.h"
8#include "kateglobal.h"
9
10#include "katepartdebug.h"
11#include <KCompletionMatches>
12
13#include <ktexteditor/command.h>
14
15// BEGIN KateCmd
16#define CMD_HIST_LENGTH 256
17
18KateCmd::KateCmd()
19{
20 m_cmdCompletion.addItem(QStringLiteral("help"));
21}
22
23KateCmd::~KateCmd() = default;
24
25bool KateCmd::registerCommand(KTextEditor::Command *cmd)
26{
27 const QStringList &l = cmd->cmds();
28
29 for (int z = 0; z < l.count(); z++) {
30 if (m_dict.contains(key: l[z])) {
31 qCDebug(LOG_KTE) << "Command already registered: " << l[z] << ". Aborting.";
32 return false;
33 }
34 }
35
36 for (int z = 0; z < l.count(); z++) {
37 m_dict.insert(key: l[z], value: cmd);
38 // qCDebug(LOG_KTE)<<"Inserted command:"<<l[z];
39 }
40
41 m_cmds += l;
42 m_cmdCompletion.insertItems(items: l);
43
44 return true;
45}
46
47bool KateCmd::unregisterCommand(KTextEditor::Command *cmd)
48{
49 QStringList l;
50
51 QHash<QString, KTextEditor::Command *>::const_iterator i = m_dict.constBegin();
52 while (i != m_dict.constEnd()) {
53 if (i.value() == cmd) {
54 l << i.key();
55 }
56 ++i;
57 }
58
59 for (QStringList::Iterator it1 = l.begin(); it1 != l.end(); ++it1) {
60 m_dict.remove(key: *it1);
61 m_cmdCompletion.removeItem(item: *it1);
62 // qCDebug(LOG_KTE)<<"Removed command:"<<*it1;
63 }
64
65 return true;
66}
67
68KTextEditor::Command *KateCmd::queryCommand(const QString &cmd) const
69{
70 // a command can be named ".*[\w\-]+" with the constrain that it must
71 // contain at least one letter.
72 int f = 0;
73 bool b = false;
74
75 // special case: '-' and '_' can be part of a command name, but if the
76 // command is 's' (substitute), it should be considered the delimiter and
77 // should not be counted as part of the command name
78 if (cmd.length() >= 2 && cmd.at(i: 0) == QLatin1Char('s') && (cmd.at(i: 1) == QLatin1Char('-') || cmd.at(i: 1) == QLatin1Char('_'))) {
79 return m_dict.value(QStringLiteral("s"));
80 }
81
82 for (; f < cmd.length(); f++) {
83 if (cmd[f].isLetter()) {
84 b = true;
85 }
86 if (b && (!cmd[f].isLetterOrNumber() && cmd[f] != QLatin1Char('-') && cmd[f] != QLatin1Char('_'))) {
87 break;
88 }
89 }
90 return m_dict.value(key: cmd.left(n: f));
91}
92
93QList<KTextEditor::Command *> KateCmd::commands() const
94{
95 return m_dict.values();
96}
97
98QStringList KateCmd::commandList() const
99{
100 return m_cmds;
101}
102
103KateCmd *KateCmd::self()
104{
105 return KTextEditor::EditorPrivate::self()->cmdManager();
106}
107
108void KateCmd::appendHistory(const QString &cmd)
109{
110 if (!m_history.isEmpty()) { // this line should be backported to 3.x
111 if (m_history.last() == cmd) {
112 return;
113 }
114 }
115
116 if (m_history.count() == CMD_HIST_LENGTH) {
117 m_history.removeFirst();
118 }
119
120 m_history.append(t: cmd);
121}
122
123const QString KateCmd::fromHistory(int index) const
124{
125 if (index < 0 || index > m_history.count() - 1) {
126 return QString();
127 }
128 return m_history[index];
129}
130
131KCompletion *KateCmd::commandCompletionObject()
132{
133 return &m_cmdCompletion;
134}
135// END KateCmd
136
137// BEGIN KateCmdShellCompletion
138/*
139 A lot of the code in the below class is copied from
140 kdelibs/kio/kio/kshellcompletion.cpp
141 SPDX-FileCopyrightText: 2000 David Smith <dsmith@algonet.se>
142 SPDX-FileCopyrightText: 2004 Anders Lund <anders@alweb.dk>
143*/
144KateCmdShellCompletion::KateCmdShellCompletion()
145 : KCompletion()
146{
147 m_word_break_char = QLatin1Char(' ');
148 m_quote_char1 = QLatin1Char('\"');
149 m_quote_char2 = QLatin1Char('\'');
150 m_escape_char = QLatin1Char('\\');
151}
152
153QString KateCmdShellCompletion::makeCompletion(const QString &text)
154{
155 // Split text at the last unquoted space
156 //
157 splitText(text, text_start&: m_text_start, text_compl&: m_text_compl);
158
159 // Make completion on the last part of text
160 //
161 return KCompletion::makeCompletion(string: m_text_compl);
162}
163
164void KateCmdShellCompletion::postProcessMatch(QString *match) const
165{
166 if (match->isNull()) {
167 return;
168 }
169
170 match->prepend(s: m_text_start);
171}
172
173void KateCmdShellCompletion::postProcessMatches(QStringList *matches) const
174{
175 for (QStringList::Iterator it = matches->begin(); it != matches->end(); it++) {
176 if (!(*it).isNull()) {
177 (*it).prepend(s: m_text_start);
178 }
179 }
180}
181
182void KateCmdShellCompletion::postProcessMatches(KCompletionMatches *matches) const
183{
184 for (KCompletionMatches::Iterator it = matches->begin(); it != matches->end(); it++) {
185 if (!(*it).value().isNull()) {
186 (*it).value().prepend(s: m_text_start);
187 }
188 }
189}
190
191void KateCmdShellCompletion::splitText(const QString &text, QString &text_start, QString &text_compl) const
192{
193 bool in_quote = false;
194 bool escaped = false;
195 QChar p_last_quote_char;
196 int last_unquoted_space = -1;
197
198 for (int pos = 0; pos < text.length(); pos++) {
199 if (escaped) {
200 escaped = false;
201 } else if (in_quote && text[pos] == p_last_quote_char) {
202 in_quote = false;
203 } else if (!in_quote && text[pos] == m_quote_char1) {
204 p_last_quote_char = m_quote_char1;
205 in_quote = true;
206 } else if (!in_quote && text[pos] == m_quote_char2) {
207 p_last_quote_char = m_quote_char2;
208 in_quote = true;
209 } else if (text[pos] == m_escape_char) {
210 escaped = true;
211 } else if (!in_quote && text[pos] == m_word_break_char) {
212 while (pos + 1 < text.length() && text[pos + 1] == m_word_break_char) {
213 pos++;
214 }
215
216 if (pos + 1 == text.length()) {
217 break;
218 }
219
220 last_unquoted_space = pos;
221 }
222 }
223
224 text_start = text.left(n: last_unquoted_space + 1);
225
226 // the last part without trailing blanks
227 text_compl = text.mid(position: last_unquoted_space + 1);
228}
229
230// END KateCmdShellCompletion
231

source code of ktexteditor/src/utils/katecmd.cpp