Goto/main.cpp
UnrealDragon e9eb24defb goto v0.0.1
2025-09-10 18:54:44 +05:30

304 lines
9.7 KiB
C++

#include <cstdlib>
#include <fstream>
# include <iostream>
# include <filesystem>
# include <unordered_map>
#include <QObject>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
#include <QString>
#include <QCoreApplication>
#include <QProcess>
#include <QFile>
#include <QTimer>
# include <QStandardPaths>
#include <sstream>
#include <type_traits>
# include <unistd.h>
#include <unordered_map>
# include <expected>
namespace globals {
static std::filesystem::path config_path;
std::expected<QJsonObject, bool> read_config() {
if (std::filesystem::exists(globals::config_path)) {
std::fstream file_input(globals::config_path, std::fstream::in);
std::string data;
std::string temp;
while(std::getline(file_input, temp)) {
data += temp;
}
file_input.close();
return QJsonDocument::fromJson(QByteArray::fromStdString(data)).object();
} else {
return std::unexpected(false);
}
}
void overwrite_config(QJsonObject& obj) {
QJsonDocument doc;
doc.setObject(obj);
std::string data = doc.toJson().toStdString();
std::fstream file_input(globals::config_path, std::fstream::out);
file_input << data;
file_input.flush();
file_input.close();
}
}
std::string get_current_time() {
const auto now = std::chrono::system_clock::now();
std::time_t ctime_now = std::chrono::system_clock::to_time_t(now);
std::stringstream ss;
ss << "[" << std::put_time(std::localtime(&ctime_now), "%d-%m-%y %H:%M:%S") << "] ";
return ss.str();
}
int get_parent_id() {
std::stringstream ss;
int var;
ss << getppid();
ss >> var;
return var;
}
void show_help() {
std::stringstream ss;
ss << "Usage: goto [OPTION|LINK_NAME]" << std::endl;
ss << "Options:" << std::endl;
ss << " -h --help : Show this info" << std::endl;
ss << " -c --create_link : Create a new link e.g: goto --create_link [LINK_NAME] [FROM_PATH]" << std::endl;
ss << " -l --list : List all the existing links" << std::endl;
ss << " -d --delete_link : Delete an exisiting link e.g: goto -d [LINK_NAME]" << std::endl;
ss << " -rf --delete_file : Delete the existing link file completely." << std::endl;
ss << " [LINK_NAME] : Goes to an exisiting link e.g: goto [LINK_NAME]" << std::endl;
ss << " [LINK_NAME] : Rules for creating [LINK_NAME] name must be BASH variable and must not start with \"-\"" << std::endl;
ss << " [LINK_NAME] : [LINK_NAME] cannot be \"last\"" << std::endl;
std::cout << ss.str();
}
void show_invalid() {
std::stringstream ss;
ss << "[goto] Invalid arguments use -h or --help for help" << std::endl;
std::cout << ss.str();
}
void print_links() {
QJsonObject links = globals::read_config().or_else([](bool err){
std::cout << "Could not read config file." << std::endl;
exit(-1);
return std::expected<QJsonObject, bool> {QJsonObject()};
}).value();
std::unordered_map<std::string, std::string> link_list;
for(auto i = links.begin(); i != links.end(); i++) {
link_list[i.key().toStdString()] = i.value().toString().toStdString();
}
int iter = 1;
std::cout << "Links from file: " << globals::config_path << std::endl;
for(auto &[key, value]: link_list) {
if(key != "last")
std::cout << iter++ << ". " << key << " --> " << value << std::endl;
}
if(link_list.find("last") != link_list.end()) {
std::cout << iter << ". Last place --> " << link_list["last"] << std::endl;
}
}
void delete_link(std::string link_name) {
QJsonObject obj = globals::read_config().or_else([](bool err){
std::cout << "Could not read config file." << std::endl;
exit(-1);
return std::expected<QJsonObject, bool> {QJsonObject()};
}).value();
obj.remove(QString::fromStdString(link_name));
globals::overwrite_config(obj);
std::cout << "Link: " << link_name << " deleted." << std::endl;
}
void create_link(std::string link_name, std::string dir) {
if(dir == ".") {
dir = std::filesystem::current_path().string();
}
if(std::filesystem::exists(globals::config_path)) {
QJsonObject links = globals::read_config().or_else([](bool err){
std::cout << "Could not read config file." << std::endl;
exit(-1);
return std::expected<QJsonObject, bool> {QJsonObject()};
}).value();
if(links.find(QString::fromStdString(link_name)) == links.end())
links[QString::fromStdString(link_name)] = QString::fromStdString(dir);
else {
std::string char_in;
std::cout << "Warning: Link name: " << link_name << " already exists. Do you want to overwrite it?";
std::cout.flush();
std::getline(std::cin, char_in);
if(char_in.size() >= 1 && (char_in[0] == 'Y' || char_in[0] == 'y')) {
std::string prev_value = links[QString::fromStdString(link_name)].toString().toStdString();
links[QString::fromStdString(link_name)] = QString::fromStdString(dir);
globals::overwrite_config(links);
std::cout << "Overwritten link: " << link_name << " -> " << dir << " from: " << prev_value << " in: " << globals::config_path << std::endl;
exit(0);
}
else {
exit(-1);
}
}
globals::overwrite_config(links);
std::cout << "Written new link: " << link_name << " -> " << dir << " in: " << globals::config_path << std::endl;
exit(0);
}
else {
QJsonObject new_link;
new_link[QString::fromStdString(link_name)] = QString::fromStdString(dir);
globals::overwrite_config(new_link);
std::cout << "Written new link: " << link_name << " -> " << dir << " in: " << globals::config_path << std::endl;
exit(0);
}
}
void goto_link(std::string link_name) {
QJsonObject config = globals::read_config().or_else([](bool err){
std::cout << "Could not read config file." << std::endl;
exit(-1);
return std::expected<QJsonObject, bool> {QJsonObject()};
}).value();
std::string place = config[QString::fromStdString(link_name)].toString("-_- Place Does not exist.").toStdString();
if(place == "-_- Place Does not exist.") {
std::cout << "Specified link: " << link_name << " does not exist in links file." << std::endl;
exit(-1);
}
config["last"] = QString::fromStdString(place);
globals::overwrite_config(config);
// int parent_id = get_parent_id();
// std::ostringstream std_out, std_err, std_log;
//
// auto prev_cout_buffer = std::cout.rdbuf();
// auto prev_clog_buffer = std::clog.rdbuf();
// auto prev_cerr_buffer = std::cerr.rdbuf();
// std::cout.rdbuf(std_out.rdbuf());
// std::cerr.rdbuf(std_err.rdbuf());
// std::clog.rdbuf(std_log.rdbuf());
std::cout << place << std::endl;
// system(std::format("sh -c cd {}", place).c_str());
// system(std::format("kill -9 {}", parent_id).c_str());
// QProcess *proc = new QProcess();
// proc->setProgram("/usr/bin/bash");
// proc->setWorkingDirectory(QString::fromStdString(place));
// proc->startDetached();
// std::cout.rdbuf(prev_cout_buffer);
// std::cerr.rdbuf(prev_cerr_buffer);
// std::clog.rdbuf(prev_clog_buffer);
}
void delete_file() {
std::string in;
std::cout << "Are you sure you want to completely remove the links.json file?";
std::cout.flush();
std::getline(std::cin, in);
if(in.size() >= 1 && (in[0] == 'y' || in[0] == 'Y')) {
std::filesystem::remove(globals::config_path);
std::cout << "Removed config file from: " <<globals::config_path << std::endl;
} else {
std::cout << "Not removing config file." << std::endl;
}
}
int main(int argc, char *argv[]) {
QCoreApplication app(argc, argv);
QCoreApplication::setApplicationName("goto");
QCoreApplication::setApplicationVersion("0.0.1");
globals::config_path = QStandardPaths::writableLocation(QStandardPaths::ConfigLocation).toStdString();
globals::config_path = globals::config_path / "goto";
if(!std::filesystem::exists(globals::config_path)) {
std::filesystem::create_directories(globals::config_path);
}
globals::config_path = globals::config_path / "links.json";
std::unordered_map<std::string, int> command_list = {{"help", 1}, {"h", 1}, {"create_link", 2}, {"c", 2}, {"l", 3}, {"list", 3}, {"d", 4}, {"delete_link", 4}, {"rf", 5}, {"delete_file", 5}};
int command_size = argc - 1;
if(command_size == 0) {
show_invalid();
exit(0);
} else {
bool arg = false;
if(std::string(argv[1]).starts_with("--") || std::string(argv[1]).starts_with("-")) {
while(argv[1][0] == '-') {
++argv[1];
}
arg = true;
}
if(arg) {
if(command_list.find(argv[1]) == command_list.end()) {
show_invalid();
exit(-1);
}
else {
switch (command_list[argv[1]]) {
case 1: {
show_help();
exit(0);
}
case 2: {
if(command_size != 3) {
show_invalid();
exit(-1);
}
std::string link_name, directory;
link_name = argv[2];
directory = argv[3];
create_link(link_name, directory);
exit(0);
}
case 3: {
if(command_size != 1) {
show_invalid();
exit(-1);
}
print_links();
exit(0);
}
case 4: {
if(command_size != 2) {
show_invalid();
exit(-1);
}
std::string link_name;
link_name = argv[2];
delete_link(link_name);
exit(0);
}
case 5: {
if(command_size != 1) {
show_invalid();
exit(-1);
}
delete_file();
exit(0);
}
}
}
}
else {
std::string link_name = argv[1];
goto_link(link_name);
exit(0);
}
exit(0);
}
return app.exec();
}