Compare commits
11 commits
7e4141b282
...
48f25d4baa
Author | SHA1 | Date | |
---|---|---|---|
|
48f25d4baa | ||
|
1b655704ee | ||
|
46c83022c9 | ||
|
75eb05bd1a | ||
|
a2186366b8 | ||
|
dbd34e0817 | ||
|
d1fbe99800 | ||
|
86a13a1705 | ||
|
b18270cd7b | ||
|
1df359175e | ||
|
fc53f9bfb1 |
|
@ -8,7 +8,7 @@ file(GLOB_RECURSE SOURCES_FILES src/*)
|
||||||
|
|
||||||
add_executable(clippy_terminal ${SOURCES_FILES})
|
add_executable(clippy_terminal ${SOURCES_FILES})
|
||||||
target_include_directories(clippy_terminal PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src)
|
target_include_directories(clippy_terminal PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src)
|
||||||
target_link_libraries(clippy_terminal cppshell rang)
|
target_link_libraries(clippy_terminal PRIVATE cppshell tmuxub rang jsoncons yaml-cpp)
|
||||||
|
|
||||||
install(TARGETS clippy_terminal DESTINATION bin)
|
install(TARGETS clippy_terminal DESTINATION bin)
|
||||||
|
|
||||||
|
@ -20,9 +20,31 @@ FetchContent_Declare(
|
||||||
)
|
)
|
||||||
FetchContent_MakeAvailable(cppshell)
|
FetchContent_MakeAvailable(cppshell)
|
||||||
|
|
||||||
|
FetchContent_Declare(
|
||||||
|
tmuxub
|
||||||
|
GIT_REPOSITORY https://gitlab.com/Onyad/tmuxub
|
||||||
|
GIT_TAG origin/main
|
||||||
|
)
|
||||||
|
FetchContent_MakeAvailable(tmuxub)
|
||||||
|
|
||||||
FetchContent_Declare(
|
FetchContent_Declare(
|
||||||
rang
|
rang
|
||||||
GIT_REPOSITORY https://github.com/agauniyal/rang.git
|
GIT_REPOSITORY https://github.com/agauniyal/rang.git
|
||||||
GIT_TAG origin/master
|
GIT_TAG origin/master
|
||||||
)
|
)
|
||||||
FetchContent_MakeAvailable(rang)
|
FetchContent_MakeAvailable(rang)
|
||||||
|
|
||||||
|
set(JSONCONS_BUILD_TESTS OFF CACHE INTERNAL "Turn off tests")
|
||||||
|
FetchContent_Declare(
|
||||||
|
jsoncons
|
||||||
|
GIT_REPOSITORY https://github.com/danielaparker/jsoncons
|
||||||
|
GIT_TAG origin/master
|
||||||
|
)
|
||||||
|
FetchContent_MakeAvailable(jsoncons)
|
||||||
|
|
||||||
|
FetchContent_Declare(
|
||||||
|
yaml-cpp
|
||||||
|
GIT_REPOSITORY https://github.com/jbeder/yaml-cpp.git
|
||||||
|
GIT_TAG origin/master
|
||||||
|
)
|
||||||
|
FetchContent_MakeAvailable(yaml-cpp)
|
||||||
|
|
|
@ -25,15 +25,13 @@ void Clippy::Run(const std::vector<std::string>& args) {
|
||||||
for (size_t i = 1; i < args.size(); ++i) {
|
for (size_t i = 1; i < args.size(); ++i) {
|
||||||
std::cout << args[i] << (i + 1 == args.size() ? "" : ",") << " ";
|
std::cout << args[i] << (i + 1 == args.size() ? "" : ",") << " ";
|
||||||
}
|
}
|
||||||
std::cout << "}" << std::endl << rang::bg::reset << rang::style::reset;
|
std::cout << "}" << rang::bg::reset << rang::style::reset << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
Clippy::TargetPtr Clippy::TryExecuteClippyCommand(
|
Clippy::TargetPtr Clippy::TryExecuteClippyCommand(const std::vector<std::string>& args) {
|
||||||
const std::vector<std::string>& args) {
|
|
||||||
using namespace utils::parametres;
|
using namespace utils::parametres;
|
||||||
using namespace clippy::targets;
|
using namespace clippy::targets;
|
||||||
if (CheckPatternParametres(args, Parameter::Skip, "help",
|
if (CheckPatternParametres(args, Parameter::Skip, "help", Parameter::Anything)) {
|
||||||
Parameter::Anything)) {
|
|
||||||
std::cout << "Hello I'm clippy" << std::endl;
|
std::cout << "Hello I'm clippy" << std::endl;
|
||||||
std::cout << "Parametres: { ";
|
std::cout << "Parametres: { ";
|
||||||
for (size_t i = 0; i < args.size(); ++i) {
|
for (size_t i = 0; i < args.size(); ++i) {
|
||||||
|
@ -41,11 +39,12 @@ Clippy::TargetPtr Clippy::TryExecuteClippyCommand(
|
||||||
}
|
}
|
||||||
std::cout << "}" << std::endl;
|
std::cout << "}" << std::endl;
|
||||||
|
|
||||||
|
std::cout << "You can use:\n cfg\n crt\n prj\n list\n setname\n loadcfg\n op" << std::endl;
|
||||||
|
|
||||||
return std::make_unique<EmptyTarget>();
|
return std::make_unique<EmptyTarget>();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (CheckPatternParametres(args, Parameter::Skip, "cfg",
|
if (CheckPatternParametres(args, Parameter::Skip, "cfg", Parameter::Anything)) {
|
||||||
Parameter::Anything)) {
|
|
||||||
LoadProjects();
|
LoadProjects();
|
||||||
auto p = projects_->GetCurrentProject();
|
auto p = projects_->GetCurrentProject();
|
||||||
|
|
||||||
|
@ -56,17 +55,44 @@ Clippy::TargetPtr Clippy::TryExecuteClippyCommand(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (CheckPatternParametres(args, Parameter::Skip, "crt",
|
if (CheckPatternParametres(args, Parameter::Skip, "crt", Parameter::Anything)) {
|
||||||
Parameter::Anything)) {
|
|
||||||
LoadProjects();
|
LoadProjects();
|
||||||
return std::make_unique<CreateProjectConfig>(projects_.value());
|
return std::make_unique<CreateProjectConfig>(projects_.value());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (CheckPatternParametres(args, Parameter::Skip, "prj", Parameter::Anything)) {
|
||||||
|
// TODO description current project or project by name
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CheckPatternParametres(args, Parameter::Skip, "list", Parameter::Nothing)) {
|
||||||
|
LoadProjects();
|
||||||
|
|
||||||
|
return std::make_unique<PrintListProjects>(projects_.value());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CheckPatternParametres(args, Parameter::Skip, "setname", Parameter::Anything)) {
|
||||||
|
LoadProjects();
|
||||||
|
|
||||||
|
return std::make_unique<SetNameProject>(projects_.value(), args[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CheckPatternParametres(args, Parameter::Skip, "loadcfg", Parameter::Nothing)) {
|
||||||
|
LoadProjects();
|
||||||
|
|
||||||
|
return std::make_unique<OpenLoadConfig>(projects_.value());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CheckPatternParametres(args, Parameter::Skip, "op", Parameter::Anything)) {
|
||||||
|
LoadProjects();
|
||||||
|
|
||||||
|
return std::make_unique<OpenProject>(projects_.value(), args[2]);
|
||||||
|
}
|
||||||
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
Clippy::TargetPtr Clippy::GetScriptTarget(
|
Clippy::TargetPtr Clippy::GetScriptTarget(const std::vector<std::string>& args) {
|
||||||
const std::vector<std::string>& args) {
|
|
||||||
LoadProjects();
|
LoadProjects();
|
||||||
auto p = projects_->GetCurrentProject();
|
auto p = projects_->GetCurrentProject();
|
||||||
|
|
||||||
|
|
|
@ -25,11 +25,13 @@ std::unique_ptr<clippy::targets::RunShellScript> Config::GetTarget(
|
||||||
std::vector<std::string> target_commands;
|
std::vector<std::string> target_commands;
|
||||||
target_commands.emplace_back("cd " + initial_directory_);
|
target_commands.emplace_back("cd " + initial_directory_);
|
||||||
|
|
||||||
bool target_begin = false;
|
bool target_exists = false;
|
||||||
|
bool in_target = false;
|
||||||
|
|
||||||
while (std::getline(in, current)) {
|
while (std::getline(in, current)) {
|
||||||
if (current == target + ":") {
|
if (current == target + ":") {
|
||||||
target_begin = true;
|
target_exists = true;
|
||||||
|
in_target = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,18 +39,18 @@ std::unique_ptr<clippy::targets::RunShellScript> Config::GetTarget(
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!std::isspace(current[0]) && target_begin) {
|
if (!std::isspace(current[0])) {
|
||||||
target_begin = false;
|
in_target = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (target_begin) {
|
if (in_target) {
|
||||||
target_commands.emplace_back(Strip(std::move(current)));
|
target_commands.emplace_back(Strip(std::move(current)));
|
||||||
} else if (current[0] == '!') {
|
} else if (current[0] == '!') {
|
||||||
target_commands.emplace_back(current.substr(1, current.size() - 1));
|
target_commands.emplace_back(current.substr(1, current.size() - 1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!target_begin) {
|
if (!target_exists) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,75 +1,45 @@
|
||||||
#include <clippy/project_list.hpp>
|
#include <clippy/project_list.hpp>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
|
#include <optional>
|
||||||
|
#include <sstream>
|
||||||
#include <utils/lock_file.hpp>
|
#include <utils/lock_file.hpp>
|
||||||
|
#include <utils/filesystem.hpp>
|
||||||
|
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <random>
|
#include <random>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
|
||||||
Config ProjectList::GetNewConfig(
|
#include <utils/filesystem.hpp>
|
||||||
const std::filesystem::path& config_directory) {
|
|
||||||
|
#include <jsoncons/json.hpp>
|
||||||
|
#include <jsoncons_ext/cbor/cbor.hpp>
|
||||||
|
#include "yaml-cpp/node/parse.h"
|
||||||
|
|
||||||
|
#include <yaml-cpp/yaml.h>
|
||||||
|
|
||||||
|
Config ProjectList::GetNewConfig(const std::filesystem::path& config_directory) {
|
||||||
std::lock_guard guard(lock_file_);
|
std::lock_guard guard(lock_file_);
|
||||||
|
|
||||||
LoadWithouLock();
|
LoadWithoutLock();
|
||||||
|
|
||||||
std::mt19937 rnd(std::chrono::system_clock::now().time_since_epoch().count());
|
auto path_to_config = utils::filesystem::GenerateFile(config_directory);
|
||||||
|
|
||||||
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::app);
|
|
||||||
out << std::filesystem::current_path() << " " << path_to_config << std::endl;
|
|
||||||
out.close();
|
|
||||||
|
|
||||||
projects_.emplace_back(std::filesystem::current_path(), path_to_config);
|
projects_.emplace_back(std::filesystem::current_path(), path_to_config);
|
||||||
|
|
||||||
|
SaveConfig();
|
||||||
|
|
||||||
return {path_to_config, std::filesystem::current_path()};
|
return {path_to_config, std::filesystem::current_path()};
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProjectList::Load() {
|
void ProjectList::Load() {
|
||||||
std::lock_guard guard(lock_file_);
|
std::lock_guard guard(lock_file_);
|
||||||
|
|
||||||
LoadWithouLock();
|
LoadWithoutLock();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProjectList::LoadWithouLock() {
|
void ProjectList::OldLoadConfig(const std::string& data) {
|
||||||
std::ifstream in(path_);
|
std::stringstream in(data);
|
||||||
|
|
||||||
Project current;
|
Project current;
|
||||||
|
|
||||||
|
@ -78,15 +48,147 @@ void ProjectList::LoadWithouLock() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<Project> ProjectList::GetCurrentProject() {
|
template <typename U, typename T>
|
||||||
|
void UpdateField(jsoncons::json& data, const std::string& field, std::optional<T> member) {
|
||||||
|
if (member) {
|
||||||
|
data[field] = static_cast<U>(member.value());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename U, typename T>
|
||||||
|
void UpdateField(YAML::Node& data, const std::string& field, std::optional<T> member) {
|
||||||
|
if (member) {
|
||||||
|
data[field] = static_cast<U>(member.value());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProjectList::SaveConfig(tag_json) {
|
||||||
|
jsoncons::json result;
|
||||||
|
|
||||||
|
result["version"] = "0.1";
|
||||||
|
result["projects"] = std::vector<std::string>();
|
||||||
|
|
||||||
|
for (auto& project : projects_) {
|
||||||
|
jsoncons::json current;
|
||||||
|
current["path_to_config"] = std::string(project.configuration_file);
|
||||||
|
current["path_root_project"] = std::string(project.root_project);
|
||||||
|
|
||||||
|
UpdateField<std::string>(current, "name", project.name);
|
||||||
|
UpdateField<std::string>(current, "open_script", project.open_script);
|
||||||
|
|
||||||
|
result["projects"].emplace_back(current);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ofstream out(path_);
|
||||||
|
out << result.to_string();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProjectList::SaveConfig() {
|
||||||
|
YAML::Node result;
|
||||||
|
result["version"] = "0.2";
|
||||||
|
|
||||||
|
for (auto& project : projects_) {
|
||||||
|
YAML::Node current;
|
||||||
|
|
||||||
|
UpdateField<std::string>(current, "name", project.name);
|
||||||
|
current["path_root_project"] = std::string(project.root_project);
|
||||||
|
current["path_to_config"] = std::string(project.configuration_file);
|
||||||
|
UpdateField<std::string>(current, "open_script", project.open_script);
|
||||||
|
|
||||||
|
result["projects"].push_back(current);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ofstream out(path_);
|
||||||
|
out << result;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
std::optional<T> GetOptionalField(const jsoncons::json& data, std::string field) {
|
||||||
|
return data.contains(field) ? std::make_optional(data[field].as<std::string>()) : std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
std::optional<T> GetOptionalField(const YAML::Node& data, std::string field) {
|
||||||
|
return data[field].IsDefined() ? std::make_optional(data[field].as<std::string>()) : std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProjectList::LoadConfig(const YAML::Node& data) {
|
||||||
|
if (data["version"].as<std::string>() != "0.2") {
|
||||||
|
throw std::logic_error("unsupport version");
|
||||||
|
}
|
||||||
|
|
||||||
|
Project current;
|
||||||
|
for (const auto& project : data["projects"]) {
|
||||||
|
current.configuration_file = project["path_to_config"].as<std::string>();
|
||||||
|
current.root_project = project["path_root_project"].as<std::string>();
|
||||||
|
|
||||||
|
current.name = GetOptionalField<std::string>(project, "name");
|
||||||
|
current.open_script = GetOptionalField<std::string>(project, "open_script");
|
||||||
|
|
||||||
|
projects_.emplace_back(current);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProjectList::LoadConfig(const jsoncons::json& data) {
|
||||||
|
if (data["version"] != "0.1") {
|
||||||
|
throw std::logic_error("unsupported version config");
|
||||||
|
}
|
||||||
|
|
||||||
|
Project current;
|
||||||
|
for (auto& project : data["projects"].array_range()) {
|
||||||
|
current.configuration_file = project["path_to_config"].as<std::string>();
|
||||||
|
current.root_project = project["path_root_project"].as<std::string>();
|
||||||
|
|
||||||
|
current.name = GetOptionalField<std::string>(project, "name");
|
||||||
|
current.open_script = GetOptionalField<std::string>(project, "open_script");
|
||||||
|
|
||||||
|
projects_.emplace_back(current);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProjectList::LoadWithoutLock() {
|
||||||
|
projects_.clear();
|
||||||
|
|
||||||
|
try {
|
||||||
|
LoadConfig(YAML::LoadFile(path_));
|
||||||
|
} catch (...) {
|
||||||
|
auto data = utils::filesystem::LoadFile(path_);
|
||||||
|
|
||||||
|
std::cout << "I can't parse yaml. Try read json?" << std::endl;
|
||||||
|
|
||||||
|
std::string result;
|
||||||
|
std::getline(std::cin, result);
|
||||||
|
|
||||||
|
if (result == "y") {
|
||||||
|
try {
|
||||||
|
LoadConfig(jsoncons::json::parse(data));
|
||||||
|
} catch (...) {
|
||||||
|
std::cout << "I can't read project lists. Try fix it?" << std::endl;
|
||||||
|
|
||||||
|
std::string result;
|
||||||
|
std::getline(std::cin, result);
|
||||||
|
|
||||||
|
if (result == "y") {
|
||||||
|
OldLoadConfig(data);
|
||||||
|
SaveConfig();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SaveConfig();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Project* ProjectList::GetCurrentProject_() {
|
||||||
auto current_path = std::filesystem::current_path();
|
auto current_path = std::filesystem::current_path();
|
||||||
|
|
||||||
std::optional<Project> result;
|
Project* result = nullptr;
|
||||||
auto UpdateResult = [&result](Project p) {
|
auto UpdateResult = [&result](Project& p) {
|
||||||
if (!result.has_value()) {
|
if (!result) {
|
||||||
result = p;
|
result = &p;
|
||||||
} else {
|
} else {
|
||||||
result = std::max(p, result.value());
|
if (*result < p) {
|
||||||
|
result = &p;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -108,3 +210,16 @@ std::optional<Project> ProjectList::GetCurrentProject() {
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Project* ProjectList::GetProjectByName_(const std::string& name) {
|
||||||
|
Project* result = nullptr;
|
||||||
|
for (auto& project : projects_) {
|
||||||
|
if (!project.name) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (project.name == name) {
|
||||||
|
result = &project;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
|
@ -1,12 +1,20 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <clippy/config.hpp>
|
#include <clippy/config.hpp>
|
||||||
|
|
||||||
|
#include <mutex>
|
||||||
|
#include <stdexcept>
|
||||||
#include <utils/lock_file.hpp>
|
#include <utils/lock_file.hpp>
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
|
||||||
|
#include <jsoncons/json.hpp>
|
||||||
|
#include <yaml-cpp/yaml.h>
|
||||||
|
#include "utils/config_path.hpp"
|
||||||
|
#include "utils/editor.hpp"
|
||||||
|
#include "utils/filesystem.hpp"
|
||||||
|
|
||||||
struct Project {
|
struct Project {
|
||||||
Project() {}
|
Project() {}
|
||||||
|
|
||||||
|
@ -15,10 +23,14 @@ struct Project {
|
||||||
|
|
||||||
std::strong_ordering operator<=>(const Project&) const = default;
|
std::strong_ordering operator<=>(const Project&) const = default;
|
||||||
|
|
||||||
Config GetConfig() { return Config{configuration_file, root_project}; }
|
Config GetConfig() {
|
||||||
|
return Config{configuration_file, root_project};
|
||||||
|
}
|
||||||
|
|
||||||
std::filesystem::path root_project;
|
std::filesystem::path root_project;
|
||||||
std::filesystem::path configuration_file;
|
std::filesystem::path configuration_file;
|
||||||
|
std::optional<std::string> name;
|
||||||
|
std::optional<std::filesystem::path> open_script;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ProjectList {
|
class ProjectList {
|
||||||
|
@ -29,13 +41,72 @@ class ProjectList {
|
||||||
|
|
||||||
Config GetNewConfig(const std::filesystem::path& config_directory);
|
Config GetNewConfig(const std::filesystem::path& config_directory);
|
||||||
|
|
||||||
const std::vector<Project>& GetProjects() const { return projects_; }
|
const std::vector<Project>& GetProjects() const {
|
||||||
|
return projects_;
|
||||||
|
}
|
||||||
|
|
||||||
std::optional<Project> GetCurrentProject();
|
std::optional<Project> GetCurrentProject() {
|
||||||
|
auto* p = GetCurrentProject_();
|
||||||
|
if (p) {
|
||||||
|
return *p;
|
||||||
|
} else {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetNameCurrentProject(const std::string& name) {
|
||||||
|
auto* p = GetCurrentProject_();
|
||||||
|
if (p) {
|
||||||
|
p->name = name;
|
||||||
|
SaveConfig();
|
||||||
|
} else {
|
||||||
|
throw std::logic_error("Not exists current project");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::filesystem::path GetCurrentLoadConfig() {
|
||||||
|
auto* p = GetCurrentProject_();
|
||||||
|
if (p) {
|
||||||
|
if (p->open_script) {
|
||||||
|
return p->open_script.value();
|
||||||
|
} else {
|
||||||
|
auto scripts_path = utils::GetProjectDirectory() / "scripts";
|
||||||
|
{
|
||||||
|
std::lock_guard lock(lock_file_);
|
||||||
|
p->open_script = utils::filesystem::GenerateFile(scripts_path);
|
||||||
|
SaveConfig();
|
||||||
|
}
|
||||||
|
return p->open_script.value();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw std::logic_error("Not exists current project");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<Project> GetProjectByName(const std::string& name) {
|
||||||
|
auto* p = GetProjectByName_(name);
|
||||||
|
if (p) {
|
||||||
|
return *p;
|
||||||
|
} else {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
Project* GetCurrentProject_();
|
||||||
|
Project* GetProjectByName_(const std::string&);
|
||||||
|
|
||||||
|
void OldLoadConfig(const std::string&);
|
||||||
|
|
||||||
|
struct tag_json {};
|
||||||
|
void SaveConfig(tag_json);
|
||||||
|
|
||||||
|
void SaveConfig();
|
||||||
|
|
||||||
void Load();
|
void Load();
|
||||||
void LoadWithouLock();
|
void LoadConfig(const jsoncons::json&);
|
||||||
|
void LoadConfig(const YAML::Node&);
|
||||||
|
void LoadWithoutLock();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::filesystem::path path_;
|
std::filesystem::path path_;
|
||||||
|
|
|
@ -11,8 +11,12 @@
|
||||||
#include <rang.hpp>
|
#include <rang.hpp>
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <deque>
|
||||||
#include <ranges>
|
#include <ranges>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
#include "utils/filesystem.hpp"
|
||||||
|
|
||||||
|
#include <tmuxub/tmuxub.hpp>
|
||||||
|
|
||||||
namespace clippy::targets {
|
namespace clippy::targets {
|
||||||
class Target {
|
class Target {
|
||||||
|
@ -31,7 +35,9 @@ class OpenProjectConfig : public Target {
|
||||||
public:
|
public:
|
||||||
OpenProjectConfig(Config config) : config_(config) {}
|
OpenProjectConfig(Config config) : config_(config) {}
|
||||||
|
|
||||||
void Execute() override { config_.Edit(); }
|
void Execute() override {
|
||||||
|
config_.Edit();
|
||||||
|
}
|
||||||
~OpenProjectConfig() override {}
|
~OpenProjectConfig() override {}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -58,7 +64,8 @@ class CreateProjectConfig : public Target {
|
||||||
class RunShellScript : public Target {
|
class RunShellScript : public Target {
|
||||||
public:
|
public:
|
||||||
template <template <typename, typename...> class C, typename... Params>
|
template <template <typename, typename...> class C, typename... Params>
|
||||||
RunShellScript(const C<std::string, Params...>& commands) : commands_(commands.begin(), commands.end()) {}
|
RunShellScript(const C<std::string, Params...>& commands)
|
||||||
|
: commands_(commands.begin(), commands.end()) {}
|
||||||
|
|
||||||
void PushBack(const std::string& command) {
|
void PushBack(const std::string& command) {
|
||||||
commands_.push_back(command);
|
commands_.push_back(command);
|
||||||
|
@ -75,16 +82,15 @@ class RunShellScript : public Target {
|
||||||
cppshell::Shell s("bash", tmp_path);
|
cppshell::Shell s("bash", tmp_path);
|
||||||
|
|
||||||
for (auto& command : commands_) {
|
for (auto& command : commands_) {
|
||||||
std::cout << rang::fg::green << rang::style::bold << rang::bgB::blue << "->" << rang::fg::reset
|
std::cout << rang::fg::green << rang::style::bold << rang::bgB::blue << "->"
|
||||||
<< rang::bg::reset << " " << command << rang::style::reset << std::endl;
|
<< rang::fg::reset << rang::bg::reset << " " << command << rang::style::reset
|
||||||
|
<< std::endl;
|
||||||
s.Execute(command);
|
s.Execute(command);
|
||||||
if (int err = s.GetExitCodeLastCommand(); err != 0) {
|
if (int err = s.GetExitCodeLastCommand(); err != 0) {
|
||||||
std::cout << rang::fg::red << rang::style::bold
|
std::cout << rang::fg::red << rang::style::bold << "Command exit with code " << err
|
||||||
<< "Command exit with code " << err << rang::fg::reset
|
<< rang::fg::reset << rang::style::reset << std::endl;
|
||||||
<< rang::style::reset << std::endl;
|
std::cout << rang::fg::blue << rang::style::bold << "Continue execution? [Y/n] "
|
||||||
std::cout << rang::fg::blue << rang::style::bold
|
<< rang::fg::reset << rang::style::reset;
|
||||||
<< "Continue execution? [Y/n] " << rang::fg::reset
|
|
||||||
<< rang::style::reset;
|
|
||||||
|
|
||||||
std::string result;
|
std::string result;
|
||||||
std::getline(std::cin, result);
|
std::getline(std::cin, result);
|
||||||
|
@ -102,4 +108,72 @@ class RunShellScript : public Target {
|
||||||
private:
|
private:
|
||||||
std::deque<std::string> commands_;
|
std::deque<std::string> commands_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class PrintListProjects : public Target {
|
||||||
|
public:
|
||||||
|
PrintListProjects(ProjectList& projects) : projects_(projects) {}
|
||||||
|
|
||||||
|
void Execute() override {
|
||||||
|
for (auto& project : projects_.GetProjects()) {
|
||||||
|
std::cout << std::setw(10) << project.name.value_or("-") << " " << std::setw(50)
|
||||||
|
<< project.root_project << " " << std::setw(70) << project.configuration_file
|
||||||
|
<< std::setw(70) << project.open_script.value_or("-") << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
ProjectList& projects_;
|
||||||
|
};
|
||||||
|
|
||||||
|
class SetNameProject : public Target {
|
||||||
|
public:
|
||||||
|
SetNameProject(ProjectList& projects, std::string new_name)
|
||||||
|
: projects_(projects), new_name_(std::move(new_name)) {}
|
||||||
|
|
||||||
|
void Execute() override {
|
||||||
|
projects_.SetNameCurrentProject(new_name_);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
ProjectList& projects_;
|
||||||
|
std::string new_name_;
|
||||||
|
};
|
||||||
|
|
||||||
|
class OpenLoadConfig : public Target {
|
||||||
|
public:
|
||||||
|
OpenLoadConfig(ProjectList& projects) : projects_(projects) {}
|
||||||
|
|
||||||
|
void Execute() override {
|
||||||
|
utils::OpenEditor(projects_.GetCurrentLoadConfig());
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
ProjectList& projects_;
|
||||||
|
std::string new_name_;
|
||||||
|
};
|
||||||
|
|
||||||
|
class OpenProject : public Target {
|
||||||
|
public:
|
||||||
|
OpenProject(ProjectList& projects, const std::string& name) : projects_(projects), name_(name) {}
|
||||||
|
|
||||||
|
void Execute() override {
|
||||||
|
auto p = projects_.GetProjectByName(name_);
|
||||||
|
|
||||||
|
tmuxub::Tmux t(utils::GetProjectDirectory() / "tmuxsocket");
|
||||||
|
if (t.HasSession(name_)) {
|
||||||
|
t.ConnectToSession(name_);
|
||||||
|
t.Exec();
|
||||||
|
} else {
|
||||||
|
auto file = utils::filesystem::LoadFile(p->open_script.value());
|
||||||
|
chdir(std::string(p.value().root_project).data());
|
||||||
|
t.CreateSession(name_);
|
||||||
|
t.SplitWindow(file);
|
||||||
|
t.Exec();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
ProjectList& projects_;
|
||||||
|
std::string name_;
|
||||||
|
};
|
||||||
} // namespace clippy::targets
|
} // namespace clippy::targets
|
||||||
|
|
|
@ -6,6 +6,10 @@
|
||||||
|
|
||||||
#include <csignal>
|
#include <csignal>
|
||||||
|
|
||||||
|
#include <utils/filesystem.hpp>
|
||||||
|
|
||||||
|
#include <jsoncons/json.hpp>
|
||||||
|
|
||||||
int main(int argc, char* argv[]) {
|
int main(int argc, char* argv[]) {
|
||||||
std::signal(SIGPIPE, SIG_IGN);
|
std::signal(SIGPIPE, SIG_IGN);
|
||||||
|
|
||||||
|
|
67
src/utils/filesystem.hpp
Normal file
67
src/utils/filesystem.hpp
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <string>
|
||||||
|
#include <filesystem>
|
||||||
|
#include <fstream>
|
||||||
|
#include <random>
|
||||||
|
#include <chrono>
|
||||||
|
|
||||||
|
#include <utils/random.hpp>
|
||||||
|
|
||||||
|
namespace utils::filesystem {
|
||||||
|
inline std::string LoadFile(const std::filesystem::path& file) {
|
||||||
|
std::ifstream in(file);
|
||||||
|
|
||||||
|
std::string result;
|
||||||
|
std::string tmp;
|
||||||
|
|
||||||
|
while (std::getline(in, tmp)) {
|
||||||
|
result += tmp;
|
||||||
|
result += "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::filesystem::path GenerateFile(std::filesystem::path dir) {
|
||||||
|
if (!std::filesystem::is_directory(dir)) {
|
||||||
|
throw std::logic_error(std::string(dir) + " is not directory");
|
||||||
|
}
|
||||||
|
|
||||||
|
static auto RandomSymbol = []() {
|
||||||
|
int n = utils::random::RandInt(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 = [length = 6]() mutable {
|
||||||
|
if (length > 10) {
|
||||||
|
throw std::logic_error("failed to create file");
|
||||||
|
}
|
||||||
|
std::string filename;
|
||||||
|
for (size_t i = 0; i < length; ++i) {
|
||||||
|
filename += RandomSymbol();
|
||||||
|
}
|
||||||
|
length++;
|
||||||
|
|
||||||
|
return filename;
|
||||||
|
};
|
||||||
|
|
||||||
|
auto filename = GenerateFilename();
|
||||||
|
while (true) {
|
||||||
|
if (std::filesystem::status(dir / filename).type() == std::filesystem::file_type::not_found) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
filename = GenerateFilename();
|
||||||
|
}
|
||||||
|
|
||||||
|
return dir / filename;
|
||||||
|
}
|
||||||
|
} // namespace utils::filesystem
|
12
src/utils/random.hpp
Normal file
12
src/utils/random.hpp
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <random>
|
||||||
|
#include <chrono>
|
||||||
|
|
||||||
|
namespace utils::random {
|
||||||
|
static inline std::mt19937_64 rnd(std::chrono::system_clock::now().time_since_epoch().count());
|
||||||
|
|
||||||
|
inline uint64_t RandInt(uint64_t max_n) {
|
||||||
|
return rnd() % max_n;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue