diff --git a/src/clippy/clippy.cpp b/src/clippy/clippy.cpp index 6854848..f5042ce 100644 --- a/src/clippy/clippy.cpp +++ b/src/clippy/clippy.cpp @@ -2,6 +2,7 @@ #include #include +#include #include #include @@ -9,8 +10,11 @@ #include void Clippy::Run(const std::vector& args) { - auto result = TryExecuteClippyCommand(args); - if (result) { + if (auto result = TryExecuteClippyCommand(args); result) { + result->Execute(); + return; + } + if (auto result = GetScriptTarget(args); result) { result->Execute(); return; } @@ -34,15 +38,34 @@ Clippy::TargetPtr Clippy::TryExecuteClippyCommand( if (CheckPatternParametres(args, Parameter::Skip, "cfg", Parameter::Anything)) { - projects_.LoadFrom("test"); - auto p = projects_.GetCurrentProject(); + LoadProjects(); + auto p = projects_->GetCurrentProject(); if (p.has_value()) { - return std::make_unique(p.value().configuration_file); + return std::make_unique(p->GetConfig()); } else { - return std::make_unique(projects_); + return std::make_unique(projects_.value()); } } return nullptr; } + +Clippy::TargetPtr Clippy::GetScriptTarget( + const std::vector& args) { + LoadProjects(); + auto p = projects_->GetCurrentProject(); + + if (!p.has_value() || args.size() < 2) { + return nullptr; + } + + auto cfg = p->GetConfig(); + return cfg.GetTarget(args[1]); +} + +void Clippy::LoadProjects() { + if (!projects_.has_value()) { + projects_.emplace(utils::GetProjectDirectory() / "projects"); + } +} diff --git a/src/clippy/clippy.hpp b/src/clippy/clippy.hpp index a944267..42c1d3e 100644 --- a/src/clippy/clippy.hpp +++ b/src/clippy/clippy.hpp @@ -14,6 +14,9 @@ class Clippy { using TargetPtr = std::unique_ptr; private: TargetPtr TryExecuteClippyCommand(const std::vector& args); + TargetPtr GetScriptTarget(const std::vector& args); - ProjectList projects_; + void LoadProjects(); + + std::optional projects_; }; diff --git a/src/clippy/config.cpp b/src/clippy/config.cpp new file mode 100644 index 0000000..a966c97 --- /dev/null +++ b/src/clippy/config.cpp @@ -0,0 +1,52 @@ +#include +#include + +#include +#include + +std::string Strip(std::string s) { + while (!s.empty() && std::isspace(s.back())) { + s.pop_back(); + } + std::reverse(s.begin(), s.end()); + while (!s.empty() && std::isspace(s.back())) { + s.pop_back(); + } + std::reverse(s.begin(), s.end()); + + return s; +} + +std::unique_ptr Config::GetTarget( + const std::string& target) { + std::ifstream in(path_); + + std::string current; + std::vector target_commands; + + bool target_begin = false; + + while (std::getline(in, current)) { + if (current == target + ":") { + target_begin = true; + continue; + } + if (current.empty()) { + continue; + } + if (!std::isspace(current[0]) && target_begin) { + break; + } + + if (target_begin) { + target_commands.emplace_back(Strip(std::move(current))); + } + } + + if (!target_begin) { + return nullptr; + } + + return std::make_unique( + std::move(target_commands)); +} diff --git a/src/clippy/config.hpp b/src/clippy/config.hpp index 21b4bf9..e9927a5 100644 --- a/src/clippy/config.hpp +++ b/src/clippy/config.hpp @@ -1,5 +1,22 @@ #pragma once -class Config { +#include +#include +#include + +namespace clippy::targets { +class Target; +} + +class Config { + public: + Config(std::string path) : path_(std::move(path)) {} + + void Edit() { utils::OpenEditor(path_); } + + std::unique_ptr GetTarget(const std::string& target); + + private: + std::string path_; }; diff --git a/src/clippy/project_list.cpp b/src/clippy/project_list.cpp index 0225ef3..b4ed2a9 100644 --- a/src/clippy/project_list.cpp +++ b/src/clippy/project_list.cpp @@ -4,14 +4,72 @@ #include #include +#include +#include -#include +Config ProjectList::GetNewConfig( + const std::filesystem::path& config_directory) { + std::lock_guard guard(lock_file_); -void ProjectList::LoadFrom(const std::string& path) { - utils::filesystem::LockFile lock(path); - std::lock_guard guard(lock); + LoadWithouLock(); - std::ifstream in(path); + std::mt19937 rnd(std::chrono::system_clock::now().time_since_epoch().count()); + + auto RandomSymbol = [&rnd]() { + int n = rnd() % (26 + 26 + 10); + if (n < 26) { + return 'a' + n; + } else if (n < 26 + 26) { + return 'A' + n - 26; + } else { + return '0' + n - 26 - 26; + } + }; + + auto GenerateFilename = [&rnd, &RandomSymbol]() { + std::string filename; + for (size_t i = 0; i < 6; ++i) { + filename += RandomSymbol(); + } + + return filename; + }; + + auto filename = GenerateFilename(); + while (true) { + bool exist_config = false; + for (auto& project : projects_) { + if (filename == project.configuration_file.filename()) { + exist_config = true; + break; + } + } + if (!exist_config) { + break; + } + + filename = GenerateFilename(); + } + + auto path_to_config = config_directory / filename; + + std::ofstream out(path_, std::ios::ate); + out << std::filesystem::current_path() << " " << path_to_config << std::endl; + out.close(); + + projects_.emplace_back(std::filesystem::current_path(), path_to_config); + + return {path_to_config}; +} + +void ProjectList::Load() { + std::lock_guard guard(lock_file_); + + LoadWithouLock(); +} + +void ProjectList::LoadWithouLock() { + std::ifstream in(path_); Project current; diff --git a/src/clippy/project_list.hpp b/src/clippy/project_list.hpp index be5d369..2a49462 100644 --- a/src/clippy/project_list.hpp +++ b/src/clippy/project_list.hpp @@ -1,6 +1,8 @@ #pragma once #include +#include + #include #include #include @@ -8,20 +10,31 @@ struct Project { std::strong_ordering operator<=>(const Project&) const = default; + Config GetConfig() { return Config{configuration_file}; } + std::filesystem::path root_project; std::filesystem::path configuration_file; }; class ProjectList { public: - ProjectList() {} + ProjectList(std::filesystem::path path) : path_(std::move(path)), lock_file_(path_) { + Load(); + } - void LoadFrom(const std::string& path); + Config GetNewConfig(const std::filesystem::path& config_directory); const std::vector& GetProjects() const { return projects_; } std::optional GetCurrentProject(); private: + void Load(); + void LoadWithouLock(); + + private: + std::filesystem::path path_; + utils::filesystem::LockFile lock_file_; + std::vector projects_; }; diff --git a/src/clippy/target.cpp b/src/clippy/target.cpp new file mode 100644 index 0000000..8fe34e3 --- /dev/null +++ b/src/clippy/target.cpp @@ -0,0 +1,37 @@ +namespace clippy::targets { +class Target { + public: + virtual void Execute() = 0; +}; + +class EmptyTarget : public Target { + public: + void Execute() override {} +}; + +class OpenProjectConfig : public Target { + public: + OpenProjectConfig(Config config) : config_(config) {} + + void Execute() override { config_.Edit(); } + + private: + Config config_; +}; + +class CreateProjectConfig : public Target { + public: + CreateProjectConfig(ProjectList& projects) : projects_(projects) {} + + void Execute() override { + auto scripts_path = utils::GetProjectDirectory() / "scripts"; + std::filesystem::create_directories(scripts_path); + + auto config = projects_.GetNewConfig(scripts_path); + config.Edit(); + } + + private: + ProjectList& projects_; +}; +} // namespace clippy::targets diff --git a/src/clippy/target.hpp b/src/clippy/target.hpp index 75676f5..8ac2308 100644 --- a/src/clippy/target.hpp +++ b/src/clippy/target.hpp @@ -1,8 +1,14 @@ #pragma once #include +#include #include +#include + +#define SIGPIPE_ALWAYS_IGNORE +#include +#undef SIGPIPE_ALWAYS_IGNORE #include #include @@ -20,15 +26,12 @@ class EmptyTarget : public Target { class OpenProjectConfig : public Target { public: - OpenProjectConfig(std::string config_path) : config_path_(config_path) {} + OpenProjectConfig(Config config) : config_(config) {} - void Execute() override { - utils::OpenEditor(config_path_); - std::cout << "Open editor TODO" << std::endl; - } + void Execute() override { config_.Edit(); } private: - std::string config_path_; + Config config_; }; class CreateProjectConfig : public Target { @@ -36,10 +39,35 @@ class CreateProjectConfig : public Target { CreateProjectConfig(ProjectList& projects) : projects_(projects) {} void Execute() override { - std::cout << "Make new project config and open editor TODO" << std::endl; + auto scripts_path = utils::GetProjectDirectory() / "scripts"; + std::filesystem::create_directories(scripts_path); + + auto config = projects_.GetNewConfig(scripts_path); + config.Edit(); } private: ProjectList& projects_; }; + +class RunShellScript : public Target { + public: + RunShellScript(std::vector commands) + : commands_(std::move(commands)) {} + + void Execute() override { + cppshell::Shell s; + + for (auto& i : commands_) { + std::cout << "-> " << i << std::endl; + s.Execute(i); + if (int err = s.GetExitCodeLastCommand(); err != 0) { + std::cout << "ERROR" << std::endl; + } + } + } + + private: + std::vector commands_; +}; } // namespace clippy::targets diff --git a/src/utils/config_path.hpp b/src/utils/config_path.hpp new file mode 100644 index 0000000..b901253 --- /dev/null +++ b/src/utils/config_path.hpp @@ -0,0 +1,20 @@ +#pragma once + +#include +#include +#include +#include + +namespace utils { +inline std::filesystem::path GetProjectDirectory() { + namespace fs = std::filesystem; + using std::filesystem::path; + + path config_path = + std::string(std::getenv("HOME")) + "/.local/share/clippy-terminal/"; + + fs::create_directories(config_path); + + return config_path; +} +} // namespace utils