Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 75 additions & 0 deletions src/ConfigManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@
#include <string>
#include <sys/ucontext.h>
#include "helpers/Log.hpp"
#include "helpers/MiscFunctions.hpp"
#include <glob.h>
#include <cstring>
#include <filesystem>

static std::string getMainConfigPath() {
static const auto paths = Hyprutils::Path::findConfig("hyprsunset");
Expand All @@ -17,6 +21,18 @@ CConfigManager::CConfigManager(std::string configPath) :
currentConfigPath = configPath.empty() ? getMainConfigPath() : configPath;
}

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;
}

void CConfigManager::init() {
m_config.addConfigValue("max-gamma", Hyprlang::INT{100});

Expand All @@ -26,6 +42,12 @@ void CConfigManager::init() {
m_config.addSpecialConfigValue("profile", "gamma", Hyprlang::FLOAT{1.0f});
m_config.addSpecialConfigValue("profile", "identity", Hyprlang::INT{0});

// track the file in the circular dependency chain
const auto mainConfigPath = getMainConfigPath();
alreadyIncludedSourceFiles.insert(std::filesystem::canonical(mainConfigPath));

m_config.registerHandler(&::handleSource, "source", {.allowFlags = false});

m_config.commence();

auto result = m_config.parse();
Expand Down Expand Up @@ -94,3 +116,56 @@ float CConfigManager::getMaxGamma() {
RASSERT(false, "Failed to construct max-gamma: {}", e.what()); //
}
}

std::optional<std::string> CConfigManager::handleSource(const std::string& command, const std::string& rawpath) {
if (rawpath.length() < 2) {
return "source path " + rawpath + " bogus!";
}
std::unique_ptr<glob_t, void (*)(glob_t*)> glob_buf{new glob_t, [](glob_t* g) { globfree(g); }};
memset(glob_buf.get(), 0, sizeof(glob_t));

const auto CURRENTDIR = std::filesystem::path(currentConfigPath).parent_path().string();

if (auto r = glob(absolutePath(rawpath, CURRENTDIR).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++) {
const auto PATH = absolutePath(glob_buf->gl_pathv[i], CURRENTDIR);

if (PATH.empty() || PATH == currentConfigPath) {
Debug::log(WARN, "source= skipping invalid path");
continue;
}

if (std::find(alreadyIncludedSourceFiles.begin(), alreadyIncludedSourceFiles.end(), PATH) != alreadyIncludedSourceFiles.end()) {
Debug::log(WARN, "source= skipping already included source file {} to prevent circular dependency", PATH);
continue;
}

if (!std::filesystem::is_regular_file(PATH)) {
if (std::filesystem::exists(PATH)) {
Debug::log(WARN, "source= skipping non-file {}", PATH);
continue;
}

Debug::log(ERR, "source= file doesnt exist");
return "source file " + PATH + " doesn't exist!";
}

// track the file in the circular dependency chain
alreadyIncludedSourceFiles.insert(PATH);

// allow for nested config parsing
auto backupConfigPath = currentConfigPath;
currentConfigPath = PATH;

m_config.parseFile(PATH.c_str());

currentConfigPath = backupConfigPath;
}

return {};
}
8 changes: 6 additions & 2 deletions src/ConfigManager.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include "Hyprsunset.hpp"
#include <hyprlang.hpp>
#include <vector>
#include <set>

class CConfigManager {
public:
Expand All @@ -13,10 +14,13 @@ class CConfigManager {

void init();

std::optional<std::string> handleSource(const std::string&, const std::string&);

private:
Hyprlang::CConfig m_config;
Hyprlang::CConfig m_config;

std::string currentConfigPath;
std::string currentConfigPath;
std::set<std::string> alreadyIncludedSourceFiles;
};

inline UP<CConfigManager> g_pConfigManager;
19 changes: 19 additions & 0 deletions src/helpers/MiscFunctions.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#include <filesystem>

#include "MiscFunctions.hpp"

std::string absolutePath(const std::string& rawpath, const std::string& currentDir) {
std::filesystem::path path(rawpath);

// Handling where rawpath starts with '~'
if (!rawpath.empty() && rawpath[0] == '~') {
static const char* const ENVHOME = getenv("HOME");
path = std::filesystem::path(ENVHOME) / path.relative_path().string().substr(2);
}

// Handling e.g. ./, ../
if (path.is_relative())
return std::filesystem::weakly_canonical(std::filesystem::path(currentDir) / path);
else
return std::filesystem::weakly_canonical(path);
}
5 changes: 5 additions & 0 deletions src/helpers/MiscFunctions.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#pragma once

#include <string>

std::string absolutePath(const std::string&, const std::string&);