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