Compare commits

..

No commits in common. "48f25d4baa4b106342cbf681f14db8e3293682b7" and "7e4141b2825b98ea9bde2e6a963687e7afa7efda" have entirely different histories.

9 changed files with 87 additions and 480 deletions

View file

@ -8,7 +8,7 @@ file(GLOB_RECURSE SOURCES_FILES src/*)
add_executable(clippy_terminal ${SOURCES_FILES})
target_include_directories(clippy_terminal PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src)
target_link_libraries(clippy_terminal PRIVATE cppshell tmuxub rang jsoncons yaml-cpp)
target_link_libraries(clippy_terminal cppshell rang)
install(TARGETS clippy_terminal DESTINATION bin)
@ -20,31 +20,9 @@ FetchContent_Declare(
)
FetchContent_MakeAvailable(cppshell)
FetchContent_Declare(
tmuxub
GIT_REPOSITORY https://gitlab.com/Onyad/tmuxub
GIT_TAG origin/main
)
FetchContent_MakeAvailable(tmuxub)
FetchContent_Declare(
rang
GIT_REPOSITORY https://github.com/agauniyal/rang.git
GIT_TAG origin/master
)
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)

View file

@ -25,13 +25,15 @@ void Clippy::Run(const std::vector<std::string>& args) {
for (size_t i = 1; i < args.size(); ++i) {
std::cout << args[i] << (i + 1 == args.size() ? "" : ",") << " ";
}
std::cout << "}" << rang::bg::reset << rang::style::reset << std::endl;
std::cout << "}" << std::endl << rang::bg::reset << rang::style::reset;
}
Clippy::TargetPtr Clippy::TryExecuteClippyCommand(const std::vector<std::string>& args) {
Clippy::TargetPtr Clippy::TryExecuteClippyCommand(
const std::vector<std::string>& args) {
using namespace utils::parametres;
using namespace clippy::targets;
if (CheckPatternParametres(args, Parameter::Skip, "help", Parameter::Anything)) {
if (CheckPatternParametres(args, Parameter::Skip, "help",
Parameter::Anything)) {
std::cout << "Hello I'm clippy" << std::endl;
std::cout << "Parametres: { ";
for (size_t i = 0; i < args.size(); ++i) {
@ -39,12 +41,11 @@ Clippy::TargetPtr Clippy::TryExecuteClippyCommand(const std::vector<std::string>
}
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>();
}
if (CheckPatternParametres(args, Parameter::Skip, "cfg", Parameter::Anything)) {
if (CheckPatternParametres(args, Parameter::Skip, "cfg",
Parameter::Anything)) {
LoadProjects();
auto p = projects_->GetCurrentProject();
@ -55,44 +56,17 @@ Clippy::TargetPtr Clippy::TryExecuteClippyCommand(const std::vector<std::string>
}
}
if (CheckPatternParametres(args, Parameter::Skip, "crt", Parameter::Anything)) {
if (CheckPatternParametres(args, Parameter::Skip, "crt",
Parameter::Anything)) {
LoadProjects();
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;
}
Clippy::TargetPtr Clippy::GetScriptTarget(const std::vector<std::string>& args) {
Clippy::TargetPtr Clippy::GetScriptTarget(
const std::vector<std::string>& args) {
LoadProjects();
auto p = projects_->GetCurrentProject();

View file

@ -25,13 +25,11 @@ std::unique_ptr<clippy::targets::RunShellScript> Config::GetTarget(
std::vector<std::string> target_commands;
target_commands.emplace_back("cd " + initial_directory_);
bool target_exists = false;
bool in_target = false;
bool target_begin = false;
while (std::getline(in, current)) {
if (current == target + ":") {
target_exists = true;
in_target = true;
target_begin = true;
continue;
}
@ -39,18 +37,18 @@ std::unique_ptr<clippy::targets::RunShellScript> Config::GetTarget(
continue;
}
if (!std::isspace(current[0])) {
in_target = false;
if (!std::isspace(current[0]) && target_begin) {
target_begin = false;
}
if (in_target) {
if (target_begin) {
target_commands.emplace_back(Strip(std::move(current)));
} else if (current[0] == '!') {
target_commands.emplace_back(current.substr(1, current.size() - 1));
}
}
if (!target_exists) {
if (!target_begin) {
return nullptr;
}

View file

@ -1,45 +1,75 @@
#include <clippy/project_list.hpp>
#include <filesystem>
#include <optional>
#include <sstream>
#include <utils/lock_file.hpp>
#include <utils/filesystem.hpp>
#include <fstream>
#include <mutex>
#include <random>
#include <chrono>
#include <utils/filesystem.hpp>
#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) {
Config ProjectList::GetNewConfig(
const std::filesystem::path& config_directory) {
std::lock_guard guard(lock_file_);
LoadWithoutLock();
LoadWithouLock();
auto path_to_config = utils::filesystem::GenerateFile(config_directory);
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::app);
out << std::filesystem::current_path() << " " << path_to_config << std::endl;
out.close();
projects_.emplace_back(std::filesystem::current_path(), path_to_config);
SaveConfig();
return {path_to_config, std::filesystem::current_path()};
}
void ProjectList::Load() {
std::lock_guard guard(lock_file_);
LoadWithoutLock();
LoadWithouLock();
}
void ProjectList::OldLoadConfig(const std::string& data) {
std::stringstream in(data);
void ProjectList::LoadWithouLock() {
std::ifstream in(path_);
Project current;
@ -48,147 +78,15 @@ void ProjectList::OldLoadConfig(const std::string& data) {
}
}
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_() {
std::optional<Project> ProjectList::GetCurrentProject() {
auto current_path = std::filesystem::current_path();
Project* result = nullptr;
auto UpdateResult = [&result](Project& p) {
if (!result) {
result = &p;
std::optional<Project> result;
auto UpdateResult = [&result](Project p) {
if (!result.has_value()) {
result = p;
} else {
if (*result < p) {
result = &p;
}
result = std::max(p, result.value());
}
};
@ -210,16 +108,3 @@ Project* ProjectList::GetCurrentProject_() {
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;
}

View file

@ -1,20 +1,12 @@
#pragma once
#include <clippy/config.hpp>
#include <mutex>
#include <stdexcept>
#include <utils/lock_file.hpp>
#include <vector>
#include <filesystem>
#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 {
Project() {}
@ -23,14 +15,10 @@ struct Project {
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 configuration_file;
std::optional<std::string> name;
std::optional<std::filesystem::path> open_script;
};
class ProjectList {
@ -41,72 +29,13 @@ class ProjectList {
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() {
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;
}
}
std::optional<Project> GetCurrentProject();
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 LoadConfig(const jsoncons::json&);
void LoadConfig(const YAML::Node&);
void LoadWithoutLock();
void LoadWithouLock();
private:
std::filesystem::path path_;

View file

@ -11,12 +11,8 @@
#include <rang.hpp>
#include <iostream>
#include <deque>
#include <ranges>
#include <functional>
#include "utils/filesystem.hpp"
#include <tmuxub/tmuxub.hpp>
namespace clippy::targets {
class Target {
@ -35,9 +31,7 @@ class OpenProjectConfig : public Target {
public:
OpenProjectConfig(Config config) : config_(config) {}
void Execute() override {
config_.Edit();
}
void Execute() override { config_.Edit(); }
~OpenProjectConfig() override {}
private:
@ -64,8 +58,7 @@ class CreateProjectConfig : public Target {
class RunShellScript : public Target {
public:
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) {
commands_.push_back(command);
@ -82,15 +75,16 @@ class RunShellScript : public Target {
cppshell::Shell s("bash", tmp_path);
for (auto& command : commands_) {
std::cout << rang::fg::green << rang::style::bold << rang::bgB::blue << "->"
<< rang::fg::reset << rang::bg::reset << " " << command << rang::style::reset
<< std::endl;
std::cout << rang::fg::green << rang::style::bold << rang::bgB::blue << "->" << rang::fg::reset
<< rang::bg::reset << " " << command << rang::style::reset << std::endl;
s.Execute(command);
if (int err = s.GetExitCodeLastCommand(); err != 0) {
std::cout << rang::fg::red << rang::style::bold << "Command exit with code " << err
<< rang::fg::reset << rang::style::reset << std::endl;
std::cout << rang::fg::blue << rang::style::bold << "Continue execution? [Y/n] "
<< rang::fg::reset << rang::style::reset;
std::cout << rang::fg::red << rang::style::bold
<< "Command exit with code " << err << rang::fg::reset
<< rang::style::reset << std::endl;
std::cout << rang::fg::blue << rang::style::bold
<< "Continue execution? [Y/n] " << rang::fg::reset
<< rang::style::reset;
std::string result;
std::getline(std::cin, result);
@ -108,72 +102,4 @@ class RunShellScript : public Target {
private:
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

View file

@ -6,10 +6,6 @@
#include <csignal>
#include <utils/filesystem.hpp>
#include <jsoncons/json.hpp>
int main(int argc, char* argv[]) {
std::signal(SIGPIPE, SIG_IGN);

View file

@ -1,67 +0,0 @@
#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

View file

@ -1,12 +0,0 @@
#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;
}
}