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(t: macroRegister); |
24 | } |
25 | QStringList macroContents; |
26 | for (const QChar macroRegister : macroKeys) { |
27 | macroContents.append(t: KeyParser::self()->decodeKeySequence(keys: m_macros[macroRegister])); |
28 | } |
29 | QStringList macroCompletions; |
30 | for (const QChar macroRegister : macroKeys) { |
31 | macroCompletions.append(t: QString::number(m_completions[macroRegister].length())); |
32 | for (const Completion &completionForMacro : m_completions[macroRegister]) { |
33 | macroCompletions.append(t: encodeMacroCompletionForConfig(completionForMacro)); |
34 | } |
35 | } |
36 | config.writeEntry(key: "Macro Registers" , value: macroRegisters); |
37 | config.writeEntry(key: "Macro Contents" , value: macroContents); |
38 | config.writeEntry(key: "Macro Completions" , value: macroCompletions); |
39 | } |
40 | |
41 | void Macros::readConfig(const KConfigGroup &config) |
42 | { |
43 | const QStringList macroRegisters = config.readEntry(key: "Macro Registers" , aDefault: QStringList()); |
44 | const QStringList macroContents = config.readEntry(key: "Macro Contents" , aDefault: QStringList()); |
45 | const QStringList macroCompletions = config.readEntry(key: "Macro Completions" , aDefault: 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(i: 0); |
50 | m_macros[macroRegister] = KeyParser::self()->encodeKeySequence(keys: macroContents[macroIndex]); |
51 | macroCompletionsIndex = readMacroCompletions(reg: macroRegister, encodedMacroCompletions: macroCompletions, macroCompletionIndex: 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(key: reg); |
64 | } |
65 | |
66 | void Macros::store(const QChar ®, const QList<KeyEvent> ¯oKeyEventLog, const CompletionList &completions) |
67 | { |
68 | m_macros[reg].clear(); |
69 | QList<KeyEvent> withoutClosingQ = macroKeyEventLog; |
70 | Q_ASSERT(!macroKeyEventLog.isEmpty() && macroKeyEventLog.last().key() == Qt::Key_Q); |
71 | withoutClosingQ.pop_back(); |
72 | for (const KeyEvent &keyEvent : std::as_const(t&: withoutClosingQ)) { |
73 | const QChar key = KeyParser::self()->KeyEventToQChar(keyEvent); |
74 | m_macros[reg].append(c: key); |
75 | } |
76 | m_completions[reg] = completions; |
77 | } |
78 | |
79 | QString Macros::get(const QChar ®) const |
80 | { |
81 | return m_macros.contains(key: reg) ? m_macros[reg] : QString(); |
82 | } |
83 | |
84 | CompletionList Macros::getCompletions(const QChar ®) const |
85 | { |
86 | return m_completions.contains(key: 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(ok: &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(t: decodeMacroCompletionFromConfig(encodedMacroCompletion)); |
101 | } |
102 | } |
103 | return macroCompletionsIndex; |
104 | } |
105 | |
106 | QString Macros::encodeMacroCompletionForConfig(const Completion &completionForMacro) |
107 | { |
108 | const bool endedWithSemiColon = completionForMacro.completedText().endsWith(c: QLatin1Char(';')); |
109 | QString encodedMacroCompletion = completionForMacro.completedText().remove(QStringLiteral("()" )).remove(c: 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(c: QLatin1Char('|')); |
127 | Completion::CompletionType completionType = Completion::PlainText; |
128 | if (encodedMacroCompletion.contains(s: QLatin1String("(...)" ))) { |
129 | completionType = Completion::FunctionWithArgs; |
130 | } else if (encodedMacroCompletion.contains(s: QLatin1String("()" ))) { |
131 | completionType = Completion::FunctionWithoutArgs; |
132 | } |
133 | QString completionText = encodedMacroCompletion; |
134 | completionText.replace(before: QLatin1String("(...)" ), after: QLatin1String("()" )).remove(c: QLatin1Char('|')); |
135 | |
136 | return Completion(completionText, removeTail, completionType); |
137 | } |
138 | |