1 /* 2 SPDX-FileCopyrightText: KDE Developers 3 4 SPDX-License-Identifier: LGPL-2.0-or-later 5 */ 6 7 #include "macros.h" 8 #include <vimode/keyparser.h> 9 10 #include <KConfigGroup> 11 12 using namespace KateVi; 13 14 Macros::Macros() = default; 15 16 Macros::~Macros() = default; 17 18 void Macros::writeConfig(KConfigGroup &config) const 19 { 20 const auto macroKeys = m_macros.keys(); 21 QStringList macroRegisters; 22 for (const QChar macroRegister : macroKeys) { 23 macroRegisters.append(macroRegister); 24 } 25 QStringList macroContents; 26 for (const QChar macroRegister : macroKeys) { 27 macroContents.append(KeyParser::self()->decodeKeySequence(m_macros[macroRegister])); 28 } 29 QStringList macroCompletions; 30 for (const QChar macroRegister : macroKeys) { 31 macroCompletions.append(QString::number(m_completions[macroRegister].length())); 32 for (const Completion &completionForMacro : m_completions[macroRegister]) { 33 macroCompletions.append(encodeMacroCompletionForConfig(completionForMacro)); 34 } 35 } 36 config.writeEntry("Macro Registers", macroRegisters); 37 config.writeEntry("Macro Contents", macroContents); 38 config.writeEntry("Macro Completions", macroCompletions); 39 } 40 41 void Macros::readConfig(const KConfigGroup &config) 42 { 43 const QStringList macroRegisters = config.readEntry("Macro Registers", QStringList()); 44 const QStringList macroContents = config.readEntry("Macro Contents", QStringList()); 45 const QStringList macroCompletions = config.readEntry("Macro Completions", QStringList()); 46 int macroCompletionsIndex = 0; 47 if (macroRegisters.length() == macroContents.length()) { 48 for (int macroIndex = 0; macroIndex < macroRegisters.length(); macroIndex++) { 49 const QChar macroRegister = macroRegisters[macroIndex].at(0); 50 m_macros[macroRegister] = KeyParser::self()->encodeKeySequence(macroContents[macroIndex]); 51 macroCompletionsIndex = readMacroCompletions(macroRegister, macroCompletions, macroCompletionsIndex); 52 } 53 } 54 } 55 56 void Macros::clear() 57 { 58 m_macros.clear(); 59 } 60 61 void Macros::remove(const QChar ®) 62 { 63 m_macros.remove(reg); 64 } 65 66 void Macros::store(const QChar ®, const QList<QKeyEvent> ¯oKeyEventLog, const CompletionList &completions) 67 { 68 m_macros[reg].clear(); 69 QList<QKeyEvent> withoutClosingQ = macroKeyEventLog; 70 Q_ASSERT(!macroKeyEventLog.isEmpty() && macroKeyEventLog.last().key() == Qt::Key_Q); 71 withoutClosingQ.pop_back(); 72 for (const QKeyEvent &keyEvent : std::as_const(withoutClosingQ)) { 73 const QChar key = KeyParser::self()->KeyEventToQChar(keyEvent); 74 m_macros[reg].append(key); 75 } 76 m_completions[reg] = completions; 77 } 78 79 QString Macros::get(const QChar ®) const 80 { 81 return m_macros.contains(reg) ? m_macros[reg] : QString(); 82 } 83 84 CompletionList Macros::getCompletions(const QChar ®) const 85 { 86 return m_completions.contains(reg) ? m_completions[reg] : CompletionList(); 87 } 88 89 int Macros::readMacroCompletions(const QChar ®, const QStringList &encodedMacroCompletions, int macroCompletionsIndex) 90 { 91 if (macroCompletionsIndex < encodedMacroCompletions.length()) { 92 bool parsedNumCompletionsSuccessfully = false; 93 const QString numCompletionsAsString = encodedMacroCompletions[macroCompletionsIndex++]; 94 const int numCompletions = numCompletionsAsString.toInt(&parsedNumCompletionsSuccessfully); 95 int count = 0; 96 m_completions[reg].clear(); 97 while (count < numCompletions && macroCompletionsIndex < encodedMacroCompletions.length()) { 98 const QString encodedMacroCompletion = encodedMacroCompletions[macroCompletionsIndex++]; 99 count++; 100 m_completions[reg].append(decodeMacroCompletionFromConfig(encodedMacroCompletion)); 101 } 102 } 103 return macroCompletionsIndex; 104 } 105 106 QString Macros::encodeMacroCompletionForConfig(const Completion &completionForMacro) const 107 { 108 const bool endedWithSemiColon = completionForMacro.completedText().endsWith(QLatin1Char(';')); 109 QString encodedMacroCompletion = completionForMacro.completedText().remove(QStringLiteral("()")).remove(QLatin1Char(';')); 110 if (completionForMacro.completionType() == Completion::FunctionWithArgs) { 111 encodedMacroCompletion += QLatin1String("(...)"); 112 } else if (completionForMacro.completionType() == Completion::FunctionWithoutArgs) { 113 encodedMacroCompletion += QLatin1String("()"); 114 } 115 if (endedWithSemiColon) { 116 encodedMacroCompletion += QLatin1Char(';'); 117 } 118 if (completionForMacro.removeTail()) { 119 encodedMacroCompletion += QLatin1Char('|'); 120 } 121 return encodedMacroCompletion; 122 } 123 124 Completion Macros::decodeMacroCompletionFromConfig(const QString &encodedMacroCompletion) 125 { 126 const bool removeTail = encodedMacroCompletion.endsWith(QLatin1Char('|')); 127 Completion::CompletionType completionType = Completion::PlainText; 128 if (encodedMacroCompletion.contains(QLatin1String("(...)"))) { 129 completionType = Completion::FunctionWithArgs; 130 } else if (encodedMacroCompletion.contains(QLatin1String("()"))) { 131 completionType = Completion::FunctionWithoutArgs; 132 } 133 QString completionText = encodedMacroCompletion; 134 completionText.replace(QLatin1String("(...)"), QLatin1String("()")).remove(QLatin1Char('|')); 135 136 return Completion(completionText, removeTail, completionType); 137 } 138