diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 3927562..7acba01 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -1,5 +1,20 @@ #include "ConfigManager.hpp" +#include "../helpers/MiscFunctions.hpp" #include +#include +#include + +static Hyprlang::CParseResult handleSource(const char* c, const char* v) { + const std::string VALUE = v; + const std::string COMMAND = c; + + const auto RESULT = g_pConfigManager->handleSource(COMMAND, VALUE); + + Hyprlang::CParseResult result; + if (RESULT.has_value()) + result.setError(RESULT.value().c_str()); + return result; +} static std::string getConfigDir() { static const char* xdgConfigHome = getenv("XDG_CONFIG_HOME"); @@ -15,7 +30,7 @@ static std::string getMainConfigPath() { } CConfigManager::CConfigManager() : m_config(getMainConfigPath().c_str(), Hyprlang::SConfigOptions{.throwAllErrors = true, .allowMissingConfig = true}) { - ; + configCurrentPath = getMainConfigPath(); } void CConfigManager::init() { @@ -62,6 +77,8 @@ void CConfigManager::init() { m_config.addSpecialConfigValue("label", "halign", Hyprlang::STRING{"none"}); m_config.addSpecialConfigValue("label", "valign", Hyprlang::STRING{"none"}); + m_config.registerHandler(&::handleSource, "source", {false}); + m_config.commence(); auto result = m_config.parse(); @@ -149,3 +166,48 @@ std::vector CConfigManager::getWidgetConfigs() { return result; } + +std::optional CConfigManager::handleSource(const std::string& command, const std::string& rawpath) { + if (rawpath.length() < 2) { + Debug::log(ERR, "source= path garbage"); + return "source path " + rawpath + " bogus!"; + } + std::unique_ptr glob_buf{new glob_t, [](glob_t* g) { globfree(g); }}; + memset(glob_buf.get(), 0, sizeof(glob_t)); + + if (auto r = glob(absolutePath(rawpath, configCurrentPath)->c_str(), GLOB_TILDE, nullptr, glob_buf.get()); r != 0) { + std::string err = std::format("source= globbing error: {}", r == GLOB_NOMATCH ? "found no match" : GLOB_ABORTED ? "read error" : "out of memory"); + Debug::log(ERR, "{}", err); + return err; + } + + for (size_t i = 0; i < glob_buf->gl_pathc; i++) { + auto pathValueOpt = absolutePath(glob_buf->gl_pathv[i], configCurrentPath); + if (pathValueOpt->empty()) { + Debug::log(WARN, "source= skipping invalid path"); + continue; + } + + auto pathValue = pathValueOpt.value(); + + if (!std::filesystem::is_regular_file(pathValue)) { + if (std::filesystem::exists(pathValue)) { + Debug::log(WARN, "source= skipping non-file {}", pathValue); + continue; + } + + Debug::log(ERR, "source= file doesnt exist"); + return "source file " + pathValue + " doesn't exist!"; + } + + // allow for nested config parsing + auto backupConfigPath = configCurrentPath; + configCurrentPath = pathValue; + + m_config.parseFile(pathValue.c_str()); + + configCurrentPath = backupConfigPath; + } + + return {}; +} \ No newline at end of file diff --git a/src/config/ConfigManager.hpp b/src/config/ConfigManager.hpp index c0ab72b..d1b5d87 100644 --- a/src/config/ConfigManager.hpp +++ b/src/config/ConfigManager.hpp @@ -22,6 +22,9 @@ class CConfigManager { }; std::vector getWidgetConfigs(); + std::optional handleSource(const std::string&, const std::string&); + + std::string configCurrentPath; private: Hyprlang::CConfig m_config; diff --git a/src/helpers/MiscFunctions.cpp b/src/helpers/MiscFunctions.cpp new file mode 100644 index 0000000..25455f5 --- /dev/null +++ b/src/helpers/MiscFunctions.cpp @@ -0,0 +1,23 @@ +#include +#include "MiscFunctions.hpp" + +std::optional absolutePath(const std::string& rawpath, const std::string& rawcurrentpath) { + std::filesystem::path path(rawpath); + + // Handling where rawpath starts with '~' + if (!rawpath.empty() && rawpath[0] == '~') { + static const char* const ENVHOME = getenv("HOME"); + return std::filesystem::path(ENVHOME) / path.relative_path().string().substr(2); + } + // Handling e.g. ./, ../ + else if (path.is_relative()) { + const std::filesystem::path currentDir = std::filesystem::path(rawcurrentpath).parent_path(); + + auto finalPath = currentDir / path; + if (exists(finalPath)) + return std::filesystem::canonical(currentDir / path); + return {}; + } else { + return std::filesystem::canonical(path); + } +} \ No newline at end of file diff --git a/src/helpers/MiscFunctions.hpp b/src/helpers/MiscFunctions.hpp new file mode 100644 index 0000000..fc56855 --- /dev/null +++ b/src/helpers/MiscFunctions.hpp @@ -0,0 +1,6 @@ +#pragma once + +#include +#include + +std::optional absolutePath(const std::string&, const std::string&);