From f8aac06893029cbfee4e1acffd2a9242afce8b49 Mon Sep 17 00:00:00 2001 From: Javier Feliz Date: Sun, 7 Sep 2025 19:39:19 -0400 Subject: [PATCH] Added installation to nix flake as well as home manager module --- README.md | 42 +++++++++++++++ flake.nix | 75 +++++++++++++++++++++++++-- modules/home-manager/waycast.nix | 89 ++++++++++++++++++++++++++++++++ waycast-config/src/main.rs | 42 --------------- waycast-core/src/cache/mod.rs | 6 +-- 5 files changed, 205 insertions(+), 49 deletions(-) create mode 100644 modules/home-manager/waycast.nix delete mode 100644 waycast-config/src/main.rs diff --git a/README.md b/README.md index b5640d1..604eb9c 100644 --- a/README.md +++ b/README.md @@ -61,6 +61,48 @@ Waycast aims to be: - **Extensible** - Plugin system for custom functionality - **Native** - Proper Wayland integration, not an Electron app +## Installation + +### Nix Flakes + +Add to your `flake.nix` inputs: +```nix +waycast.url = "git+https://gitgud.foo/thegrind/waycast"; +``` + +**Install as package:** +```nix +environment.systemPackages = [ inputs.waycast.packages.${system}.default ]; +# or for home-manager: +home.packages = [ inputs.waycast.packages.${system}.default ]; +``` + +**With Home Manager module (recommended):** +```nix +imports = [ inputs.waycast.homeManagerModules.default ]; + +programs.waycast = { + enable = true; + config = { + plugins.projects = { + search_paths = ["/absolute/path/to/search"]; + skip_dirs = [ "node_modules" "target" ".git" ]; + open_command = "code -n {path}"; + }; + plugins.file_search = { + search_paths = ["/absolute/path/to/search"]; + ignore_dirs = ["scripts", "temp"]; # Just directory names here + }; + }; + css = '' + window { + background: rgba(0, 0, 0, 0.8); + border-radius: 12px; + } + ''; +}; +``` + ## Contributing TBA diff --git a/flake.nix b/flake.nix index e6d0c58..26a2741 100644 --- a/flake.nix +++ b/flake.nix @@ -6,12 +6,66 @@ flake-utils.url = "github:numtide/flake-utils"; }; - outputs = { self, nixpkgs, flake-utils }: - flake-utils.lib.eachDefaultSystem (system: + outputs = + { + self, + nixpkgs, + flake-utils, + }: + flake-utils.lib.eachDefaultSystem ( + system: let pkgs = nixpkgs.legacyPackages.${system}; in { + packages.default = pkgs.rustPlatform.buildRustPackage { + pname = "waycast"; + version = "0.0.1"; + src = self; + + cargoLock.lockFile = ./Cargo.lock; + + doCheck = true; + cargoTestFlags = [ + "--bins" + "--tests" + ]; + + nativeBuildInputs = with pkgs; [ + pkg-config + makeWrapper + ]; + + buildInputs = with pkgs; [ + # GTK4 stack + gtk4 + glib + gdk-pixbuf + pango + cairo + harfbuzz + librsvg + + # Wayland + layer shell (GTK4 variant) + wayland + gtk4-layer-shell + ]; + + # Wrap binary to ensure icon themes are available + postInstall = '' + wrapProgram $out/bin/waycast \ + --prefix XDG_DATA_DIRS : "${pkgs.hicolor-icon-theme}/share:${pkgs.adwaita-icon-theme}/share" + ''; + + meta = with pkgs.lib; { + description = "GTK4-based application launcher for Wayland compositors"; + homepage = "https://gitgud.foo/thegrind/waycast"; + license = licenses.mit; + maintainers = [ "Javier Feliz" ]; + platforms = platforms.linux; + }; + }; + devShells.default = pkgs.mkShell { buildInputs = with pkgs; [ # Build tools @@ -35,5 +89,18 @@ adwaita-icon-theme ]; }; - }); -} \ No newline at end of file + + homeManagerModules.waycast = + { + config, + lib, + pkgs, + ... + }: + { + imports = [ ./modules/home-manager/waycast.nix ]; + programs.waycast.package = self.packages.${system}.default; + }; + } + ); +} diff --git a/modules/home-manager/waycast.nix b/modules/home-manager/waycast.nix new file mode 100644 index 0000000..56eb31b --- /dev/null +++ b/modules/home-manager/waycast.nix @@ -0,0 +1,89 @@ +{ + config, + lib, + pkgs, + ... +}: + +with lib; + +let + cfg = config.programs.waycast; + + # Convert a Nix attribute set to TOML format + toToml = value: pkgs.formats.toml { }.generate "waycast.toml" value; + +in +{ + options.programs.waycast = { + enable = mkEnableOption "waycast application launcher"; + + package = mkOption { + type = types.package; + default = pkgs.waycast or (throw "waycast package not found in pkgs"); + description = "The waycast package to use"; + }; + + settings = mkOption { + type = types.attrs; + default = { }; + example = literalExpression '' + { + plugins = { + projects = { + search_paths = [ "~/code" "~/projects" ]; + skip_dirs = [ "node_modules" "target" ".git" ]; + open_command = "code -n {path}"; + }; + file_search = { + search_paths = [ "~/Documents" "~/Downloads" ]; + ignore_dirs = [ "cache" "vendor" ]; + }; + }; + } + ''; + description = '' + Waycast configuration. This will be converted to TOML format + and placed in ~/.config/waycast/waycast.toml + ''; + }; + + css = mkOption { + type = types.nullOr types.lines; + default = null; + example = '' + window { + background: rgba(0, 0, 0, 0.8); + border-radius: 12px; + } + + .search-entry { + font-size: 16px; + padding: 12px; + } + ''; + description = '' + Custom GTK CSS styling for waycast. + This will be placed in ~/.config/waycast/waycast.css + ''; + }; + }; + + config = mkIf cfg.enable { + home.packages = [ cfg.package ]; + + xdg.configFile = mkMerge [ + (mkIf (cfg.config != { }) { + "waycast/waycast.toml".source = toToml cfg.config; + }) + + (mkIf (cfg.css != null) { + "waycast/waycast.css".text = cfg.css; + }) + ]; + + # Ensure cache and data dirs exist to avoid runtime errors in the future + home.file."${config.xdg.cacheHome}/waycast".isDir = true; + home.file."${config.xdg.dataHome}/waycast".isDir = true; + }; +} diff --git a/waycast-config/src/main.rs b/waycast-config/src/main.rs deleted file mode 100644 index ee84a6b..0000000 --- a/waycast-config/src/main.rs +++ /dev/null @@ -1,42 +0,0 @@ -use std::collections::HashMap; - -use config::Config; -use directories::ProjectDirs; -pub fn main() { - // if let Some(dirs) = ProjectDirs::from("dev.thegrind", "The Grind", "waycast") { - // let config_dir = dirs.config_dir(); - // let cache_dir = dirs.cache_dir(); - // let data_dir = dirs.data_dir(); - - // println!("Config: {}", config_dir.display()); - // println!("Cache: {}", cache_dir.display()); - // println!("Data: {}", data_dir.display()); - // } - - // let settings = Config::builder() - // .add_source(config::File::with_name("waycast.toml")) - // .add_source(config::Environment::with_prefix("WAYCAST")) - // .build() - // .unwrap(); - - println!( - "{:?}", - waycast_config::config_file() - .get::("plugins.projects.open_command") - .expect("Could not deserialize") - ); - - // // Start with defaults - // let mut config = WaycastConfig::default(); - - // config.plugins.file_search.ignore_dirs = - // vec!["vendor".into(), "pycache".into(), "node_modules".into()]; - - // // Serialize to TOML - // let toml_str = toml::to_string_pretty(&config).expect("Failed"); - // println!("Serialized TOML:\n{}", toml_str); - - // // Deserialize back - // let parsed: WaycastConfig = toml::from_str(&toml_str).expect("Fuck"); - // println!("Deserialized struct:\n{:#?}", parsed); -} diff --git a/waycast-core/src/cache/mod.rs b/waycast-core/src/cache/mod.rs index d94e6be..86acef2 100644 --- a/waycast-core/src/cache/mod.rs +++ b/waycast-core/src/cache/mod.rs @@ -50,7 +50,7 @@ pub fn get() -> &'static Cache { // Get an existing cache at the given path or // create it if it doesn't exist -fn new>(db_path: P) -> Result { +pub fn new>(db_path: P) -> Result { let db = Database::create(db_path)?; // Initialize the table if it doesn't exist @@ -224,7 +224,7 @@ mod tests { #[test] fn test_cache_remember() { let temp_file = NamedTempFile::new().unwrap(); - let cache = Cache::new(temp_file.path()).unwrap(); + let cache = new(temp_file.path()).unwrap(); let result = cache .remember("test_key", || "computed_value".to_string()) @@ -241,7 +241,7 @@ mod tests { #[test] fn test_cache_ttl() { let temp_file = NamedTempFile::new().unwrap(); - let cache = Cache::new(temp_file.path()).unwrap(); + let cache = new(temp_file.path()).unwrap(); // Cache with very short TTL let result = cache