File indexing completed on 2024-04-14 03:55:28
0001 /* 0002 SPDX-FileCopyrightText: 2001-2010 Christoph Cullmann <cullmann@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #include "katecmd.h" 0008 #include "kateglobal.h" 0009 0010 #include "katepartdebug.h" 0011 #include <KCompletionMatches> 0012 0013 #include <ktexteditor/command.h> 0014 0015 // BEGIN KateCmd 0016 #define CMD_HIST_LENGTH 256 0017 0018 KateCmd::KateCmd() 0019 { 0020 m_cmdCompletion.addItem(QStringLiteral("help")); 0021 } 0022 0023 KateCmd::~KateCmd() = default; 0024 0025 bool KateCmd::registerCommand(KTextEditor::Command *cmd) 0026 { 0027 const QStringList &l = cmd->cmds(); 0028 0029 for (int z = 0; z < l.count(); z++) { 0030 if (m_dict.contains(l[z])) { 0031 qCDebug(LOG_KTE) << "Command already registered: " << l[z] << ". Aborting."; 0032 return false; 0033 } 0034 } 0035 0036 for (int z = 0; z < l.count(); z++) { 0037 m_dict.insert(l[z], cmd); 0038 // qCDebug(LOG_KTE)<<"Inserted command:"<<l[z]; 0039 } 0040 0041 m_cmds += l; 0042 m_cmdCompletion.insertItems(l); 0043 0044 return true; 0045 } 0046 0047 bool KateCmd::unregisterCommand(KTextEditor::Command *cmd) 0048 { 0049 QStringList l; 0050 0051 QHash<QString, KTextEditor::Command *>::const_iterator i = m_dict.constBegin(); 0052 while (i != m_dict.constEnd()) { 0053 if (i.value() == cmd) { 0054 l << i.key(); 0055 } 0056 ++i; 0057 } 0058 0059 for (QStringList::Iterator it1 = l.begin(); it1 != l.end(); ++it1) { 0060 m_dict.remove(*it1); 0061 m_cmdCompletion.removeItem(*it1); 0062 // qCDebug(LOG_KTE)<<"Removed command:"<<*it1; 0063 } 0064 0065 return true; 0066 } 0067 0068 KTextEditor::Command *KateCmd::queryCommand(const QString &cmd) const 0069 { 0070 // a command can be named ".*[\w\-]+" with the constrain that it must 0071 // contain at least one letter. 0072 int f = 0; 0073 bool b = false; 0074 0075 // special case: '-' and '_' can be part of a command name, but if the 0076 // command is 's' (substitute), it should be considered the delimiter and 0077 // should not be counted as part of the command name 0078 if (cmd.length() >= 2 && cmd.at(0) == QLatin1Char('s') && (cmd.at(1) == QLatin1Char('-') || cmd.at(1) == QLatin1Char('_'))) { 0079 return m_dict.value(QStringLiteral("s")); 0080 } 0081 0082 for (; f < cmd.length(); f++) { 0083 if (cmd[f].isLetter()) { 0084 b = true; 0085 } 0086 if (b && (!cmd[f].isLetterOrNumber() && cmd[f] != QLatin1Char('-') && cmd[f] != QLatin1Char('_'))) { 0087 break; 0088 } 0089 } 0090 return m_dict.value(cmd.left(f)); 0091 } 0092 0093 QList<KTextEditor::Command *> KateCmd::commands() const 0094 { 0095 return m_dict.values(); 0096 } 0097 0098 QStringList KateCmd::commandList() const 0099 { 0100 return m_cmds; 0101 } 0102 0103 KateCmd *KateCmd::self() 0104 { 0105 return KTextEditor::EditorPrivate::self()->cmdManager(); 0106 } 0107 0108 void KateCmd::appendHistory(const QString &cmd) 0109 { 0110 if (!m_history.isEmpty()) { // this line should be backported to 3.x 0111 if (m_history.last() == cmd) { 0112 return; 0113 } 0114 } 0115 0116 if (m_history.count() == CMD_HIST_LENGTH) { 0117 m_history.removeFirst(); 0118 } 0119 0120 m_history.append(cmd); 0121 } 0122 0123 const QString KateCmd::fromHistory(int index) const 0124 { 0125 if (index < 0 || index > m_history.count() - 1) { 0126 return QString(); 0127 } 0128 return m_history[index]; 0129 } 0130 0131 KCompletion *KateCmd::commandCompletionObject() 0132 { 0133 return &m_cmdCompletion; 0134 } 0135 // END KateCmd 0136 0137 // BEGIN KateCmdShellCompletion 0138 /* 0139 A lot of the code in the below class is copied from 0140 kdelibs/kio/kio/kshellcompletion.cpp 0141 SPDX-FileCopyrightText: 2000 David Smith <dsmith@algonet.se> 0142 SPDX-FileCopyrightText: 2004 Anders Lund <anders@alweb.dk> 0143 */ 0144 KateCmdShellCompletion::KateCmdShellCompletion() 0145 : KCompletion() 0146 { 0147 m_word_break_char = QLatin1Char(' '); 0148 m_quote_char1 = QLatin1Char('\"'); 0149 m_quote_char2 = QLatin1Char('\''); 0150 m_escape_char = QLatin1Char('\\'); 0151 } 0152 0153 QString KateCmdShellCompletion::makeCompletion(const QString &text) 0154 { 0155 // Split text at the last unquoted space 0156 // 0157 splitText(text, m_text_start, m_text_compl); 0158 0159 // Make completion on the last part of text 0160 // 0161 return KCompletion::makeCompletion(m_text_compl); 0162 } 0163 0164 void KateCmdShellCompletion::postProcessMatch(QString *match) const 0165 { 0166 if (match->isNull()) { 0167 return; 0168 } 0169 0170 match->prepend(m_text_start); 0171 } 0172 0173 void KateCmdShellCompletion::postProcessMatches(QStringList *matches) const 0174 { 0175 for (QStringList::Iterator it = matches->begin(); it != matches->end(); it++) { 0176 if (!(*it).isNull()) { 0177 (*it).prepend(m_text_start); 0178 } 0179 } 0180 } 0181 0182 void KateCmdShellCompletion::postProcessMatches(KCompletionMatches *matches) const 0183 { 0184 for (KCompletionMatches::Iterator it = matches->begin(); it != matches->end(); it++) { 0185 if (!(*it).value().isNull()) { 0186 (*it).value().prepend(m_text_start); 0187 } 0188 } 0189 } 0190 0191 void KateCmdShellCompletion::splitText(const QString &text, QString &text_start, QString &text_compl) const 0192 { 0193 bool in_quote = false; 0194 bool escaped = false; 0195 QChar p_last_quote_char; 0196 int last_unquoted_space = -1; 0197 0198 for (int pos = 0; pos < text.length(); pos++) { 0199 if (escaped) { 0200 escaped = false; 0201 } else if (in_quote && text[pos] == p_last_quote_char) { 0202 in_quote = false; 0203 } else if (!in_quote && text[pos] == m_quote_char1) { 0204 p_last_quote_char = m_quote_char1; 0205 in_quote = true; 0206 } else if (!in_quote && text[pos] == m_quote_char2) { 0207 p_last_quote_char = m_quote_char2; 0208 in_quote = true; 0209 } else if (text[pos] == m_escape_char) { 0210 escaped = true; 0211 } else if (!in_quote && text[pos] == m_word_break_char) { 0212 while (pos + 1 < text.length() && text[pos + 1] == m_word_break_char) { 0213 pos++; 0214 } 0215 0216 if (pos + 1 == text.length()) { 0217 break; 0218 } 0219 0220 last_unquoted_space = pos; 0221 } 0222 } 0223 0224 text_start = text.left(last_unquoted_space + 1); 0225 0226 // the last part without trailing blanks 0227 text_compl = text.mid(last_unquoted_space + 1); 0228 } 0229 0230 // END KateCmdShellCompletion