diff options
| author | BossCode45 <human.cyborg42@gmail.com> | 2025-01-04 15:14:05 +1300 |
|---|---|---|
| committer | BossCode45 <human.cyborg42@gmail.com> | 2025-01-04 15:14:05 +1300 |
| commit | aa1500fea32db04c9e4fe72786ebd7e3479b6a8a (patch) | |
| tree | df2bcb0182704dac9e1813f269fb46bb67e65c61 | |
| parent | d1d4a63d4473cd4910b678cf5b385f622186fbd3 (diff) | |
| download | YATwm-aa1500fea32db04c9e4fe72786ebd7e3479b6a8a.tar.gz YATwm-aa1500fea32db04c9e4fe72786ebd7e3479b6a8a.zip | |
feat: Commands restructure + home manager module now makes config
Commands module is now a separate libraray that the flake includes.
The home manager module will now auto generate the config and has
options for different things such as keybinds, gaps, workspaces, etc.
| -rw-r--r-- | YATwm.nix | 14 | ||||
| -rw-r--r-- | flake.nix | 23 | ||||
| -rw-r--r-- | makefile | 7 | ||||
| -rw-r--r-- | nix/hm-module.nix | 194 | ||||
| -rw-r--r-- | readme.org | 7 | ||||
| -rw-r--r-- | src/IPC.h | 2 | ||||
| -rw-r--r-- | src/commands.cpp | 335 | ||||
| -rw-r--r-- | src/commands.h | 89 | ||||
| -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 | ||||
| -rw-r--r-- | src/main.cpp | 3 |
13 files changed, 236 insertions, 452 deletions
@@ -3,7 +3,9 @@ fetchgit, xorg, libnotify, - pkg-config + pkg-config, + inputs, + ... }: @@ -14,7 +16,7 @@ stdenv.mkDerivation { src = fetchgit { url = "https://git.tehbox.org/cgit/boss/YATwm.git/"; rev = "v0.0.1"; - hash = "sha256-c0GIwZFZoaYsq6cK1cPzjxwPZzNg7tyDh44vLFsdMAI="; + hash = "sha256-A4Yra/903rOeEbXfFia/A2HRPrFyE1b05mzHWlDImCY="; }; installPhase = '' @@ -26,5 +28,11 @@ install -D -m 644 config $out/etc/YATwm/config runHook postInstall ''; - buildInputs = [ xorg.libX11 xorg.libXrandr libnotify pkg-config ]; + buildInputs = [ + xorg.libX11 + xorg.libXrandr + libnotify + pkg-config + inputs.libCommands.packages.x86_64-linux.default + ]; } @@ -2,23 +2,28 @@ 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; in { devShells.x86_64-linux.default = pkgs.mkShell { - buildInputs = with pkgs; [ - gcc - gnumake - xorg.libX11 - xorg.libXrandr - libnotify - pkg-config - clang-tools + nativeBuildInputs = [ + pkgs.gcc + pkgs.gnumake + pkgs.xorg.libX11 + pkgs.xorg.libXrandr + pkgs.libnotify + pkgs.pkg-config + pkgs.clang-tools + inputs.libCommands.packages.x86_64-linux.default ]; }; - packages.x86_64-linux.YATwm = (pkgs.callPackage ./YATwm.nix {}); + packages.x86_64-linux.YATwm = (pkgs.callPackage ./YATwm.nix {inherit inputs;}); packages.x86_64-linux.default = self.packages.x86_64-linux.YATwm; nixosModules.YATwm = import ./nix/module.nix; nixosModules.default = self.nixosModules.YATwm; @@ -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 +LINKFLAGS := -lX11 -lXrandr -lcommands OBJS_DIR := ./build OUT_DIR := ./out SOURCE_DIR := ./src @@ -33,9 +33,8 @@ remove: r $(OBJS_DIR)/main.o: $(SOURCE_FILES) $(SOURCE_HEADERS) $(OBJS_DIR)/ewmh.o: $(SOURCE_DIR)/ewmh.cpp $(SOURCE_DIR)/ewmh.h $(OBJS_DIR)/util.o: $(SOURCE_DIR)/util.cpp $(SOURCE_DIR)/util.h -$(OBJS_DIR)/commands.o: $(SOURCE_DIR)/commands.cpp $(SOURCE_DIR)/commands.h -$(OBJS_DIR)/config.o: $(SOURCE_DIR)/config.cpp $(SOURCE_DIR)/config.h $(SOURCE_DIR)/commands.h -$(OBJS_DIR)/keybinds.o: $(SOURCE_DIR)/keybinds.cpp $(SOURCE_DIR)/keybinds.h $(SOURCE_DIR)/commands.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 $(OBJS_DIR)/ipc.o: $(SOURCE_DIR)/ipc.cpp $(SOURCE_DIR)/ipc.h $(SOURCE_DIR)/commands.h $(SOURCE_DIR)/ewmh.h clean: diff --git a/nix/hm-module.nix b/nix/hm-module.nix index 87b47f2..c9f914b 100644 --- a/nix/hm-module.nix +++ b/nix/hm-module.nix @@ -1,7 +1,5 @@ { config, lib, pkgs, ... }: - with lib; - let cfg = config.xsession.windowManager.YATwm; in @@ -10,11 +8,203 @@ in options.xsession.windowManager.YATwm = { enable = mkEnableOption "YATwm"; package = mkPackageOption pkgs null { }; + extraConfig = mkOption { + type = types.lines; + default = ""; + example = '' +# Focus +bind mod+h focChange left +bind mod+j focChange down +bind mod+k focChange up +bind mod+l focChange right +''; + description = '' +Extra config lines to be included in the config file +''; + }; + useEmacsBinds = mkOption { + type = types.bool; + default = false; + description = '' +Whether to use the emacs binding system instead of the i3 binding system (only applies if keybinds are set with the home manager module). +Note: Adds the `bindmode emacs` command to the config, and doesn't reset it before any config in extraConfig +''; + }; + quitKey = mkOption { + type = types.str; + default = "mod+g"; + example = "mod+q"; + description = '' +Special key that cannot be bound to which will cancel any in progress keybind (only applies if keybinds are set with the home manager module). +Note: Shouldn't be a key chord. +''; + }; + swapMods = mkOption { + type = types.bool; + default = false; + description = '' +Swap the mod key (windows key) and alt key (meta key) (only applies if keybinds are set with the home manager module). +''; + }; + keybinds = mkOption { + type = types.attrsOf (types.nullOr types.str); + default = {}; + example = '' +{ + "mod+h" = "focChange left"; + "mod+j" = "focChange down"; + "mod+k" = "focChange up"; + "mod+l" = "focChange right"; +} +''; + description = '' +Key combinations and their respective commands to be bound. +Will add a line for each in the form `bind "<keybind>" <command>` (quotes around keybind included) +''; + }; + startup = mkOption { + type = types.listOf (types.submodule { + options = { + command = mkOption { + type = types.str; + default = ""; + example = "nitrogen --restore"; + description = '' +Command to execute. +''; + }; + once = mkOption { + type = types.bool; + default = true; + description = '' +Only execute the command the first time the config is read. +''; + }; + bash = mkOption { + type = types.bool; + default = true; + description = '' +Use bashSpawn instead of spawn. +''; + }; + }; + }); + default = []; + example = '' +[ + { + command = "nitrogen --restore"; + } + { + command = "nm-applet"; + once = false; + bash = false; + } +] +''; + description = '' +List of commands to be executed at startup. +''; + }; + workspaces = mkOption { + type = types.listOf (types.submodule { + options = { + name = mkOption { + type = types.str; + default = "1"; + description = '' +Name for workspace. +''; + }; + monitorPriorities = mkOption { + type = types.listOf types.int; + default = [1]; + description = '' +List of priorities for which monitor to put the workspace on +''; + }; + }; + }); + default = [ + {name = "1: A";} + {name = "2: B";} + {name = "3: C";} + {name = "4: D";} + {name = "5: E";} + {name = "6: F";} + {name = "7: G";} + {name = "8: H";} + {name = "9: I";} + {name = "10: J";} + ]; + description = '' +List of workspaces to add. +Note: do not chance this while YATwm is running, apart from maybe changing the names, as it can cause issues. +''; + }; + gaps = { + inner = mkOption { + type = types.int; + default = 3; + description = '' +Margins around windows (ends up looking doubled, as all windows have it). +''; + }; + outer = mkOption { + type = types.int; + default = 3; + description = '' +Margin around all windows on an output. +''; + }; + }; }; config = mkIf cfg.enable { home.packages = [ cfg.package ]; xsession.windowManager.command = "${cfg.package}/bin/YATwm"; xsession.enable = true; + xdg.configFile."YATwm/config" = { + text = (strings.concatStringsSep "\n" [ + "# Home manager generated config:\n" + (optionalString (cfg.keybinds != {}) + (strings.concatStrings [ + "# Keybinds:\n" + (optionalString cfg.useEmacsBinds "bindmode emacs\n") + "quitkey ${cfg.quitKey}\n" + (optionalString cfg.swapMods "swapmods\n") + (strings.concatStrings (mapAttrsToList (bind: command: + "bind \"${bind}\" ${command}\n") cfg.keybinds)) + ]) + ) + (optionalString (cfg.workspaces != []) + "# Workspaces:\n" + + (strings.concatStrings (map (workspace: + let + monitorPreferenceString = (strings.concatMapStringsSep " " (x: toString x) workspace.monitorPriorities); + in + "addWorkspace \"${workspace.name}\" ${monitorPreferenceString}\n") cfg.workspaces))) + (optionalString (cfg.startup != []) + "# Startup:\n" + (strings.concatStrings (map (command: + let + spawnCommand = (if command.bash then "bashSpawn" else "spawn") + (optionalString command.once "Once"); + in + "${spawnCommand} ${command.command}\n") cfg.startup))) + "# Gaps:" + "gaps ${toString cfg.gaps.inner}" + "outergaps ${toString cfg.gaps.outer}" + "" + (optionalString (cfg.extraConfig != "") + "# Extra config:\n" + cfg.extraConfig + ) + ]); + onChange = '' + if [ -n "''${DISPLAY+1}" ]; then + if xprop -root | grep YATwm; then + ${cfg.package}/bin/YATwm reload + fi + fi + ''; + }; }; } @@ -7,12 +7,15 @@ This only just works, multiple monitors aren't supported and floating windows ca * Usage instructions ** Installation -*** Pre reqs +*** Nixos +Use the flake. +*** Other distros +**** Pre reqs - ~Xlib~ and ~g++~ and ~libnotify~ to build the program - ~Xephyr~ for the test script - ~rofi~, ~alacritty~, and ~i3lock~ for the default config - The current default config is currently just the configuration that I want to use (this will likely change) -*** Installing and removing +**** Installing and removing - ~make i~ or ~make install~ to install - ~make r~ or ~make remove~ to remove - ~./test~ to test @@ -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 deleted file mode 100644 index 5688da4..0000000 --- a/src/commands.cpp +++ /dev/null @@ -1,335 +0,0 @@ -#include "commands.h" -#include "error.h" -#include "util.h" - -#include <cctype> -#include <iostream> -#include <algorithm> -#include <iterator> -#include <stdexcept> -#include <string> -#include <utility> -#include <vector> -#include <regex> -#include <cstring> - -using std::cout, std::endl, std::string, std::vector; - -const void CommandsModule::echo(const CommandArg* argv) -{ - cout << argv[0].str << endl; -} - -CommandsModule::CommandsModule() -{ - addCommand("echo", &CommandsModule::echo, 1, {STR_REST}, this); -} -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 deleted file mode 100644 index af4a4a0..0000000 --- a/src/commands.h +++ /dev/null @@ -1,89 +0,0 @@ -#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); -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 925e6ea..df195aa 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -1,6 +1,7 @@ #include "config.h" -#include "commands.h" -#include "error.h" +#include <commands.h> +//TODO: FIX THIS +#include <error.h> #include <X11/Xlib.h> diff --git a/src/config.h b/src/config.h index 452db9c..b04753f 100644 --- a/src/config.h +++ b/src/config.h @@ -1,8 +1,8 @@ #pragma once -#include "commands.h" #include <X11/X.h> #include <X11/keysym.h> +#include <commands.h> #include <string> #include <vector> diff --git a/src/keybinds.cpp b/src/keybinds.cpp index 235f8c1..127a534 100644 --- a/src/keybinds.cpp +++ b/src/keybinds.cpp @@ -7,8 +7,9 @@ #include <vector> #include <regex> -#include "commands.h" -#include "error.h" +#include <commands.h> +//TODO: FIX THIS +#include <error.h> #include "keybinds.h" #include "util.h" diff --git a/src/keybinds.h b/src/keybinds.h index a742240..5fd4fba 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" diff --git a/src/main.cpp b/src/main.cpp index da1ae9b..3e01b4d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -36,7 +36,8 @@ #include "config.h" #include "util.h" #include "ewmh.h" -#include "error.h" +//TODO: FIX THIS +#include <error.h> using std::cout; using std::string; |
