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 }