File indexing completed on 2024-04-28 11:45:59

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 }