Hyprlang
A fast and user-friendly configuration language
Loading...
Searching...
No Matches
hyprlang.hpp
Go to the documentation of this file.
1#pragma once
2
3#ifndef HYPRLANG_HPP
4#define HYPRLANG_HPP
5
6#include <typeindex>
7#include <any>
8#include <string>
9#include <ostream>
10#include <vector>
11#include <print>
12#include <cstdlib>
13
14class CConfigImpl;
15struct SConfigDefaultValue;
16struct SSpecialCategory;
17
18#define HYPRLANG_END_MAGIC 0x1337BEEF
19
20namespace Hyprlang {
21
22 struct SVector2D;
24
25 /* Variable typedefs */
26
27 /*!
28 Basic integer config type
29 */
30 typedef int64_t INT;
31
32 /*!
33 Basic float config type
34 */
35 typedef float FLOAT;
36
37 /*!
38 Basic string config type
39 */
40 typedef const char* STRING;
41
42 /*!
43 Basic vec2 config type
44 */
45 typedef SVector2D VEC2;
46
47 /*!
48 Custom config type
49 */
51
52 /*!
53 A very simple vector type
54 */
55 struct SVector2D {
56 float x = 0, y = 0;
57
58 //
59 bool operator==(const SVector2D& rhs) const {
60 return x == rhs.x && y == rhs.y;
61 }
62
63 friend std::ostream& operator<<(std::ostream& os, const SVector2D& rhs) {
64 return os << "[" << rhs.x << ", " << rhs.y << "]";
65 }
66 };
67
69 public:
70 bool error = false;
71 /*!
72 Get this ParseResult's error string.
73 Pointer valid until the error string is changed or this
74 object gets destroyed.
75 */
76 const char* getError() const {
77 return errorString;
78 }
79 /*!
80 Set an error contained by this ParseResult.
81 Creates a copy of the string, does not take ownership.
82 */
83 void setError(const char* err);
84
85 private:
86 void setError(const std::string& err);
87
88 std::string errorStdString = "";
89 const char* errorString = nullptr;
90
91 friend class CConfig;
92 };
93
94 /*!
95 Generic struct for options for the config parser
96 */
98 /*!
99 Don't throw errors on missing values.
100 */
101 int verifyOnly = false;
102
103 /*!
104 Return all errors instead of just the first
105 */
106 int throwAllErrors = false;
107
108 /*!
109 \since 0.2.0
110
111 Don't throw on a missing config file. Carry on as if nothing happened.
112 */
114
115 /*!
116 \since 0.4.2
117
118 Treat configPath as a raw config stream.
119 */
120 int pathIsStream = false;
121
122 // INTERNAL: DO NOT MODIFY
124 };
125
126 /*!
127 Generic struct for options for handlers
128 */
130 /*!
131 Allow flags for this handler
132 */
133 bool allowFlags = false;
134
135 // INTERNAL: DO NOT MODIFY
137 };
138
139 /*!
140 Generic struct for options for special categories
141 */
143 /*!
144 a key is the name of a value that will be the identifier of a special category
145 can be left null for no key, aka a generic one
146 keys are always strings. Default key value is "0"
147 */
148 const char* key = nullptr;
149
150 /*!
151 don't pop up an error if the config value is missing
152 */
153 int ignoreMissing = false;
154
155 /*!
156 Make this category an anonymous special one.
157 key has to be nullptr.
158
159 Anonymous special categories behave like key-based ones, but the keys
160 will be automatically assigned without user input.
161
162 \since 0.4.0
163 */
164 int anonymousKeyBased = false;
165
166 // INTERNAL: DO NOT MODIFY
168 };
169
170 /*!
171 typedefs
172 */
173 typedef CParseResult (*PCONFIGHANDLERFUNC)(const char* COMMAND, const char* VALUE);
174 typedef CParseResult (*PCONFIGCUSTOMVALUEHANDLERFUNC)(const char* VALUE, void** data);
175 typedef void (*PCONFIGCUSTOMVALUEDESTRUCTOR)(void** data);
176
177 /*!
178 Container for a custom config value type
179 When creating, pass your handler.
180 Handler will receive a void** that points to a void* that you can set to your own
181 thing. Pass a dtor to free whatever you allocated when the custom value type is being released.
182 data may always be pointing to a nullptr.
183 */
185 public:
188
189 /*!
190 \since 0.3.0
191
192 get the data pointer for the custom value type.
193 */
194 void* getData() {
195 return data;
196 }
197
198 private:
199 PCONFIGCUSTOMVALUEHANDLERFUNC handler = nullptr;
200 PCONFIGCUSTOMVALUEDESTRUCTOR dtor = nullptr;
201 void* data = nullptr;
202 std::string defaultVal = "";
203 std::string lastVal = "";
204
205 friend class CConfigValue;
206 friend class CConfig;
207 };
208
209 /*!
210 Container for a config value
211 */
213 public:
215 CConfigValue(const INT value);
216 CConfigValue(const FLOAT value);
217 CConfigValue(const STRING value);
218 CConfigValue(const VEC2 value);
221 CConfigValue(const CConfigValue&&) = delete;
223
224 /*!
225 \since 0.3.0
226 */
228
230
231 /*!
232 Return a pointer to the data. Prefer getDataStaticPtr()
233 */
234 void* dataPtr() const;
235
236 /*!
237 \since 0.2.0
238
239 Return a static pointer to the m_pData.
240 As long as this configValue is alive, this pointer is valid.
241 CConfigValues are alive as long as the owning CConfig is alive.
242
243 Please note only the first (outer) pointer is static. The second
244 may (and most likely will) be changing.
245
246 For all types except STRING typeof(**retval) is the config value type
247 (e.g. INT or FLOAT)
248
249 Please note STRING is a special type and instead of
250 typeof(**retval) being const char*, typeof(\*retval) is a const char*.
251 */
252 void* const* getDataStaticPtr() const;
253
254 /*!
255 Get the contained value as an std::any.
256 For strings, this is a const char*.
257 For custom data types, this is a void* representing the data ptr stored by it.
258 */
259 std::any getValue() const {
260 switch (m_eType) {
261 case CONFIGDATATYPE_EMPTY: throw;
262 case CONFIGDATATYPE_INT: return std::any(*reinterpret_cast<INT*>(m_pData));
263 case CONFIGDATATYPE_FLOAT: return std::any(*reinterpret_cast<FLOAT*>(m_pData));
264 case CONFIGDATATYPE_STR: return std::any(reinterpret_cast<STRING>(m_pData));
265 case CONFIGDATATYPE_VEC2: return std::any(*reinterpret_cast<VEC2*>(m_pData));
266 case CONFIGDATATYPE_CUSTOM: return std::any(reinterpret_cast<CUSTOMTYPE*>(m_pData)->data);
267 default: throw;
268 }
269 return {}; // unreachable
270 }
271
272 /*!
273 \since 0.3.0
274
275 a flag to notify whether this value has been set explicitly by the user,
276 or not.
277 */
278 bool m_bSetByUser = false;
279
280 private:
281 // remember to also edit config.hpp if editing
282 enum eDataType {
283 CONFIGDATATYPE_EMPTY,
284 CONFIGDATATYPE_INT,
285 CONFIGDATATYPE_FLOAT,
286 CONFIGDATATYPE_STR,
287 CONFIGDATATYPE_VEC2,
288 CONFIGDATATYPE_CUSTOM,
289 };
290 eDataType m_eType = eDataType::CONFIGDATATYPE_EMPTY;
291 void* m_pData = nullptr;
292 void defaultFrom(SConfigDefaultValue& ref);
293 void setFrom(std::any ref);
294 void setFrom(const CConfigValue* const ref);
295
296 friend class CConfig;
297 };
298
299 /*!
300 Base class for a config file
301 */
302 class CConfig {
303 public:
304 CConfig(const char* configPath, const SConfigOptions& options);
306
307 /*!
308 Add a config value, for example myCategory:myValue.
309 This has to be done before commence()
310 Value provided becomes default.
311 */
312 void addConfigValue(const char* name, const CConfigValue& value);
313
314 /*!
315 Register a handler. Can be called anytime, though not recommended
316 to do this dynamically .
317 */
318 void registerHandler(PCONFIGHANDLERFUNC func, const char* name, SHandlerOptions options);
319
320 /*!
321 \since 0.3.0
322
323 Unregister a handler.
324 */
325 void unregisterHandler(const char* name);
326
327 /*!
328 Commence the config state. Config becomes immutable, as in
329 no new values may be added or removed. Required for parsing.
330 */
331 void commence();
332
333 /*!
334 Add a special category. Can be done dynamically.
335 */
336 void addSpecialCategory(const char* name, SSpecialCategoryOptions options);
337
338 /*!
339 \since 0.3.0
340
341 Remove a special category. Can be done dynamically.
342 */
343 void removeSpecialCategory(const char* name);
344
345 /*!
346 \since 0.3.2
347
348 Add a config value to a special category.
349
350 \note Before 0.3.2, this takes a `const CConfigValue` (non-ref)
351 */
352 void addSpecialConfigValue(const char* cat, const char* name, const CConfigValue& value);
353
354 /*!
355 Remove a config value from a special category.
356 */
357 void removeSpecialConfigValue(const char* cat, const char* name);
358
359 /*!
360 Parse the config. Refresh the values.
361 */
363
364 /*!
365 Same as parse(), but parse a specific file, without any refreshing.
366 recommended to use for stuff like source = path.conf
367 */
368 CParseResult parseFile(const char* file);
369
370 /*!
371 Parse a single "line", dynamically.
372 Values set by this are temporary and will be overwritten
373 by default / config on the next parse()
374 */
375 CParseResult parseDynamic(const char* line);
376 CParseResult parseDynamic(const char* command, const char* value);
377
378 /*!
379 Get a config's value ptr. These are static.
380 nullptr on fail
381 */
382 CConfigValue* getConfigValuePtr(const char* name);
383
384 /*!
385 Get a special category's config value ptr. These are only static for static (key-less)
386 categories.
387 key can be nullptr for static categories. Cannot be nullptr for id-based categories.
388 nullptr on fail.
389 */
390 CConfigValue* getSpecialConfigValuePtr(const char* category, const char* name, const char* key = nullptr);
391
392 /*!
393 Get a config value's stored value. Empty on fail
394 */
395 std::any getConfigValue(const char* name) {
396 CConfigValue* val = getConfigValuePtr(name);
397 if (!val)
398 return {};
399 return val->getValue();
400 }
401
402 /*!
403 Get a special config value's stored value. Empty on fail.
404 */
405 std::any getSpecialConfigValue(const char* category, const char* name, const char* key = nullptr) {
406 CConfigValue* val = getSpecialConfigValuePtr(category, name, key);
407 if (!val)
408 return {};
409 return val->getValue();
410 }
411
412 /*!
413 Check whether a special category with the provided key value exists
414
415 \since 0.3.0
416 */
417 bool specialCategoryExistsForKey(const char* category, const char* key);
418
419 /*!
420 Get a vector with all registered keys for a special category
421
422 It's an error to query this for a static or non-existent category
423
424 \since 0.4.0
425 */
426 std::vector<std::string> listKeysForSpecialCategory(const char* category) {
427 const char** cats = nullptr;
428 size_t len = 0;
429 retrieveKeysForCat(category, &cats, &len);
430
431 if (len == 0)
432 return {};
433
434 std::vector<std::string> result;
435 for (size_t i = 0; i < len; ++i) {
436 result.push_back(cats[i]);
437 }
438
439 free(cats);
440
441 return result;
442 }
443
444 private:
445 bool m_bCommenced = false;
446
447 CConfigImpl* impl;
448
449 CParseResult parseLine(std::string line, bool dynamic = false);
450 CParseResult configSetValueSafe(const std::string& command, const std::string& value);
451 CParseResult parseVariable(const std::string& lhs, const std::string& rhs, bool dynamic = false);
452 void clearState();
453 void applyDefaultsToCat(SSpecialCategory& cat);
454 void retrieveKeysForCat(const char* category, const char*** out, size_t* len);
455 CParseResult parseRawStream(const std::string& stream);
456 };
457
458 /*!
459 Templated wrapper for Hyprlang values. Much more straightforward to use.
460
461 \since 0.6.0
462 */
463 template <typename T>
465 public:
466 CSimpleConfigValue(CConfig* const pConfig, const char* val) {
467 const auto VAL = pConfig->getConfigValuePtr(val);
468
469 if (!VAL) {
470 std::println("CSimpleConfigValue: value not found");
471 abort();
472 }
473
474 // NOLINTNEXTLINE
475 p_ = VAL->getDataStaticPtr();
476
477#ifdef HYPRLAND_DEBUG
478 // verify type
479 const auto ANY = VAL->getValue();
480 const auto TYPE = std::type_index(ANY.type());
481
482 // exceptions
483 const bool STRINGEX = (typeid(T) == typeid(std::string) && TYPE == typeid(Hyprlang::STRING));
484 const bool CUSTOMEX = (typeid(T) == typeid(Hyprlang::CUSTOMTYPE) && (TYPE == typeid(Hyprlang::CUSTOMTYPE*) || TYPE == typeid(void*) /* dunno why it does this? */));
485
486 if (typeid(T) != TYPE && !STRINGEX && !CUSTOMEX) {
487 std::println("CSimpleConfigValue: Mismatched type in CConfigValue<T>, got {} but has {}", typeid(T).name(), TYPE.name());
488 abort();
489 }
490#endif
491 }
492
493 T* ptr() const {
494 return *(T* const*)p_;
495 }
496
497 T operator*() const {
498 return *ptr();
499 }
500
501 private:
502 void* const* p_ = nullptr;
503 };
504
505 template <>
506 inline std::string* CSimpleConfigValue<std::string>::ptr() const {
507 std::print("Impossible to implement ptr() of CConfigValue<std::string>");
508 abort();
509 return nullptr;
510 }
511
512 template <>
514 return std::string{*(Hyprlang::STRING*)p_};
515 }
516
517 template <>
521
522 template <>
526
527 template <>
531
532 template <>
534 std::print("Impossible to implement operator* of CConfigValue<Hyprlang::CUSTOMTYPE>, use ptr()");
535 abort();
536 return *ptr();
537 }
538};
539
540#ifndef HYPRLANG_INTERNAL
541#undef HYPRLANG_END_MAGIC
542#endif
543
544#endif
Definition hyprlang.hpp:184
friend class CConfigValue
Definition hyprlang.hpp:205
void * getData()
Definition hyprlang.hpp:194
CConfigCustomValueType(PCONFIGCUSTOMVALUEHANDLERFUNC handler_, PCONFIGCUSTOMVALUEDESTRUCTOR dtor_, const char *defaultValue)
friend class CConfig
Definition hyprlang.hpp:206
Definition hyprlang.hpp:212
void *const * getDataStaticPtr() const
void * dataPtr() const
CConfigValue(const VEC2 value)
CConfigValue(CUSTOMTYPE &&value)
CConfigValue(const CConfigValue &)
CConfigValue(const STRING value)
std::any getValue() const
Definition hyprlang.hpp:259
CConfigValue(const FLOAT value)
CConfigValue(const INT value)
CConfigValue(CConfigValue &&)=delete
CConfigValue(CConfigValue &)=delete
CConfigValue(const CConfigValue &&)=delete
bool m_bSetByUser
Definition hyprlang.hpp:278
friend class CConfig
Definition hyprlang.hpp:296
Definition hyprlang.hpp:302
void addConfigValue(const char *name, const CConfigValue &value)
CParseResult parse()
CParseResult parseDynamic(const char *command, const char *value)
void addSpecialConfigValue(const char *cat, const char *name, const CConfigValue &value)
CParseResult parseDynamic(const char *line)
std::any getSpecialConfigValue(const char *category, const char *name, const char *key=nullptr)
Definition hyprlang.hpp:405
CConfig(const char *configPath, const SConfigOptions &options)
void unregisterHandler(const char *name)
CConfigValue * getConfigValuePtr(const char *name)
std::vector< std::string > listKeysForSpecialCategory(const char *category)
Definition hyprlang.hpp:426
void removeSpecialCategory(const char *name)
bool specialCategoryExistsForKey(const char *category, const char *key)
CConfigValue * getSpecialConfigValuePtr(const char *category, const char *name, const char *key=nullptr)
std::any getConfigValue(const char *name)
Definition hyprlang.hpp:395
void registerHandler(PCONFIGHANDLERFUNC func, const char *name, SHandlerOptions options)
void addSpecialCategory(const char *name, SSpecialCategoryOptions options)
CParseResult parseFile(const char *file)
void removeSpecialConfigValue(const char *cat, const char *name)
Definition hyprlang.hpp:68
bool error
Definition hyprlang.hpp:70
const char * getError() const
Definition hyprlang.hpp:76
friend class CConfig
Definition hyprlang.hpp:91
void setError(const char *err)
T * ptr() const
Definition hyprlang.hpp:493
T operator*() const
Definition hyprlang.hpp:497
CSimpleConfigValue(CConfig *const pConfig, const char *val)
Definition hyprlang.hpp:466
#define HYPRLANG_END_MAGIC
Definition hyprlang.hpp:18
Definition hyprlang.hpp:20
const char * STRING
Definition hyprlang.hpp:40
int64_t INT
Definition hyprlang.hpp:30
CParseResult(* PCONFIGCUSTOMVALUEHANDLERFUNC)(const char *VALUE, void **data)
Definition hyprlang.hpp:174
SVector2D VEC2
Definition hyprlang.hpp:45
CConfigCustomValueType CUSTOMTYPE
Definition hyprlang.hpp:50
void(* PCONFIGCUSTOMVALUEDESTRUCTOR)(void **data)
Definition hyprlang.hpp:175
float FLOAT
Definition hyprlang.hpp:35
CParseResult(* PCONFIGHANDLERFUNC)(const char *COMMAND, const char *VALUE)
Definition hyprlang.hpp:173
Definition hyprlang.hpp:97
int __internal_struct_end
Definition hyprlang.hpp:123
int allowMissingConfig
Definition hyprlang.hpp:113
int pathIsStream
Definition hyprlang.hpp:120
int verifyOnly
Definition hyprlang.hpp:101
int throwAllErrors
Definition hyprlang.hpp:106
Definition hyprlang.hpp:129
bool allowFlags
Definition hyprlang.hpp:133
int __internal_struct_end
Definition hyprlang.hpp:136
Definition hyprlang.hpp:142
int __internal_struct_end
Definition hyprlang.hpp:167
const char * key
Definition hyprlang.hpp:148
int anonymousKeyBased
Definition hyprlang.hpp:164
int ignoreMissing
Definition hyprlang.hpp:153
Definition hyprlang.hpp:55
float y
Definition hyprlang.hpp:56
float x
Definition hyprlang.hpp:56
friend std::ostream & operator<<(std::ostream &os, const SVector2D &rhs)
Definition hyprlang.hpp:63
bool operator==(const SVector2D &rhs) const
Definition hyprlang.hpp:59