File indexing completed on 2024-04-28 15:31:17
0001 /* 0002 SPDX-FileCopyrightText: 2003-2005 Anders Lund <anders@alweb.dk> 0003 SPDX-FileCopyrightText: 2001-2010 Christoph Cullmann <cullmann@kde.org> 0004 SPDX-FileCopyrightText: 2001 Charles Samuels <charles@kde.org> 0005 0006 SPDX-License-Identifier: LGPL-2.0-or-later 0007 */ 0008 0009 #include <vimode/cmds.h> 0010 0011 #include "globalstate.h" 0012 #include "katecmd.h" 0013 #include "kateview.h" 0014 #include "kateviinputmode.h" 0015 #include "marks.h" 0016 #include <vimode/emulatedcommandbar/emulatedcommandbar.h> 0017 #include <vimode/inputmodemanager.h> 0018 #include <vimode/modes/normalvimode.h> 0019 #include <vimode/searcher.h> 0020 0021 #include <KLocalizedString> 0022 0023 #include <QRegularExpression> 0024 0025 using namespace KateVi; 0026 0027 // BEGIN ViCommands 0028 Commands *Commands::m_instance = nullptr; 0029 0030 bool Commands::exec(KTextEditor::View *view, const QString &_cmd, QString &msg, const KTextEditor::Range &range) 0031 { 0032 Q_UNUSED(range) 0033 // cast it hardcore, we know that it is really a kateview :) 0034 KTextEditor::ViewPrivate *v = static_cast<KTextEditor::ViewPrivate *>(view); 0035 0036 if (!v) { 0037 msg = i18n("Could not access view"); 0038 return false; 0039 } 0040 0041 // create a list of args 0042 QStringList args(_cmd.split(QRegularExpression(QStringLiteral("\\s+")), Qt::SkipEmptyParts)); 0043 QString cmd(args.takeFirst()); 0044 0045 // ALL commands that takes no arguments. 0046 if (mappingCommands().contains(cmd)) { 0047 if (cmd.endsWith(QLatin1String("unmap"))) { 0048 if (args.count() == 1) { 0049 m_viGlobal->mappings()->remove(modeForMapCommand(cmd), args.at(0)); 0050 return true; 0051 } else { 0052 msg = i18n("Missing argument. Usage: %1 <from>", cmd); 0053 return false; 0054 } 0055 } else if (cmd == QLatin1String("nohlsearch") || cmd == QLatin1String("noh")) { 0056 m_viInputModeManager->searcher()->hideCurrentHighlight(); 0057 return true; 0058 } else if (cmd == QLatin1String("set-hlsearch") || cmd == QLatin1String("set-hls")) { 0059 m_viInputModeManager->searcher()->enableHighlightSearch(true); 0060 return true; 0061 } else if (cmd == QLatin1String("set-nohlsearch") || cmd == QLatin1String("set-nohls")) { 0062 m_viInputModeManager->searcher()->enableHighlightSearch(false); 0063 return true; 0064 } 0065 if (args.count() == 1) { 0066 msg = m_viGlobal->mappings()->get(modeForMapCommand(cmd), args.at(0), true); 0067 if (msg.isEmpty()) { 0068 msg = i18n("No mapping found for \"%1\"", args.at(0)); 0069 return false; 0070 } else { 0071 msg = i18n("\"%1\" is mapped to \"%2\"", args.at(0), msg); 0072 } 0073 } else if (args.count() == 2) { 0074 Mappings::MappingRecursion mappingRecursion = (isMapCommandRecursive(cmd)) ? Mappings::Recursive : Mappings::NonRecursive; 0075 m_viGlobal->mappings()->add(modeForMapCommand(cmd), args.at(0), args.at(1), mappingRecursion); 0076 } else { 0077 msg = i18n("Missing argument(s). Usage: %1 <from> [<to>]", cmd); 0078 return false; 0079 } 0080 0081 return true; 0082 } 0083 0084 NormalViMode *nm = m_viInputModeManager->getViNormalMode(); 0085 0086 if (cmd == QLatin1String("d") || cmd == QLatin1String("delete") || cmd == QLatin1String("j") || cmd == QLatin1String("c") || cmd == QLatin1String("change") 0087 || cmd == QLatin1String("<") || cmd == QLatin1String(">") || cmd == QLatin1String("y") || cmd == QLatin1String("yank")) { 0088 KTextEditor::Cursor start_cursor_position = v->cursorPosition(); 0089 0090 int count = 1; 0091 if (range.isValid()) { 0092 count = qAbs(range.end().line() - range.start().line()) + 1; 0093 v->setCursorPosition(KTextEditor::Cursor(qMin(range.start().line(), range.end().line()), 0)); 0094 } 0095 0096 static const QRegularExpression number(QStringLiteral("^(\\d+)$")); 0097 for (int i = 0; i < args.count(); i++) { 0098 auto match = number.match(args.at(i)); 0099 if (match.hasMatch()) { 0100 count += match.captured(0).toInt() - 1; 0101 } 0102 0103 QChar r = args.at(i).at(0); 0104 if (args.at(i).size() == 1 0105 && ((r >= QLatin1Char('a') && r <= QLatin1Char('z')) || r == QLatin1Char('_') || r == QLatin1Char('-') || r == QLatin1Char('+') 0106 || r == QLatin1Char('*'))) { 0107 nm->setRegister(r); 0108 } 0109 } 0110 0111 nm->setCount(count); 0112 0113 if (cmd == QLatin1String("d") || cmd == QLatin1String("delete")) { 0114 nm->commandDeleteLine(); 0115 } 0116 if (cmd == QLatin1String("j")) { 0117 nm->commandJoinLines(); 0118 } 0119 if (cmd == QLatin1String("c") || cmd == QLatin1String("change")) { 0120 nm->commandChangeLine(); 0121 } 0122 if (cmd == QLatin1String("<")) { 0123 nm->commandUnindentLine(); 0124 } 0125 if (cmd == QLatin1String(">")) { 0126 nm->commandIndentLine(); 0127 } 0128 if (cmd == QLatin1String("y") || cmd == QLatin1String("yank")) { 0129 nm->commandYankLine(); 0130 v->setCursorPosition(start_cursor_position); 0131 } 0132 0133 // TODO - should we resetParser, here? We'd have to make it public, if so. 0134 // Or maybe synthesise a KateViCommand to execute instead ... ? 0135 nm->setCount(0); 0136 0137 return true; 0138 } 0139 0140 if (cmd == QLatin1String("mark") || cmd == QLatin1String("ma") || cmd == QLatin1String("k")) { 0141 if (args.count() == 0) { 0142 if (cmd == QLatin1String("mark")) { 0143 // TODO: show up mark list; 0144 } else { 0145 msg = i18n("Wrong arguments"); 0146 return false; 0147 } 0148 } else if (args.count() == 1) { 0149 QChar r = args.at(0).at(0); 0150 int line; 0151 if ((r >= QLatin1Char('a') && r <= QLatin1Char('z')) || r == QLatin1Char('_') || r == QLatin1Char('+') || r == QLatin1Char('*')) { 0152 if (range.isValid()) { 0153 line = qMax(range.end().line(), range.start().line()); 0154 } else { 0155 line = v->cursorPosition().line(); 0156 } 0157 0158 m_viInputModeManager->marks()->setUserMark(r, KTextEditor::Cursor(line, 0)); 0159 } 0160 } else { 0161 msg = i18n("Wrong arguments"); 0162 return false; 0163 } 0164 return true; 0165 } 0166 0167 // should not happen :) 0168 msg = i18n("Unknown command '%1'", cmd); 0169 return false; 0170 } 0171 0172 bool Commands::supportsRange(const QString &range) 0173 { 0174 static QStringList l; 0175 0176 if (l.isEmpty()) { 0177 l << QStringLiteral("d") << QStringLiteral("delete") << QStringLiteral("j") << QStringLiteral("c") << QStringLiteral("change") << QStringLiteral("<") 0178 << QStringLiteral(">") << QStringLiteral("y") << QStringLiteral("yank") << QStringLiteral("ma") << QStringLiteral("mark") << QStringLiteral("k"); 0179 } 0180 0181 return l.contains(range.split(QLatin1Char(' ')).at(0)); 0182 } 0183 0184 KCompletion *Commands::completionObject(KTextEditor::View *view, const QString &cmd) 0185 { 0186 Q_UNUSED(view) 0187 0188 KTextEditor::ViewPrivate *v = static_cast<KTextEditor::ViewPrivate *>(view); 0189 0190 if (v && (cmd == QLatin1String("nn") || cmd == QLatin1String("nnoremap"))) { 0191 QStringList l = m_viGlobal->mappings()->getAll(Mappings::NormalModeMapping); 0192 0193 KateCmdShellCompletion *co = new KateCmdShellCompletion(); 0194 co->setItems(l); 0195 co->setIgnoreCase(false); 0196 return co; 0197 } 0198 return nullptr; 0199 } 0200 0201 const QStringList &Commands::mappingCommands() 0202 { 0203 static QStringList mappingsCommands; 0204 if (mappingsCommands.isEmpty()) { 0205 mappingsCommands << QStringLiteral("nmap") << QStringLiteral("nm") << QStringLiteral("noremap") << QStringLiteral("nnoremap") << QStringLiteral("nn") 0206 << QStringLiteral("no") << QStringLiteral("vmap") << QStringLiteral("vm") << QStringLiteral("vnoremap") << QStringLiteral("vn") 0207 << QStringLiteral("imap") << QStringLiteral("im") << QStringLiteral("inoremap") << QStringLiteral("ino") << QStringLiteral("cmap") 0208 << QStringLiteral("cm") << QStringLiteral("cnoremap") << QStringLiteral("cno"); 0209 0210 mappingsCommands << QStringLiteral("nunmap") << QStringLiteral("vunmap") << QStringLiteral("iunmap") << QStringLiteral("cunmap"); 0211 0212 mappingsCommands << QStringLiteral("nohlsearch") << QStringLiteral("noh") << QStringLiteral("set-hlsearch") << QStringLiteral("set-hls") 0213 << QStringLiteral("set-nohlsearch") << QStringLiteral("set-nohls"); 0214 } 0215 return mappingsCommands; 0216 } 0217 0218 Mappings::MappingMode Commands::modeForMapCommand(const QString &mapCommand) 0219 { 0220 static QMap<QString, Mappings::MappingMode> modeForMapCommand; 0221 if (modeForMapCommand.isEmpty()) { 0222 // Normal is the default. 0223 modeForMapCommand.insert(QStringLiteral("vmap"), Mappings::VisualModeMapping); 0224 modeForMapCommand.insert(QStringLiteral("vm"), Mappings::VisualModeMapping); 0225 modeForMapCommand.insert(QStringLiteral("vnoremap"), Mappings::VisualModeMapping); 0226 modeForMapCommand.insert(QStringLiteral("vn"), Mappings::VisualModeMapping); 0227 modeForMapCommand.insert(QStringLiteral("imap"), Mappings::InsertModeMapping); 0228 modeForMapCommand.insert(QStringLiteral("im"), Mappings::InsertModeMapping); 0229 modeForMapCommand.insert(QStringLiteral("inoremap"), Mappings::InsertModeMapping); 0230 modeForMapCommand.insert(QStringLiteral("ino"), Mappings::InsertModeMapping); 0231 modeForMapCommand.insert(QStringLiteral("cmap"), Mappings::CommandModeMapping); 0232 modeForMapCommand.insert(QStringLiteral("cm"), Mappings::CommandModeMapping); 0233 modeForMapCommand.insert(QStringLiteral("cnoremap"), Mappings::CommandModeMapping); 0234 modeForMapCommand.insert(QStringLiteral("cno"), Mappings::CommandModeMapping); 0235 0236 modeForMapCommand.insert(QStringLiteral("nunmap"), Mappings::NormalModeMapping); 0237 modeForMapCommand.insert(QStringLiteral("vunmap"), Mappings::VisualModeMapping); 0238 modeForMapCommand.insert(QStringLiteral("iunmap"), Mappings::InsertModeMapping); 0239 modeForMapCommand.insert(QStringLiteral("cunmap"), Mappings::CommandModeMapping); 0240 } 0241 return modeForMapCommand.value(mapCommand); 0242 } 0243 0244 bool Commands::isMapCommandRecursive(const QString &mapCommand) 0245 { 0246 static QMap<QString, bool> isMapCommandRecursive; 0247 if (isMapCommandRecursive.isEmpty()) { 0248 isMapCommandRecursive.insert(QStringLiteral("nmap"), true); 0249 isMapCommandRecursive.insert(QStringLiteral("nm"), true); 0250 isMapCommandRecursive.insert(QStringLiteral("vmap"), true); 0251 isMapCommandRecursive.insert(QStringLiteral("vm"), true); 0252 isMapCommandRecursive.insert(QStringLiteral("imap"), true); 0253 isMapCommandRecursive.insert(QStringLiteral("im"), true); 0254 isMapCommandRecursive.insert(QStringLiteral("cmap"), true); 0255 isMapCommandRecursive.insert(QStringLiteral("cm"), true); 0256 } 0257 return isMapCommandRecursive.value(mapCommand); 0258 } 0259 0260 // END ViCommands 0261 0262 // BEGIN SedReplace 0263 SedReplace *SedReplace::m_instance = nullptr; 0264 0265 bool SedReplace::interactiveSedReplace(KTextEditor::ViewPrivate *, QSharedPointer<InteractiveSedReplacer> interactiveSedReplace) 0266 { 0267 EmulatedCommandBar *emulatedCommandBar = m_viInputModeManager->inputAdapter()->viModeEmulatedCommandBar(); 0268 emulatedCommandBar->startInteractiveSearchAndReplace(interactiveSedReplace); 0269 return true; 0270 } 0271 // END SedReplace