diff options
| -rw-r--r-- | YATwm.nix | 1 | ||||
| -rw-r--r-- | flake.lock | 6 | ||||
| -rw-r--r-- | flake.nix | 5 | ||||
| -rw-r--r-- | makefile | 3 | ||||
| -rw-r--r-- | src/IPC.h | 2 | ||||
| -rw-r--r-- | src/commands.cpp | 372 | ||||
| -rw-r--r-- | src/commands.h | 91 | ||||
| -rw-r--r-- | src/config.cpp | 5 | ||||
| -rw-r--r-- | src/config.h | 2 | ||||
| -rw-r--r-- | src/keybinds.cpp | 5 | ||||
| -rw-r--r-- | src/keybinds.h | 2 |
11 files changed, 475 insertions, 19 deletions
@@ -33,6 +33,5 @@ runHook postInstall xorg.libXrandr libnotify pkg-config - inputs.libCommands.packages.x86_64-linux.default ]; } @@ -2,11 +2,11 @@ "nodes": { "nixpkgs": { "locked": { - "lastModified": 1734323986, - "narHash": "sha256-m/lh6hYMIWDYHCAsn81CDAiXoT3gmxXI9J987W5tZrE=", + "lastModified": 1735141468, + "narHash": "sha256-VIAjBr1qGcEbmhLwQJD6TABppPMggzOvqFsqkDoMsAY=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "394571358ce82dff7411395829aa6a3aad45b907", + "rev": "4005c3ff7505313cbc21081776ad0ce5dfd7a3ce", "type": "github" }, "original": { @@ -2,10 +2,6 @@ description = "YATwm"; inputs = { nixpkgs.url = "github:NixOS/nixpkgs/nixos-24.11"; - libCommands = { - url = "github:BossCode45/commands"; - inputs.nixpkgs.follows = "nixpkgs"; - }; }; outputs = { self, nixpkgs, ... }@inputs: let pkgs = nixpkgs.legacyPackages.x86_64-linux; @@ -20,7 +16,6 @@ pkgs.libnotify pkgs.pkg-config pkgs.clang-tools - inputs.libCommands.packages.x86_64-linux.default ]; }; packages.x86_64-linux.YATwm = (pkgs.callPackage ./YATwm.nix {inherit inputs;}); @@ -1,7 +1,7 @@ .PHONY: clean CXX := g++ CXXFLAGS := -std=c++17 `pkg-config --cflags --libs libnotify`# -g -fsanitize=address -fno-omit-frame-pointer -LINKFLAGS := -lX11 -lXrandr -lcommands +LINKFLAGS := -lX11 -lXrandr OBJS_DIR := ./build OUT_DIR := ./out SOURCE_DIR := ./src @@ -32,6 +32,7 @@ remove: r #Files to be compiled $(OBJS_DIR)/main.o: $(SOURCE_FILES) $(SOURCE_HEADERS) $(OBJS_DIR)/ewmh.o: $(SOURCE_DIR)/ewmh.cpp $(SOURCE_DIR)/ewmh.h +$(OBJS_DIR)/command.o: $(SOURCE_DIR)/commands.cpp $(SOURCE_DIR)/commands.h $(SOURCE_DIR)/util.h $(SOURCE_DIR)/error.h $(OBJS_DIR)/util.o: $(SOURCE_DIR)/util.cpp $(SOURCE_DIR)/util.h $(OBJS_DIR)/config.o: $(SOURCE_DIR)/config.cpp $(SOURCE_DIR)/config.h $(OBJS_DIR)/keybinds.o: $(SOURCE_DIR)/keybinds.cpp $(SOURCE_DIR)/keybinds.h @@ -3,7 +3,7 @@ #include <sys/socket.h> #include <sys/un.h> -#include <commands.h> +#include "commands.h" #include "config.h" #include "util.h" diff --git a/src/commands.cpp b/src/commands.cpp new file mode 100644 index 0000000..caa82eb --- /dev/null +++ b/src/commands.cpp @@ -0,0 +1,372 @@ +#include "commands.h" +#include "error.h" +#include "util.h" + +#include <cctype> +#include <filesystem> +#include <iostream> +#include <algorithm> +#include <stdexcept> +#include <string> +#include <vector> +#include <cstring> +#include <fstream> + +using std::cout, std::endl, std::string, std::vector; + +const void CommandsModule::echo(const CommandArg* argv) +{ + cout << argv[0].str << endl; +} + +const void CommandsModule::loadFile(const CommandArg* argv) +{ + std::vector<Err> errs; + + string path = cwd + "/" + std::string(argv[0].str); + + std::ifstream file(path); + if(!file.good()) + throw Err(CMD_ERR_NON_FATAL, "File '" + std::string(argv[0].str) + "' doesn't exist"); + + string prevCWD = cwd; + cwd = std::filesystem::path(path).parent_path(); + + cout << "Loading file '" << argv[0].str << "'" << endl; + + int line = 0; + for(string cmd; std::getline(file, cmd);) + { + line++; + if(cmd.size() == 0) + continue; + if(cmd.at(0) == '#') + continue; + try + { + this->runCommand(cmd); + } + catch (Err e) + { + throw Err(e.code, "Error in file '" + std::string(argv[0].str) + "' (line " + std::to_string(line) + "): " + std::to_string(e.code) + "\n\tMessage: " + e.message); + } + } + + cwd = prevCWD; +} + +CommandsModule::CommandsModule() +{ + addCommand("echo", &CommandsModule::echo, 1, {STR_REST}, this); + addCommand("loadFile", &CommandsModule::loadFile, 1, {STR_REST}, this); + cwd = std::filesystem::current_path(); +} +CommandsModule::~CommandsModule() +{ + for(Command c : commandList) + { + if(c.argc > 0) + delete[] c.argTypes; + } +} + +void CommandsModule::addCommand(Command c) +{ + if(lookupCommand(c.name) != nullptr) + { + cout << "Duplicate command: " << c.name << endl; + } + commandList.push_back(c); +} +void CommandsModule::addCommand(std::string name, const void (*func)(const CommandArg *), const int argc, CommandArgType *argTypes) +{ + Command c = {name, nullptr, func, argc, argTypes, nullptr}; + addCommand(c); +} +void CommandsModule::addCommand(std::string name, const void(*func)(const CommandArg*), const int argc, std::vector<CommandArgType> argTypes) +{ + CommandArgType* argTypesArr = new CommandArgType[argc]; + for(int i = 0; i < argc; i++) + { + argTypesArr[i] = argTypes[i]; + } + addCommand(name, func, argc, argTypesArr); +} + +struct NameMatches +{ + NameMatches(string s): s_{s} {} + bool operator()(Command c) { return (c.name == s_); } + string s_; +}; + +Command* CommandsModule::lookupCommand(string name) +{ + auto elem = std::find_if(commandList.begin(), commandList.end(), NameMatches(name)); + if (elem != commandList.end()) + { + int i = elem - commandList.begin(); + return &(commandList[i]); + } + else + { + return nullptr; + } +} + +vector<string> CommandsModule::splitCommand(string command) +{ + vector<string> v; + string arg = ""; + bool inQuotes = false; + bool escapeNext = true; + char quoteType; + for(int i = 0; i < command.size(); i++) + { + if(escapeNext) + { + arg += command[i]; + escapeNext = false; + } + else if(command[i] == '\\') + { + escapeNext = true; + } + else if(inQuotes) + { + if(command[i] == quoteType) + { + if(arg != "") + { + v.push_back(arg); + arg = ""; + } + inQuotes = false; + } + else + { + arg += command[i]; + } + } + else + { + if(command[i] == ' ') + { + if(arg != "") + { + v.push_back(arg); + arg = ""; + } + } + else if(command[i] == '"' || command[i] == '\'') + { + inQuotes = true; + quoteType = command[i]; + } + else + { + arg += command[i]; + } + } + } + if(arg != "") + v.push_back(arg); + return v; +} + +CommandArg* CommandsModule::getCommandArgs(vector<string>& split, const CommandArgType* argTypes, const int argc) +{ + CommandArg* args = new CommandArg[argc]; + for(int i = 1; i < argc + 1; i++) + { + switch(argTypes[i-1]) + { + case STR: args[i-1].str = (char*)split[i].c_str(); break; + case NUM: + { + try + { + args[i-1].num = std::stoi(split[i]); + break; + } + catch(std::invalid_argument e) + { + delete[] args; + throw Err(CMD_ERR_WRONG_ARGS, split[i] + " is not a number!"); + } + } + case MOVDIR: + { + if(lowercase(split[i]) == "up") + args[i-1].dir = UP; + else if(lowercase(split[i]) == "down") + args[i-1].dir = DOWN; + else if(lowercase(split[i]) == "left") + args[i-1].dir = LEFT; + else if(lowercase(split[i]) == "right") + args[i-1].dir = RIGHT; + else + { + delete[] args; + throw Err(CMD_ERR_WRONG_ARGS, split[i] + " is not a direction!"); + } + break; + } + case STR_REST: + { + string rest = ""; + for(int j = i; j < split.size(); j++) + { + rest += split[j]; + if(j != split.size() - 1) + rest += " "; + } + args[i-1].str = new char[rest.size()]; + strncpy(args[i-1].str, rest.c_str(), rest.size()); + return args; + } + case NUM_ARR_REST: + { + int* rest = new int[split.size() - i]; + for(int j = 0; j < split.size() - i; j++) + { + try + { + rest[j] = std::stoi(split[j + i]); + } + catch(std::invalid_argument e) + { + delete[] rest; + delete[] args; + throw Err(CMD_ERR_WRONG_ARGS, split[i] + " is not a number!"); + } + } + args[i-1].numArr = {rest, (int) split.size() - i}; + return args; + } + default: cout << "UH OH SOMETHING IS VERY WRONG" << endl; + } + } + return args; +} + +void CommandsModule::runCommand(string command) +{ + vector<string> split = splitCommand(command); + vector<string>::const_iterator start = split.begin(); + int count = 0; + for(string s : split) + { + if(s == ";") + { + vector<string>::const_iterator end = start + count; + vector<string> partialCmd(start, end); + runCommand(partialCmd); + count = 0; + start = end + 1; + } + else + { + count++; + } + } + if(start != split.end()) + { + vector<string> partialCmd(start, (vector<string>::const_iterator)split.end()); + runCommand(partialCmd); + } +} +void CommandsModule::runCommand(vector<string> split) +{ + Command* cmd = lookupCommand(split[0]); + if(cmd == nullptr) + throw Err(CMD_ERR_NOT_FOUND, split[0] + " is not a valid command name"); + if(cmd->argc > split.size() - 1) + throw Err(CMD_ERR_WRONG_ARGS, "wrong number of arguments"); + CommandArg* args; + try + { + args = getCommandArgs(split, cmd->argTypes, cmd->argc); + } + catch(Err e) + { + throw e; + } + try + { + if(cmd->module == nullptr) + cmd->staticFunc(args); + else + cmd->func(*cmd->module, args); + } + catch (Err e) + { + for(int i = 0; i < cmd->argc; i++) + { + if(cmd->argTypes[i] == STR_REST) + delete[] args[i].str; + } + delete[] args; + throw e; + } + for(int i = 0; i < cmd->argc; i++) + { + if(cmd->argTypes[i] == STR_REST) + delete[] args[i].str; + } + delete[] args; +} + +vector<Err> CommandsModule::checkCommand(string command) +{ + vector<Err> errs; + vector<string> split = splitCommand(command); + vector<string>::const_iterator start = split.begin(); + int count = 0; + for(string s : split) + { + if(s == ";") + { + vector<string>::const_iterator end = start + count; + vector<string> partialCmd(start, end); + errs.push_back(checkCommand(partialCmd)); + count = 0; + start = end + 1; + } + else + { + count++; + } + } + if(start != split.end()) + { + vector<string> partialCmd(start, (vector<string>::const_iterator)split.end()); + errs.push_back(checkCommand(partialCmd)); + } + return errs; +} + +Err CommandsModule::checkCommand(vector<string> split) +{ + Command* cmd = lookupCommand(split[0]); + if(cmd == nullptr) + return Err(CMD_ERR_NOT_FOUND, split[0] + " is not a valid command name"); + if(cmd->argc > split.size()) + return Err(CMD_ERR_WRONG_ARGS, "wrong number of arguments"); + CommandArg* args; + try + { + args = getCommandArgs(split, cmd->argTypes, cmd->argc); + } + catch(Err e) + { + return e; + } + for(int i = 0; i < cmd->argc; i++) + { + if(cmd->argTypes[i] == STR_REST || cmd->argTypes[i] == NUM_ARR_REST) + delete[] args[i].str; + } + delete[] args; + return Err(NOERR, ""); +} diff --git a/src/commands.h b/src/commands.h new file mode 100644 index 0000000..4825f1c --- /dev/null +++ b/src/commands.h @@ -0,0 +1,91 @@ +#pragma once + +#include "error.h" + +#include <vector> +#include <string> +#include <any> +#include <functional> + +enum MoveDir + { + UP, + RIGHT, + DOWN, + LEFT + }; +enum CommandArgType + { + STR, + NUM, + MOVDIR, + STR_REST, + NUM_ARR_REST + }; + +struct NumArr +{ + int* arr; + int size; +}; +typedef union +{ + char* str; + int num; + NumArr numArr; + MoveDir dir; +} CommandArg; + +struct Command +{ + const std::string name; + const std::function<void(std::any&, const CommandArg* argv)> func; + const std::function<void(const CommandArg* argv)> staticFunc; + const int argc; + CommandArgType* argTypes; + std::any* module; +}; +class CommandsModule +{ +private: + std::vector<Command> commandList; + std::vector<std::string> splitCommand(std::string command); + CommandArg* getCommandArgs(std::vector<std::string>& args, const CommandArgType* argTypes, const int argc); + const void echo(const CommandArg* argv); + const void loadFile(const CommandArg* argv); + std::string cwd; +public: + CommandsModule(); + ~CommandsModule(); + template <class T> + void addCommand(std::string name, const void(T::*func)(const CommandArg*), const int argc, CommandArgType* argTypes, T* module); + void addCommand(std::string name, const void(*func)(const CommandArg*), const int argc, CommandArgType* argTypes); + template <class T> + void addCommand(std::string name, const void(T::*func)(const CommandArg*), const int argc, std::vector<CommandArgType> argTypes, T* module); + void addCommand(std::string name, const void(*func)(const CommandArg*), const int argc, std::vector<CommandArgType> argTypes); + void addCommand(Command c); + Command* lookupCommand(std::string name); + void runCommand(std::string command); + void runCommand(std::vector<std::string> split); + std::vector<Err> checkCommand(std::string command); + Err checkCommand(std::vector<std::string> split); +}; + +// YES I KNOW THIS IS BAD +// but it needs to be done this way +template <class T> +void CommandsModule::addCommand(std::string name, const void(T::*func)(const CommandArg*), const int argc, CommandArgType* argTypes, T* module) +{ + Command c = {name, (const void*(std::any::*)(const CommandArg* argv)) func, nullptr, argc, argTypes, (std::any*)module}; + addCommand(c); +} +template <class T> +void CommandsModule::addCommand(std::string name, const void(T::*func)(const CommandArg*), const int argc, std::vector<CommandArgType> argTypes, T* module) +{ + CommandArgType* argTypesArr = new CommandArgType[argc]; + for(int i = 0; i < argc; i++) + { + argTypesArr[i] = argTypes[i]; + } + addCommand(name, func, argc, argTypesArr, module); +} diff --git a/src/config.cpp b/src/config.cpp index df195aa..925e6ea 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -1,7 +1,6 @@ #include "config.h" -#include <commands.h> -//TODO: FIX THIS -#include <error.h> +#include "commands.h" +#include "error.h" #include <X11/Xlib.h> diff --git a/src/config.h b/src/config.h index b04753f..55e4fd3 100644 --- a/src/config.h +++ b/src/config.h @@ -2,7 +2,7 @@ #include <X11/X.h> #include <X11/keysym.h> -#include <commands.h> +#include "commands.h" #include <string> #include <vector> diff --git a/src/keybinds.cpp b/src/keybinds.cpp index 127a534..235f8c1 100644 --- a/src/keybinds.cpp +++ b/src/keybinds.cpp @@ -7,9 +7,8 @@ #include <vector> #include <regex> -#include <commands.h> -//TODO: FIX THIS -#include <error.h> +#include "commands.h" +#include "error.h" #include "keybinds.h" #include "util.h" diff --git a/src/keybinds.h b/src/keybinds.h index 5fd4fba..a742240 100644 --- a/src/keybinds.h +++ b/src/keybinds.h @@ -8,7 +8,7 @@ #include <X11/keysym.h> #include <vector> -#include <commands.h> +#include "commands.h" #include "config.h" #include "util.h" |
