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