File indexing completed on 2024-05-05 05:54:13

0001 /*
0002     This file is part of Konsole, a terminal emulator for KDE.
0003 
0004     SPDX-FileCopyrightText: 2018 Mariusz Glebocki <mglb@arccos-1.net>
0005 
0006     SPDX-License-Identifier: GPL-2.0-or-later
0007 */
0008 
0009 #ifndef TEMPLATE_H
0010 #define TEMPLATE_H
0011 
0012 #include <QMap>
0013 #include <QString>
0014 #include <QVector>
0015 
0016 // QVariant doesn't offer modification in place. Var does.
0017 class Var
0018 {
0019 public:
0020     using Number = qint64;
0021     using String = QString;
0022     using Map = QMap<String, Var>;
0023     using Vector = QVector<Var>;
0024 
0025     enum class DataType {
0026         Invalid,
0027         Number,
0028         String,
0029         Vector,
0030         Map,
0031     };
0032 
0033     const QString dataTypeAsString() const
0034     {
0035         switch (dataType()) {
0036         case DataType::Invalid:
0037             return QStringLiteral("Invalid");
0038         case DataType::Number:
0039             return QStringLiteral("Number");
0040         case DataType::String:
0041             return QStringLiteral("String");
0042         case DataType::Vector:
0043             return QStringLiteral("Vector");
0044         case DataType::Map:
0045             return QStringLiteral("Map");
0046         default:
0047             return QStringLiteral("Unknown?");
0048         }
0049     }
0050 
0051     Var()
0052         : num(0)
0053         , _dataType(DataType::Invalid)
0054     {
0055     }
0056     Var(const Var &other)
0057     {
0058         *this = other;
0059     }
0060 
0061     Var(const Number &newNum)
0062         : _dataType(DataType::Number)
0063     {
0064         new (&num) auto(newNum);
0065     }
0066     Var(const String &newStr)
0067         : _dataType(DataType::String)
0068     {
0069         new (&str) auto(newStr);
0070     }
0071     Var(const Vector &newVec)
0072         : _dataType(DataType::Vector)
0073     {
0074         new (&vec) auto(newVec);
0075     }
0076     Var(const Map &newMap)
0077         : _dataType(DataType::Map)
0078     {
0079         new (&map) auto(newMap);
0080     }
0081 
0082     // Allow initialization without type name
0083     Var(const char *newStr)
0084         : _dataType(DataType::String)
0085     {
0086         new (&str) String(QString::fromUtf8(newStr));
0087     }
0088     Var(std::initializer_list<Var> newVec)
0089         : _dataType(DataType::Vector)
0090     {
0091         new (&vec) Vector(newVec);
0092     }
0093 
0094     ~Var()
0095     {
0096         switch (dataType()) {
0097         case DataType::String:
0098             str.~String();
0099             break;
0100         case DataType::Vector:
0101             vec.~Vector();
0102             break;
0103         case DataType::Map:
0104             map.~Map();
0105             break;
0106         default:
0107             break;
0108         }
0109     }
0110 
0111     Var &operator=(const Var &other)
0112     {
0113         _dataType = other.dataType();
0114         switch (other.dataType()) {
0115         case DataType::Number:
0116             new (&num) auto(other.num);
0117             break;
0118         case DataType::String:
0119             new (&str) auto(other.str);
0120             break;
0121         case DataType::Vector:
0122             new (&vec) auto(other.vec);
0123             break;
0124         case DataType::Map:
0125             new (&map) auto(other.map);
0126             break;
0127         default:
0128             break;
0129         }
0130         return *this;
0131     }
0132 
0133     Var &operator[](unsigned index)
0134     {
0135         Q_ASSERT(_dataType == DataType::Vector);
0136         return vec.data()[index];
0137     }
0138     const Var &operator[](unsigned index) const
0139     {
0140         Q_ASSERT(_dataType == DataType::Vector);
0141         return vec.constData()[index];
0142     }
0143     Var &operator[](const String &key)
0144     {
0145         Q_ASSERT(_dataType == DataType::Map);
0146         return map[key];
0147     }
0148     const Var &operator[](const String &key) const
0149     {
0150         Q_ASSERT(_dataType == DataType::Map);
0151         return *map.find(key);
0152     }
0153 
0154     DataType dataType() const
0155     {
0156         return _dataType;
0157     }
0158 
0159     union {
0160         Number num;
0161         String str;
0162         Vector vec;
0163         Map map;
0164     };
0165 
0166 private:
0167     DataType _dataType;
0168 };
0169 
0170 class Template
0171 {
0172 public:
0173     Template(const QString &text);
0174     void parse();
0175     QString generate(const Var &data);
0176 
0177     struct Element {
0178         Element(const Element *parent = nullptr, const QString &name = QString())
0179             : outer()
0180             , inner()
0181             , name(name)
0182             , fmt()
0183             , line(0)
0184             , column(0)
0185             , isComment(false)
0186             , children()
0187             , parent(parent)
0188         {
0189         }
0190 
0191         Element(const Element &other)
0192             : outer(other.outer)
0193             , inner(other.inner)
0194             , name(other.name)
0195             , fmt(other.fmt)
0196             , line(other.line)
0197             , column(other.column)
0198             , isComment(other.isComment)
0199             , parent(other.parent)
0200         {
0201             for (const auto &child : other.children) {
0202                 children.append(child);
0203             }
0204         }
0205 
0206         const QString findFmt(Var::DataType type) const;
0207         QString path() const;
0208         bool isCommand() const
0209         {
0210             return name.startsWith(QLatin1Char('!'));
0211         }
0212         bool hasName() const
0213         {
0214             return !isCommand() && !name.isEmpty();
0215         }
0216 
0217         static const QString defaultFmt(Var::DataType type);
0218         static bool isValidFmt(const QString &fmt, Var::DataType type);
0219 
0220         QStringRef outer;
0221         QStringRef inner;
0222         QString name;
0223         QString fmt;
0224         uint line;
0225         uint column;
0226         bool isComment;
0227         QList<Element> children;
0228         const Element *parent;
0229     };
0230 
0231 private:
0232     void executeCommand(Element &element, const Element &childStub, const QStringList &argv);
0233     void parseRecursively(Element &element);
0234     int generateRecursively(QString &result, const Element &element, const Var &data, int consumed = 0);
0235 
0236     QString _text; // FIXME: make it pointer (?)
0237     Element _root; // FIXME: make it pointer
0238 };
0239 
0240 #endif