File indexing completed on 2024-04-14 03:55:49
0001 /* 0002 SPDX-FileCopyrightText: KDE Developers 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #include "katepartdebug.h" 0008 #include "kateviinputmode.h" 0009 #include <vimode/emulatedcommandbar/emulatedcommandbar.h> 0010 #include <vimode/inputmodemanager.h> 0011 #include <vimode/keyparser.h> 0012 #include <vimode/mappings.h> 0013 0014 #include <KConfigGroup> 0015 0016 using namespace KateVi; 0017 0018 void Mappings::readConfig(const KConfigGroup &config) 0019 { 0020 readMappings(config, QStringLiteral("Normal"), NormalModeMapping); 0021 readMappings(config, QStringLiteral("Visual"), VisualModeMapping); 0022 readMappings(config, QStringLiteral("Insert"), InsertModeMapping); 0023 readMappings(config, QStringLiteral("Command"), CommandModeMapping); 0024 } 0025 0026 void Mappings::writeConfig(KConfigGroup &config) const 0027 { 0028 writeMappings(config, QStringLiteral("Normal"), NormalModeMapping); 0029 writeMappings(config, QStringLiteral("Visual"), VisualModeMapping); 0030 writeMappings(config, QStringLiteral("Insert"), InsertModeMapping); 0031 writeMappings(config, QStringLiteral("Command"), CommandModeMapping); 0032 } 0033 0034 void Mappings::writeMappings(KConfigGroup &config, const QString &mappingModeName, MappingMode mappingMode) const 0035 { 0036 config.writeEntry(mappingModeName + QLatin1String(" Mode Mapping Keys"), getAll(mappingMode, true)); 0037 QStringList l; 0038 QList<bool> recursives; 0039 const auto all = getAll(mappingMode); 0040 l.reserve(all.size()); 0041 recursives.reserve(all.size()); 0042 for (const QString &s : all) { 0043 l << KeyParser::self()->decodeKeySequence(get(mappingMode, s)); 0044 recursives << isRecursive(mappingMode, s); 0045 } 0046 config.writeEntry(mappingModeName + QLatin1String(" Mode Mappings"), l); 0047 config.writeEntry(mappingModeName + QLatin1String(" Mode Mappings Recursion"), recursives); 0048 0049 QChar leader = (m_leader.isNull()) ? QChar::fromLatin1('\\') : m_leader; 0050 config.writeEntry(QStringLiteral("Map Leader"), QString(leader)); 0051 } 0052 0053 void Mappings::readMappings(const KConfigGroup &config, const QString &mappingModeName, MappingMode mappingMode) 0054 { 0055 const QStringList keys = config.readEntry(mappingModeName + QLatin1String(" Mode Mapping Keys"), QStringList()); 0056 const QStringList mappings = config.readEntry(mappingModeName + QLatin1String(" Mode Mappings"), QStringList()); 0057 const QList<bool> isRecursive = config.readEntry(mappingModeName + QLatin1String(" Mode Mappings Recursion"), QList<bool>()); 0058 0059 const QString &mapLeader = config.readEntry(QStringLiteral("Map Leader"), QString()); 0060 m_leader = (mapLeader.isEmpty()) ? QChar::fromLatin1('\\') : mapLeader[0]; 0061 0062 // sanity check 0063 if (keys.length() == mappings.length()) { 0064 for (int i = 0; i < keys.length(); i++) { 0065 // "Recursion" is a newly-introduced part of the config that some users won't have, 0066 // so rather than abort (and lose our mappings) if there are not enough entries, simply 0067 // treat any missing ones as Recursive (for backwards compatibility). 0068 MappingRecursion recursion = Recursive; 0069 if (isRecursive.size() > i && !isRecursive.at(i)) { 0070 recursion = NonRecursive; 0071 } 0072 add(mappingMode, keys.at(i), mappings.at(i), recursion); 0073 } 0074 } else { 0075 qCDebug(LOG_KTE) << "Error when reading mappings from " << mappingModeName << " config: number of keys != number of values"; 0076 } 0077 } 0078 0079 void Mappings::add(MappingMode mode, const QString &from, const QString &to, MappingRecursion recursion) 0080 { 0081 const QString &encodedMapping = KeyParser::self()->encodeKeySequence(from); 0082 0083 if (from.isEmpty()) { 0084 return; 0085 } 0086 0087 const QString encodedTo = KeyParser::self()->encodeKeySequence(to); 0088 Mapping mapping = {encodedTo, (recursion == Recursive), false}; 0089 0090 // Add this mapping as is. 0091 m_mappings[mode][encodedMapping] = mapping; 0092 0093 // In normal mode replace the <leader> with its value. 0094 if (mode == NormalModeMapping) { 0095 QString other = from; 0096 other.replace(QLatin1String("<leader>"), m_leader); 0097 other = KeyParser::self()->encodeKeySequence(other); 0098 if (other != encodedMapping) { 0099 mapping.temporary = true; 0100 m_mappings[mode][other] = mapping; 0101 } 0102 } 0103 } 0104 0105 void Mappings::remove(MappingMode mode, const QString &from) 0106 { 0107 const QString &encodedMapping = KeyParser::self()->encodeKeySequence(from); 0108 m_mappings[mode].remove(encodedMapping); 0109 } 0110 0111 void Mappings::clear(MappingMode mode) 0112 { 0113 m_mappings[mode].clear(); 0114 } 0115 0116 QString Mappings::get(MappingMode mode, const QString &from, bool decode, bool includeTemporary) const 0117 { 0118 if (!m_mappings[mode].contains(from)) { 0119 return QString(); 0120 } 0121 0122 const Mapping &mapping = m_mappings[mode][from]; 0123 if (mapping.temporary && !includeTemporary) { 0124 return QString(); 0125 } 0126 0127 const QString &ret = mapping.encoded; 0128 if (decode) { 0129 return KeyParser::self()->decodeKeySequence(ret); 0130 } 0131 0132 return ret; 0133 } 0134 0135 QStringList Mappings::getAll(MappingMode mode, bool decode, bool includeTemporary) const 0136 { 0137 QStringList mappings; 0138 const QHash<QString, Mapping> mappingsForMode = m_mappings[mode]; 0139 0140 for (auto i = mappingsForMode.begin(); i != mappingsForMode.end(); i++) { 0141 if (!includeTemporary && i.value().temporary) { 0142 continue; 0143 } 0144 0145 if (decode) { 0146 mappings << KeyParser::self()->decodeKeySequence(i.key()); 0147 } else { 0148 mappings << i.key(); 0149 } 0150 } 0151 return mappings; 0152 } 0153 0154 bool Mappings::isRecursive(MappingMode mode, const QString &from) const 0155 { 0156 if (!m_mappings[mode].contains(from)) { 0157 return false; 0158 } 0159 0160 return m_mappings[mode][from].recursive; 0161 } 0162 0163 void Mappings::setLeader(const QChar &leader) 0164 { 0165 m_leader = leader; 0166 } 0167 0168 Mappings::MappingMode Mappings::mappingModeForCurrentViMode(KateViInputMode *viInputMode) 0169 { 0170 if (viInputMode->viModeEmulatedCommandBar()->isActive()) { 0171 return CommandModeMapping; 0172 } 0173 const ViMode mode = viInputMode->viInputModeManager()->getCurrentViMode(); 0174 switch (mode) { 0175 case ViMode::NormalMode: 0176 return NormalModeMapping; 0177 case ViMode::VisualMode: 0178 case ViMode::VisualLineMode: 0179 case ViMode::VisualBlockMode: 0180 return VisualModeMapping; 0181 case ViMode::InsertMode: 0182 case ViMode::ReplaceMode: 0183 return InsertModeMapping; 0184 default: 0185 Q_ASSERT(false && "unrecognised ViMode!"); 0186 return NormalModeMapping; // Return arbitrary mode to satisfy compiler. 0187 } 0188 }