From 0b49d9615c3c3dfd41d2e66a2486dc7847f7660b Mon Sep 17 00:00:00 2001 From: workflow <4farlion@gmail.com> Date: Fri, 30 Jan 2026 19:01:50 +0000 Subject: [PATCH 01/26] docs: add dendritic pattern architecture documentation --- AGENTS.md | 15 +++- README.md | 11 ++- doc/DENDRITIC.md | 219 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 242 insertions(+), 3 deletions(-) create mode 100644 doc/DENDRITIC.md diff --git a/AGENTS.md b/AGENTS.md index 031f08f2..5af0c3e3 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,10 +1,23 @@ +# Architecture + +This configuration follows the [dendritic pattern](doc/DENDRITIC.md). Key points: + +- All modules live in `parts/` +- Each feature file configures both NixOS and home-manager aspects together +- Host-specific values are in top-level config options (`config.dendrix.*`), not `specialArgs` +- Features own their persistence paths + # Bash commands + - `nh os switch`: build and switch to new NixOS generation (including home-manager) - `nh os build`: build only # Code style + ## Shell Scripts in Nix -Use `pkgs.writeShellApplication`, provide all necessary `runtimeInputs` and move the script into its own file inside the /scripts/ dir. + +Use `pkgs.writeShellApplication`, provide all necessary `runtimeInputs` and move the script into its own file inside the `/scripts/` dir. # Workflow + - Instead of searching the web for NixOS or home-manager options, use `man configuration.nix` for NixOS and `man home-configuration.nix` for the home-manager manual locally. diff --git a/README.md b/README.md index 12a6105a..592f6488 100644 --- a/README.md +++ b/README.md @@ -63,11 +63,18 @@ But here's a rough guide: ![nix-valley-of-doom](assets/nix-valley-of-despair.png) -## Notes +## Architecture + +This configuration follows the [dendritic pattern](doc/DENDRITIC.md) using flake-parts. + +## Upgrades +- [Upgrade Checklist](doc/upgrades/Checklist.md) - [NixOS 24.11 Upgrade Adventures](doc/upgrades/2411/NixOS-24.11.md) - [NixOS 24.05 Upgrade Adventures](doc/upgrades/2405/NixOS-24.05.md) -- [NixOS Upgrade Checklist](doc/upgrades/Checklist.md) + +## Notes + - [Moving an Existing Installation to a new Disk](doc/MOVING.md) ## Acknowledgements diff --git a/doc/DENDRITIC.md b/doc/DENDRITIC.md new file mode 100644 index 00000000..89145060 --- /dev/null +++ b/doc/DENDRITIC.md @@ -0,0 +1,219 @@ +# Dendritic Pattern Architecture + +This document describes the architecture of this NixOS configuration, which follows the [dendritic pattern](https://github.com/mightyiam/dendritic). + +## Core Principles + +1. **Aspect-oriented**: Each file configures a single feature across all relevant configuration classes (NixOS, home-manager) +2. **Top-level modules**: All files are flake-parts modules imported into a unified evaluation +3. **Co-location**: Related NixOS and home-manager config live together in one file +4. **Automatic imports**: Files in `parts/` are auto-imported; adding a feature = creating a file +5. **No specialArgs pass-thru**: Host-specific values live in top-level config options, accessible to all modules + +## Directory Structure + +``` +nixos-config/ +├── flake.nix # Minimal: inputs + flake-parts import +├── flake.lock +│ +├── parts/ # All flake-parts modules +│ ├── _bootstrap/ # Core infrastructure +│ │ ├── default.nix # Auto-imports all parts/**/*.nix +│ │ ├── hosts.nix # Host definitions and feature composition +│ │ └── lib.nix # Shared functions and constants +│ │ +│ ├── features/ # Feature modules +│ │ ├── core/ # Essential system features +│ │ │ ├── boot.nix +│ │ │ ├── networking.nix +│ │ │ ├── users.nix +│ │ │ ├── nix-settings.nix +│ │ │ └── locale.nix +│ │ │ +│ │ ├── hardware/ # Hardware-specific features +│ │ │ ├── nvidia.nix # Driver + env vars + home config +│ │ │ ├── amd.nix +│ │ │ ├── audio.nix # PipeWire + home audio tools +│ │ │ └── bluetooth.nix +│ │ │ +│ │ ├── desktop/ # Desktop environment +│ │ │ ├── niri.nix # Compositor + keybindings + scripts +│ │ │ ├── waybar.nix +│ │ │ ├── dunst.nix +│ │ │ ├── fuzzel.nix +│ │ │ └── theming.nix # Stylix + specialisations +│ │ │ +│ │ ├── dev/ # Development tools +│ │ │ ├── neovim/ # Complex features can be directories +│ │ │ │ ├── default.nix +│ │ │ │ ├── lsp.nix +│ │ │ │ └── plugins/ +│ │ │ ├── git.nix +│ │ │ ├── jujutsu.nix +│ │ │ └── claude-code.nix +│ │ │ +│ │ ├── apps/ # Applications +│ │ │ ├── firefox.nix +│ │ │ ├── alacritty.nix +│ │ │ ├── fish.nix +│ │ │ └── ... +│ │ │ +│ │ ├── services/ # System services +│ │ │ ├── docker.nix +│ │ │ ├── syncthing.nix +│ │ │ └── restic.nix +│ │ │ +│ │ └── security/ # Security features +│ │ ├── sops.nix +│ │ ├── gpg.nix +│ │ └── keyring.nix +│ │ +│ └── hosts/ # Host-specific config +│ ├── flexbox/ +│ │ ├── default.nix # Host options + overrides +│ │ └── hardware-scan.nix +│ └── numenor/ +│ ├── default.nix +│ └── hardware-scan.nix +│ +└── doc/ + └── DENDRITIC.md +``` + +## Anatomy of a Feature File + +A feature file configures all aspects of a single feature: + +```nix +# parts/features/apps/alacritty.nix +{ config, lib, ... }: +{ + flake.modules.nixos.alacritty = { pkgs, ... }: { + fonts.packages = [ pkgs.fira-code ]; + }; + + flake.modules.homeManager.alacritty = { pkgs, ... }: { + programs.alacritty = { + enable = true; + settings = { + font.normal.family = "FiraCode Nerd Font"; + }; + }; + + # Feature owns its persistence paths + home.persistence."/persist" = lib.mkIf config.dendrix.isImpermanent { + directories = [ ".config/alacritty" ]; + }; + }; +} +``` + +## Host-Specific Values via Top-Level Config + +Instead of threading `specialArgs` through module evaluations, host-specific values are defined as options in the top-level configuration. Every module can read from this shared config: + +```nix +# parts/_bootstrap/options.nix +{ lib, ... }: +{ + options.dendrix = { + hostname = lib.mkOption { type = lib.types.str; }; + isLaptop = lib.mkOption { type = lib.types.bool; default = false; }; + isImpermanent = lib.mkOption { type = lib.types.bool; default = false; }; + hasNvidia = lib.mkOption { type = lib.types.bool; default = false; }; + hasAmd = lib.mkOption { type = lib.types.bool; default = false; }; + }; +} + +# parts/hosts/flexbox/default.nix +{ ... }: +{ + config.dendrix = { + hostname = "flexbox"; + isLaptop = true; + hasNvidia = true; + }; +} + +# Any feature can then access these values: +# parts/features/hardware/nvidia.nix +{ config, lib, ... }: +{ + flake.modules.nixos.nvidia = lib.mkIf config.dendrix.hasNvidia { + # NVIDIA configuration + }; +} +``` + +## Host Definition + +Hosts compose features in `parts/_bootstrap/hosts.nix`: + +```nix +{ inputs, ... }: +{ + flake.nixosConfigurations = { + flexbox = inputs.nixpkgs.lib.nixosSystem { + system = "x86_64-linux"; + modules = [ + inputs.self.modules.nixos.boot + inputs.self.modules.nixos.networking + inputs.self.modules.nixos.users + inputs.self.modules.nixos.nvidia + inputs.self.modules.nixos.niri + inputs.self.modules.nixos.theming + inputs.self.modules.nixos.alacritty + + ../hosts/flexbox/hardware-scan.nix + inputs.self.modules.nixos.host-flexbox + ]; + }; + + numenor = inputs.nixpkgs.lib.nixosSystem { + system = "x86_64-linux"; + modules = [ + inputs.self.modules.nixos.amd + inputs.self.modules.nixos.impermanence + # ... + ]; + }; + }; +} +``` + +## Key Concepts + +### flake-parts + +[flake-parts](https://flake.parts) provides the module system for flake outputs. The `flake.modules..` options use `deferredModule` types, allowing modules to be defined once and composed into multiple host configurations. + +### Feature Ownership + +Each feature owns all its concerns: +- System-level configuration (`flake.modules.nixos.*`) +- User-level configuration (`flake.modules.homeManager.*`) +- Persistence paths (declared within the home-manager module) +- Scripts (co-located in the feature file or a sibling `scripts/` directory) + +### Specialisations + +Theme switching is handled in `parts/features/desktop/theming.nix`: + +```nix +flake.modules.nixos.theming = { ... }: { + stylix.base16Scheme = "gruvbox-dark-hard.yaml"; + + specialisation.light.configuration = { + stylix.base16Scheme = "catppuccin-latte.yaml"; + stylix.polarity = "light"; + }; +}; +``` + +## References + +- [Dendritic pattern introduction (video)](https://youtu.be/-TRbzkw6Hjs) +- [mightyiam/dendritic](https://github.com/mightyiam/dendritic) +- [flake.parts documentation](https://flake.parts) +- [Doc-Steve/dendritic-design-with-flake-parts](https://github.com/Doc-Steve/dendritic-design-with-flake-parts) From 556519171e8a10ffc656b5093ed359b355154806 Mon Sep 17 00:00:00 2001 From: workflow <4farlion@gmail.com> Date: Fri, 30 Jan 2026 19:17:33 +0000 Subject: [PATCH 02/26] feat(dendritic): add flake-parts bootstrap infrastructure - Add flake-parts and import-tree inputs - Create parts/_bootstrap/ with options.nix (config.dendrix.*) and lib.nix - Restructure flake.nix outputs to use flake-parts.lib.mkFlake - Legacy configuration preserved in flake = { ... } block for incremental migration --- flake.lock | 56 ++++++- flake.nix | 274 ++++++++++++++++++----------------- parts/_bootstrap/default.nix | 6 + parts/_bootstrap/lib.nix | 4 + parts/_bootstrap/options.nix | 42 ++++++ 5 files changed, 243 insertions(+), 139 deletions(-) create mode 100644 parts/_bootstrap/default.nix create mode 100644 parts/_bootstrap/lib.nix create mode 100644 parts/_bootstrap/options.nix diff --git a/flake.lock b/flake.lock index 437f7bf0..865b17e4 100644 --- a/flake.lock +++ b/flake.lock @@ -179,6 +179,24 @@ } }, "flake-parts_2": { + "inputs": { + "nixpkgs-lib": "nixpkgs-lib" + }, + "locked": { + "lastModified": 1768135262, + "narHash": "sha256-PVvu7OqHBGWN16zSi6tEmPwwHQ4rLPU9Plvs8/1TUBY=", + "owner": "hercules-ci", + "repo": "flake-parts", + "rev": "80daad04eddbbf5a4d883996a73f3f542fa437ac", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "flake-parts", + "type": "github" + } + }, + "flake-parts_3": { "inputs": { "nixpkgs-lib": [ "nur", @@ -199,7 +217,7 @@ "type": "github" } }, - "flake-parts_3": { + "flake-parts_4": { "inputs": { "nixpkgs-lib": [ "stylix", @@ -381,6 +399,21 @@ "type": "github" } }, + "import-tree": { + "locked": { + "lastModified": 1763762820, + "narHash": "sha256-ZvYKbFib3AEwiNMLsejb/CWs/OL/srFQ8AogkebEPF0=", + "owner": "vic", + "repo": "import-tree", + "rev": "3c23749d8013ec6daa1d7255057590e9ca726646", + "type": "github" + }, + "original": { + "owner": "vic", + "repo": "import-tree", + "type": "github" + } + }, "niri": { "inputs": { "niri-stable": "niri-stable", @@ -540,6 +573,21 @@ "type": "github" } }, + "nixpkgs-lib": { + "locked": { + "lastModified": 1765674936, + "narHash": "sha256-k00uTP4JNfmejrCLJOwdObYC9jHRrr/5M/a/8L2EIdo=", + "owner": "nix-community", + "repo": "nixpkgs.lib", + "rev": "2075416fcb47225d9b68ac469a5c4801a9c4dd85", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "nixpkgs.lib", + "type": "github" + } + }, "nixpkgs-regression": { "locked": { "lastModified": 1643052045, @@ -684,7 +732,7 @@ }, "nur": { "inputs": { - "flake-parts": "flake-parts_2", + "flake-parts": "flake-parts_3", "nixpkgs": "nixpkgs_6" }, "locked": { @@ -747,8 +795,10 @@ "root": { "inputs": { "determinate": "determinate", + "flake-parts": "flake-parts_2", "home-manager": "home-manager", "impermanence": "impermanence", + "import-tree": "import-tree", "niri": "niri", "nix-index-database": "nix-index-database", "nixos-hardware": "nixos-hardware", @@ -827,7 +877,7 @@ "base16-helix": "base16-helix", "base16-vim": "base16-vim", "firefox-gnome-theme": "firefox-gnome-theme", - "flake-parts": "flake-parts_3", + "flake-parts": "flake-parts_4", "gnome-shell": "gnome-shell", "nixpkgs": "nixpkgs_8", "nur": "nur_2", diff --git a/flake.nix b/flake.nix index 87774165..1fb1d69d 100644 --- a/flake.nix +++ b/flake.nix @@ -3,11 +3,13 @@ inputs = { determinate.url = "https://flakehub.com/f/DeterminateSystems/determinate/*"; + flake-parts.url = "github:hercules-ci/flake-parts"; home-manager = { url = "github:nix-community/home-manager/release-25.11"; inputs.nixpkgs.follows = "nixpkgs"; }; impermanence.url = "github:nix-community/impermanence"; + import-tree.url = "github:vic/import-tree"; niri = { url = "github:sodiboo/niri-flake"; }; @@ -35,149 +37,149 @@ }; }; - outputs = { - self, - determinate, - nixpkgs, - nixos-unstable, - home-manager, - impermanence, - niri, - nur, - secrets, - sops-nix, - stylix, - ... - } @ inputs: let - commonModules = [ - { - nixpkgs.overlays = [ - (_: _: overlays) + outputs = inputs: + inputs.flake-parts.lib.mkFlake {inherit inputs;} ({...}: { + systems = ["x86_64-linux"]; + + imports = [ + ./parts/_bootstrap + (inputs.import-tree ./parts) + ]; + + # Legacy configuration - will be migrated to parts/ incrementally + flake = let + inherit (inputs) determinate nixpkgs nixos-unstable home-manager impermanence niri nur secrets sops-nix stylix; + + commonModules = [ + { + nixpkgs.overlays = [ + (_: _: overlays) + ]; + } + determinate.nixosModules.default + nixpkgs.nixosModules.notDetected + ./configuration.nix + nur.modules.nixos.default + impermanence.nixosModules.impermanence + sops-nix.nixosModules.sops + stylix.nixosModules.stylix + home-manager.nixosModules.home-manager + niri.nixosModules.niri ]; - } - determinate.nixosModules.default - nixpkgs.nixosModules.notDetected - ./configuration.nix - nur.modules.nixos.default - impermanence.nixosModules.impermanence - sops-nix.nixosModules.sops - stylix.nixosModules.stylix - home-manager.nixosModules.home-manager - niri.nixosModules.niri - ]; - commonHomeManagerSettings = { - useGlobalPkgs = true; - useUserPackages = true; - backupFileExtension = "home-manager-backup"; - users.farlion = import ./home; - }; - overlays = { - unstable = import nixos-unstable { - system = "x86_64-linux"; - config.allowUnfree = true; - }; - }; + commonHomeManagerSettings = { + useGlobalPkgs = true; + useUserPackages = true; + backupFileExtension = "home-manager-backup"; + users.farlion = import ./home; + }; + overlays = { + unstable = import nixos-unstable { + system = "x86_64-linux"; + config.allowUnfree = true; + }; + }; - mkSystem = { - hostname, - isImpermanent, - isLaptop, - isAmd, - isNvidia, - extraModules ? [], - }: let - machineArgs = { - inherit inputs secrets isImpermanent isLaptop; - }; - in - nixpkgs.lib.nixosSystem { - specialArgs = machineArgs; - modules = - commonModules - ++ [ - ./machines/${hostname}/hardware-scan.nix - ./machines/${hostname}/system.nix - { - home-manager = - commonHomeManagerSettings - // { - extraSpecialArgs = - machineArgs + mkSystem = { + hostname, + isImpermanent, + isLaptop, + isAmd, + isNvidia, + extraModules ? [], + }: let + machineArgs = { + inherit inputs secrets isImpermanent isLaptop; + }; + in + nixpkgs.lib.nixosSystem { + specialArgs = machineArgs; + modules = + commonModules + ++ [ + ./machines/${hostname}/hardware-scan.nix + ./machines/${hostname}/system.nix + { + home-manager = + commonHomeManagerSettings // { - inherit isAmd isNvidia; + extraSpecialArgs = + machineArgs + // { + inherit isAmd isNvidia; + }; }; - }; - } - ] - ++ extraModules; - }; - in { - nixosConfigurations.flexbox = mkSystem { - hostname = "flexbox"; - isImpermanent = false; - isLaptop = true; - isAmd = false; - isNvidia = true; - extraModules = [./system/nvidia]; - }; - - nixosConfigurations.numenor = mkSystem { - hostname = "numenor"; - isImpermanent = true; - isLaptop = false; - isAmd = true; - isNvidia = false; - extraModules = [./system/amd ./system/btrfs]; - }; + } + ] + ++ extraModules; + }; + in { + nixosConfigurations.flexbox = mkSystem { + hostname = "flexbox"; + isImpermanent = false; + isLaptop = true; + isAmd = false; + isNvidia = true; + extraModules = [./system/nvidia]; + }; - # Home-manager standalone configuration for `home-manager news` CLI - # Uses actual config with all host-specific features enabled for maximum news coverage - # Actual home-manager is managed via NixOS module (see nixosConfigurations above) - homeConfigurations.farlion = home-manager.lib.homeManagerConfiguration { - pkgs = nixpkgs.legacyPackages.x86_64-linux; - extraSpecialArgs = { - inherit inputs secrets; - # Enable all host-specific features to get maximum applicable news - isImpermanent = true; - isLaptop = true; - isAmd = true; - isNvidia = true; - # Mock osConfig for standalone mode - osConfig = { - networking.hostName = "standalone-news-config"; - specialisation = {}; + nixosConfigurations.numenor = mkSystem { + hostname = "numenor"; + isImpermanent = true; + isLaptop = false; + isAmd = true; + isNvidia = false; + extraModules = [./system/amd ./system/btrfs]; }; - }; - modules = [ - { - nixpkgs.overlays = [(_: _: overlays)]; - } - # Import impermanence home-manager module directly (the flake output is deprecated) - "${impermanence}/home-manager.nix" - nur.modules.homeManager.default - stylix.homeManagerModules.stylix - niri.homeModules.niri - { - home = { - username = "farlion"; - homeDirectory = "/home/farlion"; + + # Home-manager standalone configuration for `home-manager news` CLI + # Uses actual config with all host-specific features enabled for maximum news coverage + # Actual home-manager is managed via NixOS module (see nixosConfigurations above) + homeConfigurations.farlion = home-manager.lib.homeManagerConfiguration { + pkgs = nixpkgs.legacyPackages.x86_64-linux; + extraSpecialArgs = { + inherit inputs secrets; + # Enable all host-specific features to get maximum applicable news + isImpermanent = true; + isLaptop = true; + isAmd = true; + isNvidia = true; + # Mock osConfig for standalone mode + osConfig = { + networking.hostName = "standalone-news-config"; + specialisation = {}; + }; }; - assertions = nixpkgs.lib.mkForce []; - } - (import ./home) - ]; - }; + modules = [ + { + nixpkgs.overlays = [(_: _: overlays)]; + } + # Import impermanence home-manager module directly (the flake output is deprecated) + "${impermanence}/home-manager.nix" + nur.modules.homeManager.default + stylix.homeManagerModules.stylix + niri.homeModules.niri + { + home = { + username = "farlion"; + homeDirectory = "/home/farlion"; + }; + assertions = nixpkgs.lib.mkForce []; + } + (import ./home) + ]; + }; - # Expose profiling helper as a package and an app - # Call with `nix run .#nh-eval-profile -- ` - packages.x86_64-linux.nh-eval-profile = let - pkgsFor = nixpkgs.legacyPackages.x86_64-linux; - in - pkgsFor.callPackage ./system/scripts/nh-eval-profile.nix {}; + # Expose profiling helper as a package and an app + # Call with `nix run .#nh-eval-profile -- ` + packages.x86_64-linux.nh-eval-profile = let + pkgsFor = nixpkgs.legacyPackages.x86_64-linux; + in + pkgsFor.callPackage ./system/scripts/nh-eval-profile.nix {}; - apps.x86_64-linux.nh-eval-profile = { - type = "app"; - program = "${self.packages.x86_64-linux.nh-eval-profile}/bin/nh-eval-profile"; - }; - }; + apps.x86_64-linux.nh-eval-profile = { + type = "app"; + program = "${inputs.self.packages.x86_64-linux.nh-eval-profile}/bin/nh-eval-profile"; + }; + }; + }); } diff --git a/parts/_bootstrap/default.nix b/parts/_bootstrap/default.nix new file mode 100644 index 00000000..d8e411e6 --- /dev/null +++ b/parts/_bootstrap/default.nix @@ -0,0 +1,6 @@ +{...}: { + imports = [ + ./options.nix + ./lib.nix + ]; +} diff --git a/parts/_bootstrap/lib.nix b/parts/_bootstrap/lib.nix new file mode 100644 index 00000000..a6532d64 --- /dev/null +++ b/parts/_bootstrap/lib.nix @@ -0,0 +1,4 @@ +{lib, ...}: { + # Shared utilities for dendritic modules + # Currently minimal - expand as patterns emerge during migration +} diff --git a/parts/_bootstrap/options.nix b/parts/_bootstrap/options.nix new file mode 100644 index 00000000..beeccad6 --- /dev/null +++ b/parts/_bootstrap/options.nix @@ -0,0 +1,42 @@ +{lib, ...}: { + options.dendrix = { + hostname = lib.mkOption { + type = lib.types.str; + description = "Hostname of this machine"; + }; + + isLaptop = lib.mkOption { + type = lib.types.bool; + default = false; + description = "Whether this is a laptop"; + }; + + isImpermanent = lib.mkOption { + type = lib.types.bool; + default = false; + description = "Whether this machine uses impermanence (ephemeral root)"; + }; + + hasNvidia = lib.mkOption { + type = lib.types.bool; + default = false; + description = "Whether this machine has an NVIDIA GPU"; + }; + + hasAmd = lib.mkOption { + type = lib.types.bool; + default = false; + description = "Whether this machine has an AMD GPU"; + }; + + stateVersion = lib.mkOption { + type = lib.types.str; + description = "NixOS state version for this host"; + }; + + homeStateVersion = lib.mkOption { + type = lib.types.str; + description = "Home Manager state version for this host"; + }; + }; +} From 558fc1370c9e5d237d2b829ce0eb4047291db6ca Mon Sep 17 00:00:00 2001 From: workflow <4farlion@gmail.com> Date: Fri, 30 Jan 2026 19:22:23 +0000 Subject: [PATCH 03/26] feat(dendritic): migrate first batch of apps to dendritic pattern - Import flake-parts.flakeModules.modules for flake.modules option - Migrate btop, broot, fzf, ripgrep, starship, tealdeer, trash-cli, zoxide - Features using isImpermanent now use config.dendrix.isImpermanent --- flake.nix | 1 + parts/features/apps/broot.nix | 5 ++ parts/features/apps/btop.nix | 5 ++ parts/features/apps/fzf.nix | 8 ++ parts/features/apps/ripgrep.nix | 8 ++ parts/features/apps/starship.nix | 121 ++++++++++++++++++++++++++++++ parts/features/apps/tealdeer.nix | 12 +++ parts/features/apps/trash-cli.nix | 5 ++ parts/features/apps/zoxide.nix | 12 +++ 9 files changed, 177 insertions(+) create mode 100644 parts/features/apps/broot.nix create mode 100644 parts/features/apps/btop.nix create mode 100644 parts/features/apps/fzf.nix create mode 100644 parts/features/apps/ripgrep.nix create mode 100644 parts/features/apps/starship.nix create mode 100644 parts/features/apps/tealdeer.nix create mode 100644 parts/features/apps/trash-cli.nix create mode 100644 parts/features/apps/zoxide.nix diff --git a/flake.nix b/flake.nix index 1fb1d69d..bc1b55e5 100644 --- a/flake.nix +++ b/flake.nix @@ -42,6 +42,7 @@ systems = ["x86_64-linux"]; imports = [ + inputs.flake-parts.flakeModules.modules ./parts/_bootstrap (inputs.import-tree ./parts) ]; diff --git a/parts/features/apps/broot.nix b/parts/features/apps/broot.nix new file mode 100644 index 00000000..a4bc1129 --- /dev/null +++ b/parts/features/apps/broot.nix @@ -0,0 +1,5 @@ +{...}: { + flake.modules.homeManager.broot = {...}: { + programs.broot.enable = true; + }; +} diff --git a/parts/features/apps/btop.nix b/parts/features/apps/btop.nix new file mode 100644 index 00000000..9c54b28c --- /dev/null +++ b/parts/features/apps/btop.nix @@ -0,0 +1,5 @@ +{...}: { + flake.modules.homeManager.btop = {...}: { + programs.btop.enable = true; + }; +} diff --git a/parts/features/apps/fzf.nix b/parts/features/apps/fzf.nix new file mode 100644 index 00000000..cc390a44 --- /dev/null +++ b/parts/features/apps/fzf.nix @@ -0,0 +1,8 @@ +{...}: { + flake.modules.homeManager.fzf = {...}: { + programs.fzf = { + enable = true; + defaultCommand = "rg --files --no-ignore-vcs --hidden"; + }; + }; +} diff --git a/parts/features/apps/ripgrep.nix b/parts/features/apps/ripgrep.nix new file mode 100644 index 00000000..95880ee1 --- /dev/null +++ b/parts/features/apps/ripgrep.nix @@ -0,0 +1,8 @@ +{...}: { + flake.modules.homeManager.ripgrep = {...}: { + programs.ripgrep = { + enable = true; + arguments = ["--smart-case"]; + }; + }; +} diff --git a/parts/features/apps/starship.nix b/parts/features/apps/starship.nix new file mode 100644 index 00000000..c02817a7 --- /dev/null +++ b/parts/features/apps/starship.nix @@ -0,0 +1,121 @@ +{config, lib, ...}: { + flake.modules.homeManager.starship = {...}: { + home.persistence."/persist" = lib.mkIf config.dendrix.isImpermanent { + directories = [".cache/starship"]; + }; + + programs.starship = { + enable = true; + enableTransience = true; + + settings = { + format = lib.concatStrings [ + "$username" + "$hostname" + "$localip" + "$shlvl" + "$singularity" + "$directory" + "$vcsh" + "$docker_context" + "$package" + "$buf" + "$c" + "$cmake" + "$cobol" + "$container" + "$daml" + "$dart" + "$deno" + "$dotnet" + "$elixir" + "$elm" + "$erlang" + "$golang" + "$haskell" + "$helm" + "$java" + "$julia" + "$kotlin" + "$lua" + "$nim" + "$nodejs" + "$ocaml" + "$perl" + "$php" + "$pulumi" + "$purescript" + "$python" + "$rlang" + "$red" + "$ruby" + "$rust" + "$scala" + "$swift" + "$terraform" + "$vlang" + "$vagrant" + "$zig" + "$nix_shell" + "$conda" + "$spack" + "$memory_usage" + "$aws" + "$gcloud" + "$kubernetes" + "$openstack" + "$azure" + "$env_var" + "$crystal" + "$custom" + "$sudo" + "$cmd_duration" + "$line_break" + "$jobs" + "$battery" + "$time" + "$status" + "$shell" + "$character" + ]; + + aws.disabled = true; + + gcloud = { + disabled = true; + format = "on [$symbol$account(@$domain)|($project)](green) "; + }; + + kubernetes = { + disabled = false; + style = "green"; + contexts = [ + { + "context_pattern" = "kind-kind"; + "context_alias" = "kind"; + } + ]; + }; + + shell = { + disabled = false; + fish_indicator = "🐟"; + bash_indicator = "💩"; + nu_indicator = "🦀"; + }; + + status = { + disabled = false; + map_symbol = true; + pipestatus = false; + }; + + nix_shell = { + disabled = true; + format = "via [$symbol$state]($style) "; + impure_msg = ""; + }; + }; + }; + }; +} diff --git a/parts/features/apps/tealdeer.nix b/parts/features/apps/tealdeer.nix new file mode 100644 index 00000000..83ecd02a --- /dev/null +++ b/parts/features/apps/tealdeer.nix @@ -0,0 +1,12 @@ +{config, lib, ...}: { + flake.modules.homeManager.tealdeer = {...}: { + home.persistence."/persist" = lib.mkIf config.dendrix.isImpermanent { + directories = [".cache/tealdeer"]; + }; + + programs.tealdeer = { + enable = true; + settings.updates.auto_update = true; + }; + }; +} diff --git a/parts/features/apps/trash-cli.nix b/parts/features/apps/trash-cli.nix new file mode 100644 index 00000000..a4322bf9 --- /dev/null +++ b/parts/features/apps/trash-cli.nix @@ -0,0 +1,5 @@ +{...}: { + flake.modules.homeManager.trash-cli = {pkgs, ...}: { + home.packages = [pkgs.trash-cli]; + }; +} diff --git a/parts/features/apps/zoxide.nix b/parts/features/apps/zoxide.nix new file mode 100644 index 00000000..858bf9c7 --- /dev/null +++ b/parts/features/apps/zoxide.nix @@ -0,0 +1,12 @@ +{config, lib, ...}: { + flake.modules.homeManager.zoxide = {...}: { + home.persistence."/persist" = lib.mkIf config.dendrix.isImpermanent { + directories = [ + ".cache/zoxide" + ".local/share/zoxide" + ]; + }; + + programs.zoxide.enable = true; + }; +} From e9756e11e30ce298b5382fb831a8683ba6c75c6b Mon Sep 17 00:00:00 2001 From: workflow <4farlion@gmail.com> Date: Fri, 30 Jan 2026 19:30:24 +0000 Subject: [PATCH 04/26] refactor(dendritic): flatten structure to match original pattern - Remove _bootstrap directory - Move options.nix to parts/options.nix - Create parts/modules.nix for flakeModules.modules import - Simplify flake.nix to just use import-tree ./parts - Update doc/DENDRITIC.md to reflect new structure --- doc/DENDRITIC.md | 15 +++++++-------- flake.nix | 2 -- parts/_bootstrap/default.nix | 6 ------ parts/_bootstrap/lib.nix | 4 ---- parts/modules.nix | 5 +++++ parts/{_bootstrap => }/options.nix | 0 6 files changed, 12 insertions(+), 20 deletions(-) delete mode 100644 parts/_bootstrap/default.nix delete mode 100644 parts/_bootstrap/lib.nix create mode 100644 parts/modules.nix rename parts/{_bootstrap => }/options.nix (100%) diff --git a/doc/DENDRITIC.md b/doc/DENDRITIC.md index 89145060..cfd404d1 100644 --- a/doc/DENDRITIC.md +++ b/doc/DENDRITIC.md @@ -14,14 +14,13 @@ This document describes the architecture of this NixOS configuration, which foll ``` nixos-config/ -├── flake.nix # Minimal: inputs + flake-parts import +├── flake.nix # Minimal: inputs + import-tree ./parts ├── flake.lock │ -├── parts/ # All flake-parts modules -│ ├── _bootstrap/ # Core infrastructure -│ │ ├── default.nix # Auto-imports all parts/**/*.nix -│ │ ├── hosts.nix # Host definitions and feature composition -│ │ └── lib.nix # Shared functions and constants +├── parts/ # All flake-parts modules (auto-imported) +│ ├── options.nix # config.dendrix.* option definitions +│ ├── modules.nix # Imports flake-parts.flakeModules.modules +│ ├── hosts.nix # Host definitions and feature composition │ │ │ ├── features/ # Feature modules │ │ ├── core/ # Essential system features @@ -114,7 +113,7 @@ A feature file configures all aspects of a single feature: Instead of threading `specialArgs` through module evaluations, host-specific values are defined as options in the top-level configuration. Every module can read from this shared config: ```nix -# parts/_bootstrap/options.nix +# parts/options.nix { lib, ... }: { options.dendrix = { @@ -148,7 +147,7 @@ Instead of threading `specialArgs` through module evaluations, host-specific val ## Host Definition -Hosts compose features in `parts/_bootstrap/hosts.nix`: +Hosts compose features in `parts/hosts.nix`: ```nix { inputs, ... }: diff --git a/flake.nix b/flake.nix index bc1b55e5..a983bdbc 100644 --- a/flake.nix +++ b/flake.nix @@ -42,8 +42,6 @@ systems = ["x86_64-linux"]; imports = [ - inputs.flake-parts.flakeModules.modules - ./parts/_bootstrap (inputs.import-tree ./parts) ]; diff --git a/parts/_bootstrap/default.nix b/parts/_bootstrap/default.nix deleted file mode 100644 index d8e411e6..00000000 --- a/parts/_bootstrap/default.nix +++ /dev/null @@ -1,6 +0,0 @@ -{...}: { - imports = [ - ./options.nix - ./lib.nix - ]; -} diff --git a/parts/_bootstrap/lib.nix b/parts/_bootstrap/lib.nix deleted file mode 100644 index a6532d64..00000000 --- a/parts/_bootstrap/lib.nix +++ /dev/null @@ -1,4 +0,0 @@ -{lib, ...}: { - # Shared utilities for dendritic modules - # Currently minimal - expand as patterns emerge during migration -} diff --git a/parts/modules.nix b/parts/modules.nix new file mode 100644 index 00000000..8b515f36 --- /dev/null +++ b/parts/modules.nix @@ -0,0 +1,5 @@ +{inputs, ...}: { + imports = [ + inputs.flake-parts.flakeModules.modules + ]; +} diff --git a/parts/_bootstrap/options.nix b/parts/options.nix similarity index 100% rename from parts/_bootstrap/options.nix rename to parts/options.nix From 2b20e05ed99e138c0325bdbd428191eb59b5c68e Mon Sep 17 00:00:00 2001 From: workflow <4farlion@gmail.com> Date: Fri, 30 Jan 2026 19:34:30 +0000 Subject: [PATCH 05/26] feat(dendritic): migrate more features to dendritic pattern - Add syncthing (both nixos and home-manager modules) - Add direnv, git (with co-located config files) - Total: 11 homeManager modules, 1 nixos module --- parts/features/dev/direnv.nix | 13 +++++ parts/features/dev/git/default.nix | 76 +++++++++++++++++++++++++++ parts/features/dev/git/gh.config.yml | 7 +++ parts/features/services/syncthing.nix | 38 ++++++++++++++ 4 files changed, 134 insertions(+) create mode 100644 parts/features/dev/direnv.nix create mode 100644 parts/features/dev/git/default.nix create mode 100644 parts/features/dev/git/gh.config.yml create mode 100644 parts/features/services/syncthing.nix diff --git a/parts/features/dev/direnv.nix b/parts/features/dev/direnv.nix new file mode 100644 index 00000000..72b1abaa --- /dev/null +++ b/parts/features/dev/direnv.nix @@ -0,0 +1,13 @@ +{config, lib, ...}: { + flake.modules.homeManager.direnv = {...}: { + home.persistence."/persist" = lib.mkIf config.dendrix.isImpermanent { + directories = [".local/share/direnv"]; + }; + + programs.direnv = { + enable = true; + nix-direnv.enable = true; + config.strict_env = true; + }; + }; +} diff --git a/parts/features/dev/git/default.nix b/parts/features/dev/git/default.nix new file mode 100644 index 00000000..42cdadee --- /dev/null +++ b/parts/features/dev/git/default.nix @@ -0,0 +1,76 @@ +{config, lib, ...}: { + flake.modules.homeManager.git = {pkgs, ...}: { + home.persistence."/persist" = lib.mkIf config.dendrix.isImpermanent { + directories = [".config/glab-cli"]; + }; + + home.packages = with pkgs; [ + delta + github-cli + glab + ]; + + home.file.".config/gh/config.yml".source = ./gh.config.yml; + + programs.difftastic = { + enable = true; + git.enable = true; + }; + + programs.git = { + enable = true; + + includes = [ + { + path = "~/code/dlh/.gitconfig"; + condition = "gitdir:~/code/dlh/"; + } + { + path = "~/code/dlh/plansee/.gitconfig"; + condition = "gitdir:~/code/dlh/plansee/"; + } + ]; + + signing = { + signByDefault = true; + key = "24575DB93F6CEC16"; + }; + + settings = { + alias = { + c = "commit"; + dlog = "-c diff.external=difft log --ext-diff"; + dshow = "-c diff.external=difft show --ext-diff"; + ddiff = "-c diff.external=difft diff"; + dl = "-c diff.external=difft log -p --ext-diff"; + ds = "-c diff.external=difft show --ext-diff"; + dft = "-c diff.external=difft diff"; + p = "push"; + rim = "rebase -i main"; + rimm = "rebase -i master"; + }; + + core.pager = "delta"; + diff.colorMoved = "default"; + init.defaultBranch = "main"; + interactive.diffFilter = "delta --color-only"; + merge.conflictstyle = "diff3"; + pull = { + ff = "only"; + rebase = true; + }; + rebase = { + autoStash = true; + autoSquash = true; + }; + url."https://github.com".insteadOf = "git://github.com"; + user.email = "4farlion@gmail.com"; + user.name = "workflow"; + }; + + ignores = [".idea" "nohup.out" "mzdata" ".vimspector.json"]; + }; + + programs.mergiraf.enable = true; + }; +} diff --git a/parts/features/dev/git/gh.config.yml b/parts/features/dev/git/gh.config.yml new file mode 100644 index 00000000..016fae1d --- /dev/null +++ b/parts/features/dev/git/gh.config.yml @@ -0,0 +1,7 @@ +git_protocol: ssh +editor: +prompt: enabled +pager: +aliases: + co: pr checkout +version: 1 diff --git a/parts/features/services/syncthing.nix b/parts/features/services/syncthing.nix new file mode 100644 index 00000000..f8ed46aa --- /dev/null +++ b/parts/features/services/syncthing.nix @@ -0,0 +1,38 @@ +{config, lib, ...}: { + flake.modules.nixos.syncthing = {pkgs, ...}: { + # Prevent syncthing from preventing sleep + powerManagement.powerDownCommands = '' + export XDG_RUNTIME_DIR=/run/user/1000 + ${pkgs.systemd}/bin/machinectl shell farlion@ /run/current-system/sw/bin/systemctl --user stop syncthing.service + ''; + powerManagement.resumeCommands = '' + export XDG_RUNTIME_DIR=/run/user/1000 + ${pkgs.systemd}/bin/machinectl shell farlion@ /run/current-system/sw/bin/systemctl --user start syncthing.service + ''; + }; + + flake.modules.homeManager.syncthing = {...}: { + home.persistence."/persist" = lib.mkIf config.dendrix.isImpermanent { + directories = [ + ".local/state/syncthing" + ".config/syncthing" + ]; + files = [ + ".config/syncthingtray.ini" + ]; + }; + + services.syncthing = { + enable = true; + tray = { + enable = true; + command = "syncthingtray --wait"; + }; + }; + + systemd.user.services.syncthingtray.Service = { + Restart = "on-failure"; + RestartSec = 5; + }; + }; +} From f522a4353730ae1a72e628e6ae4785021f3f0bb1 Mon Sep 17 00:00:00 2001 From: workflow <4farlion@gmail.com> Date: Fri, 30 Jan 2026 19:39:23 +0000 Subject: [PATCH 06/26] feat(dendritic): migrate neovim with 43 plugin sub-modules - Prefix plugin directories with _ to exclude from import-tree - Plugin modules are imported internally by the neovim feature - Uses cfg.dendrix.isImpermanent for persistence - Preserves osConfig.specialisation check for theme detection --- parts/features/dev/neovim/_avante/avante.lua | 147 ++++++++ parts/features/dev/neovim/_avante/default.nix | 26 ++ parts/features/dev/neovim/_carbon/default.nix | 46 +++ parts/features/dev/neovim/_cmp/cmp.lua | 105 ++++++ parts/features/dev/neovim/_cmp/default.nix | 27 ++ .../dev/neovim/_comment-nvim/default.nix | 11 + .../features/dev/neovim/_conform/conform.lua | 23 ++ .../features/dev/neovim/_conform/default.nix | 13 + parts/features/dev/neovim/_dadbod/default.nix | 36 ++ parts/features/dev/neovim/_dap/dap-ui.lua | 24 ++ parts/features/dev/neovim/_dap/dap.lua | 134 ++++++++ parts/features/dev/neovim/_dap/default.nix | 25 ++ .../dev/neovim/_diffview-nvim/default.nix | 9 + .../neovim/_diffview-nvim/diffview-nvim.lua | 35 ++ parts/features/dev/neovim/_fidget/default.nix | 12 + parts/features/dev/neovim/_folds/default.nix | 9 + parts/features/dev/neovim/_folds/ufo.lua | 9 + .../features/dev/neovim/_fugitive/default.nix | 22 ++ .../dev/neovim/_fugitive/fugitive.lua | 63 ++++ .../dev/neovim/_git-conflict-nvim/default.nix | 11 + .../features/dev/neovim/_gitsigns/default.nix | 9 + .../dev/neovim/_gitsigns/gitsigns.lua | 52 +++ .../features/dev/neovim/_gruvbox/default.nix | 18 + parts/features/dev/neovim/_jdtls/default.nix | 11 + parts/features/dev/neovim/_jdtls/jdtls.lua | 99 ++++++ parts/features/dev/neovim/_jj/default.nix | 45 +++ parts/features/dev/neovim/_jj/jj.lua | 21 ++ .../features/dev/neovim/_lspsaga/default.nix | 16 + .../features/dev/neovim/_lualine/default.nix | 58 ++++ .../dev/neovim/_mason-lsp/default.nix | 84 +++++ .../features/dev/neovim/_mason-lsp/mason.lua | 200 +++++++++++ .../neovim/_mason-lsp/shared_lsp_config.lua | 41 +++ .../dev/neovim/_mini-icons/default.nix | 12 + .../dev/neovim/_mini-operators/default.nix | 31 ++ .../features/dev/neovim/_neotest/default.nix | 21 ++ .../features/dev/neovim/_neotest/neotest.lua | 31 ++ parts/features/dev/neovim/_noice/default.nix | 9 + parts/features/dev/neovim/_noice/noice.lua | 28 ++ parts/features/dev/neovim/_notify/default.nix | 21 ++ parts/features/dev/neovim/_nui/default.nix | 10 + .../dev/neovim/_nvim-tree-lua/default.nix | 9 + .../dev/neovim/_nvim-tree-lua/nvim-tree.lua | 59 ++++ .../dev/neovim/_obsidian-nvim/default.nix | 31 ++ parts/features/dev/neovim/_oil/default.nix | 27 ++ parts/features/dev/neovim/_otter/default.nix | 25 ++ .../features/dev/neovim/_overseer/default.nix | 25 ++ .../dev/neovim/_overseer/overseer.lua | 29 ++ .../dev/neovim/_overseer/overseer_lib.lua | 25 ++ .../_overseer/templates/gmailctl_apply.lua | 12 + .../_overseer/templates/java_gradle/init.lua | 57 ++++ .../_overseer/templates/java_maven/init.lua | 30 ++ .../templates/nixos_rebuild_boot.lua | 12 + .../templates/nixos_rebuild_switch.lua | 12 + .../templates/nixos_update_secrets.lua | 12 + .../_overseer/templates/skaffold_dev.lua | 12 + .../features/dev/neovim/_plenary/default.nix | 10 + .../dev/neovim/_rainbow-csv/default.nix | 21 ++ .../dev/neovim/_render-markdown/default.nix | 16 + .../dev/neovim/_telescope/default.nix | 87 +++++ .../dev/neovim/_toggleterm/default.nix | 14 + .../dev/neovim/_treesitter/default.nix | 36 ++ .../_treesitter/queries/nix/injections.scm | 91 +++++ .../dev/neovim/_treesitter/treesitter.lua | 49 +++ .../features/dev/neovim/_trouble/default.nix | 9 + .../features/dev/neovim/_trouble/trouble.lua | 19 ++ .../features/dev/neovim/_undotree/default.nix | 7 + .../dev/neovim/_vim-be-good/default.nix | 7 + .../dev/neovim/_vim-terraform/default.nix | 7 + .../dev/neovim/_vim-visual-multi/default.nix | 13 + .../dev/neovim/_web-devicons/default.nix | 15 + .../dev/neovim/_yank-file-line/default.nix | 3 + .../neovim/_yank-file-line/yank-file-line.lua | 21 ++ parts/features/dev/neovim/default.nix | 319 ++++++++++++++++++ 73 files changed, 2725 insertions(+) create mode 100644 parts/features/dev/neovim/_avante/avante.lua create mode 100644 parts/features/dev/neovim/_avante/default.nix create mode 100644 parts/features/dev/neovim/_carbon/default.nix create mode 100644 parts/features/dev/neovim/_cmp/cmp.lua create mode 100644 parts/features/dev/neovim/_cmp/default.nix create mode 100644 parts/features/dev/neovim/_comment-nvim/default.nix create mode 100644 parts/features/dev/neovim/_conform/conform.lua create mode 100644 parts/features/dev/neovim/_conform/default.nix create mode 100644 parts/features/dev/neovim/_dadbod/default.nix create mode 100644 parts/features/dev/neovim/_dap/dap-ui.lua create mode 100644 parts/features/dev/neovim/_dap/dap.lua create mode 100644 parts/features/dev/neovim/_dap/default.nix create mode 100644 parts/features/dev/neovim/_diffview-nvim/default.nix create mode 100644 parts/features/dev/neovim/_diffview-nvim/diffview-nvim.lua create mode 100644 parts/features/dev/neovim/_fidget/default.nix create mode 100644 parts/features/dev/neovim/_folds/default.nix create mode 100644 parts/features/dev/neovim/_folds/ufo.lua create mode 100644 parts/features/dev/neovim/_fugitive/default.nix create mode 100644 parts/features/dev/neovim/_fugitive/fugitive.lua create mode 100644 parts/features/dev/neovim/_git-conflict-nvim/default.nix create mode 100644 parts/features/dev/neovim/_gitsigns/default.nix create mode 100644 parts/features/dev/neovim/_gitsigns/gitsigns.lua create mode 100644 parts/features/dev/neovim/_gruvbox/default.nix create mode 100644 parts/features/dev/neovim/_jdtls/default.nix create mode 100644 parts/features/dev/neovim/_jdtls/jdtls.lua create mode 100644 parts/features/dev/neovim/_jj/default.nix create mode 100644 parts/features/dev/neovim/_jj/jj.lua create mode 100644 parts/features/dev/neovim/_lspsaga/default.nix create mode 100644 parts/features/dev/neovim/_lualine/default.nix create mode 100644 parts/features/dev/neovim/_mason-lsp/default.nix create mode 100644 parts/features/dev/neovim/_mason-lsp/mason.lua create mode 100644 parts/features/dev/neovim/_mason-lsp/shared_lsp_config.lua create mode 100644 parts/features/dev/neovim/_mini-icons/default.nix create mode 100644 parts/features/dev/neovim/_mini-operators/default.nix create mode 100644 parts/features/dev/neovim/_neotest/default.nix create mode 100644 parts/features/dev/neovim/_neotest/neotest.lua create mode 100644 parts/features/dev/neovim/_noice/default.nix create mode 100644 parts/features/dev/neovim/_noice/noice.lua create mode 100644 parts/features/dev/neovim/_notify/default.nix create mode 100644 parts/features/dev/neovim/_nui/default.nix create mode 100644 parts/features/dev/neovim/_nvim-tree-lua/default.nix create mode 100644 parts/features/dev/neovim/_nvim-tree-lua/nvim-tree.lua create mode 100644 parts/features/dev/neovim/_obsidian-nvim/default.nix create mode 100644 parts/features/dev/neovim/_oil/default.nix create mode 100644 parts/features/dev/neovim/_otter/default.nix create mode 100644 parts/features/dev/neovim/_overseer/default.nix create mode 100644 parts/features/dev/neovim/_overseer/overseer.lua create mode 100644 parts/features/dev/neovim/_overseer/overseer_lib.lua create mode 100644 parts/features/dev/neovim/_overseer/templates/gmailctl_apply.lua create mode 100644 parts/features/dev/neovim/_overseer/templates/java_gradle/init.lua create mode 100644 parts/features/dev/neovim/_overseer/templates/java_maven/init.lua create mode 100644 parts/features/dev/neovim/_overseer/templates/nixos_rebuild_boot.lua create mode 100644 parts/features/dev/neovim/_overseer/templates/nixos_rebuild_switch.lua create mode 100644 parts/features/dev/neovim/_overseer/templates/nixos_update_secrets.lua create mode 100644 parts/features/dev/neovim/_overseer/templates/skaffold_dev.lua create mode 100644 parts/features/dev/neovim/_plenary/default.nix create mode 100644 parts/features/dev/neovim/_rainbow-csv/default.nix create mode 100644 parts/features/dev/neovim/_render-markdown/default.nix create mode 100644 parts/features/dev/neovim/_telescope/default.nix create mode 100644 parts/features/dev/neovim/_toggleterm/default.nix create mode 100644 parts/features/dev/neovim/_treesitter/default.nix create mode 100644 parts/features/dev/neovim/_treesitter/queries/nix/injections.scm create mode 100644 parts/features/dev/neovim/_treesitter/treesitter.lua create mode 100644 parts/features/dev/neovim/_trouble/default.nix create mode 100644 parts/features/dev/neovim/_trouble/trouble.lua create mode 100644 parts/features/dev/neovim/_undotree/default.nix create mode 100644 parts/features/dev/neovim/_vim-be-good/default.nix create mode 100644 parts/features/dev/neovim/_vim-terraform/default.nix create mode 100644 parts/features/dev/neovim/_vim-visual-multi/default.nix create mode 100644 parts/features/dev/neovim/_web-devicons/default.nix create mode 100644 parts/features/dev/neovim/_yank-file-line/default.nix create mode 100644 parts/features/dev/neovim/_yank-file-line/yank-file-line.lua create mode 100644 parts/features/dev/neovim/default.nix diff --git a/parts/features/dev/neovim/_avante/avante.lua b/parts/features/dev/neovim/_avante/avante.lua new file mode 100644 index 00000000..89244a38 --- /dev/null +++ b/parts/features/dev/neovim/_avante/avante.lua @@ -0,0 +1,147 @@ +require('avante_lib').load() +require('avante').setup({ + acp_providers = { + ["claude-code"] = { + command = "npx", + args = { "@zed-industries/claude-code-acp" }, + env = { + NODE_NO_WARNINGS = "1", + ANTHROPIC_API_KEY = os.getenv("ANTHROPIC_API_KEY"), + }, + }, + ["codex"] = { + command = "npx", + args = { "@zed-industries/codex-acp" }, + env = { + NODE_NO_WARNINGS = "1", + OPENAI_API_KEY = os.getenv("OPENAI_API_KEY"), + }, + }, + }, + behaviour = { + enable_fastapply = true, -- Uses morphllm.com + auto_approve_tool_permissions = false, + }, + debug = false, + dual_boost = { + enabled = false, + first_provider = "azure", + }, + hints = { enabled = false }, + instructions_file = "agents.md", + providers = { + openai = { + model = "gpt-5.2", + extra_request_body = { + temperature = 1, + }, + }, + openai_5_thinking = { + __inherited_from = 'openai', + model = "gpt-5.2", + extra_request_body = { + temperature = 1, + reasoning_effort = "high", + }, + }, + claude = { + endpoint = "https://api.anthropic.com", + model = "claude-sonnet-4-5", + }, + claude_thinking = { + __inherited_from = 'claude', + model = "claude-sonnet-4-5", + thinking = { + type = "enabled", + }, + }, + morph = { + model = "auto", + }, + }, + provider = "openai_5_thinking", + selector = { + provider = "telescope", + exclude_auto_select = { "NvimTree" }, + }, + system_prompt = + "When trying to read a pasted image, as a temporary workaround copy it to the current project directory before using str_replace_based_edit_tool(view) on it. When writing to AGENTS.md, don't document history, only note architectural changes that would be important to know going forward. Use jj instead of git. When writing shell scripts, always prefer the longhand version of arguments (e.g., --all instead of -a) and reserve the short-hand version for ad-hoc command invocations.", + + web_search_engine = { + provider = "kagi", + }, +}) + +-- Improve contrast for Avante diffs when using a light colorscheme (e.g., gruvbox-light) +-- This specifically targets deleted lines which tend to have very low contrast. +local function set_avante_light_highlights() + if vim.o.background ~= 'light' then return end + + -- Make deleted lines readable on light background + -- Use a stronger red background and high-contrast foreground + vim.api.nvim_set_hl(0, 'DiffDelete', { fg = '#7c0000', bg = '#ffb4b4', bold = true }) + + -- Ensure diff text hunk highlight is also visible enough on light backgrounds + vim.api.nvim_set_hl(0, 'DiffText', { bg = '#ffe29a' }) + + -- Avante-specific groups that can appear for deleted blocks in edit/suggestion views + pcall(vim.api.nvim_set_hl, 0, 'AvanteToBeDeleted', + { fg = '#7c0000', bg = '#ffb4b4', strikethrough = true, bold = true }) + pcall(vim.api.nvim_set_hl, 0, 'AvanteToBeDeletedWOStrikethrough', { fg = '#ffffff', bg = '#a23a3f', bold = true }) + + -- Avante exposes highlight groups for conflicts; set them to readable backgrounds if present + -- Use pcall so this doesn't error if groups don't exist or are managed by the plugin + pcall(vim.api.nvim_set_hl, 0, 'AvanteConflictCurrent', { bg = '#ffe8b3' }) -- ours/current + pcall(vim.api.nvim_set_hl, 0, 'AvanteConflictIncoming', { bg = '#d9f2d9' }) -- theirs/incoming +end + +-- Apply immediately and re-apply when colorscheme or background changes +set_avante_light_highlights() +vim.api.nvim_create_autocmd('ColorScheme', { + callback = set_avante_light_highlights, +}) +vim.api.nvim_create_autocmd('OptionSet', { + pattern = 'background', + callback = set_avante_light_highlights, +}) + +local wk = require("which-key") +wk.add( + { + { + { "a", group = "[A]vante" }, + { "", "AvanteToggle", desc = "Toggle Avante", mode = { "n", "v" } }, + { "", "AvanteToggle", desc = "Toggle Avante", mode = { "i" } }, + }, + } +) + +-- Set up buffer-local mappings for NvimTree +vim.api.nvim_create_autocmd("FileType", { + pattern = "NvimTree", + callback = function(args) + local bufnr = args.buf + vim.keymap.set("n", "a+", function() + local tree_ext = require("avante.extensions.nvim_tree") + tree_ext.add_file() + end, { buffer = bufnr, desc = "Select file in NvimTree" }) + + vim.keymap.set("n", "a-", function() + local tree_ext = require("avante.extensions.nvim_tree") + tree_ext.remove_file() + end, { buffer = bufnr, desc = "Deselect file in NvimTree" }) + end, +}) + +-- Manual "Reject with reason" +vim.keymap.set("n", "ax", function() + vim.ui.input({ prompt = "Why reject? " }, function(reason) + if reason and reason ~= "" then + -- send the feedback to Avante + vim.cmd("AvanteAsk " .. vim.fn.shellescape( + "I rejected your last action because: " .. reason .. + ". Please adjust your plan and try again." + )) + end + end) +end, { desc = "Avante: reject with reason (send feedback)" }) diff --git a/parts/features/dev/neovim/_avante/default.nix b/parts/features/dev/neovim/_avante/default.nix new file mode 100644 index 00000000..6aea934d --- /dev/null +++ b/parts/features/dev/neovim/_avante/default.nix @@ -0,0 +1,26 @@ +# Cursor style AI IDE +{ + isImpermanent, + lib, + pkgs, + ... +}: { + home.persistence."/persist" = lib.mkIf isImpermanent { + directories = [ + ".config/avante.nvim" # Some Avante state like last used model + ]; + }; + programs.neovim = { + extraLuaConfig = '' + -- views can only be fully collapsed with the global statusline + vim.opt.laststatus = 3 + ''; + plugins = [ + { + plugin = pkgs.vimPlugins.avante-nvim; + config = builtins.readFile ./avante.lua; + type = "lua"; + } + ]; + }; +} diff --git a/parts/features/dev/neovim/_carbon/default.nix b/parts/features/dev/neovim/_carbon/default.nix new file mode 100644 index 00000000..dd7eab17 --- /dev/null +++ b/parts/features/dev/neovim/_carbon/default.nix @@ -0,0 +1,46 @@ +{pkgs, ...}: let + carbon-now = pkgs.vimUtils.buildVimPlugin { + name = "carbon-now"; + src = pkgs.fetchFromGitHub { + owner = "ellisonleao"; + repo = "carbon-now.nvim"; + rev = "4524d2b347830257bb9357d45c4f934960058476"; + sha256 = "id9KSrv683eb03ZB9VZ+ERBKuAlWbypjx0kEzCeiL0c="; + }; + }; +in { + programs.neovim.plugins = [ + { + plugin = carbon-now; + config = '' + require('carbon-now').setup({ + options = { + bg = "purple", + drop_shadow_blur = "68px", + drop_shadow = false, + drop_shadow_offset_y = "20px", + font_family = "Fira Code", + font_size = "18px", + line_height = "133%", + line_numbers = true, + theme = "one-dark", + titlebar = "Made with carbon-now.nvim", + watermark = false, + window_theme = "sharp", + padding_horizontal = "5px", + padding_vertical = "5px", + }, + }) + + vim.keymap.set("v", "s", ":CarbonNow", { silent = true }) + local wk = require("which-key") + wk.add( + { + { "s", desc = "[S]creenshot", mode = "v" }, + } + ) + ''; + type = "lua"; + } + ]; +} diff --git a/parts/features/dev/neovim/_cmp/cmp.lua b/parts/features/dev/neovim/_cmp/cmp.lua new file mode 100644 index 00000000..d8b239e5 --- /dev/null +++ b/parts/features/dev/neovim/_cmp/cmp.lua @@ -0,0 +1,105 @@ +local cmp = require 'cmp' +local luasnip = require 'luasnip' +require('luasnip.loaders.from_vscode').lazy_load() +luasnip.config.setup {} + +cmp.setup { + snippet = { + expand = function(args) + luasnip.lsp_expand(args.body) + end, + }, + completion = { + completeopt = 'menu,menuone,noinsert', + }, + mapping = cmp.mapping.preset.insert { + -- Select the [n]ext item + [''] = cmp.mapping.select_next_item(), + -- Select the [p]revious item + [''] = cmp.mapping.select_prev_item(), + + -- Scroll the documentation window [b]ack / [f]orward + [''] = cmp.mapping.scroll_docs(-4), + [''] = cmp.mapping.scroll_docs(-4), + [''] = cmp.mapping.scroll_docs(4), + [''] = cmp.mapping.scroll_docs(4), + + -- Exit completion + [''] = cmp.mapping.abort(), + + -- Accept ([y]es) the completion. + -- This will auto-import if your LSP supports it. + -- This will expand snippets if the LSP sent a snippet. + [''] = cmp.mapping(function(fallback) + if cmp.visible() then + cmp.confirm({ select = true }) + else + fallback() + end + end), + [''] = cmp.mapping.confirm { select = true }, + + [''] = cmp.mapping.complete {}, + }, + sources = { + { name = 'nvim_lsp' }, + { name = 'luasnip' }, + { name = 'path' }, + { name = 'buffer' }, + }, +} + +-- Use buffer source for `/` and `?` (if you enabled `native_menu`, this won't work anymore). +cmp.setup.cmdline({ '/', '?' }, { + mapping = cmp.mapping.preset.cmdline(), + sources = { + { name = 'buffer' } + } +}) + +-- Use cmdline & path source for ':' (if you enabled `native_menu`, this won't work anymore). +cmp.setup.cmdline(':', { + mapping = cmp.mapping.preset.cmdline(), + sources = cmp.config.sources({ + { name = 'path' } + }, { + { name = 'cmdline' } + }), + matching = { disallow_symbol_nonprefix_matching = false } +}) + +local lspkind = require('lspkind') +cmp.setup { + formatting = { + format = lspkind.cmp_format({ + mode = 'symbol', -- show only symbol annotations + maxwidth = 50, -- prevent the popup from showing more than provided characters (e.g 50 will not show more than 50 characters) + -- can also be a function to dynamically calculate max width such as + -- maxwidth = function() return math.floor(0.45 * vim.o.columns) end, + ellipsis_char = '...', -- when popup menu exceed maxwidth, the truncated part would show ellipsis_char instead (must define maxwidth first) + show_labelDetails = true, -- show labelDetails in menu. Disabled by default + + -- The function below will be called before any actual modifications from lspkind + -- so that you can provide more controls on popup customization. (See [#30](https://github.com/onsails/lspkind-nvim/pull/30)) + before = function(entry, vim_item) + vim_item.menu = ({ + buffer = "[Buffer]", + nvim_lsp = "[LSP]", + luasnip = "[Snippet]", + path = "[Path]", + -- Specify the name for other sources you may have + })[entry.source.name] + + return vim_item + end + }) + } +} + +-- nvim-dadbod (SQL) setup +cmp.setup.filetype({ "sql" }, { + sources = { + { name = 'vim-dadbod-completion' }, + { name = 'buffer' }, + }, +}) diff --git a/parts/features/dev/neovim/_cmp/default.nix b/parts/features/dev/neovim/_cmp/default.nix new file mode 100644 index 00000000..9f26e7f2 --- /dev/null +++ b/parts/features/dev/neovim/_cmp/default.nix @@ -0,0 +1,27 @@ +{pkgs, ...}: { + programs.neovim.plugins = with pkgs.vimPlugins; [ + { + plugin = nvim-cmp; # Autocompletion + config = builtins.readFile ./cmp.lua; + type = "lua"; + } + { + plugin = cmp_luasnip; # Autocompletion for luasnip + } + { + plugin = cmp-nvim-lsp; # Autocompletion Additions + } + { + plugin = cmp-path; # Path completions + } + { + plugin = cmp-buffer; # Buffer completions + } + { + plugin = cmp-cmdline; # Commandline completions + } + { + plugin = lspkind-nvim; # VSCode-like pictograms for LSP completions + } + ]; +} diff --git a/parts/features/dev/neovim/_comment-nvim/default.nix b/parts/features/dev/neovim/_comment-nvim/default.nix new file mode 100644 index 00000000..5a2e46f1 --- /dev/null +++ b/parts/features/dev/neovim/_comment-nvim/default.nix @@ -0,0 +1,11 @@ +{pkgs, ...}: { + programs.neovim.plugins = with pkgs.vimPlugins; [ + { + plugin = comment-nvim; # Commenting with gc + config = '' + require('Comment').setup() + ''; + type = "lua"; + } + ]; +} diff --git a/parts/features/dev/neovim/_conform/conform.lua b/parts/features/dev/neovim/_conform/conform.lua new file mode 100644 index 00000000..dba25c5d --- /dev/null +++ b/parts/features/dev/neovim/_conform/conform.lua @@ -0,0 +1,23 @@ +require("conform").setup({ + formatters_by_ft = { + sh = { "shfmt" }, + bash = { "shfmt" }, + html = { "prettierd" }, + json = { "prettierd" }, + yaml = { "prettierd" }, + markdown = { "prettierd" }, + python = { "ruff_format", "ruff_organize_imports" }, + }, + -- Uncomment to enable format on save: + -- format_on_save = { + -- timeout_ms = 500, + -- lsp_format = "fallback", + -- }, +}) + +-- Optional: Set up a keybinding for manual formatting +-- Use f since LSP-related actions use localleader +local wk = require("which-key") +wk.add({ + { "f", function() require("conform").format({ async = true, lsp_format = "fallback" }) end, desc = "[F]ormat buffer" }, +}) diff --git a/parts/features/dev/neovim/_conform/default.nix b/parts/features/dev/neovim/_conform/default.nix new file mode 100644 index 00000000..32806c92 --- /dev/null +++ b/parts/features/dev/neovim/_conform/default.nix @@ -0,0 +1,13 @@ +{pkgs, ...}: { + programs.neovim.extraPackages = with pkgs; [ + eslint + ruff + ]; + programs.neovim.plugins = with pkgs.vimPlugins; [ + { + plugin = conform-nvim; + config = builtins.readFile ./conform.lua; + type = "lua"; + } + ]; +} diff --git a/parts/features/dev/neovim/_dadbod/default.nix b/parts/features/dev/neovim/_dadbod/default.nix new file mode 100644 index 00000000..30f35172 --- /dev/null +++ b/parts/features/dev/neovim/_dadbod/default.nix @@ -0,0 +1,36 @@ +{ + isImpermanent, + lib, + pkgs, + ... +}: { + home.persistence."/persist" = lib.mkIf isImpermanent { + directories = [ + ".local/share/db_ui" + ]; + }; + programs.neovim.plugins = with pkgs.vimPlugins; [ + { + plugin = vim-dadbod; # SQL Fu + } + { + plugin = vim-dadbod-completion; + } + { + plugin = vim-dadbod-ui; + config = '' + vim.g.db_ui_use_nerd_fonts = 1 + + local wk = require("which-key") + wk.add( + { + { "D", group = "[D]atabase" }, + { "Dn", "tab DBUI", desc = "open in [n]ew tab" }, + { "Dt", "DBUIToggle", desc = "[t]oggle" }, + } + ) + ''; + type = "lua"; + } + ]; +} diff --git a/parts/features/dev/neovim/_dap/dap-ui.lua b/parts/features/dev/neovim/_dap/dap-ui.lua new file mode 100644 index 00000000..6d83e572 --- /dev/null +++ b/parts/features/dev/neovim/_dap/dap-ui.lua @@ -0,0 +1,24 @@ +local wk = require("which-key") +local dap, dapui = require("dap"), require("dapui") +dapui.setup({ + wk.add( + { + { "dt", require('dapui').toggle, desc = "[T]oggle UI" }, + { "", require('dapui').toggle, desc = "[T]oggle UI" }, + } + ) +}) + +-- Events to auto-open/close the UI +dap.listeners.before.attach.dapui_config = function() + dapui.open() +end +dap.listeners.before.launch.dapui_config = function() + dapui.open() +end +dap.listeners.before.event_terminated.dapui_config = function() + dapui.close() +end +dap.listeners.before.event_exited.dapui_config = function() + dapui.close() +end diff --git a/parts/features/dev/neovim/_dap/dap.lua b/parts/features/dev/neovim/_dap/dap.lua new file mode 100644 index 00000000..f272f62d --- /dev/null +++ b/parts/features/dev/neovim/_dap/dap.lua @@ -0,0 +1,134 @@ +local wk = require("which-key") +local dap = require("dap") +wk.add( + { + { "d", group = "[D]ebug" }, + { "dB", function() dap.set_breakpoint(vim.fn.input('Breakpoint condition: ')) end, desc = "Set conditional [B]reakpoint" }, + { "db", function() dap.toggle_breakpoint() end, desc = "Toggle [B]reakpoint" }, + { "dc", function() dap.continue() end, desc = "[C]ontinue" }, + { "", function() dap.continue() end, desc = "Continue" }, + { "dC", function() dap.run_to_cursor() end, desc = "Run to [C]ursor" }, + { "di", function() dap.step_into() end, desc = "Step [I]nto" }, + { "", function() dap.step_into() end, desc = "Step Into" }, + { "do", function() dap.step_over() end, desc = "Step [O]ver" }, + { "", function() dap.step_over() end, desc = "Step Over" }, + { "dq", function() dap.close() end, desc = "[Q]uit/Close dap" }, + { "dr", function() dap.repl.open() end, desc = "Open [R]epl" }, + { "du", function() dap.step_out() end, desc = "Step O[u]t" }, + { "", function() dap.step_out() end, desc = "Step Out" }, + } +) + +-- Fix color highlighting for stopped DAP line +-- See https://github.com/mfussenegger/nvim-dap/discussions/355#discussioncomment-8389225 +vim.api.nvim_create_autocmd("ColorScheme", { + pattern = "*", + desc = "Prevent colorscheme clearing self-defined DAP marker colors", + callback = function() + -- Reuse current SignColumn background (except for DapStoppedLine) + local sign_column_hl = vim.api.nvim_get_hl(0, { name = 'SignColumn' }) + -- if bg or ctermbg aren't found, use bg = 'bg' (which means current Normal) and ctermbg = 'Black' + -- convert to 6 digit hex value starting with # + local sign_column_bg = (sign_column_hl.bg ~= nil) and ('#%06x'):format(sign_column_hl.bg) or 'bg' + local sign_column_ctermbg = (sign_column_hl.ctermbg ~= nil) and sign_column_hl.ctermbg or 'Black' + + vim.api.nvim_set_hl(0, 'DapStopped', { fg = '#00ff00', bg = sign_column_bg, ctermbg = sign_column_ctermbg }) + vim.api.nvim_set_hl(0, 'DapStoppedLine', { bg = '#2e4d3d', ctermbg = 'Green' }) + vim.api.nvim_set_hl(0, 'DapBreakpoint', { fg = '#c23127', bg = sign_column_bg, ctermbg = sign_column_ctermbg }) + vim.api.nvim_set_hl(0, 'DapBreakpointRejected', + { fg = '#888ca6', bg = sign_column_bg, ctermbg = sign_column_ctermbg }) + vim.api.nvim_set_hl(0, 'DapLogPoint', { fg = '#61afef', bg = sign_column_bg, ctermbg = sign_column_ctermbg }) + + vim.fn.sign_define('DapStopped', { + text = '→', + texthl = 'DapStopped', + linehl = 'DapStoppedLine', + numhl = 'DapStoppedLine', + }) + end +}) + +-- Existing Rust/C/C++ debug adapter (codelldb) +dap.adapters.codelldb = { + type = "executable", + command = "codelldb", +}; + +dap.configurations.cpp = { + { + name = "Launch file", + type = "codelldb", + request = "launch", + program = function() + return vim.fn.input('Path to executable: ', vim.fn.getcwd() .. '/', 'file') + end, + cwd = '${workspaceFolder}', + stopOnEntry = false, + }, +} +dap.configurations.c = dap.configurations.cpp + +-- Rust uses the same config as C/C++ +dap.configurations.rust = dap.configurations.cpp + +-- JavaScript/TypeScript debug (vscode-js-debug via nvim-dap-vscode-js) +-- Requires Mason package: js-debug-adapter +local ok, vscode_js = pcall(require, 'dap-vscode-js') +if ok then + vscode_js.setup({ + -- Path where Mason installs the js-debug adapter + debugger_path = vim.fn.stdpath('data') .. '/mason/packages/js-debug-adapter', + adapters = { 'pwa-node', 'pwa-chrome', 'pwa-msedge', 'node-terminal', 'pwa-extensionHost' }, + }) + + local js_based_languages = { 'typescript', 'javascript', 'typescriptreact', 'javascriptreact' } + + for _, language in ipairs(js_based_languages) do + dap.configurations[language] = dap.configurations[language] or {} + + -- Launch current file using ts-node + table.insert(dap.configurations[language], { + type = 'pwa-node', + request = 'launch', + name = 'Launch TS (ts-node)', + program = '${file}', + cwd = '${workspaceFolder}', + runtimeExecutable = 'node', + runtimeArgs = { '-r', 'ts-node/register' }, + sourceMaps = true, + protocol = 'inspector', + console = 'integratedTerminal', + env = { TS_NODE_PROJECT = '${workspaceFolder}/tsconfig.json' }, + }) + + -- Attach to a running Node process (start node with --inspect or --inspect-brk) + table.insert(dap.configurations[language], { + type = 'pwa-node', + request = 'attach', + name = 'Attach to Node', + processId = require('dap.utils').pick_process, + cwd = '${workspaceFolder}', + }) + + -- Launch transpiled JS from dist (requires a build step) + table.insert(dap.configurations[language], { + type = 'pwa-node', + request = 'launch', + name = 'Launch built app (dist)', + program = '${workspaceFolder}/dist/index.js', + cwd = '${workspaceFolder}', + outFiles = { '${workspaceFolder}/dist/**/*.js' }, + sourceMaps = true, + console = 'integratedTerminal', + }) + + -- Debug a web app in Chrome (points to local dev server) + table.insert(dap.configurations[language], { + type = 'pwa-chrome', + request = 'launch', + name = 'Chrome: localhost', + url = 'http://localhost:3000', + webRoot = '${workspaceFolder}', + }) + end +end diff --git a/parts/features/dev/neovim/_dap/default.nix b/parts/features/dev/neovim/_dap/default.nix new file mode 100644 index 00000000..79dd6fff --- /dev/null +++ b/parts/features/dev/neovim/_dap/default.nix @@ -0,0 +1,25 @@ +{pkgs, ...}: { + programs.neovim.plugins = with pkgs.vimPlugins; [ + { + plugin = nvim-dap; # Debug Adapter Protocol + config = builtins.readFile ./dap.lua; + type = "lua"; + } + { + plugin = nvim-dap-ui; # DAP UI + config = builtins.readFile ./dap-ui.lua; + type = "lua"; + } + { + plugin = nvim-dap-virtual-text; # Virtual text showing values using Treesitter + config = '' + require("nvim-dap-virtual-text").setup() + ''; + type = "lua"; + } + # JavaScript/TypeScript DAP adapter + { + plugin = nvim-dap-vscode-js; + } + ]; +} diff --git a/parts/features/dev/neovim/_diffview-nvim/default.nix b/parts/features/dev/neovim/_diffview-nvim/default.nix new file mode 100644 index 00000000..df54f0dc --- /dev/null +++ b/parts/features/dev/neovim/_diffview-nvim/default.nix @@ -0,0 +1,9 @@ +{pkgs, ...}: { + programs.neovim.plugins = with pkgs.vimPlugins; [ + { + plugin = diffview-nvim; + config = builtins.readFile ./diffview-nvim.lua; + type = "lua"; + } + ]; +} diff --git a/parts/features/dev/neovim/_diffview-nvim/diffview-nvim.lua b/parts/features/dev/neovim/_diffview-nvim/diffview-nvim.lua new file mode 100644 index 00000000..f5802765 --- /dev/null +++ b/parts/features/dev/neovim/_diffview-nvim/diffview-nvim.lua @@ -0,0 +1,35 @@ +local wk = require("which-key") +wk.add({ + { "v", group = "Diff[v]iew" }, + { "vo", ":DiffviewOpen", desc = "[O]pen" }, + { "vh", ":DiffviewFileHistory %", desc = "File [h]istory" }, + { "vH", ":DiffviewFileHistory .", desc = "Directory [H]istory" }, + { "vc", ":DiffviewClose", desc = "[C]lose" }, +}) + +require("diffview").setup({ + keymaps = { + view = { + { "n", "]c", false }, + { "n", "[c", false }, + { "n", "]x", false }, + { "n", "[x", false }, + { "n", "]l", require("diffview.actions").next_entry, { desc = "Next entry" } }, + { "n", "[l", require("diffview.actions").prev_entry, { desc = "Previous entry" } }, + }, + file_panel = { + { "n", "j", false }, + { "n", "k", false }, + { "n", "k", require("diffview.actions").next_entry, { desc = "Next entry" } }, + { "n", "l", require("diffview.actions").prev_entry, { desc = "Previous entry" } }, + { "n", "", require("diffview.actions").select_entry, { desc = "Open diff" } }, + }, + file_history_panel = { + { "n", "j", false }, + { "n", "k", false }, + { "n", "k", require("diffview.actions").next_entry, { desc = "Next entry" } }, + { "n", "l", require("diffview.actions").prev_entry, { desc = "Previous entry" } }, + { "n", "", require("diffview.actions").select_entry, { desc = "Open entry" } }, + }, + }, +}) diff --git a/parts/features/dev/neovim/_fidget/default.nix b/parts/features/dev/neovim/_fidget/default.nix new file mode 100644 index 00000000..d7cbada2 --- /dev/null +++ b/parts/features/dev/neovim/_fidget/default.nix @@ -0,0 +1,12 @@ +# Sidebar notifications for LSP +{pkgs, ...}: { + programs.neovim.plugins = with pkgs.vimPlugins; [ + { + plugin = fidget-nvim; + config = '' + require('fidget').setup() + ''; + type = "lua"; + } + ]; +} diff --git a/parts/features/dev/neovim/_folds/default.nix b/parts/features/dev/neovim/_folds/default.nix new file mode 100644 index 00000000..4a6a0065 --- /dev/null +++ b/parts/features/dev/neovim/_folds/default.nix @@ -0,0 +1,9 @@ +{pkgs, ...}: { + programs.neovim.plugins = [ + { + plugin = pkgs.vimPlugins.nvim-ufo; + config = builtins.readFile ./ufo.lua; + type = "lua"; + } + ]; +} diff --git a/parts/features/dev/neovim/_folds/ufo.lua b/parts/features/dev/neovim/_folds/ufo.lua new file mode 100644 index 00000000..20ec576a --- /dev/null +++ b/parts/features/dev/neovim/_folds/ufo.lua @@ -0,0 +1,9 @@ +vim.o.foldcolumn = '0' -- '1' makes it visible, but is kinda ugly and interferes with stuff like lspsaga +vim.o.foldlevel = 99 -- Using ufo provider need a large value, feel free to decrease the value +vim.o.foldlevelstart = 99 +vim.o.foldenable = true + +vim.keymap.set('n', 'zR', require('ufo').openAllFolds) +vim.keymap.set('n', 'zM', require('ufo').closeAllFolds) + +require('ufo').setup() diff --git a/parts/features/dev/neovim/_fugitive/default.nix b/parts/features/dev/neovim/_fugitive/default.nix new file mode 100644 index 00000000..3ebf685a --- /dev/null +++ b/parts/features/dev/neovim/_fugitive/default.nix @@ -0,0 +1,22 @@ +{pkgs, ...}: { + programs.neovim.plugins = with pkgs.vimPlugins; [ + { + plugin = fugitive; + config = builtins.readFile ./fugitive.lua; + type = "lua"; + } + { + plugin = vim-fubitive; + config = '' + let g:fubitive_domain_pattern = 'bitbucket-ssh\.plansee-group\.com' + ''; + } + { + plugin = fugitive-gitlab-vim; + config = '' + let g:fugitive_gitlab_domains = ['https://git.datalabhell.at', 'https://gitlab.k8s.plansee-group.com'] + ''; + } + vim-rhubarb # github bindings for fugitive + ]; +} diff --git a/parts/features/dev/neovim/_fugitive/fugitive.lua b/parts/features/dev/neovim/_fugitive/fugitive.lua new file mode 100644 index 00000000..53bde8d8 --- /dev/null +++ b/parts/features/dev/neovim/_fugitive/fugitive.lua @@ -0,0 +1,63 @@ +local wk = require("which-key") +wk.add( + { + { "g", group = "[G]it", silent = false }, + { "gB", ":Git blame", desc = "[B]lame", silent = false }, + { "gb", ":Git checkout -b", desc = "New [b]ranch", silent = false }, + { "gc", ":Git checkout", desc = "[C]heckout branch/tag", silent = false }, + { "gd", group = "[D]iff", silent = false }, + { "gdd", ":Gdiff", desc = "[D]iff", silent = false }, + { "gds", ":Gdiffsplit!", desc = "[S]plit diff", silent = false }, + { "ge", ":Gedit", desc = "Ch[e]ckout any branch/sha/file", silent = false }, + { "gh", ":0Gclog", desc = "[H]istory for entire file", silent = false }, + { "gl", ":Gclog", desc = "[L]og", silent = false }, + { "gm", ":GMove", desc = "[M]ove", silent = false }, + { "gp", group = "[P]ush/pull", silent = false }, + { + "gpf", + function() + vim.cmd( + 'TermExec cmd="git push --force-with-lease" | call fugitive#ReloadStatus()') + end, + desc = "[F]orce push with lease", + silent = false + }, + { "gpl", function() vim.cmd('TermExec cmd="git pull" | call fugitive#ReloadStatus()') end, desc = "[P]ull", silent = false }, + { + "gpn", + function() + vim.cmd( + 'TermExec cmd="git push -u origin HEAD" | call fugitive#ReloadStatus()') + end, + desc = "Push [n]ew branch", + silent = false + }, + { "gps", function() vim.cmd('TermExec cmd="git push" | call fugitive#ReloadStatus()') end, desc = "Pu[s]h", silent = false }, + { "gr", ":Gread", desc = "[R]evert to working tree/index copy of file", silent = false }, + { "gw", ":Gwrite", desc = "[W]rite to index", silent = false }, + } +) + +wk.add( + { + { "g", group = "[G]it", mode = "v" }, + { "gh", ":Gclog", desc = "[H]istory for selection", mode = "v" }, + } +) + + +-- Fugitive only mappings +vim.api.nvim_create_autocmd("BufReadPost", { + pattern = "*", + callback = function() + local bufnr = vim.api.nvim_get_current_buf() + local bufname = vim.api.nvim_buf_get_name(bufnr) + + if string.match(bufname, "^fugitive://") then + vim.api.nvim_buf_set_keymap(bufnr, "n", "gj", ":diffget //2", + { noremap = true, silent = false }) + vim.api.nvim_buf_set_keymap(bufnr, "n", "g;", ":diffget //3", + { noremap = true, silent = false }) + end + end, +}) diff --git a/parts/features/dev/neovim/_git-conflict-nvim/default.nix b/parts/features/dev/neovim/_git-conflict-nvim/default.nix new file mode 100644 index 00000000..41e38cdc --- /dev/null +++ b/parts/features/dev/neovim/_git-conflict-nvim/default.nix @@ -0,0 +1,11 @@ +{pkgs, ...}: { + programs.neovim.plugins = with pkgs.vimPlugins; [ + { + plugin = git-conflict-nvim; + config = '' + require('git-conflict').setup({}) + ''; + type = "lua"; + } + ]; +} diff --git a/parts/features/dev/neovim/_gitsigns/default.nix b/parts/features/dev/neovim/_gitsigns/default.nix new file mode 100644 index 00000000..cfc634dd --- /dev/null +++ b/parts/features/dev/neovim/_gitsigns/default.nix @@ -0,0 +1,9 @@ +{pkgs, ...}: { + programs.neovim.plugins = with pkgs.vimPlugins; [ + { + plugin = gitsigns-nvim; + config = builtins.readFile ./gitsigns.lua; + type = "lua"; + } + ]; +} diff --git a/parts/features/dev/neovim/_gitsigns/gitsigns.lua b/parts/features/dev/neovim/_gitsigns/gitsigns.lua new file mode 100644 index 00000000..11bc1a51 --- /dev/null +++ b/parts/features/dev/neovim/_gitsigns/gitsigns.lua @@ -0,0 +1,52 @@ +require('gitsigns').setup { + on_attach = function(bufnr) + local gitsigns = require('gitsigns') + local wk = require("which-key") + + -- Navigation + vim.keymap.set('n', ']c', function() + if vim.wo.diff then + vim.cmd.normal({ ']c', bang = true }) + else + gitsigns.nav_hunk('next') + end + end, { buffer = bufnr, desc = "Next hunk" }) + + vim.keymap.set('n', '[c', function() + if vim.wo.diff then + vim.cmd.normal({ '[c', bang = true }) + else + gitsigns.nav_hunk('prev') + end + end, { buffer = bufnr, desc = "Previous hunk" }) + + -- Text object + vim.keymap.set({ 'o', 'x' }, 'ih', gitsigns.select_hunk, { buffer = bufnr, desc = "Select hunk" }) + + -- Which-key mappings for gitsigns + wk.add({ + { "h", group = "[H]unk", buffer = bufnr }, + { "hs", gitsigns.stage_hunk, desc = "[S]tage hunk", buffer = bufnr }, + { "hr", gitsigns.reset_hunk, desc = "[R]eset hunk", buffer = bufnr }, + { "hS", gitsigns.stage_buffer, desc = "[S]tage buffer", buffer = bufnr }, + { "hR", gitsigns.reset_buffer, desc = "[R]eset buffer", buffer = bufnr }, + { "hp", gitsigns.preview_hunk, desc = "[P]review hunk", buffer = bufnr }, + { "hi", gitsigns.preview_hunk_inline, desc = "Preview hunk [i]nline", buffer = bufnr }, + { "hb", function() gitsigns.blame_line({ full = true }) end, desc = "[B]lame line", buffer = bufnr }, + { "hd", gitsigns.diffthis, desc = "[D]iff this", buffer = bufnr }, + { "hD", function() gitsigns.diffthis('~') end, desc = "[D]iff this ~", buffer = bufnr }, + { "hQ", function() gitsigns.setqflist('all') end, desc = "Set [Q]uickfix list (all)", buffer = bufnr }, + { "hq", gitsigns.setqflist, desc = "Set [q]uickfix list", buffer = bufnr }, + { "ht", group = "[T]oggle", buffer = bufnr }, + { "htb", gitsigns.toggle_current_line_blame, desc = "Toggle [b]lame", buffer = bufnr }, + { "htw", gitsigns.toggle_word_diff, desc = "Toggle [w]ord diff", buffer = bufnr }, + }) + + -- Visual mode mappings + wk.add({ + { "h", group = "[H]unk", mode = "v", buffer = bufnr }, + { "hs", function() gitsigns.stage_hunk({ vim.fn.line('.'), vim.fn.line('v') }) end, desc = "[S]tage hunk", mode = "v", buffer = bufnr }, + { "hr", function() gitsigns.reset_hunk({ vim.fn.line('.'), vim.fn.line('v') }) end, desc = "[R]eset hunk", mode = "v", buffer = bufnr }, + }) + end +} diff --git a/parts/features/dev/neovim/_gruvbox/default.nix b/parts/features/dev/neovim/_gruvbox/default.nix new file mode 100644 index 00000000..fa88fa86 --- /dev/null +++ b/parts/features/dev/neovim/_gruvbox/default.nix @@ -0,0 +1,18 @@ +{pkgs, ...}: { + programs.neovim = { + extraConfig = '' + " Colorscheme + autocmd vimenter * ++nested colorscheme gruvbox + nnoremap [oh :call gruvbox#hls_show() + nnoremap ]oh :call gruvbox#hls_hide() + nnoremap coh :call gruvbox#hls_toggle() + + nnoremap * :let @/ = "":call gruvbox#hls_show()* + nnoremap / :let @/ = "":call gruvbox#hls_show()/ + nnoremap ? :let @/ = "":call gruvbox#hls_show()? + ''; + plugins = with pkgs.vimPlugins; [ + gruvbox + ]; + }; +} diff --git a/parts/features/dev/neovim/_jdtls/default.nix b/parts/features/dev/neovim/_jdtls/default.nix new file mode 100644 index 00000000..8bdd68cb --- /dev/null +++ b/parts/features/dev/neovim/_jdtls/default.nix @@ -0,0 +1,11 @@ +{pkgs, ...}: { + programs.neovim.plugins = [ + { + plugin = pkgs.vimPlugins.nvim-jdtls; + runtime = { + "ftplugin/java.lua".source = ./jdtls.lua; + }; + type = "lua"; + } + ]; +} diff --git a/parts/features/dev/neovim/_jdtls/jdtls.lua b/parts/features/dev/neovim/_jdtls/jdtls.lua new file mode 100644 index 00000000..17defc4a --- /dev/null +++ b/parts/features/dev/neovim/_jdtls/jdtls.lua @@ -0,0 +1,99 @@ +local root_dir = require('jdtls.setup').find_root({ '.git' }); +local project_name = vim.fn.fnamemodify(root_dir, ':p:h:t') +local data_dir = vim.fn.expand('$HOME/.cache/nvim/jdtls/workspaces/') .. project_name + +local jdtls_path = vim.fn.expand('$HOME/.local/share/nvim/mason/packages/jdtls') +local jdebug_path = vim.fn.expand('$HOME/.local/share/nvim/mason/packages/java-debug-adapter') +local jtest_path = vim.fn.expand('$HOME/.local/share/nvim/mason/packages/java-test') + + +local bundles = { + vim.fn.glob(jdebug_path .. "/extension/server/com.microsoft.java.debug.plugin-*.jar", true), +} +vim.list_extend(bundles, vim.split(vim.fn.glob(jtest_path .. "/extension/server/*.jar", true), "\n")) + +local extendedClientCapabilities = require('jdtls').extendedClientCapabilities +extendedClientCapabilities.resolveAdditionalTextEditsSupport = true + +-- Java-specific LSP keybindings (common ones are in shared_lsp_config via LspAttach) +local on_attach = function(_, bufnr) + local nmap = function(keys, func, desc) + if desc then + desc = 'LSP: ' .. desc + end + + vim.keymap.set('n', keys, func, { buffer = bufnr, desc = desc }) + end + + local wk = require("which-key") + wk.add({ + { "e", group = "[E]xtract" }, + { "t", group = "[T]est" }, + }) + nmap('o', require('jdtls').organize_imports, '[O]rganize Imports') + nmap('ev', require('jdtls').extract_variable, '[V]ariable') + nmap('ec', require('jdtls').extract_constant, '[C]onstant') + nmap('em', require('jdtls').extract_method, '[M]ethod') + + -- DAP specific keybindings, since not yet compatible wit neotest + nmap('tc', require('jdtls').test_class, 'Debug Test [C]lass') + nmap('tn', require('jdtls').test_nearest_method, 'Debug Test [N]earest') + + require('jdtls').setup_dap({ hotcodereplace = "auto" }) + require('jdtls.dap').setup_dap_main_class_configs() + require('jdtls.setup').add_commands() +end + + +-- See `:help vim.lsp.start_client` for an overview of the supported `config` options. +local config = { + -- The command that starts the language server + -- See: https://github.com/eclipse/eclipse.jdt.ls#running-from-the-command-line + cmd = { + 'java', -- or '/path/to/java17_or_newer/bin/java' + -- depends on if `java` is in your $PATH env variable and if it points to the right version. + + '-Declipse.application=org.eclipse.jdt.ls.core.id1', + '-Dosgi.bundles.defaultStartLevel=4', + '-Declipse.product=org.eclipse.jdt.ls.core.product', + '-Dlog.protocol=true', + '-Dlog.level=ALL', + '-Xmx1g', + '-javaagent:' .. jdtls_path .. '/lombok.jar', + '--add-modules=ALL-SYSTEM', + '--add-opens', 'java.base/java.util=ALL-UNNAMED', + '--add-opens', 'java.base/java.lang=ALL-UNNAMED', + '-jar', vim.fn.glob(jdtls_path .. '/plugins/org.eclipse.equinox.launcher_*.jar'), + '-configuration', jdtls_path .. '/config_linux', + '-data', data_dir, + }, + + on_attach = on_attach, + + -- This is the default if not provided, you can remove it. Or adjust as needed. + -- One dedicated LSP server & client will be started per unique root_dir + root_dir = root_dir, + + -- Here you can configure eclipse.jdt.ls specific settings + -- See https://github.com/eclipse/eclipse.jdt.ls/wiki/Running-the-JAVA-LS-server-from-the-command-line#initialize-request + -- for a list of options + settings = { + java = { + } + }, + + -- Language server `initializationOptions` + -- You need to extend the `bundles` with paths to jar files + -- if you want to use additional eclipse.jdt.ls plugins. + -- + -- See https://github.com/mfussenegger/nvim-jdtls#java-debug-installation + -- + -- If you don't plan on using the debugger or other eclipse.jdt.ls plugins you can remove this + init_options = { + bundles = bundles, + extendedClientCapabilities = extendedClientCapabilities, + }, +} +-- This starts a new client & server, +-- or attaches to an existing client & server depending on the `root_dir`. +require('jdtls').start_or_attach(config) diff --git a/parts/features/dev/neovim/_jj/default.nix b/parts/features/dev/neovim/_jj/default.nix new file mode 100644 index 00000000..54092451 --- /dev/null +++ b/parts/features/dev/neovim/_jj/default.nix @@ -0,0 +1,45 @@ +{pkgs, ...}: let + jj-nvim = pkgs.vimUtils.buildVimPlugin { + name = "jj-nvim"; + src = pkgs.fetchFromGitHub { + owner = "NicolasGB"; + repo = "jj.nvim"; + rev = "v0.4.0"; + sha256 = "sha256-BY4wDMMQUdu6DHfMqP4lpHQdHhS+yL6+CUiKQJFJY2Q="; + }; + }; +in { + programs.neovim.plugins = with pkgs.vimPlugins; [ + { + plugin = toggleterm-nvim; + config = builtins.readFile ./jj.lua; + type = "lua"; + } + { + plugin = jj-nvim; + config = '' + require("jj").setup({ + diff = { + backend = "diffview", + }, + }) + + local wk = require("which-key") + local cmd = require("jj.cmd") + wk.add({ + { "j", group = "[J]ujutsu" }, + { "jl", cmd.log, desc = "[L]og" }, + { "js", cmd.status, desc = "[S]tatus" }, + { "jc", cmd.commit, desc = "[C]ommit" }, + { "jd", cmd.describe, desc = "[D]escribe" }, + { "jn", function() cmd.new({ show_log = true }) end, desc = "[N]ew change" }, + { "ju", cmd.undo, desc = "[U]ndo" }, + -- Bypass jj.nvim's push handler to use our custom jj push alias + { "jp", function() require("jj.ui.terminal").run("jj push") end, desc = "[P]ush" }, + { "jr", cmd.redo, desc = "[R]edo" }, + }) + ''; + type = "lua"; + } + ]; +} diff --git a/parts/features/dev/neovim/_jj/jj.lua b/parts/features/dev/neovim/_jj/jj.lua new file mode 100644 index 00000000..ca029a06 --- /dev/null +++ b/parts/features/dev/neovim/_jj/jj.lua @@ -0,0 +1,21 @@ +-- F3 keybinding to toggle jjui in a floating terminal +local Terminal = require('toggleterm.terminal').Terminal +local jjui_term = Terminal:new({ + cmd = "jjui", + direction = "float", + hidden = true, + on_open = function(term) + vim.cmd("startinsert!") + -- Allow ESC to work inside jjui instead of exiting terminal mode + vim.keymap.set('t', '', '', { buffer = term.bufnr, noremap = true }) + end, +}) + +vim.keymap.set('n', '', function() + jjui_term:toggle() +end, { desc = "Toggle jjui in floating terminal" }) + +vim.keymap.set('t', '', function() + jjui_term:toggle() +end, { desc = "Toggle jjui in floating terminal" }) + diff --git a/parts/features/dev/neovim/_lspsaga/default.nix b/parts/features/dev/neovim/_lspsaga/default.nix new file mode 100644 index 00000000..10d4c4bb --- /dev/null +++ b/parts/features/dev/neovim/_lspsaga/default.nix @@ -0,0 +1,16 @@ +{pkgs, ...}: { + programs.neovim.plugins = with pkgs.vimPlugins; [ + { + plugin = lspsaga-nvim; + config = '' + require('lspsaga').setup({ + lightbulb = { + enable = true, + sign = false, -- disable the sign in signcolumn, which creates bouncy shit + }, + }) + ''; + type = "lua"; + } + ]; +} diff --git a/parts/features/dev/neovim/_lualine/default.nix b/parts/features/dev/neovim/_lualine/default.nix new file mode 100644 index 00000000..96239466 --- /dev/null +++ b/parts/features/dev/neovim/_lualine/default.nix @@ -0,0 +1,58 @@ +# Status line for neovim +{pkgs, ...}: { + programs.neovim.plugins = with pkgs.vimPlugins; [ + { + plugin = lualine-nvim; + config = '' + require('lualine').setup({ + options = { + theme = 'gruvbox', + }, + extensions = { + 'fugitive', + 'mason', + 'nvim-tree', + 'oil', + 'overseer', + 'quickfix', + 'toggleterm', + 'trouble', + }, + sections = { + lualine_a = {'mode'}, + lualine_b = {'branch', 'diff', 'fugitive_branch', 'diagnostics'}, + lualine_c = {'filename'}, + lualine_x = { + { + require("noice").api.status.message.get_hl, + cond = require("noice").api.status.message.has, + }, + { + require("noice").api.status.command.get, + cond = require("noice").api.status.command.has, + color = { fg = "#ff9e64" }, + }, + { + require("noice").api.status.mode.get, + cond = require("noice").api.status.mode.has, + color = { fg = "#ff9e64" }, + }, + { + require("noice").api.status.search.get, + cond = require("noice").api.status.search.has, + color = { fg = "#ff9e64" }, + }, + { "overseer", colored = false }, + 'encoding', + 'fileformat', + 'filetype' + }, + lualine_y = {'progress'}, + lualine_z = {'location'} + }, + }) + ''; + type = "lua"; + } + ]; +} diff --git a/parts/features/dev/neovim/_mason-lsp/default.nix b/parts/features/dev/neovim/_mason-lsp/default.nix new file mode 100644 index 00000000..e5272123 --- /dev/null +++ b/parts/features/dev/neovim/_mason-lsp/default.nix @@ -0,0 +1,84 @@ +{ + isImpermanent, + lib, + pkgs, + ... +}: { + home.persistence."/persist" = lib.mkIf isImpermanent { + directories = [ + ".local/state/logrotate" # Logrotate state for nvim LSP logs + ]; + }; + + programs.neovim = { + extraLuaConfig = '' + -- LSP diagnostics: show inline virtual text + vim.diagnostic.config({ + virtual_text = { + spacing = 2, + prefix = "●", + }, + signs = true, -- keep signs in the gutter + underline = true, -- underline offending code + update_in_insert = false, -- reduce noise while typing + severity_sort = true, -- sort diagnostics by severity + float = { + border = "rounded", + source = "if_many", + }, + }) + ''; + + plugins = with pkgs.vimPlugins; [ + { + plugin = mason-nvim; # Automatically install LSP servers + config = builtins.readFile ./mason.lua; + runtime = { + "lua/shared_lsp_config.lua".source = ./shared_lsp_config.lua; + }; + type = "lua"; + } + { + plugin = mason-lspconfig-nvim; # Automatically install LSP servers + } + { + plugin = mason-nvim-dap-nvim; # Automatically configure DAP adapters + } + ]; + }; + + # User-level logrotate for nvim LSP logs (hm doesn't support that yet) + home.packages = [pkgs.logrotate]; + systemd.user.services.logrotate-nvim = { + Unit = { + Description = "Rotate nvim LSP log"; + }; + Service = { + Type = "oneshot"; + ExecStartPre = "${pkgs.coreutils}/bin/mkdir --parents %h/.local/state/logrotate"; + ExecStart = "${pkgs.logrotate}/bin/logrotate --state=%h/.local/state/logrotate/nvim.state %h/.config/logrotate/nvim.conf"; + }; + }; + systemd.user.timers.logrotate-nvim = { + Unit = { + Description = "Timer for nvim LSP log rotation"; + }; + Timer = { + OnCalendar = "hourly"; + Persistent = true; + }; + Install = { + WantedBy = ["timers.target"]; + }; + }; + home.file.".config/logrotate/nvim.conf".text = '' + /home/farlion/.local/state/nvim/lsp.log { + size 1M + rotate 5 + compress + copytruncate + missingok + notifempty + } + ''; +} diff --git a/parts/features/dev/neovim/_mason-lsp/mason.lua b/parts/features/dev/neovim/_mason-lsp/mason.lua new file mode 100644 index 00000000..52cd1a29 --- /dev/null +++ b/parts/features/dev/neovim/_mason-lsp/mason.lua @@ -0,0 +1,200 @@ +-- General Diagnostic keymaps +local wk = require("which-key") +local lspsaga = require("lspsaga") +wk.add( + { + { "d", vim.diagnostic.open_float, desc = "Open Floating [D]iagnostics" }, + { "l", vim.diagnostic.setloclist, desc = "Open Diagnostics in [L]ocation List" }, + { "q", vim.diagnostic.setqflist, desc = "Open Diagnostics in [Q]uickfix List" }, + { "[d", "Lspsaga diagnostic_jump_prev", desc = "Prev [D]iagnostic" }, + { "]d", "Lspsaga diagnostic_jump_next", desc = "Next [D]iagnostic" }, + } +) + +-- Autoformat, from https://github.com/nvim-lua/kickstart.nvim/blob/master/lua/kickstart/plugins/autoformat.lua +-- Switch for controlling whether you want autoformatting. +-- Use :AutoFormatToggle to toggle autoformatting on or off +local format_is_enabled = true +vim.api.nvim_create_user_command('AutoFormatToggle', function() + format_is_enabled = not format_is_enabled + print('Setting autoformatting to: ' .. tostring(format_is_enabled)) +end, {}) + +-- Create an augroup that is used for managing our formatting autocmds. +-- We need one augroup per client to make sure that multiple clients +-- can attach to the same buffer without interfering with each other. +local _augroups = {} +local get_augroup = function(client) + if not _augroups[client.id] then + local group_name = 'kickstart-lsp-format-' .. client.name + local id = vim.api.nvim_create_augroup(group_name, { clear = true }) + _augroups[client.id] = id + end + + return _augroups[client.id] +end + +-- Whenever an LSP attaches to a buffer, we will run this function. +-- +-- See `:help LspAttach` for more information about this autocmd event. +vim.api.nvim_create_autocmd('LspAttach', { + group = vim.api.nvim_create_augroup('kickstart-lsp-attach-format', { clear = true }), + -- This is where we attach the autoformatting for reasonable clients + callback = function(args) + local client_id = args.data.client_id + local client = vim.lsp.get_client_by_id(client_id) + local bufnr = args.buf + + -- Only attach to clients that support document formatting + if not client.server_capabilities.documentFormattingProvider then + return + end + + -- Tsserver usually works poorly. Sorry you work with bad languages + -- You can remove this line if you know what you're doing :) + if client.name == 'tsserver' then + return + end + + -- Create an autocmd that will run *before* we save the buffer. + -- Run the formatting command for the LSP that has just attached. + vim.api.nvim_create_autocmd('BufWritePre', { + group = get_augroup(client), + buffer = bufnr, + callback = function() + if not format_is_enabled then + return + end + + vim.lsp.buf.format { + async = false, + filter = function(c) + return c.id == client.id + end, + } + end, + }) + end, +}) + +-- Document workspace keymap +require('which-key').add( + { + { "w", group = "[W]orkspace" }, + { "w_", hidden = true }, + } +) + +-- Mason setup +require('mason').setup() +require("mason-nvim-dap").setup({ + ensure_installed = { + "codelldb", + "javadbg", + "javatest", + }, +}) + +-- Setup neovim lua configuration +require('neodev').setup() + +-- nvim-cmp supports additional completion capabilities +local capabilities = vim.lsp.protocol.make_client_capabilities() +capabilities = require('cmp_nvim_lsp').default_capabilities(capabilities) + +-- UFO code folding support +capabilities.textDocument.foldingRange = { + dynamicRegistration = false, + lineFoldingOnly = true +} + +-- Global LSP configuration applied to all servers +vim.lsp.config('*', { + capabilities = capabilities, +}) + +-- Server-specific configurations using vim.lsp.config (Neovim 0.11+) +vim.lsp.config('bashls', {}) +vim.lsp.config('jsonls', {}) +vim.lsp.config('julials', {}) +vim.lsp.config('ruff', {}) +vim.lsp.config('terraformls', {}) +vim.lsp.config('tflint', {}) +vim.lsp.config('ts_ls', {}) + +vim.lsp.config('lua_ls', { + settings = { + Lua = { + workspace = { checkThirdParty = false }, + telemetry = { enable = false }, + }, + }, +}) + +vim.lsp.config('rust_analyzer', { + settings = { + checkOnSave = { + command = 'clippy', + }, + }, +}) + +vim.lsp.config('yamlls', { + settings = { + schemas = { + kubernetes = "*.yaml", + ["http://json.schemastore.org/github-workflow"] = ".github/workflows/*", + ["http://json.schemastore.org/github-action"] = ".github/action.{yml,yaml}", + ["http://json.schemastore.org/ansible-stable-2.9"] = "roles/tasks/*.{yml,yaml}", + ["http://json.schemastore.org/prettierrc"] = ".prettierrc.{yml,yaml}", + ["http://json.schemastore.org/kustomization"] = "kustomization.{yml,yaml}", + ["http://json.schemastore.org/ansible-playbook"] = "*play*.{yml,yaml}", + ["http://json.schemastore.org/chart"] = "Chart.{yml,yaml}", + ["https://json.schemastore.org/dependabot-v2"] = ".github/dependabot.{yml,yaml}", + ["https://json.schemastore.org/gitlab-ci"] = "*gitlab-ci*.{yml,yaml}", + ["https://raw.githubusercontent.com/OAI/OpenAPI-Specification/main/schemas/v3.1/schema.json"] = "*api*.{yml,yaml}", + ["https://raw.githubusercontent.com/compose-spec/compose-spec/master/schema/compose-spec.json"] = + "*docker-compose*.{yml,yaml}", + ["https://raw.githubusercontent.com/argoproj/argo-workflows/master/api/jsonschema/schema.json"] = + "*flow*.{yml,yaml}", + }, + }, +}) + +-- Language Servers managed outside of Mason +vim.lsp.config('pyright', {}) + +vim.lsp.config('nixd', { + settings = { + nixd = { + formatting = { + command = { "alejandra" }, + }, + }, + }, +}) + +vim.lsp.config('harper_ls', { + filetypes = { "markdown", "text", "gitcommit" }, +}) + +-- Mason-lspconfig with automatic_enable (v2.x for Neovim 0.11+) +-- Automatically enables installed servers via vim.lsp.enable() +require('mason-lspconfig').setup { + ensure_installed = { + 'bashls', 'jsonls', 'lua_ls', 'julials', 'ruff', + 'rust_analyzer', 'terraformls', 'tflint', 'ts_ls', 'yamlls', + 'jdtls', -- Managed by jdtls-nvim plugin + }, + automatic_enable = { + exclude = { 'jdtls' }, -- jdtls-nvim manages its own client + }, +} + +-- Enable servers managed outside Mason +vim.lsp.enable('pyright') +vim.lsp.enable('nixd') +vim.lsp.enable('harper_ls') + +-- Load shared LSP keybindings (gd, gr, K, etc.) +require('shared_lsp_config') diff --git a/parts/features/dev/neovim/_mason-lsp/shared_lsp_config.lua b/parts/features/dev/neovim/_mason-lsp/shared_lsp_config.lua new file mode 100644 index 00000000..dd8b40ad --- /dev/null +++ b/parts/features/dev/neovim/_mason-lsp/shared_lsp_config.lua @@ -0,0 +1,41 @@ +-- LSP keybindings applied to all LSP clients via LspAttach autocmd +vim.api.nvim_create_autocmd('LspAttach', { + group = vim.api.nvim_create_augroup('lsp-keybindings', { clear = true }), + callback = function(args) + local bufnr = args.buf + + local nmap = function(keys, func, desc) + if desc then + desc = 'LSP: ' .. desc + end + vim.keymap.set('n', keys, func, { buffer = bufnr, desc = desc }) + end + + nmap('r', vim.lsp.buf.rename, '[R]e[n]ame') + nmap('a', vim.lsp.buf.code_action, '[C]ode [A]ction') + nmap('x', function() vim.api.nvim_command('LspRestart') end, '[R]estart LSP Client') + + nmap('gd', require('telescope.builtin').lsp_definitions, '[G]oto [D]efinition') + nmap('gD', vim.lsp.buf.declaration, '[G]oto [D]eclaration') + nmap('gR', require('telescope.builtin').lsp_references, '[G]oto [R]eferences') + nmap('gI', require('telescope.builtin').lsp_implementations, '[G]oto [I]mplementation') + nmap('gy', require('telescope.builtin').lsp_type_definitions, '[G]oto T[y]pe Definition') + nmap('s', require('telescope.builtin').lsp_document_symbols, '[D]ocument [S]ymbols') + nmap('w', require('telescope.builtin').lsp_dynamic_workspace_symbols, '[W]orkspace [S]ymbols') + + nmap('K', vim.lsp.buf.hover, 'Hover Documentation') + nmap('', vim.lsp.buf.signature_help, 'Signature Documentation') + + -- Workspace Fu + nmap('wa', vim.lsp.buf.add_workspace_folder, '[W]orkspace [A]dd Folder') + nmap('wr', vim.lsp.buf.remove_workspace_folder, '[W]orkspace [R]emove Folder') + nmap('wl', function() + print(vim.inspect(vim.lsp.buf.list_workspace_folders())) + end, '[W]orkspace [L]ist Folders') + + -- Create a command `:Format` local to the LSP buffer + vim.api.nvim_buf_create_user_command(bufnr, 'Format', function(_) + vim.lsp.buf.format() + end, { desc = 'Format current buffer with LSP' }) + end, +}) diff --git a/parts/features/dev/neovim/_mini-icons/default.nix b/parts/features/dev/neovim/_mini-icons/default.nix new file mode 100644 index 00000000..2452163c --- /dev/null +++ b/parts/features/dev/neovim/_mini-icons/default.nix @@ -0,0 +1,12 @@ +{pkgs, ...}: { + programs.neovim.plugins = [ + { + plugin = pkgs.vimPlugins.mini-icons; + config = '' + require('mini.icons').setup() + require('mini.icons').mock_nvim_web_devicons() + ''; + type = "lua"; + } + ]; +} diff --git a/parts/features/dev/neovim/_mini-operators/default.nix b/parts/features/dev/neovim/_mini-operators/default.nix new file mode 100644 index 00000000..cc5ddd91 --- /dev/null +++ b/parts/features/dev/neovim/_mini-operators/default.nix @@ -0,0 +1,31 @@ +{pkgs, ...}: let + mini-operators = pkgs.vimUtils.buildVimPlugin { + name = "mini-operators"; + src = pkgs.fetchFromGitHub { + owner = "echasnovski"; + repo = "mini.operators"; + rev = "2edc808e32fbf3e0d4759bdef26a7a143a19f509"; + sha256 = "OFZyzhOTK+vUYejjdUMQoc905auZP/x6iqIZaS5KBVY="; + }; + }; +in { + programs.neovim.plugins = [ + { + plugin = mini-operators; + config = '' + -- Remove conflicting global default LSP keymaps + vim.keymap.del('n', 'grn') -- unset rename + vim.keymap.del({'n','v'}, 'gra') -- unset code_action + vim.keymap.del('n', 'grr') -- unset references + vim.keymap.del('n', 'gri') -- unset implementations + vim.keymap.del('n', 'grt') -- unset type_definition + require('mini.operators').setup({ + exchange = { + prefix = 'gX', -- default is 'gx' which overrides gx as open link from neovim/netRW + }, + }) + ''; + type = "lua"; + } + ]; +} diff --git a/parts/features/dev/neovim/_neotest/default.nix b/parts/features/dev/neovim/_neotest/default.nix new file mode 100644 index 00000000..75044bbc --- /dev/null +++ b/parts/features/dev/neovim/_neotest/default.nix @@ -0,0 +1,21 @@ +{pkgs, ...}: { + programs.neovim.plugins = with pkgs.vimPlugins; [ + { + plugin = FixCursorHold-nvim; + } + { + plugin = neotest; + config = builtins.readFile ./neotest.lua; + type = "lua"; + } + { + plugin = neotest-java; + } + { + plugin = neotest-rust; + } + { + plugin = nvim-nio; + } + ]; +} diff --git a/parts/features/dev/neovim/_neotest/neotest.lua b/parts/features/dev/neovim/_neotest/neotest.lua new file mode 100644 index 00000000..c7f56126 --- /dev/null +++ b/parts/features/dev/neovim/_neotest/neotest.lua @@ -0,0 +1,31 @@ +require("neotest").setup({ + adapters = { + require("neotest-rust") { + args = { "--no-capture" }, + dap_adapter = "codelldb", + }, + }, + consumers = { + overseer = require("neotest.consumers.overseer"), + }, +}) + +local wk = require("which-key") +wk.add( + { + { "t", group = "neo[T]est" }, + { "ta", require("neotest").run.attach, desc = "[A]ttach to nearest" }, + { "td", function() require("neotest").run.run({ strategy = "dap" }) end, desc = "[D]ebug nearest" }, + { "tf", function() require("neotest").run.run(vim.fn.expand("%")) end, desc = "[F]ile" }, + { "tn", require("neotest").run.run, desc = "[N]earest" }, + { + "to", + function() + require("neotest").output_panel.toggle() + vim.cmd("wincmd p") + end, + desc = "Toggle [O]utput Panel" + }, + { "ts", function() require("neotest").summary.toggle({ enter = true }) end, desc = "Toggle [S]ummary" }, + } +) diff --git a/parts/features/dev/neovim/_noice/default.nix b/parts/features/dev/neovim/_noice/default.nix new file mode 100644 index 00000000..b95a6f9c --- /dev/null +++ b/parts/features/dev/neovim/_noice/default.nix @@ -0,0 +1,9 @@ +{pkgs, ...}: { + programs.neovim.plugins = with pkgs.vimPlugins; [ + { + plugin = noice-nvim; + config = builtins.readFile ./noice.lua; + type = "lua"; + } + ]; +} diff --git a/parts/features/dev/neovim/_noice/noice.lua b/parts/features/dev/neovim/_noice/noice.lua new file mode 100644 index 00000000..d657e100 --- /dev/null +++ b/parts/features/dev/neovim/_noice/noice.lua @@ -0,0 +1,28 @@ +require("noice").setup({ + lsp = { + -- override markdown rendering so that **cmp** and other plugins use **Treesitter** + override = { + ["vim.lsp.util.convert_input_to_markdown_lines"] = true, + ["vim.lsp.util.stylize_markdown"] = true, + ["cmp.entry.get_documentation"] = true, -- requires hrsh7th/nvim-cmp + }, + }, + -- you can enable a preset for easier configuration + presets = { + bottom_search = true, -- use a classic bottom cmdline for search + command_palette = true, -- position the cmdline and popupmenu together + long_message_to_split = true, -- long messages will be sent to a split + inc_rename = false, -- enables an input dialog for inc-rename.nvim + lsp_doc_border = false, -- add a border to hover docs and signature help + }, +}) + +local wk = require("which-key") +wk.add( + { + { "n", group = "[N]oice" }, + { "nd", "NoiceDismiss", desc = "[D]ismiss Notifications" }, + { "nl", "NoiceLast", desc = "[L]ast Notifiation" }, + { "nn", "Noice", desc = "Show all [N]otifications" }, + } +) diff --git a/parts/features/dev/neovim/_notify/default.nix b/parts/features/dev/neovim/_notify/default.nix new file mode 100644 index 00000000..2276cd57 --- /dev/null +++ b/parts/features/dev/neovim/_notify/default.nix @@ -0,0 +1,21 @@ +{pkgs, ...}: { + programs.neovim = { + extraLuaConfig = '' + vim.notify = require("notify") + ''; + plugins = with pkgs.vimPlugins; [ + { + plugin = nvim-notify; + config = '' + require('notify').setup() + + local wk = require("which-key") + wk.add({ + { "nh", "Telescope notify", desc = "Notification [H]istory" }, + }) + ''; + type = "lua"; + } + ]; + }; +} diff --git a/parts/features/dev/neovim/_nui/default.nix b/parts/features/dev/neovim/_nui/default.nix new file mode 100644 index 00000000..2980c541 --- /dev/null +++ b/parts/features/dev/neovim/_nui/default.nix @@ -0,0 +1,10 @@ +{pkgs, ...}: { + programs.neovim.plugins = with pkgs.vimPlugins; [ + { + plugin = nui-nvim; + config = '' + ''; + type = "lua"; + } + ]; +} diff --git a/parts/features/dev/neovim/_nvim-tree-lua/default.nix b/parts/features/dev/neovim/_nvim-tree-lua/default.nix new file mode 100644 index 00000000..4e9decbb --- /dev/null +++ b/parts/features/dev/neovim/_nvim-tree-lua/default.nix @@ -0,0 +1,9 @@ +{pkgs, ...}: { + programs.neovim.plugins = with pkgs.vimPlugins; [ + { + plugin = nvim-tree-lua; + config = builtins.readFile ./nvim-tree.lua; + type = "lua"; + } + ]; +} diff --git a/parts/features/dev/neovim/_nvim-tree-lua/nvim-tree.lua b/parts/features/dev/neovim/_nvim-tree-lua/nvim-tree.lua new file mode 100644 index 00000000..f8e7bedf --- /dev/null +++ b/parts/features/dev/neovim/_nvim-tree-lua/nvim-tree.lua @@ -0,0 +1,59 @@ +-- Ensure mini.icons mock is active before configuring nvim-tree +local ok_icons, Icons = pcall(require, 'mini.icons') +if ok_icons and Icons and Icons.mock_nvim_web_devicons then + -- Replace nvim-web-devicons so nvim-tree and others use mini.icons + pcall(Icons.mock_nvim_web_devicons) +end + +local function my_on_attach(bufnr) + local api = require "nvim-tree.api" + local function opts(desc) + return { desc = "nvim-tree: " .. desc, buffer = bufnr, noremap = true, silent = true, nowait = true } + end + -- default mappings + api.config.mappings.default_on_attach(bufnr) + -- custom mappings + vim.keymap.set('n', '', api.node.open.horizontal, opts('Open: Horizontal Split')) + vim.keymap.set('n', '?', api.tree.toggle_help, opts('Help')) +end +require("nvim-tree").setup({ + on_attach = my_on_attach, + disable_netrw = false, -- keeping netrw for :GBrowse from fugitive to work + hijack_netrw = true, -- once no longer needed, check :he nvim-tree-netrw + -- Ensure devicons are enabled so the mini.icons mock is used + renderer = { + icons = { + -- Use simple ASCII for folder glyphs to avoid NF v2/v3 codepoint mismatches + glyphs = { + folder = { + arrow_closed = "", + arrow_open = "", + default = "", + open = "", + empty = "", + empty_open = "", + symlink = "", + symlink_open = "", + }, + }, + }, + }, + -- Dynamic width + view = { + width = { + min = 30, + max = -1, + }, + }, +}) +local wk = require("which-key") +wk.add( + { + { "f", group = "[F]iles(NvimTree)" }, + { "fc", "NvimTreeCollapse", desc = "[C]ollapse NVimTree Node Recursively" }, + { "ff", "NvimTreeFindFile", desc = "Move the cursor in the tree for the current buffer, opening [f]olders if needed." }, + { "ft", "NvimTreeToggle", desc = "[T]oggle NvimTree" }, + { "", "NvimTreeToggle", desc = "Toggle NvimTree", mode = { "n", "v" } }, + { "", "NvimTreeToggle", desc = "Toggle NvimTree", mode = { "i" } }, + } +) diff --git a/parts/features/dev/neovim/_obsidian-nvim/default.nix b/parts/features/dev/neovim/_obsidian-nvim/default.nix new file mode 100644 index 00000000..20bd3deb --- /dev/null +++ b/parts/features/dev/neovim/_obsidian-nvim/default.nix @@ -0,0 +1,31 @@ +{pkgs, ...}: { + programs.neovim.plugins = with pkgs.vimPlugins; [ + { + plugin = obsidian-nvim; + config = '' + require("obsidian").setup({ + follow_img_func = function(img) + vim.fn.jobstart({"xdg-open", url}) + end, + legacy_commands = false, + -- Clashes with render-markdown.nvim + ui = { + enable = false, + }, + workspaces = { + { + name = "main", + path = "~/Obsidian", + } + }, + }) + + local wk = require("which-key") + wk.add({ + { "o", "Obsidian Search", desc = "Search [O]bsidian" }, + }) + ''; + type = "lua"; + } + ]; +} diff --git a/parts/features/dev/neovim/_oil/default.nix b/parts/features/dev/neovim/_oil/default.nix new file mode 100644 index 00000000..f87a54cd --- /dev/null +++ b/parts/features/dev/neovim/_oil/default.nix @@ -0,0 +1,27 @@ +{pkgs, ...}: { + programs.neovim.plugins = with pkgs.vimPlugins; [ + { + plugin = oil-nvim; + config = '' + require('oil').setup({ + default_file_explorer = false, + delete_to_trash = true, + skip_confirm_for_simple_edits = true, + view_options = { + show_hidden = true, + natural_order = true, + is_always_hidden = function(name, _) + return name == '..' or name == '.git' + end, + }, + win_options = { + wrap = true, + }, + }) + + vim.keymap.set("n", "-", "Oil", { desc = "Open parent directory" }) + ''; + type = "lua"; + } + ]; +} diff --git a/parts/features/dev/neovim/_otter/default.nix b/parts/features/dev/neovim/_otter/default.nix new file mode 100644 index 00000000..526b48ef --- /dev/null +++ b/parts/features/dev/neovim/_otter/default.nix @@ -0,0 +1,25 @@ +{pkgs, ...}: { + programs.neovim.plugins = with pkgs.vimPlugins; [ + { + plugin = otter-nvim; + config = '' + require('otter').setup({ + lsp = { + hover = { + -- Border style for LSP hover windows in embedded code + border = { "╭", "─", "╮", "│", "╯", "─", "╰", "│" }, + }, + }, + }) + + local wk = require("which-key") + wk.add({ + { "O", group = "[O]tter" }, + { "Oa", function() require("otter").activate() end, desc = "[A]ctivate Otter" }, + { "Od", function() require("otter").deactivate() end, desc = "[D]eactivate Otter" }, + }) + ''; + type = "lua"; + } + ]; +} diff --git a/parts/features/dev/neovim/_overseer/default.nix b/parts/features/dev/neovim/_overseer/default.nix new file mode 100644 index 00000000..9a613669 --- /dev/null +++ b/parts/features/dev/neovim/_overseer/default.nix @@ -0,0 +1,25 @@ +{pkgs, ...}: { + home.file = { + ".config/nvim/lua/overseer/template/user/gmailctl_apply.lua".source = ./templates/gmailctl_apply.lua; + + ".config/nvim/lua/overseer/template/user/java_gradle.lua".source = ./templates/java_gradle/init.lua; + + ".config/nvim/lua/overseer/template/user/java_maven.lua".source = ./templates/java_maven/init.lua; + + ".config/nvim/lua/overseer/template/user/nixos_rebuild_switch.lua".source = ./templates/nixos_rebuild_switch.lua; + ".config/nvim/lua/overseer/template/user/nixos_rebuild_boot.lua".source = ./templates/nixos_rebuild_boot.lua; + ".config/nvim/lua/overseer/template/user/nixos_update_secrets.lua".source = ./templates/nixos_update_secrets.lua; + ".config/nvim/lua/overseer/template/user/skaffold_dev.lua".source = ./templates/skaffold_dev.lua; + }; + + programs.neovim.plugins = [ + { + config = builtins.readFile ./overseer.lua; + plugin = pkgs.vimPlugins.overseer-nvim; + runtime = { + "lua/overseer_lib.lua".source = ./overseer_lib.lua; + }; + type = "lua"; + } + ]; +} diff --git a/parts/features/dev/neovim/_overseer/overseer.lua b/parts/features/dev/neovim/_overseer/overseer.lua new file mode 100644 index 00000000..d93da1e2 --- /dev/null +++ b/parts/features/dev/neovim/_overseer/overseer.lua @@ -0,0 +1,29 @@ +require('overseer').setup({ + templates = { + "builtin", + "user.gmailctl_apply", + "user.java_gradle", + "user.java_maven", + "user.nixos_rebuild_switch", + "user.nixos_rebuild_boot", + "user.nixos_update_secrets", + "user.skaffold_dev", + }, + component_aliases = { + default = { + "on_exit_set_status", + "on_complete_notify", + { "on_complete_dispose", require_view = { "SUCCESS", "FAILURE" } }, + { "open_output", direction = "dock", on_start = "always", focus = true }, + }, + }, +}) +local wk = require("which-key") +wk.add( + { + { "o", group = "[O]verseer" }, + { "or", "OverseerRun", desc = "[R]un" }, + { "ot", "OverseerToggle", desc = "[T]oggle List" }, + { "", "OverseerToggle", desc = "Toggle Overseer" }, + } +) diff --git a/parts/features/dev/neovim/_overseer/overseer_lib.lua b/parts/features/dev/neovim/_overseer/overseer_lib.lua new file mode 100644 index 00000000..d6ee95ed --- /dev/null +++ b/parts/features/dev/neovim/_overseer/overseer_lib.lua @@ -0,0 +1,25 @@ +local M = {} + +M.is_gradle_project = function(dir) + while dir ~= "" and dir ~= "/" do + if vim.fn.filereadable(dir .. "/gradlew") == 1 then + return true + end + dir = vim.fn.fnamemodify(dir, ":h") + end + + return false +end + +M.is_maven_project = function(dir) + while dir ~= "" and dir ~= "/" do + if vim.fn.filereadable(dir .. "/pom.xml") == 1 then + return true + end + dir = vim.fn.fnamemodify(dir, ":h") + end + + return false +end + +return M diff --git a/parts/features/dev/neovim/_overseer/templates/gmailctl_apply.lua b/parts/features/dev/neovim/_overseer/templates/gmailctl_apply.lua new file mode 100644 index 00000000..7cd2fa29 --- /dev/null +++ b/parts/features/dev/neovim/_overseer/templates/gmailctl_apply.lua @@ -0,0 +1,12 @@ +return { + name = "gmailctl apply", + builder = function() + return { + cmd = { "gmailctl" }, + args = { "apply" }, + } + end, + condition = { + filetype = { "jsonnet" }, + }, +} diff --git a/parts/features/dev/neovim/_overseer/templates/java_gradle/init.lua b/parts/features/dev/neovim/_overseer/templates/java_gradle/init.lua new file mode 100644 index 00000000..4fd493ab --- /dev/null +++ b/parts/features/dev/neovim/_overseer/templates/java_gradle/init.lua @@ -0,0 +1,57 @@ +local overseer_lib = require("overseer_lib") + +return { + generator = function(search) + if not overseer_lib.is_gradle_project(search.dir) then + return {} + end + + return { + { + name = "gradlew: build", + builder = function() + return { + cmd = { "./gradlew" }, + args = { "build" }, + } + end, + }, + { + name = "gradlew: test", + builder = function() + return { + cmd = { "./gradlew" }, + args = { "test" }, + } + end, + }, + { + name = "gradlew: clean", + builder = function() + return { + cmd = { "./gradlew" }, + args = { "clean" }, + } + end, + }, + { + name = "gradlew: bootRun", + builder = function() + return { + cmd = { "./gradlew" }, + args = { "bootRun" }, + } + end, + }, + { + name = "gradlew: spotlessApply", + builder = function() + return { + cmd = { "./gradlew" }, + args = { "spotlessApply" }, + } + end, + }, + } + end, +} diff --git a/parts/features/dev/neovim/_overseer/templates/java_maven/init.lua b/parts/features/dev/neovim/_overseer/templates/java_maven/init.lua new file mode 100644 index 00000000..32cb54ea --- /dev/null +++ b/parts/features/dev/neovim/_overseer/templates/java_maven/init.lua @@ -0,0 +1,30 @@ +local overseer_lib = require("overseer_lib") + +return { + generator = function(search) + if not overseer_lib.is_maven_project(search.dir) then + return {} + end + + return { + { + name = "mvn: test", + builder = function() + return { + cmd = { "mvn" }, + args = { "test" }, + } + end, + }, + { + name = "mvn: clean package", + builder = function() + return { + cmd = { "mvn" }, + args = { "clean", "package" }, + } + end, + }, + } + end, +} diff --git a/parts/features/dev/neovim/_overseer/templates/nixos_rebuild_boot.lua b/parts/features/dev/neovim/_overseer/templates/nixos_rebuild_boot.lua new file mode 100644 index 00000000..c2fd6aeb --- /dev/null +++ b/parts/features/dev/neovim/_overseer/templates/nixos_rebuild_boot.lua @@ -0,0 +1,12 @@ +return { + name = "nixos rebuild boot", + builder = function() + return { + cmd = { "nh" }, + args = { "os", "boot" }, + } + end, + condition = { + dir = "~/code/nixos-config", + }, +} diff --git a/parts/features/dev/neovim/_overseer/templates/nixos_rebuild_switch.lua b/parts/features/dev/neovim/_overseer/templates/nixos_rebuild_switch.lua new file mode 100644 index 00000000..6cf2ce7a --- /dev/null +++ b/parts/features/dev/neovim/_overseer/templates/nixos_rebuild_switch.lua @@ -0,0 +1,12 @@ +return { + name = "nixos rebuild switch", + builder = function() + return { + cmd = { "nh" }, + args = { "os", "switch" }, + } + end, + condition = { + dir = "~/code/nixos-config", + }, +} diff --git a/parts/features/dev/neovim/_overseer/templates/nixos_update_secrets.lua b/parts/features/dev/neovim/_overseer/templates/nixos_update_secrets.lua new file mode 100644 index 00000000..24267e5f --- /dev/null +++ b/parts/features/dev/neovim/_overseer/templates/nixos_update_secrets.lua @@ -0,0 +1,12 @@ +return { + name = "update secrets", + builder = function() + return { + cmd = { "nix" }, + args = { "flake", "lock", "--update-input", "secrets" }, + } + end, + condition = { + dir = "~/code/nixos-config", + }, +} diff --git a/parts/features/dev/neovim/_overseer/templates/skaffold_dev.lua b/parts/features/dev/neovim/_overseer/templates/skaffold_dev.lua new file mode 100644 index 00000000..7e67baff --- /dev/null +++ b/parts/features/dev/neovim/_overseer/templates/skaffold_dev.lua @@ -0,0 +1,12 @@ +return { + name = "skaffold dev", + builder = function() + return { + cmd = { "skaffold" }, + args = { "dev" }, + } + end, + condition = { + filetype = "yaml", + }, +} diff --git a/parts/features/dev/neovim/_plenary/default.nix b/parts/features/dev/neovim/_plenary/default.nix new file mode 100644 index 00000000..6111b769 --- /dev/null +++ b/parts/features/dev/neovim/_plenary/default.nix @@ -0,0 +1,10 @@ +{pkgs, ...}: { + programs.neovim.plugins = with pkgs.vimPlugins; [ + { + plugin = plenary-nvim; + config = '' + ''; + type = "lua"; + } + ]; +} diff --git a/parts/features/dev/neovim/_rainbow-csv/default.nix b/parts/features/dev/neovim/_rainbow-csv/default.nix new file mode 100644 index 00000000..ffcd8b21 --- /dev/null +++ b/parts/features/dev/neovim/_rainbow-csv/default.nix @@ -0,0 +1,21 @@ +{pkgs, ...}: let + rainbow-csv-nvim = pkgs.vimUtils.buildVimPlugin { + name = "rainbow-csv-nvim"; + src = pkgs.fetchFromGitHub { + owner = "cameron-wags"; + repo = "rainbow_csv.nvim"; + rev = "7f3fddfe813641035fac2cdf94c2ff69bb0bf0b9"; + sha256 = "sha256-/XHQd/+sqhVeeMAkcKNvFDKFuFecChrgp56op3KQAhs="; + }; + }; +in { + programs.neovim.plugins = [ + { + plugin = rainbow-csv-nvim; + config = '' + require('rainbow_csv').setup({}) + ''; + type = "lua"; + } + ]; +} diff --git a/parts/features/dev/neovim/_render-markdown/default.nix b/parts/features/dev/neovim/_render-markdown/default.nix new file mode 100644 index 00000000..2ef10c12 --- /dev/null +++ b/parts/features/dev/neovim/_render-markdown/default.nix @@ -0,0 +1,16 @@ +{pkgs, ...}: { + programs.neovim.extraPackages = with pkgs; [ + python3Packages.pylatexenc + ]; + programs.neovim.plugins = with pkgs.vimPlugins; [ + { + plugin = render-markdown-nvim; + config = '' + require('render-markdown').setup({ + file_types = {'markdown', 'Avante'}, + }) + ''; + type = "lua"; + } + ]; +} diff --git a/parts/features/dev/neovim/_telescope/default.nix b/parts/features/dev/neovim/_telescope/default.nix new file mode 100644 index 00000000..2b097939 --- /dev/null +++ b/parts/features/dev/neovim/_telescope/default.nix @@ -0,0 +1,87 @@ +{pkgs, ...}: { + programs.neovim.plugins = with pkgs.vimPlugins; [ + { + plugin = telescope-nvim; + config = '' + local builtin = require("telescope.builtin") + local utils = require("telescope.utils") + require("telescope").setup({ + defaults = { + mappings = { + i = { + [""] = require("telescope.actions").select_horizontal, + }, + n = { + [""] = require("telescope.actions").select_horizontal, + }, + }, + }, + pickers = { + find_files = { + hidden = true, + }, + }, + }) + require("telescope").load_extension("fzf") + local wk = require("which-key") + wk.add( + { + { "", group = "Find[ ](Telescope)" }, + { ".", function() builtin.find_files({ cwd = utils.buffer_dir() }) end, desc = "Files in CWD" }, + { "", "Telescope git_files", desc = "Version Controlled Files" }, + { "?", "Telescope keymaps", desc = "Vim Keymap Cheatsheet" }, + { "b", "Telescope buffers", desc = "[B]uffers" }, + { "c", "Telescope commands", desc = "[C]ommands" }, + { "d", "Telescope command_history", desc = "Comman[d] History" }, + { "e", "Telescope help_tags", desc = "H[e]lp Tags" }, + { "f", "Telescope find_files", desc = "All [F]iles" }, + { "g", "Telescope live_grep", desc = "[G]rep" }, + } + ) + ''; + type = "lua"; + } + { + plugin = telescope-fzf-native-nvim; + } + { + plugin = telescope-frecency-nvim; + config = '' + require("telescope").setup({ + extensions = { + frecency = { + show_scores = true, + auto_validate = false, -- manually gc with :FrecencyValidate + }, + }, + }) + require("telescope").load_extension("frecency") + local wk = require("which-key") + wk.add( + { + { "h", "Telescope frecency workspace=CWD", desc = "History (Frecency)" }, + } + ) + ''; + type = "lua"; + } + { + plugin = telescope-undo-nvim; + config = '' + require("telescope").setup({ + extensions = { + undo = {}; + }, + }) + require("telescope").load_extension("undo") + local wk = require("which-key") + wk.add( + { + { "u", "Telescope undo", desc = "[U]ndo Tree" }, + } + ) + ''; + type = "lua"; + } + ]; +} diff --git a/parts/features/dev/neovim/_toggleterm/default.nix b/parts/features/dev/neovim/_toggleterm/default.nix new file mode 100644 index 00000000..13616f02 --- /dev/null +++ b/parts/features/dev/neovim/_toggleterm/default.nix @@ -0,0 +1,14 @@ +{pkgs, ...}: { + programs.neovim.plugins = with pkgs.vimPlugins; [ + { + plugin = toggleterm-nvim; + config = '' + require("toggleterm").setup({ + open_mapping = [[]], + direction = 'float', + }) + ''; + type = "lua"; + } + ]; +} diff --git a/parts/features/dev/neovim/_treesitter/default.nix b/parts/features/dev/neovim/_treesitter/default.nix new file mode 100644 index 00000000..aa280bdc --- /dev/null +++ b/parts/features/dev/neovim/_treesitter/default.nix @@ -0,0 +1,36 @@ +{pkgs, ...}: { + programs.neovim.extraPackages = [ + pkgs.gcc + pkgs.tree-sitter + ]; + + programs.neovim.plugins = with pkgs.vimPlugins; [ + # TODO: This is Neovim-Native after 0.10, see https://github.com/nvim-treesitter/playground + { + plugin = playground; + config = '' + ''; + type = "lua"; + } + { + plugin = nvim-treesitter.withAllGrammars; + config = builtins.readFile ./treesitter.lua; + runtime = { + "after/queries/nix/injections.scm".source = ./queries/nix/injections.scm; + }; + type = "lua"; + } + { + plugin = nvim-treesitter-context; # ip, ap, etc... from treesitter! + config = '' + ''; + type = "lua"; + } + { + plugin = nvim-treesitter-textobjects; # ip, ap, etc... from treesitter! + config = '' + ''; + type = "lua"; + } + ]; +} diff --git a/parts/features/dev/neovim/_treesitter/queries/nix/injections.scm b/parts/features/dev/neovim/_treesitter/queries/nix/injections.scm new file mode 100644 index 00000000..6db97763 --- /dev/null +++ b/parts/features/dev/neovim/_treesitter/queries/nix/injections.scm @@ -0,0 +1,91 @@ +;extends +; extraLuaConfig -> Lua +(binding + attrpath: (attrpath + (identifier) @_path) + expression: [ + (string_expression + ((string_fragment) @injection.content + (#set! injection.language "lua"))) + (indented_string_expression + ((string_fragment) @injection.content + (#set! injection.language "lua"))) + ] + (#match? @_path "^extraLuaConfig$") + (#set! injection.combined)) + +; neovim.extraConfig -> Vim +(binding + ( + (attrpath + (identifier) @_outer + (identifier) @_inner + ) + ) + (attrset_expression + (binding_set + (binding + attrpath: (attrpath + (identifier) @_path) + expression: [ + (string_expression + ((string_fragment) @injection.content + (#set! injection.language "vim"))) + (indented_string_expression + ((string_fragment) @injection.content + (#set! injection.language "vim"))) + ] + (#match? @_path "^extraConfig$") + (#match? @_inner "^neovim$") + (#set! injection.combined) + ) + ) + ) +) + +; inline vim plugin configs of type Lua +(binding_set + binding: (binding + attrpath: (attrpath + (identifier) @_path) + expression: [ + (string_expression + ((string_fragment) @injection.content + (#set! injection.language "lua"))) + (indented_string_expression + ((string_fragment) @injection.content + (#set! injection.language "lua"))) + ] + ) + binding: (binding + attrpath: (attrpath + (identifier) @_typearg) + expression: [ + (string_expression + ((string_fragment) @_typeval + )) + (indented_string_expression + ((string_fragment) @_typeval + )) + ] + ) + (#match? @_typearg "^type$") + (#match? @_typeval "^lua$") + (#match? @_path "^config$") + (#set! injection.combined) +) + +; style -> CSS +(binding + attrpath: (attrpath + (identifier) @_path) + expression: [ + (string_expression + ((string_fragment) @injection.content + (#set! injection.language "css"))) + (indented_string_expression + ((string_fragment) @injection.content + (#set! injection.language "css"))) + ] + (#match? @_path "^style$") + (#set! injection.combined)) diff --git a/parts/features/dev/neovim/_treesitter/treesitter.lua b/parts/features/dev/neovim/_treesitter/treesitter.lua new file mode 100644 index 00000000..c1f7bbdd --- /dev/null +++ b/parts/features/dev/neovim/_treesitter/treesitter.lua @@ -0,0 +1,49 @@ +local function ts_disable_long_files(_, bufnr) + return vim.api.nvim_buf_line_count(bufnr) > 5000 +end + +local disabled_languages = { + "csv", -- In favor of rainbow-csv-nvim +} + +-- Defer Treesitter setup after first render to improve startup time of 'nvim {filename}' +vim.defer_fn(function() + require('nvim-treesitter.configs').setup { + auto_install = false, + highlight = { + enable = true, + disable = function(lang, bufnr) + return vim.tbl_contains(disabled_languages, lang) or ts_disable_long_files(lang, bufnr) + end, + }, + indent = { enable = true }, + incremental_selection = { + enable = true, + keymaps = { + init_selection = '', + node_incremental = '', + scope_incremental = false, -- Disable to avoid 'grc' conflict with mini.operators + node_decremental = '', + }, + }, + } + + -- Add additional intuitive keybindings for treesitter selection + -- These complement the bindings and work in visual mode + vim.keymap.set('x', '+', function() + require('nvim-treesitter.incremental_selection').node_incremental() + end, { desc = 'Treesitter: Expand selection' }) + + vim.keymap.set('x', '_', function() + require('nvim-treesitter.incremental_selection').node_decremental() + end, { desc = 'Treesitter: Shrink selection' }) + + -- Document the keybindings with which-key + local wk = require("which-key") + wk.add({ + { "", desc = "Treesitter: Init/Expand selection", mode = {"n", "x"} }, + { "", desc = "Treesitter: Shrink selection", mode = "x" }, + { "+", desc = "Treesitter: Expand selection", mode = "x" }, + { "_", desc = "Treesitter: Shrink selection", mode = "x" }, + }) +end, 0) diff --git a/parts/features/dev/neovim/_trouble/default.nix b/parts/features/dev/neovim/_trouble/default.nix new file mode 100644 index 00000000..04e163fe --- /dev/null +++ b/parts/features/dev/neovim/_trouble/default.nix @@ -0,0 +1,9 @@ +{pkgs, ...}: { + programs.neovim.plugins = with pkgs.vimPlugins; [ + { + plugin = trouble-nvim; + config = builtins.readFile ./trouble.lua; + type = "lua"; + } + ]; +} diff --git a/parts/features/dev/neovim/_trouble/trouble.lua b/parts/features/dev/neovim/_trouble/trouble.lua new file mode 100644 index 00000000..ab0f5545 --- /dev/null +++ b/parts/features/dev/neovim/_trouble/trouble.lua @@ -0,0 +1,19 @@ +local wk = require("which-key") +wk.add( + { + { "x", group = "Trouble" }, + { "xx", "Trouble diagnostics toggle focus=false", desc = "Diagnostics", mode = { "n", "v" } }, + { "xX", "Trouble diagnostics toggle filter.buf=0", desc = "Buffer Diagnostics", mode = { "n", "v" } }, + { "xl", "Trouble loclist toggle", desc = "[L]ocation List" }, + { "xq", "Trouble quickfix toggle", desc = "[Q]uickfix" }, + { "xs", "Trouble symbols toggle focus=false", desc = "[S]ymbols" }, + } +) +require("trouble").setup({ + action_keys = { -- key mappings for actions in the trouble list + open_split = { "" }, -- open buffer in new split + open_vsplit = { "" }, -- open buffer in new vsplit + previous = "l", -- previous item + next = "k" -- next item + }, +}) diff --git a/parts/features/dev/neovim/_undotree/default.nix b/parts/features/dev/neovim/_undotree/default.nix new file mode 100644 index 00000000..331724cf --- /dev/null +++ b/parts/features/dev/neovim/_undotree/default.nix @@ -0,0 +1,7 @@ +{pkgs, ...}: { + programs.neovim.plugins = with pkgs.vimPlugins; [ + { + plugin = undotree; + } + ]; +} diff --git a/parts/features/dev/neovim/_vim-be-good/default.nix b/parts/features/dev/neovim/_vim-be-good/default.nix new file mode 100644 index 00000000..a52a174a --- /dev/null +++ b/parts/features/dev/neovim/_vim-be-good/default.nix @@ -0,0 +1,7 @@ +{pkgs, ...}: { + programs.neovim.plugins = with pkgs.vimPlugins; [ + { + plugin = vim-be-good; + } + ]; +} diff --git a/parts/features/dev/neovim/_vim-terraform/default.nix b/parts/features/dev/neovim/_vim-terraform/default.nix new file mode 100644 index 00000000..3bfaedcf --- /dev/null +++ b/parts/features/dev/neovim/_vim-terraform/default.nix @@ -0,0 +1,7 @@ +{pkgs, ...}: { + programs.neovim.plugins = with pkgs.vimPlugins; [ + { + plugin = vim-terraform; + } + ]; +} diff --git a/parts/features/dev/neovim/_vim-visual-multi/default.nix b/parts/features/dev/neovim/_vim-visual-multi/default.nix new file mode 100644 index 00000000..4980a21b --- /dev/null +++ b/parts/features/dev/neovim/_vim-visual-multi/default.nix @@ -0,0 +1,13 @@ +{pkgs, ...}: { + programs.neovim.plugins = with pkgs.vimPlugins; [ + { + plugin = vim-visual-multi; + config = '' + let g:VM_maps = {} + let g:VM_maps['Motion ,'] = ',,' " Removes conflict with , as LSP Leader + let g:VM_maps['Goto Prev'] = '[[' " Removes conflict with vim-unimpaired + let g:VM_maps['Goto Next'] = ']]' " Removes conflict with vim-unimpaired + ''; + } + ]; +} diff --git a/parts/features/dev/neovim/_web-devicons/default.nix b/parts/features/dev/neovim/_web-devicons/default.nix new file mode 100644 index 00000000..5968cae5 --- /dev/null +++ b/parts/features/dev/neovim/_web-devicons/default.nix @@ -0,0 +1,15 @@ +{pkgs, ...}: { + programs.neovim.plugins = [ + { + # Intentionally put a minimal web-devicons plugin config BEFORE nvim-tree + # so that nvim-tree sees a ready devicons provider (which is then mocked + # by mini.icons). This avoids lazy-loading races in some plugin managers. + plugin = pkgs.vimPlugins.nvim-web-devicons; + config = '' + -- Minimal setup; will be overridden by mini.icons.mock_nvim_web_devicons() + require('nvim-web-devicons').setup({ color_icons = true, default = true }) + ''; + type = "lua"; + } + ]; +} diff --git a/parts/features/dev/neovim/_yank-file-line/default.nix b/parts/features/dev/neovim/_yank-file-line/default.nix new file mode 100644 index 00000000..30305e61 --- /dev/null +++ b/parts/features/dev/neovim/_yank-file-line/default.nix @@ -0,0 +1,3 @@ +{...}: { + programs.neovim.extraLuaConfig = builtins.readFile ./yank-file-line.lua; +} diff --git a/parts/features/dev/neovim/_yank-file-line/yank-file-line.lua b/parts/features/dev/neovim/_yank-file-line/yank-file-line.lua new file mode 100644 index 00000000..7dd2fb52 --- /dev/null +++ b/parts/features/dev/neovim/_yank-file-line/yank-file-line.lua @@ -0,0 +1,21 @@ +vim.keymap.set('v', 'y', function() + local file = vim.fn.expand('%:p') + local git_root = vim.fn.systemlist('git rev-parse --show-toplevel')[1] + local relative_path + if git_root and vim.fn.isdirectory(git_root) == 1 then + relative_path = file:sub(#git_root + 2) + else + relative_path = vim.fn.expand('%:.') + end + local start_line = vim.fn.line('v') + local end_line = vim.fn.line('.') + local line_part + if start_line == end_line then + line_part = tostring(start_line) + else + line_part = math.min(start_line, end_line) .. '-' .. math.max(start_line, end_line) + end + local result = relative_path .. ':' .. line_part + vim.fn.setreg('+', result) + vim.notify('Copied: ' .. result) +end, { desc = '[Y]ank file:line to clipboard' }) diff --git a/parts/features/dev/neovim/default.nix b/parts/features/dev/neovim/default.nix new file mode 100644 index 00000000..a92ecd9f --- /dev/null +++ b/parts/features/dev/neovim/default.nix @@ -0,0 +1,319 @@ +{config, lib, ...}: let + cfg = config; +in { + flake.modules.homeManager.neovim = { + osConfig, + pkgs, + lib, + ... + }: let + isLightTheme = osConfig.specialisation != {}; + in { + home.persistence."/persist" = lib.mkIf cfg.dendrix.isImpermanent { + directories = [ + ".local/share/nvim" + ".local/state/nvim" + ".cache/nvim" + ]; + }; + + imports = + [ + ./_avante + ./_carbon + ./_cmp + ./_comment-nvim + ./_dadbod + ./_dap + ./_diffview-nvim + ./_fidget + ./_folds + ./_fugitive + ./_git-conflict-nvim + ./_gitsigns + ./_jdtls + ./_jj + ./_lspsaga + ./_lualine + ./_mason-lsp + ./_mini-icons + ./_mini-operators + ./_neotest + ./_noice + ./_conform + ./_notify + ./_nui + ./_nvim-tree-lua + ./_obsidian-nvim + ./_oil + ./_otter + ./_overseer + ./_plenary + ./_rainbow-csv + ./_render-markdown + ./_telescope + ./_toggleterm + ./_treesitter + ./_trouble + ./_undotree + ./_vim-be-good + ./_vim-terraform + ./_vim-visual-multi + ./_web-devicons + ./_yank-file-line + ] + ++ lib.optionals isLightTheme [./_gruvbox]; + + programs.neovim = { + enable = true; + + extraConfig = '' + set mouse=a + set number + set clipboard=unnamedplus + set ignorecase + set smartcase + + " Defaults to be overwritten by vim-sleuth + set tabstop=4 + set shiftwidth=4 + + set grepprg=rg\ --vimgrep\ --no-heading\ --smart-case + + noremap h ; + noremap ; l + noremap l k + noremap k j + noremap j h + noremap ; l + noremap l k + noremap k j + noremap j h + noremap : L + noremap L K + noremap K J + noremap J H + + " Vertical Awesomeness + nnoremap zz + nnoremap zz + nnoremap G Gzz + + tnoremap h + tnoremap j + tnoremap k + tnoremap l + inoremap h + inoremap j + inoremap k + inoremap l + nnoremap h + nnoremap j + nnoremap k + nnoremap l + + set shell=/etc/profiles/per-user/farlion/bin/fish + + let mapleader = ' ' + let maplocalleader = ',' + + " Diff Settings + set diffopt+=internal,algorithm:patience + + " Quickfix Lists + nnoremap :cprev + nnoremap :cnext + + " Saving - use z. for centering the cursor instead + nnoremap zz :update + + " Applying a macro to lines matching in visual selection + xnoremap @ :call ExecuteMacroOverVisualRange() + function! ExecuteMacroOverVisualRange() + echo "@".getcmdline() + execute ":'<,'>normal @".nr2char(getchar()) + endfunction + + lua require('crates').setup() + + " Fugitive + function! s:ftplugin_fugitive() abort + nnoremap cc :Git commit --quiet + nnoremap ca :Git commit --quiet --amend + nnoremap ce :Git commit --quiet --amend --no-edit + endfunction + augroup quiet_fugitive + autocmd! + autocmd FileType fugitive call s:ftplugin_fugitive() + augroup END + + " Vim Visual Multi + let g:VM_custom_motions = {'h': ';', ';': 'l', 'l': 'k', 'k': 'j', 'j': 'h'} + let g:VM_mouse_mappings = 1 + + " Background light/dark toggling + nmap i :let &bg=(&bg=='light'?'dark':'light') + + " Sudo powers with :w!! + cnoremap w!! execute 'silent! write !sudo tee % >/dev/null' edit! + ''; + + extraLuaConfig = '' + vim.opt.termguicolors = true + vim.o.breakindent = true + vim.keymap.set('n', 'k', "v:count == 0 ? 'gj' : 'j'", { expr = true, silent = true }) + vim.keymap.set('n', 'l', "v:count == 0 ? 'gk' : 'k'", { expr = true, silent = true }) + vim.o.undofile = true + vim.o.timeout = true + vim.o.timeoutlen = 300 + vim.o.updatetime = 250 + vim.o.completeopt = 'menuone,noselect' + vim.keymap.set({ 'n', 'v' }, '', '', { silent = true }) + vim.opt.swapfile = false + vim.keymap.set('t', '', '', { silent = true }) + vim.keymap.set('t', '', [[]], { silent = true }) + vim.keymap.set({ 'n', 'v', 't' }, 'ZQ', ':qa!') + vim.keymap.set({'n', 'i'}, '', '', { noremap = true, silent = true }) + ''; + + extraPackages = with pkgs; [ + harper + nixd + nodejs + prettierd + pyright + shellcheck + shfmt + ]; + + plugins = with pkgs.vimPlugins; [ + argtextobj-vim + { + plugin = b64-nvim; + config = '' + local wk = require("which-key") + wk.add( + { + { + mode = { "v" }, + { "b", group = "[B]ase64" }, + { "bd", require("b64").decode, desc = "Base64 [D]ecode" }, + { "be", require("b64").decode, desc = "Base64 [E]ncode" }, + }, + } + ) + ''; + type = "lua"; + } + { + plugin = dressing-nvim; + config = ""; + type = "lua"; + } + {plugin = friendly-snippets;} + vim-highlightedyank + { + plugin = indent-blankline-nvim; + config = '' + require("ibl").setup({ + exclude = { + filetypes = {"startify"}, + } + }) + local hooks = require "ibl.hooks" + hooks.register(hooks.type.ACTIVE, function(bufnr) + return vim.tbl_contains( + { "yaml", "html", "svelte" }, + vim.api.nvim_get_option_value("filetype", { buf = bufnr }) + ) + end) + local wk = require("which-key") + wk.add({ + { "[i", function() require("ibl").setup_buffer(0, {enabled = true}) end, desc = "Indentation Guides ON" }, + { "]i", function() require("ibl").setup_buffer(0, {enabled = false}) end, desc = "Indentation Guides OFF" }, + }) + ''; + type = "lua"; + } + {plugin = nvim-lspconfig;} + {plugin = luasnip;} + { + plugin = markdown-preview-nvim; + config = '' + local wk = require("which-key") + wk.add({ + { "p", "MarkdownPreviewToggle", desc = "Toggle Markdown [P]review" }, + }) + ''; + type = "lua"; + } + vim-numbertoggle + { + plugin = vim-qf; + config = ""; + } + vim-rooter + vim-sleuth + { + plugin = vim-startify; + config = '' + let g:startify_change_to_dir = 0 + let g:startify_change_to_vcs_root = 1 + let g:startify_session_persistence = 1 + let g:startify_bookmarks = [ {'c': '~/nixos-config/parts/features/dev/neovim/default.nix'} ] + ''; + } + vim-surround + {plugin = vim-suda;} + { + plugin = text-case-nvim; + config = '' + require("textcase").setup({ + prefix = "ga", + }) + require("telescope").load_extension("textcase") + local wk = require("which-key") + wk.add({ + { "ga.", "TextCaseOpenTelescope", desc = "Telescope" }, + }) + ''; + type = "lua"; + } + vim-textobj-entire + vim-toml + vim-unimpaired + { + plugin = which-key-nvim; + config = '' + require("which-key").setup { + } + ''; + type = "lua"; + } + crates-nvim + dart-vim-plugin + elm-vim + vim-graphql + vim-jsonnet + { + plugin = neodev-nvim; + config = '' + require("neodev").setup({ + library = { plugins = { "nvim-dap-ui", "neotest" }, types = true }, + }) + ''; + type = "lua"; + } + vim-flutter + vim-helm + vim-shellcheck + vim-solidity + vim-nix + ]; + + viAlias = true; + vimAlias = true; + vimdiffAlias = true; + }; + }; +} From 0b2bee2abd1a6112daab808f9c488578e67c4f7e Mon Sep 17 00:00:00 2001 From: workflow <4farlion@gmail.com> Date: Fri, 30 Jan 2026 20:56:53 +0000 Subject: [PATCH 07/26] feat(dendritic): migrate complex features (niri, theming, audio, fish, firefox) --- parts/features/apps/firefox.nix | 29 + parts/features/apps/fish.nix | 138 +++++ .../desktop/niri/_scripts/niri-auto-column.sh | 71 +++ .../niri/_scripts/niri-open-on-workspace.sh | 24 + .../desktop/niri/_scripts/niri-pick-window.sh | 92 ++++ .../desktop/niri/_scripts/niri-qalc.sh | 53 ++ .../niri/_scripts/niri-reorder-workspaces.sh | 76 +++ .../niri/_scripts/niri-set-wallpaper.sh | 26 + .../niri/_wallpapers/gruvbox-dark-rainbow.png | Bin 0 -> 185977 bytes .../_wallpapers/gruvbox-light-rainbow.png | Bin 0 -> 192946 bytes parts/features/desktop/niri/default.nix | 519 ++++++++++++++++++ parts/features/desktop/theming.nix | 104 ++++ .../_wallpapers/gruvbox-dark-rainbow.png | Bin 0 -> 185977 bytes .../_wallpapers/gruvbox-light-rainbow.png | Bin 0 -> 192946 bytes parts/features/hardware/audio.nix | 106 ++++ ...round-48k-z-edition-stereo-plus20-bass.irs | Bin 0 -> 71372 bytes .../output/bass-enhancing-perfect-eq.json | 226 ++++++++ parts/features/hardware/audio/pulsemixer.cfg | 7 + 18 files changed, 1471 insertions(+) create mode 100644 parts/features/apps/firefox.nix create mode 100644 parts/features/apps/fish.nix create mode 100644 parts/features/desktop/niri/_scripts/niri-auto-column.sh create mode 100644 parts/features/desktop/niri/_scripts/niri-open-on-workspace.sh create mode 100644 parts/features/desktop/niri/_scripts/niri-pick-window.sh create mode 100644 parts/features/desktop/niri/_scripts/niri-qalc.sh create mode 100755 parts/features/desktop/niri/_scripts/niri-reorder-workspaces.sh create mode 100644 parts/features/desktop/niri/_scripts/niri-set-wallpaper.sh create mode 100644 parts/features/desktop/niri/_wallpapers/gruvbox-dark-rainbow.png create mode 100644 parts/features/desktop/niri/_wallpapers/gruvbox-light-rainbow.png create mode 100644 parts/features/desktop/niri/default.nix create mode 100644 parts/features/desktop/theming.nix create mode 100644 parts/features/desktop/theming/_wallpapers/gruvbox-dark-rainbow.png create mode 100644 parts/features/desktop/theming/_wallpapers/gruvbox-light-rainbow.png create mode 100644 parts/features/hardware/audio.nix create mode 100644 parts/features/hardware/audio/_presets/irs/razor-surround-48k-z-edition-stereo-plus20-bass.irs create mode 100644 parts/features/hardware/audio/_presets/output/bass-enhancing-perfect-eq.json create mode 100644 parts/features/hardware/audio/pulsemixer.cfg diff --git a/parts/features/apps/firefox.nix b/parts/features/apps/firefox.nix new file mode 100644 index 00000000..84be7dda --- /dev/null +++ b/parts/features/apps/firefox.nix @@ -0,0 +1,29 @@ +{config, lib, ...}: let + cfg = config; +in { + flake.modules.homeManager.firefox = { + lib, + pkgs, + ... + }: { + home.persistence."/persist" = lib.mkIf cfg.dendrix.isImpermanent { + directories = [ + ".mozilla/firefox" + ".cache/mozilla/firefox" + ]; + }; + + programs.firefox = { + enable = true; + profiles = { + main = { + extensions.packages = with pkgs.nur.repos.rycee.firefox-addons; [ + bitwarden + ]; + id = 0; + isDefault = true; + }; + }; + }; + }; +} diff --git a/parts/features/apps/fish.nix b/parts/features/apps/fish.nix new file mode 100644 index 00000000..417bebcd --- /dev/null +++ b/parts/features/apps/fish.nix @@ -0,0 +1,138 @@ +{config, lib, ...}: let + cfg = config; +in { + flake.modules.homeManager.fish = { + config, + lib, + pkgs, + ... + }: let + functions = { + fish_user_key_bindings = + /* + fish + */ + '' + fish_vi_key_bindings + + # VI mode updates + bind -s --preset --mode default j backward-char + bind -s --preset --mode default \; forward-char + bind -s --preset k down-or-search + bind -s --preset l up-or-search + bind -s --preset --mode visual j backward-char + bind -s --preset --mode visual \; forward-char + bind -s --preset --mode visual l up-line + bind -s --preset --mode visual k down-line + + # Completions + bind -s --mode insert \cw forward-word + # Tab --> accept autosuggestions + bind -s --mode insert \t accept-autosuggestion + # CTRL-S --> original TAB behaviour + bind -s --mode insert \cs complete + + # Bang-Bang bindings, manually added so they have precedence: + bind --mode insert ! __history_previous_command + bind --mode insert '$' __history_previous_command_arguments + ''; + + lf = + /* + fish + */ + '' + set -x LF_CD_FILE /var/tmp/.lfcd-$fish_pid + command lf $argv + if test -s "$LF_CD_FILE" + set DIR (realpath (cat "$LF_CD_FILE")) + if test "$DIR" != "$PWD" + cd "$DIR" + end + rm "$LF_CD_FILE" + end + set -e LF_CD_FILE + ''; + + pirate = + /* + fish + */ + '' + set toTranslate $argv + curl -sG \ + --data-urlencode "english=$toTranslate" \ + 'http://pirate.monkeyness.com/cgi-bin/translator.pl?client=monkeyness&version=1.0' -H 'Accept: application/json' -H 'Connection: keep-alive' -H 'Accept-Encoding: gzip, deflate' -H 'Referer: http://pirate.monkeyness.com/online_pirate_translator' -H 'Accept-Language: en-US,en;q=0.9' -H 'User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.87 Safari/537.36' --compressed --insecure \ + | xq -r .pirateAPI.pirate \ + | curl -sG \ + --data-urlencode "source_text=$toTranslate" \ + 'https://speakpirate.com/' -H 'authority: speakpirate.com' -H 'cache-control: max-age=0' -H 'origin: https://speakpirate.com' -H 'upgrade-insecure-requests: 1' -H 'content-type: application/x-www-form-urlencoded' -H 'user-agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.87 Safari/537.36' -H 'sec-fetch-mode: navigate' -H 'sec-fetch-user: ?1' -H 'accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3' -H 'sec-fetch-site: same-origin' -H 'referer: https://speakpirate.com/' -H 'accept-encoding: gzip, deflate, br' -H 'accept-language: en-US,en;q=0.9' -H 'cookie: __utma=133499724.1448464120.1565964854.1565964854.1565964854.1; __utmc=133499724; __utmz=133499724.1565964854.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none); __utmt=1; __utmb=133499724.1.10.1565964854' --compressed \ + | pup 'textarea#translated json{}' | jq -r '.[0].text' + ''; + + posix-source = + /* + fish + */ + '' + for i in (cat $argv) + set arr (echo $i | string match -r "([^=]+)=(.*)") + set -gx $arr[2] $arr[3] + end + ''; + + kubectlgetall = + /* + fish + */ + '' + for i in (kubectl api-resources --verbs=list --namespaced -o name | grep -v "events.events.k8s.io" | grep -v "events" | sort | uniq) + echo "Resource:" $i + kubectl -n "$argv[1]" get --ignore-not-found "$i" + end + ''; + }; + + plugins = with pkgs.fishPlugins; [ + { + name = "bang-bang"; + src = bang-bang.src; + } + ]; + + shellInit = '' + ${variables} + ''; + + variables = + /* + fish + */ + '' + set -g fish_key_bindings fish_default_key_bindings + set fish_greeting # disable greeting + ''; + in { + home.persistence."/persist" = lib.mkIf cfg.dendrix.isImpermanent { + directories = [ + ".config/fish" + ".local/share/fish" + ]; + }; + + programs.fish = { + enable = true; + interactiveShellInit = shellInit; + inherit functions plugins; + shellAbbrs = + config.home.shellAliases + // { + bash = "${config.programs.bash.package}/bin/bash"; + cc = "tee /dev/tty | wl-copy"; + dark-theme = "nh os test --no-specialisation && niri-set-wallpaper"; + light-theme = "nh os test --specialisation light && niri-set-wallpaper"; + pa = "pw-play ~/Music/Own\\ Speech/IckbinArschratte.WAV"; + }; + }; + }; +} diff --git a/parts/features/desktop/niri/_scripts/niri-auto-column.sh b/parts/features/desktop/niri/_scripts/niri-auto-column.sh new file mode 100644 index 00000000..83ecc98f --- /dev/null +++ b/parts/features/desktop/niri/_scripts/niri-auto-column.sh @@ -0,0 +1,71 @@ +#!/usr/bin/env bash + +# Auto-consume windows into columns on vertical monitors +# Listens to niri event stream and consumes new windows on specified outputs + +set -euo pipefail + +# Outputs where windows should auto-stack into columns +VERTICAL_OUTPUTS=("HDMI-A-2" "HDMI-A-1") + +get_workspace_output() { + local workspace_id="$1" + niri msg --json workspaces | jq -r --argjson id "$workspace_id" \ + '.[] | select(.id == $id) | .output // empty' +} + +is_vertical_output() { + local output="$1" + for v in "${VERTICAL_OUTPUTS[@]}"; do + if [[ "$output" == "$v" ]]; then + return 0 + fi + done + return 1 +} + +get_column_window_count() { + local window_id="$1" + # Get the focused window's column info from the layout + niri msg --json windows | jq --argjson id "$window_id" ' + [.[] | select(.workspace_id == (.[] | select(.id == $id) | .workspace_id))] | length + ' 2>/dev/null || echo "1" +} + +# Main event loop +niri msg --json event-stream | while IFS= read -r event; do + event_type=$(echo "$event" | jq -r 'keys[0]') + + if [[ "$event_type" == "WindowOpenedOrChanged" ]]; then + window=$(echo "$event" | jq '.WindowOpenedOrChanged.window') + window_id=$(echo "$window" | jq -r '.id') + workspace_id=$(echo "$window" | jq -r '.workspace_id // empty') + is_focused=$(echo "$window" | jq -r '.is_focused') + + # Skip if no workspace (floating or special windows) + if [[ -z "$workspace_id" || "$workspace_id" == "null" ]]; then + continue + fi + + # Get the output for this workspace + output=$(get_workspace_output "$workspace_id") + + if [[ -z "$output" ]]; then + continue + fi + + # Check if this is a vertical output + if is_vertical_output "$output"; then + # Only act on focused windows (newly opened windows get focus) + if [[ "$is_focused" == "true" ]]; then + # Small delay to let niri finish placing the window + sleep 0.05 + # Move focus to the left column, then consume the new window from the right + niri msg action focus-column-left 2>/dev/null || true + niri msg action consume-window-into-column 2>/dev/null || true + # Focus the newly consumed window (inserted after current focus) + niri msg action focus-window-down 2>/dev/null || true + fi + fi + fi +done diff --git a/parts/features/desktop/niri/_scripts/niri-open-on-workspace.sh b/parts/features/desktop/niri/_scripts/niri-open-on-workspace.sh new file mode 100644 index 00000000..a5c4de64 --- /dev/null +++ b/parts/features/desktop/niri/_scripts/niri-open-on-workspace.sh @@ -0,0 +1,24 @@ +#!/usr/bin/env bash +# Opens a command and moves its window to a specific workspace once the title matches + +set -euo pipefail + +workspace="$1" +title_pattern="$2" +shift 2 + +# Launch the command in background +"$@" & + +# Wait for window with matching title to appear (max 30 seconds) +for _ in {1..60}; do + sleep 0.5 + window_id=$(niri msg -j windows | jq -r ".[] | select(.title | test(\"$title_pattern\")) | .id" | head -n1) + if [[ -n "$window_id" ]]; then + niri msg action move-window-to-workspace --window-id "$window_id" "$workspace" + exit 0 + fi +done + +echo "Timeout waiting for window with title matching: $title_pattern" >&2 +exit 1 diff --git a/parts/features/desktop/niri/_scripts/niri-pick-window.sh b/parts/features/desktop/niri/_scripts/niri-pick-window.sh new file mode 100644 index 00000000..49ac2c00 --- /dev/null +++ b/parts/features/desktop/niri/_scripts/niri-pick-window.sh @@ -0,0 +1,92 @@ +# Grab the current windows from Niri (id, title, app_id, workspace_id, …) +wins_json="$(niri msg --json windows)" + +# Keep a parallel list of window IDs so we can map fuzzel's index → id. +mapfile -t IDS < <(jq -r '.[].id' <<<"$wins_json") + +# Resolve an icon name from .desktop files for a given app_id. +resolve_icon_from_desktop() { + # We try exact app_id.desktop and its last reverse-DNS segment. + # We return the Icon= value if found (prefer theme name without extension unless absolute path). + local appid="$1" + [ -z "$appid" ] && return 1 + local xdg_home="${XDG_DATA_HOME:-$HOME/.local/share}" + local xdg_dirs="${XDG_DATA_DIRS:-/usr/local/share:/usr/share}" + local -a search_dirs=("$xdg_home/applications") + IFS=: read -r -a _xdg_dirs <<<"$xdg_dirs" + for d in "${_xdg_dirs[@]}"; do + search_dirs+=("$d/applications") + done + local last_seg="${appid##*.}" + local name + for name in "$appid" "$last_seg"; do + for d in "${search_dirs[@]}"; do + if [ -f "$d/$name.desktop" ]; then + # Extract first Icon= value + local icon + icon="$(sed -n 's/^Icon=\(.*\)$/\1/p' "$d/$name.desktop" | head -n 1)" + if [ -n "$icon" ]; then + case "$icon" in + /*) printf '%s' "$icon" ;; + *.png|*.svg|*.xpm) printf '%s' "${icon%.*}" ;; + *) printf '%s' "$icon" ;; + esac + return 0 + fi + fi + done + done + return 1 +} + +# Build the fuzzel menu. We attach icons using the Rofi extended dmenu protocol: +# append a NUL, then "icon", then unit-separator, then the comma-separated icon names. +SEL_IDX="$( + # Create TAB-separated lines: label \t icon-candidates \t app_id + jq -r ' + def slug: (. // "") | ascii_downcase | gsub("[^a-z0-9]+"; "-"); + def hyphenate: (. // "") | ascii_downcase | gsub("[.]+"; "-"); + + .[] as $w + | ($w.app_id // "") as $app_raw + | ($app_raw | ascii_downcase) as $app + | ($app | split(".")) as $parts + | ($parts | length) as $len + | (if $len > 0 then $parts[$len-1] else "" end) as $last + | (if $len > 1 then $parts[$len-2] else "" end) as $penult + | ($app | hyphenate) as $app_hyph + | ($last | slug) as $last_slug + | ($penult | slug) as $penult_slug + | [ + $app, + $app_hyph, + (if $len > 1 then ($penult_slug + "-" + $last_slug) else null end), + $penult, + $last, + $penult_slug, + $last_slug, + "application-default-icon", + "application-x-executable" + ] + | map(select(. != null and . != "")) + | join(",") as $icons + | "\($w.title) — [ws \($w.workspace_id)] (\($w.app_id // "?"))\t\($icons)\t\($app_raw)" + ' <<<"$wins_json" | + # For each line, optionally prefix the candidate list with the .desktop Icon= value, + # then convert to the dmenu icon protocol with real NUL (0) and US (31) separators. + while IFS=$'\t' read -r label icons appid; do + resolved_icon="$(resolve_icon_from_desktop "$appid" 2>/dev/null || true)" + if [ -n "$resolved_icon" ]; then + icons="$resolved_icon,$icons" + fi + printf '%s\t%s\n' "$label" "$icons" + done | + awk -v FS='\t' 'BEGIN{ nul=sprintf("%c",0); us=sprintf("%c",31);} { printf "%s" nul "icon" us "%s\n", $1, $2 }' | + fuzzel --dmenu --index --icon-theme Papirus-Dark --log-level info 2>"${XDG_CACHE_HOME:-$HOME/.cache}"/niri-pick-window-fuzzel.log +)" + +# If the user cancelled, exit quietly. +[[ -z "${SEL_IDX}" ]] && exit 0 + +# Focus the selected window by ID. +niri msg action focus-window --id "${IDS[$SEL_IDX]}" diff --git a/parts/features/desktop/niri/_scripts/niri-qalc.sh b/parts/features/desktop/niri/_scripts/niri-qalc.sh new file mode 100644 index 00000000..8a9b8b44 --- /dev/null +++ b/parts/features/desktop/niri/_scripts/niri-qalc.sh @@ -0,0 +1,53 @@ +# Simple calculator wrapper for fuzzel --dmenu using qalc. +# - Prompts for an expression via fuzzel +# - Evaluates it with qalc +# - Copies the result to the clipboard +# - Shows a notification with the result + +prompt="calc> " + +# Prefer dunstify if available; otherwise fall back to notify-send. +NOTIFY_BIN="$(command -v dunstify || true)" +if [ -z "$NOTIFY_BIN" ]; then + NOTIFY_BIN="$(command -v notify-send || true)" +fi +ICON_NAME="accessories-calculator" + +notify() { + # Usage: notify "summary" "body" + local summary="$1" + local body="$2" + if [ -n "$NOTIFY_BIN" ]; then + # Set an app name for nicer presentation; both dunstify and notify-send support -a + "$NOTIFY_BIN" -a "Calc" -i "$ICON_NAME" "$summary" "$body" || true + fi +} + +# Ask the user for an expression using fuzzel's dmenu mode. +# We feed an empty list so that free-form input is returned. +expr_input="$(printf '%s' "" | fuzzel --dmenu --prompt "$prompt" --lines 0 2>/dev/null || true)" + +# Exit silently if the user cancelled or input is empty/whitespace. +if [ -z "${expr_input//[[:space:]]/}" ]; then + exit 0 +fi + +# Evaluate the expression using qalc in terse mode to get only the result. +# If qalc fails, we notify and exit with non-zero status. +result="$(qalc -t -- "$expr_input" 2>/dev/null || true)" +# Normalize whitespace/newlines +result="$(printf '%s' "$result" | tr '\n' ' ' | sed 's/^\s\+//; s/\s\+$//')" + +if [ -z "$result" ]; then + notify "Calc" "Invalid expression: $expr_input" + exit 1 +fi + +# Copy to clipboard +printf '%s' "$result" | wl-copy + +# Notify the user +notify "Calc" "$expr_input = $result (copied to clipboard)" + +# Print to stdout as well (useful for logs) +printf '%s\n' "$result" diff --git a/parts/features/desktop/niri/_scripts/niri-reorder-workspaces.sh b/parts/features/desktop/niri/_scripts/niri-reorder-workspaces.sh new file mode 100755 index 00000000..78f5ee3d --- /dev/null +++ b/parts/features/desktop/niri/_scripts/niri-reorder-workspaces.sh @@ -0,0 +1,76 @@ +#!/usr/bin/env bash + +# Script to reorder Niri workspaces based on their names +# This ensures workspaces maintain their logical order even after being moved between monitors + +set -euo pipefail + +# Define the desired workspace order +declare -A WORKSPACE_ORDER=( + [" a"]=0 + [" 1"]=1 + [" 2"]=2 + [" 3"]=3 + [" 4"]=4 + [" 5"]=5 + [" 6"]=6 + [" 7"]=7 + [" 8"]=8 + [" 9"]=9 + [" 10"]=10 +) + +# Get all workspaces as JSON +workspaces_json=$(niri msg --json workspaces) + +# Get unique output names +outputs=$(echo "$workspaces_json" | jq -r '.[].output' | sort -u) + +# For each output/monitor +while IFS= read -r output; do + # Get workspaces on this output with their current indices and names + workspace_data=$(echo "$workspaces_json" | jq -r \ + --arg output "$output" \ + '.[] | select(.output == $output) | "\(.idx)|\(.name)"') + + # Build an array of workspaces with their sort order + declare -a workspace_list=() + + while IFS='|' read -r current_idx name; do + # Look up the desired order for this workspace name + if [[ -v WORKSPACE_ORDER["$name"] ]]; then + sort_order="${WORKSPACE_ORDER[$name]}" + # Store as: sort_order|current_idx|name + workspace_list+=("$sort_order|$current_idx|$name") + fi + done <<<"$workspace_data" + + # Sort workspaces by their logical order (first field) + mapfile -t sorted_workspaces < <(printf '%s\n' "${workspace_list[@]}" | sort -t'|' -k1 -n) + + # Assign sequential target indices (forward iteration) + for ((i = 0; i < ${#sorted_workspaces[@]}; i++)); do + target_indices[i]=$i + done + + # Move workspaces to their target positions (backward iteration to avoid displacement) + for ((i = ${#sorted_workspaces[@]} - 1; i >= 0; i--)); do + IFS='|' read -r sort_order current_idx name <<<"${sorted_workspaces[$i]}" + target_idx=${target_indices[i]} + + if [[ "$current_idx" != "$target_idx" ]]; then + # Focus the workspace by name first + niri msg action focus-workspace "$name" >/dev/null 2>&1 || true + + # Move it to the correct index + niri msg action move-workspace-to-index "$target_idx" >/dev/null 2>&1 || true + fi + done + + # Clear arrays for the next output + unset workspace_list + unset sorted_workspaces + unset target_indices +done <<<"$outputs" + +echo "Workspaces reordered successfully!" diff --git a/parts/features/desktop/niri/_scripts/niri-set-wallpaper.sh b/parts/features/desktop/niri/_scripts/niri-set-wallpaper.sh new file mode 100644 index 00000000..39d5b953 --- /dev/null +++ b/parts/features/desktop/niri/_scripts/niri-set-wallpaper.sh @@ -0,0 +1,26 @@ +wallpapersDir="${HOME}/.local/share/wallpapers" + +pkill swaybg || true + +# Read the current specialisation, default to "dark" if missing +if [ -r /etc/specialisation ]; then + SPEC=$(tr -d '\n' /dev/null) +else + SPEC=dark +fi + +case "$SPEC" in + +light) + swaybg -i "${wallpapersDir}/gruvbox-light.png" -m fill & + disown + ;; +dark) + swaybg -i "${wallpapersDir}/gruvbox-dark.png" -m fill & + disown + ;; +*) + swaybg -i "${wallpapersDir}/gruvbox-dark.png" -m fill & + disown + ;; +esac diff --git a/parts/features/desktop/niri/_wallpapers/gruvbox-dark-rainbow.png b/parts/features/desktop/niri/_wallpapers/gruvbox-dark-rainbow.png new file mode 100644 index 0000000000000000000000000000000000000000..b15ba5a97602c2e04138e96f0e48be21ff39e5d6 GIT binary patch literal 185977 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 L{uKA4)sg=JgoI_M literal 0 HcmV?d00001 diff --git a/parts/features/desktop/niri/_wallpapers/gruvbox-light-rainbow.png b/parts/features/desktop/niri/_wallpapers/gruvbox-light-rainbow.png new file mode 100644 index 0000000000000000000000000000000000000000..3217d92a564491f787d16bb44b79f3a46c2cd445 GIT binary patch literal 192946 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

=xE)K9{<4cEUj|~-RwRN*B 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 ZzcH`q(x)A=dr2l7^Iqt?+egky{uf^Cdo2I} literal 0 HcmV?d00001 diff --git a/parts/features/hardware/audio.nix b/parts/features/hardware/audio.nix new file mode 100644 index 00000000..e4917a0c --- /dev/null +++ b/parts/features/hardware/audio.nix @@ -0,0 +1,106 @@ +{config, lib, ...}: let + cfg = config; +in { + flake.modules.nixos.audio = { + config, + lib, + pkgs, + ... + }: { + home-manager.users.farlion.home.persistence."/persist" = lib.mkIf cfg.dendrix.isImpermanent { + directories = [ + ".local/state/wireplumber" + ".config/rncbc.org" + ".config/pulse" + ]; + }; + + environment.systemPackages = with pkgs; [ + alsa-utils + pulseaudioFull + qpwgraph + ]; + + users.users.farlion.extraGroups = ["audio"]; + + security.rtkit.enable = true; + services.pipewire = { + enable = true; + alsa.enable = true; + alsa.support32Bit = true; + pulse.enable = true; + + extraConfig.pipewire."92-adjust-clock-quantum" = { + "context.properties" = { + "default.clock.quantum" = 2048; + "default.clock.min-quantum" = 512; + "default.clock.max-quantum" = 8192; + }; + }; + extraConfig.pipewire."93-disable-autosuspend" = { + "context.properties" = { + "session.suspend-timeout-seconds" = 0; + }; + }; + + wireplumber.extraConfig = { + "monitor.bluez.properties" = { + "bluez5.enable-sbc-xq" = true; + "bluez5.enable-msbc" = true; + "bluez5.enable-hw-volume" = true; + "bluez5.roles" = ["hsp_hs" "hsp_ag" "hfp_hf" "hfp_ag"]; + }; + + "disable-unused-nodes" = { + "monitor.alsa.rules" = [ + { + matches = [ + { + "device.nick" = "HDA NVidia"; + } + ]; + actions = { + update-props = { + "device.disabled" = true; + }; + }; + } + ]; + }; + }; + }; + }; + + flake.modules.homeManager.audio = { + lib, + pkgs, + ... + }: { + home.persistence."/persist" = lib.mkIf cfg.dendrix.isImpermanent { + directories = [ + ".config/easyeffects" + ]; + files = [ + ".config/pavucontrol.ini" + ]; + }; + + home.file = { + ".config/easyeffects/irs/Razor Surround ((48k Z-Edition)) 2.Stereo +20 bass.irs".source = ./audio/_presets/irs/razor-surround-48k-z-edition-stereo-plus20-bass.irs; + ".config/pulsemixer.cfg".source = ./audio/pulsemixer.cfg; + }; + + home.packages = [ + pkgs.pavucontrol + pkgs.pulsemixer + ]; + + services.easyeffects = { + enable = true; + preset = "bass-enhancing-perfect-eq"; + extraPresets = { + "bass-enhancing-perfect-eq" = builtins.fromJSON (builtins.readFile ./audio/_presets/output/bass-enhancing-perfect-eq.json); + }; + }; + }; +} diff --git a/parts/features/hardware/audio/_presets/irs/razor-surround-48k-z-edition-stereo-plus20-bass.irs b/parts/features/hardware/audio/_presets/irs/razor-surround-48k-z-edition-stereo-plus20-bass.irs new file mode 100644 index 0000000000000000000000000000000000000000..a70dcb3645465cf60ada5d5942c6451ccad4bc17 GIT binary patch literal 71372 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 yKy+3OFGkZi9%4B!v6=CiBVzz literal 0 HcmV?d00001 diff --git a/parts/features/hardware/audio/_presets/output/bass-enhancing-perfect-eq.json b/parts/features/hardware/audio/_presets/output/bass-enhancing-perfect-eq.json new file mode 100644 index 00000000..2530984e --- /dev/null +++ b/parts/features/hardware/audio/_presets/output/bass-enhancing-perfect-eq.json @@ -0,0 +1,226 @@ +{ + "output": { + "blocklist": [], + "convolver": { + "input-gain": -2.0, + "ir-width": 100, + "kernel-name": "Razor Surround ((48k Z-Edition)) 2.Stereo +20 bass", + "output-gain": 0.0 + }, + "equalizer": { + "input-gain": -2.0, + "left": { + "band0": { + "frequency": 32.0, + "gain": 4.0, + "mode": "RLC (BT)", + "mute": false, + "q": 1.504760237537245, + "slope": "x1", + "solo": false, + "type": "Bell" + }, + "band1": { + "frequency": 64.0, + "gain": 2.0, + "mode": "RLC (BT)", + "mute": false, + "q": 1.5047602375372453, + "slope": "x1", + "solo": false, + "type": "Bell" + }, + "band2": { + "frequency": 125.0, + "gain": 1.0, + "mode": "RLC (BT)", + "mute": false, + "q": 1.504760237537245, + "slope": "x1", + "solo": false, + "type": "Bell" + }, + "band3": { + "frequency": 250.0, + "gain": 0.0, + "mode": "RLC (BT)", + "mute": false, + "q": 1.504760237537245, + "slope": "x1", + "solo": false, + "type": "Bell" + }, + "band4": { + "frequency": 500.0, + "gain": -1.0, + "mode": "RLC (BT)", + "mute": false, + "q": 1.5047602375372453, + "slope": "x1", + "solo": false, + "type": "Bell" + }, + "band5": { + "frequency": 1000.0, + "gain": -2.0, + "mode": "RLC (BT)", + "mute": false, + "q": 1.504760237537245, + "slope": "x1", + "solo": false, + "type": "Bell" + }, + "band6": { + "frequency": 2000.0, + "gain": 0.0, + "mode": "RLC (BT)", + "mute": false, + "q": 1.5047602375372449, + "slope": "x1", + "solo": false, + "type": "Bell" + }, + "band7": { + "frequency": 4000.0, + "gain": 2.0, + "mode": "RLC (BT)", + "mute": false, + "q": 1.5047602375372449, + "slope": "x1", + "solo": false, + "type": "Bell" + }, + "band8": { + "frequency": 8000.0, + "gain": 3.0, + "mode": "RLC (BT)", + "mute": false, + "q": 1.5047602375372453, + "slope": "x1", + "solo": false, + "type": "Bell" + }, + "band9": { + "frequency": 16000.0, + "gain": 3.0, + "mode": "RLC (BT)", + "mute": false, + "q": 1.504760237537245, + "slope": "x1", + "solo": false, + "type": "Bell" + } + }, + "mode": "IIR", + "num-bands": 10, + "output-gain": 0.0, + "right": { + "band0": { + "frequency": 32.0, + "gain": 4.0, + "mode": "RLC (BT)", + "mute": false, + "q": 1.504760237537245, + "slope": "x1", + "solo": false, + "type": "Bell" + }, + "band1": { + "frequency": 64.0, + "gain": 2.0, + "mode": "RLC (BT)", + "mute": false, + "q": 1.5047602375372453, + "slope": "x1", + "solo": false, + "type": "Bell" + }, + "band2": { + "frequency": 125.0, + "gain": 1.0, + "mode": "RLC (BT)", + "mute": false, + "q": 1.504760237537245, + "slope": "x1", + "solo": false, + "type": "Bell" + }, + "band3": { + "frequency": 250.0, + "gain": 0.0, + "mode": "RLC (BT)", + "mute": false, + "q": 1.504760237537245, + "slope": "x1", + "solo": false, + "type": "Bell" + }, + "band4": { + "frequency": 500.0, + "gain": -1.0, + "mode": "RLC (BT)", + "mute": false, + "q": 1.5047602375372453, + "slope": "x1", + "solo": false, + "type": "Bell" + }, + "band5": { + "frequency": 1000.0, + "gain": -2.0, + "mode": "RLC (BT)", + "mute": false, + "q": 1.504760237537245, + "slope": "x1", + "solo": false, + "type": "Bell" + }, + "band6": { + "frequency": 2000.0, + "gain": 0.0, + "mode": "RLC (BT)", + "mute": false, + "q": 1.5047602375372449, + "slope": "x1", + "solo": false, + "type": "Bell" + }, + "band7": { + "frequency": 4000.0, + "gain": 2.0, + "mode": "RLC (BT)", + "mute": false, + "q": 1.5047602375372449, + "slope": "x1", + "solo": false, + "type": "Bell" + }, + "band8": { + "frequency": 8000.0, + "gain": 3.0, + "mode": "RLC (BT)", + "mute": false, + "q": 1.5047602375372453, + "slope": "x1", + "solo": false, + "type": "Bell" + }, + "band9": { + "frequency": 16000.0, + "gain": 3.0, + "mode": "RLC (BT)", + "mute": false, + "q": 1.504760237537245, + "slope": "x1", + "solo": false, + "type": "Bell" + } + }, + "split-channels": false + }, + "plugins_order": [ + "equalizer", + "convolver" + ] + } +} diff --git a/parts/features/hardware/audio/pulsemixer.cfg b/parts/features/hardware/audio/pulsemixer.cfg new file mode 100644 index 00000000..cad6ed98 --- /dev/null +++ b/parts/features/hardware/audio/pulsemixer.cfg @@ -0,0 +1,7 @@ +[keys] +;; To bind "special keys" such as arrows see "Key constant" table in +;; https://docs.python.org/3/library/curses.html#constants +up = l, KEY_UP, KEY_PPAGE +down = k, KEY_DOWN, KEY_NPAGE +left = j, KEY_LEFT +right = ';', KEY_RIGHT From bb4b32671e70ec1d54d3320bd84d3dfcdd997920 Mon Sep 17 00:00:00 2001 From: workflow <4farlion@gmail.com> Date: Fri, 30 Jan 2026 21:11:24 +0000 Subject: [PATCH 08/26] feat(dendritic): bulk migrate apps and desktop features (batch 1) --- parts/features/apps/aichat.nix | 52 ++ parts/features/apps/alacritty.nix | 70 +++ parts/features/apps/aliases.nix | 61 ++ parts/features/apps/bash.nix | 27 + parts/features/apps/less.nix | 11 + parts/features/apps/nh.nix | 8 + .../features/apps/ssh/_scripts/ssh-add-all.sh | 74 +++ parts/features/apps/ssh/default.nix | 37 ++ parts/features/apps/xdg.nix | 60 ++ parts/features/desktop/dunst.nix | 20 + parts/features/desktop/fuzzel.nix | 8 + .../waybar/_scripts/dunst-dnd-waybar.sh | 9 + parts/features/desktop/waybar/default.nix | 575 ++++++++++++++++++ parts/features/dev/aider.nix | 7 + parts/features/dev/claude-code/CLAUDE.md | 17 + parts/features/dev/claude-code/default.nix | 54 ++ parts/features/dev/jujutsu.nix | 64 ++ 17 files changed, 1154 insertions(+) create mode 100644 parts/features/apps/aichat.nix create mode 100644 parts/features/apps/alacritty.nix create mode 100644 parts/features/apps/aliases.nix create mode 100644 parts/features/apps/bash.nix create mode 100644 parts/features/apps/less.nix create mode 100644 parts/features/apps/nh.nix create mode 100644 parts/features/apps/ssh/_scripts/ssh-add-all.sh create mode 100644 parts/features/apps/ssh/default.nix create mode 100644 parts/features/apps/xdg.nix create mode 100644 parts/features/desktop/dunst.nix create mode 100644 parts/features/desktop/fuzzel.nix create mode 100644 parts/features/desktop/waybar/_scripts/dunst-dnd-waybar.sh create mode 100644 parts/features/desktop/waybar/default.nix create mode 100644 parts/features/dev/aider.nix create mode 100644 parts/features/dev/claude-code/CLAUDE.md create mode 100644 parts/features/dev/claude-code/default.nix create mode 100644 parts/features/dev/jujutsu.nix diff --git a/parts/features/apps/aichat.nix b/parts/features/apps/aichat.nix new file mode 100644 index 00000000..c240f1e3 --- /dev/null +++ b/parts/features/apps/aichat.nix @@ -0,0 +1,52 @@ +{config, lib, ...}: let + cfg = config; +in { + flake.modules.homeManager.aichat = { + lib, + pkgs, + ... + }: { + home.persistence."/persist" = lib.mkIf cfg.dendrix.isImpermanent { + directories = [ + ".config/aichat" + ]; + }; + + programs.aichat = { + enable = true; + package = pkgs.unstable.aichat; + settings = { + model = "openai:gpt-5.1-chat-latest"; + keybindings = "vi"; + save_session = true; + compress_threshold = 0; + clients = [ + {type = "openai";} + {type = "deepseek";} + { + type = "gemini"; + patch.chat_completions.".*".body.safetySettings = [ + { + category = "HARM_CATEGORY_HARASSMENT"; + threshold = "BLOCK_NONE"; + } + { + category = "HARM_CATEGORY_HATE_SPEECH"; + threshold = "BLOCK_NONE"; + } + { + category = "HARM_CATEGORY_SEXUALLY_EXPLICIT"; + threshold = "BLOCK_NONE"; + } + { + category = "HARM_CATEGORY_DANGEROUS_CONTENT"; + threshold = "BLOCK_NONE"; + } + ]; + } + {type = "claude";} + ]; + }; + }; + }; +} diff --git a/parts/features/apps/alacritty.nix b/parts/features/apps/alacritty.nix new file mode 100644 index 00000000..b47b9ded --- /dev/null +++ b/parts/features/apps/alacritty.nix @@ -0,0 +1,70 @@ +{...}: { + flake.modules.homeManager.alacritty = {...}: { + programs.alacritty = { + enable = true; + + settings = { + cursor = { + vi_mode_style = { + shape = "Beam"; + blinking = "Always"; + }; + }; + + keyboard.bindings = [ + { + key = "Return"; + mods = "Control|Super"; + action = "SpawnNewInstance"; + } + { + key = "Escape"; + mods = "Alt"; + action = "ToggleViMode"; + } + { + key = "Semicolon"; + mode = "Vi|~Search"; + action = "Right"; + } + { + key = "L"; + mode = "Vi|~Search"; + action = "Up"; + } + { + key = "K"; + mode = "Vi|~Search"; + action = "Down"; + } + { + key = "J"; + mode = "Vi|~Search"; + action = "Left"; + } + { + key = 53; + mode = "Vi|~Search"; + mods = "Shift"; + action = "SearchBackward"; + } + ]; + + env = { + TERM = "xterm-256color"; + }; + + scrolling = { + history = 100000; + }; + + window = { + padding = { + x = 5; + y = 4; + }; + }; + }; + }; + }; +} diff --git a/parts/features/apps/aliases.nix b/parts/features/apps/aliases.nix new file mode 100644 index 00000000..ded91862 --- /dev/null +++ b/parts/features/apps/aliases.nix @@ -0,0 +1,61 @@ +{...}: { + flake.modules.homeManager.aliases = {...}: { + home.shellAliases = { + ".." = "cd .."; + "..." = "cd ../.."; + "...." = "cd ../../.."; + "....." = "cd ../../../.."; + + as = "aichat --model openai:gpt-4o-mini-search-preview"; + ae = "aichat -e"; + + caffeinate = "systemctl --user stop swayidle"; + decaffeinate = "systemctl --user start swayidle"; + + c = "wl-copy"; + + cdn = "cd ~/nixos-config"; + cdc = "cd ~/code"; + + dira = "direnv allow"; + dird = "direnv deny"; + dirr = "direnv reload"; + dr = "direnv reload"; + + ghco = "gh pr checkout"; + ghpa = "gh pr review --approve"; + ghmr = "gh pr merge -r"; + + isdu = "isd --startup_mode=user"; + + k9s-kind = "k9s --context kind-kind"; + + kc = "kubectl"; + kc-kind = "kubectl --context kind-kind"; + + lh = "/run/current-system/sw/bin/ls -ah"; + + myip = "dig @resolver1.opendns.com ANY myip.opendns.com +short"; + + n = "nh os switch"; + + nl = "sudo nix-env --list-generations --profile /nix/var/nix/profiles/system"; + ngc = "sudo nix-env --delete-generations 30d --profile /nix/var/nix/profiles/system"; + + nsn = "nh search"; + + paste = "wl-paste"; + + ra = "systemctl restart --user pipewire"; + + rm = "trash-put"; + + stern-kind = "stern --context kind-kind"; + + tailup = "sudo tailscale up --accept-routes --accept-dns=false"; + taildown = "sudo tailscale down"; + + x = "exit"; + }; + }; +} diff --git a/parts/features/apps/bash.nix b/parts/features/apps/bash.nix new file mode 100644 index 00000000..03fcb2c1 --- /dev/null +++ b/parts/features/apps/bash.nix @@ -0,0 +1,27 @@ +{config, lib, ...}: let + cfg = config; +in { + flake.modules.homeManager.bash = { + lib, + pkgs, + ... + }: { + home.persistence."/persist" = lib.mkIf cfg.dendrix.isImpermanent { + files = [ + ".bash_history" + ]; + }; + + programs.bash = { + enable = true; + package = pkgs.bashInteractive; + initExtra = '' + # Ctrl-x: Copy current command line to clipboard + copy-command-line() { + printf '%s' "$READLINE_LINE" | ${pkgs.wl-clipboard}/bin/wl-copy + } + bind -x '"\C-x": copy-command-line' + ''; + }; + }; +} diff --git a/parts/features/apps/less.nix b/parts/features/apps/less.nix new file mode 100644 index 00000000..7091e40d --- /dev/null +++ b/parts/features/apps/less.nix @@ -0,0 +1,11 @@ +{...}: { + flake.modules.homeManager.less = {...}: { + programs.less = { + enable = true; + config = '' + k forw-line + l back-line + ''; + }; + }; +} diff --git a/parts/features/apps/nh.nix b/parts/features/apps/nh.nix new file mode 100644 index 00000000..f7bb4146 --- /dev/null +++ b/parts/features/apps/nh.nix @@ -0,0 +1,8 @@ +{...}: { + flake.modules.homeManager.nh = {...}: { + programs.nh = { + enable = true; + flake = "/home/farlion/code/nixos-config"; + }; + }; +} diff --git a/parts/features/apps/ssh/_scripts/ssh-add-all.sh b/parts/features/apps/ssh/_scripts/ssh-add-all.sh new file mode 100644 index 00000000..cf17b5ca --- /dev/null +++ b/parts/features/apps/ssh/_scripts/ssh-add-all.sh @@ -0,0 +1,74 @@ +#!/usr/bin/env bash +# SSH Key Manager for GNOME Keyring +# This script adds all SSH keys from ~/.ssh to the GNOME Keyring SSH agent + +set -euo pipefail + +# Check if SSH agent is running +if [ -z "${SSH_AUTH_SOCK:-}" ]; then + echo "Error: SSH_AUTH_SOCK is not set. SSH agent might not be running." + echo "Make sure GNOME Keyring SSH agent is started." + exit 1 +fi + +# Find all SSH private keys in ~/.ssh directory +SSH_DIR="$HOME/.ssh" +if [ ! -d "$SSH_DIR" ]; then + echo "Error: SSH directory $SSH_DIR does not exist." + exit 1 +fi + +# Common SSH key patterns +KEY_PATTERNS=("id_rsa" "id_ed25519" "id_ecdsa" "id_dsa") + +echo "Looking for SSH keys in $SSH_DIR..." + +KEYS_FOUND=0 +for pattern in "${KEY_PATTERNS[@]}"; do + # Check for exact match first + if [ -f "$SSH_DIR/$pattern" ]; then + echo "Found key: $SSH_DIR/$pattern" + ssh-add "$SSH_DIR/$pattern" || echo "Warning: Failed to add $SSH_DIR/$pattern" + KEYS_FOUND=$((KEYS_FOUND + 1)) + fi + + # Check for numbered variants (e.g., id_rsa_1, id_rsa_2) + for key_file in "$SSH_DIR"/"${pattern}"_*; do + if [ -f "$key_file" ] && [[ ! "$key_file" == *.pub ]]; then + echo "Found key: $key_file" + ssh-add "$key_file" || echo "Warning: Failed to add $key_file" + KEYS_FOUND=$((KEYS_FOUND + 1)) + fi + done +done + +# Also look for any other files that look like private keys +for key_file in "$SSH_DIR"/*; do + if [ -f "$key_file" ] && [[ ! "$key_file" == *.pub ]] && [[ ! "$key_file" == *config* ]] && [[ ! "$key_file" == *known_hosts* ]]; then + # Skip if we already processed this key + basename_key=$(basename "$key_file") + already_processed=false + for pattern in "${KEY_PATTERNS[@]}"; do + if [[ "$basename_key" == "$pattern" ]] || [[ "$basename_key" == ${pattern}_* ]]; then + already_processed=true + break + fi + done + + if [ "$already_processed" = false ]; then + echo "Found potential key: $key_file" + ssh-add "$key_file" || echo "Warning: Failed to add $key_file" + KEYS_FOUND=$((KEYS_FOUND + 1)) + fi + fi +done + +if [ $KEYS_FOUND -eq 0 ]; then + echo "No SSH keys found in $SSH_DIR" + echo "You can create a new SSH key with: ssh-keygen -t ed25519 -C \"your_email@example.com\"" +else + echo "Processed $KEYS_FOUND SSH key(s)" + echo "" + echo "Current keys in SSH agent:" + ssh-add -l || echo "No keys currently loaded in SSH agent" +fi diff --git a/parts/features/apps/ssh/default.nix b/parts/features/apps/ssh/default.nix new file mode 100644 index 00000000..36e74d14 --- /dev/null +++ b/parts/features/apps/ssh/default.nix @@ -0,0 +1,37 @@ +{config, lib, ...}: let + cfg = config; +in { + flake.modules.homeManager.ssh = { + lib, + pkgs, + ... + }: let + ssh-add-all = pkgs.writeShellApplication { + name = "ssh-add-all"; + runtimeInputs = with pkgs; [openssh coreutils]; + text = builtins.readFile ./_scripts/ssh-add-all.sh; + }; + in { + home.persistence."/persist" = lib.mkIf cfg.dendrix.isImpermanent { + directories = [ + ".ssh" + ]; + }; + + home.packages = [ssh-add-all]; + + programs.ssh = { + enable = true; + enableDefaultConfig = false; + matchBlocks."*" = { + addKeysToAgent = "yes"; + }; + }; + + services.ssh-agent.enable = false; + + home.sessionVariables = { + SSH_AUTH_SOCK = "$XDG_RUNTIME_DIR/gcr/ssh"; + }; + }; +} diff --git a/parts/features/apps/xdg.nix b/parts/features/apps/xdg.nix new file mode 100644 index 00000000..16c065cc --- /dev/null +++ b/parts/features/apps/xdg.nix @@ -0,0 +1,60 @@ +{config, lib, ...}: let + cfg = config; +in { + flake.modules.homeManager.xdg = { + lib, + pkgs, + ... + }: { + home.persistence."/persist" = lib.mkIf cfg.dendrix.isImpermanent { + directories = [ + ".xournal" + ]; + }; + + home.packages = [ + pkgs.selectdefaultapplication + ]; + + home.sessionVariables = { + XDG_CONFIG_HOME = "/home/farlion/.config"; + }; + + home.preferXdgDirectories = true; + + xdg = { + mimeApps = { + associations = { + added = { + "x-scheme-handler/tg" = "org.telegram.desktop.desktop"; + }; + }; + enable = true; + defaultApplications = { + "application/pdf" = ["okular.desktop"]; + "applications/x-www-browser" = ["brave-browser.desktop"]; + "image/bmp" = ["oculante.desktop"]; + "image/gif" = ["oculante.desktop"]; + "image/jpeg" = ["oculante.desktop"]; + "image/png" = ["oculante.desktop"]; + "image/svg+xml" = ["oculante.desktop"]; + "image/tiff" = ["oculante.desktop"]; + "image/webp" = ["oculante.desktop"]; + "inode/directory" = ["lf.desktop"]; + "text/html" = ["brave-browser.desktop"]; + "text/plain" = ["nvim.desktop"]; + "x-scheme-handler/about" = ["brave-browser.desktop"]; + "x-scheme-handler/http" = ["brave-browser.desktop"]; + "x-scheme-handler/https" = ["brave-browser.desktop"]; + "x-scheme-handler/mailto" = ["brave-browser.desktop"]; + "x-scheme-handler/msteams" = ["teams-for-linux.desktop"]; + "x-scheme-handler/slack" = ["slack.desktop"]; + "x-scheme-handler/tg" = ["org.telegram.desktop.desktop"]; + "x-scheme-handler/tonsite" = ["org.telegram.desktop.desktop"]; + "x-scheme-handler/unknown" = ["brave-browser.desktop"]; + "x-scheme-handler/webcal" = ["brave-browser.desktop"]; + }; + }; + }; + }; +} diff --git a/parts/features/desktop/dunst.nix b/parts/features/desktop/dunst.nix new file mode 100644 index 00000000..6ab80f87 --- /dev/null +++ b/parts/features/desktop/dunst.nix @@ -0,0 +1,20 @@ +{...}: { + flake.modules.homeManager.dunst = {pkgs, ...}: { + services.dunst = { + enable = true; + + iconTheme = { + name = "Papirus-Dark"; + package = pkgs.papirus-icon-theme; + }; + + settings = { + global = { + browser = "brave"; + dmenu = "fuzzel --dmenu"; + follow = "mouse"; + }; + }; + }; + }; +} diff --git a/parts/features/desktop/fuzzel.nix b/parts/features/desktop/fuzzel.nix new file mode 100644 index 00000000..424709c8 --- /dev/null +++ b/parts/features/desktop/fuzzel.nix @@ -0,0 +1,8 @@ +{...}: { + flake.modules.homeManager.fuzzel = {pkgs, ...}: { + programs.fuzzel = { + enable = true; + package = pkgs.unstable.fuzzel; + }; + }; +} diff --git a/parts/features/desktop/waybar/_scripts/dunst-dnd-waybar.sh b/parts/features/desktop/waybar/_scripts/dunst-dnd-waybar.sh new file mode 100644 index 00000000..ca4fa2d2 --- /dev/null +++ b/parts/features/desktop/waybar/_scripts/dunst-dnd-waybar.sh @@ -0,0 +1,9 @@ +if dunstctl is-paused | grep -q "true"; then + state="dnd" +else + state="running" +fi + +count=$(dunstctl count waiting) + +printf '{"alt":"%s","text":%d,"class":"%s"}\n' "$state" "$count" "$state" diff --git a/parts/features/desktop/waybar/default.nix b/parts/features/desktop/waybar/default.nix new file mode 100644 index 00000000..fdfe967e --- /dev/null +++ b/parts/features/desktop/waybar/default.nix @@ -0,0 +1,575 @@ +{config, lib, ...}: let + cfg = config; +in { + flake.modules.homeManager.waybar = { + config, + lib, + pkgs, + ... + }: let + dunst-dnd-waybar = pkgs.writeShellApplication { + name = "dunst-dnd-waybar"; + runtimeInputs = [pkgs.dunst]; + text = builtins.readFile ./_scripts/dunst-dnd-waybar.sh; + }; + isNvidia = cfg.dendrix.hasNvidia; + isNumenor = cfg.dendrix.hostname == "numenor"; + isFlexbox = cfg.dendrix.hostname == "flexbox"; + + leftSection = { + modules-left = [ + "niri/workspaces" + ]; + }; + + centerSection = { + modules-center = [ + "systemd-failed-units" + "group/cpu" + "memory" + "disk" + "group/gpu" + "group/network" + "group/screens" + "group/audio" + "bluetooth" + "group/power" + ]; + + systemd-failed-units = { + format = " {nr_failed} failed"; + format-ok = " 0"; + hide-on-ok = false; + on-click = "alacritty --command journalctl --pager-end --catalog --boot --priority 3..3 | lnav"; + on-click-right = "alacritty --command isd"; + }; + + "group/cpu" = { + modules = [ + "cpu" + "temperature#cpu" + "custom/cpu-profile-toggler" + ]; + orientation = "inherit"; + }; + + cpu = { + format = " {usage}%"; + states = { + info = 80; + }; + on-click = "alacritty --command btop"; + on-click-right = "alacritty --command btop"; + }; + + "temperature#cpu" = { + critical-threshold = 90; + format = " {temperatureC}°C"; + on-click = "alacritty --command btop"; + on-click-right = "alacritty --command btop"; + hwmon-path = + if isNumenor + then "/sys/devices/pci0000:00/0000:00:18.3/hwmon/hwmon2/temp1_input" + else "/sys/devices/platform/coretemp.0/hwmon/hwmon7/temp1_input"; + }; + + "custom/cpu-profile-toggler" = { + format = "{icon}"; + format-icons = { + performance = ""; + powersave = ""; + }; + exec = "cpu-profile-toggler"; + on-click = "auto-cpufreq-gtk"; + on-click-middle = "cpu-profile-toggler --toggle"; + on-click-right = "cpu-profile-toggler --reset"; + return-type = "json"; + interval = 5; + }; + + memory = { + format = " {percentage}%"; + states = { + warning = 60; + critical = 80; + }; + on-click = "alacritty --command btop"; + on-click-right = "alacritty --command btop"; + tooltip-format = "{used:0.1f}GiB mem used, {swapUsed:0.1f}GiB swap used"; + }; + + disk = { + format = " {percentage_used}%"; + on-click = "alacritty --command ncdu /"; + on-click-right = "alacritty --command btop"; + states = { + warning = 60; + critical = 80; + }; + }; + + "group/gpu" = { + modules = + [ + ( + if isNvidia + then "custom/nvidia" + else "custom/gpu-usage" + ) + ] + ++ lib.optional (!isNvidia) "temperature#gpu"; + orientation = "inherit"; + }; + + "custom/gpu-usage" = { + exec = "cat /sys/class/hwmon/hwmon1/device/gpu_busy_percent"; + format = " {}%"; + return-type = ""; + interval = 1; + on-click = "alacritty --command nvtop"; + on-click-right = "alacritty --command nvtop"; + }; + + "custom/nvidia" = { + exec = "nvidia-smi --query-gpu=utilization.gpu,temperature.gpu --format=csv,nounits,noheader | sed 's/\\([0-9]\\+\\), \\([0-9]\\+\\)/\\1% \\2°C/g'"; + format = " {}"; + interval = 2; + on-click = "alacritty --command nvtop"; + on-click-right = "alacritty --command nvtop"; + }; + + "temperature#gpu" = { + critical-threshold = 90; + on-click = "alacritty --command nvtop"; + on-click-right = "alacritty --command nvtop"; + hwmon-path = + if isNumenor + then "/sys/devices/pci0000:00/0000:00:01.1/0000:01:00.0/0000:02:00.0/0000:03:00.0/hwmon/hwmon1/temp2_input" + else "TODO find me according to waybar docs similar to CPU temp hwmon path"; + }; + + "group/network" = { + modules = ["network" "network#tailscale" "custom/macgyver" "network#mullvad" "network#wireguard"]; + orientation = "inherit"; + }; + + "network" = { + interval = 3; + format = " "; + format-disconnected = " "; + format-ethernet = " "; + format-wifi = " "; + format-linked = " 🚧"; + format-alt = "{bandwidthDownBytes} {bandwidthUpBytes}"; + tooltip-format = "IF:{ifname} SSID:{essid} FREQ:{frequency} :{signalStrength} IP:{ipaddr} GW:{gwaddr} NM:{netmask} {bandwidthDownBytes} {bandwidthUpBytes}"; + tooltip-format-ethernet = "IF:{ifname} IP:{ipaddr} NM:{netmask} {bandwidthDownBytes} {bandwidthUpBytes}"; + tooltip-format-wifi = "IF:{ifname} SSID:{essid} FREQ:{frequency} :{signalStrength} IP:{ipaddr} GW:{gwaddr} NM:{netmask} {bandwidthDownBytes} {bandwidthUpBytes}"; + tooltip-format-linked = "IF:{ifname} IP:{ipaddr} Connected but no internet"; + on-click-right = "alacritty --command nmtui"; + }; + + "network#tailscale" = { + interface = "tailscale0"; + interval = 3; + format-linked = " "; + format = " "; + format-alt = " {bandwidthDownBytes} {bandwidthUpBytes}"; + tooltip-format = " Tailscale IP:{ipaddr} NM:{netmask} {bandwidthDownBytes} {bandwidthUpBytes}"; + tooltip-format-linked = " Tailscale down. Right click to connect."; + on-click-right = "tailscale up"; + on-click-middle = "tailscale down"; + }; + + "custom/macgyver" = { + exec = "macgyver-status"; + return-type = "json"; + interval = 3; + format = "{icon}"; + format-icons = { + up = ""; + down = ""; + error = "❌"; + }; + tooltip-format = " MacGyver is {text}"; + on-click-right = "sudo systemctl start macgyver"; + on-click-middle = "sudo systemctl stop macgyver"; + }; + + "network#mullvad" = { + interface = "wg0-mullvad"; + interval = 3; + format-disconnected = " "; + format-disabled = " "; + format-linked = " "; + format = " "; + format-alt = " {bandwidthDownBytes} {bandwidthUpBytes}"; + tooltip-format = " Mullvad IP:{ipaddr} NM:{netmask} {bandwidthDownBytes} {bandwidthUpBytes}"; + tooltip-format-linked = " Mullvad down. Right click to connect or double right click for GUI."; + tooltip-format-disabled = " Mullvad down. Rickt click to connect or double right click for GUI."; + on-click-right = "mullvad connect"; + on-double-click-right = "mullvad-gui"; + on-click-middle = "mullvad disconnect"; + }; + + "network#wireguard" = { + interface = "wg0"; + interval = 3; + format-disconnected = " "; + format-disabled = " "; + format-linked = " "; + format = " "; + format-alt = " {bandwidthDownBytes} {bandwidthUpBytes}"; + tooltip-format = " Wireguard IP:{ipaddr} GW:{gwaddr} NM:{netmask} {bandwidthDownBytes} {bandwidthUpBytes}"; + tooltip-format-linked = " Wireguard down."; + tooltip-format-disabled = " Wireguard down."; + }; + + "group/screens" = { + modules = + if isFlexbox + then ["backlight" "custom/wlsunset"] + else ["custom/ddc-backlight-left" "custom/ddc-backlight-middle" "custom/ddc-backlight-right" "custom/wlsunset"]; + orientation = "inherit"; + }; + + backlight = { + format = "{icon} {percent}%"; + format-icons = ["🌑" "🌘" "🌗" "🌖" "🌕"]; + }; + + "custom/ddc-backlight-left" = { + format = "{icon} "; + tooltip-format = "Left {percentage}%"; + format-icons = ["🌑" "🌘" "🌗" "🌖" "🌕"]; + exec = "ddc-backlight 7"; + exec-on-event = false; + on-scroll-up = "flock /tmp/ddc_backlight.lock ddcutil setvcp 10 + 5 -b 7"; + on-scroll-down = "flock /tmp/ddc_backlight.lock ddcutil setvcp 10 - 5 -b 7"; + on-click = "kanshictl switch numenor-movie"; + on-click-middle = "wdisplays"; + on-click-right = "kanshictl switch numenor"; + return-type = "json"; + interval = 60; + }; + + "custom/ddc-backlight-middle" = { + format = "{icon} "; + tooltip-format = "Middle {percentage}%"; + format-icons = ["🌑" "🌘" "🌗" "🌖" "🌕"]; + exec = "ddc-backlight 9"; + exec-on-event = false; + on-scroll-up = "flock /tmp/ddc_backlight.lock ddcutil setvcp 10 + 5 -b 9"; + on-scroll-down = "flock /tmp/ddc_backlight.lock ddcutil setvcp 10 - 5 -b 9"; + on-click = "kanshictl switch numenor-movie"; + on-click-middle = "wdisplays"; + on-click-right = "kanshictl switch numenor"; + return-type = "json"; + interval = 60; + }; + + "custom/ddc-backlight-right" = { + format = "{icon}"; + tooltip-format = "Right {percentage}%"; + format-icons = ["🌑" "🌘" "🌗" "🌖" "🌕"]; + exec = "ddc-backlight 6"; + exec-on-event = false; + on-scroll-up = "flock /tmp/ddc_backlight.lock ddcutil setvcp 10 + 5 -b 6"; + on-scroll-down = "flock /tmp/ddc_backlight.lock ddcutil setvcp 10 - 5 -b 6"; + on-click = "kanshictl switch numenor-movie"; + on-click-middle = "wdisplays"; + on-click-right = "kanshictl switch numenor"; + return-type = "json"; + interval = 60; + }; + + "custom/wlsunset" = { + interval = 1; + exec = "if pgrep wlsunset >/dev/null 2>&1; then stdbuf -oL printf '{\"alt\": \"on\",\"class\": \"on\"}'; else stdbuf -oL printf '{\"alt\": \"off\",\"class\": \"off\"}'; fi"; + on-click = "wlsunset-waybar"; + return-type = "json"; + format = " {icon}"; + tooltip-format = "wlsunset: {alt}"; + signal = 1; + format-icons = { + on = ""; + off = ""; + }; + }; + + "group/audio" = { + modules = [ + "pulseaudio#in" + "pulseaudio#out" + "mpris" + ]; + orientation = "inherit"; + }; + + "pulseaudio#in" = { + format = "{format_source}"; + format-source = " {volume}%"; + format-source-muted = ""; + format-icons = { + "bluez_input.DC:69:E2:9A:6E:30" = ""; + "alsa_input.usb-Apple__Inc._USB-C_to_3.5mm_Headphone_Jack_Adapter_DWH84440324JKLTA7-00.mono-fallback" = ""; + default = ["" ""]; + }; + max-volume = 200; + scroll-step = 5; + on-scroll-up = "pactl set-source-volume @DEFAULT_SOURCE@ +5%"; + on-scroll-down = "pactl set-source-volume @DEFAULT_SOURCE@ -5%"; + on-click = "pavucontrol --tab=4"; + on-click-right = "alacritty --command pulsemixer"; + on-click-middle = "pactl set-source-mute @DEFAULT_SOURCE@ toggle"; + tooltip-format = "{format_source}"; + }; + + "pulseaudio#out" = { + format = "{icon} {volume}%"; + format-bluetooth = "{icon} {volume}%"; + format-muted = ""; + format-icons = { + "alsa_output.usb-Generic_USB_Audio-00.analog-stereo" = ""; + "alsa_output.usb-Lenovo_ThinkPad_Thunderbolt_3_Dock_USB_Audio_000000000000-00.analog-stereo" = ""; + "bluez_output.14_3F_A6_28_DC_51.1" = ""; + "alsa_output.pci-0000_03_00.1.hdmi-stereo-extra3" = "🍿"; + "bluez_output.DC_69_E2_9A_6E_30.1" = ""; + "bluez_sink.DC_69_E2_9A_6E_30.handsfree_head_unit" = ""; + "alsa_output.pci-0000_00_1f.3-platform-sof_sdw.HiFi___ucm0003.hw_sofsoundwire_2__sink" = ""; + "alsa_output.pci-0000_00_1f.3-platform-sof_sdw.HiFi___ucm0005.hw_sofsoundwire_2__sink" = ""; + "alsa_output.pci-0000_00_1f.3-platform-sof_sdw.HiFi___ucm0007.hw_sofsoundwire_2__sink" = ""; + "alsa_output.pci-0000_00_1f.3-platform-sof_sdw.HiFi__hw_sofsoundwire_2__sink" = ""; + "alsa_output.pci-0000_00_1f.3-platform-sof_sdw.HiFi__Speaker__sink" = ""; + "alsa_output.pci-0000_00_1f.3-platform-sof_sdw.HiFi__hw_sofsoundwire__sink" = ""; + "alsa_output.usb-Apple__Inc._USB-C_to_3.5mm_Headphone_Jack_Adapter_DWH84440324JKLTA7-00.analog-stereo" = ""; + "bluez_output.34_E3_FB_C5_01_E0.1" = ""; + "bluez_sink.34_E3_FB_C5_01_E0.handsfree_head_unit" = ""; + default = ["" ""]; + }; + max-volume = 200; + on-click = "pavucontrol --tab=3"; + on-click-right = "alacritty --command pulsemixer"; + on-click-middle = "pactl set-sink-mute @DEFAULT_SINK@ toggle"; + ignored-sinks = ["Easy Effects Sink"]; + }; + + mpris = { + format = "{player_icon}"; + format-paused = "{status_icon}"; + on-click-right = ''niri msg action focus-window --id $(niri msg --json windows | jq -r '.[] | select(.app_id == "YouTube Music Desktop App") | .id')''; + player-icons = { + default = "▶"; + mpv = ""; + chromium = ""; + }; + status-icons = { + paused = "⏸"; + }; + }; + + bluetooth = { + format = "{icon}"; + format-connected = "{icon} {num_connections}"; + format-connnected-battery = "{icon} {num_connections} {device_battery_percentage}%"; + format-icons = { + connected = ""; + on = ""; + off = ""; + disabled = ""; + disconnected = ""; + default = ""; + }; + on-click = "bluetoothctl power on"; + on-click-right = "bluetoothctl power off"; + on-click-middle = "blueman-manager"; + tooltip-format = "{status} {num_connections}"; + }; + + "group/power" = { + modules = [ + "battery" + ]; + orientation = "inherit"; + }; + + battery = { + events = { + on-discharging-warning = "notify-send -u normal 'Low Battery'"; + on-discharging-critical = "notify-send -u critical 'Very Low Battery'"; + on-charging-100 = "notify-send -u normal 'Battery is full'"; + }; + states = { + warning = 30; + critical = 15; + }; + format = " {icon} {capacity}%"; + format-icons = ["" "" "" "" ""]; + tooltip = true; + backend = "upower"; + }; + }; + + rightSection = { + modules-right = [ + "privacy" + "custom/dunst-dnd" + "custom/caffeinate" + "niri/language" + "clock" + "tray" + ]; + + "custom/dunst-dnd" = { + exec = "${dunst-dnd-waybar}/bin/dunst-dnd-waybar"; + return-type = "json"; + interval = 1; + format = "{icon}{text}"; + tooltip-format = "{text}"; + format-icons = { + running = ""; + dnd = ""; + }; + on-click = "dunstctl set-paused toggle"; + on-click-right = "dunstctl set-paused false"; + }; + + "custom/caffeinate" = { + exec = "if systemctl --user is-active swayidle >/dev/null 2>&1; then echo '{\"alt\": \"deactivated\", \"class\": \"deactivated\"}'; else echo '{\"alt\": \"activated\", \"class\": \"activated\"}'; fi"; + return-type = "json"; + interval = 1; + format = " {icon}"; + format-icons = { + activated = ""; + deactivated = ""; + }; + on-click = "systemctl --user stop swayidle"; + on-click-right = "systemctl --user start swayidle"; + on-click-middle = "systemctl --user start swayidle"; + }; + + "niri/language" = { + format = "{short}"; + on-click = "niri msg action switch-layout next"; + on-click-right = "niri msg action switch-layout prev"; + on-click-middle = "niri msg action switch-layout 0"; + }; + + clock = { + format = "{:%H:%M}"; + format-alt = "{:%A, %B %d, %Y (%R)} "; + tooltip-format = "{calendar}"; + calendar = { + mode = "year"; + mode-mon-col = 3; + weeks-pos = "right"; + on-scroll = 1; + format = { + months = "{}"; + days = "{}"; + weeks = "W{}"; + weekdays = "{}"; + today = "{}"; + }; + }; + actions = { + on-click-right = "mode"; + on-scroll-up = "shift_up"; + on-scroll-down = "shift_down"; + }; + on-click-middle = "brave calendar.google.com"; + }; + + tray = { + show-passive-items = true; + spacing = 3; + }; + }; + in { + programs.waybar = { + enable = true; + settings = { + main = + { + layer = "top"; + position = "bottom"; + expand-center = true; + output = [ + "DP-1" + "eDP-1" + ]; + } + // leftSection // centerSection // rightSection; + + aux = + { + layer = "top"; + position = "bottom"; + output = [ + "HDMI-A-1" + "HDMI-A-2" + ]; + } + // leftSection // rightSection; + }; + + style = '' + .info { + color: @base0D; + } + .critical { + color: @base08; + } + .warning { + color: @base0A; + } + + #systemd-failed-units.degraded { + color: @base08; + } + + #network.ethernet, + #network.wifi { + color: @base0B; + } + + #custom-dunst-dnd.dnd { + color: @base0A; + } + + #custom-macgyver.up { + color: @base0B; + } + + #custom-wlsunset.off { + color: @base0A; + } + + #custom-caffeinate.activated { + color: @base0A; + } + + #language:not(.us) { + color: @base0A; + } + + /* Can remove once https://github.com/nix-community/stylix/pull/1919 is merged */ + tooltip label { + color: @base05; + } + ''; + + systemd = { + enable = true; + enableDebug = false; + enableInspect = false; + }; + }; + + systemd.user.services.waybar = { + Service.Environment = lib.mkForce "PATH=/run/wrappers/bin:${config.home.profileDirectory}/bin:/run/current-system/sw/bin"; + Install.WantedBy = lib.mkForce ["niri.service"]; + Unit.Requires = ["niri.service"]; + Unit.After = ["niri.service"]; + }; + }; +} diff --git a/parts/features/dev/aider.nix b/parts/features/dev/aider.nix new file mode 100644 index 00000000..662bcda1 --- /dev/null +++ b/parts/features/dev/aider.nix @@ -0,0 +1,7 @@ +{...}: { + flake.modules.homeManager.aider = {...}: { + programs.aider-chat = { + enable = true; + }; + }; +} diff --git a/parts/features/dev/claude-code/CLAUDE.md b/parts/features/dev/claude-code/CLAUDE.md new file mode 100644 index 00000000..0f5c0d8d --- /dev/null +++ b/parts/features/dev/claude-code/CLAUDE.md @@ -0,0 +1,17 @@ +- Comment code sparsely, and only where it adds true novel context to the code being executed. This is an example of superfluous commenting: +```rust + // Set current carrier in the database to track it in the logic module + CurrentCarrierRepository::set(ctx.tx(), carrier_number) + .await + .context("Failed to set current carrier")?; +``` +A comment like this would be a sign that the function naming (CurrentCarrierRepository::set) is not clear enough in the context and should be refactored instead. +Extensive File and function headers are still useful to give context. +- Apply the "Small Functions" practice: functions should be small, stay at a single level of abstraction and extract helper functions with intention-revealing names so the code reads clearly without needing comments. +- Apply the "step-down" rule: Top level reads like a story, details pushed into well-named helpers. Helpers should live below their main functions/tests wherever possible, reading like a newspaper (headlines first, details later). +* When good tests exists, prefer TDD. +- Make a `jj commit` at the end of your changes: Don't include the "Created with Claude Code" and "Co-Authored-by" lines. Also keep commits short and to the point. Use conventional-commits (such as perf, feat...etc) for commit headings. Put the subject in parentheses, i.e. `feat(logic-module): add X operation` or `chore(clippy): add a lint` +- `jj commit` does not have an `--amend` option - instead try `jj absorb` and if that doesn't find the right target then use `jj squash` to squash changes into the latest commit and then re-describe that commit as needed. +- Use `jj` instead of `git` for all version control operations +- For opening PRs on github, since jj does not map directly to git branches, first push the new bookmark with jj and then use `gh pr create --head --base main ...` +- When offering to open Github PRs, open them in draft mode and do not include a "Generated with Claude" line, nor a `## Test Plan` section unless the Test Plan is core to this specific PR. diff --git a/parts/features/dev/claude-code/default.nix b/parts/features/dev/claude-code/default.nix new file mode 100644 index 00000000..610e5ee0 --- /dev/null +++ b/parts/features/dev/claude-code/default.nix @@ -0,0 +1,54 @@ +{config, lib, ...}: let + cfg = config; +in { + flake.modules.homeManager.claude-code = { + lib, + pkgs, + ... + }: { + home.persistence."/persist" = lib.mkIf cfg.dendrix.isImpermanent { + directories = [ + ".claude" + ".cache/claude-cli-nodejs" + ]; + files = [ + ".claude.json" + ]; + }; + + programs.claude-code = { + enable = true; + package = pkgs.unstable.claude-code; + + memory.source = ./CLAUDE.md; + + settings = { + permissions = { + allow = [ + "Bash(jj log:*)" + "Bash(jj diff:*)" + "Bash(jj status)" + "Grep" + "WebFetch(domain:github.com)" + "WebSearch" + ]; + deny = [ + "Read(./.env)" + "Read(./.env.*)" + "Read(./secrets/secrets.json)" + "Read(./config/credentials.json)" + ]; + }; + alwaysThinkingEnabled = true; + }; + }; + + programs.alacritty.settings.keyboard.bindings = [ + { + key = "Return"; + mods = "Shift"; + chars = "\n"; + } + ]; + }; +} diff --git a/parts/features/dev/jujutsu.nix b/parts/features/dev/jujutsu.nix new file mode 100644 index 00000000..41f5d596 --- /dev/null +++ b/parts/features/dev/jujutsu.nix @@ -0,0 +1,64 @@ +{...}: { + flake.modules.homeManager.jujutsu = {pkgs, ...}: { + programs.difftastic.enable = true; + programs.jjui = { + enable = true; + package = pkgs.unstable.jjui; + }; + programs.jujutsu = { + enable = true; + package = pkgs.unstable.jujutsu; + settings = { + remotes.origin.auto-track-bookmarks = "main"; + ui.diff-formatter = ["difft" "--color=always" "$left" "$right"]; + user = { + email = "4farlion@gmail.com"; + name = "workflow"; + }; + signing = { + backend = "gpg"; + key = "24575DB93F6CEC16"; + behavior = "own"; + }; + aliases = { + bt = ["bookmark" "track"]; + c = ["commit"]; + init = ["git" "init" "--colocate"]; + push = [ + "util" + "exec" + "--" + "bash" + "-c" + '' + set -e + + # Check if current commit has both description and changes + has_description=$(jj log -r @ --no-graph --color never -T 'description' | grep -q . && echo "yes" || echo "no") + # Use 'empty' template keyword to check if commit has changes + has_changes=$(jj log -r @ --no-graph --color never -T 'empty' | grep -q "false" && echo "yes" || echo "no") + + if [ "$has_description" = "yes" ] && [ "$has_changes" = "yes" ]; then + echo "Current commit has description and changes, creating new commit..." + jj new + fi + + # Get the bookmark from the parent commit directly + bookmark=$(jj log -r 'ancestors(@) & bookmarks()' -n 1 --no-graph --color never -T 'bookmarks' | sed 's/\*$//' | tr -d ' ') + + if [ -z "$bookmark" ]; then + echo "No bookmark found on parent commit" + exit 1 + fi + + echo "Moving bookmark '$bookmark' to parent commit and pushing..." + jj bookmark set "$bookmark" -r @- + jj git fetch + jj git push --bookmark "$bookmark" --allow-new + '' + ]; + }; + }; + }; + }; +} From 3025c7b49a3df0f9ea470c6765f049e153aa35e0 Mon Sep 17 00:00:00 2001 From: workflow <4farlion@gmail.com> Date: Fri, 30 Jan 2026 23:55:04 +0000 Subject: [PATCH 09/26] feat(dendritic): bulk migrate apps and desktop features (batch 2) --- parts/features/apps/brave-browser.nix | 54 +++ parts/features/apps/discord.nix | 15 + parts/features/apps/lf/_pistol/pistol.conf | 1 + parts/features/apps/lf/default.nix | 419 ++++++++++++++++++ parts/features/apps/mpv.nix | 20 + parts/features/apps/obsidian.nix | 20 + parts/features/apps/signal.nix | 19 + parts/features/apps/telegram.nix | 19 + .../features/dev/k9s/_skins/gruvbox-dark.yaml | 102 +++++ .../dev/k9s/_skins/gruvbox-light.yaml | 104 +++++ parts/features/dev/k9s/default.nix | 25 ++ 11 files changed, 798 insertions(+) create mode 100644 parts/features/apps/brave-browser.nix create mode 100644 parts/features/apps/discord.nix create mode 100644 parts/features/apps/lf/_pistol/pistol.conf create mode 100644 parts/features/apps/lf/default.nix create mode 100644 parts/features/apps/mpv.nix create mode 100644 parts/features/apps/obsidian.nix create mode 100644 parts/features/apps/signal.nix create mode 100644 parts/features/apps/telegram.nix create mode 100644 parts/features/dev/k9s/_skins/gruvbox-dark.yaml create mode 100644 parts/features/dev/k9s/_skins/gruvbox-light.yaml create mode 100644 parts/features/dev/k9s/default.nix diff --git a/parts/features/apps/brave-browser.nix b/parts/features/apps/brave-browser.nix new file mode 100644 index 00000000..fe3c5c5a --- /dev/null +++ b/parts/features/apps/brave-browser.nix @@ -0,0 +1,54 @@ +{config, lib, ...}: let + cfg = config; +in { + flake.modules.homeManager.brave-browser = { + lib, + pkgs, + ... + }: let + isNvidia = cfg.dendrix.hasNvidia; + braveNiriOpen = pkgs.writeShellApplication { + name = "brave-niri-open"; + runtimeInputs = [pkgs.niri pkgs.jq pkgs.coreutils pkgs.brave]; + text = '' + #!/usr/bin/env bash + set -euo pipefail + brave_id=$(niri msg --json windows | jq -r '.[] | select(.app_id == "brave-browser") | .id' | head -n1 || true) + if [ -n "''${brave_id:-}" ]; then + niri msg action focus-window --id "$brave_id" >/dev/null 2>&1 || true + fi + exec ${pkgs.brave}/bin/brave ${ + if isNvidia + then "--enable-features=VaapiVideoDecoder,VaapiVideoEncoder --password-store=seahorse" + else "--password-store=seahorse" + } "$@" + ''; + }; + in { + home.persistence."/persist" = lib.mkIf cfg.dendrix.isImpermanent { + directories = [ + ".config/BraveSoftware" + ".cache/BraveSoftware" + ]; + }; + + home.packages = [ + pkgs.brave + ]; + + xdg.desktopEntries = { + brave-browser = { + exec = "${braveNiriOpen}/bin/brave-niri-open %U"; + name = "Brave Browser"; + comment = "Access the Internet"; + genericName = "Web Browser"; + categories = ["Network" "WebBrowser"]; + icon = "brave-browser"; + mimeType = ["application/pdf" "application/rdf+xml" "application/rss+xml" "application/xhtml+xml" "application/xhtml_xml" "application/xml" "image/gif" "image/jpeg" "image/png" "image/webp" "text/html" "text/xml" "x-scheme-handler/http" "x-scheme-handler/https" "x-scheme-handler/ipfs" "x-scheme-handler/ipns"]; + startupNotify = true; + terminal = false; + type = "Application"; + }; + }; + }; +} diff --git a/parts/features/apps/discord.nix b/parts/features/apps/discord.nix new file mode 100644 index 00000000..1d4ee82b --- /dev/null +++ b/parts/features/apps/discord.nix @@ -0,0 +1,15 @@ +{config, lib, ...}: let + cfg = config; +in { + flake.modules.homeManager.discord = {lib, ...}: { + home.persistence."/persist" = lib.mkIf cfg.dendrix.isImpermanent { + directories = [ + ".config/discord" + ]; + }; + + programs.discord = { + enable = true; + }; + }; +} diff --git a/parts/features/apps/lf/_pistol/pistol.conf b/parts/features/apps/lf/_pistol/pistol.conf new file mode 100644 index 00000000..9f63d568 --- /dev/null +++ b/parts/features/apps/lf/_pistol/pistol.conf @@ -0,0 +1 @@ +image/* sh: chafa --fill=block --symbols=block -s 80x80 "%pistol-filename%" || exit 1 diff --git a/parts/features/apps/lf/default.nix b/parts/features/apps/lf/default.nix new file mode 100644 index 00000000..3364fda0 --- /dev/null +++ b/parts/features/apps/lf/default.nix @@ -0,0 +1,419 @@ +{config, lib, ...}: let + cfg = config; +in { + flake.modules.homeManager.lf = { + lib, + pkgs, + ... + }: let + dlfile = pkgs.writers.writeBashBin "dlfile" '' + url=$(dragon -t -x) + + if [ -n "$url" ]; then + printf "File Name: " + name="" + while [ -z $name ] || [ -e $name ] + do + read -r name + if [ -e "$name" ]; then + printf "File already exists, overwrite (y|n): " + read -r ans + + if [ "$ans" = "y" ]; then + break + else + printf "File Name: " + fi + fi + done + + # Download the file with curl + [ -n "$name" ] && curl -o "$name" "$url" || exit 1 + else + exit 1 + fi + ''; + in { + home.persistence."/persist" = lib.mkIf cfg.dendrix.isImpermanent { + directories = [ + ".local/share/lf" + ]; + }; + + home.packages = with pkgs; [ + chafa + dlfile + imagemagick + pistol + ripdrag + ]; + + home.file = { + ".config/pistol/pistol.conf".source = ./_pistol/pistol.conf; + }; + + programs.lf = { + enable = true; + + commands = { + archive = '' + ''${{ + tar --create --xz --file="$PWD/$(basename "$f").tar.xz" "$f" + }} + ''; + + chmod = '' + ''${{ + printf "Mode Bits: " + read ans + + for file in "$fx" + do + chmod $ans $file + done + + lf -remote 'send reload' + }} + ''; + + dlfile = "%dlfile"; + dragon = "%ripdrag -a $fx"; + + mkdir = '' + ''${{ + printf "Directory Name: " + read ans + mkdir $ans + }} + ''; + + mkfile = '' + ''${{ + printf "File Name: " + read ans + $EDITOR $ans + }} + ''; + + paste-image = '' + ''${{ + printf "File Name (e.g., image.png): " + read ans + + if [ -z "$ans" ]; then + echo "No filename provided" + exit 1 + fi + + if [ -e "$ans" ]; then + printf "File already exists, overwrite (y|n): " + read overwrite + if [ "$overwrite" != "y" ]; then + exit 1 + fi + fi + + wl-paste > "$ans" + if [ $? -eq 0 ]; then + echo "Pasted clipboard content to $ans" + else + echo "Failed to paste from clipboard" + fi + }} + ''; + + open = '' + ''${{ + case $(file --mime-type "$f" -bL) in + text/*|application/json) $EDITOR "$f";; + video/*|image/*/application/pdf) xdg-open "$f";; + *) xdg-open "$f";; + esac + }} + ''; + + quit-and-cd = '' + &{{ + pwd > $LF_CD_FILE + lf -remote "send $id quit" + }} + ''; + + sudomkfile = '' + ''${{ + printf "File Name: " + read ans + sudo $EDITOR $ANS + }} + ''; + + trash = '' + ''${{ + files=$(printf "$fx" | tr '\n' ';') + while [ "$files" ]; do + # extract the substring from start of string up to delimiter. + # this is the first "element" of the string. + file=''${files%%;*} + + trash-put "$(basename "$file")" + # if there's only one element left, set `files` to an empty string. + # this causes us to exit this `while` loop. + # else, we delete the first "element" of the string from files, and move onto the next. + if [ "$files" = "$file" ]; then + files=''' + else + files="''${files#*;}" + fi + done + }} + ''; + + unarchive = '' + ''${{ + case "$f" in + *.zip) unzip "$f";; + *.tar.gz) tar -xzvf "$f" ;; + *.tar.bz2) tar -xjvf "$f" ;; + *.tar) tar -xvf "$f" ;; + *) echo "Unsupported format" ;; + esac + }} + ''; + + yank-file = ''$printf '%s' "$f" | wl-copy''; + yank-paths = ''$printf '%s' "$fx" | wl-copy''; + yank-dirname = ''&printf '%s' "$PWD" | wl-copy''; + yank-basename = ''&basename -a -- $fx | head -c-1 | wl-copy''; + yank-basename-without-extension = ''&basename -a -- $fx | sed -E 's/\.[^.]+$//' | head -c-1 | wl-copy''; + + yank-image = '' + ''${{ + # Copy the first selected file's binary content to clipboard as PNG + # Many apps only accept PNG from clipboard on Wayland + file="$(echo "$fx" | head -n1)" + mime_type="$(file --mime-type -b "$file")" + + if [[ "$mime_type" == image/png ]]; then + # Already PNG, copy directly + wl-copy -t image/png < "$file" + else + # Convert to PNG first for compatibility + convert "$file" png:- | wl-copy -t image/png + fi + }} + ''; + + z = '' + %{{ + result="$(zoxide query --exclude $PWD $@ | sed 's/\\/\\\\/g;s/"/\\"/g')" + lf -remote "send $id cd \"$result\"" + }} + ''; + + zi = '' + ''${{ + result="$(zoxide query -i | sed 's/\\/\\\\/g;s/"/\\"/g')" + lf -remote "send $id cd \"$result\"" + }} + ''; + }; + + keybindings = { + "." = "set hidden!"; + d = null; + dd = "trash"; + dl = "dlfile"; + dr = "dragon"; + f = "zi"; + h = "chmod"; + k = "down"; + l = "up"; + ";" = "open"; + j = "updir"; + m = null; + md = "mkdir"; + mf = "mkfile"; + mr = "sudomkfile"; + mp = "paste-image"; + Q = "quit-and-cd"; + x = "cut"; + Y = "yank-image"; + }; + + previewer = { + keybinding = "i"; + source = "${pkgs.pistol}/bin/pistol"; + }; + + settings = { + icons = true; + ifs = "\n"; + }; + }; + + home.sessionVariables = { + LF_ICONS = '' + tw=:\ + st=:\ + ow=:\ + dt=:\ + di=:\ + fi=:\ + ln=:\ + or=:\ + ex=:\ + *.c=:\ + *.cc=:\ + *.clj=:\ + *.coffee=:\ + *.cpp=:\ + *.css=:\ + *.d=:\ + *.dart=:\ + *.erl=:\ + *.exs=:\ + *.fs=:\ + *.go=:\ + *.h=:\ + *.hh=:\ + *.hpp=:\ + *.hs=:\ + *.html=:\ + *.java=:\ + *.jl=:\ + *.js=:\ + *.json=:\ + *.lua=:\ + *.md=:\ + *.php=:\ + *.pl=:\ + *.pro=:\ + *.py=:\ + *.rb=:\ + *.rs=:\ + *.scala=:\ + *.ts=:\ + *.vim=:\ + *.cmd=:\ + *.ps1=:\ + *.sh=:\ + *.bash=:\ + *.zsh=:\ + *.fish=:\ + *.tar=:\ + *.tgz=:\ + *.arc=:\ + *.arj=:\ + *.taz=:\ + *.lha=:\ + *.lz4=:\ + *.lzh=:\ + *.lzma=:\ + *.tlz=:\ + *.txz=:\ + *.tzo=:\ + *.t7z=:\ + *.zip=:\ + *.z=:\ + *.dz=:\ + *.gz=:\ + *.lrz=:\ + *.lz=:\ + *.lzo=:\ + *.xz=:\ + *.zst=:\ + *.tzst=:\ + *.bz2=:\ + *.bz=:\ + *.tbz=:\ + *.tbz2=:\ + *.tz=:\ + *.deb=:\ + *.rpm=:\ + *.jar=:\ + *.war=:\ + *.ear=:\ + *.sar=:\ + *.rar=:\ + *.alz=:\ + *.ace=:\ + *.zoo=:\ + *.cpio=:\ + *.7z=:\ + *.rz=:\ + *.cab=:\ + *.wim=:\ + *.swm=:\ + *.dwm=:\ + *.esd=:\ + *.jpg=:\ + *.jpeg=:\ + *.mjpg=:\ + *.mjpeg=:\ + *.gif=:\ + *.bmp=:\ + *.pbm=:\ + *.pgm=:\ + *.ppm=:\ + *.tga=:\ + *.xbm=:\ + *.xpm=:\ + *.tif=:\ + *.tiff=:\ + *.png=:\ + *.svg=:\ + *.svgz=:\ + *.mng=:\ + *.pcx=:\ + *.mov=:\ + *.mpg=:\ + *.mpeg=:\ + *.m2v=:\ + *.mkv=:\ + *.webm=:\ + *.ogm=:\ + *.mp4=:\ + *.m4v=:\ + *.mp4v=:\ + *.vob=:\ + *.qt=:\ + *.nuv=:\ + *.wmv=:\ + *.asf=:\ + *.rm=:\ + *.rmvb=:\ + *.flc=:\ + *.avi=:\ + *.fli=:\ + *.flv=:\ + *.gl=:\ + *.dl=:\ + *.xcf=:\ + *.xwd=:\ + *.yuv=:\ + *.cgm=:\ + *.emf=:\ + *.ogv=:\ + *.ogx=:\ + *.aac=:\ + *.au=:\ + *.flac=:\ + *.m4a=:\ + *.mid=:\ + *.midi=:\ + *.mka=:\ + *.mp3=:\ + *.mpc=:\ + *.ogg=:\ + *.ra=:\ + *.wav=:\ + *.oga=:\ + *.opus=:\ + *.spx=:\ + *.xspf=:\ + *.pdf=:\ + *.nix=: + ''; + }; + }; +} diff --git a/parts/features/apps/mpv.nix b/parts/features/apps/mpv.nix new file mode 100644 index 00000000..63f43290 --- /dev/null +++ b/parts/features/apps/mpv.nix @@ -0,0 +1,20 @@ +{config, lib, ...}: let + cfg = config; +in { + flake.modules.homeManager.mpv = { + lib, + pkgs, + ... + }: { + home.persistence."/persist" = lib.mkIf cfg.dendrix.isImpermanent { + directories = [ + ".config/mpv" + ".cache/mpv" + ]; + }; + + home.packages = [ + pkgs.mpv + ]; + }; +} diff --git a/parts/features/apps/obsidian.nix b/parts/features/apps/obsidian.nix new file mode 100644 index 00000000..cc08645d --- /dev/null +++ b/parts/features/apps/obsidian.nix @@ -0,0 +1,20 @@ +{config, lib, ...}: let + cfg = config; +in { + flake.modules.homeManager.obsidian = { + lib, + pkgs, + ... + }: { + home.persistence."/persist" = lib.mkIf cfg.dendrix.isImpermanent { + directories = [ + ".config/obsidian" + "Obsidian" + ]; + }; + + home.packages = [ + pkgs.obsidian + ]; + }; +} diff --git a/parts/features/apps/signal.nix b/parts/features/apps/signal.nix new file mode 100644 index 00000000..e46f08ed --- /dev/null +++ b/parts/features/apps/signal.nix @@ -0,0 +1,19 @@ +{config, lib, ...}: let + cfg = config; +in { + flake.modules.homeManager.signal = { + lib, + pkgs, + ... + }: { + home.persistence."/persist" = lib.mkIf cfg.dendrix.isImpermanent { + directories = [ + ".config/Signal" + ]; + }; + + home.packages = [ + pkgs.signal-desktop + ]; + }; +} diff --git a/parts/features/apps/telegram.nix b/parts/features/apps/telegram.nix new file mode 100644 index 00000000..c2a47450 --- /dev/null +++ b/parts/features/apps/telegram.nix @@ -0,0 +1,19 @@ +{config, lib, ...}: let + cfg = config; +in { + flake.modules.homeManager.telegram = { + lib, + pkgs, + ... + }: { + home.persistence."/persist" = lib.mkIf cfg.dendrix.isImpermanent { + directories = [ + ".local/share/TelegramDesktop" + ]; + }; + + home.packages = [ + pkgs.telegram-desktop + ]; + }; +} diff --git a/parts/features/dev/k9s/_skins/gruvbox-dark.yaml b/parts/features/dev/k9s/_skins/gruvbox-dark.yaml new file mode 100644 index 00000000..3724404b --- /dev/null +++ b/parts/features/dev/k9s/_skins/gruvbox-dark.yaml @@ -0,0 +1,102 @@ +# K9s Gruvbox Dark Skin +# Author: [@indiebrain](https://github.com/indiebrain) + +foreground: &foreground "#ebdbb2" +background: &background "#272727" +current_line: ¤t_line "#ebdbb2" +selection: &selection "#3c3735" +comment: &comment "#bdad93" +cyan: &cyan "#689d69" +green: &green "#989719" +orange: &orange "#d79920" +magenta: &magenta "#b16185" +blue: &blue "#448488" +red: &red "#cc231c" + +k9s: + body: + fgColor: *foreground + bgColor: *background + logoColor: *blue + prompt: + fgColor: *foreground + bgColor: *background + suggestColor: *orange + info: + fgColor: *magenta + sectionColor: *foreground + help: + fgColor: *foreground + bgColor: *background + keyColor: *magenta + numKeyColor: *blue + sectionColor: *green + dialog: + fgColor: *foreground + bgColor: *background + buttonFgColor: *foreground + buttonBgColor: *magenta + buttonFocusFgColor: white + buttonFocusBgColor: *cyan + labelFgColor: *orange + fieldFgColor: *foreground + frame: + border: + fgColor: *selection + focusColor: *current_line + menu: + fgColor: *foreground + keyColor: *magenta + numKeyColor: *magenta + crumbs: + fgColor: *foreground + bgColor: *comment + activeColor: *blue + status: + newColor: *cyan + modifyColor: *blue + addColor: *green + errorColor: *red + highlightColor: *orange + killColor: *comment + completedColor: *comment + title: + fgColor: *foreground + bgColor: *background + highlightColor: *orange + counterColor: *blue + filterColor: *magenta + views: + charts: + bgColor: background + defaultDialColors: + - *blue + - *red + defaultChartColors: + - *blue + - *red + table: + fgColor: *foreground + bgColor: *background + cursorFgColor: "#fff" + cursorBgColor: *current_line + header: + fgColor: *foreground + bgColor: *background + sorterColor: *selection + xray: + fgColor: *foreground + bgColor: *background + cursorColor: *current_line + graphicColor: *blue + showIcons: false + yaml: + keyColor: *magenta + colonColor: *blue + valueColor: *foreground + logs: + fgColor: *foreground + bgColor: *background + indicator: + fgColor: *foreground + bgColor: *background diff --git a/parts/features/dev/k9s/_skins/gruvbox-light.yaml b/parts/features/dev/k9s/_skins/gruvbox-light.yaml new file mode 100644 index 00000000..554cf28a --- /dev/null +++ b/parts/features/dev/k9s/_skins/gruvbox-light.yaml @@ -0,0 +1,104 @@ +# K9s Gruvbox Light Skin +# Author: [@indiebrain](https://github.com/indiebrain) + +foreground: &foreground "#3c3735" +background: &background "#fbf1c7" +current_line: ¤t_line "#ebdbb2" +selection: &selection "#3c3735" +comment: &comment "#bdad93" +cyan: &cyan "#689d69" +green: &green "#989719" +orange: &orange "#d79920" +magenta: &magenta "#b16185" +blue: &blue "#448488" +red: &red "#cc231c" + +k9s: + body: + fgColor: *foreground + bgColor: *background + logoColor: *blue + prompt: + fgColor: *foreground + bgColor: *background + suggestColor: *orange + info: + fgColor: *magenta + sectionColor: *foreground + help: + fgColor: *foreground + bgColor: *background + keyColor: *magenta + numKeyColor: *blue + sectionColor: *green + dialog: + fgColor: *foreground + bgColor: *background + buttonFgColor: *foreground + buttonBgColor: *magenta + buttonFocusFgColor: white + buttonFocusBgColor: *cyan + labelFgColor: *orange + fieldFgColor: *foreground + frame: + border: + fgColor: *selection + focusColor: *current_line + menu: + fgColor: *foreground + keyColor: *magenta + numKeyColor: *magenta + crumbs: + fgColor: *foreground + bgColor: *comment + activeColor: *blue + status: + newColor: *cyan + modifyColor: *blue + addColor: *green + errorColor: *red + highlightColor: *orange + killColor: *comment + completedColor: *comment + title: + fgColor: *foreground + bgColor: *background + highlightColor: *orange + counterColor: *blue + filterColor: *magenta + views: + charts: + bgColor: background + defaultDialColors: + - *blue + - *red + defaultChartColors: + - *blue + - *red + table: + fgColor: *foreground + bgColor: *background + cursorFgColor: *foreground + cursorBgColor: *current_line + header: + fgColor: *foreground + bgColor: *background + sorterColor: *selection + xray: + fgColor: *foreground + bgColor: *background + cursorColor: *current_line + graphicColor: *blue + showIcons: false + yaml: + keyColor: *magenta + colonColor: *blue + valueColor: *foreground + logs: + fgColor: *foreground + bgColor: *background + indicator: + fgColor: *foreground + bgColor: *background + toggleOnColor: *magenta + toggleOffColor: *blue diff --git a/parts/features/dev/k9s/default.nix b/parts/features/dev/k9s/default.nix new file mode 100644 index 00000000..bc4d5153 --- /dev/null +++ b/parts/features/dev/k9s/default.nix @@ -0,0 +1,25 @@ +{...}: { + flake.modules.homeManager.k9s = { + pkgs, + lib, + ... + }: { + programs.k9s = { + enable = true; + package = pkgs.unstable.k9s; + + skins = { + gruvbox-dark = ./_skins/gruvbox-dark.yaml; + gruvbox-light = ./_skins/gruvbox-light.yaml; + }; + + settings = { + k9s = { + ui = { + skin = lib.mkDefault "gruvbox-dark"; + }; + }; + }; + }; + }; +} From e96399b37c08b70e8be1101f38367f04518755c4 Mon Sep 17 00:00:00 2001 From: workflow <4farlion@gmail.com> Date: Fri, 30 Jan 2026 23:58:08 +0000 Subject: [PATCH 10/26] feat(dendritic): migrate system features (bluetooth, virtualisation) --- parts/features/hardware/bluetooth.nix | 19 +++ .../_scripts/benchmark-containers.nix | 6 + .../_scripts/benchmark-containers.sh | 53 +++++++ .../_scripts/benchmark-heavy-containers.nix | 6 + .../_scripts/benchmark-heavy-containers.sh | 138 ++++++++++++++++++ .../_scripts/reset-container-state.nix | 6 + .../_scripts/reset-container-state.sh | 96 ++++++++++++ .../services/virtualisation/default.nix | 106 ++++++++++++++ 8 files changed, 430 insertions(+) create mode 100644 parts/features/hardware/bluetooth.nix create mode 100644 parts/features/services/virtualisation/_scripts/benchmark-containers.nix create mode 100644 parts/features/services/virtualisation/_scripts/benchmark-containers.sh create mode 100644 parts/features/services/virtualisation/_scripts/benchmark-heavy-containers.nix create mode 100644 parts/features/services/virtualisation/_scripts/benchmark-heavy-containers.sh create mode 100644 parts/features/services/virtualisation/_scripts/reset-container-state.nix create mode 100644 parts/features/services/virtualisation/_scripts/reset-container-state.sh create mode 100644 parts/features/services/virtualisation/default.nix diff --git a/parts/features/hardware/bluetooth.nix b/parts/features/hardware/bluetooth.nix new file mode 100644 index 00000000..eb54314d --- /dev/null +++ b/parts/features/hardware/bluetooth.nix @@ -0,0 +1,19 @@ +{config, lib, ...}: let + cfg = config; +in { + flake.modules.nixos.bluetooth = {lib, ...}: { + environment.persistence."/persist/system" = lib.mkIf cfg.dendrix.isImpermanent { + directories = [ + "/var/lib/bluetooth" + ]; + }; + services.blueman.enable = true; + hardware.bluetooth.enable = true; + }; + + flake.modules.homeManager.bluetuith = {...}: { + programs.bluetuith = { + enable = true; + }; + }; +} diff --git a/parts/features/services/virtualisation/_scripts/benchmark-containers.nix b/parts/features/services/virtualisation/_scripts/benchmark-containers.nix new file mode 100644 index 00000000..99980c77 --- /dev/null +++ b/parts/features/services/virtualisation/_scripts/benchmark-containers.nix @@ -0,0 +1,6 @@ +{pkgs, ...}: +pkgs.writeShellApplication { + name = "benchmark-containers"; + runtimeInputs = with pkgs; [docker podman coreutils]; + text = builtins.readFile ./benchmark-containers.sh; +} diff --git a/parts/features/services/virtualisation/_scripts/benchmark-containers.sh b/parts/features/services/virtualisation/_scripts/benchmark-containers.sh new file mode 100644 index 00000000..4e82f967 --- /dev/null +++ b/parts/features/services/virtualisation/_scripts/benchmark-containers.sh @@ -0,0 +1,53 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Container Performance Benchmark Script +# Tests image pull, container start, and filesystem I/O performance + +echo "=== Container Performance Benchmark ===" +echo "" + +# Check storage drivers +echo "Storage Configuration:" +echo " Docker: $(docker info 2>/dev/null | grep 'Storage Driver' | awk '{print $3}')" +echo " Podman: $(podman info --format=json 2>/dev/null | grep -oP '"graphDriverName": "\K[^"]+')" +echo "" + +# Test 1: Image Pull Speed +echo "Test 1: Image Pull Speed (alpine:latest)" +docker rmi alpine:latest 2>/dev/null || true +time docker pull alpine:latest +echo "" + +# Test 2: Container Start Time (10 iterations) +echo "Test 2: Container Start Time (10 iterations)" +total=0 +for _ in {1..10}; do + start=$(date +%s%N) + docker run --rm alpine:latest echo "test" > /dev/null + end=$(date +%s%N) + elapsed=$(((end - start) / 1000000)) + total=$((total + elapsed)) +done +avg=$((total / 10)) +echo " Average start time: ${avg}ms" +echo "" + +# Test 3: Filesystem I/O Performance +echo "Test 3: Filesystem I/O (writing 1GB)" +docker run --rm alpine:latest sh -c 'dd if=/dev/zero of=/tmp/test bs=1M count=1024 2>&1 | grep -E "copied|MB/s"' +echo "" + +# Test 4: Build Performance +echo "Test 4: Build Performance (simple Dockerfile)" +tmpdir=$(mktemp -d) +cat > "$tmpdir/Dockerfile" <<'EOF' +FROM alpine:latest +RUN apk add --no-cache curl git +RUN dd if=/dev/zero of=/tmp/test bs=1M count=100 +EOF +time docker build -q "$tmpdir" > /dev/null +rm -rf "$tmpdir" +echo "" + +echo "=== Benchmark Complete ===" diff --git a/parts/features/services/virtualisation/_scripts/benchmark-heavy-containers.nix b/parts/features/services/virtualisation/_scripts/benchmark-heavy-containers.nix new file mode 100644 index 00000000..463502dd --- /dev/null +++ b/parts/features/services/virtualisation/_scripts/benchmark-heavy-containers.nix @@ -0,0 +1,6 @@ +{pkgs, ...}: +pkgs.writeShellApplication { + name = "benchmark-heavy-containers"; + runtimeInputs = with pkgs; [docker podman coreutils]; + text = builtins.readFile ./benchmark-heavy-containers.sh; +} diff --git a/parts/features/services/virtualisation/_scripts/benchmark-heavy-containers.sh b/parts/features/services/virtualisation/_scripts/benchmark-heavy-containers.sh new file mode 100644 index 00000000..a0dad8ce --- /dev/null +++ b/parts/features/services/virtualisation/_scripts/benchmark-heavy-containers.sh @@ -0,0 +1,138 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Heavy Container Performance Benchmark Script +# Tests with realistic workloads: large images, many containers, heavy I/O + +echo "=== Heavy Container Performance Benchmark ===" +echo "This will take 5-10 minutes to complete..." +echo "" + +# Check storage drivers +echo "Storage Configuration:" +echo " Docker: $(docker info 2>/dev/null | grep 'Storage Driver' | awk '{print $3}')" +echo " Podman: $(podman info --format=json 2>/dev/null | grep -oP '"graphDriverName": "\K[^"]+')" +echo "" + +# Test 1: Large Image Pulls +echo "Test 1: Large Image Pull Speed (postgres, node, python)" +docker rmi postgres:latest node:latest python:latest 2>/dev/null || true +echo " Pulling postgres..." +time docker pull postgres:latest > /dev/null +echo " Pulling node..." +time docker pull node:latest > /dev/null +echo " Pulling python..." +time docker pull python:latest > /dev/null +echo "" + +# Test 2: Many Container Starts +echo "Test 2: Container Start Time (100 iterations)" +total=0 +for _ in {1..100}; do + start=$(date +%s%N) + docker run --rm alpine:latest echo "test" > /dev/null 2>&1 + end=$(date +%s%N) + elapsed=$(((end - start) / 1000000)) + total=$((total + elapsed)) +done +avg=$((total / 100)) +echo " Average start time: ${avg}ms (100 runs)" +echo "" + +# Test 3: Heavy Filesystem I/O +echo "Test 3: Heavy Filesystem I/O" +echo " Writing 10GB sequential..." +docker run --rm alpine:latest sh -c 'dd if=/dev/zero of=/tmp/test bs=1M count=10240 2>&1 | grep -E "copied|MB/s"' +echo " Random write performance (1000 files of 10MB each)..." +time docker run --rm alpine:latest sh -c 'for i in $(seq 1 1000); do dd if=/dev/urandom of=/tmp/file$i bs=1M count=10 2>/dev/null; done' +echo "" + +# Test 4: Complex Multi-stage Build +echo "Test 4: Complex Multi-stage Build" +tmpdir=$(mktemp -d) +cat > "$tmpdir/Dockerfile" <<'EOF' +FROM node:latest AS builder +WORKDIR /app +RUN dd if=/dev/zero of=/tmp/dummy1 bs=1M count=500 +RUN npm install -g npm@latest +RUN dd if=/dev/zero of=/tmp/dummy2 bs=1M count=500 + +FROM python:latest AS python-builder +WORKDIR /app +RUN dd if=/dev/zero of=/tmp/dummy3 bs=1M count=500 +RUN pip install --upgrade pip +RUN dd if=/dev/zero of=/tmp/dummy4 bs=1M count=500 + +FROM alpine:latest +WORKDIR /app +COPY --from=builder /tmp/dummy1 /app/ +COPY --from=python-builder /tmp/dummy3 /app/ +RUN dd if=/dev/zero of=/tmp/final bs=1M count=100 +EOF +time docker build -q "$tmpdir" > /dev/null +rm -rf "$tmpdir" +echo "" + +# Test 5: Layer Creation Performance +echo "Test 5: Layer Creation (50 layers)" +tmpdir=$(mktemp -d) +cat > "$tmpdir/Dockerfile" <<'EOF' +FROM alpine:latest +EOF +for i in $(seq 1 50); do + echo "RUN dd if=/dev/zero of=/tmp/layer$i bs=1M count=20 && rm /tmp/layer$i" >> "$tmpdir/Dockerfile" +done +time docker build -q "$tmpdir" > /dev/null +rm -rf "$tmpdir" +echo "" + +# Test 6: Concurrent Container Operations +echo "Test 6: Concurrent Container Starts (20 parallel)" +time for _ in {1..20}; do + docker run --rm -d alpine:latest sleep 10 > /dev/null +done +docker ps -q | xargs -r docker stop > /dev/null 2>&1 || true +echo "" + +# Test 7: Volume Operations +echo "Test 7: Volume I/O Performance" +vol_name="benchmark-vol-$(date +%s)" +docker volume create "$vol_name" > /dev/null +echo " Writing 5GB to volume..." +docker run --rm -v "$vol_name":/data alpine:latest sh -c 'dd if=/dev/zero of=/data/test bs=1M count=5120 2>&1 | grep -E "copied|MB/s"' +echo " Reading 5GB from volume..." +docker run --rm -v "$vol_name":/data alpine:latest sh -c 'dd if=/data/test of=/dev/null bs=1M 2>&1 | grep -E "copied|MB/s"' +docker volume rm "$vol_name" > /dev/null +echo "" + +# Test 8: Image Layer Cache Performance +echo "Test 8: Build Cache Performance (rebuild same image 5 times)" +tmpdir=$(mktemp -d) +cat > "$tmpdir/Dockerfile" <<'EOF' +FROM python:latest +RUN pip install requests flask numpy pandas +RUN dd if=/dev/zero of=/tmp/data bs=1M count=200 +EOF +echo " First build (no cache):" +time docker build -q "$tmpdir" > /dev/null +echo " Rebuilds (with cache):" +for i in {1..4}; do + echo " Build $i:" + time docker build -q "$tmpdir" > /dev/null +done +rm -rf "$tmpdir" +echo "" + +# Test 9: Snapshot/Copy Performance +echo "Test 9: Container Commit Performance" +cid=$(docker run -d postgres:latest sleep 30) +time docker commit "$cid" benchmark-snapshot:latest > /dev/null +docker stop "$cid" > /dev/null 2>&1 || true +docker rm "$cid" > /dev/null 2>&1 || true +docker rmi benchmark-snapshot:latest > /dev/null 2>&1 || true +echo "" + +echo "=== Heavy Benchmark Complete ===" +echo "" +echo "Summary: Check the timing results above to compare storage drivers." +echo "Key metrics: Large image pulls, multi-stage builds, layer operations, and volume I/O." diff --git a/parts/features/services/virtualisation/_scripts/reset-container-state.nix b/parts/features/services/virtualisation/_scripts/reset-container-state.nix new file mode 100644 index 00000000..57435040 --- /dev/null +++ b/parts/features/services/virtualisation/_scripts/reset-container-state.nix @@ -0,0 +1,6 @@ +{pkgs, ...}: +pkgs.writeShellApplication { + name = "reset-container-state"; + runtimeInputs = with pkgs; [docker podman coreutils util-linux systemd]; + text = builtins.readFile ./reset-container-state.sh; +} diff --git a/parts/features/services/virtualisation/_scripts/reset-container-state.sh b/parts/features/services/virtualisation/_scripts/reset-container-state.sh new file mode 100644 index 00000000..a54cdfc2 --- /dev/null +++ b/parts/features/services/virtualisation/_scripts/reset-container-state.sh @@ -0,0 +1,96 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Reset container state for fair benchmarking +# This clears all images, containers, volumes, caches, and storage backends +# Works when switching between overlay2 and btrfs drivers + +echo "=== Resetting Container State ===" +echo "" + +# Check current storage driver before cleanup +echo "Current storage configuration:" +docker info 2>/dev/null | grep 'Storage Driver' || echo " Docker: not running" +podman info --format=json 2>/dev/null | grep -oP '"graphDriverName": "\K[^"]+' | sed 's/^/ Podman: /' || echo " Podman: not running" +echo "" + +# Stop all running containers (if services are running) +echo "Stopping all containers..." +containers=$(docker ps -aq 2>/dev/null || true) +if [ -n "$containers" ]; then + docker stop "$containers" 2>/dev/null || true + docker rm -f "$containers" 2>/dev/null || true +fi +podman stop -a 2>/dev/null || true +podman rm -a -f 2>/dev/null || true + +# Remove all images via API (cleans metadata properly) +echo "Removing all images..." +images=$(docker images -aq 2>/dev/null || true) +if [ -n "$images" ]; then + docker rmi -f "$images" 2>/dev/null || true +fi +podman rmi -a -f 2>/dev/null || true + +# Remove all volumes +echo "Removing all volumes..." +volumes=$(docker volume ls -q 2>/dev/null || true) +if [ -n "$volumes" ]; then + docker volume rm "$volumes" 2>/dev/null || true +fi +podman volume rm -a -f 2>/dev/null || true + +# Prune everything to clean build cache and metadata +echo "Pruning system..." +docker system prune -a -f --volumes 2>/dev/null || true +podman system prune -a -f --volumes 2>/dev/null || true + +# Stop services before cleaning storage +echo "Stopping Docker and Podman services..." +sudo systemctl stop docker.socket docker.service 2>/dev/null || true +sudo systemctl stop podman.socket podman.service 2>/dev/null || true + +# Wait for services to fully stop +sleep 2 + +# Remove all Docker storage (both overlay2 and btrfs) +echo "Removing all Docker storage backends..." +sudo rm -rf /var/lib/docker/* 2>/dev/null || true + +# Remove all Podman storage +echo "Removing all Podman storage..." +sudo rm -rf /var/lib/containers/storage/* 2>/dev/null || true +rm -rf ~/.local/share/containers/storage/* 2>/dev/null || true + +# Podman system reset (if podman can start) +echo "Resetting Podman state..." +podman system reset -f 2>/dev/null || true + +# Restart services with clean storage +echo "Restarting Docker and Podman services..." +sudo systemctl start docker.service +sudo systemctl start podman.service + +# Wait for services to be ready +sleep 3 + +# Verify clean state +echo "" +echo "Verifying clean state..." +docker images 2>/dev/null && echo " Docker: Clean (no images)" || echo " Docker: Service starting..." +podman images 2>/dev/null && echo " Podman: Clean (no images)" || echo " Podman: Service starting..." + +# Drop system caches for fair benchmarking +echo "" +echo "Dropping system caches..." +sudo sync +echo 3 | sudo tee /proc/sys/vm/drop_caches > /dev/null + +echo "" +echo "=== Container State Reset Complete ===" +echo "All storage backends (overlay2, btrfs) have been cleared." +echo "New storage driver configuration:" +docker info 2>/dev/null | grep 'Storage Driver' || echo " Docker: initializing..." +podman info --format=json 2>/dev/null | grep -oP '"graphDriverName": "\K[^"]+' | sed 's/^/ Podman: /' || echo " Podman: initializing..." +echo "" +echo "Ready to run benchmarks with clean storage!" diff --git a/parts/features/services/virtualisation/default.nix b/parts/features/services/virtualisation/default.nix new file mode 100644 index 00000000..e2a90e04 --- /dev/null +++ b/parts/features/services/virtualisation/default.nix @@ -0,0 +1,106 @@ +{config, lib, ...}: let + cfg = config; +in { + flake.modules.nixos.virtualisation = { + config, + lib, + pkgs, + ... + }: let + benchmark-containers = pkgs.writeShellApplication { + name = "benchmark-containers"; + runtimeInputs = with pkgs; [docker podman coreutils]; + text = builtins.readFile ./_scripts/benchmark-containers.sh; + }; + benchmark-heavy-containers = pkgs.writeShellApplication { + name = "benchmark-heavy-containers"; + runtimeInputs = with pkgs; [docker podman coreutils]; + text = builtins.readFile ./_scripts/benchmark-heavy-containers.sh; + }; + reset-container-state = pkgs.writeShellApplication { + name = "reset-container-state"; + runtimeInputs = with pkgs; [docker podman coreutils systemd]; + text = builtins.readFile ./_scripts/reset-container-state.sh; + }; + in { + environment.persistence."/persist/system" = lib.mkIf cfg.dendrix.isImpermanent { + directories = [ + "/var/lib/containers" + "/var/lib/docker" + "/var/lib/libvirt" + ]; + }; + home-manager.users.farlion.home.persistence."/persist" = lib.mkIf cfg.dendrix.isImpermanent { + directories = [ + ".local/share/containers" + ]; + }; + + environment.systemPackages = [ + pkgs.podman-compose + pkgs.virt-manager + benchmark-containers + benchmark-heavy-containers + reset-container-state + ]; + + virtualisation.docker = { + enable = true; + storageDriver = "overlay2"; + daemon.settings = { + dns = ["172.17.0.1"]; + ip = "127.0.0.1"; + ipv6 = false; + ip6tables = false; + iptables = true; + }; + }; + + networking.firewall.interfaces.docker0.allowedTCPPorts = [53]; + networking.firewall.interfaces.docker0.allowedUDPPorts = [53]; + + networking.firewall.extraCommands = '' + for iface in $(${pkgs.iproute2}/bin/ip link show | grep -o 'br-[a-f0-9]\{12\}' || true); do + if [ -n "$iface" ]; then + iptables -I nixos-fw 1 -i "$iface" -p tcp --dport 53 -j ACCEPT + iptables -I nixos-fw 1 -i "$iface" -p udp --dport 53 -j ACCEPT + fi + done + + iptables -I FORWARD 1 -s 172.16.0.0/12 -d 172.16.0.0/12 -p tcp --dport 53 -j ACCEPT + iptables -I FORWARD 1 -s 172.16.0.0/12 -d 172.16.0.0/12 -p udp --dport 53 -j ACCEPT + + iptables -t mangle -A FORWARD -s 172.17.0.0/16 -d 100.64.0.0/10 -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu + iptables -t mangle -A FORWARD -s 172.18.0.0/16 -d 100.64.0.0/10 -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu + iptables -t mangle -A FORWARD -s 172.17.0.0/16 -d 100.100.0.0/16 -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu + iptables -t mangle -A FORWARD -s 172.18.0.0/16 -d 100.100.0.0/16 -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu + ''; + + virtualisation.libvirtd.enable = true; + + virtualisation.podman = { + enable = true; + }; + + virtualisation.containers.storage.settings = { + storage = { + driver = "overlay"; + runroot = "/run/containers/storage"; + graphroot = "/var/lib/containers/storage"; + options = { + pull_options = { + enable_partial_images = "true"; + use_hard_links = "false"; + ostree_repos = ""; + }; + overlay = { + mountopt = "nodev,metacopy=on"; + force_mask = "0000"; + }; + }; + }; + }; + + users.users.farlion.extraGroups = ["libvirtd" "kvm" "docker"]; + }; +} From e962e3b21520c8e1c7bd128ee56158add66df861 Mon Sep 17 00:00:00 2001 From: workflow <4farlion@gmail.com> Date: Sat, 31 Jan 2026 00:06:09 +0000 Subject: [PATCH 11/26] feat(dendritic): bulk migrate hardware, desktop, and app features (batch 3) --- parts/features/apps/gimp.nix | 20 +++++ parts/features/apps/libreoffice.nix | 19 +++++ parts/features/apps/nix-index.nix | 19 +++++ parts/features/apps/qalculate.nix | 20 +++++ parts/features/apps/rofimoji/default.nix | 10 +++ parts/features/apps/rofimoji/rofimoji.rc | 3 + .../apps/satty/_scripts/satty-screenshot.sh | 30 +++++++ parts/features/apps/satty/default.nix | 39 +++++++++ parts/features/apps/vlc.nix | 20 +++++ parts/features/apps/zoom.nix | 24 ++++++ parts/features/desktop/cliphist.nix | 32 ++++++++ parts/features/desktop/dconf.nix | 11 +++ parts/features/desktop/gtk-qt.nix | 41 ++++++++++ parts/features/desktop/kanshi.nix | 80 +++++++++++++++++++ parts/features/desktop/udiskie.nix | 25 ++++++ .../wlsunset/_scripts/wlsunset-waybar.sh | 22 +++++ parts/features/desktop/wlsunset/default.nix | 14 ++++ parts/features/dev/devenv.nix | 19 +++++ parts/features/hardware/amd.nix | 28 +++++++ parts/features/hardware/nvidia.nix | 30 +++++++ parts/features/hardware/power.nix | 53 ++++++++++++ parts/features/security/bitwarden.nix | 20 +++++ parts/features/services/printing.nix | 18 +++++ 23 files changed, 597 insertions(+) create mode 100644 parts/features/apps/gimp.nix create mode 100644 parts/features/apps/libreoffice.nix create mode 100644 parts/features/apps/nix-index.nix create mode 100644 parts/features/apps/qalculate.nix create mode 100644 parts/features/apps/rofimoji/default.nix create mode 100644 parts/features/apps/rofimoji/rofimoji.rc create mode 100644 parts/features/apps/satty/_scripts/satty-screenshot.sh create mode 100644 parts/features/apps/satty/default.nix create mode 100644 parts/features/apps/vlc.nix create mode 100644 parts/features/apps/zoom.nix create mode 100644 parts/features/desktop/cliphist.nix create mode 100644 parts/features/desktop/dconf.nix create mode 100644 parts/features/desktop/gtk-qt.nix create mode 100644 parts/features/desktop/kanshi.nix create mode 100644 parts/features/desktop/udiskie.nix create mode 100644 parts/features/desktop/wlsunset/_scripts/wlsunset-waybar.sh create mode 100644 parts/features/desktop/wlsunset/default.nix create mode 100644 parts/features/dev/devenv.nix create mode 100644 parts/features/hardware/amd.nix create mode 100644 parts/features/hardware/nvidia.nix create mode 100644 parts/features/hardware/power.nix create mode 100644 parts/features/security/bitwarden.nix create mode 100644 parts/features/services/printing.nix diff --git a/parts/features/apps/gimp.nix b/parts/features/apps/gimp.nix new file mode 100644 index 00000000..71567d95 --- /dev/null +++ b/parts/features/apps/gimp.nix @@ -0,0 +1,20 @@ +{config, lib, ...}: let + cfg = config; +in { + flake.modules.homeManager.gimp = { + lib, + pkgs, + ... + }: { + home.persistence."/persist" = lib.mkIf cfg.dendrix.isImpermanent { + directories = [ + ".config/GIMP" + ".cache/gimp" + ]; + }; + + home.packages = [ + pkgs.gimp + ]; + }; +} diff --git a/parts/features/apps/libreoffice.nix b/parts/features/apps/libreoffice.nix new file mode 100644 index 00000000..faed0713 --- /dev/null +++ b/parts/features/apps/libreoffice.nix @@ -0,0 +1,19 @@ +{config, lib, ...}: let + cfg = config; +in { + flake.modules.homeManager.libreoffice = { + lib, + pkgs, + ... + }: { + home.persistence."/persist" = lib.mkIf cfg.dendrix.isImpermanent { + directories = [ + ".config/libreoffice" + ]; + }; + + home.packages = [ + pkgs.libreoffice + ]; + }; +} diff --git a/parts/features/apps/nix-index.nix b/parts/features/apps/nix-index.nix new file mode 100644 index 00000000..ff00fad3 --- /dev/null +++ b/parts/features/apps/nix-index.nix @@ -0,0 +1,19 @@ +{config, lib, inputs, ...}: let + cfg = config; +in { + flake.modules.homeManager.nix-index = {lib, ...}: { + imports = [ + inputs.nix-index-database.homeModules.nix-index + ]; + + home.persistence."/persist" = lib.mkIf cfg.dendrix.isImpermanent { + files = [ + ".local/state/comma-choices" + ]; + }; + + programs.nix-index = { + enable = true; + }; + }; +} diff --git a/parts/features/apps/qalculate.nix b/parts/features/apps/qalculate.nix new file mode 100644 index 00000000..7e09c2e0 --- /dev/null +++ b/parts/features/apps/qalculate.nix @@ -0,0 +1,20 @@ +{config, lib, ...}: let + cfg = config; +in { + flake.modules.homeManager.qalculate = { + lib, + pkgs, + ... + }: { + home.persistence."/persist" = lib.mkIf cfg.dendrix.isImpermanent { + directories = [ + ".config/qalculate" + ".local/share/qalculate" + ]; + }; + + home.packages = [ + pkgs.qalculate-gtk + ]; + }; +} diff --git a/parts/features/apps/rofimoji/default.nix b/parts/features/apps/rofimoji/default.nix new file mode 100644 index 00000000..8097c49f --- /dev/null +++ b/parts/features/apps/rofimoji/default.nix @@ -0,0 +1,10 @@ +{...}: { + flake.modules.homeManager.rofimoji = {pkgs, ...}: { + home.packages = [ + pkgs.rofimoji + pkgs.wtype + ]; + + xdg.configFile."rofimoji.rc".source = ./rofimoji.rc; + }; +} diff --git a/parts/features/apps/rofimoji/rofimoji.rc b/parts/features/apps/rofimoji/rofimoji.rc new file mode 100644 index 00000000..84825664 --- /dev/null +++ b/parts/features/apps/rofimoji/rofimoji.rc @@ -0,0 +1,3 @@ +files = [emojis, math, currency_symbols, combining_diacritical_marks, fontawesome6] +skin-tone = "neutral" +selector = "fuzzel" diff --git a/parts/features/apps/satty/_scripts/satty-screenshot.sh b/parts/features/apps/satty/_scripts/satty-screenshot.sh new file mode 100644 index 00000000..6e897696 --- /dev/null +++ b/parts/features/apps/satty/_scripts/satty-screenshot.sh @@ -0,0 +1,30 @@ +# Take a fullscreen screenshot of the current focused screen and open it with Satty + +temp_file=$(mktemp --suffix=".png") + +# Try to get the focused output, fallback to just taking a screenshot of all outputs +focused_output=$(niri msg --json focused-output 2>/dev/null | jq -r '.name' 2>/dev/null || echo "") + +# Take the screenshot +screenshot_success=false +if [ -n "$focused_output" ]; then + if grim -o "$focused_output" "$temp_file"; then + screenshot_success=true + fi +else + if grim "$temp_file"; then + screenshot_success=true + fi +fi + +if [ "$screenshot_success" = true ]; then + # Open the screenshot with Satty for editing + satty --filename "$temp_file" --copy-command "wl-copy" --early-exit + + # Clean up the temporary file + rm "$temp_file" +else + echo "Failed to take screenshot" >&2 + rm "$temp_file" + exit 1 +fi diff --git a/parts/features/apps/satty/default.nix b/parts/features/apps/satty/default.nix new file mode 100644 index 00000000..04a421a9 --- /dev/null +++ b/parts/features/apps/satty/default.nix @@ -0,0 +1,39 @@ +{config, lib, ...}: let + cfg = config; +in { + flake.modules.homeManager.satty = { + lib, + pkgs, + ... + }: let + sattyScreenshot = pkgs.writeShellApplication { + name = "satty-screenshot"; + runtimeInputs = with pkgs; [ + satty + grim + wl-clipboard + jq + niri + ]; + text = builtins.readFile ./_scripts/satty-screenshot.sh; + }; + in { + home.persistence."/persist" = lib.mkIf cfg.dendrix.isImpermanent { + directories = [ + ".cache/satty" + ]; + }; + + programs.satty = { + enable = true; + settings.general = { + fullscreen = true; + initial-tool = "crop"; + }; + }; + + home.packages = [ + sattyScreenshot + ]; + }; +} diff --git a/parts/features/apps/vlc.nix b/parts/features/apps/vlc.nix new file mode 100644 index 00000000..f28b8aea --- /dev/null +++ b/parts/features/apps/vlc.nix @@ -0,0 +1,20 @@ +{config, lib, ...}: let + cfg = config; +in { + flake.modules.homeManager.vlc = { + lib, + pkgs, + ... + }: { + home.persistence."/persist" = lib.mkIf cfg.dendrix.isImpermanent { + directories = [ + ".config/vlc" + ".local/share/vlc" + ]; + }; + + home.packages = [ + pkgs.vlc + ]; + }; +} diff --git a/parts/features/apps/zoom.nix b/parts/features/apps/zoom.nix new file mode 100644 index 00000000..066aee2b --- /dev/null +++ b/parts/features/apps/zoom.nix @@ -0,0 +1,24 @@ +{config, lib, ...}: let + cfg = config; +in { + flake.modules.homeManager.zoom = { + lib, + pkgs, + ... + }: { + home.persistence."/persist" = lib.mkIf cfg.dendrix.isImpermanent { + files = [ + ".config/zoom.conf" + ".config/zoomus.conf" + ]; + directories = [ + ".zoom" + ".cache/zoom" + ]; + }; + + home.packages = [ + pkgs.zoom-us + ]; + }; +} diff --git a/parts/features/desktop/cliphist.nix b/parts/features/desktop/cliphist.nix new file mode 100644 index 00000000..eba0fb4e --- /dev/null +++ b/parts/features/desktop/cliphist.nix @@ -0,0 +1,32 @@ +{config, lib, ...}: let + cfg = config; +in { + flake.modules.homeManager.cliphist = { + lib, + pkgs, + ... + }: { + home.persistence."/persist" = lib.mkIf cfg.dendrix.isImpermanent { + directories = [ + ".cache/cliphist" + ]; + }; + + services.cliphist = { + enable = true; + }; + + systemd.user.services.cliphist = { + Install.WantedBy = lib.mkForce ["niri.service"]; + Unit.Requires = ["niri.service"]; + Unit.After = ["niri.service"]; + }; + systemd.user.services.cliphist-images = { + Install.WantedBy = lib.mkForce ["niri.service"]; + Unit.Requires = ["niri.service"]; + Unit.After = ["niri.service"]; + }; + + home.packages = [pkgs.xdg-utils]; + }; +} diff --git a/parts/features/desktop/dconf.nix b/parts/features/desktop/dconf.nix new file mode 100644 index 00000000..4c8d17ba --- /dev/null +++ b/parts/features/desktop/dconf.nix @@ -0,0 +1,11 @@ +{config, lib, ...}: let + cfg = config; +in { + flake.modules.homeManager.dconf = {lib, ...}: { + home.persistence."/persist" = lib.mkIf cfg.dendrix.isImpermanent { + directories = [ + ".config/dconf" + ]; + }; + }; +} diff --git a/parts/features/desktop/gtk-qt.nix b/parts/features/desktop/gtk-qt.nix new file mode 100644 index 00000000..f6ec18b1 --- /dev/null +++ b/parts/features/desktop/gtk-qt.nix @@ -0,0 +1,41 @@ +{config, lib, ...}: let + cfg = config; +in { + flake.modules.homeManager.gtk-qt = { + lib, + pkgs, + ... + }: { + home.persistence."/persist" = lib.mkIf cfg.dendrix.isImpermanent { + files = [ + ".config/QtProject.conf" + ]; + }; + + gtk = { + enable = true; + gtk3 = { + extraConfig = { + gtk-application-prefer-dark-theme = true; + }; + }; + }; + + qt = { + enable = true; + platformTheme.name = "qtct"; + style.name = "kvantum"; + }; + + home.packages = with pkgs; [ + lxappearance + libsForQt5.qt5ct + qt6Packages.qt6ct + ]; + + home.sessionVariables = { + QT_AUTO_SCREEN_SCALE_FACTOR = "1"; + QT_ENABLE_HIGHDPI_SCALING = "1"; + }; + }; +} diff --git a/parts/features/desktop/kanshi.nix b/parts/features/desktop/kanshi.nix new file mode 100644 index 00000000..36a11b65 --- /dev/null +++ b/parts/features/desktop/kanshi.nix @@ -0,0 +1,80 @@ +{...}: { + flake.modules.homeManager.kanshi = {...}: { + services.kanshi = { + enable = true; + settings = [ + { + output = { + alias = "leftLG27"; + criteria = "HDMI-A-2"; + mode = "3840x2160@60.000Hz"; + position = "0,0"; + scale = 2.0; + transform = "90"; + }; + } + { + output = { + alias = "middleLG34"; + criteria = "DP-1"; + mode = "3840x2160@144.050Hz"; + position = "1080,208"; + scale = 1.5; + transform = "normal"; + }; + } + { + output = { + alias = "rightLG27"; + criteria = "HDMI-A-1"; + mode = "3840x2160@60.000Hz"; + position = "3640,0"; + scale = 2.0; + transform = "90"; + }; + } + { + profile = { + name = "numenor"; + outputs = [ + { + criteria = "$leftLG27"; + status = "enable"; + } + { + criteria = "$middleLG34"; + status = "enable"; + } + { + criteria = "$rightLG27"; + status = "enable"; + } + ]; + }; + } + { + profile = { + name = "numenor-movie"; + outputs = [ + { + criteria = "$leftLG27"; + status = "enable"; + position = "0,272"; + transform = "normal"; + } + { + criteria = "$middleLG34"; + status = "enable"; + position = "1920,132"; + } + { + criteria = "$rightLG27"; + status = "disable"; + } + ]; + }; + } + ]; + }; + }; +} diff --git a/parts/features/desktop/udiskie.nix b/parts/features/desktop/udiskie.nix new file mode 100644 index 00000000..c8861c8c --- /dev/null +++ b/parts/features/desktop/udiskie.nix @@ -0,0 +1,25 @@ +{...}: { + flake.modules.homeManager.udiskie = { + lib, + pkgs, + ... + }: { + services.udiskie = { + enable = true; + automount = false; + }; + + systemd.user.services.udiskie = { + Unit = { + After = ["niri.service" "graphical-session.target"]; + Wants = ["graphical-session.target"]; + ConditionEnvironment = lib.mkForce []; + }; + Service = { + ExecStartPre = "${pkgs.coreutils}/bin/sleep 2"; + Restart = lib.mkForce "on-failure"; + RestartSec = "5"; + }; + }; + }; +} diff --git a/parts/features/desktop/wlsunset/_scripts/wlsunset-waybar.sh b/parts/features/desktop/wlsunset/_scripts/wlsunset-waybar.sh new file mode 100644 index 00000000..c4fe1b0a --- /dev/null +++ b/parts/features/desktop/wlsunset/_scripts/wlsunset-waybar.sh @@ -0,0 +1,22 @@ +# Originally looted from https://github.com/CyrilSLi/linux-scripts +if pgrep -x wlsunset; then + killall -9 wlsunset +else + RETRIES=30 + counter=0 + while true; do + if CONTENT=$(curl -s http://ip-api.com/json/); then + break + fi + counter=$((counter + 1)) + if [ $counter -eq $RETRIES ]; then + notify-send wlsunset.sh "Unable to connect to ip-api." + break + fi + sleep 2 + done + longitude=$(echo "$CONTENT" | jq .lon) + latitude=$(echo "$CONTENT" | jq .lat) + wlsunset -l "$latitude" -L "$longitude" & +fi +pkill -35 waybar diff --git a/parts/features/desktop/wlsunset/default.nix b/parts/features/desktop/wlsunset/default.nix new file mode 100644 index 00000000..6a9b9360 --- /dev/null +++ b/parts/features/desktop/wlsunset/default.nix @@ -0,0 +1,14 @@ +{...}: { + flake.modules.homeManager.wlsunset = {pkgs, ...}: let + wlsunset-waybar = pkgs.writeShellApplication { + name = "wlsunset-waybar"; + runtimeInputs = with pkgs; [wlsunset procps killall]; + text = builtins.readFile ./_scripts/wlsunset-waybar.sh; + }; + in { + home.packages = [ + pkgs.wlsunset + wlsunset-waybar + ]; + }; +} diff --git a/parts/features/dev/devenv.nix b/parts/features/dev/devenv.nix new file mode 100644 index 00000000..6012a9a4 --- /dev/null +++ b/parts/features/dev/devenv.nix @@ -0,0 +1,19 @@ +{config, lib, ...}: let + cfg = config; +in { + flake.modules.homeManager.devenv = { + lib, + pkgs, + ... + }: { + home.persistence."/persist" = lib.mkIf cfg.dendrix.isImpermanent { + directories = [ + ".local/share/devenv" + ]; + }; + + home.packages = [ + pkgs.devenv + ]; + }; +} diff --git a/parts/features/hardware/amd.nix b/parts/features/hardware/amd.nix new file mode 100644 index 00000000..d68f1d93 --- /dev/null +++ b/parts/features/hardware/amd.nix @@ -0,0 +1,28 @@ +{...}: { + flake.modules.nixos.amd = {pkgs, ...}: { + hardware.amdgpu = { + initrd.enable = true; + opencl.enable = true; + }; + + boot.kernelParams = [ + "amdgpu.runpm=0" + ]; + + environment.systemPackages = with pkgs; [ + lact + libva-utils + mesa-demos + nvtopPackages.full + vulkan-tools + ]; + services.xserver.videoDrivers = ["amdgpu"]; + hardware.graphics = { + enable = true; + enable32Bit = true; + }; + + systemd.packages = with pkgs; [lact]; + systemd.services.lactd.wantedBy = ["multi-user.target"]; + }; +} diff --git a/parts/features/hardware/nvidia.nix b/parts/features/hardware/nvidia.nix new file mode 100644 index 00000000..8e6af39c --- /dev/null +++ b/parts/features/hardware/nvidia.nix @@ -0,0 +1,30 @@ +{...}: { + flake.modules.nixos.nvidia = {pkgs, ...}: { + boot.blacklistedKernelModules = ["nouveau"]; + environment.systemPackages = [ + pkgs.nvtopPackages.full + pkgs.mesa-demos + pkgs.vulkan-tools + pkgs.libva-utils + pkgs.nvidia-vaapi-driver + ]; + + environment.sessionVariables = { + LIBVA_DRIVER_NAME = "nvidia"; + NVD_BACKEND = "direct"; + }; + + services.xserver.videoDrivers = ["nvidia"]; + hardware.graphics = { + enable = true; + }; + + hardware.nvidia = { + modesetting.enable = true; + powerManagement.enable = false; + powerManagement.finegrained = true; + open = false; + nvidiaSettings = true; + }; + }; +} diff --git a/parts/features/hardware/power.nix b/parts/features/hardware/power.nix new file mode 100644 index 00000000..46eea35b --- /dev/null +++ b/parts/features/hardware/power.nix @@ -0,0 +1,53 @@ +{config, lib, ...}: let + cfg = config; +in { + flake.modules.nixos.power = { + lib, + pkgs, + ... + }: let + isFlexbox = cfg.dendrix.hostname == "flexbox"; + in { + services.thermald.enable = true; + + services.logind = { + settings = { + Login = { + HandleLidSwitch = "suspend-then-hibernate"; + HandleLidSwitchDocked = "lock"; + HandleLidSwitchExternalPower = "lock"; + }; + }; + }; + systemd.sleep.extraConfig = '' + HibernateDelaySec=1h + ''; + + environment.systemPackages = + [] + ++ lib.lists.optional isFlexbox pkgs.libsmbios; + + services.auto-cpufreq = { + enable = true; + settings = {}; + }; + + security.sudo.extraRules = [ + { + users = ["farlion"]; + commands = [ + { + command = "${pkgs.auto-cpufreq}/bin/auto-cpufreq --force *"; + options = ["NOPASSWD" "SETENV"]; + } + { + command = "/run/current-system/sw/bin/auto-cpufreq --force *"; + options = ["NOPASSWD" "SETENV"]; + } + ]; + } + ]; + + services.upower.enable = true; + }; +} diff --git a/parts/features/security/bitwarden.nix b/parts/features/security/bitwarden.nix new file mode 100644 index 00000000..d56d3c63 --- /dev/null +++ b/parts/features/security/bitwarden.nix @@ -0,0 +1,20 @@ +{config, lib, ...}: let + cfg = config; +in { + flake.modules.homeManager.bitwarden = { + lib, + pkgs, + ... + }: { + home.persistence."/persist" = lib.mkIf cfg.dendrix.isImpermanent { + directories = [ + ".config/Bitwarden" + ]; + }; + + home.packages = [ + pkgs.bitwarden-desktop + pkgs.bitwarden-cli + ]; + }; +} diff --git a/parts/features/services/printing.nix b/parts/features/services/printing.nix new file mode 100644 index 00000000..158d805e --- /dev/null +++ b/parts/features/services/printing.nix @@ -0,0 +1,18 @@ +{...}: { + flake.modules.nixos.printing = {pkgs, ...}: { + services.printing = { + enable = true; + drivers = [ + pkgs.gutenprint + pkgs.hplip + ]; + listenAddresses = ["127.0.0.1:631"]; + }; + + services.avahi = { + enable = true; + nssmdns4 = true; + openFirewall = true; + }; + }; +} From 9d893cfef8a7d761f7e5c57f3abe50a835f5ca92 Mon Sep 17 00:00:00 2001 From: workflow <4farlion@gmail.com> Date: Sat, 31 Jan 2026 00:15:28 +0000 Subject: [PATCH 12/26] feat(dendritic): migrate security features (yubico, security, nushell) --- flake.lock | 2 +- .../apps/nushell/_syncthing/stignore-nushell | 7 ++ parts/features/apps/nushell/config.nu | 30 +++++++++ parts/features/apps/nushell/default.nix | 30 +++++++++ parts/features/apps/nushell/env.nu | 1 + parts/features/security/security.nix | 62 +++++++++++++++++ .../yubikey-touch-detector/default.nix | 66 +++++++++++++++++++ parts/features/security/yubico/default.nix | 21 ++++++ 8 files changed, 218 insertions(+), 1 deletion(-) create mode 100644 parts/features/apps/nushell/_syncthing/stignore-nushell create mode 100644 parts/features/apps/nushell/config.nu create mode 100644 parts/features/apps/nushell/default.nix create mode 100644 parts/features/apps/nushell/env.nu create mode 100644 parts/features/security/security.nix create mode 100644 parts/features/security/yubico/_modules/yubikey-touch-detector/default.nix create mode 100644 parts/features/security/yubico/default.nix diff --git a/flake.lock b/flake.lock index 865b17e4..20d49f50 100644 --- a/flake.lock +++ b/flake.lock @@ -820,7 +820,7 @@ "sops-nix": "sops-nix" }, "locked": { - "narHash": "sha256-x3Mp8iZo/o5Xdz1s3og0cUAslOACoUqJolAjKk+H+ZE=", + "narHash": "sha256-inUTNigfTrWwN6eW7gRLUK9FZJF5VMUUU8mcwL2paJQ=", "path": "/home/farlion/code/nixos-secrets", "type": "path" }, diff --git a/parts/features/apps/nushell/_syncthing/stignore-nushell b/parts/features/apps/nushell/_syncthing/stignore-nushell new file mode 100644 index 00000000..4605b98f --- /dev/null +++ b/parts/features/apps/nushell/_syncthing/stignore-nushell @@ -0,0 +1,7 @@ +// .stignore for ~/.config/nushell +// (?d) allows for removal when deleting parent dirs and only an ignored file/directory remains + +// Only sync nushell history +!history.txt +// Ignore everything else +* diff --git a/parts/features/apps/nushell/config.nu b/parts/features/apps/nushell/config.nu new file mode 100644 index 00000000..40a158c4 --- /dev/null +++ b/parts/features/apps/nushell/config.nu @@ -0,0 +1,30 @@ +# Nushell Config File +# +# Defaults: https://github.com/nushell/nushell/blob/main/docs/sample_config/default_config.nu + +# The default config record. This is where much of your global configuration is setup. +$env.config = { + history: { + max_size: 1_000_000 # Session has to be reloaded for this to take effect + } + + keybindings: [ + { + name: open_command_editor + modifier: control + keycode: char_e + mode: [emacs, vi_normal, vi_insert] + event: { send: openeditor } + } + { + name: copy_command_line + modifier: control + keycode: char_x + mode: [emacs, vi_normal, vi_insert] + event: [ + { edit: selectall } + { edit: copyselectionsystem } + ] + } + ] +} diff --git a/parts/features/apps/nushell/default.nix b/parts/features/apps/nushell/default.nix new file mode 100644 index 00000000..bf4dd038 --- /dev/null +++ b/parts/features/apps/nushell/default.nix @@ -0,0 +1,30 @@ +{config, lib, ...}: let + cfg = config; +in { + flake.modules.homeManager.nushell = { + lib, + pkgs, + ... + }: let + nushellWithClipboard = pkgs.unstable.nushell.overrideAttrs (oldAttrs: { + cargoBuildFeatures = (oldAttrs.cargoBuildFeatures or []) ++ ["system-clipboard"]; + }); + in { + home.persistence."/persist" = lib.mkIf cfg.dendrix.isImpermanent { + directories = [ + ".config/nushell" + ]; + }; + home.file = { + ".config/nushell/.stignore" = { + source = ./_syncthing/stignore-nushell; + }; + }; + programs.nushell = { + enable = true; + configFile.source = ./config.nu; + envFile.source = ./env.nu; + package = nushellWithClipboard; + }; + }; +} diff --git a/parts/features/apps/nushell/env.nu b/parts/features/apps/nushell/env.nu new file mode 100644 index 00000000..889413ff --- /dev/null +++ b/parts/features/apps/nushell/env.nu @@ -0,0 +1 @@ +# Nushell Environment Config File diff --git a/parts/features/security/security.nix b/parts/features/security/security.nix new file mode 100644 index 00000000..f61981f3 --- /dev/null +++ b/parts/features/security/security.nix @@ -0,0 +1,62 @@ +{config, lib, ...}: let + cfg = config; +in { + flake.modules.nixos.security = { + lib, + pkgs, + ... + }: { + environment.persistence."/persist/system" = lib.mkIf cfg.dendrix.isImpermanent { + directories = [ + "/var/lib/boltd" + "/run/sudo" + ]; + }; + home-manager.users.farlion.home.persistence."/persist" = lib.mkIf cfg.dendrix.isImpermanent { + directories = [ + ".local/share/keyrings" + ".gnupg" + ]; + }; + + services.hardware.bolt.enable = true; + + services.gnome.gnome-keyring.enable = true; + environment.systemPackages = with pkgs; [ + libsecret + ]; + + programs.gnupg.agent = { + enable = true; + enableSSHSupport = false; + pinentryPackage = pkgs.pinentry-gnome3; + }; + + programs.seahorse.enable = true; + + security.sudo.extraConfig = '' + Defaults:root,%wheel timestamp_timeout=30 + ''; + users.users.farlion.extraGroups = ["wheel"]; + + services.pcscd.enable = true; + security.pam = { + u2f = { + enable = true; + control = "sufficient"; + settings = { + origin = "pam://farlion-realm"; + appid = "pam://farlion-realm"; + cue = false; + }; + }; + services = { + login.u2fAuth = false; + ly.u2fAuth = false; + sudo.u2fAuth = true; + swaylock.u2fAuth = true; + }; + }; + services.udev.packages = [pkgs.yubikey-personalization]; + }; +} diff --git a/parts/features/security/yubico/_modules/yubikey-touch-detector/default.nix b/parts/features/security/yubico/_modules/yubikey-touch-detector/default.nix new file mode 100644 index 00000000..de9ff892 --- /dev/null +++ b/parts/features/security/yubico/_modules/yubikey-touch-detector/default.nix @@ -0,0 +1,66 @@ +{ + config, + lib, + pkgs, + ... +}: +with lib; let + cfg = config.services.yubikey-touch-detector; +in { + options.services.yubikey-touch-detector = { + enable = mkEnableOption "a tool to detect when your YubiKey is waiting for a touch"; + + package = mkOption { + type = types.package; + default = pkgs.yubikey-touch-detector; + defaultText = "pkgs.yubikey-touch-detector"; + description = '' + Package to use. Binary is expected to be called "yubikey-touch-detector". + ''; + }; + + socket.enable = mkEnableOption "starting the process only when the socket is used"; + + extraArgs = mkOption { + type = types.listOf types.str; + default = ["--libnotify"]; + defaultText = literalExpression ''[ "--libnotify" ]''; + description = '' + Extra arguments to pass to the tool. The arguments are not escaped. + ''; + }; + }; + + config = mkIf cfg.enable { + home.packages = [cfg.package]; + + # Service description licensed under ISC + # See https://github.com/maximbaz/yubikey-touch-detector/blob/c9fdff7163361d6323e2de0449026710cacbc08a/LICENSE + # Author: Maxim Baz + systemd.user.sockets.yubikey-touch-detector = mkIf cfg.socket.enable { + Unit.Description = "Unix socket activation for YubiKey touch detector service"; + Socket = { + ListenFIFO = "%t/yubikey-touch-detector.sock"; + RemoveOnStop = true; + SocketMode = "0660"; + }; + Install.WantedBy = ["sockets.target"]; + }; + + # Same license thing for the description here + systemd.user.services.yubikey-touch-detector = { + Unit = { + Description = "Detects when your YubiKey is waiting for a touch"; + Requires = optionals cfg.socket.enable ["yubikey-touch-detector.socket"]; + }; + Service = { + ExecStart = "${cfg.package}/bin/yubikey-touch-detector ${concatStringsSep " " cfg.extraArgs}"; + Environment = ["PATH=${lib.makeBinPath [pkgs.gnupg]}"]; + Restart = "on-failure"; + RestartSec = "1sec"; + }; + Install.Also = optionals cfg.socket.enable ["yubikey-touch-detector.socket"]; + Install.WantedBy = ["default.target"]; + }; + }; +} diff --git a/parts/features/security/yubico/default.nix b/parts/features/security/yubico/default.nix new file mode 100644 index 00000000..105221a8 --- /dev/null +++ b/parts/features/security/yubico/default.nix @@ -0,0 +1,21 @@ +{...}: { + flake.modules.homeManager.yubico = {pkgs, ...}: { + imports = [ + ./_modules/yubikey-touch-detector + ]; + + home.packages = with pkgs; [ + pam_u2f + yubikey-manager + yubioath-flutter + ]; + + services = { + yubikey-touch-detector.enable = true; + dunst.settings.yubikey_touch_detector_icon = { + summary = "YubiKey is waiting for a touch"; + new_icon = "${pkgs.yubikey-touch-detector}/share/icons/hicolor/128x128/apps/yubikey-touch-detector.png"; + }; + }; + }; +} From d9f0a1eaa5641e85cfd3e870e69ea285fd418040 Mon Sep 17 00:00:00 2001 From: workflow <4farlion@gmail.com> Date: Sat, 31 Jan 2026 00:27:25 +0000 Subject: [PATCH 13/26] feat(dendritic): migrate batch of apps modules (obs, kubernetes-tools, etc.) --- parts/features/apps/ansible.nix | 9 + parts/features/apps/aws.nix | 15 ++ parts/features/apps/calibre.nix | 19 ++ .../_scripts/cpu-profile-toggler.sh | 19 ++ .../apps/cpu-profile-toggler/default.nix | 11 + .../_scripts/xps-9700-mic-fixer.sh | 3 + .../apps/fix-flexbox-mike/default.nix | 29 +++ parts/features/apps/galaxy-buds-client.nix | 15 ++ parts/features/apps/gnome-connections.nix | 19 ++ parts/features/apps/hoppscotch.nix | 22 ++ parts/features/apps/hwatch.nix | 5 + parts/features/apps/isd.nix | 19 ++ parts/features/apps/jqp.nix | 5 + .../_scripts/kind-with-local-registry.sh | 63 +++++ .../apps/kind-with-local-registry/default.nix | 9 + parts/features/apps/kubernetes-tools.nix | 19 ++ parts/features/apps/libation.nix | 18 ++ parts/features/apps/lnav.nix | 15 ++ .../_scripts/mic-levels-maintainer-flexbox.sh | 54 ++++ .../_scripts/mic-levels-maintainer-numenor.sh | 29 +++ .../apps/mic-levels-maintainer/default.nix | 28 ++ parts/features/apps/nautilus.nix | 18 ++ .../apps/networkmanager-dmenu/_config.ini | 48 ++++ .../apps/networkmanager-dmenu/default.nix | 6 + .../apps/obs/_scripts/obs-catcam-toggle.sh | 2 + .../apps/obs/_scripts/obs-main-scene.sh | 2 + .../apps/obs/_scripts/obs-recording-pause.sh | 2 + .../apps/obs/_scripts/obs-recording-toggle.sh | 2 + .../apps/obs/_scripts/obs-screensharing.sh | 2 + .../apps/obs/_scripts/obs-webcam-toggle.sh | 2 + parts/features/apps/obs/default.nix | 86 +++++++ parts/features/apps/onboard.nix | 5 + parts/features/apps/pgcli.nix | 5 + parts/features/apps/pomodoro-gtk.nix | 5 + parts/features/apps/portfolio-performance.nix | 15 ++ parts/features/apps/psql/_psqlrc | 2 + parts/features/apps/psql/default.nix | 6 + parts/features/apps/ripgrep-all.nix | 5 + parts/features/apps/showmethekey.nix | 5 + parts/features/apps/solaar.nix | 18 ++ .../_scripts/sound-switcher-flexbox.sh | 241 ++++++++++++++++++ .../_scripts/sound-switcher-numenor.sh | 156 ++++++++++++ .../features/apps/sound-switcher/default.nix | 14 + .../systemd-errors-and-warnings-counter.sh | 18 ++ .../default.nix | 11 + parts/features/apps/thunderbird.nix | 26 ++ parts/features/apps/urxvt.nix | 28 ++ parts/features/apps/variety/_variety.conf | 225 ++++++++++++++++ parts/features/apps/variety/default.nix | 6 + parts/features/dev/codex.nix | 15 ++ parts/features/dev/git-worktree-switcher.nix | 5 + 51 files changed, 1406 insertions(+) create mode 100644 parts/features/apps/ansible.nix create mode 100644 parts/features/apps/aws.nix create mode 100644 parts/features/apps/calibre.nix create mode 100644 parts/features/apps/cpu-profile-toggler/_scripts/cpu-profile-toggler.sh create mode 100644 parts/features/apps/cpu-profile-toggler/default.nix create mode 100644 parts/features/apps/fix-flexbox-mike/_scripts/xps-9700-mic-fixer.sh create mode 100644 parts/features/apps/fix-flexbox-mike/default.nix create mode 100644 parts/features/apps/galaxy-buds-client.nix create mode 100644 parts/features/apps/gnome-connections.nix create mode 100644 parts/features/apps/hoppscotch.nix create mode 100644 parts/features/apps/hwatch.nix create mode 100644 parts/features/apps/isd.nix create mode 100644 parts/features/apps/jqp.nix create mode 100644 parts/features/apps/kind-with-local-registry/_scripts/kind-with-local-registry.sh create mode 100644 parts/features/apps/kind-with-local-registry/default.nix create mode 100644 parts/features/apps/kubernetes-tools.nix create mode 100644 parts/features/apps/libation.nix create mode 100644 parts/features/apps/lnav.nix create mode 100644 parts/features/apps/mic-levels-maintainer/_scripts/mic-levels-maintainer-flexbox.sh create mode 100644 parts/features/apps/mic-levels-maintainer/_scripts/mic-levels-maintainer-numenor.sh create mode 100644 parts/features/apps/mic-levels-maintainer/default.nix create mode 100644 parts/features/apps/nautilus.nix create mode 100644 parts/features/apps/networkmanager-dmenu/_config.ini create mode 100644 parts/features/apps/networkmanager-dmenu/default.nix create mode 100644 parts/features/apps/obs/_scripts/obs-catcam-toggle.sh create mode 100644 parts/features/apps/obs/_scripts/obs-main-scene.sh create mode 100644 parts/features/apps/obs/_scripts/obs-recording-pause.sh create mode 100644 parts/features/apps/obs/_scripts/obs-recording-toggle.sh create mode 100644 parts/features/apps/obs/_scripts/obs-screensharing.sh create mode 100644 parts/features/apps/obs/_scripts/obs-webcam-toggle.sh create mode 100644 parts/features/apps/obs/default.nix create mode 100644 parts/features/apps/onboard.nix create mode 100644 parts/features/apps/pgcli.nix create mode 100644 parts/features/apps/pomodoro-gtk.nix create mode 100644 parts/features/apps/portfolio-performance.nix create mode 100644 parts/features/apps/psql/_psqlrc create mode 100644 parts/features/apps/psql/default.nix create mode 100644 parts/features/apps/ripgrep-all.nix create mode 100644 parts/features/apps/showmethekey.nix create mode 100644 parts/features/apps/solaar.nix create mode 100644 parts/features/apps/sound-switcher/_scripts/sound-switcher-flexbox.sh create mode 100644 parts/features/apps/sound-switcher/_scripts/sound-switcher-numenor.sh create mode 100644 parts/features/apps/sound-switcher/default.nix create mode 100644 parts/features/apps/systemd-errors-and-warnings-counter/_scripts/systemd-errors-and-warnings-counter.sh create mode 100644 parts/features/apps/systemd-errors-and-warnings-counter/default.nix create mode 100644 parts/features/apps/thunderbird.nix create mode 100644 parts/features/apps/urxvt.nix create mode 100644 parts/features/apps/variety/_variety.conf create mode 100644 parts/features/apps/variety/default.nix create mode 100644 parts/features/dev/codex.nix create mode 100644 parts/features/dev/git-worktree-switcher.nix diff --git a/parts/features/apps/ansible.nix b/parts/features/apps/ansible.nix new file mode 100644 index 00000000..446a7453 --- /dev/null +++ b/parts/features/apps/ansible.nix @@ -0,0 +1,9 @@ +{config, lib, ...}: let + cfg = config; +in { + flake.modules.homeManager.ansible = {lib, ...}: { + home.persistence."/persist" = lib.mkIf cfg.dendrix.isImpermanent { + directories = [".ansible"]; + }; + }; +} diff --git a/parts/features/apps/aws.nix b/parts/features/apps/aws.nix new file mode 100644 index 00000000..0d910485 --- /dev/null +++ b/parts/features/apps/aws.nix @@ -0,0 +1,15 @@ +{config, lib, ...}: let + cfg = config; +in { + flake.modules.homeManager.aws = { + lib, + pkgs, + ... + }: { + home.persistence."/persist" = lib.mkIf cfg.dendrix.isImpermanent { + directories = [".aws"]; + }; + + home.packages = [pkgs.awscli2]; + }; +} diff --git a/parts/features/apps/calibre.nix b/parts/features/apps/calibre.nix new file mode 100644 index 00000000..fe95b69d --- /dev/null +++ b/parts/features/apps/calibre.nix @@ -0,0 +1,19 @@ +{config, lib, ...}: let + cfg = config; +in { + flake.modules.homeManager.calibre = { + lib, + pkgs, + ... + }: { + home.persistence."/persist" = lib.mkIf cfg.dendrix.isImpermanent { + directories = [ + "Calibre Library" + ".config/calibre" + ".cache/calibre" + ]; + }; + + home.packages = [pkgs.calibre]; + }; +} diff --git a/parts/features/apps/cpu-profile-toggler/_scripts/cpu-profile-toggler.sh b/parts/features/apps/cpu-profile-toggler/_scripts/cpu-profile-toggler.sh new file mode 100644 index 00000000..06ad9d5c --- /dev/null +++ b/parts/features/apps/cpu-profile-toggler/_scripts/cpu-profile-toggler.sh @@ -0,0 +1,19 @@ +current_mode=$(cpupower frequency-info | grep -oP '(?<= governor ").*(?=")') + +if [[ "${1:-}" == "--toggle" ]]; then + if [ "$current_mode" == "powersave" ]; then + sudo auto-cpufreq --force performance + elif [ "$current_mode" == "performance" ]; then + sudo auto-cpufreq --force powersave + fi +elif [[ "${1:-}" == "--reset" ]]; then + if [ "$current_mode" == "powersave" ]; then + sudo auto-cpufreq --force reset + fi +else + if [ "$current_mode" == "powersave" ]; then + echo "{\"alt\": \"powersave\"}" + elif [ "$current_mode" == "performance" ]; then + echo "{\"alt\": \"performance\"}" + fi +fi diff --git a/parts/features/apps/cpu-profile-toggler/default.nix b/parts/features/apps/cpu-profile-toggler/default.nix new file mode 100644 index 00000000..005c4558 --- /dev/null +++ b/parts/features/apps/cpu-profile-toggler/default.nix @@ -0,0 +1,11 @@ +{...}: { + flake.modules.homeManager.cpu-profile-toggler = {pkgs, ...}: let + cpu-profile-toggler = pkgs.writeShellApplication { + name = "cpu-profile-toggler"; + runtimeInputs = with pkgs; [gnugrep auto-cpufreq linuxKernel.packages.linux_zen.cpupower]; + text = builtins.readFile ./_scripts/cpu-profile-toggler.sh; + }; + in { + home.packages = [cpu-profile-toggler]; + }; +} diff --git a/parts/features/apps/fix-flexbox-mike/_scripts/xps-9700-mic-fixer.sh b/parts/features/apps/fix-flexbox-mike/_scripts/xps-9700-mic-fixer.sh new file mode 100644 index 00000000..18972df9 --- /dev/null +++ b/parts/features/apps/fix-flexbox-mike/_scripts/xps-9700-mic-fixer.sh @@ -0,0 +1,3 @@ +amixer --card 1 set "rt715 ADC 24 Mux" "DMIC3" +amixer --card 1 set "rt715 DMIC3 Boost" 3 +amixer --card 1 set "PGA2.0 2 Master" 80 unmute diff --git a/parts/features/apps/fix-flexbox-mike/default.nix b/parts/features/apps/fix-flexbox-mike/default.nix new file mode 100644 index 00000000..640f4e07 --- /dev/null +++ b/parts/features/apps/fix-flexbox-mike/default.nix @@ -0,0 +1,29 @@ +{config, ...}: let + cfg = config; +in { + flake.modules.homeManager.fix-flexbox-mike = { + lib, + pkgs, + ... + }: let + isFlexbox = cfg.dendrix.hostname == "flexbox"; + xps-9700-mic-fixer = pkgs.writeShellApplication { + name = "xps-9700-mic-fixer"; + runtimeInputs = [pkgs.alsa-utils]; + text = builtins.readFile ./_scripts/xps-9700-mic-fixer.sh; + }; + in { + systemd.user.services.fixXPS9700Mike = lib.mkIf isFlexbox { + Unit = { + Description = "Fix ALSA settings for internal mic on Dell XPS 9700"; + }; + Install.WantedBy = ["pipewire.service"]; + Service = { + Environment = "PATH=$PATH:/run/current-system/sw/bin"; + ExecStart = "${xps-9700-mic-fixer}/bin/xps-9700-mic-fixer"; + Type = "oneshot"; + RemainAfterExit = true; + }; + }; + }; +} diff --git a/parts/features/apps/galaxy-buds-client.nix b/parts/features/apps/galaxy-buds-client.nix new file mode 100644 index 00000000..31b37c42 --- /dev/null +++ b/parts/features/apps/galaxy-buds-client.nix @@ -0,0 +1,15 @@ +{config, lib, ...}: let + cfg = config; +in { + flake.modules.homeManager.galaxy-buds-client = { + lib, + pkgs, + ... + }: { + home.persistence."/persist" = lib.mkIf cfg.dendrix.isImpermanent { + directories = [".local/share/GalaxyBudsClient"]; + }; + + home.packages = [pkgs.galaxy-buds-client]; + }; +} diff --git a/parts/features/apps/gnome-connections.nix b/parts/features/apps/gnome-connections.nix new file mode 100644 index 00000000..9a4cc24d --- /dev/null +++ b/parts/features/apps/gnome-connections.nix @@ -0,0 +1,19 @@ +{config, lib, ...}: let + cfg = config; +in { + flake.modules.homeManager.gnome-connections = { + lib, + pkgs, + ... + }: { + home.persistence."/persist" = lib.mkIf cfg.dendrix.isImpermanent { + directories = [ + ".config/freerdp" + ".config/dconf" + ]; + files = [".config/connections.db"]; + }; + + home.packages = [pkgs.gnome-connections]; + }; +} diff --git a/parts/features/apps/hoppscotch.nix b/parts/features/apps/hoppscotch.nix new file mode 100644 index 00000000..be2a7be1 --- /dev/null +++ b/parts/features/apps/hoppscotch.nix @@ -0,0 +1,22 @@ +{...}: { + flake.modules.homeManager.hoppscotch = {pkgs, ...}: let + hoppscotch-wrapped = pkgs.symlinkJoin { + name = "hoppscotch-wrapped"; + paths = [pkgs.unstable.hoppscotch]; + buildInputs = [pkgs.makeWrapper]; + postBuild = '' + wrapProgram $out/bin/hoppscotch \ + --set NIXOS_OZONE_WL 1 \ + --add-flags "--use-gl=desktop" \ + --add-flags "--disable-gpu-sandbox" + ''; + }; + in { + home.persistence."/persist".directories = [ + ".local/share/io.hoppscotch.desktop" + ".config/io.hoppscotch.desktop" + ]; + + home.packages = [hoppscotch-wrapped]; + }; +} diff --git a/parts/features/apps/hwatch.nix b/parts/features/apps/hwatch.nix new file mode 100644 index 00000000..a3db9bd8 --- /dev/null +++ b/parts/features/apps/hwatch.nix @@ -0,0 +1,5 @@ +{...}: { + flake.modules.homeManager.hwatch = {pkgs, ...}: { + home.packages = [pkgs.hwatch]; + }; +} diff --git a/parts/features/apps/isd.nix b/parts/features/apps/isd.nix new file mode 100644 index 00000000..6d895f8e --- /dev/null +++ b/parts/features/apps/isd.nix @@ -0,0 +1,19 @@ +{config, lib, ...}: let + cfg = config; +in { + flake.modules.homeManager.isd = { + lib, + pkgs, + ... + }: { + home.persistence."/persist" = lib.mkIf cfg.dendrix.isImpermanent { + directories = [ + ".config/isd_tui" + ".local/share/isd_tui" + ".cache/isd_tui" + ]; + }; + + home.packages = [pkgs.isd]; + }; +} diff --git a/parts/features/apps/jqp.nix b/parts/features/apps/jqp.nix new file mode 100644 index 00000000..ea5ac80f --- /dev/null +++ b/parts/features/apps/jqp.nix @@ -0,0 +1,5 @@ +{...}: { + flake.modules.homeManager.jqp = {...}: { + programs.jqp.enable = true; + }; +} diff --git a/parts/features/apps/kind-with-local-registry/_scripts/kind-with-local-registry.sh b/parts/features/apps/kind-with-local-registry/_scripts/kind-with-local-registry.sh new file mode 100644 index 00000000..80927c9a --- /dev/null +++ b/parts/features/apps/kind-with-local-registry/_scripts/kind-with-local-registry.sh @@ -0,0 +1,63 @@ +set -o errexit + +# 1. Create registry container unless it already exists +reg_name='kind-registry' +reg_port='5001' +if [ "$(docker inspect -f '{{.State.Running}}' "${reg_name}" 2>/dev/null || true)" != 'true' ]; then + docker run \ + -d --restart=always -p "127.0.0.1:${reg_port}:5000" --network bridge --name "${reg_name}" --log-driver json-file \ + registry:2 +fi + +# 2. Create kind cluster with containerd registry config dir enabled +# TODO: kind will eventually enable this by default and this patch will +# be unnecessary. +# +# See: +# https://github.com/kubernetes-sigs/kind/issues/2875 +# https://github.com/containerd/containerd/blob/main/docs/cri/config.md#registry-configuration +# See: https://github.com/containerd/containerd/blob/main/docs/hosts.md +cat < # (Default: False) use highlighting instead of active_chars (only applicable to Rofi / Wofi) +# highlight_fg = # (Default: None) foreground color of active connection (only applicable to Wofi) +# highlight_bg = # (Default: None) background color of active connection (only applicable to Wofi) +# highlight_bold = # (Default: True) make active connection bold (only applicable to Wofi) +# compact = # (Default: False). Remove extra spacing from display +# pinentry = # (Default: None) e.g. `pinentry-gtk` +# wifi_chars = +# wifi_chars = ▂▄▆█ +# wifi_icons = +# wifi_icons = 󰤯󰤟󰤢󰤥󰤨 +# format = +# format = {name} {sec} {bars} +# # Available variables are: +# # * {name} - Access point name +# # * {sec} - Security type +# # * {signal} - Signal strength on a scale of 0-100 +# # * {bars} - Bar-based display of signal strength (see wifi_chars) +# # * {icon} - Icon-based display of signal strength (see wifi_icons) +# # * {max_len_name} and {max_len_sec} are the maximum lengths of {name} / {sec} +# # respectively and may be useful for formatting. +# list_saved = # (Default: False) list saved connections + +[dmenu_passphrase] +# # Uses the -password flag for Rofi, -x for bemenu. For dmenu, sets -nb and +# # -nf to the same color or uses -P if the dmenu password patch is applied +# # https://tools.suckless.org/dmenu/patches/password/ +# obscure = True +# obscure_color = #222222 + +[pinentry] +# description = (Default: Get network password) +# prompt = (Default: Password:) + +[editor] +# terminal = +# gui_if_available = (Default: True) + +[nmdm] +# rescan_delay = # (seconds to wait after a wifi rescan before redisplaying the results) diff --git a/parts/features/apps/networkmanager-dmenu/default.nix b/parts/features/apps/networkmanager-dmenu/default.nix new file mode 100644 index 00000000..411f0006 --- /dev/null +++ b/parts/features/apps/networkmanager-dmenu/default.nix @@ -0,0 +1,6 @@ +{...}: { + flake.modules.homeManager.networkmanager-dmenu = {pkgs, ...}: { + home.packages = [pkgs.networkmanager_dmenu]; + xdg.configFile."networkmanager-dmenu/config.ini".source = ./_config.ini; + }; +} diff --git a/parts/features/apps/obs/_scripts/obs-catcam-toggle.sh b/parts/features/apps/obs/_scripts/obs-catcam-toggle.sh new file mode 100644 index 00000000..82702ea7 --- /dev/null +++ b/parts/features/apps/obs/_scripts/obs-catcam-toggle.sh @@ -0,0 +1,2 @@ +# Toggle Catcam source visibility +obs-cmd scene-item toggle "Virtual Cam" "Overlay: Cat Cam" diff --git a/parts/features/apps/obs/_scripts/obs-main-scene.sh b/parts/features/apps/obs/_scripts/obs-main-scene.sh new file mode 100644 index 00000000..7ca04626 --- /dev/null +++ b/parts/features/apps/obs/_scripts/obs-main-scene.sh @@ -0,0 +1,2 @@ +# Switch to OBS Main Scene +obs-cmd scene switch "OBS Vintage Cam" diff --git a/parts/features/apps/obs/_scripts/obs-recording-pause.sh b/parts/features/apps/obs/_scripts/obs-recording-pause.sh new file mode 100644 index 00000000..92170fd1 --- /dev/null +++ b/parts/features/apps/obs/_scripts/obs-recording-pause.sh @@ -0,0 +1,2 @@ +# Pause/Unpause Recording +obs-cmd recording toggle-pause diff --git a/parts/features/apps/obs/_scripts/obs-recording-toggle.sh b/parts/features/apps/obs/_scripts/obs-recording-toggle.sh new file mode 100644 index 00000000..11f0f70e --- /dev/null +++ b/parts/features/apps/obs/_scripts/obs-recording-toggle.sh @@ -0,0 +1,2 @@ +# Start/Stop Recording +obs-cmd recording toggle diff --git a/parts/features/apps/obs/_scripts/obs-screensharing.sh b/parts/features/apps/obs/_scripts/obs-screensharing.sh new file mode 100644 index 00000000..1debacd6 --- /dev/null +++ b/parts/features/apps/obs/_scripts/obs-screensharing.sh @@ -0,0 +1,2 @@ +# Switch to Screensharing scene +obs-cmd scene switch "Screensharing" diff --git a/parts/features/apps/obs/_scripts/obs-webcam-toggle.sh b/parts/features/apps/obs/_scripts/obs-webcam-toggle.sh new file mode 100644 index 00000000..107a08fb --- /dev/null +++ b/parts/features/apps/obs/_scripts/obs-webcam-toggle.sh @@ -0,0 +1,2 @@ +# Toggle Webcam source visibility +obs-cmd scene-item toggle "OBS Vintage Cam" Webcam diff --git a/parts/features/apps/obs/default.nix b/parts/features/apps/obs/default.nix new file mode 100644 index 00000000..74dc2d1b --- /dev/null +++ b/parts/features/apps/obs/default.nix @@ -0,0 +1,86 @@ +{config, lib, ...}: let + cfg = config; +in { + flake.modules.homeManager.obs = { + lib, + pkgs, + ... + }: let + isFlexbox = cfg.dendrix.hostname == "flexbox"; + + obsMainScene = pkgs.writeShellApplication { + name = "obs-main-scene"; + runtimeInputs = [pkgs.obs-cmd]; + text = builtins.readFile ./_scripts/obs-main-scene.sh; + }; + + obsScreensharing = pkgs.writeShellApplication { + name = "obs-screensharing"; + runtimeInputs = [pkgs.obs-cmd]; + text = builtins.readFile ./_scripts/obs-screensharing.sh; + }; + + obsCatcamToggle = pkgs.writeShellApplication { + name = "obs-catcam-toggle"; + runtimeInputs = [pkgs.obs-cmd]; + text = builtins.readFile ./_scripts/obs-catcam-toggle.sh; + }; + + obsRecordingToggle = pkgs.writeShellApplication { + name = "obs-recording-toggle"; + runtimeInputs = [pkgs.obs-cmd]; + text = builtins.readFile ./_scripts/obs-recording-toggle.sh; + }; + + obsRecordingPause = pkgs.writeShellApplication { + name = "obs-recording-pause"; + runtimeInputs = [pkgs.obs-cmd]; + text = builtins.readFile ./_scripts/obs-recording-pause.sh; + }; + + obsWebcamToggle = pkgs.writeShellApplication { + name = "obs-webcam-toggle"; + runtimeInputs = [pkgs.obs-cmd]; + text = builtins.readFile ./_scripts/obs-webcam-toggle.sh; + }; + in { + home.packages = [ + pkgs.obs-cmd + obsMainScene + obsScreensharing + obsCatcamToggle + obsRecordingToggle + obsRecordingPause + obsWebcamToggle + ]; + + home.persistence."/persist" = lib.mkIf cfg.dendrix.isImpermanent { + directories = [".config/obs-studio"]; + }; + + programs.obs-studio = { + enable = true; + plugins = with pkgs.obs-studio-plugins; [ + obs-backgroundremoval + pkgs.unstable.obs-studio-plugins.obs-noise + pkgs.unstable.obs-studio-plugins.pixel-art + pkgs.unstable.obs-studio-plugins.obs-recursion-effect + pkgs.unstable.obs-studio-plugins.obs-retro-effects + obs-vintage-filter + ]; + }; + + xdg.desktopEntries = lib.mkIf isFlexbox { + obs = { + name = "OBS Studio (NVIDIA GPU)"; + exec = "nvidia-offload obs"; + genericName = "Streaming/Recording Software"; + terminal = false; + type = "Application"; + categories = ["AudioVideo" "Recorder"]; + icon = "com.obsproject.Studio"; + startupNotify = true; + }; + }; + }; +} diff --git a/parts/features/apps/onboard.nix b/parts/features/apps/onboard.nix new file mode 100644 index 00000000..45a0ac95 --- /dev/null +++ b/parts/features/apps/onboard.nix @@ -0,0 +1,5 @@ +{...}: { + flake.modules.homeManager.onboard = {pkgs, ...}: { + home.packages = [pkgs.onboard]; + }; +} diff --git a/parts/features/apps/pgcli.nix b/parts/features/apps/pgcli.nix new file mode 100644 index 00000000..792944fd --- /dev/null +++ b/parts/features/apps/pgcli.nix @@ -0,0 +1,5 @@ +{...}: { + flake.modules.homeManager.pgcli = {...}: { + programs.pgcli.enable = true; + }; +} diff --git a/parts/features/apps/pomodoro-gtk.nix b/parts/features/apps/pomodoro-gtk.nix new file mode 100644 index 00000000..d108f447 --- /dev/null +++ b/parts/features/apps/pomodoro-gtk.nix @@ -0,0 +1,5 @@ +{...}: { + flake.modules.homeManager.pomodoro-gtk = {pkgs, ...}: { + home.packages = [pkgs.pomodoro-gtk]; + }; +} diff --git a/parts/features/apps/portfolio-performance.nix b/parts/features/apps/portfolio-performance.nix new file mode 100644 index 00000000..f00a213b --- /dev/null +++ b/parts/features/apps/portfolio-performance.nix @@ -0,0 +1,15 @@ +{config, lib, ...}: let + cfg = config; +in { + flake.modules.homeManager.portfolio-performance = { + lib, + pkgs, + ... + }: { + home.persistence."/persist" = lib.mkIf cfg.dendrix.isImpermanent { + directories = [".PortfolioPerformance"]; + }; + + home.packages = [pkgs.unstable.portfolio]; + }; +} diff --git a/parts/features/apps/psql/_psqlrc b/parts/features/apps/psql/_psqlrc new file mode 100644 index 00000000..7755ea63 --- /dev/null +++ b/parts/features/apps/psql/_psqlrc @@ -0,0 +1,2 @@ +\x auto +\pset pager 0 diff --git a/parts/features/apps/psql/default.nix b/parts/features/apps/psql/default.nix new file mode 100644 index 00000000..e228ad97 --- /dev/null +++ b/parts/features/apps/psql/default.nix @@ -0,0 +1,6 @@ +{...}: { + flake.modules.homeManager.psql = {pkgs, ...}: { + home.packages = [pkgs.postgresql]; + home.file.".psqlrc".source = ./_psqlrc; + }; +} diff --git a/parts/features/apps/ripgrep-all.nix b/parts/features/apps/ripgrep-all.nix new file mode 100644 index 00000000..53183512 --- /dev/null +++ b/parts/features/apps/ripgrep-all.nix @@ -0,0 +1,5 @@ +{...}: { + flake.modules.homeManager.ripgrep-all = {...}: { + programs.ripgrep-all.enable = true; + }; +} diff --git a/parts/features/apps/showmethekey.nix b/parts/features/apps/showmethekey.nix new file mode 100644 index 00000000..3979d989 --- /dev/null +++ b/parts/features/apps/showmethekey.nix @@ -0,0 +1,5 @@ +{...}: { + flake.modules.homeManager.showmethekey = {pkgs, ...}: { + home.packages = [pkgs.showmethekey]; + }; +} diff --git a/parts/features/apps/solaar.nix b/parts/features/apps/solaar.nix new file mode 100644 index 00000000..c98c599f --- /dev/null +++ b/parts/features/apps/solaar.nix @@ -0,0 +1,18 @@ +{config, lib, ...}: let + cfg = config; +in { + flake.modules.homeManager.solaar = { + lib, + pkgs, + ... + }: { + home.persistence."/persist" = lib.mkIf cfg.dendrix.isImpermanent { + directories = [".config/solaar"]; + }; + + home.packages = [ + pkgs.hicolor-icon-theme + pkgs.solaar + ]; + }; +} diff --git a/parts/features/apps/sound-switcher/_scripts/sound-switcher-flexbox.sh b/parts/features/apps/sound-switcher/_scripts/sound-switcher-flexbox.sh new file mode 100644 index 00000000..08319848 --- /dev/null +++ b/parts/features/apps/sound-switcher/_scripts/sound-switcher-flexbox.sh @@ -0,0 +1,241 @@ +chosen="$(echo -e "🔌local\n\ + buds(listen)\n\ + buds(talk)\n\ +🎧sony\n\ +🎧oh(localmic) +🎧🎙️oh(ohmic) +📢boombox\n\ + budsFE(listen)\n\ + budsFE(talk)\n\ +" | fuzzel --dmenu --prompt "🎶 [M]usic and 🎤 Switch")" + +localspeaker() { + local card_name_pattern="00_1f" + local potential_sinks=( + "alsa_output.pci-0000_00_1f.3-platform-sof_sdw.HiFi___ucm0003.hw_sofsoundwire_2__sink" + "alsa_output.pci-0000_00_1f.3-platform-sof_sdw.HiFi___ucm0005.hw_sofsoundwire_2__sink" + "alsa_output.pci-0000_00_1f.3-platform-sof_sdw.HiFi___ucm0007.hw_sofsoundwire_2__sink" + "alsa_output.pci-0000_00_1f.3-platform-sof_sdw.HiFi__hw_sofsoundwire_2__sink" + "alsa_output.pci-0000_00_1f.3-platform-sof_sdw.HiFi__Speaker__sink" + "alsa_output.pci-0000_00_1f.3.analog-stereo" + "alsa_output.pci-0000_00_1f.3.analog-stereo.2" + ) + local actual_sinks + local selected_sink + local card_profile="HiFi" + + actual_sinks=$(pactl list sinks) + for source in "${potential_sinks[@]}"; do + if [[ "$actual_sinks" == *"$source"* ]]; then + selected_sink=$source + break + fi + done + + if [ -z "$selected_sink" ]; then + echo "Local speaker not found" + return 1 + fi + + set_default_sink "$card_name_pattern" "$selected_sink" "$card_profile" + + localmike +} + +ohlocalmic() { + local card_name_pattern="Apple" + local sink="alsa_output.usb-Apple__Inc._USB-C_to_3.5mm_Headphone_Jack_Adapter_DWH84440324JKLTA7-00.analog-stereo" + local card_profile="HiFi" + + set_default_sink "$card_name_pattern" "$sink" "$card_profile" + + localmike +} + +ohohmic() { + local card_name_pattern="Apple" + local sink="alsa_output.usb-Apple__Inc._USB-C_to_3.5mm_Headphone_Jack_Adapter_DWH84440324JKLTA7-00.analog-stereo" + local card_profile="?" + + set_default_sink "$card_name_pattern" "$sink" "$card_profile" + + ohmike +} + +boombox() { + local card_name_pattern="04_21" + local sink="bluez_sink.04_21_44_B6_92_39.a2dp_sink" + local card_profile="?" + + local bd_address="04:21:44:B6:92:39" + local card_id + if [[ -z $card_id ]]; then + connect_bluetooth "$bd_address" + fi + + set_default_sink "$card_name_pattern" "$sink" "$card_profile" + + localmike +} + +budsfelisten() { + local card_name_pattern="34_E3" + local sink="bluez_output.34_E3_FB_C5_01_E0.1" + local card_profile="a2dp-sink-sbc" + + set_default_sink "$card_name_pattern" "$sink" "$card_profile" + + localmike +} + +budsfetalk() { + local card_name_pattern="34_E3" + local sink="bluez_output.34_E3_FB_C5_01_E0.1" + local card_profile="headset-head-unit" + + set_default_sink "$card_name_pattern" "$sink" "$card_profile" + + budsfemike +} + +budslisten() { + local card_name_pattern="DC_69" + local sink="bluez_output.DC_69_E2_9A_6E_30.1" + local card_profile="a2dp-sink-sbc" + + set_default_sink "$card_name_pattern" "$sink" "$card_profile" + + localmike +} + +budstalk() { + local card_name_pattern="DC_69" + local sink="bluez_output.DC_69_E2_9A_6E_30.1" + local card_profile="headset-head-unit" + + set_default_sink "$card_name_pattern" "$sink" "$card_profile" + + budsmike +} + +sony() { + local card_name_pattern="14_3F" + local sink="bluez_output.14_3F_A6_28_DC_51.1" + local card_profile="a2dp-sink" + + local bd_address="14:3F:A6:28:DC:51" + local card_id + card_id=$(get_card_id "$card_name_pattern") + if [[ -z $card_id ]]; then + connect_bluetooth "$bd_address" + fi + + set_default_sink "$card_name_pattern" "$sink" "$card_profile" + + localmike +} + +localmike() { + local card_name_pattern="00_1f" + local potential_sources=( + "alsa_input.pci-0000_00_1f.3-platform-sof_sdw.HiFi___ucm0003.hw_sofsoundwire_4__source" + "alsa_input.pci-0000_00_1f.3-platform-sof_sdw.HiFi___ucm0005.hw_sofsoundwire_4__source" + "alsa_input.pci-0000_00_1f.3-platform-sof_sdw.HiFi___ucm0007.hw_sofsoundwire_4__source" + "alsa_input.pci-0000_00_1f.3-platform-sof_sdw.HiFi__hw_sofsoundwire_4__source" + "alsa_input.usb-C-Media_Electronics_Inc._USB_PnP_Audio_Device-00.mono-fallback" + "alsa_input.pci-0000_00_1f.3-platform-sof_sdw.HiFi__Mic__source" + ) + local actual_sources + local selected_source + local card_profile="HiFi" + + actual_sources=$(pactl list sources) + for source in "${potential_sources[@]}"; do + if [[ "$actual_sources" == *"$source"* ]]; then + selected_source=$source + break + fi + done + + if [ -z "$selected_source" ]; then + echo "Local mike not found" + return 1 + fi + + set_default_source "$card_name_pattern" "$selected_source" "$card_profile" +} + +ohmike() { + local card_name_pattern="Apple" + local source="alsa_input.usb-Apple__Inc._USB-C_to_3.5mm_Headphone_Jack_Adapter_DWH84440324JKLTA7-00.mono-fallback" + local card_profile="?" + + set_default_source "$card_name_pattern" "$source" "$card_profile" +} + +budsfemike() { + local card_name_pattern="34_E3" + local source="bluez_input.34_E3_FB_C5_01_E0" + local card_profile="headset-head-unit" + + set_default_source "$card_name_pattern" "$source" "$card_profile" +} + +budsmike() { + local card_name_pattern="DC_69" + local source="bluez_input.DC:69:E2:9A:6E:30" + local card_profile="headset-head-unit" + + set_default_source "$card_name_pattern" "$source" "$card_profile" +} + +get_card_id() { + local card_name_pattern="$1" + nu -c "pactl list cards short | lines | parse \"{id}\t{name}\t{_}\" | where \$it.name =~ \"$card_name_pattern\" | get id | get 0" || true +} + +set_default_sink() { + local card_name_pattern="$1" + local sink="$2" + local card_profile="$3" + + local card_id + card_id=$(get_card_id "$card_name_pattern") + + pactl set-card-profile "$card_id" "$card_profile" + pactl set-default-sink "$sink" +} + +set_default_source() { + local card_name_pattern="$1" + local source="$2" + local card_profile="$3" + + local card_id + card_id=$(get_card_id "$card_name_pattern") + + pactl set-card-profile "$card_id" "$card_profile" + pactl set-default-source "$source" +} + +connect_bluetooth() { + local bd_address="$1" + + echo -e 'power on\nquit' | bluetoothctl + sleep 2 + echo -e "connect $bd_address\nquit" | bluetoothctl + sleep 10 +} + +case "$chosen" in +🔌local) localspeaker ;; +"🎧oh(localmic)") ohlocalmic ;; +"🎧🎙️oh(ohmic)") ohohmic ;; +🎧sony) sony ;; +" budsFE(listen)") budsfelisten ;; +" budsFE(talk)") budsfetalk ;; +" buds(listen)") budslisten ;; +" buds(talk)") budstalk ;; +📢boombox) boombox ;; +*) exit 1 ;; +esac diff --git a/parts/features/apps/sound-switcher/_scripts/sound-switcher-numenor.sh b/parts/features/apps/sound-switcher/_scripts/sound-switcher-numenor.sh new file mode 100644 index 00000000..d5cb6833 --- /dev/null +++ b/parts/features/apps/sound-switcher/_scripts/sound-switcher-numenor.sh @@ -0,0 +1,156 @@ +chosen="$(echo -e "🎧oh\n\ +🔊creative\n\ +🎧sony\n\ +🍿movie\n\ + buds(listen)\n\ + buds(talk)\n\ +📢boombox\n\ +" | fuzzel --dmenu --prompt "🎶 [M]usic and 🎤 Switch")" + +oh() { + local card_name_pattern="ThinkPad_Thunderbolt" + local sink="alsa_output.usb-Lenovo_ThinkPad_Thunderbolt_3_Dock_USB_Audio_000000000000-00.analog-stereo" + local card_profile="output:analog-stereo" + + set_default_sink "$card_name_pattern" "$sink" "$card_profile" + + localmike +} + +creative() { + local card_name_pattern="usb-Generic_USB_Audio-00" + local sink="alsa_output.usb-Generic_USB_Audio-00.analog-stereo" + local card_profile="output:analog-stereo" + + set_default_sink "$card_name_pattern" "$sink" "$card_profile" + + localmike +} + +movie() { + local card_name_pattern="0000_03_00" + local sink="alsa_output.pci-0000_03_00.1.hdmi-stereo-extra3" + local card_profile="output:hdmi-stereo-extra3" + + set_default_sink "$card_name_pattern" "$sink" "$card_profile" + + localmike +} + +boombox() { + local card_name_pattern="04_21" + local sink="bluez_sink.04_21_44_B6_92_39.a2dp_sink" + local card_profile="?" + + local bd_address="04:21:44:B6:92:39" + local card_id + if [[ -z $card_id ]]; then + connect_bluetooth "$bd_address" + fi + + set_default_sink "$card_name_pattern" "$sink" "$card_profile" + + localmike +} + +budslisten() { + local card_name_pattern="DC_69" + local sink="bluez_output.DC_69_E2_9A_6E_30.1" + local card_profile="a2dp-sink-sbc" + + set_default_sink "$card_name_pattern" "$sink" "$card_profile" + + localmike +} + +budstalk() { + local card_name_pattern="DC_69" + local sink="bluez_output.DC_69_E2_9A_6E_30.1" + local card_profile="headset-head-unit" + + set_default_sink "$card_name_pattern" "$sink" "$card_profile" + + budsmike +} + +sony() { + local card_name_pattern="14_3F" + local sink="bluez_output.14_3F_A6_28_DC_51.1" + local card_profile="a2dp-sink" + + local bd_address="14:3F:A6:28:DC:51" + local card_id + card_id=$(get_card_id "$card_name_pattern") + if [[ -z $card_id ]]; then + connect_bluetooth "$bd_address" + fi + + set_default_sink "$card_name_pattern" "$sink" "$card_profile" + + localmike +} + +localmike() { + local card_name_pattern="Blue_Microphones" + local source="alsa_input.usb-Generic_Blue_Microphones_LT_221104181411AD020101_111000-00.analog-stereo" + local card_profile="input:analog-stereo" + + set_default_source "$card_name_pattern" "$source" "$card_profile" +} + +budsmike() { + local card_name_pattern="DC_69" + local source="bluez_input.DC:69:E2:9A:6E:30" + local card_profile="headset-head-unit" + + set_default_source "$card_name_pattern" "$source" "$card_profile" +} + +get_card_id() { + local card_name_pattern="$1" + nu -c "pactl list cards short | lines | parse \"{id}\t{name}\t{_}\" | where \$it.name =~ \"$card_name_pattern\" | get id | get 0" || true +} + +set_default_sink() { + local card_name_pattern="$1" + local sink="$2" + local card_profile="$3" + + local card_id + card_id=$(get_card_id "$card_name_pattern") + + pactl set-card-profile "$card_id" "$card_profile" + pactl set-default-sink "$sink" +} + +set_default_source() { + local card_name_pattern="$1" + local source="$2" + local card_profile="$3" + + local card_id + card_id=$(get_card_id "$card_name_pattern") + + pactl set-card-profile "$card_id" "$card_profile" + pactl set-default-source "$source" +} + +connect_bluetooth() { + local bd_address="$1" + + echo -e 'power on\nquit' | bluetoothctl + sleep 2 + echo -e "connect $bd_address\nquit" | bluetoothctl + sleep 10 +} + +case "$chosen" in +🎧oh) oh ;; +🔊creative) creative ;; +🎧sony) sony ;; +🍿movie) movie ;; +" buds(listen)") budslisten ;; +" buds(talk)") budstalk ;; +📢boombox) boombox ;; +*) exit 1 ;; +esac diff --git a/parts/features/apps/sound-switcher/default.nix b/parts/features/apps/sound-switcher/default.nix new file mode 100644 index 00000000..83fcf4fc --- /dev/null +++ b/parts/features/apps/sound-switcher/default.nix @@ -0,0 +1,14 @@ +{config, ...}: let + cfg = config; +in { + flake.modules.homeManager.sound-switcher = {pkgs, ...}: let + isNumenor = cfg.dendrix.hostname == "numenor"; + sound-switcher = pkgs.writers.writeBashBin "sound-switcher" ( + if isNumenor + then (builtins.readFile ./_scripts/sound-switcher-numenor.sh) + else (builtins.readFile ./_scripts/sound-switcher-flexbox.sh) + ); + in { + home.packages = [sound-switcher]; + }; +} diff --git a/parts/features/apps/systemd-errors-and-warnings-counter/_scripts/systemd-errors-and-warnings-counter.sh b/parts/features/apps/systemd-errors-and-warnings-counter/_scripts/systemd-errors-and-warnings-counter.sh new file mode 100644 index 00000000..24691ce8 --- /dev/null +++ b/parts/features/apps/systemd-errors-and-warnings-counter/_scripts/systemd-errors-and-warnings-counter.sh @@ -0,0 +1,18 @@ +WARNINGS=$(journalctl -p 4..4 --since "10 minutes ago" --boot --output json | wc -l) +ERRORS=$(journalctl -p 3..3 --since "10 minutes ago" --boot --output json | wc -l) + +WARNING_ICON="⚠️" +ERROR_ICON="❗" + +# Determine state based on number of errors +if [ "$ERRORS" -eq 0 ]; then + STATE="Good" +elif [ "$ERRORS" -le 2 ]; then + STATE="Info" +elif [ "$ERRORS" -le 5 ]; then + STATE="Warning" +else + STATE="Critical" +fi + +echo "{\"text\":\"${ERROR_ICON}${ERRORS} ${WARNING_ICON}${WARNINGS}\",\"short_text\":\"${ERRORS}\",\"state\":\"${STATE}\"}" diff --git a/parts/features/apps/systemd-errors-and-warnings-counter/default.nix b/parts/features/apps/systemd-errors-and-warnings-counter/default.nix new file mode 100644 index 00000000..35b2c8aa --- /dev/null +++ b/parts/features/apps/systemd-errors-and-warnings-counter/default.nix @@ -0,0 +1,11 @@ +{...}: { + flake.modules.homeManager.systemd-errors-and-warnings-counter = {pkgs, ...}: let + systemd-errors-and-warnings-counter = pkgs.writeShellApplication { + name = "systemd-errors-and-warnings-counter"; + runtimeInputs = [pkgs.systemd pkgs.coreutils]; + text = builtins.readFile ./_scripts/systemd-errors-and-warnings-counter.sh; + }; + in { + home.packages = [systemd-errors-and-warnings-counter]; + }; +} diff --git a/parts/features/apps/thunderbird.nix b/parts/features/apps/thunderbird.nix new file mode 100644 index 00000000..4d73d31f --- /dev/null +++ b/parts/features/apps/thunderbird.nix @@ -0,0 +1,26 @@ +{config, lib, ...}: let + cfg = config; +in { + flake.modules.homeManager.thunderbird = {lib, ...}: { + home.persistence."/persist" = lib.mkIf cfg.dendrix.isImpermanent { + directories = [ + ".thunderbird" + ".cache/thunderbird" + ]; + }; + + programs.thunderbird = { + enable = true; + profiles = { + "main" = { + isDefault = true; + settings = { + "calendar.alarms.showmissed" = false; + "calendar.alarms.playsound" = false; + "calendar.alarms.show" = false; + }; + }; + }; + }; + }; +} diff --git a/parts/features/apps/urxvt.nix b/parts/features/apps/urxvt.nix new file mode 100644 index 00000000..370b5ba2 --- /dev/null +++ b/parts/features/apps/urxvt.nix @@ -0,0 +1,28 @@ +{...}: { + flake.modules.homeManager.urxvt = {pkgs, ...}: { + programs.urxvt = { + enable = true; + + extraConfig = { + perl-ext-common = "default,matcher,resize-font,vtwheel,keyboard-select,-searchable-scrollback"; + url-launcher = "${pkgs.xdg-utils}/bin/xdg-open"; + "matcher.button" = 1; + iso14755_52 = false; + "keyboard-select.clipboard" = true; + }; + + fonts = ["xft:FiraCode Nerd Font Mono:size=8"]; + iso14755 = false; + + keybindings = { + "Shift-Control-C" = "eval:selection_to_clipboard"; + "Shift-Control-V" = "eval:paste_clipboard"; + "Meta-Escape" = "perl:keyboard-select:activate"; + "Meta-Shift-S" = "perl:keyboard-select:search"; + }; + + package = pkgs.rxvt-unicode; + scroll.bar.enable = false; + }; + }; +} diff --git a/parts/features/apps/variety/_variety.conf b/parts/features/apps/variety/_variety.conf new file mode 100644 index 00000000..57116dd5 --- /dev/null +++ b/parts/features/apps/variety/_variety.conf @@ -0,0 +1,225 @@ +# change_on_start = +change_on_start = False + +# change_enabled = +change_enabled = True + +# change_interval = +change_interval = 86400 + +# safe_mode = +safe_mode = False + +# download_folder = - when not specified, the default is ~/.config/variety/Downloaded +download_folder = ~/.config/variety/Downloaded + +# download_preference_ratio - if we have "unconsumed" download sources, we'll prefer to show a newly +# downloades image instead of an existing one in this percentage of the cases +download_preference_ratio = 0.9 + +# Determine if the download folder sould not exceed a certain size (in megabytes) +# quota_enabled = +# quota_size = +quota_enabled = False +quota_size = 1000 + +# favorites_folder = - when not specified, the default is ~/.config/variety/Favorites +favorites_folder = ~/Pictures/variety/Favorites + +# Prefer Copy to Favorites or Move to Favorites operation (or both), depending on the folder of the current image +# favorites_operations = +# The default is: Downloaded:Copy;Fetched:Move;Others:Copy +# Order is important - the first matching entry will determine what operation(s) to show in the menu for a specific file +# Special folder names you can use: Downloaded, Fetched and Others (same as "/" - use it as last entry to determine the default operation) +# Example1: Downloaded:Copy;Fetched:Move;/pics/RandomImages:Move;/pics/OrganizedAlbums:Copy;Others:Copy +# Example2: Others:Both - always show both Copy and Move to Favorites, no matter which image is shown +# Move to Favorites is only shown when the user has write permissions over the file, otherwise we fallback to Copy +favorites_operations = Downloaded:Copy;Fetched:Move;Others:Copy + +# wallpaper_display_mode = <"os" | +# "smart" | "zoom" | "fill-with-black" | "fill-with-blur" | +# "gnome-zoom" | "gnome-centered" | "gnome-scaled" | "gnome-stretched" | "gnome-spanned", "gnome-wallpaper"> +wallpaper_display_mode = "smart" + +# fetch_folder = - when not specified, the default is ~/.config/variety/Fetched +fetched_folder = ~/.config/variety/Fetched + +# Clipboard monitoring settings +# clipboard_enabled = +# clipboard_use_whitelist = +# clipboard_hosts = +clipboard_enabled = False +clipboard_use_whitelist = True +clipboard_hosts = "wallhaven.cc,wallpapers.net,flickr.com,imgur.com,deviantart.com,interfacelift.com,vladstudio.com,imageshack.us,deviantart.net,imageshack.com" + +# Icon settings +# icon = +icon = Dark + +# Prefer only images with this color: +# desired_color_enabled = +# desired_color = +# DISCLAIMER: This feature is still experimental +desired_color_enabled = False +desired_color = 160 160 160 + +# Minimum size of images to use, as a percentage of the screen resolution +# min_size_enabled = +# min_size = +min_size_enabled = True +min_size = 80 + +# Should we use only landscape-oriented images? +# use_landscape_enabled = +use_landscape_enabled = True + +# Prefer light or dark images +# lightness_enabled = +# lightness_mode = <0 for Dark, 1 for Light> +lightness_enabled = True +lightness_mode = 0 + +# Use a filter by rating? +# min_rating_enabled = +# min_rating = <1 | 2 | 3 | 4 | 5> +min_rating_enabled = False +min_rating = 4 + +# What parts of the initial wizard have we covered +smart_notice_shown = False +smart_register_shown = False +stats_notice_shown = False + +# Are smart features enabled (i.e. data collection on Fav/Trash operations), also sync, and anonymous usage stats collection? +# smart_enabled = +smart_enabled = True +sync_enabled = True +stats_enabled = True + +# Folder to copy the wallpaper image to and make it world-readable. Provides LightDM support. +# copyto_enabled = , default is False +# copyto_folder = , the default is Default +# Default means to use the XDG Pictures folder when home folder is unencrypted and /usr/share/backgrounds when it is encrypted. +copyto_enabled = False +copyto_folder = Default + +# Clock settings +# clock_enabled = +# clock_font = , default is "Ubuntu Condensed, 70" +# clock_date_font = , default is "Ubuntu Condensed, 30" +clock_enabled = False +clock_font = "Ubuntu Condensed, 70" +clock_date_font = "Ubuntu Condensed, 30" + +# clock_filter = +# +# The filter defines the ImageMagick command that Variety uses to render the clock on the wallpaper. +# First some scaling is applied to get the image down to the screen size - this ensures +# the final drawn clock won't be rescaled by the desktop wallpaper system. +# Easiest way to see what's happening is to run variety with -v, enable clock and see what ImageMagick +# commands Variety dumps in the log. +# +# The user may want to customize the following aspects: +# fill - color of "filling" +# stroke - color of outline +# strokewidth - width of outline +# gravity - in which corner to display the clock - SouthEast, NorthEast, SouthWest, NorthWest +# annotate - these must be in the form 0x0+[%HOFFSET+X]+[%VOFFSET+Y], where you can edit X and Y - +# distance from the screen corner defined by gravity. Write them in even if they are 0. +# +# The %HOFFSET and %VOFFSET parameters are there for Variety to replace in order to compensate for the +# diferent dimensions of every image and screen. +# The several %FONT parameters are there for Variety to replace with the font settings from the GUI. +# +# The texts can contain these symbols: +# +# %H - hours (24), %I - zero-padded hours (12), %l - hours (12), %p - am or pm, %M - minutes, +# %A - day of week (full), %a - day of week abbreviation, %B - month name, %b - month abbreviation, %d - day of month, %Y - year. +# The full list for these can be seen here: http://docs.python.org/library/datetime.html#strftime-strptime-behavior +# Have in mind that Variety will not update the clock more often than once every minute, so using seconds (%S) for example is pointless +# +# A tutorial on "annotating" with ImageMagick that you may use as a reference: http://www.imagemagick.org/Usage/annotating/ +# You can get a very uniquely looking clock with some of the more advanced techniques (e.g. circle-shaped text, interesting colors and shading, etc....). + +clock_filter = "-density 100 -font `fc-match -f '%{file[0]}' '%CLOCK_FONT_NAME'` -pointsize %CLOCK_FONT_SIZE -gravity SouthEast -fill '#00000044' -annotate 0x0+[%HOFFSET+58]+[%VOFFSET+108] '%H:%M' -fill white -annotate 0x0+[%HOFFSET+60]+[%VOFFSET+110] '%H:%M' -font `fc-match -f '%{file[0]}' '%DATE_FONT_NAME'` -pointsize %DATE_FONT_SIZE -fill '#00000044' -annotate 0x0+[%HOFFSET+58]+[%VOFFSET+58] '%A, %B %d' -fill white -annotate 0x0+[%HOFFSET+60]+[%VOFFSET+60] '%A, %B %d'" + +# Quotes settings +# quotes_enabled = +# quotes_font = , default is Bitstream Charter 30 +# quotes_text_color = , default is 255 255 255 +# quotes_bg_color = , default is 80 80 80 +# quotes_bg_opacity = <0-100>, default is 55 +# quotes_width = <0-100>, default is 70 +# quotes_hpos = <0-100>, default is 100 +# quotes_vpos = <0-100>, default is 40 +# quotes_max_length = a positive integer, quotes above this length will not be displayed +# (as they often won't fit well on screen) +# quotes_text_shadow = , default is False +# quotes_disabled_sources = <|-separated list of disabled quote plugin names>, default is empty +# quotes_tags = , default is empty +# quotes_authors = , default is empty +# quotes_change_enabled = +# quotes_change_interval = , default is 300 +quotes_enabled = True +quotes_font = Fira Code 30 +quotes_text_color = 234 212 155 # #ead49b +quotes_bg_color = 30 39 43 # #1e272b +quotes_bg_opacity = 55 +quotes_text_shadow = False +quotes_width = 70 +quotes_hpos = 100 +quotes_vpos = 40 +quotes_max_length = 250 +quotes_disabled_sources = "Urban Dictionary" +quotes_tags = "" +quotes_authors = "" +quotes_change_enabled = False +quotes_change_interval = 86400 +quotes_favorites_file = ~/Pictures/variety/favorite_quotes.txt +quotes_favorites_format = fortune + +# Slideshow settings +slideshow_favorites_enabled = True +slideshow_sources_enabled = True +slideshow_downloads_enabled = False +slideshow_custom_enabled = False +slideshow_custom_folder = ~/Pictures +slideshow_sort_order = Random +slideshow_monitor = All +slideshow_mode = Fullscreen +slideshow_seconds = 6.0 +slideshow_fade = 0.4 +slideshow_zoom = 0.2 +slideshow_pan = 0.05 + +# List of sources +# Each source is srcX = +# location depends on type - path or url or search options, or just a name for unconfigurable sources +# Folders are included recursively +# BE CAREFUL: all keys below (src1, src2, etc.) MUST be different +[sources] +src1 = True|favorites|The Favorites folder +src2 = False|fetched|The Fetched folder +src3 = True|folder|/usr/share/backgrounds +src4 = False|flickr|user:www.flickr.com/photos/peter-levi/;user_id:93647178@N00; +src5 = True|apod|NASA's Astronomy Picture of the Day +src6 = True|bing|Bing Photo of the Day +src7 = True|chromeos|Chrome OS Wallpapers +src8 = True|desktoppr|Random wallpapers from Desktoppr.co +src9 = False|earth|World Sunlight Map - live wallpaper from Die.net +src10 = False|earthview|Google Earth View Wallpapers +src11 = True|unsplash|High-resolution photos from Unsplash.com +src12 = True|natgeo|National Geographic Photo of the Day + +# Image filters to apply randomly to every wallpaper (ImageMagick is used for this) +# Each filter is filterX = +# BE CAREFUL: all keys below (filter1, filter2, etc.) MUST be different +[filters] +filter1 = True|Keep original| +filter2 = False|Grayscale|-type Grayscale +filter3 = False|Heavy blur|-blur 120x40 +filter4 = False|Soft blur|-blur 20x7 +filter5 = True|Oil painting|-paint 8 +filter6 = False|Pointilism|-spread 10 -noise 3 +filter7 = False|Pixellate|-scale 3% -scale 3333% + diff --git a/parts/features/apps/variety/default.nix b/parts/features/apps/variety/default.nix new file mode 100644 index 00000000..d92a74b3 --- /dev/null +++ b/parts/features/apps/variety/default.nix @@ -0,0 +1,6 @@ +{...}: { + flake.modules.homeManager.variety = {pkgs, ...}: { + home.packages = [pkgs.variety]; + home.file.".config/variety/variety.conf".source = ./_variety.conf; + }; +} diff --git a/parts/features/dev/codex.nix b/parts/features/dev/codex.nix new file mode 100644 index 00000000..35a8e9ff --- /dev/null +++ b/parts/features/dev/codex.nix @@ -0,0 +1,15 @@ +{config, lib, ...}: let + cfg = config; +in { + flake.modules.homeManager.codex = { + lib, + pkgs, + ... + }: { + home.persistence."/persist" = lib.mkIf cfg.dendrix.isImpermanent { + directories = [".codex"]; + }; + + home.packages = [pkgs.unstable.codex]; + }; +} diff --git a/parts/features/dev/git-worktree-switcher.nix b/parts/features/dev/git-worktree-switcher.nix new file mode 100644 index 00000000..0b8e2632 --- /dev/null +++ b/parts/features/dev/git-worktree-switcher.nix @@ -0,0 +1,5 @@ +{...}: { + flake.modules.homeManager.git-worktree-switcher = {...}: { + programs.git-worktree-switcher.enable = true; + }; +} From 17b79ad50ce0f9f700d435a63d6d82019861cb6b Mon Sep 17 00:00:00 2001 From: workflow <4farlion@gmail.com> Date: Sat, 31 Jan 2026 00:33:18 +0000 Subject: [PATCH 14/26] feat(dendritic): migrate core system modules (boot, networking, users, etc.) --- parts/features/apps/wireshark.nix | 7 + parts/features/core/boot.nix | 16 +++ parts/features/core/cachix.nix | 5 + parts/features/core/dns.nix | 14 ++ .../fonts/_scripts/patch-fira-with-fa6-pro.sh | 130 ++++++++++++++++++ parts/features/core/fonts/default.nix | 76 ++++++++++ parts/features/core/impermanence.nix | 96 +++++++++++++ parts/features/core/kernel.nix | 21 +++ parts/features/core/locale.nix | 25 ++++ .../core/networking/_scripts/tailscale-ip.sh | 9 ++ parts/features/core/networking/default.nix | 65 +++++++++ parts/features/core/nix-ld.nix | 5 + parts/features/core/performance.nix | 8 ++ parts/features/core/smb.nix | 6 + parts/features/core/systemd.nix | 5 + parts/features/core/users.nix | 24 ++++ parts/features/desktop/display-manager.nix | 62 +++++++++ parts/features/hardware/btrfs.nix | 15 ++ parts/features/hardware/firmware.nix | 11 ++ parts/features/hardware/io.nix | 42 ++++++ parts/features/hardware/video.nix | 12 ++ parts/features/services/kind-killer.nix | 15 ++ parts/features/services/localsend.nix | 13 ++ parts/features/services/scrutiny.nix | 26 ++++ 24 files changed, 708 insertions(+) create mode 100644 parts/features/apps/wireshark.nix create mode 100644 parts/features/core/boot.nix create mode 100644 parts/features/core/cachix.nix create mode 100644 parts/features/core/dns.nix create mode 100644 parts/features/core/fonts/_scripts/patch-fira-with-fa6-pro.sh create mode 100644 parts/features/core/fonts/default.nix create mode 100644 parts/features/core/impermanence.nix create mode 100644 parts/features/core/kernel.nix create mode 100644 parts/features/core/locale.nix create mode 100644 parts/features/core/networking/_scripts/tailscale-ip.sh create mode 100644 parts/features/core/networking/default.nix create mode 100644 parts/features/core/nix-ld.nix create mode 100644 parts/features/core/performance.nix create mode 100644 parts/features/core/smb.nix create mode 100644 parts/features/core/systemd.nix create mode 100644 parts/features/core/users.nix create mode 100644 parts/features/desktop/display-manager.nix create mode 100644 parts/features/hardware/btrfs.nix create mode 100644 parts/features/hardware/firmware.nix create mode 100644 parts/features/hardware/io.nix create mode 100644 parts/features/hardware/video.nix create mode 100644 parts/features/services/kind-killer.nix create mode 100644 parts/features/services/localsend.nix create mode 100644 parts/features/services/scrutiny.nix diff --git a/parts/features/apps/wireshark.nix b/parts/features/apps/wireshark.nix new file mode 100644 index 00000000..f6ff67fe --- /dev/null +++ b/parts/features/apps/wireshark.nix @@ -0,0 +1,7 @@ +{...}: { + flake.modules.nixos.wireshark = {pkgs, ...}: { + environment.systemPackages = [pkgs.wireshark]; + programs.wireshark.enable = true; + users.users.farlion.extraGroups = ["wireshark"]; + }; +} diff --git a/parts/features/core/boot.nix b/parts/features/core/boot.nix new file mode 100644 index 00000000..dceaccd9 --- /dev/null +++ b/parts/features/core/boot.nix @@ -0,0 +1,16 @@ +{...}: { + flake.modules.nixos.boot = {...}: { + boot = { + loader.systemd-boot = { + enable = true; + memtest86.enable = true; + }; + loader.efi.canTouchEfiVariables = true; + consoleLogLevel = 7; + + initrd = { + systemd.enable = true; + }; + }; + }; +} diff --git a/parts/features/core/cachix.nix b/parts/features/core/cachix.nix new file mode 100644 index 00000000..d9984b78 --- /dev/null +++ b/parts/features/core/cachix.nix @@ -0,0 +1,5 @@ +{...}: { + flake.modules.nixos.cachix = {pkgs, ...}: { + environment.systemPackages = [pkgs.cachix]; + }; +} diff --git a/parts/features/core/dns.nix b/parts/features/core/dns.nix new file mode 100644 index 00000000..8661ba30 --- /dev/null +++ b/parts/features/core/dns.nix @@ -0,0 +1,14 @@ +{...}: { + flake.modules.nixos.dns = {...}: { + services.resolved = { + enable = true; + llmnr = "false"; + extraConfig = '' + MulticastDNS=false + DNSStubListenerExtra=172.17.0.1 + ''; + fallbackDns = []; + }; + networking.networkmanager.dns = "systemd-resolved"; + }; +} diff --git a/parts/features/core/fonts/_scripts/patch-fira-with-fa6-pro.sh b/parts/features/core/fonts/_scripts/patch-fira-with-fa6-pro.sh new file mode 100644 index 00000000..c0b655b6 --- /dev/null +++ b/parts/features/core/fonts/_scripts/patch-fira-with-fa6-pro.sh @@ -0,0 +1,130 @@ +# This script is executed by a Nix-built wrapper (pkgs.writeShellApplication) +# Required tools are provided via runtimeInputs. Do not add Nix-specific paths here. +set -euo pipefail + +FA_DIR="$HOME/.local/share/fonts/Font Awesome v6.5.1" +if [ ! -d "$FA_DIR" ]; then + echo "[patch-fira-with-fa6-pro] Font Awesome 6 Pro not found at: $FA_DIR" + echo "[patch-fira-with-fa6-pro] Skipping patch step." + exit 0 +fi + +OUT_DIR="$HOME/.local/share/fonts/NerdPatched/FiraCodeFAPro" +mkdir -p "$OUT_DIR" + +# Fix ownership and permissions to avoid PermissionError from nerd-font-patcher +echo "[patch-fira-with-fa6-pro] Ensuring proper permissions for output directory..." + +# Ensure the directory and all its contents are owned by the current user +if [ -d "$OUT_DIR" ]; then + # Change ownership if needed (may require sudo, but let's try without first) + if ! [ -O "$OUT_DIR" ]; then + echo "[patch-fira-with-fa6-pro] WARNING: Output directory not owned by current user" + echo "[patch-fira-with-fa6-pro] You may need to run: sudo chown -R \"$USER\":\"$USER\" \"$OUT_DIR\"" + fi + + # Ensure directory is writable + chmod u+w "$OUT_DIR" 2>/dev/null || { + echo "[patch-fira-with-fa6-pro] ERROR: Cannot make output directory writable: $OUT_DIR" >&2 + echo "[patch-fira-with-fa6-pro] Suggested fix: sudo chown -R \"$USER\":\"$USER\" \"$OUT_DIR\"" >&2 + echo "[patch-fira-with-fa6-pro] Then run: chmod -R u+w \"$OUT_DIR\"" >&2 + exit 1 + } + + # Make existing files writable + find "$OUT_DIR" -type f -exec chmod u+w {} \; 2>/dev/null || { + echo "[patch-fira-with-fa6-pro] ERROR: Cannot make existing files writable in $OUT_DIR" >&2 + echo "[patch-fira-with-fa6-pro] Suggested fix: sudo chown -R \"$USER\":\"$USER\" \"$OUT_DIR\"" >&2 + exit 1 + } +fi + +# Ensure created files are world-readable +umask 022 + +# Use a cache-backed temp base to avoid any /tmp quirks +CACHE_DIR="${XDG_CACHE_HOME:-$HOME/.cache}/nerd-font-patcher" +mkdir -p "$CACHE_DIR" + +# Try to locate a suitable FA6 Pro Regular font file (otf or ttf) +FA_PRO_FILE="$(find "$FA_DIR" -type f \( -iname '*Pro-Regular-400.*' -o -iname '*Pro-Regular.*' \) | head -n 1 || true)" +if [ -z "${FA_PRO_FILE:-}" ]; then + echo "[patch-fira-with-fa6-pro] Could not find a 'Font Awesome 6 Pro Regular' font file in: $FA_DIR" + echo "[patch-fira-with-fa6-pro] Skipping patch step." + exit 0 +fi + +# The wrapper sets SRC_DIR to the absolute path for Fira Code TTFs +if [ -z "${SRC_DIR:-}" ] || [ ! -d "$SRC_DIR" ]; then + echo "[patch-fira-with-fa6-pro] ERROR: SRC_DIR not set or not a directory (expected Fira Code .ttf source)." >&2 + exit 1 +fi + +echo "[patch-fira-with-fa6-pro] Using FA6 Pro: $FA_PRO_FILE" +echo "[patch-fira-with-fa6-pro] Patching Fira Code fonts from: $SRC_DIR -> $OUT_DIR" + +failures=0 +set +e +for font in "$SRC_DIR"/*.ttf; do + base="$(basename "$font")" + echo "[patch-fira-with-fa6-pro] Patching $base ..." + + # Create a temporary directory for this operation to avoid permission issues + temp_dir=$(mktemp -d "$CACHE_DIR/patch.XXXXXX") + temp_output="$temp_dir/output" + mkdir -p "$temp_output" + + # Copy source font into temp dir to avoid nerd-font-patcher opening read-only Nix store paths with r+b + # Use a .woff extension to bypass the patcher's head-table tweaking step that opens files r+b + base_woff="${base%.ttf}.woff" + src_copy="$temp_dir/$base_woff" + cp "$font" "$src_copy" + chmod u+rw "$src_copy" 2>/dev/null || true + + # Run patcher and capture output (do not echo log by default) + patch_log="$temp_dir/patch.log" + nerd-font-patcher \ + "$src_copy" \ + --complete \ + --custom "$FA_PRO_FILE" \ + --careful \ + --extension ttf \ + -out "$temp_output" >"$patch_log" 2>&1 + rc=$? + + if [ "$rc" -eq 0 ]; then + # Move the patched font from temp directory to final destination + if ls "$temp_output"/*.ttf 1>/dev/null 2>&1; then + # Show a concise success summary per font + for f in "$temp_output"/*.ttf; do + echo "[patch-fira-with-fa6-pro] Generated $(basename "$f")" + done + mv "$temp_output"/*.ttf "$OUT_DIR/" || { + echo "[patch-fira-with-fa6-pro] ERROR: Failed to move patched font for $base" >&2 + rc=1 + } + else + echo "[patch-fira-with-fa6-pro] ERROR: No patched font found for $base" >&2 + rc=1 + fi + fi + + # Clean up temp directory + rm -rf "$temp_dir" + + if [ "$rc" -ne 0 ]; then + echo "[patch-fira-with-fa6-pro] ERROR: Patching failed for $base (exit $rc). Log at: $patch_log" >&2 + failures=$((failures + 1)) + fi +done +set -e + +# Refresh the font cache so newly patched fonts are available +fc-cache -f "$HOME/.local/share/fonts" || true + +if [ "$failures" -gt 0 ]; then + echo "[patch-fira-with-fa6-pro] Completed with $failures failure(s). See log(s) referenced above." >&2 + exit 1 +fi + +echo "[patch-fira-with-fa6-pro] Done." diff --git a/parts/features/core/fonts/default.nix b/parts/features/core/fonts/default.nix new file mode 100644 index 00000000..5381c7e0 --- /dev/null +++ b/parts/features/core/fonts/default.nix @@ -0,0 +1,76 @@ +{config, lib, ...}: let + cfg = config; +in { + flake.modules.nixos.fonts = {pkgs, ...}: let + fontSmokeTest = pkgs.writers.writeBashBin "font-smoke-test" '' + set -e + + printf "%b\n" "Normal" + printf "%b\n" "\033[1mBold\033[22m" + printf "%b\n" "\033[3mItalic\033[23m" + printf "%b\n" "\033[3;1mBold Italic\033[0m" + printf "%b\n" "\033[4mUnderline\033[24m" + printf "%b\n" "== === !== >= <= =>" + printf "%b\n" " 󰾆 󱑥 󰒲 󰗼" + ''; + patchFiraWithFA6Pro = pkgs.writeShellApplication { + name = "patch-fira-with-fa6-pro"; + runtimeInputs = [ + pkgs.fira-code + pkgs.fontforge + pkgs.findutils + pkgs.coreutils + pkgs.fontconfig + pkgs.nerd-font-patcher + ]; + runtimeEnv = { + SRC_DIR = "${pkgs.fira-code}/share/fonts/truetype"; + }; + text = builtins.readFile ./_scripts/patch-fira-with-fa6-pro.sh; + }; + in { + environment.systemPackages = [ + fontSmokeTest + patchFiraWithFA6Pro + ]; + + home-manager.users.farlion.home.activation.patchFiraWithFA6Pro = '' + OUT_DIR="$HOME/.local/share/fonts/NerdPatched/FiraCodeFAPro" + if [ ! -d "$OUT_DIR" ] || [ -z "$(ls -A "$OUT_DIR" 2>/dev/null)" ]; then + echo "[patch-fira-with-fa6-pro] Patched fonts not found or directory empty, running patcher..." + "${patchFiraWithFA6Pro}/bin/patch-fira-with-fa6-pro" + else + echo "[patch-fira-with-fa6-pro] Patched fonts already exist in $OUT_DIR, skipping..." + fi + ''; + + fonts = { + enableDefaultPackages = false; + packages = [ + pkgs.fira-code + pkgs.fira-code-symbols + pkgs.dejavu_fonts + pkgs.font-awesome_5 + pkgs.font-awesome_6 + pkgs.unstable.font-awesome + pkgs.noto-fonts-color-emoji + ]; + fontconfig = { + defaultFonts = { + sansSerif = ["DejaVu Sans"]; + serif = ["DejaVu Serif"]; + monospace = ["FiraCode Nerd Font" "Fira Code"]; + }; + }; + }; + }; + + flake.modules.homeManager.fonts = {lib, ...}: { + home.persistence."/persist" = lib.mkIf cfg.dendrix.isImpermanent { + directories = [ + ".local/share/fonts" + ".cache/fontconfig" + ]; + }; + }; +} diff --git a/parts/features/core/impermanence.nix b/parts/features/core/impermanence.nix new file mode 100644 index 00000000..33579adb --- /dev/null +++ b/parts/features/core/impermanence.nix @@ -0,0 +1,96 @@ +{...}: { + flake.modules.nixos.impermanence = { + lib, + pkgs, + ... + }: let + rootExplosion = '' + echo "Time to 🧨" >/dev/kmsg + mkdir /btrfs_tmp + mount /dev/mapper/nixos--vg-root /btrfs_tmp + + # Root impermanence + if [[ -e /btrfs_tmp/root ]]; then + mkdir -p /btrfs_tmp/persist/old_roots + timestamp=$(date --date="@$(stat -c %Y /btrfs_tmp/root)" "+%Y-%m-%d_%H:%M:%S") + if [[ ! -e /btrfs_tmp/persist/old_roots/$timestamp ]]; then + mv /btrfs_tmp/root "/btrfs_tmp/persist/old_roots/$timestamp" + else + btrfs subvolume delete /btrfs_tmp/root + fi + fi + + ### + # GC + ### + latest_snapshot=$(find /btrfs_tmp/persist/old_roots/ -mindepth 1 -maxdepth 1 -type d | sort -r | head -n 1) + # Only delete old snapshots if there's at least one that will remain after deletion + if [ -n "$latest_snapshot" ]; then + for i in $(find /btrfs_tmp/persist/old_roots/ -mindepth 1 -maxdepth 1 -mtime +30 | grep -v -e "$latest_snapshot"); do + btrfs subvolume delete -R "$i" + done + fi + + btrfs subvolume create /btrfs_tmp/root + umount /btrfs_tmp + echo "Done with 🧨. Au revoir!" >/dev/kmsg + ''; + in { + boot.initrd.systemd = { + extraBin = { + grep = "${pkgs.gnugrep}/bin/grep"; + }; + services = { + root-explode = { + enableStrictShellChecks = false; + wantedBy = ["initrd-root-device.target"]; + wants = ["lvm2-activation.service"]; + after = ["lvm2-activation.service" "local-fs-pre.target"]; + before = ["sysroot.mount"]; + unitConfig = { + ConditionKernelCommandLine = ["!resume="]; + RequiresMountsFor = ["/dev/mapper/nixos--vg-root"]; + }; + serviceConfig = { + StandardOutput = "journal+console"; + StandardError = "journal+console"; + Type = "oneshot"; + }; + script = rootExplosion; + }; + }; + }; + + boot.tmp.cleanOnBoot = true; + + fileSystems."/persist".neededForBoot = true; + + environment.persistence."/persist/system" = { + enable = true; + hideMounts = true; + directories = [ + "/root/.cache/nix" + "/var/lib/logrotate" + "/var/lib/nixos" + "/var/lib/systemd/coredump" + "/var/lib/systemd/timers" + "/var/lib/udisks2" + "/var/log" + ]; + files = ["/etc/machine-id"]; + }; + environment.etc = { + "localtime".source = "/persist/system/etc/localtime"; + }; + + services.logrotate.extraArgs = lib.mkAfter ["--state" "/var/lib/logrotate/logrotate.status"]; + + system.activationScripts.bootstrapPersistHome.text = '' + mkdir -p /persist/home/farlion + chown farlion:users /persist/home/farlion + chmod 0700 /persist/home/farlion + ''; + + programs.fuse.userAllowOther = true; + }; +} diff --git a/parts/features/core/kernel.nix b/parts/features/core/kernel.nix new file mode 100644 index 00000000..8221f525 --- /dev/null +++ b/parts/features/core/kernel.nix @@ -0,0 +1,21 @@ +{...}: { + flake.modules.nixos.kernel = {pkgs, ...}: { + boot.kernel.sysctl = { + "kernel.sysrq" = 1; + "vm.swappiness" = 20; + }; + + boot.kernelPackages = pkgs.linuxPackages_zen; + environment.systemPackages = with pkgs; [ + perf + linuxKernel.packages.linux_zen.cpupower + ]; + + boot.initrd.verbose = true; + boot.kernelParams = [ + "systemd.show_status=1" + "i915.enable_psr=0" + "i915.fastboot=0" + ]; + }; +} diff --git a/parts/features/core/locale.nix b/parts/features/core/locale.nix new file mode 100644 index 00000000..8116ec3c --- /dev/null +++ b/parts/features/core/locale.nix @@ -0,0 +1,25 @@ +{...}: { + flake.modules.nixos.locale = {pkgs, ...}: { + environment.systemPackages = [pkgs.comma]; + + services.atd.enable = true; + + boot.supportedFilesystems = ["ntfs"]; + + services.tzupdate = { + enable = true; + timer.enable = false; + }; + systemd.services.tzupdate = { + after = ["network-online.target"]; + wants = ["network-online.target"]; + serviceConfig = { + Restart = "on-failure"; + RestartSec = "30s"; + RestartMode = "direct"; + }; + }; + + i18n.defaultLocale = "en_US.UTF-8"; + }; +} diff --git a/parts/features/core/networking/_scripts/tailscale-ip.sh b/parts/features/core/networking/_scripts/tailscale-ip.sh new file mode 100644 index 00000000..dd380671 --- /dev/null +++ b/parts/features/core/networking/_scripts/tailscale-ip.sh @@ -0,0 +1,9 @@ +set -euo pipefail + +isOnline=$(tailscale status --json | jq -r '.Self.Online') +if [[ "$isOnline" == "true" ]]; then + tailscaleIp=$(tailscale status --json | jq -r '.Self.TailscaleIPs[0]') + echo "{\"icon\": \"tailscale_up\", \"text\": \"$tailscaleIp\", \"state\": \"Good\"}" +else + echo "{\"icon\": \"tailscale_down\", \"text\": \"\", \"state\": \"Idle\"}" +fi diff --git a/parts/features/core/networking/default.nix b/parts/features/core/networking/default.nix new file mode 100644 index 00000000..7f389d50 --- /dev/null +++ b/parts/features/core/networking/default.nix @@ -0,0 +1,65 @@ +{config, lib, ...}: let + cfg = config; +in { + flake.modules.nixos.networking = { + lib, + pkgs, + ... + }: let + tailscale-ip = pkgs.writers.writeBashBin "tailscale-ip" ( + builtins.readFile ./_scripts/tailscale-ip.sh + ); + in { + environment.persistence."/persist/system" = lib.mkIf cfg.dendrix.isImpermanent { + directories = [ + "/etc/NetworkManager/system-connections" + "/var/lib/tailscale" + "/var/lib/NetworkManager" + ]; + }; + + environment.systemPackages = [ + pkgs.pwru + tailscale-ip + ]; + + networking.firewall = { + logReversePathDrops = true; + logRefusedPackets = true; + }; + + services.tailscale = { + enable = true; + package = pkgs.unstable.tailscale; + useRoutingFeatures = "client"; + }; + + environment.etc.hosts.mode = "0644"; + + networking.firewall.allowedTCPPorts = [22000]; + networking.firewall.allowedUDPPorts = [22000 21027]; + + boot.kernel.sysctl = { + "net.core.default_qdisc" = "fq"; + "net.ipv4.tcp_congestion_control" = "bbr"; + }; + + networking.networkmanager.enable = true; + users.users.farlion.extraGroups = ["networkmanager"]; + + networking.dhcpcd.enable = false; + + programs.captive-browser = lib.mkIf cfg.dendrix.isLaptop { + enable = true; + bindInterface = false; + }; + + systemd.network.wait-online.anyInterface = true; + }; + + flake.modules.homeManager.networking = {lib, ...}: { + home.persistence."/persist" = lib.mkIf cfg.dendrix.isImpermanent { + directories = [".config/tailscale"]; + }; + }; +} diff --git a/parts/features/core/nix-ld.nix b/parts/features/core/nix-ld.nix new file mode 100644 index 00000000..466b1b85 --- /dev/null +++ b/parts/features/core/nix-ld.nix @@ -0,0 +1,5 @@ +{...}: { + flake.modules.nixos.nix-ld = {...}: { + programs.nix-ld.enable = true; + }; +} diff --git a/parts/features/core/performance.nix b/parts/features/core/performance.nix new file mode 100644 index 00000000..65790739 --- /dev/null +++ b/parts/features/core/performance.nix @@ -0,0 +1,8 @@ +{...}: { + flake.modules.nixos.performance = {...}: { + documentation.man = { + enable = true; + generateCaches = false; + }; + }; +} diff --git a/parts/features/core/smb.nix b/parts/features/core/smb.nix new file mode 100644 index 00000000..9925b5c5 --- /dev/null +++ b/parts/features/core/smb.nix @@ -0,0 +1,6 @@ +{...}: { + flake.modules.nixos.smb = {pkgs, ...}: { + boot.supportedFilesystems = ["cifs"]; + environment.systemPackages = [pkgs.cifs-utils]; + }; +} diff --git a/parts/features/core/systemd.nix b/parts/features/core/systemd.nix new file mode 100644 index 00000000..098a0954 --- /dev/null +++ b/parts/features/core/systemd.nix @@ -0,0 +1,5 @@ +{...}: { + flake.modules.nixos.systemd = {...}: { + systemd.enableStrictShellChecks = true; + }; +} diff --git a/parts/features/core/users.nix b/parts/features/core/users.nix new file mode 100644 index 00000000..08009ae8 --- /dev/null +++ b/parts/features/core/users.nix @@ -0,0 +1,24 @@ +{...}: { + flake.modules.nixos.users = { + lib, + pkgs, + ... + }: { + users.mutableUsers = false; + + users.users.farlion = { + description = "Florian Peter"; + extraGroups = ["disk"]; + group = "users"; + hashedPassword = lib.mkDefault ""; + isNormalUser = true; + shell = pkgs.fish; + }; + + programs.vim = { + defaultEditor = true; + enable = true; + }; + programs.fish.enable = true; + }; +} diff --git a/parts/features/desktop/display-manager.nix b/parts/features/desktop/display-manager.nix new file mode 100644 index 00000000..8135b016 --- /dev/null +++ b/parts/features/desktop/display-manager.nix @@ -0,0 +1,62 @@ +{config, lib, ...}: let + cfg = config; +in { + flake.modules.nixos.display-manager = { + lib, + pkgs, + ... + }: { + environment.persistence."/persist/system" = lib.mkIf cfg.dendrix.isImpermanent { + files = ["/etc/ly/save.ini"]; + }; + + services.displayManager = { + defaultSession = "niri"; + ly = { + enable = true; + settings = { + animation = "doom"; + hide_borders = true; + }; + }; + }; + + services.gvfs.enable = true; + + programs.niri.enable = true; + + xdg.portal = { + enable = true; + config = { + common = { + default = ["gnome" "gtk"]; + }; + niri = { + default = ["gnome" "gtk"]; + "org.freedesktop.impl.portal.ScreenCast" = ["gnome"]; + "org.freedesktop.impl.portal.Screenshot" = ["gnome"]; + "org.freedesktop.impl.portal.FileChooser" = ["gtk"]; + }; + }; + extraPortals = [ + pkgs.xdg-desktop-portal-gnome + pkgs.xdg-desktop-portal-gtk + ]; + }; + + systemd.user.services.xdg-desktop-portal = { + after = ["xdg-desktop-autostart.target"]; + }; + systemd.user.services.xdg-desktop-portal-gtk = { + after = ["xdg-desktop-autostart.target"]; + }; + systemd.user.services.xdg-desktop-portal-gnome = { + after = ["xdg-desktop-autostart.target"]; + }; + systemd.user.services.niri-flake-polkit = { + after = ["xdg-desktop-autostart.target"]; + }; + + programs.sway.enable = true; + }; +} diff --git a/parts/features/hardware/btrfs.nix b/parts/features/hardware/btrfs.nix new file mode 100644 index 00000000..c14e0958 --- /dev/null +++ b/parts/features/hardware/btrfs.nix @@ -0,0 +1,15 @@ +{config, lib, ...}: let + cfg = config; +in { + flake.modules.nixos.btrfs = {lib, ...}: { + environment.persistence."/persist/system" = lib.mkIf cfg.dendrix.isImpermanent { + directories = ["/var/lib/btrfs"]; + }; + + services.btrfs.autoScrub = { + enable = true; + interval = "monthly"; + fileSystems = ["/"]; + }; + }; +} diff --git a/parts/features/hardware/firmware.nix b/parts/features/hardware/firmware.nix new file mode 100644 index 00000000..2012c28e --- /dev/null +++ b/parts/features/hardware/firmware.nix @@ -0,0 +1,11 @@ +{config, lib, ...}: let + cfg = config; +in { + flake.modules.nixos.firmware = {lib, ...}: { + environment.persistence."/persist/system" = lib.mkIf cfg.dendrix.isImpermanent { + directories = ["/var/lib/fwupd"]; + }; + + services.fwupd.enable = true; + }; +} diff --git a/parts/features/hardware/io.nix b/parts/features/hardware/io.nix new file mode 100644 index 00000000..03d3992f --- /dev/null +++ b/parts/features/hardware/io.nix @@ -0,0 +1,42 @@ +{...}: { + flake.modules.nixos.io = {pkgs, ...}: { + hardware.logitech.wireless = { + enable = true; + enableGraphical = true; + }; + + environment.systemPackages = [pkgs.keyd]; + services.keyd = { + enable = true; + keyboards.default = { + ids = ["*"]; + settings = { + main = { + capslock = "overload(fkeys, esc)"; + }; + fkeys = { + "1" = "f1"; + "2" = "f2"; + "3" = "f3"; + "4" = "f4"; + "5" = "f5"; + "6" = "f6"; + "7" = "f7"; + "8" = "f8"; + "9" = "f9"; + "0" = "f10"; + minus = "f11"; + equal = "f12"; + }; + }; + }; + }; + + environment.etc."libinput/local-overrides.quirks".text = '' + [Serial Keyboards] + MatchUdevType=keyboard + MatchName=keyd*keyboard + AttrKeyboardIntegration=internal + ''; + }; +} diff --git a/parts/features/hardware/video.nix b/parts/features/hardware/video.nix new file mode 100644 index 00000000..7a83926f --- /dev/null +++ b/parts/features/hardware/video.nix @@ -0,0 +1,12 @@ +{...}: { + flake.modules.nixos.video = {pkgs, ...}: { + programs.obs-studio = { + enable = true; + enableVirtualCamera = true; + }; + + environment.systemPackages = [pkgs.v4l-utils]; + + users.users.farlion.extraGroups = ["video"]; + }; +} diff --git a/parts/features/services/kind-killer.nix b/parts/features/services/kind-killer.nix new file mode 100644 index 00000000..342c9579 --- /dev/null +++ b/parts/features/services/kind-killer.nix @@ -0,0 +1,15 @@ +{...}: { + flake.modules.nixos.kind-killer = {pkgs, ...}: { + systemd.services.kind-killer = { + description = "Kill kind cluster on shutdown"; + after = ["docker.service"]; + requires = ["docker.service"]; + wantedBy = ["multi-user.target"]; + serviceConfig = { + Environment = "PATH=$PATH:/run/current-system/sw/bin"; + ExecStart = "${pkgs.coreutils}/bin/sleep infinity"; + ExecStop = "${pkgs.kind}/bin/kind delete cluster"; + }; + }; + }; +} diff --git a/parts/features/services/localsend.nix b/parts/features/services/localsend.nix new file mode 100644 index 00000000..4e44e43d --- /dev/null +++ b/parts/features/services/localsend.nix @@ -0,0 +1,13 @@ +{config, lib, ...}: let + cfg = config; +in { + flake.modules.nixos.localsend = {...}: { + programs.localsend.enable = true; + }; + + flake.modules.homeManager.localsend = {lib, ...}: { + home.persistence."/persist" = lib.mkIf cfg.dendrix.isImpermanent { + directories = [".local/share/org.localsend.localsend_app"]; + }; + }; +} diff --git a/parts/features/services/scrutiny.nix b/parts/features/services/scrutiny.nix new file mode 100644 index 00000000..5ba8fa20 --- /dev/null +++ b/parts/features/services/scrutiny.nix @@ -0,0 +1,26 @@ +{config, lib, ...}: let + cfg = config; +in { + flake.modules.nixos.scrutiny = {lib, ...}: { + environment.persistence."/persist/system" = lib.mkIf cfg.dendrix.isImpermanent { + directories = [ + { + directory = "/var/lib/private"; + mode = "0700"; + } + "/var/lib/private/scrutiny" + ]; + }; + + services.scrutiny = { + enable = true; + settings.web.listen.port = 8081; + }; + + systemd.services.scrutiny.enableStrictShellChecks = false; + + systemd.tmpfiles.rules = [ + "d /var/lib/private 0700 root root -" + ]; + }; +} From 9e40f50e4a30b142bd51b660ea5564463d6925cb Mon Sep 17 00:00:00 2001 From: workflow <4farlion@gmail.com> Date: Sat, 31 Jan 2026 00:35:08 +0000 Subject: [PATCH 15/26] feat(dendritic): add nix-settings module --- parts/features/core/nix-settings.nix | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 parts/features/core/nix-settings.nix diff --git a/parts/features/core/nix-settings.nix b/parts/features/core/nix-settings.nix new file mode 100644 index 00000000..d6307cd0 --- /dev/null +++ b/parts/features/core/nix-settings.nix @@ -0,0 +1,22 @@ +{...}: { + flake.modules.nixos.nix-settings = {pkgs, ...}: { + nix = { + settings = { + trusted-users = ["root" "farlion" "@wheel" "@sudo"]; + substituters = ["https://cache.nixos.org/"]; + trusted-public-keys = []; + }; + + extraOptions = '' + experimental-features = nix-command flakes + ''; + + nixPath = [ + "nixpkgs=${pkgs.path}" + "nixos-unstable=${pkgs.unstable.path}" + ]; + }; + + nixpkgs.config.allowUnfree = true; + }; +} From 56f59597191bbcddfe3d643f9e73ccd5455cb967 Mon Sep 17 00:00:00 2001 From: workflow <4farlion@gmail.com> Date: Sat, 31 Jan 2026 00:39:43 +0000 Subject: [PATCH 16/26] feat(dendritic): add hosts composition layer (Phase 4 foundation) --- parts/hosts.nix | 118 ++++++++++++++++++++++++++ parts/hosts/flexbox/default.nix | 38 +++++++++ parts/hosts/flexbox/hardware-scan.nix | 29 +++++++ parts/hosts/numenor/default.nix | 36 ++++++++ parts/hosts/numenor/hardware-scan.nix | 37 ++++++++ 5 files changed, 258 insertions(+) create mode 100644 parts/hosts.nix create mode 100644 parts/hosts/flexbox/default.nix create mode 100644 parts/hosts/flexbox/hardware-scan.nix create mode 100644 parts/hosts/numenor/default.nix create mode 100644 parts/hosts/numenor/hardware-scan.nix diff --git a/parts/hosts.nix b/parts/hosts.nix new file mode 100644 index 00000000..0c4b3c13 --- /dev/null +++ b/parts/hosts.nix @@ -0,0 +1,118 @@ +{ + config, + lib, + inputs, + ... +}: let + inherit (inputs) nixpkgs home-manager impermanence niri nur sops-nix stylix determinate; + + # All dendritic modules for NixOS + nixosModules = builtins.attrValues config.flake.modules.nixos; + + # All dendritic modules for home-manager + homeManagerModules = builtins.attrValues config.flake.modules.homeManager; + + commonOverlays = { + unstable = import inputs.nixos-unstable { + system = "x86_64-linux"; + config.allowUnfree = true; + }; + }; + + commonNixosModules = [ + { + nixpkgs.overlays = [ + (_: _: commonOverlays) + ]; + } + determinate.nixosModules.default + nixpkgs.nixosModules.notDetected + nur.modules.nixos.default + impermanence.nixosModules.impermanence + sops-nix.nixosModules.sops + stylix.nixosModules.stylix + home-manager.nixosModules.home-manager + niri.nixosModules.niri + ]; + + commonHomeManagerSettings = { + useGlobalPkgs = true; + useUserPackages = true; + backupFileExtension = "home-manager-backup"; + sharedModules = + homeManagerModules + ++ [ + "${impermanence}/home-manager.nix" + nur.modules.homeManager.default + stylix.homeManagerModules.stylix + niri.homeModules.niri + ]; + }; + + mkHost = { + hostname, + hostModule, + dendrixConfig, + extraModules ? [], + }: + nixpkgs.lib.nixosSystem { + specialArgs = { + inherit inputs; + secrets = inputs.secrets; + }; + modules = + commonNixosModules + ++ nixosModules + ++ [ + # Host-specific hardware and settings + hostModule + + # Set dendrix options + { + dendrix = dendrixConfig; + } + + # Home-manager configuration + { + home-manager = + commonHomeManagerSettings + // { + users.farlion = {pkgs, ...}: { + home.stateVersion = dendrixConfig.homeStateVersion; + }; + }; + } + ] + ++ extraModules; + }; +in { + flake.nixosConfigurations = { + flexbox = mkHost { + hostname = "flexbox"; + hostModule = ./hosts/flexbox; + dendrixConfig = { + hostname = "flexbox"; + isLaptop = true; + isImpermanent = false; + hasNvidia = true; + hasAmd = false; + stateVersion = "22.05"; + homeStateVersion = "22.05"; + }; + }; + + numenor = mkHost { + hostname = "numenor"; + hostModule = ./hosts/numenor; + dendrixConfig = { + hostname = "numenor"; + isLaptop = false; + isImpermanent = true; + hasNvidia = false; + hasAmd = true; + stateVersion = "24.11"; + homeStateVersion = "24.11"; + }; + }; + }; +} diff --git a/parts/hosts/flexbox/default.nix b/parts/hosts/flexbox/default.nix new file mode 100644 index 00000000..9adfaaea --- /dev/null +++ b/parts/hosts/flexbox/default.nix @@ -0,0 +1,38 @@ +{config, lib, pkgs, ...}: { + imports = [./hardware-scan.nix]; + + # Flexbox-specific settings + boot.kernelParams = [ + "nvme_core.default_ps_max_latency_us=0" + "acpiphp.disable=1" + ]; + + # NVIDIA GPU settings + hardware.nvidia.prime = { + offload = { + enable = true; + enableOffloadCmd = true; + }; + intelBusId = "PCI:0:2:0"; + nvidiaBusId = "PCI:1:0:0"; + }; + + # SOF audio card power fix + services.udev.extraRules = '' + ACTION=="add|change", SUBSYSTEM=="pci", KERNELS=="0000:00:1f.3", ATTR{power/control}="on" + ''; + + # LVM on LUKS + boot.initrd.luks.devices = { + root = { + device = "/dev/disk/by-uuid/ae713884-749b-4edb-adbc-b16fe447e956"; + preLVM = true; + }; + }; + + networking.hostName = "flexbox"; + networking.useDHCP = false; + networking.interfaces.wlp0s20f3.useDHCP = true; + + system.stateVersion = "22.05"; +} diff --git a/parts/hosts/flexbox/hardware-scan.nix b/parts/hosts/flexbox/hardware-scan.nix new file mode 100644 index 00000000..0423c4fe --- /dev/null +++ b/parts/hosts/flexbox/hardware-scan.nix @@ -0,0 +1,29 @@ +# Do not modify this file! It was generated by ‘nixos-generate-config’ +# and may be overwritten by future invocations. Please make changes +# to /etc/nixos/configuration.nix instead. +{lib, ...}: { + boot.initrd.availableKernelModules = ["xhci_pci" "nvme" "usbhid" "usb_storage" "sd_mod" "rtsx_pci_sdmmc"]; + boot.initrd.kernelModules = ["dm-snapshot"]; + boot.kernelModules = ["kvm-intel"]; + boot.extraModulePackages = []; + + fileSystems."/" = { + device = "/dev/disk/by-uuid/e5687086-9188-42e8-aa57-423df9cbb863"; + fsType = "ext4"; + options = ["noatime"]; + }; + + fileSystems."/boot" = { + device = "/dev/disk/by-uuid/8483-92D7"; + fsType = "vfat"; + options = ["fmask=0022" "dmask=0022"]; + }; + + hardware.cpu.intel.updateMicrocode = true; + + swapDevices = [{device = "/dev/disk/by-uuid/0fb837c4-ba4e-437d-a54c-ff25312af20c";}]; + + nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; + + powerManagement.cpuFreqGovernor = lib.mkDefault "powersave"; +} diff --git a/parts/hosts/numenor/default.nix b/parts/hosts/numenor/default.nix new file mode 100644 index 00000000..7764c15f --- /dev/null +++ b/parts/hosts/numenor/default.nix @@ -0,0 +1,36 @@ +{config, lib, pkgs, ...}: { + imports = [./hardware-scan.nix]; + + # LVM on LUKS + boot.initrd.luks.devices = { + root = { + device = "/dev/nvme0n1p6"; + preLVM = true; + }; + }; + + # Needed for ddcutil + hardware.i2c.enable = true; + + # Plenty of RAM so... + boot.tmp.useTmpfs = true; + + networking.useDHCP = false; + networking.interfaces.enp74s0.useDHCP = true; + networking.hostName = "numenor"; + + # Disable Wifi at boot + systemd.services.disable-wifi = { + enable = true; + description = "Disable Wi-Fi at boot"; + after = ["network.target" "NetworkManager.service"]; + wantedBy = ["multi-user.target"]; + path = [pkgs.networkmanager]; + serviceConfig = { + Type = "oneshot"; + ExecStart = "${pkgs.networkmanager}/bin/nmcli radio wifi off"; + }; + }; + + system.stateVersion = "24.11"; +} diff --git a/parts/hosts/numenor/hardware-scan.nix b/parts/hosts/numenor/hardware-scan.nix new file mode 100644 index 00000000..8cea533a --- /dev/null +++ b/parts/hosts/numenor/hardware-scan.nix @@ -0,0 +1,37 @@ +{lib, ...}: { + boot.initrd.availableKernelModules = ["thunderbolt" "xhci_pci" "ahci" "nvme" "usbhid" "usb_storage" "sd_mod"]; + boot.initrd.kernelModules = ["dm-snapshot"]; + boot.kernelModules = ["kvm-amd"]; + boot.extraModulePackages = []; + + fileSystems."/" = { + device = "/dev/disk/by-uuid/d601a8b7-17a4-46b5-a95e-ab29e94790ef"; + fsType = "btrfs"; + options = ["subvol=root" "compress=zstd" "noatime"]; + }; + + fileSystems."/nix" = { + device = "/dev/disk/by-uuid/d601a8b7-17a4-46b5-a95e-ab29e94790ef"; + fsType = "btrfs"; + options = ["subvol=nix" "compress=zstd" "noatime"]; + }; + + fileSystems."/persist" = { + device = "/dev/disk/by-uuid/d601a8b7-17a4-46b5-a95e-ab29e94790ef"; + fsType = "btrfs"; + options = ["subvol=persist" "compress=zstd" "noatime"]; + }; + + fileSystems."/boot" = { + device = "/dev/disk/by-uuid/12CE-A600"; + fsType = "vfat"; + options = ["fmask=0022" "dmask=0022"]; + }; + + swapDevices = [ + {device = "/dev/disk/by-uuid/daee540c-201b-4ccd-9315-7d8c44c57af6";} + ]; + + nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; + hardware.cpu.amd.updateMicrocode = true; +} From 1976b73243066a70de408804b07bdb35700e533a Mon Sep 17 00:00:00 2001 From: workflow <4farlion@gmail.com> Date: Sat, 31 Jan 2026 00:42:56 +0000 Subject: [PATCH 17/26] refactor(dendritic): fix dendrix options and cleanup old structure - Fix impermanence module to be conditional on config.dendrix.isImpermanent - Update feature modules to use correct osConfig.dendrix.* pattern - Remove old directories: home/, system/, machines/, nix/, specialisations/ - Remove old configuration.nix --- configuration.nix | 7 - doc/DENDRITIC.md | 154 +++-- flake.nix | 136 ---- home/aichat/default.nix | 49 -- home/aider/default.nix | 5 - home/alacritty/default.nix | 69 -- home/aliases/default.nix | 59 -- home/ansible/default.nix | 11 - home/asciinema/default.nix | 5 - home/aws/default.nix | 14 - home/bash/default.nix | 24 - home/bitwarden/default.nix | 17 - home/bluetuith/default.nix | 5 - home/brave-browser/default.nix | 52 -- home/broot/default.nix | 5 - home/btop/default.nix | 5 - home/calibre/default.nix | 18 - home/claude-code/CLAUDE.md | 17 - home/claude-code/default.nix | 52 -- home/cliphist/default.nix | 30 - home/codex/default.nix | 14 - home/cpu-profile-toggler/default.nix | 10 - .../scripts/cpu-profile-toggler.sh | 19 - home/dconf/default.nix | 11 - home/ddc-backlight/default.nix | 10 - home/ddc-backlight/scripts/ddc-backlight.sh | 49 -- home/default.nix | 266 -------- home/devenv/default.nix | 16 - home/direnv/default.nix | 17 - home/discord/default.nix | 15 - home/dunst/default.nix | 18 - home/easyeffects/default.nix | 24 - ...round-48k-z-edition-stereo-plus20-bass.irs | Bin 71372 -> 0 bytes .../output/bass-enhancing-perfect-eq.json | 226 ------- home/email/default.nix | 26 - home/firefox/default.nix | 26 - home/fish/default.nix | 143 ---- home/fix-flexbox-mike/default.nix | 27 - .../scripts/xps-9700-mic-fixer.sh | 3 - home/fuzzel/default.nix | 6 - home/fzf/default.nix | 6 - home/galaxy-buds-client/default.nix | 16 - home/gimp/default.nix | 17 - home/git-worktree-switcher/default.nix | 5 - home/git/default.nix | 104 --- home/git/github-cli/gh.config.yml | 12 - home/gnome-connections/default.nix | 20 - home/gtk-qt/default.nix | 39 -- home/gtk-qt/qtct.conf | 8 - home/hoppscotch/default.nix | 23 - home/hwatch/default.nix | 5 - home/impermanence/default.nix | 15 - home/isd/default.nix | 18 - home/jqp/default.nix | 5 - home/jujutsu/default.nix | 62 -- home/k9s/default.nix | 24 - home/k9s/gruvbox-dark.yaml | 102 --- home/k9s/gruvbox-light.yaml | 104 --- home/kanshi/default.nix | 78 --- home/kind-with-local-registry/default.nix | 10 - .../scripts/kind-with-local-registry.sh | 63 -- home/kubernetes-tools/default.nix | 18 - home/less/default.nix | 9 - home/lf/default.nix | 418 ------------ home/lf/pistol/pistol.conf | 1 - home/libation/default.nix | 17 - home/libreoffice/default.nix | 16 - home/lnav/default.nix | 16 - home/mic-levels-maintainer/default.nix | 29 - .../scripts/mic-levels-maintainer-flexbox.sh | 54 -- .../scripts/mic-levels-maintainer-numenor.sh | 29 - home/mpv/default.nix | 17 - home/mullvad-browser/default.nix | 16 - home/nautilus/default.nix | 17 - home/neovim/avante/avante.lua | 147 ---- home/neovim/avante/default.nix | 26 - home/neovim/carbon/default.nix | 46 -- home/neovim/cmp/cmp.lua | 105 --- home/neovim/cmp/default.nix | 27 - home/neovim/comment-nvim/default.nix | 11 - home/neovim/conform/conform.lua | 23 - home/neovim/conform/default.nix | 13 - home/neovim/dadbod/default.nix | 36 - home/neovim/dap/dap-ui.lua | 24 - home/neovim/dap/dap.lua | 134 ---- home/neovim/dap/default.nix | 25 - home/neovim/default.nix | 356 ---------- home/neovim/diffview-nvim/default.nix | 9 - home/neovim/diffview-nvim/diffview-nvim.lua | 35 - home/neovim/fidget/default.nix | 12 - home/neovim/folds/default.nix | 9 - home/neovim/folds/ufo.lua | 9 - home/neovim/fugitive/default.nix | 22 - home/neovim/fugitive/fugitive.lua | 63 -- home/neovim/git-conflict-nvim/default.nix | 11 - home/neovim/gitsigns/default.nix | 9 - home/neovim/gitsigns/gitsigns.lua | 52 -- home/neovim/gruvbox/default.nix | 18 - home/neovim/jdtls/default.nix | 11 - home/neovim/jdtls/jdtls.lua | 99 --- home/neovim/jj/default.nix | 45 -- home/neovim/jj/jj.lua | 21 - home/neovim/lspsaga/default.nix | 16 - home/neovim/lualine/default.nix | 58 -- home/neovim/mason-lsp/default.nix | 84 --- home/neovim/mason-lsp/mason.lua | 200 ------ home/neovim/mason-lsp/shared_lsp_config.lua | 41 -- home/neovim/mini-icons/default.nix | 12 - home/neovim/mini-operators/default.nix | 31 - home/neovim/neotest/default.nix | 21 - home/neovim/neotest/neotest.lua | 31 - home/neovim/noice/default.nix | 9 - home/neovim/noice/noice.lua | 28 - home/neovim/notify/default.nix | 21 - home/neovim/nui/default.nix | 10 - home/neovim/nvim-tree-lua/default.nix | 9 - home/neovim/nvim-tree-lua/nvim-tree.lua | 59 -- home/neovim/obsidian-nvim/default.nix | 31 - home/neovim/oil/default.nix | 27 - home/neovim/otter/default.nix | 25 - home/neovim/overseer/default.nix | 25 - home/neovim/overseer/overseer.lua | 29 - home/neovim/overseer/overseer_lib.lua | 25 - .../overseer/templates/gmailctl_apply.lua | 12 - .../overseer/templates/java_gradle/init.lua | 57 -- .../overseer/templates/java_maven/init.lua | 30 - .../overseer/templates/nixos_rebuild_boot.lua | 12 - .../templates/nixos_rebuild_switch.lua | 12 - .../templates/nixos_update_secrets.lua | 12 - .../overseer/templates/skaffold_dev.lua | 12 - home/neovim/plenary/default.nix | 10 - home/neovim/rainbow-csv/default.nix | 21 - home/neovim/render-markdown/default.nix | 16 - home/neovim/telescope/default.nix | 87 --- home/neovim/toggleterm/default.nix | 14 - home/neovim/treesitter/default.nix | 36 - .../treesitter/queries/nix/injections.scm | 91 --- home/neovim/treesitter/treesitter.lua | 49 -- home/neovim/trouble/default.nix | 9 - home/neovim/trouble/trouble.lua | 19 - home/neovim/undotree/default.nix | 7 - home/neovim/vim-be-good/default.nix | 7 - home/neovim/vim-terraform/default.nix | 7 - home/neovim/vim-visual-multi/default.nix | 13 - home/neovim/web-devicons/default.nix | 15 - home/neovim/yank-file-line/default.nix | 3 - home/neovim/yank-file-line/yank-file-line.lua | 21 - home/networkmanager-dmenu/config.ini | 48 -- home/networkmanager-dmenu/default.nix | 4 - home/nh/default.nix | 6 - home/niri/default.nix | 640 ------------------ home/niri/scripts/niri-auto-column.sh | 71 -- home/niri/scripts/niri-open-on-workspace.sh | 24 - home/niri/scripts/niri-pick-window.sh | 92 --- home/niri/scripts/niri-qalc.sh | 53 -- home/niri/scripts/niri-reorder-workspaces.sh | 76 --- home/niri/scripts/niri-set-wallpaper.sh | 26 - home/niri/wallpapers/gruvbox-dark-rainbow.png | Bin 185977 -> 0 bytes .../niri/wallpapers/gruvbox-light-rainbow.png | Bin 192946 -> 0 bytes home/nix-index/default.nix | 19 - home/nix-inspect/default.nix | 5 - home/nushell/config.nu | 30 - home/nushell/default.nix | 28 - home/nushell/env.nu | 1 - home/nushell/syncthing/stignore-nushell | 7 - home/obs/default.nix | 85 --- home/obs/scripts/obs-catcam-toggle.sh | 2 - home/obs/scripts/obs-main-scene.sh | 2 - home/obs/scripts/obs-recording-pause.sh | 2 - home/obs/scripts/obs-recording-toggle.sh | 2 - home/obs/scripts/obs-screensharing.sh | 2 - home/obs/scripts/obs-webcam-toggle.sh | 2 - home/obsidian/default.nix | 17 - home/onboard/default.nix | 6 - home/pavucontrol/default.nix | 16 - home/pgcli/default.nix | 5 - home/pomodoro-gtk/default.nix | 5 - home/portfolio-performance/default.nix | 16 - home/psql/default.nix | 6 - home/psql/psqlrc | 2 - home/pulsemixer/default.nix | 9 - home/pulsemixer/pulsemixer.cfg | 7 - home/qalculate/default.nix | 17 - home/ripgrep-all/default.nix | 5 - home/ripgrep/default.nix | 8 - home/rofimoji/default.nix | 8 - home/rofimoji/rofimoji.rc | 3 - home/satty/default.nix | 36 - home/satty/scripts/satty-screenshot.sh | 30 - home/showmethekey/default.nix | 6 - home/signal/default.nix | 16 - home/solaar/default.nix | 17 - home/sound-switcher/default.nix | 15 - .../scripts/sound-switcher-flexbox.sh | 241 ------- .../scripts/sound-switcher-numenor.sh | 156 ----- home/ssh/README.md | 75 -- home/ssh/default.nix | 36 - home/ssh/ssh-add-all.sh | 74 -- home/starship/default.nix | 128 ---- home/stylix/default.nix | 19 - home/syncthing/default.nix | 30 - .../default.nix | 10 - .../systemd-errors-and-warnings-counter.sh | 18 - home/tealdeer/default.nix | 20 - home/telegram/default.nix | 16 - home/television/default.nix | 18 - home/tomat/default.nix | 5 - home/trash-cli/default.nix | 5 - home/tray-tui/default.nix | 5 - home/udiskie/default.nix | 27 - home/urxvt/default.nix | 38 -- home/variety/default.nix | 9 - home/variety/variety.conf | 225 ------ home/virtual-cable/default.nix | 21 - home/virtual-cable/scripts/obs-mic.sh | 13 - home/vlc/default.nix | 17 - home/waybar/default.nix | 578 ---------------- home/waybar/scripts/dunst-dnd-waybar.sh | 9 - home/witr/default.nix | 3 - home/wlsunset/default.nix | 14 - home/wlsunset/scripts/wlsunset-waybar.sh | 22 - home/wluma/default.nix | 12 - home/xdg/default.nix | 62 -- home/ytmdesktop/default.nix | 31 - home/yubico/default.nix | 19 - .../yubikey-touch-detector/default.nix | 66 -- home/zen/default.nix | 54 -- home/zoom/default.nix | 21 - home/zoxide/default.nix | 16 - machines/flexbox/system.nix | 51 -- machines/numenor/system.nix | 55 -- nix/default.nix | 26 - parts/{hosts => _hosts}/flexbox/default.nix | 0 .../_hosts}/flexbox/hardware-scan.nix | 0 parts/{hosts => _hosts}/numenor/default.nix | 0 .../_hosts}/numenor/hardware-scan.nix | 0 parts/features/apps/aichat.nix | 7 +- parts/features/apps/ansible.nix | 8 +- parts/features/apps/aws.nix | 7 +- parts/features/apps/bash.nix | 7 +- parts/features/apps/brave-browser.nix | 9 +- parts/features/apps/calibre.nix | 7 +- parts/features/apps/discord.nix | 8 +- parts/features/apps/firefox.nix | 7 +- parts/features/apps/fish.nix | 7 +- .../apps/fix-flexbox-mike/default.nix | 7 +- parts/features/apps/galaxy-buds-client.nix | 7 +- parts/features/apps/gimp.nix | 7 +- parts/features/apps/gnome-connections.nix | 7 +- parts/features/apps/isd.nix | 7 +- parts/features/apps/kubernetes-tools.nix | 7 +- parts/features/apps/lf/default.nix | 7 +- parts/features/apps/libation.nix | 7 +- parts/features/apps/libreoffice.nix | 7 +- parts/features/apps/lnav.nix | 7 +- .../apps/mic-levels-maintainer/default.nix | 8 +- parts/features/apps/mpv.nix | 7 +- parts/features/apps/nautilus.nix | 7 +- parts/features/apps/nix-index.nix | 8 +- parts/features/apps/nushell/default.nix | 7 +- parts/features/apps/obs/default.nix | 9 +- parts/features/apps/obsidian.nix | 7 +- parts/features/apps/portfolio-performance.nix | 7 +- parts/features/apps/qalculate.nix | 7 +- parts/features/apps/satty/default.nix | 7 +- parts/features/apps/signal.nix | 7 +- parts/features/apps/solaar.nix | 7 +- .../features/apps/sound-switcher/default.nix | 8 +- parts/features/apps/ssh/default.nix | 7 +- parts/features/apps/starship.nix | 6 +- parts/features/apps/tealdeer.nix | 6 +- parts/features/apps/telegram.nix | 7 +- parts/features/apps/thunderbird.nix | 8 +- parts/features/apps/vlc.nix | 7 +- parts/features/apps/xdg.nix | 7 +- parts/features/apps/zoom.nix | 7 +- parts/features/apps/zoxide.nix | 6 +- parts/features/core/fonts/default.nix | 8 +- parts/features/core/impermanence.nix | 4 +- parts/features/core/networking/default.nix | 13 +- parts/features/desktop/cliphist.nix | 7 +- parts/features/desktop/dconf.nix | 8 +- parts/features/desktop/display-manager.nix | 7 +- parts/features/desktop/gtk-qt.nix | 7 +- parts/features/desktop/niri/default.nix | 9 +- parts/features/desktop/theming.nix | 4 +- parts/features/desktop/waybar/default.nix | 11 +- parts/features/dev/claude-code/default.nix | 7 +- parts/features/dev/codex.nix | 7 +- parts/features/dev/devenv.nix | 7 +- parts/features/dev/direnv.nix | 6 +- parts/features/dev/git/default.nix | 6 +- parts/features/dev/neovim/_avante/default.nix | 4 +- parts/features/dev/neovim/_dadbod/default.nix | 4 +- .../dev/neovim/_mason-lsp/default.nix | 4 +- parts/features/dev/neovim/default.nix | 6 +- parts/features/hardware/audio.nix | 9 +- parts/features/hardware/bluetooth.nix | 8 +- parts/features/hardware/btrfs.nix | 8 +- parts/features/hardware/firmware.nix | 8 +- parts/features/hardware/power.nix | 7 +- parts/features/security/bitwarden.nix | 7 +- parts/features/security/security.nix | 9 +- parts/features/services/localsend.nix | 8 +- parts/features/services/scrutiny.nix | 8 +- parts/features/services/syncthing.nix | 6 +- .../services/virtualisation/default.nix | 8 +- parts/hosts.nix | 47 +- parts/hosts/flexbox/hardware-scan.nix | 29 - parts/hosts/numenor/hardware-scan.nix | 37 - parts/options.nix | 42 -- specialisations/light/default.nix | 53 -- system/amd/default.nix | 39 -- system/audio/default.nix | 73 -- system/bluetooth/default.nix | 13 - system/boot/default.nix | 17 - system/btrfs/default.nix | 17 - system/cachix/default.nix | 5 - system/default.nix | 46 -- system/desktop/default.nix | 68 -- system/dns/default.nix | 12 - system/firmware/default.nix | 14 - system/fonts/default.nix | 78 --- .../fonts/scripts/patch-fira-with-fa6-pro.sh | 130 ---- system/impermanence/default.nix | 105 --- system/io/default.nix | 45 -- system/kernel/default.nix | 22 - system/kind-killer/default.nix | 13 - system/localsend/default.nix | 15 - system/networking/default.nix | 91 --- system/nix-ld/default.nix | 3 - system/nvidia/default.nix | 50 -- system/performance/default.nix | 6 - system/power/default.nix | 52 -- system/printing/default.nix | 16 - system/scripts/nh-eval-profile.nix | 68 -- system/scrutiny/default.nix | 26 - system/security/default.nix | 65 -- system/smb/default.nix | 4 - system/stylix/default.nix | 37 - system/stylix/gruvbox-dark-rainbow.png | Bin 185977 -> 0 bytes system/stylix/gruvbox-light-rainbow.png | Bin 192946 -> 0 bytes system/syncthing/default.nix | 11 - system/systemd/default.nix | 3 - system/users/default.nix | 26 - system/various/default.nix | 25 - system/video/default.nix | 12 - system/virtualisation/default.nix | 102 --- .../scripts/benchmark-containers.nix | 6 - .../scripts/benchmark-containers.sh | 53 -- .../scripts/benchmark-heavy-containers.nix | 6 - .../scripts/benchmark-heavy-containers.sh | 138 ---- .../scripts/reset-container-state.nix | 6 - .../scripts/reset-container-state.sh | 96 --- system/wireshark/default.nix | 7 - 355 files changed, 353 insertions(+), 11522 deletions(-) delete mode 100644 configuration.nix delete mode 100644 home/aichat/default.nix delete mode 100644 home/aider/default.nix delete mode 100644 home/alacritty/default.nix delete mode 100644 home/aliases/default.nix delete mode 100644 home/ansible/default.nix delete mode 100644 home/asciinema/default.nix delete mode 100644 home/aws/default.nix delete mode 100644 home/bash/default.nix delete mode 100644 home/bitwarden/default.nix delete mode 100644 home/bluetuith/default.nix delete mode 100644 home/brave-browser/default.nix delete mode 100644 home/broot/default.nix delete mode 100644 home/btop/default.nix delete mode 100644 home/calibre/default.nix delete mode 100644 home/claude-code/CLAUDE.md delete mode 100644 home/claude-code/default.nix delete mode 100644 home/cliphist/default.nix delete mode 100644 home/codex/default.nix delete mode 100644 home/cpu-profile-toggler/default.nix delete mode 100644 home/cpu-profile-toggler/scripts/cpu-profile-toggler.sh delete mode 100644 home/dconf/default.nix delete mode 100644 home/ddc-backlight/default.nix delete mode 100644 home/ddc-backlight/scripts/ddc-backlight.sh delete mode 100644 home/default.nix delete mode 100644 home/devenv/default.nix delete mode 100644 home/direnv/default.nix delete mode 100644 home/discord/default.nix delete mode 100644 home/dunst/default.nix delete mode 100644 home/easyeffects/default.nix delete mode 100644 home/easyeffects/presets/irs/razor-surround-48k-z-edition-stereo-plus20-bass.irs delete mode 100644 home/easyeffects/presets/output/bass-enhancing-perfect-eq.json delete mode 100644 home/email/default.nix delete mode 100644 home/firefox/default.nix delete mode 100644 home/fish/default.nix delete mode 100644 home/fix-flexbox-mike/default.nix delete mode 100644 home/fix-flexbox-mike/scripts/xps-9700-mic-fixer.sh delete mode 100644 home/fuzzel/default.nix delete mode 100644 home/fzf/default.nix delete mode 100644 home/galaxy-buds-client/default.nix delete mode 100644 home/gimp/default.nix delete mode 100644 home/git-worktree-switcher/default.nix delete mode 100644 home/git/default.nix delete mode 100644 home/git/github-cli/gh.config.yml delete mode 100644 home/gnome-connections/default.nix delete mode 100644 home/gtk-qt/default.nix delete mode 100644 home/gtk-qt/qtct.conf delete mode 100644 home/hoppscotch/default.nix delete mode 100644 home/hwatch/default.nix delete mode 100644 home/impermanence/default.nix delete mode 100644 home/isd/default.nix delete mode 100644 home/jqp/default.nix delete mode 100644 home/jujutsu/default.nix delete mode 100644 home/k9s/default.nix delete mode 100644 home/k9s/gruvbox-dark.yaml delete mode 100644 home/k9s/gruvbox-light.yaml delete mode 100644 home/kanshi/default.nix delete mode 100644 home/kind-with-local-registry/default.nix delete mode 100644 home/kind-with-local-registry/scripts/kind-with-local-registry.sh delete mode 100644 home/kubernetes-tools/default.nix delete mode 100644 home/less/default.nix delete mode 100644 home/lf/default.nix delete mode 100644 home/lf/pistol/pistol.conf delete mode 100644 home/libation/default.nix delete mode 100644 home/libreoffice/default.nix delete mode 100644 home/lnav/default.nix delete mode 100644 home/mic-levels-maintainer/default.nix delete mode 100644 home/mic-levels-maintainer/scripts/mic-levels-maintainer-flexbox.sh delete mode 100644 home/mic-levels-maintainer/scripts/mic-levels-maintainer-numenor.sh delete mode 100644 home/mpv/default.nix delete mode 100644 home/mullvad-browser/default.nix delete mode 100644 home/nautilus/default.nix delete mode 100644 home/neovim/avante/avante.lua delete mode 100644 home/neovim/avante/default.nix delete mode 100644 home/neovim/carbon/default.nix delete mode 100644 home/neovim/cmp/cmp.lua delete mode 100644 home/neovim/cmp/default.nix delete mode 100644 home/neovim/comment-nvim/default.nix delete mode 100644 home/neovim/conform/conform.lua delete mode 100644 home/neovim/conform/default.nix delete mode 100644 home/neovim/dadbod/default.nix delete mode 100644 home/neovim/dap/dap-ui.lua delete mode 100644 home/neovim/dap/dap.lua delete mode 100644 home/neovim/dap/default.nix delete mode 100644 home/neovim/default.nix delete mode 100644 home/neovim/diffview-nvim/default.nix delete mode 100644 home/neovim/diffview-nvim/diffview-nvim.lua delete mode 100644 home/neovim/fidget/default.nix delete mode 100644 home/neovim/folds/default.nix delete mode 100644 home/neovim/folds/ufo.lua delete mode 100644 home/neovim/fugitive/default.nix delete mode 100644 home/neovim/fugitive/fugitive.lua delete mode 100644 home/neovim/git-conflict-nvim/default.nix delete mode 100644 home/neovim/gitsigns/default.nix delete mode 100644 home/neovim/gitsigns/gitsigns.lua delete mode 100644 home/neovim/gruvbox/default.nix delete mode 100644 home/neovim/jdtls/default.nix delete mode 100644 home/neovim/jdtls/jdtls.lua delete mode 100644 home/neovim/jj/default.nix delete mode 100644 home/neovim/jj/jj.lua delete mode 100644 home/neovim/lspsaga/default.nix delete mode 100644 home/neovim/lualine/default.nix delete mode 100644 home/neovim/mason-lsp/default.nix delete mode 100644 home/neovim/mason-lsp/mason.lua delete mode 100644 home/neovim/mason-lsp/shared_lsp_config.lua delete mode 100644 home/neovim/mini-icons/default.nix delete mode 100644 home/neovim/mini-operators/default.nix delete mode 100644 home/neovim/neotest/default.nix delete mode 100644 home/neovim/neotest/neotest.lua delete mode 100644 home/neovim/noice/default.nix delete mode 100644 home/neovim/noice/noice.lua delete mode 100644 home/neovim/notify/default.nix delete mode 100644 home/neovim/nui/default.nix delete mode 100644 home/neovim/nvim-tree-lua/default.nix delete mode 100644 home/neovim/nvim-tree-lua/nvim-tree.lua delete mode 100644 home/neovim/obsidian-nvim/default.nix delete mode 100644 home/neovim/oil/default.nix delete mode 100644 home/neovim/otter/default.nix delete mode 100644 home/neovim/overseer/default.nix delete mode 100644 home/neovim/overseer/overseer.lua delete mode 100644 home/neovim/overseer/overseer_lib.lua delete mode 100644 home/neovim/overseer/templates/gmailctl_apply.lua delete mode 100644 home/neovim/overseer/templates/java_gradle/init.lua delete mode 100644 home/neovim/overseer/templates/java_maven/init.lua delete mode 100644 home/neovim/overseer/templates/nixos_rebuild_boot.lua delete mode 100644 home/neovim/overseer/templates/nixos_rebuild_switch.lua delete mode 100644 home/neovim/overseer/templates/nixos_update_secrets.lua delete mode 100644 home/neovim/overseer/templates/skaffold_dev.lua delete mode 100644 home/neovim/plenary/default.nix delete mode 100644 home/neovim/rainbow-csv/default.nix delete mode 100644 home/neovim/render-markdown/default.nix delete mode 100644 home/neovim/telescope/default.nix delete mode 100644 home/neovim/toggleterm/default.nix delete mode 100644 home/neovim/treesitter/default.nix delete mode 100644 home/neovim/treesitter/queries/nix/injections.scm delete mode 100644 home/neovim/treesitter/treesitter.lua delete mode 100644 home/neovim/trouble/default.nix delete mode 100644 home/neovim/trouble/trouble.lua delete mode 100644 home/neovim/undotree/default.nix delete mode 100644 home/neovim/vim-be-good/default.nix delete mode 100644 home/neovim/vim-terraform/default.nix delete mode 100644 home/neovim/vim-visual-multi/default.nix delete mode 100644 home/neovim/web-devicons/default.nix delete mode 100644 home/neovim/yank-file-line/default.nix delete mode 100644 home/neovim/yank-file-line/yank-file-line.lua delete mode 100644 home/networkmanager-dmenu/config.ini delete mode 100644 home/networkmanager-dmenu/default.nix delete mode 100644 home/nh/default.nix delete mode 100644 home/niri/default.nix delete mode 100644 home/niri/scripts/niri-auto-column.sh delete mode 100644 home/niri/scripts/niri-open-on-workspace.sh delete mode 100644 home/niri/scripts/niri-pick-window.sh delete mode 100644 home/niri/scripts/niri-qalc.sh delete mode 100755 home/niri/scripts/niri-reorder-workspaces.sh delete mode 100644 home/niri/scripts/niri-set-wallpaper.sh delete mode 100644 home/niri/wallpapers/gruvbox-dark-rainbow.png delete mode 100644 home/niri/wallpapers/gruvbox-light-rainbow.png delete mode 100644 home/nix-index/default.nix delete mode 100644 home/nix-inspect/default.nix delete mode 100644 home/nushell/config.nu delete mode 100644 home/nushell/default.nix delete mode 100644 home/nushell/env.nu delete mode 100644 home/nushell/syncthing/stignore-nushell delete mode 100644 home/obs/default.nix delete mode 100644 home/obs/scripts/obs-catcam-toggle.sh delete mode 100644 home/obs/scripts/obs-main-scene.sh delete mode 100644 home/obs/scripts/obs-recording-pause.sh delete mode 100644 home/obs/scripts/obs-recording-toggle.sh delete mode 100644 home/obs/scripts/obs-screensharing.sh delete mode 100644 home/obs/scripts/obs-webcam-toggle.sh delete mode 100644 home/obsidian/default.nix delete mode 100644 home/onboard/default.nix delete mode 100644 home/pavucontrol/default.nix delete mode 100644 home/pgcli/default.nix delete mode 100644 home/pomodoro-gtk/default.nix delete mode 100644 home/portfolio-performance/default.nix delete mode 100644 home/psql/default.nix delete mode 100644 home/psql/psqlrc delete mode 100644 home/pulsemixer/default.nix delete mode 100644 home/pulsemixer/pulsemixer.cfg delete mode 100644 home/qalculate/default.nix delete mode 100644 home/ripgrep-all/default.nix delete mode 100644 home/ripgrep/default.nix delete mode 100644 home/rofimoji/default.nix delete mode 100644 home/rofimoji/rofimoji.rc delete mode 100644 home/satty/default.nix delete mode 100644 home/satty/scripts/satty-screenshot.sh delete mode 100644 home/showmethekey/default.nix delete mode 100644 home/signal/default.nix delete mode 100644 home/solaar/default.nix delete mode 100644 home/sound-switcher/default.nix delete mode 100644 home/sound-switcher/scripts/sound-switcher-flexbox.sh delete mode 100644 home/sound-switcher/scripts/sound-switcher-numenor.sh delete mode 100644 home/ssh/README.md delete mode 100644 home/ssh/default.nix delete mode 100644 home/ssh/ssh-add-all.sh delete mode 100644 home/starship/default.nix delete mode 100644 home/stylix/default.nix delete mode 100644 home/syncthing/default.nix delete mode 100644 home/systemd-errors-and-warnings-counter/default.nix delete mode 100644 home/systemd-errors-and-warnings-counter/scripts/systemd-errors-and-warnings-counter.sh delete mode 100644 home/tealdeer/default.nix delete mode 100644 home/telegram/default.nix delete mode 100644 home/television/default.nix delete mode 100644 home/tomat/default.nix delete mode 100644 home/trash-cli/default.nix delete mode 100644 home/tray-tui/default.nix delete mode 100644 home/udiskie/default.nix delete mode 100644 home/urxvt/default.nix delete mode 100644 home/variety/default.nix delete mode 100644 home/variety/variety.conf delete mode 100644 home/virtual-cable/default.nix delete mode 100644 home/virtual-cable/scripts/obs-mic.sh delete mode 100644 home/vlc/default.nix delete mode 100644 home/waybar/default.nix delete mode 100644 home/waybar/scripts/dunst-dnd-waybar.sh delete mode 100644 home/witr/default.nix delete mode 100644 home/wlsunset/default.nix delete mode 100644 home/wlsunset/scripts/wlsunset-waybar.sh delete mode 100644 home/wluma/default.nix delete mode 100644 home/xdg/default.nix delete mode 100644 home/ytmdesktop/default.nix delete mode 100644 home/yubico/default.nix delete mode 100644 home/yubico/modules/yubikey-touch-detector/default.nix delete mode 100644 home/zen/default.nix delete mode 100644 home/zoom/default.nix delete mode 100644 home/zoxide/default.nix delete mode 100644 machines/flexbox/system.nix delete mode 100644 machines/numenor/system.nix delete mode 100644 nix/default.nix rename parts/{hosts => _hosts}/flexbox/default.nix (100%) rename {machines => parts/_hosts}/flexbox/hardware-scan.nix (100%) rename parts/{hosts => _hosts}/numenor/default.nix (100%) rename {machines => parts/_hosts}/numenor/hardware-scan.nix (100%) delete mode 100644 parts/hosts/flexbox/hardware-scan.nix delete mode 100644 parts/hosts/numenor/hardware-scan.nix delete mode 100644 parts/options.nix delete mode 100644 specialisations/light/default.nix delete mode 100644 system/amd/default.nix delete mode 100644 system/audio/default.nix delete mode 100644 system/bluetooth/default.nix delete mode 100644 system/boot/default.nix delete mode 100644 system/btrfs/default.nix delete mode 100644 system/cachix/default.nix delete mode 100644 system/default.nix delete mode 100644 system/desktop/default.nix delete mode 100644 system/dns/default.nix delete mode 100644 system/firmware/default.nix delete mode 100644 system/fonts/default.nix delete mode 100644 system/fonts/scripts/patch-fira-with-fa6-pro.sh delete mode 100644 system/impermanence/default.nix delete mode 100644 system/io/default.nix delete mode 100644 system/kernel/default.nix delete mode 100644 system/kind-killer/default.nix delete mode 100644 system/localsend/default.nix delete mode 100644 system/networking/default.nix delete mode 100644 system/nix-ld/default.nix delete mode 100644 system/nvidia/default.nix delete mode 100644 system/performance/default.nix delete mode 100644 system/power/default.nix delete mode 100644 system/printing/default.nix delete mode 100644 system/scripts/nh-eval-profile.nix delete mode 100644 system/scrutiny/default.nix delete mode 100644 system/security/default.nix delete mode 100644 system/smb/default.nix delete mode 100644 system/stylix/default.nix delete mode 100644 system/stylix/gruvbox-dark-rainbow.png delete mode 100644 system/stylix/gruvbox-light-rainbow.png delete mode 100644 system/syncthing/default.nix delete mode 100644 system/systemd/default.nix delete mode 100644 system/users/default.nix delete mode 100644 system/various/default.nix delete mode 100644 system/video/default.nix delete mode 100644 system/virtualisation/default.nix delete mode 100644 system/virtualisation/scripts/benchmark-containers.nix delete mode 100644 system/virtualisation/scripts/benchmark-containers.sh delete mode 100644 system/virtualisation/scripts/benchmark-heavy-containers.nix delete mode 100644 system/virtualisation/scripts/benchmark-heavy-containers.sh delete mode 100644 system/virtualisation/scripts/reset-container-state.nix delete mode 100644 system/virtualisation/scripts/reset-container-state.sh delete mode 100644 system/wireshark/default.nix diff --git a/configuration.nix b/configuration.nix deleted file mode 100644 index a46c2d19..00000000 --- a/configuration.nix +++ /dev/null @@ -1,7 +0,0 @@ -{...}: { - imports = [ - ./nix - ./specialisations/light - ./system - ]; -} diff --git a/doc/DENDRITIC.md b/doc/DENDRITIC.md index cfd404d1..ae5a95b7 100644 --- a/doc/DENDRITIC.md +++ b/doc/DENDRITIC.md @@ -18,9 +18,16 @@ nixos-config/ ├── flake.lock │ ├── parts/ # All flake-parts modules (auto-imported) -│ ├── options.nix # config.dendrix.* option definitions │ ├── modules.nix # Imports flake-parts.flakeModules.modules -│ ├── hosts.nix # Host definitions and feature composition +│ ├── hosts.nix # Host definitions, dendrix options, and feature composition +│ │ +│ ├── _hosts/ # Host-specific config (underscore excludes from import-tree) +│ │ ├── flexbox/ +│ │ │ ├── default.nix # Host-specific NixOS settings +│ │ │ └── hardware-scan.nix +│ │ └── numenor/ +│ │ ├── default.nix +│ │ └── hardware-scan.nix │ │ │ ├── features/ # Feature modules │ │ ├── core/ # Essential system features @@ -67,14 +74,6 @@ nixos-config/ │ │ ├── sops.nix │ │ ├── gpg.nix │ │ └── keyring.nix -│ │ -│ └── hosts/ # Host-specific config -│ ├── flexbox/ -│ │ ├── default.nix # Host options + overrides -│ │ └── hardware-scan.nix -│ └── numenor/ -│ ├── default.nix -│ └── hardware-scan.nix │ └── doc/ └── DENDRITIC.md @@ -86,13 +85,13 @@ A feature file configures all aspects of a single feature: ```nix # parts/features/apps/alacritty.nix -{ config, lib, ... }: +{ ... }: { flake.modules.nixos.alacritty = { pkgs, ... }: { fonts.packages = [ pkgs.fira-code ]; }; - flake.modules.homeManager.alacritty = { pkgs, ... }: { + flake.modules.homeManager.alacritty = { pkgs, lib, osConfig, ... }: { programs.alacritty = { enable = true; settings = { @@ -101,86 +100,119 @@ A feature file configures all aspects of a single feature: }; # Feature owns its persistence paths - home.persistence."/persist" = lib.mkIf config.dendrix.isImpermanent { + # Use osConfig to access NixOS-level dendrix options from home-manager + home.persistence."/persist" = lib.mkIf osConfig.dendrix.isImpermanent { directories = [ ".config/alacritty" ]; }; }; } ``` -## Host-Specific Values via Top-Level Config +## Host-Specific Values via NixOS Options -Instead of threading `specialArgs` through module evaluations, host-specific values are defined as options in the top-level configuration. Every module can read from this shared config: +Instead of threading `specialArgs` through module evaluations, host-specific values are defined as NixOS options (`config.dendrix.*`). These are defined in `parts/hosts.nix` and set for each host: ```nix -# parts/options.nix -{ lib, ... }: -{ - options.dendrix = { - hostname = lib.mkOption { type = lib.types.str; }; - isLaptop = lib.mkOption { type = lib.types.bool; default = false; }; - isImpermanent = lib.mkOption { type = lib.types.bool; default = false; }; - hasNvidia = lib.mkOption { type = lib.types.bool; default = false; }; - hasAmd = lib.mkOption { type = lib.types.bool; default = false; }; +# parts/hosts.nix (excerpt) +{config, lib, inputs, ...}: let + # NixOS module that defines dendrix options + dendrixOptionsModule = {lib, ...}: { + options.dendrix = { + hostname = lib.mkOption { type = lib.types.str; }; + isLaptop = lib.mkOption { type = lib.types.bool; default = false; }; + isImpermanent = lib.mkOption { type = lib.types.bool; default = false; }; + hasNvidia = lib.mkOption { type = lib.types.bool; default = false; }; + hasAmd = lib.mkOption { type = lib.types.bool; default = false; }; + stateVersion = lib.mkOption { type = lib.types.str; }; + homeStateVersion = lib.mkOption { type = lib.types.str; }; + }; + }; + + mkHost = { hostname, hostModule, dendrixConfig, ... }: + nixpkgs.lib.nixosSystem { + modules = [ + dendrixOptionsModule + { dendrix = dendrixConfig; } # Set values for this host + # ... other modules + ]; + }; +in { + flake.nixosConfigurations = { + flexbox = mkHost { + hostname = "flexbox"; + hostModule = ./_hosts/flexbox; + dendrixConfig = { + hostname = "flexbox"; + isLaptop = true; + hasNvidia = true; + # ... + }; + }; }; } +``` -# parts/hosts/flexbox/default.nix +Feature modules access these values from NixOS config: + +```nix +# parts/features/hardware/nvidia.nix - NixOS modules use config.dendrix.* { ... }: { - config.dendrix = { - hostname = "flexbox"; - isLaptop = true; - hasNvidia = true; + flake.modules.nixos.nvidia = { config, lib, ... }: { + hardware.nvidia.enable = lib.mkIf config.dendrix.hasNvidia true; }; -} -# Any feature can then access these values: -# parts/features/hardware/nvidia.nix -{ config, lib, ... }: -{ - flake.modules.nixos.nvidia = lib.mkIf config.dendrix.hasNvidia { - # NVIDIA configuration + # Home-manager modules use osConfig.dendrix.* + flake.modules.homeManager.nvidia = { osConfig, lib, ... }: { + home.sessionVariables = lib.mkIf osConfig.dendrix.hasNvidia { + __GLX_VENDOR_LIBRARY_NAME = "nvidia"; + }; }; } ``` ## Host Definition -Hosts compose features in `parts/hosts.nix`: +Hosts are defined in `parts/hosts.nix` using a `mkHost` helper that composes all dendritic modules: ```nix -{ inputs, ... }: -{ +{ config, lib, inputs, ... }: let + # Collect all dendritic modules + nixosModules = builtins.attrValues config.flake.modules.nixos; + homeManagerModules = builtins.attrValues config.flake.modules.homeManager; + + mkHost = { hostname, hostModule, dendrixConfig, ... }: + inputs.nixpkgs.lib.nixosSystem { + modules = + commonNixosModules # External modules (home-manager, stylix, etc.) + ++ [ dendrixOptionsModule ] + ++ nixosModules # All dendritic NixOS modules + ++ [ + hostModule # Host-specific hardware and settings + { dendrix = dendrixConfig; } + { + home-manager.sharedModules = homeManagerModules; + } + ]; + }; +in { flake.nixosConfigurations = { - flexbox = inputs.nixpkgs.lib.nixosSystem { - system = "x86_64-linux"; - modules = [ - inputs.self.modules.nixos.boot - inputs.self.modules.nixos.networking - inputs.self.modules.nixos.users - inputs.self.modules.nixos.nvidia - inputs.self.modules.nixos.niri - inputs.self.modules.nixos.theming - inputs.self.modules.nixos.alacritty - - ../hosts/flexbox/hardware-scan.nix - inputs.self.modules.nixos.host-flexbox - ]; + flexbox = mkHost { + hostname = "flexbox"; + hostModule = ./_hosts/flexbox; + dendrixConfig = { hostname = "flexbox"; isLaptop = true; hasNvidia = true; /* ... */ }; }; - - numenor = inputs.nixpkgs.lib.nixosSystem { - system = "x86_64-linux"; - modules = [ - inputs.self.modules.nixos.amd - inputs.self.modules.nixos.impermanence - # ... - ]; + numenor = mkHost { + hostname = "numenor"; + hostModule = ./_hosts/numenor; + dendrixConfig = { hostname = "numenor"; isImpermanent = true; hasAmd = true; /* ... */ }; }; }; } ``` +All dendritic modules are included in all hosts. Features use `config.dendrix.*` to conditionally enable host-specific behavior. + ## Key Concepts ### flake-parts diff --git a/flake.nix b/flake.nix index a983bdbc..7872a30b 100644 --- a/flake.nix +++ b/flake.nix @@ -44,141 +44,5 @@ imports = [ (inputs.import-tree ./parts) ]; - - # Legacy configuration - will be migrated to parts/ incrementally - flake = let - inherit (inputs) determinate nixpkgs nixos-unstable home-manager impermanence niri nur secrets sops-nix stylix; - - commonModules = [ - { - nixpkgs.overlays = [ - (_: _: overlays) - ]; - } - determinate.nixosModules.default - nixpkgs.nixosModules.notDetected - ./configuration.nix - nur.modules.nixos.default - impermanence.nixosModules.impermanence - sops-nix.nixosModules.sops - stylix.nixosModules.stylix - home-manager.nixosModules.home-manager - niri.nixosModules.niri - ]; - commonHomeManagerSettings = { - useGlobalPkgs = true; - useUserPackages = true; - backupFileExtension = "home-manager-backup"; - users.farlion = import ./home; - }; - overlays = { - unstable = import nixos-unstable { - system = "x86_64-linux"; - config.allowUnfree = true; - }; - }; - - mkSystem = { - hostname, - isImpermanent, - isLaptop, - isAmd, - isNvidia, - extraModules ? [], - }: let - machineArgs = { - inherit inputs secrets isImpermanent isLaptop; - }; - in - nixpkgs.lib.nixosSystem { - specialArgs = machineArgs; - modules = - commonModules - ++ [ - ./machines/${hostname}/hardware-scan.nix - ./machines/${hostname}/system.nix - { - home-manager = - commonHomeManagerSettings - // { - extraSpecialArgs = - machineArgs - // { - inherit isAmd isNvidia; - }; - }; - } - ] - ++ extraModules; - }; - in { - nixosConfigurations.flexbox = mkSystem { - hostname = "flexbox"; - isImpermanent = false; - isLaptop = true; - isAmd = false; - isNvidia = true; - extraModules = [./system/nvidia]; - }; - - nixosConfigurations.numenor = mkSystem { - hostname = "numenor"; - isImpermanent = true; - isLaptop = false; - isAmd = true; - isNvidia = false; - extraModules = [./system/amd ./system/btrfs]; - }; - - # Home-manager standalone configuration for `home-manager news` CLI - # Uses actual config with all host-specific features enabled for maximum news coverage - # Actual home-manager is managed via NixOS module (see nixosConfigurations above) - homeConfigurations.farlion = home-manager.lib.homeManagerConfiguration { - pkgs = nixpkgs.legacyPackages.x86_64-linux; - extraSpecialArgs = { - inherit inputs secrets; - # Enable all host-specific features to get maximum applicable news - isImpermanent = true; - isLaptop = true; - isAmd = true; - isNvidia = true; - # Mock osConfig for standalone mode - osConfig = { - networking.hostName = "standalone-news-config"; - specialisation = {}; - }; - }; - modules = [ - { - nixpkgs.overlays = [(_: _: overlays)]; - } - # Import impermanence home-manager module directly (the flake output is deprecated) - "${impermanence}/home-manager.nix" - nur.modules.homeManager.default - stylix.homeManagerModules.stylix - niri.homeModules.niri - { - home = { - username = "farlion"; - homeDirectory = "/home/farlion"; - }; - assertions = nixpkgs.lib.mkForce []; - } - (import ./home) - ]; - }; - - # Expose profiling helper as a package and an app - # Call with `nix run .#nh-eval-profile -- ` - packages.x86_64-linux.nh-eval-profile = let - pkgsFor = nixpkgs.legacyPackages.x86_64-linux; - in - pkgsFor.callPackage ./system/scripts/nh-eval-profile.nix {}; - - apps.x86_64-linux.nh-eval-profile = { - type = "app"; - program = "${inputs.self.packages.x86_64-linux.nh-eval-profile}/bin/nh-eval-profile"; - }; - }; }); } diff --git a/home/aichat/default.nix b/home/aichat/default.nix deleted file mode 100644 index c0f62200..00000000 --- a/home/aichat/default.nix +++ /dev/null @@ -1,49 +0,0 @@ -{ - lib, - isImpermanent, - pkgs, - ... -}: { - home.persistence."/persist" = lib.mkIf isImpermanent { - directories = [ - ".config/aichat" - ]; - }; - - programs.aichat = { - enable = true; - package = pkgs.unstable.aichat; - settings = { - model = "openai:gpt-5.1-chat-latest"; - keybindings = "vi"; - save_session = true; - compress_threshold = 0; - clients = [ - {type = "openai";} - {type = "deepseek";} - { - type = "gemini"; - patch.chat_completions.".*".body.safetySettings = [ - { - category = "HARM_CATEGORY_HARASSMENT"; - threshold = "BLOCK_NONE"; - } - { - category = "HARM_CATEGORY_HATE_SPEECH"; - threshold = "BLOCK_NONE"; - } - { - category = "HARM_CATEGORY_SEXUALLY_EXPLICIT"; - threshold = "BLOCK_NONE"; - } - { - category = "HARM_CATEGORY_DANGEROUS_CONTENT"; - threshold = "BLOCK_NONE"; - } - ]; - } - {type = "claude";} - ]; - }; - }; -} diff --git a/home/aider/default.nix b/home/aider/default.nix deleted file mode 100644 index b31b91a8..00000000 --- a/home/aider/default.nix +++ /dev/null @@ -1,5 +0,0 @@ -{...}: { - programs.aider-chat = { - enable = true; - }; -} diff --git a/home/alacritty/default.nix b/home/alacritty/default.nix deleted file mode 100644 index 7646a4ef..00000000 --- a/home/alacritty/default.nix +++ /dev/null @@ -1,69 +0,0 @@ -{...}: { - programs.alacritty = { - enable = true; - - settings = { - cursor = { - vi_mode_style = { - shape = "Beam"; - blinking = "Always"; - }; - }; - - keyboard.bindings = [ - { - key = "Return"; - mods = "Control|Super"; - action = "SpawnNewInstance"; - } - { - key = "Escape"; - mods = "Alt"; - action = "ToggleViMode"; - } - { - key = "Semicolon"; - mode = "Vi|~Search"; - action = "Right"; - } - { - key = "L"; - mode = "Vi|~Search"; - action = "Up"; - } - { - key = "K"; - mode = "Vi|~Search"; - action = "Down"; - } - { - key = "J"; - mode = "Vi|~Search"; - action = "Left"; - } - { - key = 53; - mode = "Vi|~Search"; - mods = "Shift"; - action = "SearchBackward"; - } - ]; - - env = { - # Better color support in some apps - TERM = "xterm-256color"; - }; - - scrolling = { - history = 100000; - }; - - window = { - padding = { - x = 5; - y = 4; - }; - }; - }; - }; -} diff --git a/home/aliases/default.nix b/home/aliases/default.nix deleted file mode 100644 index e887ac3a..00000000 --- a/home/aliases/default.nix +++ /dev/null @@ -1,59 +0,0 @@ -{...}: { - home.shellAliases = { - ".." = "cd .."; - "..." = "cd ../.."; - "...." = "cd ../../.."; - "....." = "cd ../../../.."; - - as = "aichat --model openai:gpt-4o-mini-search-preview"; - ae = "aichat -e"; - - caffeinate = "systemctl --user stop swayidle"; - decaffeinate = "systemctl --user start swayidle"; - - c = "wl-copy"; - - cdn = "cd ~/nixos-config"; - cdc = "cd ~/code"; - - dira = "direnv allow"; - dird = "direnv deny"; - dirr = "direnv reload"; - dr = "direnv reload"; - - ghco = "gh pr checkout"; - ghpa = "gh pr review --approve"; - ghmr = "gh pr merge -r"; - - isdu = "isd --startup_mode=user"; - - k9s-kind = "k9s --context kind-kind"; - - kc = "kubectl"; - kc-kind = "kubectl --context kind-kind"; - - lh = "/run/current-system/sw/bin/ls -ah"; - - myip = "dig @resolver1.opendns.com ANY myip.opendns.com +short"; - - n = "nh os switch"; - - nl = "sudo nix-env --list-generations --profile /nix/var/nix/profiles/system"; - ngc = "sudo nix-env --delete-generations 30d --profile /nix/var/nix/profiles/system"; - - nsn = "nh search"; - - paste = "wl-paste"; - - ra = "systemctl restart --user pipewire"; - - rm = "trash-put"; - - stern-kind = "stern --context kind-kind"; - - tailup = "sudo tailscale up --accept-routes --accept-dns=false"; - taildown = "sudo tailscale down"; - - x = "exit"; - }; -} diff --git a/home/ansible/default.nix b/home/ansible/default.nix deleted file mode 100644 index 5ac99a7a..00000000 --- a/home/ansible/default.nix +++ /dev/null @@ -1,11 +0,0 @@ -{ - lib, - isImpermanent, - ... -}: { - home.persistence."/persist" = lib.mkIf isImpermanent { - directories = [ - ".ansible" - ]; - }; -} diff --git a/home/asciinema/default.nix b/home/asciinema/default.nix deleted file mode 100644 index 8d992fc7..00000000 --- a/home/asciinema/default.nix +++ /dev/null @@ -1,5 +0,0 @@ -{...}: { - programs.asciinema = { - enable = true; - }; -} diff --git a/home/aws/default.nix b/home/aws/default.nix deleted file mode 100644 index 91871f8f..00000000 --- a/home/aws/default.nix +++ /dev/null @@ -1,14 +0,0 @@ -{ - isImpermanent, - lib, - pkgs, - ... -}: { - home.persistence."/persist" = lib.mkIf isImpermanent { - directories = [ - ".aws" - ]; - }; - - home.packages = [pkgs.awscli2]; -} diff --git a/home/bash/default.nix b/home/bash/default.nix deleted file mode 100644 index da8f5abe..00000000 --- a/home/bash/default.nix +++ /dev/null @@ -1,24 +0,0 @@ -{ - lib, - isImpermanent, - pkgs, - ... -}: { - home.persistence."/persist" = lib.mkIf isImpermanent { - files = [ - ".bash_history" - ]; - }; - - programs.bash = { - enable = true; - package = pkgs.bashInteractive; - initExtra = '' - # Ctrl-x: Copy current command line to clipboard - copy-command-line() { - printf '%s' "$READLINE_LINE" | ${pkgs.wl-clipboard}/bin/wl-copy - } - bind -x '"\C-x": copy-command-line' - ''; - }; -} diff --git a/home/bitwarden/default.nix b/home/bitwarden/default.nix deleted file mode 100644 index da9f8ccc..00000000 --- a/home/bitwarden/default.nix +++ /dev/null @@ -1,17 +0,0 @@ -{ - lib, - isImpermanent, - pkgs, - ... -}: { - home.persistence."/persist" = lib.mkIf isImpermanent { - directories = [ - ".config/Bitwarden" - ]; - }; - - home.packages = [ - pkgs.bitwarden-desktop - pkgs.bitwarden-cli - ]; -} diff --git a/home/bluetuith/default.nix b/home/bluetuith/default.nix deleted file mode 100644 index 306ceccd..00000000 --- a/home/bluetuith/default.nix +++ /dev/null @@ -1,5 +0,0 @@ -{...}: { - programs.bluetuith = { - enable = true; - }; -} diff --git a/home/brave-browser/default.nix b/home/brave-browser/default.nix deleted file mode 100644 index b3da9fc3..00000000 --- a/home/brave-browser/default.nix +++ /dev/null @@ -1,52 +0,0 @@ -{ - lib, - isImpermanent, - isNvidia, - pkgs, - ... -}: let - # Try to focus an existing Brave window on link open so the workspace comes to the foreground - braveNiriOpen = pkgs.writeShellApplication { - name = "brave-niri-open"; - runtimeInputs = [pkgs.niri pkgs.jq pkgs.coreutils pkgs.brave]; - text = '' - #!/usr/bin/env bash - set -euo pipefail - brave_id=$(niri msg --json windows | jq -r '.[] | select(.app_id == "brave-browser") | .id' | head -n1 || true) - if [ -n "''${brave_id:-}" ]; then - niri msg action focus-window --id "$brave_id" >/dev/null 2>&1 || true - fi - exec ${pkgs.brave}/bin/brave ${ - if isNvidia - then "--enable-features=VaapiVideoDecoder,VaapiVideoEncoder --password-store=seahorse" - else "--password-store=seahorse" - } "$@" - ''; - }; -in { - home.persistence."/persist" = lib.mkIf isImpermanent { - directories = [ - ".config/BraveSoftware" - ".cache/BraveSoftware" - ]; - }; - - home.packages = [ - pkgs.brave - ]; - - xdg.desktopEntries = { - brave-browser = { - exec = "${braveNiriOpen}/bin/brave-niri-open %U"; - name = "Brave Browser"; - comment = "Access the Internet"; - genericName = "Web Browser"; - categories = ["Network" "WebBrowser"]; - icon = "brave-browser"; - mimeType = ["application/pdf" "application/rdf+xml" "application/rss+xml" "application/xhtml+xml" "application/xhtml_xml" "application/xml" "image/gif" "image/jpeg" "image/png" "image/webp" "text/html" "text/xml" "x-scheme-handler/http" "x-scheme-handler/https" "x-scheme-handler/ipfs" "x-scheme-handler/ipns"]; - startupNotify = true; - terminal = false; - type = "Application"; - }; - }; -} diff --git a/home/broot/default.nix b/home/broot/default.nix deleted file mode 100644 index 1be2bd69..00000000 --- a/home/broot/default.nix +++ /dev/null @@ -1,5 +0,0 @@ -{...}: { - programs.broot = { - enable = true; - }; -} diff --git a/home/btop/default.nix b/home/btop/default.nix deleted file mode 100644 index 48572568..00000000 --- a/home/btop/default.nix +++ /dev/null @@ -1,5 +0,0 @@ -{...}: { - programs.btop = { - enable = true; - }; -} diff --git a/home/calibre/default.nix b/home/calibre/default.nix deleted file mode 100644 index 14f8767f..00000000 --- a/home/calibre/default.nix +++ /dev/null @@ -1,18 +0,0 @@ -{ - lib, - isImpermanent, - pkgs, - ... -}: { - home.persistence."/persist" = lib.mkIf isImpermanent { - directories = [ - "Calibre Library" - ".config/calibre" - ".cache/calibre" - ]; - }; - - home.packages = [ - pkgs.calibre - ]; -} diff --git a/home/claude-code/CLAUDE.md b/home/claude-code/CLAUDE.md deleted file mode 100644 index 0f5c0d8d..00000000 --- a/home/claude-code/CLAUDE.md +++ /dev/null @@ -1,17 +0,0 @@ -- Comment code sparsely, and only where it adds true novel context to the code being executed. This is an example of superfluous commenting: -```rust - // Set current carrier in the database to track it in the logic module - CurrentCarrierRepository::set(ctx.tx(), carrier_number) - .await - .context("Failed to set current carrier")?; -``` -A comment like this would be a sign that the function naming (CurrentCarrierRepository::set) is not clear enough in the context and should be refactored instead. -Extensive File and function headers are still useful to give context. -- Apply the "Small Functions" practice: functions should be small, stay at a single level of abstraction and extract helper functions with intention-revealing names so the code reads clearly without needing comments. -- Apply the "step-down" rule: Top level reads like a story, details pushed into well-named helpers. Helpers should live below their main functions/tests wherever possible, reading like a newspaper (headlines first, details later). -* When good tests exists, prefer TDD. -- Make a `jj commit` at the end of your changes: Don't include the "Created with Claude Code" and "Co-Authored-by" lines. Also keep commits short and to the point. Use conventional-commits (such as perf, feat...etc) for commit headings. Put the subject in parentheses, i.e. `feat(logic-module): add X operation` or `chore(clippy): add a lint` -- `jj commit` does not have an `--amend` option - instead try `jj absorb` and if that doesn't find the right target then use `jj squash` to squash changes into the latest commit and then re-describe that commit as needed. -- Use `jj` instead of `git` for all version control operations -- For opening PRs on github, since jj does not map directly to git branches, first push the new bookmark with jj and then use `gh pr create --head --base main ...` -- When offering to open Github PRs, open them in draft mode and do not include a "Generated with Claude" line, nor a `## Test Plan` section unless the Test Plan is core to this specific PR. diff --git a/home/claude-code/default.nix b/home/claude-code/default.nix deleted file mode 100644 index 5834eee4..00000000 --- a/home/claude-code/default.nix +++ /dev/null @@ -1,52 +0,0 @@ -{ - lib, - isImpermanent, - pkgs, - ... -}: { - home.persistence."/persist" = lib.mkIf isImpermanent { - directories = [ - ".claude" # Claude Code global settings, agents, and credentials - ".cache/claude-cli-nodejs" # Claude Code cache - ]; - files = [ - ".claude.json" # Claude Code runtime state (credentials, project settings, etc.) - ]; - }; - - programs.claude-code = { - enable = true; - package = pkgs.unstable.claude-code; - - memory.source = ./CLAUDE.md; - - settings = { - permissions = { - allow = [ - "Bash(jj log:*)" - "Bash(jj diff:*)" - "Bash(jj status)" - "Grep" - "WebFetch(domain:github.com)" - "WebSearch" - ]; - deny = [ - "Read(./.env)" - "Read(./.env.*)" - "Read(./secrets/secrets.json)" - "Read(./config/credentials.json)" - ]; - }; - alwaysThinkingEnabled = true; - }; - }; - - # See https://dylancastillo.co/til/fix-claude-code-shift-enter-alacritty.html - programs.alacritty.settings.keyboard.bindings = [ - { - key = "Return"; - mods = "Shift"; - chars = "\n"; - } - ]; -} diff --git a/home/cliphist/default.nix b/home/cliphist/default.nix deleted file mode 100644 index 77a4d628..00000000 --- a/home/cliphist/default.nix +++ /dev/null @@ -1,30 +0,0 @@ -{ - isImpermanent, - lib, - pkgs, - ... -}: { - home.persistence."/persist" = lib.mkIf isImpermanent { - directories = [ - ".cache/cliphist" - ]; - }; - - services.cliphist = { - enable = true; - }; - - # Fix cliphist systemd service to start after Niri is ready - systemd.user.services.cliphist = { - Install.WantedBy = lib.mkForce ["niri.service"]; - Unit.Requires = ["niri.service"]; - Unit.After = ["niri.service"]; - }; - systemd.user.services.cliphist-images = { - Install.WantedBy = lib.mkForce ["niri.service"]; - Unit.Requires = ["niri.service"]; - Unit.After = ["niri.service"]; - }; - - home.packages = [pkgs.xdg-utils]; # For image copy/pasting -} diff --git a/home/codex/default.nix b/home/codex/default.nix deleted file mode 100644 index 7b0ba8b4..00000000 --- a/home/codex/default.nix +++ /dev/null @@ -1,14 +0,0 @@ -{ - lib, - isImpermanent, - pkgs, - ... -}: { - home.persistence."/persist" = lib.mkIf isImpermanent { - directories = [ - ".codex" - ]; - }; - - home.packages = with pkgs.unstable; [codex]; -} diff --git a/home/cpu-profile-toggler/default.nix b/home/cpu-profile-toggler/default.nix deleted file mode 100644 index 61ed9042..00000000 --- a/home/cpu-profile-toggler/default.nix +++ /dev/null @@ -1,10 +0,0 @@ -# Toggle CPU profiles -{pkgs, ...}: let - cpu-profile-toggler = pkgs.writeShellApplication { - name = "cpu-profile-toggler"; - runtimeInputs = with pkgs; [gnugrep auto-cpufreq linuxKernel.packages.linux_zen.cpupower]; - text = builtins.readFile ./scripts/cpu-profile-toggler.sh; - }; -in { - home.packages = [cpu-profile-toggler]; -} diff --git a/home/cpu-profile-toggler/scripts/cpu-profile-toggler.sh b/home/cpu-profile-toggler/scripts/cpu-profile-toggler.sh deleted file mode 100644 index 06ad9d5c..00000000 --- a/home/cpu-profile-toggler/scripts/cpu-profile-toggler.sh +++ /dev/null @@ -1,19 +0,0 @@ -current_mode=$(cpupower frequency-info | grep -oP '(?<= governor ").*(?=")') - -if [[ "${1:-}" == "--toggle" ]]; then - if [ "$current_mode" == "powersave" ]; then - sudo auto-cpufreq --force performance - elif [ "$current_mode" == "performance" ]; then - sudo auto-cpufreq --force powersave - fi -elif [[ "${1:-}" == "--reset" ]]; then - if [ "$current_mode" == "powersave" ]; then - sudo auto-cpufreq --force reset - fi -else - if [ "$current_mode" == "powersave" ]; then - echo "{\"alt\": \"powersave\"}" - elif [ "$current_mode" == "performance" ]; then - echo "{\"alt\": \"performance\"}" - fi -fi diff --git a/home/dconf/default.nix b/home/dconf/default.nix deleted file mode 100644 index 37e6f149..00000000 --- a/home/dconf/default.nix +++ /dev/null @@ -1,11 +0,0 @@ -{ - lib, - isImpermanent, - ... -}: { - home.persistence."/persist" = lib.mkIf isImpermanent { - directories = [ - ".config/dconf" - ]; - }; -} diff --git a/home/ddc-backlight/default.nix b/home/ddc-backlight/default.nix deleted file mode 100644 index b06c071b..00000000 --- a/home/ddc-backlight/default.nix +++ /dev/null @@ -1,10 +0,0 @@ -# Toggle CPU profiles -{pkgs, ...}: let - ddc-backlight = pkgs.writeShellApplication { - name = "ddc-backlight"; - runtimeInputs = [pkgs.ddcutil pkgs.coreutils pkgs.util-linux]; - text = builtins.readFile ./scripts/ddc-backlight.sh; - }; -in { - home.packages = [ddc-backlight pkgs.ddcutil]; -} diff --git a/home/ddc-backlight/scripts/ddc-backlight.sh b/home/ddc-backlight/scripts/ddc-backlight.sh deleted file mode 100644 index 5921aa3a..00000000 --- a/home/ddc-backlight/scripts/ddc-backlight.sh +++ /dev/null @@ -1,49 +0,0 @@ -# Usage: ./ddc_backlight.sh -BUS="$1" - -LOCK_FILE="/tmp/ddc_backlight.lock" - -# Deterministic delay based on bus number to stagger execution -# Each bus will delay a different amount (0-59 seconds) -DELAY=$((BUS * 7 % 60)) -sleep "$DELAY" - -# Prevent parallel execution, which can crash the kernel  -if ! flock --nonblock 9; then - # Return a temporary placeholder instead of waiting - echo "{\"percentage\":0}" - exit 0 -fi 9>"$LOCK_FILE" - -# Check if monitor is connected and turned on - with better error handling -# 1. Attempt to read the power state of the monitor using VCP code 0xD6 (Power Mode) -{ - timeout 2 ddcutil getvcp D6 -b "$BUS" >/dev/null - power_status=$? -} || { - power_status=1 -} - -if [ $power_status -ne 0 ]; then - # Failed to read power state -> no monitor or unresponsive - echo "{\"percentage\":0}" - exit 0 -fi - -# Otherwise, we can safely get brightness value without overloading the kernel... -{ - output=$(timeout 2 ddcutil getvcp 10 -b "$BUS" 2>&1) - status=$? -} || { - status=1 -} - -if [ $status -ne 0 ]; then - echo "{\"percentage\":0}" - exit 0 -fi - -# Extract percentage -percent=$(echo "$output" | awk -F'=' '/current value/ {gsub(/,.*$/, "", $2); print $2+0}') - -echo "{\"percentage\":${percent}}" diff --git a/home/default.nix b/home/default.nix deleted file mode 100644 index 6666cf02..00000000 --- a/home/default.nix +++ /dev/null @@ -1,266 +0,0 @@ -{ - config, - inputs, - isImpermanent, - isNvidia, - lib, - osConfig, - pkgs, - secrets, - ... -}: let - impermanenceImports = lib.optionals isImpermanent [ - ./impermanence - ]; - - imports = - [ - inputs.sops-nix.homeManagerModules.sops - ./aichat - ./aider - ./alacritty - ./aliases - ./ansible - ./asciinema - ./aws - ./bash - ./bitwarden - ./bluetuith # Bluetooth TUI - ./brave-browser - ./broot - ./btop - ./calibre # Ebook reader - ./claude-code - ./cliphist - ./codex # OpenAI Codex - ./cpu-profile-toggler - ./devenv # devenv.sh - ./direnv - ./discord - ./dunst - ./easyeffects # GUI for Pipewire effects - ./email - ./firefox - ./fish - ./fix-flexbox-mike # Fix ALSA not detecting microphone on XPS 9700 - ./fuzzel - ./fzf - ./galaxy-buds-client - ./gimp - ./git - ./git-worktree-switcher # Provides wt - ./gnome-connections # RDP/VNC Client for Wayland - ./gtk-qt - ./hoppscotch # OSS Postman - ./hwatch # Modern watch alternative - ./isd # Interactive Systemd TUI in Python - ./jqp # TUI Playground for interacting with jq - ./jujutsu - ./k9s - ./kanshi # Wayland autorandr - ./kind-with-local-registry - ./kubernetes-tools - ./less - ./lf - ./libation # Audible liberator - ./libreoffice - ./lnav # Log File Navigator - ./mic-levels-maintainer - ./mpv # Media Player - ./mullvad-browser - ./nautilus # Gnome File Manager - ./neovim - ./networkmanager-dmenu - ./nh # https://github.com/nix-community/nh - ./niri - ./nix-index - ./nix-inspect # TUI for inspecting final NixOS config (and other nix exprs) - ./nushell - ./obs # OBS Studio - ./obsidian - ./onboard # Virtual Keyboard for layout visualization (no good Wayland options work) - ./pavucontrol # Pulse Audio Volume Control GUI - ./pgcli # Actually usable PostgreSQL CLI - ./pomodoro-gtk - ./portfolio-performance - ./psql # Postgresql Client with nicer config - ./pulsemixer # TUI (curses) mixer for pulseaudio, still useful under pipewire - ./qalculate # Calculator - ./ripgrep - ./ripgrep-all # Like rg, but also search in Office documents, PDFs etc...; rga-fzf is AMAZING! - ./rofimoji - ./showmethekey # screenkey for Wayland, show key presses - ./satty # Screenshot Annotation tool written in Rust - ./signal - ./solaar # Linux devices manager for the Logitech Unifying Receiver - ./sound-switcher - ./ssh - ./starship - ./stylix - ./syncthing - ./systemd-errors-and-warnings-counter - ./tealdeer - ./telegram - ./television # Fuzzy-finder in Rust with nixpkgs integration - ./tomat - ./trash-cli - ./tray-tui # TUI for tray icons - ./udiskie - ./urxvt - ./variety # Wallpaper Switcher/Randomizer with Quotes - ./virtual-cable # Virtual inputs/outputs via Pipewire (for OBS and beyond) - ./vlc - ./waybar - ./witr # Why is this running? - ./wlsunset # Day/night gamma adjustments for Wayland - ./wluma # Automatic screen brightness adjustment - ./xdg - ./ytmdesktop # Youtube Music Desktop (unofficial) - ./yubico # Yubikeys - ./zen - ./zoom - ./zoxide - ] - ++ impermanenceImports - ++ numenorImports - ++ [homeManagerSecrets]; - - isFlexbox = osConfig.networking.hostName == "flexbox"; - isNumenor = osConfig.networking.hostName == "numenor"; - - homeManagerSecrets = - if secrets ? homeManagerSecrets - then secrets.homeManagerSecrets {inherit isImpermanent lib pkgs;} - else {}; - - numenorImports = lib.optionals isNumenor [ - ./ddc-backlight - ]; -in { - home = { - # This value determines the Home Manager release that your - # configuration is compatible with. This helps avoid breakage - # when a new Home Manager release introduces backwards - # incompatible changes. - # - # You can update Home Manager without changing this value. See - # the Home Manager release notes for a list of state version - # changes in each release. - stateVersion = - if isFlexbox - then "22.05" - else if isNumenor - then "24.11" - else "24.11"; - - file."nixos-config" = { - source = config.lib.file.mkOutOfStoreSymlink "${config.home.homeDirectory}/code/nixos-config"; - target = "nixos-config"; - }; - - # Symlink flake for `home-manager news` CLI to find homeConfigurations - file.".config/home-manager/flake.nix" = { - source = config.lib.file.mkOutOfStoreSymlink "${config.home.homeDirectory}/code/nixos-config/flake.nix"; - }; - - packages = with pkgs; [ - alejandra # Nix Formatter - ast-grep # Pure Magic - bc # calculator - bind # Provides dig - dconf # Gnome configuration database - difftastic # structural diff difft, see https://github.com/Wilfred/difftastic - dive # Analyze docker images - dmidecode # Hardware info read from Bios - dnstracer - efivar # Tools and Libraries to manipulate EFI variables - fast-cli # Fast.com CLI `fast` - fastfetch # neofetch sucessor, system information tool - fd # Better find, written in Rust - ffmpeg-full - file # CLI program to show the type of a file - find-cursor - fortune - glow # Terminal markdown renderer - gomatrix # The Matrix - google-chrome - gucharmap # Unicode Character Map - hardinfo2 # Hardware/System Info - home-manager # CLI for managing home-manager, needed for `home-manager news` - httpie - iftop # Net top tool, see also nethogs - imagemagick - iotop-c - jq - kind # Kubernetes In Docker - kdePackages.kruler # Screen ruler - lazydocker # kind for vanilla Docker, kind of - libnotify # Provides notify-send - libsecret # `secret-tool` for interacting with gnome-keyring - lm_sensors # Tools for reading hardware sensors - lolcat # Pipe and See - lsof # Tool to list open file - ncdu # Disk Space Usage Visualization - nmap # Port Scanner - nethogs # Net top tool, see also iftop - net-tools # Things like arp, ifconfig, route, netstat etc... - neo-cowsay - nix-tree - oculante # img viewer written in Rust - kdePackages.okular # KDE document viewer - openssl - pdftk # PDF Manipulation Toolkit - pstree # Show the set of running processes as a tree - q-text-as-data # https://github.com/harelba/q - inputs.rmob.defaultPackage.x86_64-linux - screenkey # Screencast tool to display your keys inspired by Screenflick - smartmontools # Tools for monitoring the health of hard drives - s-tui # Processor monitor/stress test - stress # Simple workload generator for POSIX systems. It imposes a configurable amount of CPU, memory, I/O, and disk stress on the system - tcpdump - traceroute - tree - unzip - usbutils # Provides lsusb - wdisplays # arandr for wayland - external display/screen GUI - wf-recorder # Screen recorder for Wayland, useful for quick testing screen stuff - wget - wireguard-tools - whois - wl-clipboard - xournalpp # PDF Annotations, useful for saving Okular annotations as well - yq # Command-line YAML/XML/TOML processor - jq wrapper for YAML, XML, TOML documents - yt-dlp - zip - ]; - - sessionVariables = - { - PATH = "$HOME/bin:$PATH"; - NIXOS_CONFIG = "$HOME/code/nixos-config/"; - GC_INITIAL_HEAP_SIZE = "8G"; # Slightly improve nix eval times - DIRENV_LOG_FORMAT = ""; # Disable verbose direnv output showing env variables changed - NIXOS_OZONE_WL = "1"; # Enable Ozone-Wayland for Electron apps and Chromium - } - // lib.optionalAttrs isNvidia { - LIBVA_DRIVER_NAME = "nvidia"; - }; - }; - - inherit imports; - - programs = { - bat = { - enable = true; - }; - - man = { - enable = true; - generateCaches = false; # Speed up builds - }; - - vscode = { - enable = true; - }; - }; -} diff --git a/home/devenv/default.nix b/home/devenv/default.nix deleted file mode 100644 index 35ffadf6..00000000 --- a/home/devenv/default.nix +++ /dev/null @@ -1,16 +0,0 @@ -{ - lib, - isImpermanent, - pkgs, - ... -}: { - home.persistence."/persist" = lib.mkIf isImpermanent { - directories = [ - ".local/share/devenv" - ]; - }; - - home.packages = [ - pkgs.devenv - ]; -} diff --git a/home/direnv/default.nix b/home/direnv/default.nix deleted file mode 100644 index 371164b3..00000000 --- a/home/direnv/default.nix +++ /dev/null @@ -1,17 +0,0 @@ -{ - lib, - isImpermanent, - ... -}: { - home.persistence."/persist" = lib.mkIf isImpermanent { - directories = [ - ".local/share/direnv" - ]; - }; - - programs.direnv = { - enable = true; - nix-direnv.enable = true; - config.strict_env = true; # Forces all .envrc scripts through set -euo pipefail - }; -} diff --git a/home/discord/default.nix b/home/discord/default.nix deleted file mode 100644 index 1148af25..00000000 --- a/home/discord/default.nix +++ /dev/null @@ -1,15 +0,0 @@ -{ - lib, - isImpermanent, - ... -}: { - home.persistence."/persist" = lib.mkIf isImpermanent { - directories = [ - ".config/discord" - ]; - }; - - programs.discord = { - enable = true; - }; -} diff --git a/home/dunst/default.nix b/home/dunst/default.nix deleted file mode 100644 index 38d89aee..00000000 --- a/home/dunst/default.nix +++ /dev/null @@ -1,18 +0,0 @@ -{pkgs, ...}: { - services.dunst = { - enable = true; - - iconTheme = { - name = "Papirus-Dark"; - package = pkgs.papirus-icon-theme; - }; - - settings = { - global = { - browser = "brave"; - dmenu = "fuzzel --dmenu"; - follow = "mouse"; - }; - }; - }; -} diff --git a/home/easyeffects/default.nix b/home/easyeffects/default.nix deleted file mode 100644 index 727370fa..00000000 --- a/home/easyeffects/default.nix +++ /dev/null @@ -1,24 +0,0 @@ -# GUI for PipeWire effects -{ - isImpermanent, - lib, - ... -}: { - home.persistence."/persist" = lib.mkIf isImpermanent { - directories = [ - ".config/easyeffects" - ]; - }; - - # Preset from https://github.com/JackHack96/EasyEffects-Presets/blob/master/Bass%20Enhancing%20%2B%20Perfect%20EQ.json - # IRS file from the same repo above - home.file.".config/easyeffects/irs/Razor Surround ((48k Z-Edition)) 2.Stereo +20 bass.irs".source = ./presets/irs/razor-surround-48k-z-edition-stereo-plus20-bass.irs; - - services.easyeffects = { - enable = true; - preset = "bass-enhancing-perfect-eq"; - extraPresets = { - "bass-enhancing-perfect-eq" = builtins.fromJSON (builtins.readFile ./presets/output/bass-enhancing-perfect-eq.json); - }; - }; -} diff --git a/home/easyeffects/presets/irs/razor-surround-48k-z-edition-stereo-plus20-bass.irs b/home/easyeffects/presets/irs/razor-surround-48k-z-edition-stereo-plus20-bass.irs deleted file mode 100644 index a70dcb3645465cf60ada5d5942c6451ccad4bc17..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 71372 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 yKy+3OFGkZi9%4B!v6=CiBVzz diff --git a/home/easyeffects/presets/output/bass-enhancing-perfect-eq.json b/home/easyeffects/presets/output/bass-enhancing-perfect-eq.json deleted file mode 100644 index 2530984e..00000000 --- a/home/easyeffects/presets/output/bass-enhancing-perfect-eq.json +++ /dev/null @@ -1,226 +0,0 @@ -{ - "output": { - "blocklist": [], - "convolver": { - "input-gain": -2.0, - "ir-width": 100, - "kernel-name": "Razor Surround ((48k Z-Edition)) 2.Stereo +20 bass", - "output-gain": 0.0 - }, - "equalizer": { - "input-gain": -2.0, - "left": { - "band0": { - "frequency": 32.0, - "gain": 4.0, - "mode": "RLC (BT)", - "mute": false, - "q": 1.504760237537245, - "slope": "x1", - "solo": false, - "type": "Bell" - }, - "band1": { - "frequency": 64.0, - "gain": 2.0, - "mode": "RLC (BT)", - "mute": false, - "q": 1.5047602375372453, - "slope": "x1", - "solo": false, - "type": "Bell" - }, - "band2": { - "frequency": 125.0, - "gain": 1.0, - "mode": "RLC (BT)", - "mute": false, - "q": 1.504760237537245, - "slope": "x1", - "solo": false, - "type": "Bell" - }, - "band3": { - "frequency": 250.0, - "gain": 0.0, - "mode": "RLC (BT)", - "mute": false, - "q": 1.504760237537245, - "slope": "x1", - "solo": false, - "type": "Bell" - }, - "band4": { - "frequency": 500.0, - "gain": -1.0, - "mode": "RLC (BT)", - "mute": false, - "q": 1.5047602375372453, - "slope": "x1", - "solo": false, - "type": "Bell" - }, - "band5": { - "frequency": 1000.0, - "gain": -2.0, - "mode": "RLC (BT)", - "mute": false, - "q": 1.504760237537245, - "slope": "x1", - "solo": false, - "type": "Bell" - }, - "band6": { - "frequency": 2000.0, - "gain": 0.0, - "mode": "RLC (BT)", - "mute": false, - "q": 1.5047602375372449, - "slope": "x1", - "solo": false, - "type": "Bell" - }, - "band7": { - "frequency": 4000.0, - "gain": 2.0, - "mode": "RLC (BT)", - "mute": false, - "q": 1.5047602375372449, - "slope": "x1", - "solo": false, - "type": "Bell" - }, - "band8": { - "frequency": 8000.0, - "gain": 3.0, - "mode": "RLC (BT)", - "mute": false, - "q": 1.5047602375372453, - "slope": "x1", - "solo": false, - "type": "Bell" - }, - "band9": { - "frequency": 16000.0, - "gain": 3.0, - "mode": "RLC (BT)", - "mute": false, - "q": 1.504760237537245, - "slope": "x1", - "solo": false, - "type": "Bell" - } - }, - "mode": "IIR", - "num-bands": 10, - "output-gain": 0.0, - "right": { - "band0": { - "frequency": 32.0, - "gain": 4.0, - "mode": "RLC (BT)", - "mute": false, - "q": 1.504760237537245, - "slope": "x1", - "solo": false, - "type": "Bell" - }, - "band1": { - "frequency": 64.0, - "gain": 2.0, - "mode": "RLC (BT)", - "mute": false, - "q": 1.5047602375372453, - "slope": "x1", - "solo": false, - "type": "Bell" - }, - "band2": { - "frequency": 125.0, - "gain": 1.0, - "mode": "RLC (BT)", - "mute": false, - "q": 1.504760237537245, - "slope": "x1", - "solo": false, - "type": "Bell" - }, - "band3": { - "frequency": 250.0, - "gain": 0.0, - "mode": "RLC (BT)", - "mute": false, - "q": 1.504760237537245, - "slope": "x1", - "solo": false, - "type": "Bell" - }, - "band4": { - "frequency": 500.0, - "gain": -1.0, - "mode": "RLC (BT)", - "mute": false, - "q": 1.5047602375372453, - "slope": "x1", - "solo": false, - "type": "Bell" - }, - "band5": { - "frequency": 1000.0, - "gain": -2.0, - "mode": "RLC (BT)", - "mute": false, - "q": 1.504760237537245, - "slope": "x1", - "solo": false, - "type": "Bell" - }, - "band6": { - "frequency": 2000.0, - "gain": 0.0, - "mode": "RLC (BT)", - "mute": false, - "q": 1.5047602375372449, - "slope": "x1", - "solo": false, - "type": "Bell" - }, - "band7": { - "frequency": 4000.0, - "gain": 2.0, - "mode": "RLC (BT)", - "mute": false, - "q": 1.5047602375372449, - "slope": "x1", - "solo": false, - "type": "Bell" - }, - "band8": { - "frequency": 8000.0, - "gain": 3.0, - "mode": "RLC (BT)", - "mute": false, - "q": 1.5047602375372453, - "slope": "x1", - "solo": false, - "type": "Bell" - }, - "band9": { - "frequency": 16000.0, - "gain": 3.0, - "mode": "RLC (BT)", - "mute": false, - "q": 1.504760237537245, - "slope": "x1", - "solo": false, - "type": "Bell" - } - }, - "split-channels": false - }, - "plugins_order": [ - "equalizer", - "convolver" - ] - } -} diff --git a/home/email/default.nix b/home/email/default.nix deleted file mode 100644 index f360452f..00000000 --- a/home/email/default.nix +++ /dev/null @@ -1,26 +0,0 @@ -{ - isImpermanent, - lib, - ... -}: { - home.persistence."/persist" = lib.mkIf isImpermanent { - directories = [ - ".thunderbird" - ".cache/thunderbird" - ]; - }; - - programs.thunderbird = { - enable = true; - profiles = { - "main" = { - isDefault = true; - settings = { - "calendar.alarms.showmissed" = false; - "calendar.alarms.playsound" = false; - "calendar.alarms.show" = false; - }; - }; - }; - }; -} diff --git a/home/firefox/default.nix b/home/firefox/default.nix deleted file mode 100644 index 8d835a67..00000000 --- a/home/firefox/default.nix +++ /dev/null @@ -1,26 +0,0 @@ -{ - isImpermanent, - lib, - pkgs, - ... -}: { - home.persistence."/persist" = lib.mkIf isImpermanent { - directories = [ - ".mozilla/firefox" - ".cache/mozilla/firefox" - ]; - }; - - programs.firefox = { - enable = true; - profiles = { - main = { - extensions.packages = with pkgs.nur.repos.rycee.firefox-addons; [ - bitwarden - ]; - id = 0; - isDefault = true; - }; - }; - }; -} diff --git a/home/fish/default.nix b/home/fish/default.nix deleted file mode 100644 index 26b7e2db..00000000 --- a/home/fish/default.nix +++ /dev/null @@ -1,143 +0,0 @@ -{ - config, - isImpermanent, - lib, - pkgs, - ... -}: let - functions = { - fish_user_key_bindings = - /* - fish - */ - '' - fish_vi_key_bindings - - # VI mode updates - bind -s --preset --mode default j backward-char - bind -s --preset --mode default \; forward-char - bind -s --preset k down-or-search - bind -s --preset l up-or-search - bind -s --preset --mode visual j backward-char - bind -s --preset --mode visual \; forward-char - bind -s --preset --mode visual l up-line - bind -s --preset --mode visual k down-line - - # Completions - bind -s --mode insert \cw forward-word - # Tab --> accept autosuggestions - bind -s --mode insert \t accept-autosuggestion - # CTRL-S --> original TAB behaviour - bind -s --mode insert \cs complete - - # Bang-Bang bindings, manually added so they have precedence: - bind --mode insert ! __history_previous_command - bind --mode insert '$' __history_previous_command_arguments - ''; - - ## Wrap LF to add ability to quit with Q in current directory - ## - ## Adapted for fish from https://github.com/gokcehan/lf/wiki/Tips#cd-to-current-directory-on-quit - ## - lf = - /* - fish - */ - '' - set -x LF_CD_FILE /var/tmp/.lfcd-$fish_pid - command lf $argv - if test -s "$LF_CD_FILE" - set DIR (realpath (cat "$LF_CD_FILE")) - if test "$DIR" != "$PWD" - cd "$DIR" - end - rm "$LF_CD_FILE" - end - set -e LF_CD_FILE - ''; - - pirate = - /* - fish - */ - '' - set toTranslate $argv - curl -sG \ - --data-urlencode "english=$toTranslate" \ - 'http://pirate.monkeyness.com/cgi-bin/translator.pl?client=monkeyness&version=1.0' -H 'Accept: application/json' -H 'Connection: keep-alive' -H 'Accept-Encoding: gzip, deflate' -H 'Referer: http://pirate.monkeyness.com/online_pirate_translator' -H 'Accept-Language: en-US,en;q=0.9' -H 'User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.87 Safari/537.36' --compressed --insecure \ - | xq -r .pirateAPI.pirate \ - | curl -sG \ - --data-urlencode "source_text=$toTranslate" \ - 'https://speakpirate.com/' -H 'authority: speakpirate.com' -H 'cache-control: max-age=0' -H 'origin: https://speakpirate.com' -H 'upgrade-insecure-requests: 1' -H 'content-type: application/x-www-form-urlencoded' -H 'user-agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.87 Safari/537.36' -H 'sec-fetch-mode: navigate' -H 'sec-fetch-user: ?1' -H 'accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3' -H 'sec-fetch-site: same-origin' -H 'referer: https://speakpirate.com/' -H 'accept-encoding: gzip, deflate, br' -H 'accept-language: en-US,en;q=0.9' -H 'cookie: __utma=133499724.1448464120.1565964854.1565964854.1565964854.1; __utmc=133499724; __utmz=133499724.1565964854.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none); __utmt=1; __utmb=133499724.1.10.1565964854' --compressed \ - | pup 'textarea#translated json{}' | jq -r '.[0].text' - ''; - - # Source .env files - # Source: http://lewandowski.io/2016/10/fish-env/ - posix-source = - /* - fish - */ - '' - for i in (cat $argv) - set arr (echo $i | string match -r "([^=]+)=(.*)") - set -gx $arr[2] $arr[3] - end - ''; - - kubectlgetall = - /* - fish - */ - '' - for i in (kubectl api-resources --verbs=list --namespaced -o name | grep -v "events.events.k8s.io" | grep -v "events" | sort | uniq) - echo "Resource:" $i - kubectl -n "$argv[1]" get --ignore-not-found "$i" - end - ''; - }; - - plugins = with pkgs.fishPlugins; [ - { - name = "bang-bang"; - src = bang-bang.src; - } - ]; - - shellInit = '' - ${variables} - ''; - - variables = - /* - fish - */ - '' - set -g fish_key_bindings fish_default_key_bindings - set fish_greeting # disable greeting - ''; -in { - home.persistence."/persist" = lib.mkIf isImpermanent { - directories = [ - ".config/fish" - ".local/share/fish" # contains some unecessary state, but https://github.com/fish-shell/fish-shell/issues/10730 prevents us from only syncing the history file (.local/share/fish/fish_history) - ]; - }; - - programs.fish = { - enable = true; - interactiveShellInit = shellInit; - inherit functions plugins; - shellAbbrs = - config.home.shellAliases - // { - # Fish/bash-specific aliases that aren't compatible with nushell - # Use bashInteractive to ensure bind command is available - bash = "${config.programs.bash.package}/bin/bash"; - cc = "tee /dev/tty | wl-copy"; - dark-theme = "nh os test --no-specialisation && niri-set-wallpaper"; - light-theme = "nh os test --specialisation light && niri-set-wallpaper"; - pa = "pw-play ~/Music/Own\\ Speech/IckbinArschratte.WAV"; - }; - }; -} diff --git a/home/fix-flexbox-mike/default.nix b/home/fix-flexbox-mike/default.nix deleted file mode 100644 index e63b2269..00000000 --- a/home/fix-flexbox-mike/default.nix +++ /dev/null @@ -1,27 +0,0 @@ -# Fix ALSA not detecting microphone on XPS 9700, see https://github.com/NixOS/nixpkgs/issues/130882#issuecomment-2584286824 -{ - lib, - osConfig, - pkgs, - ... -}: let - isFlexbox = osConfig.networking.hostName == "flexbox"; - xps-9700-mic-fixer = pkgs.writeShellApplication { - name = "xps-9700-mic-fixer"; - runtimeInputs = [pkgs.alsa-utils]; - text = builtins.readFile ./scripts/xps-9700-mic-fixer.sh; - }; -in { - systemd.user.services.fixXPS9700Mike = lib.mkIf isFlexbox { - Unit = { - Description = "Fix ALSA settings for internal mic on Dell XPS 9700"; - }; - Install.WantedBy = ["pipewire.service"]; - Service = { - Environment = "PATH=$PATH:/run/current-system/sw/bin"; - ExecStart = "${xps-9700-mic-fixer}/bin/xps-9700-mic-fixer"; - Type = "oneshot"; - RemainAfterExit = true; - }; - }; -} diff --git a/home/fix-flexbox-mike/scripts/xps-9700-mic-fixer.sh b/home/fix-flexbox-mike/scripts/xps-9700-mic-fixer.sh deleted file mode 100644 index 18972df9..00000000 --- a/home/fix-flexbox-mike/scripts/xps-9700-mic-fixer.sh +++ /dev/null @@ -1,3 +0,0 @@ -amixer --card 1 set "rt715 ADC 24 Mux" "DMIC3" -amixer --card 1 set "rt715 DMIC3 Boost" 3 -amixer --card 1 set "PGA2.0 2 Master" 80 unmute diff --git a/home/fuzzel/default.nix b/home/fuzzel/default.nix deleted file mode 100644 index a8cf1f48..00000000 --- a/home/fuzzel/default.nix +++ /dev/null @@ -1,6 +0,0 @@ -{pkgs, ...}: { - programs.fuzzel = { - enable = true; - package = pkgs.unstable.fuzzel; - }; -} diff --git a/home/fzf/default.nix b/home/fzf/default.nix deleted file mode 100644 index d2d958dd..00000000 --- a/home/fzf/default.nix +++ /dev/null @@ -1,6 +0,0 @@ -{...}: { - programs.fzf = { - enable = true; - defaultCommand = "rg --files --no-ignore-vcs --hidden"; - }; -} diff --git a/home/galaxy-buds-client/default.nix b/home/galaxy-buds-client/default.nix deleted file mode 100644 index 9398e512..00000000 --- a/home/galaxy-buds-client/default.nix +++ /dev/null @@ -1,16 +0,0 @@ -{ - lib, - isImpermanent, - pkgs, - ... -}: { - home.persistence."/persist" = lib.mkIf isImpermanent { - directories = [ - ".local/share/GalaxyBudsClient" - ]; - }; - - home.packages = [ - pkgs.galaxy-buds-client - ]; -} diff --git a/home/gimp/default.nix b/home/gimp/default.nix deleted file mode 100644 index e20d984f..00000000 --- a/home/gimp/default.nix +++ /dev/null @@ -1,17 +0,0 @@ -{ - lib, - isImpermanent, - pkgs, - ... -}: { - home.persistence."/persist" = lib.mkIf isImpermanent { - directories = [ - ".config/GIMP" - ".cache/gimp" - ]; - }; - - home.packages = [ - pkgs.gimp - ]; -} diff --git a/home/git-worktree-switcher/default.nix b/home/git-worktree-switcher/default.nix deleted file mode 100644 index 113bfb48..00000000 --- a/home/git-worktree-switcher/default.nix +++ /dev/null @@ -1,5 +0,0 @@ -{...}: { - programs.git-worktree-switcher = { - enable = true; - }; -} diff --git a/home/git/default.nix b/home/git/default.nix deleted file mode 100644 index f9decb0c..00000000 --- a/home/git/default.nix +++ /dev/null @@ -1,104 +0,0 @@ -{ - lib, - isImpermanent, - pkgs, - ... -}: { - home.persistence."/persist" = lib.mkIf isImpermanent { - directories = [ - ".config/glab-cli" - ]; - }; - - home.packages = with pkgs; [ - delta # Syntax highlighter for git - github-cli - glab - ]; - - home.file.".config/gh/config.yml".source = ./github-cli/gh.config.yml; - - programs.difftastic = { - enable = true; - git.enable = true; - }; - - programs.git = { - enable = true; - - includes = [ - { - path = "~/code/dlh/.gitconfig"; - condition = "gitdir:~/code/dlh/"; - } - { - path = "~/code/dlh/plansee/.gitconfig"; - condition = "gitdir:~/code/dlh/plansee/"; - } - ]; - - signing = { - signByDefault = true; - key = "24575DB93F6CEC16"; - }; - - settings = { - alias = { - c = "commit"; - - # Difftastic - dlog = "-c diff.external=difft log --ext-diff"; - dshow = "-c diff.external=difft show --ext-diff"; - ddiff = "-c diff.external=difft diff"; - # `git log` with patches shown with difftastic. - dl = "-c diff.external=difft log -p --ext-diff"; - # Show the most recent commit with difftastic. - ds = "-c diff.external=difft show --ext-diff"; - # `git diff` with difftastic. - dft = "-c diff.external=difft diff"; - - p = "push"; - rim = "rebase -i main"; - rimm = "rebase -i master"; - }; - - core = { - pager = "delta"; - }; - diff = { - colorMoved = "default"; - }; - init = { - defaultBranch = "main"; - }; - interactive = { - diffFilter = "delta --color-only"; - }; - merge = { - conflictstyle = "diff3"; - }; - pull = { - ff = "only"; - rebase = true; - }; - rebase = { - autoStash = true; - autoSquash = true; - }; - # https://github.com/NixOS/nixpkgs/blob/master/doc/languages-frameworks/javascript.section.md#git-protocol-error - url = { - "https://github.com" = { - insteadOf = "git://github.com"; - }; - }; - user.email = "4farlion@gmail.com"; - user.name = "workflow"; - }; - - ignores = [".idea" "nohup.out" "mzdata" ".vimspector.json"]; - }; - - programs.mergiraf = { - enable = true; - }; -} diff --git a/home/git/github-cli/gh.config.yml b/home/git/github-cli/gh.config.yml deleted file mode 100644 index ea32c1ac..00000000 --- a/home/git/github-cli/gh.config.yml +++ /dev/null @@ -1,12 +0,0 @@ -# What protocol to use when performing git operations. Supported values: ssh, https -git_protocol: ssh -# What editor gh should run when creating issues, pull requests, etc. If blank, will refer to environment. -editor: -# When to interactively prompt. This is a global config that cannot be overridden by hostname. Supported values: enabled, disabled -prompt: enabled -# A pager program to send command output to, e.g. "less". Set the value to "cat" to disable the pager. -pager: -# Aliases allow you to create nicknames for gh commands -aliases: - co: pr checkout -version: 1 diff --git a/home/gnome-connections/default.nix b/home/gnome-connections/default.nix deleted file mode 100644 index 8ee79471..00000000 --- a/home/gnome-connections/default.nix +++ /dev/null @@ -1,20 +0,0 @@ -{ - lib, - isImpermanent, - pkgs, - ... -}: { - home.persistence."/persist" = lib.mkIf isImpermanent { - directories = [ - ".config/freerdp" # RDP server certificates/keys - ".config/dconf" # GNOME settings database (GSettings/dconf) - ]; - files = [ - ".config/connections.db" # GNOME Connections connection profiles database - ]; - }; - - home.packages = [ - pkgs.gnome-connections - ]; -} diff --git a/home/gtk-qt/default.nix b/home/gtk-qt/default.nix deleted file mode 100644 index f8fe7a0c..00000000 --- a/home/gtk-qt/default.nix +++ /dev/null @@ -1,39 +0,0 @@ -{ - isImpermanent, - lib, - pkgs, - ... -}: { - home.persistence."/persist" = lib.mkIf isImpermanent { - files = [ - ".config/QtProject.conf" # Stuff like history and lastVisited - ]; - }; - - gtk = { - enable = true; - gtk3 = { - extraConfig = { - gtk-application-prefer-dark-theme = true; - }; - }; - }; - - qt = { - enable = true; - platformTheme.name = "qtct"; - style.name = "kvantum"; - }; - - home.packages = with pkgs; [ - lxappearance # GTK Theme testing + tweaking - libsForQt5.qt5ct # Qt 5 Theme testing + tweaking - qt6Packages.qt6ct # Qt 6 Theme testing + tweaking - ]; - - # https://wiki.archlinux.org/title/HiDPI - home.sessionVariables = { - QT_AUTO_SCREEN_SCALE_FACTOR = "1"; - QT_ENABLE_HIGHDPI_SCALING = "1"; - }; -} diff --git a/home/gtk-qt/qtct.conf b/home/gtk-qt/qtct.conf deleted file mode 100644 index 1db523c7..00000000 --- a/home/gtk-qt/qtct.conf +++ /dev/null @@ -1,8 +0,0 @@ -[Appearance] -icon_theme=Pop -standard_dialogs=gtk3 -style=kvantum-dark - -[Fonts] -fixed="FiraCode Nerd Font Mono,9,-1,5,25,0,0,0,0,0" -general="Fira Code,9,-1,5,50,0,0,0,0,0" diff --git a/home/hoppscotch/default.nix b/home/hoppscotch/default.nix deleted file mode 100644 index 5cf1ed96..00000000 --- a/home/hoppscotch/default.nix +++ /dev/null @@ -1,23 +0,0 @@ -{pkgs, ...}: let - # Wrap Hoppscotch with Wayland-friendly flags - hoppscotch-wrapped = pkgs.symlinkJoin { - name = "hoppscotch-wrapped"; - paths = [pkgs.unstable.hoppscotch]; - buildInputs = [pkgs.makeWrapper]; - postBuild = '' - wrapProgram $out/bin/hoppscotch \ - --set NIXOS_OZONE_WL 1 \ - --add-flags "--use-gl=desktop" \ - --add-flags "--disable-gpu-sandbox" - ''; - }; -in { - home.persistence."/persist".directories = [ - ".local/share/io.hoppscotch.desktop" # Auth tokens, collections, requests, workspaces - ".config/io.hoppscotch.desktop" # App settings, bundles, window state - ]; - - home.packages = [ - hoppscotch-wrapped - ]; -} diff --git a/home/hwatch/default.nix b/home/hwatch/default.nix deleted file mode 100644 index 6b54f257..00000000 --- a/home/hwatch/default.nix +++ /dev/null @@ -1,5 +0,0 @@ -{pkgs, ...}: { - home.packages = with pkgs; [ - hwatch - ]; -} diff --git a/home/impermanence/default.nix b/home/impermanence/default.nix deleted file mode 100644 index 035fb4f1..00000000 --- a/home/impermanence/default.nix +++ /dev/null @@ -1,15 +0,0 @@ -# General home-manager impermanence setup -# Note: specifics should live with their respective modules, where possible! -{ - home.persistence."/persist" = { - enable = true; - directories = [ - ".cache/nix" - ".config/helm" # Helm repositories - ".config/nix" # cachix repositories and such - ".local/share/home-manager" # home-manager news read state - ".local/share/nix" # Nix Repl History - ".local/state/home-manager" # home-manager generations and GC roots - ]; - }; -} diff --git a/home/isd/default.nix b/home/isd/default.nix deleted file mode 100644 index 7400cead..00000000 --- a/home/isd/default.nix +++ /dev/null @@ -1,18 +0,0 @@ -{ - lib, - isImpermanent, - pkgs, - ... -}: { - home.persistence."/persist" = lib.mkIf isImpermanent { - directories = [ - ".config/isd_tui" - ".local/share/isd_tui" - ".cache/isd_tui" - ]; - }; - - home.packages = [ - pkgs.isd - ]; -} diff --git a/home/jqp/default.nix b/home/jqp/default.nix deleted file mode 100644 index 4b368f58..00000000 --- a/home/jqp/default.nix +++ /dev/null @@ -1,5 +0,0 @@ -{...}: { - programs.jqp = { - enable = true; - }; -} diff --git a/home/jujutsu/default.nix b/home/jujutsu/default.nix deleted file mode 100644 index 9fc67c41..00000000 --- a/home/jujutsu/default.nix +++ /dev/null @@ -1,62 +0,0 @@ -{pkgs, ...}: { - programs.difftastic.enable = true; - programs.jjui = { - enable = true; - package = pkgs.unstable.jjui; - }; - programs.jujutsu = { - enable = true; - package = pkgs.unstable.jujutsu; - settings = { - remotes.origin.auto-track-bookmarks = "main"; - ui.diff-formatter = ["difft" "--color=always" "$left" "$right"]; - user = { - email = "4farlion@gmail.com"; - name = "workflow"; - }; - signing = { - backend = "gpg"; - key = "24575DB93F6CEC16"; - behavior = "own"; # sign commits you authored on modify - }; - aliases = { - bt = ["bookmark" "track"]; - c = ["commit"]; - init = ["git" "init" "--colocate"]; - push = [ - "util" - "exec" - "--" - "bash" - "-c" - '' - set -e - - # Check if current commit has both description and changes - has_description=$(jj log -r @ --no-graph --color never -T 'description' | grep -q . && echo "yes" || echo "no") - # Use 'empty' template keyword to check if commit has changes - has_changes=$(jj log -r @ --no-graph --color never -T 'empty' | grep -q "false" && echo "yes" || echo "no") - - if [ "$has_description" = "yes" ] && [ "$has_changes" = "yes" ]; then - echo "Current commit has description and changes, creating new commit..." - jj new - fi - - # Get the bookmark from the parent commit directly - bookmark=$(jj log -r 'ancestors(@) & bookmarks()' -n 1 --no-graph --color never -T 'bookmarks' | sed 's/\*$//' | tr -d ' ') - - if [ -z "$bookmark" ]; then - echo "No bookmark found on parent commit" - exit 1 - fi - - echo "Moving bookmark '$bookmark' to parent commit and pushing..." - jj bookmark set "$bookmark" -r @- - jj git fetch - jj git push --bookmark "$bookmark" --allow-new - '' - ]; - }; - }; - }; -} diff --git a/home/k9s/default.nix b/home/k9s/default.nix deleted file mode 100644 index f88592a5..00000000 --- a/home/k9s/default.nix +++ /dev/null @@ -1,24 +0,0 @@ -{ - pkgs, - lib, - ... -}: { - programs.k9s = { - enable = true; - package = pkgs.unstable.k9s; - - skins = { - gruvbox-dark = ./gruvbox-dark.yaml; - gruvbox-light = ./gruvbox-light.yaml; - }; - - settings = { - k9s = { - ui = { - # Default to gruvbox-dark, override in light specialisation - skin = lib.mkDefault "gruvbox-dark"; - }; - }; - }; - }; -} diff --git a/home/k9s/gruvbox-dark.yaml b/home/k9s/gruvbox-dark.yaml deleted file mode 100644 index 3724404b..00000000 --- a/home/k9s/gruvbox-dark.yaml +++ /dev/null @@ -1,102 +0,0 @@ -# K9s Gruvbox Dark Skin -# Author: [@indiebrain](https://github.com/indiebrain) - -foreground: &foreground "#ebdbb2" -background: &background "#272727" -current_line: ¤t_line "#ebdbb2" -selection: &selection "#3c3735" -comment: &comment "#bdad93" -cyan: &cyan "#689d69" -green: &green "#989719" -orange: &orange "#d79920" -magenta: &magenta "#b16185" -blue: &blue "#448488" -red: &red "#cc231c" - -k9s: - body: - fgColor: *foreground - bgColor: *background - logoColor: *blue - prompt: - fgColor: *foreground - bgColor: *background - suggestColor: *orange - info: - fgColor: *magenta - sectionColor: *foreground - help: - fgColor: *foreground - bgColor: *background - keyColor: *magenta - numKeyColor: *blue - sectionColor: *green - dialog: - fgColor: *foreground - bgColor: *background - buttonFgColor: *foreground - buttonBgColor: *magenta - buttonFocusFgColor: white - buttonFocusBgColor: *cyan - labelFgColor: *orange - fieldFgColor: *foreground - frame: - border: - fgColor: *selection - focusColor: *current_line - menu: - fgColor: *foreground - keyColor: *magenta - numKeyColor: *magenta - crumbs: - fgColor: *foreground - bgColor: *comment - activeColor: *blue - status: - newColor: *cyan - modifyColor: *blue - addColor: *green - errorColor: *red - highlightColor: *orange - killColor: *comment - completedColor: *comment - title: - fgColor: *foreground - bgColor: *background - highlightColor: *orange - counterColor: *blue - filterColor: *magenta - views: - charts: - bgColor: background - defaultDialColors: - - *blue - - *red - defaultChartColors: - - *blue - - *red - table: - fgColor: *foreground - bgColor: *background - cursorFgColor: "#fff" - cursorBgColor: *current_line - header: - fgColor: *foreground - bgColor: *background - sorterColor: *selection - xray: - fgColor: *foreground - bgColor: *background - cursorColor: *current_line - graphicColor: *blue - showIcons: false - yaml: - keyColor: *magenta - colonColor: *blue - valueColor: *foreground - logs: - fgColor: *foreground - bgColor: *background - indicator: - fgColor: *foreground - bgColor: *background diff --git a/home/k9s/gruvbox-light.yaml b/home/k9s/gruvbox-light.yaml deleted file mode 100644 index 554cf28a..00000000 --- a/home/k9s/gruvbox-light.yaml +++ /dev/null @@ -1,104 +0,0 @@ -# K9s Gruvbox Light Skin -# Author: [@indiebrain](https://github.com/indiebrain) - -foreground: &foreground "#3c3735" -background: &background "#fbf1c7" -current_line: ¤t_line "#ebdbb2" -selection: &selection "#3c3735" -comment: &comment "#bdad93" -cyan: &cyan "#689d69" -green: &green "#989719" -orange: &orange "#d79920" -magenta: &magenta "#b16185" -blue: &blue "#448488" -red: &red "#cc231c" - -k9s: - body: - fgColor: *foreground - bgColor: *background - logoColor: *blue - prompt: - fgColor: *foreground - bgColor: *background - suggestColor: *orange - info: - fgColor: *magenta - sectionColor: *foreground - help: - fgColor: *foreground - bgColor: *background - keyColor: *magenta - numKeyColor: *blue - sectionColor: *green - dialog: - fgColor: *foreground - bgColor: *background - buttonFgColor: *foreground - buttonBgColor: *magenta - buttonFocusFgColor: white - buttonFocusBgColor: *cyan - labelFgColor: *orange - fieldFgColor: *foreground - frame: - border: - fgColor: *selection - focusColor: *current_line - menu: - fgColor: *foreground - keyColor: *magenta - numKeyColor: *magenta - crumbs: - fgColor: *foreground - bgColor: *comment - activeColor: *blue - status: - newColor: *cyan - modifyColor: *blue - addColor: *green - errorColor: *red - highlightColor: *orange - killColor: *comment - completedColor: *comment - title: - fgColor: *foreground - bgColor: *background - highlightColor: *orange - counterColor: *blue - filterColor: *magenta - views: - charts: - bgColor: background - defaultDialColors: - - *blue - - *red - defaultChartColors: - - *blue - - *red - table: - fgColor: *foreground - bgColor: *background - cursorFgColor: *foreground - cursorBgColor: *current_line - header: - fgColor: *foreground - bgColor: *background - sorterColor: *selection - xray: - fgColor: *foreground - bgColor: *background - cursorColor: *current_line - graphicColor: *blue - showIcons: false - yaml: - keyColor: *magenta - colonColor: *blue - valueColor: *foreground - logs: - fgColor: *foreground - bgColor: *background - indicator: - fgColor: *foreground - bgColor: *background - toggleOnColor: *magenta - toggleOffColor: *blue diff --git a/home/kanshi/default.nix b/home/kanshi/default.nix deleted file mode 100644 index 188ecf69..00000000 --- a/home/kanshi/default.nix +++ /dev/null @@ -1,78 +0,0 @@ -{...}: { - services.kanshi = { - enable = true; - settings = [ - { - output = { - alias = "leftLG27"; - criteria = "HDMI-A-2"; - mode = "3840x2160@60.000Hz"; - position = "0,0"; - scale = 2.0; - transform = "90"; - }; - } - { - output = { - alias = "middleLG34"; - criteria = "DP-1"; - mode = "3840x2160@144.050Hz"; - position = "1080,208"; - scale = 1.5; - transform = "normal"; - }; - } - { - output = { - alias = "rightLG27"; - criteria = "HDMI-A-1"; - mode = "3840x2160@60.000Hz"; - position = "3640,0"; - scale = 2.0; - transform = "90"; - }; - } - { - profile = { - name = "numenor"; - outputs = [ - { - criteria = "$leftLG27"; - status = "enable"; - } - { - criteria = "$middleLG34"; - status = "enable"; - } - { - criteria = "$rightLG27"; - status = "enable"; - } - ]; - }; - } - { - profile = { - name = "numenor-movie"; - outputs = [ - { - criteria = "$leftLG27"; - status = "enable"; - position = "0,272"; - transform = "normal"; - } - { - criteria = "$middleLG34"; - status = "enable"; - position = "1920,132"; - } - { - criteria = "$rightLG27"; - status = "disable"; - } - ]; - }; - } - ]; - }; -} diff --git a/home/kind-with-local-registry/default.nix b/home/kind-with-local-registry/default.nix deleted file mode 100644 index b84555fd..00000000 --- a/home/kind-with-local-registry/default.nix +++ /dev/null @@ -1,10 +0,0 @@ -# Local registry for faster image iteration, i.e. with Skaffold -# To use local registry, prefix images with localhost:5001/ and make sure `docker push` is enabled -# See https://kind.sigs.k8s.io/docs/user/local-registry/ -{pkgs, ...}: let - kind-with-local-registry = pkgs.writers.writeBashBin "kind-with-local-registry" ( - builtins.readFile ./scripts/kind-with-local-registry.sh - ); -in { - home.packages = [kind-with-local-registry]; -} diff --git a/home/kind-with-local-registry/scripts/kind-with-local-registry.sh b/home/kind-with-local-registry/scripts/kind-with-local-registry.sh deleted file mode 100644 index 80927c9a..00000000 --- a/home/kind-with-local-registry/scripts/kind-with-local-registry.sh +++ /dev/null @@ -1,63 +0,0 @@ -set -o errexit - -# 1. Create registry container unless it already exists -reg_name='kind-registry' -reg_port='5001' -if [ "$(docker inspect -f '{{.State.Running}}' "${reg_name}" 2>/dev/null || true)" != 'true' ]; then - docker run \ - -d --restart=always -p "127.0.0.1:${reg_port}:5000" --network bridge --name "${reg_name}" --log-driver json-file \ - registry:2 -fi - -# 2. Create kind cluster with containerd registry config dir enabled -# TODO: kind will eventually enable this by default and this patch will -# be unnecessary. -# -# See: -# https://github.com/kubernetes-sigs/kind/issues/2875 -# https://github.com/containerd/containerd/blob/main/docs/cri/config.md#registry-configuration -# See: https://github.com/containerd/containerd/blob/main/docs/hosts.md -cat < "$ans" - if [ $? -eq 0 ]; then - echo "Pasted clipboard content to $ans" - else - echo "Failed to paste from clipboard" - fi - }} - ''; - - open = '' - ''${{ - case $(file --mime-type "$f" -bL) in - text/*|application/json) $EDITOR "$f";; - video/*|image/*/application/pdf) xdg-open "$f";; - *) xdg-open "$f";; - esac - }} - ''; - - quit-and-cd = '' - &{{ - pwd > $LF_CD_FILE - lf -remote "send $id quit" - }} - ''; - - sudomkfile = '' - ''${{ - printf "File Name: " - read ans - sudo $EDITOR $ANS - }} - ''; - - trash = '' - ''${{ - files=$(printf "$fx" | tr '\n' ';') - while [ "$files" ]; do - # extract the substring from start of string up to delimiter. - # this is the first "element" of the string. - file=''${files%%;*} - - trash-put "$(basename "$file")" - # if there's only one element left, set `files` to an empty string. - # this causes us to exit this `while` loop. - # else, we delete the first "element" of the string from files, and move onto the next. - if [ "$files" = "$file" ]; then - files=''' - else - files="''${files#*;}" - fi - done - }} - ''; - - unarchive = '' - ''${{ - case "$f" in - *.zip) unzip "$f";; - *.tar.gz) tar -xzvf "$f" ;; - *.tar.bz2) tar -xjvf "$f" ;; - *.tar) tar -xvf "$f" ;; - *) echo "Unsupported format" ;; - esac - }} - ''; - - yank-file = ''$printf '%s' "$f" | wl-copy''; - yank-paths = ''$printf '%s' "$fx" | wl-copy''; - yank-dirname = ''&printf '%s' "$PWD" | wl-copy''; - yank-basename = ''&basename -a -- $fx | head -c-1 | wl-copy''; - yank-basename-without-extension = ''&basename -a -- $fx | sed -E 's/\.[^.]+$//' | head -c-1 | wl-copy''; - - yank-image = '' - ''${{ - # Copy the first selected file's binary content to clipboard as PNG - # Many apps only accept PNG from clipboard on Wayland - file="$(echo "$fx" | head -n1)" - mime_type="$(file --mime-type -b "$file")" - - if [[ "$mime_type" == image/png ]]; then - # Already PNG, copy directly - wl-copy -t image/png < "$file" - else - # Convert to PNG first for compatibility - convert "$file" png:- | wl-copy -t image/png - fi - }} - ''; - - z = '' - %{{ - result="$(zoxide query --exclude $PWD $@ | sed 's/\\/\\\\/g;s/"/\\"/g')" - lf -remote "send $id cd \"$result\"" - }} - ''; - - zi = '' - ''${{ - result="$(zoxide query -i | sed 's/\\/\\\\/g;s/"/\\"/g')" - lf -remote "send $id cd \"$result\"" - }} - ''; - }; - - keybindings = { - "." = "set hidden!"; - d = null; - dd = "trash"; - dl = "dlfile"; - dr = "dragon"; - f = "zi"; - h = "chmod"; - k = "down"; - l = "up"; - ";" = "open"; - j = "updir"; - m = null; - md = "mkdir"; - mf = "mkfile"; - mr = "sudomkfile"; - mp = "paste-image"; - Q = "quit-and-cd"; - x = "cut"; - Y = "yank-image"; - }; - - previewer = { - keybinding = "i"; - source = "${pkgs.pistol}/bin/pistol"; - }; - - settings = { - icons = true; - # Set IFS to newline to allow commands to work with spaces in filenames - ifs = "\n"; - }; - }; - - home.sessionVariables = { - LF_ICONS = '' - tw=:\ - st=:\ - ow=:\ - dt=:\ - di=:\ - fi=:\ - ln=:\ - or=:\ - ex=:\ - *.c=:\ - *.cc=:\ - *.clj=:\ - *.coffee=:\ - *.cpp=:\ - *.css=:\ - *.d=:\ - *.dart=:\ - *.erl=:\ - *.exs=:\ - *.fs=:\ - *.go=:\ - *.h=:\ - *.hh=:\ - *.hpp=:\ - *.hs=:\ - *.html=:\ - *.java=:\ - *.jl=:\ - *.js=:\ - *.json=:\ - *.lua=:\ - *.md=:\ - *.php=:\ - *.pl=:\ - *.pro=:\ - *.py=:\ - *.rb=:\ - *.rs=:\ - *.scala=:\ - *.ts=:\ - *.vim=:\ - *.cmd=:\ - *.ps1=:\ - *.sh=:\ - *.bash=:\ - *.zsh=:\ - *.fish=:\ - *.tar=:\ - *.tgz=:\ - *.arc=:\ - *.arj=:\ - *.taz=:\ - *.lha=:\ - *.lz4=:\ - *.lzh=:\ - *.lzma=:\ - *.tlz=:\ - *.txz=:\ - *.tzo=:\ - *.t7z=:\ - *.zip=:\ - *.z=:\ - *.dz=:\ - *.gz=:\ - *.lrz=:\ - *.lz=:\ - *.lzo=:\ - *.xz=:\ - *.zst=:\ - *.tzst=:\ - *.bz2=:\ - *.bz=:\ - *.tbz=:\ - *.tbz2=:\ - *.tz=:\ - *.deb=:\ - *.rpm=:\ - *.jar=:\ - *.war=:\ - *.ear=:\ - *.sar=:\ - *.rar=:\ - *.alz=:\ - *.ace=:\ - *.zoo=:\ - *.cpio=:\ - *.7z=:\ - *.rz=:\ - *.cab=:\ - *.wim=:\ - *.swm=:\ - *.dwm=:\ - *.esd=:\ - *.jpg=:\ - *.jpeg=:\ - *.mjpg=:\ - *.mjpeg=:\ - *.gif=:\ - *.bmp=:\ - *.pbm=:\ - *.pgm=:\ - *.ppm=:\ - *.tga=:\ - *.xbm=:\ - *.xpm=:\ - *.tif=:\ - *.tiff=:\ - *.png=:\ - *.svg=:\ - *.svgz=:\ - *.mng=:\ - *.pcx=:\ - *.mov=:\ - *.mpg=:\ - *.mpeg=:\ - *.m2v=:\ - *.mkv=:\ - *.webm=:\ - *.ogm=:\ - *.mp4=:\ - *.m4v=:\ - *.mp4v=:\ - *.vob=:\ - *.qt=:\ - *.nuv=:\ - *.wmv=:\ - *.asf=:\ - *.rm=:\ - *.rmvb=:\ - *.flc=:\ - *.avi=:\ - *.fli=:\ - *.flv=:\ - *.gl=:\ - *.dl=:\ - *.xcf=:\ - *.xwd=:\ - *.yuv=:\ - *.cgm=:\ - *.emf=:\ - *.ogv=:\ - *.ogx=:\ - *.aac=:\ - *.au=:\ - *.flac=:\ - *.m4a=:\ - *.mid=:\ - *.midi=:\ - *.mka=:\ - *.mp3=:\ - *.mpc=:\ - *.ogg=:\ - *.ra=:\ - *.wav=:\ - *.oga=:\ - *.opus=:\ - *.spx=:\ - *.xspf=:\ - *.pdf=:\ - *.nix=: - ''; - }; -} diff --git a/home/lf/pistol/pistol.conf b/home/lf/pistol/pistol.conf deleted file mode 100644 index 9f63d568..00000000 --- a/home/lf/pistol/pistol.conf +++ /dev/null @@ -1 +0,0 @@ -image/* sh: chafa --fill=block --symbols=block -s 80x80 "%pistol-filename%" || exit 1 diff --git a/home/libation/default.nix b/home/libation/default.nix deleted file mode 100644 index 6f82571b..00000000 --- a/home/libation/default.nix +++ /dev/null @@ -1,17 +0,0 @@ -{ - lib, - isImpermanent, - pkgs, - ... -}: { - home.persistence."/persist" = lib.mkIf isImpermanent { - directories = [ - "Libation" - ".local/share/Libation" - ]; - }; - - home.packages = [ - pkgs.libation - ]; -} diff --git a/home/libreoffice/default.nix b/home/libreoffice/default.nix deleted file mode 100644 index 43006658..00000000 --- a/home/libreoffice/default.nix +++ /dev/null @@ -1,16 +0,0 @@ -{ - lib, - isImpermanent, - pkgs, - ... -}: { - home.persistence."/persist" = lib.mkIf isImpermanent { - directories = [ - ".config/libreoffice" - ]; - }; - - home.packages = [ - pkgs.libreoffice - ]; -} diff --git a/home/lnav/default.nix b/home/lnav/default.nix deleted file mode 100644 index a27f90b3..00000000 --- a/home/lnav/default.nix +++ /dev/null @@ -1,16 +0,0 @@ -{ - lib, - isImpermanent, - pkgs, - ... -}: { - home.persistence."/persist" = lib.mkIf isImpermanent { - directories = [ - ".config/lnav" - ]; - }; - - home.packages = [ - pkgs.lnav - ]; -} diff --git a/home/mic-levels-maintainer/default.nix b/home/mic-levels-maintainer/default.nix deleted file mode 100644 index bd2da9cc..00000000 --- a/home/mic-levels-maintainer/default.nix +++ /dev/null @@ -1,29 +0,0 @@ -# Maintain input gain levels -{ - pkgs, - osConfig, - ... -}: let - isNumenor = osConfig.networking.hostName == "numenor"; - mic-levels-maintainer = pkgs.writers.writeBashBin "mic-levels-maintainer" ( - if isNumenor - then (builtins.readFile ./scripts/mic-levels-maintainer-numenor.sh) - else (builtins.readFile ./scripts/mic-levels-maintainer-flexbox.sh) - ); -in { - home.packages = [mic-levels-maintainer]; - - systemd.user.services.mic-levels-maintainer = { - Unit = { - After = ["obs-mic.service"]; - Description = "Maintain input gain levels"; - Requires = ["obs-mic.service"]; - }; - Install.WantedBy = ["obs-mic.service"]; - Service = { - Environment = "PATH=$PATH:/run/current-system/sw/bin"; - ExecStart = "${mic-levels-maintainer}/bin/mic-levels-maintainer"; - Restart = "always"; - }; - }; -} diff --git a/home/mic-levels-maintainer/scripts/mic-levels-maintainer-flexbox.sh b/home/mic-levels-maintainer/scripts/mic-levels-maintainer-flexbox.sh deleted file mode 100644 index f76c41fe..00000000 --- a/home/mic-levels-maintainer/scripts/mic-levels-maintainer-flexbox.sh +++ /dev/null @@ -1,54 +0,0 @@ -set -euo pipefail - -get_pipewire_node_id() { - local node_name="$1" - pw-cli ls Node | awk -v name="$node_name" ' - $1 == "id" { id=$2 } - /node.name/ && $3 == "\"" name "\"" { gsub(/,/, "", id); print id } - ' -} - -OBS_SPEAKER_ID=$(get_pipewire_node_id "ObsSpeaker") -OBS_MIC_ID=$(get_pipewire_node_id "ObsMic") -INTERNAL_MIC_ID=$(get_pipewire_node_id "alsa_input.pci-0000_00_1f.3-platform-sof_sdw.HiFi__Mic__source") -BUDS_PRO_MIC_ID=$(get_pipewire_node_id "bluez_input.DC_69_E2_9A_6E_30.0") -BUDS_FE_MIC_ID=$(get_pipewire_node_id "bluez_input_internal.34_E3_FB_C5_01_E0.0") -OH_MIC_ID=$(get_pipewire_node_id "alsa_input.usb-Apple__Inc._USB-C_to_3.5mm_Headphone_Jack_Adapter_DWH84440324JKLTA7-00.mono-fallback") - -wpctl set-volume "$OBS_SPEAKER_ID" 1.0 -wpctl set-volume "$OBS_MIC_ID" 1.0 -wpctl set-volume "$INTERNAL_MIC_ID" 2.0 -if [ -n "$OH_MIC_ID" ]; then - wpctl set-volume "$OH_MIC_ID" 0.75 -fi -if [ -n "$BUDS_PRO_MIC_ID" ]; then - wpctl set-volume "$BUDS_PRO_MIC_ID" 1.0 -fi -if [ -n "$BUDS_FE_MIC_ID" ]; then - wpctl set-volume "$BUDS_FE_MIC_ID" 0.9 -fi - -while true; do - current_volume_obs_speaker=$(wpctl get-volume "$OBS_SPEAKER_ID" | awk '{print $2}') - current_volume_obs_mic=$(wpctl get-volume "$OBS_MIC_ID" | awk '{print $2}') - current_volume_internal_mic=$(wpctl get-volume "$INTERNAL_MIC_ID" | awk '{print $2}') - - [ "$current_volume_obs_speaker" != "1.0" ] && wpctl set-volume "$OBS_SPEAKER_ID" 1.0 - [ "$current_volume_obs_mic" != "1.0" ] && wpctl set-volume "$OBS_MIC_ID" 1.0 - [ "$current_volume_internal_mic" != "2.0" ] && wpctl set-volume "$INTERNAL_MIC_ID" 2.0 - - if [ -n "$BUDS_PRO_MIC_ID" ]; then - current_volume_buds_pro_mic=$(wpctl get-volume "$BUDS_PRO_MIC_ID" | awk '{print $2}') - [ "$current_volume_buds_pro_mic" != "1.0" ] && wpctl set-volume "$BUDS_PRO_MIC_ID" 1.0 - fi - if [ -n "$BUDS_FE_MIC_ID" ]; then - current_volume_buds_fe_mic=$(wpctl get-volume "$BUDS_FE_MIC_ID" | awk '{print $2}') - [ "$current_volume_buds_fe_mic" != "0.9" ] && wpctl set-volume "$BUDS_FE_MIC_ID" 0.9 - fi - if [ -n "$OH_MIC_ID" ]; then - current_volume_oh_mic=$(wpctl get-volume "$OH_MIC_ID" | awk '{print $2}') - [ "$current_volume_oh_mic" != "0.75" ] && wpctl set-volume "$OH_MIC_ID" 0.75 - fi - - sleep 1 -done diff --git a/home/mic-levels-maintainer/scripts/mic-levels-maintainer-numenor.sh b/home/mic-levels-maintainer/scripts/mic-levels-maintainer-numenor.sh deleted file mode 100644 index efa4ac5a..00000000 --- a/home/mic-levels-maintainer/scripts/mic-levels-maintainer-numenor.sh +++ /dev/null @@ -1,29 +0,0 @@ -set -euo pipefail - -get_pipewire_node_id() { - local node_name="$1" - pw-cli ls Node | awk -v name="$node_name" ' - $1 == "id" { id=$2 } - /node.name/ && $3 == "\"" name "\"" { gsub(/,/, "", id); print id } - ' -} - -OBS_SPEAKER_ID=$(get_pipewire_node_id "ObsSpeaker") -OBS_MIC_ID=$(get_pipewire_node_id "ObsMic") -BLUE_MIC_ID=$(get_pipewire_node_id "alsa_input.usb-Generic_Blue_Microphones_LT_221104181411AD020101_111000-00.analog-stereo") - -wpctl set-volume "$OBS_SPEAKER_ID" 1.0 -wpctl set-volume "$OBS_MIC_ID" 1.0 -wpctl set-volume "$BLUE_MIC_ID" 0.7 - -while true; do - current_volume_obs_speaker=$(wpctl get-volume "$OBS_SPEAKER_ID" | awk '{print $2}') - current_volume_obs_mic=$(wpctl get-volume "$OBS_MIC_ID" | awk '{print $2}') - current_volume_blue_mic=$(wpctl get-volume "$BLUE_MIC_ID" | awk '{print $2}') - - [ "$current_volume_obs_speaker" != "1.0" ] && wpctl set-volume "$OBS_SPEAKER_ID" 1.0 - [ "$current_volume_obs_mic" != "1.0" ] && wpctl set-volume "$OBS_MIC_ID" 1.0 - [ "$current_volume_blue_mic" != "0.7" ] && wpctl set-volume "$BLUE_MIC_ID" 0.7 - - sleep 1 -done diff --git a/home/mpv/default.nix b/home/mpv/default.nix deleted file mode 100644 index d22a9f79..00000000 --- a/home/mpv/default.nix +++ /dev/null @@ -1,17 +0,0 @@ -{ - lib, - isImpermanent, - pkgs, - ... -}: { - home.persistence."/persist" = lib.mkIf isImpermanent { - directories = [ - ".config/mpv" - ".cache/mpv" - ]; - }; - - home.packages = [ - pkgs.mpv - ]; -} diff --git a/home/mullvad-browser/default.nix b/home/mullvad-browser/default.nix deleted file mode 100644 index 08248360..00000000 --- a/home/mullvad-browser/default.nix +++ /dev/null @@ -1,16 +0,0 @@ -{ - isImpermanent, - lib, - pkgs, - ... -}: { - home.persistence."/persist" = lib.mkIf isImpermanent { - directories = [ - ".mullvad" - ]; - }; - - home.packages = [ - pkgs.mullvad-browser - ]; -} diff --git a/home/nautilus/default.nix b/home/nautilus/default.nix deleted file mode 100644 index 0bbf0e40..00000000 --- a/home/nautilus/default.nix +++ /dev/null @@ -1,17 +0,0 @@ -{ - lib, - isImpermanent, - pkgs, - ... -}: { - home.persistence."/persist" = lib.mkIf isImpermanent { - directories = [ - ".config/nautilus" - ".local/share/nautilus" - ]; - }; - - home.packages = [ - pkgs.nautilus - ]; -} diff --git a/home/neovim/avante/avante.lua b/home/neovim/avante/avante.lua deleted file mode 100644 index 89244a38..00000000 --- a/home/neovim/avante/avante.lua +++ /dev/null @@ -1,147 +0,0 @@ -require('avante_lib').load() -require('avante').setup({ - acp_providers = { - ["claude-code"] = { - command = "npx", - args = { "@zed-industries/claude-code-acp" }, - env = { - NODE_NO_WARNINGS = "1", - ANTHROPIC_API_KEY = os.getenv("ANTHROPIC_API_KEY"), - }, - }, - ["codex"] = { - command = "npx", - args = { "@zed-industries/codex-acp" }, - env = { - NODE_NO_WARNINGS = "1", - OPENAI_API_KEY = os.getenv("OPENAI_API_KEY"), - }, - }, - }, - behaviour = { - enable_fastapply = true, -- Uses morphllm.com - auto_approve_tool_permissions = false, - }, - debug = false, - dual_boost = { - enabled = false, - first_provider = "azure", - }, - hints = { enabled = false }, - instructions_file = "agents.md", - providers = { - openai = { - model = "gpt-5.2", - extra_request_body = { - temperature = 1, - }, - }, - openai_5_thinking = { - __inherited_from = 'openai', - model = "gpt-5.2", - extra_request_body = { - temperature = 1, - reasoning_effort = "high", - }, - }, - claude = { - endpoint = "https://api.anthropic.com", - model = "claude-sonnet-4-5", - }, - claude_thinking = { - __inherited_from = 'claude', - model = "claude-sonnet-4-5", - thinking = { - type = "enabled", - }, - }, - morph = { - model = "auto", - }, - }, - provider = "openai_5_thinking", - selector = { - provider = "telescope", - exclude_auto_select = { "NvimTree" }, - }, - system_prompt = - "When trying to read a pasted image, as a temporary workaround copy it to the current project directory before using str_replace_based_edit_tool(view) on it. When writing to AGENTS.md, don't document history, only note architectural changes that would be important to know going forward. Use jj instead of git. When writing shell scripts, always prefer the longhand version of arguments (e.g., --all instead of -a) and reserve the short-hand version for ad-hoc command invocations.", - - web_search_engine = { - provider = "kagi", - }, -}) - --- Improve contrast for Avante diffs when using a light colorscheme (e.g., gruvbox-light) --- This specifically targets deleted lines which tend to have very low contrast. -local function set_avante_light_highlights() - if vim.o.background ~= 'light' then return end - - -- Make deleted lines readable on light background - -- Use a stronger red background and high-contrast foreground - vim.api.nvim_set_hl(0, 'DiffDelete', { fg = '#7c0000', bg = '#ffb4b4', bold = true }) - - -- Ensure diff text hunk highlight is also visible enough on light backgrounds - vim.api.nvim_set_hl(0, 'DiffText', { bg = '#ffe29a' }) - - -- Avante-specific groups that can appear for deleted blocks in edit/suggestion views - pcall(vim.api.nvim_set_hl, 0, 'AvanteToBeDeleted', - { fg = '#7c0000', bg = '#ffb4b4', strikethrough = true, bold = true }) - pcall(vim.api.nvim_set_hl, 0, 'AvanteToBeDeletedWOStrikethrough', { fg = '#ffffff', bg = '#a23a3f', bold = true }) - - -- Avante exposes highlight groups for conflicts; set them to readable backgrounds if present - -- Use pcall so this doesn't error if groups don't exist or are managed by the plugin - pcall(vim.api.nvim_set_hl, 0, 'AvanteConflictCurrent', { bg = '#ffe8b3' }) -- ours/current - pcall(vim.api.nvim_set_hl, 0, 'AvanteConflictIncoming', { bg = '#d9f2d9' }) -- theirs/incoming -end - --- Apply immediately and re-apply when colorscheme or background changes -set_avante_light_highlights() -vim.api.nvim_create_autocmd('ColorScheme', { - callback = set_avante_light_highlights, -}) -vim.api.nvim_create_autocmd('OptionSet', { - pattern = 'background', - callback = set_avante_light_highlights, -}) - -local wk = require("which-key") -wk.add( - { - { - { "a", group = "[A]vante" }, - { "", "AvanteToggle", desc = "Toggle Avante", mode = { "n", "v" } }, - { "", "AvanteToggle", desc = "Toggle Avante", mode = { "i" } }, - }, - } -) - --- Set up buffer-local mappings for NvimTree -vim.api.nvim_create_autocmd("FileType", { - pattern = "NvimTree", - callback = function(args) - local bufnr = args.buf - vim.keymap.set("n", "a+", function() - local tree_ext = require("avante.extensions.nvim_tree") - tree_ext.add_file() - end, { buffer = bufnr, desc = "Select file in NvimTree" }) - - vim.keymap.set("n", "a-", function() - local tree_ext = require("avante.extensions.nvim_tree") - tree_ext.remove_file() - end, { buffer = bufnr, desc = "Deselect file in NvimTree" }) - end, -}) - --- Manual "Reject with reason" -vim.keymap.set("n", "ax", function() - vim.ui.input({ prompt = "Why reject? " }, function(reason) - if reason and reason ~= "" then - -- send the feedback to Avante - vim.cmd("AvanteAsk " .. vim.fn.shellescape( - "I rejected your last action because: " .. reason .. - ". Please adjust your plan and try again." - )) - end - end) -end, { desc = "Avante: reject with reason (send feedback)" }) diff --git a/home/neovim/avante/default.nix b/home/neovim/avante/default.nix deleted file mode 100644 index 6aea934d..00000000 --- a/home/neovim/avante/default.nix +++ /dev/null @@ -1,26 +0,0 @@ -# Cursor style AI IDE -{ - isImpermanent, - lib, - pkgs, - ... -}: { - home.persistence."/persist" = lib.mkIf isImpermanent { - directories = [ - ".config/avante.nvim" # Some Avante state like last used model - ]; - }; - programs.neovim = { - extraLuaConfig = '' - -- views can only be fully collapsed with the global statusline - vim.opt.laststatus = 3 - ''; - plugins = [ - { - plugin = pkgs.vimPlugins.avante-nvim; - config = builtins.readFile ./avante.lua; - type = "lua"; - } - ]; - }; -} diff --git a/home/neovim/carbon/default.nix b/home/neovim/carbon/default.nix deleted file mode 100644 index dd7eab17..00000000 --- a/home/neovim/carbon/default.nix +++ /dev/null @@ -1,46 +0,0 @@ -{pkgs, ...}: let - carbon-now = pkgs.vimUtils.buildVimPlugin { - name = "carbon-now"; - src = pkgs.fetchFromGitHub { - owner = "ellisonleao"; - repo = "carbon-now.nvim"; - rev = "4524d2b347830257bb9357d45c4f934960058476"; - sha256 = "id9KSrv683eb03ZB9VZ+ERBKuAlWbypjx0kEzCeiL0c="; - }; - }; -in { - programs.neovim.plugins = [ - { - plugin = carbon-now; - config = '' - require('carbon-now').setup({ - options = { - bg = "purple", - drop_shadow_blur = "68px", - drop_shadow = false, - drop_shadow_offset_y = "20px", - font_family = "Fira Code", - font_size = "18px", - line_height = "133%", - line_numbers = true, - theme = "one-dark", - titlebar = "Made with carbon-now.nvim", - watermark = false, - window_theme = "sharp", - padding_horizontal = "5px", - padding_vertical = "5px", - }, - }) - - vim.keymap.set("v", "s", ":CarbonNow", { silent = true }) - local wk = require("which-key") - wk.add( - { - { "s", desc = "[S]creenshot", mode = "v" }, - } - ) - ''; - type = "lua"; - } - ]; -} diff --git a/home/neovim/cmp/cmp.lua b/home/neovim/cmp/cmp.lua deleted file mode 100644 index d8b239e5..00000000 --- a/home/neovim/cmp/cmp.lua +++ /dev/null @@ -1,105 +0,0 @@ -local cmp = require 'cmp' -local luasnip = require 'luasnip' -require('luasnip.loaders.from_vscode').lazy_load() -luasnip.config.setup {} - -cmp.setup { - snippet = { - expand = function(args) - luasnip.lsp_expand(args.body) - end, - }, - completion = { - completeopt = 'menu,menuone,noinsert', - }, - mapping = cmp.mapping.preset.insert { - -- Select the [n]ext item - [''] = cmp.mapping.select_next_item(), - -- Select the [p]revious item - [''] = cmp.mapping.select_prev_item(), - - -- Scroll the documentation window [b]ack / [f]orward - [''] = cmp.mapping.scroll_docs(-4), - [''] = cmp.mapping.scroll_docs(-4), - [''] = cmp.mapping.scroll_docs(4), - [''] = cmp.mapping.scroll_docs(4), - - -- Exit completion - [''] = cmp.mapping.abort(), - - -- Accept ([y]es) the completion. - -- This will auto-import if your LSP supports it. - -- This will expand snippets if the LSP sent a snippet. - [''] = cmp.mapping(function(fallback) - if cmp.visible() then - cmp.confirm({ select = true }) - else - fallback() - end - end), - [''] = cmp.mapping.confirm { select = true }, - - [''] = cmp.mapping.complete {}, - }, - sources = { - { name = 'nvim_lsp' }, - { name = 'luasnip' }, - { name = 'path' }, - { name = 'buffer' }, - }, -} - --- Use buffer source for `/` and `?` (if you enabled `native_menu`, this won't work anymore). -cmp.setup.cmdline({ '/', '?' }, { - mapping = cmp.mapping.preset.cmdline(), - sources = { - { name = 'buffer' } - } -}) - --- Use cmdline & path source for ':' (if you enabled `native_menu`, this won't work anymore). -cmp.setup.cmdline(':', { - mapping = cmp.mapping.preset.cmdline(), - sources = cmp.config.sources({ - { name = 'path' } - }, { - { name = 'cmdline' } - }), - matching = { disallow_symbol_nonprefix_matching = false } -}) - -local lspkind = require('lspkind') -cmp.setup { - formatting = { - format = lspkind.cmp_format({ - mode = 'symbol', -- show only symbol annotations - maxwidth = 50, -- prevent the popup from showing more than provided characters (e.g 50 will not show more than 50 characters) - -- can also be a function to dynamically calculate max width such as - -- maxwidth = function() return math.floor(0.45 * vim.o.columns) end, - ellipsis_char = '...', -- when popup menu exceed maxwidth, the truncated part would show ellipsis_char instead (must define maxwidth first) - show_labelDetails = true, -- show labelDetails in menu. Disabled by default - - -- The function below will be called before any actual modifications from lspkind - -- so that you can provide more controls on popup customization. (See [#30](https://github.com/onsails/lspkind-nvim/pull/30)) - before = function(entry, vim_item) - vim_item.menu = ({ - buffer = "[Buffer]", - nvim_lsp = "[LSP]", - luasnip = "[Snippet]", - path = "[Path]", - -- Specify the name for other sources you may have - })[entry.source.name] - - return vim_item - end - }) - } -} - --- nvim-dadbod (SQL) setup -cmp.setup.filetype({ "sql" }, { - sources = { - { name = 'vim-dadbod-completion' }, - { name = 'buffer' }, - }, -}) diff --git a/home/neovim/cmp/default.nix b/home/neovim/cmp/default.nix deleted file mode 100644 index 9f26e7f2..00000000 --- a/home/neovim/cmp/default.nix +++ /dev/null @@ -1,27 +0,0 @@ -{pkgs, ...}: { - programs.neovim.plugins = with pkgs.vimPlugins; [ - { - plugin = nvim-cmp; # Autocompletion - config = builtins.readFile ./cmp.lua; - type = "lua"; - } - { - plugin = cmp_luasnip; # Autocompletion for luasnip - } - { - plugin = cmp-nvim-lsp; # Autocompletion Additions - } - { - plugin = cmp-path; # Path completions - } - { - plugin = cmp-buffer; # Buffer completions - } - { - plugin = cmp-cmdline; # Commandline completions - } - { - plugin = lspkind-nvim; # VSCode-like pictograms for LSP completions - } - ]; -} diff --git a/home/neovim/comment-nvim/default.nix b/home/neovim/comment-nvim/default.nix deleted file mode 100644 index 5a2e46f1..00000000 --- a/home/neovim/comment-nvim/default.nix +++ /dev/null @@ -1,11 +0,0 @@ -{pkgs, ...}: { - programs.neovim.plugins = with pkgs.vimPlugins; [ - { - plugin = comment-nvim; # Commenting with gc - config = '' - require('Comment').setup() - ''; - type = "lua"; - } - ]; -} diff --git a/home/neovim/conform/conform.lua b/home/neovim/conform/conform.lua deleted file mode 100644 index dba25c5d..00000000 --- a/home/neovim/conform/conform.lua +++ /dev/null @@ -1,23 +0,0 @@ -require("conform").setup({ - formatters_by_ft = { - sh = { "shfmt" }, - bash = { "shfmt" }, - html = { "prettierd" }, - json = { "prettierd" }, - yaml = { "prettierd" }, - markdown = { "prettierd" }, - python = { "ruff_format", "ruff_organize_imports" }, - }, - -- Uncomment to enable format on save: - -- format_on_save = { - -- timeout_ms = 500, - -- lsp_format = "fallback", - -- }, -}) - --- Optional: Set up a keybinding for manual formatting --- Use f since LSP-related actions use localleader -local wk = require("which-key") -wk.add({ - { "f", function() require("conform").format({ async = true, lsp_format = "fallback" }) end, desc = "[F]ormat buffer" }, -}) diff --git a/home/neovim/conform/default.nix b/home/neovim/conform/default.nix deleted file mode 100644 index 32806c92..00000000 --- a/home/neovim/conform/default.nix +++ /dev/null @@ -1,13 +0,0 @@ -{pkgs, ...}: { - programs.neovim.extraPackages = with pkgs; [ - eslint - ruff - ]; - programs.neovim.plugins = with pkgs.vimPlugins; [ - { - plugin = conform-nvim; - config = builtins.readFile ./conform.lua; - type = "lua"; - } - ]; -} diff --git a/home/neovim/dadbod/default.nix b/home/neovim/dadbod/default.nix deleted file mode 100644 index 30f35172..00000000 --- a/home/neovim/dadbod/default.nix +++ /dev/null @@ -1,36 +0,0 @@ -{ - isImpermanent, - lib, - pkgs, - ... -}: { - home.persistence."/persist" = lib.mkIf isImpermanent { - directories = [ - ".local/share/db_ui" - ]; - }; - programs.neovim.plugins = with pkgs.vimPlugins; [ - { - plugin = vim-dadbod; # SQL Fu - } - { - plugin = vim-dadbod-completion; - } - { - plugin = vim-dadbod-ui; - config = '' - vim.g.db_ui_use_nerd_fonts = 1 - - local wk = require("which-key") - wk.add( - { - { "D", group = "[D]atabase" }, - { "Dn", "tab DBUI", desc = "open in [n]ew tab" }, - { "Dt", "DBUIToggle", desc = "[t]oggle" }, - } - ) - ''; - type = "lua"; - } - ]; -} diff --git a/home/neovim/dap/dap-ui.lua b/home/neovim/dap/dap-ui.lua deleted file mode 100644 index 6d83e572..00000000 --- a/home/neovim/dap/dap-ui.lua +++ /dev/null @@ -1,24 +0,0 @@ -local wk = require("which-key") -local dap, dapui = require("dap"), require("dapui") -dapui.setup({ - wk.add( - { - { "dt", require('dapui').toggle, desc = "[T]oggle UI" }, - { "", require('dapui').toggle, desc = "[T]oggle UI" }, - } - ) -}) - --- Events to auto-open/close the UI -dap.listeners.before.attach.dapui_config = function() - dapui.open() -end -dap.listeners.before.launch.dapui_config = function() - dapui.open() -end -dap.listeners.before.event_terminated.dapui_config = function() - dapui.close() -end -dap.listeners.before.event_exited.dapui_config = function() - dapui.close() -end diff --git a/home/neovim/dap/dap.lua b/home/neovim/dap/dap.lua deleted file mode 100644 index f272f62d..00000000 --- a/home/neovim/dap/dap.lua +++ /dev/null @@ -1,134 +0,0 @@ -local wk = require("which-key") -local dap = require("dap") -wk.add( - { - { "d", group = "[D]ebug" }, - { "dB", function() dap.set_breakpoint(vim.fn.input('Breakpoint condition: ')) end, desc = "Set conditional [B]reakpoint" }, - { "db", function() dap.toggle_breakpoint() end, desc = "Toggle [B]reakpoint" }, - { "dc", function() dap.continue() end, desc = "[C]ontinue" }, - { "", function() dap.continue() end, desc = "Continue" }, - { "dC", function() dap.run_to_cursor() end, desc = "Run to [C]ursor" }, - { "di", function() dap.step_into() end, desc = "Step [I]nto" }, - { "", function() dap.step_into() end, desc = "Step Into" }, - { "do", function() dap.step_over() end, desc = "Step [O]ver" }, - { "", function() dap.step_over() end, desc = "Step Over" }, - { "dq", function() dap.close() end, desc = "[Q]uit/Close dap" }, - { "dr", function() dap.repl.open() end, desc = "Open [R]epl" }, - { "du", function() dap.step_out() end, desc = "Step O[u]t" }, - { "", function() dap.step_out() end, desc = "Step Out" }, - } -) - --- Fix color highlighting for stopped DAP line --- See https://github.com/mfussenegger/nvim-dap/discussions/355#discussioncomment-8389225 -vim.api.nvim_create_autocmd("ColorScheme", { - pattern = "*", - desc = "Prevent colorscheme clearing self-defined DAP marker colors", - callback = function() - -- Reuse current SignColumn background (except for DapStoppedLine) - local sign_column_hl = vim.api.nvim_get_hl(0, { name = 'SignColumn' }) - -- if bg or ctermbg aren't found, use bg = 'bg' (which means current Normal) and ctermbg = 'Black' - -- convert to 6 digit hex value starting with # - local sign_column_bg = (sign_column_hl.bg ~= nil) and ('#%06x'):format(sign_column_hl.bg) or 'bg' - local sign_column_ctermbg = (sign_column_hl.ctermbg ~= nil) and sign_column_hl.ctermbg or 'Black' - - vim.api.nvim_set_hl(0, 'DapStopped', { fg = '#00ff00', bg = sign_column_bg, ctermbg = sign_column_ctermbg }) - vim.api.nvim_set_hl(0, 'DapStoppedLine', { bg = '#2e4d3d', ctermbg = 'Green' }) - vim.api.nvim_set_hl(0, 'DapBreakpoint', { fg = '#c23127', bg = sign_column_bg, ctermbg = sign_column_ctermbg }) - vim.api.nvim_set_hl(0, 'DapBreakpointRejected', - { fg = '#888ca6', bg = sign_column_bg, ctermbg = sign_column_ctermbg }) - vim.api.nvim_set_hl(0, 'DapLogPoint', { fg = '#61afef', bg = sign_column_bg, ctermbg = sign_column_ctermbg }) - - vim.fn.sign_define('DapStopped', { - text = '→', - texthl = 'DapStopped', - linehl = 'DapStoppedLine', - numhl = 'DapStoppedLine', - }) - end -}) - --- Existing Rust/C/C++ debug adapter (codelldb) -dap.adapters.codelldb = { - type = "executable", - command = "codelldb", -}; - -dap.configurations.cpp = { - { - name = "Launch file", - type = "codelldb", - request = "launch", - program = function() - return vim.fn.input('Path to executable: ', vim.fn.getcwd() .. '/', 'file') - end, - cwd = '${workspaceFolder}', - stopOnEntry = false, - }, -} -dap.configurations.c = dap.configurations.cpp - --- Rust uses the same config as C/C++ -dap.configurations.rust = dap.configurations.cpp - --- JavaScript/TypeScript debug (vscode-js-debug via nvim-dap-vscode-js) --- Requires Mason package: js-debug-adapter -local ok, vscode_js = pcall(require, 'dap-vscode-js') -if ok then - vscode_js.setup({ - -- Path where Mason installs the js-debug adapter - debugger_path = vim.fn.stdpath('data') .. '/mason/packages/js-debug-adapter', - adapters = { 'pwa-node', 'pwa-chrome', 'pwa-msedge', 'node-terminal', 'pwa-extensionHost' }, - }) - - local js_based_languages = { 'typescript', 'javascript', 'typescriptreact', 'javascriptreact' } - - for _, language in ipairs(js_based_languages) do - dap.configurations[language] = dap.configurations[language] or {} - - -- Launch current file using ts-node - table.insert(dap.configurations[language], { - type = 'pwa-node', - request = 'launch', - name = 'Launch TS (ts-node)', - program = '${file}', - cwd = '${workspaceFolder}', - runtimeExecutable = 'node', - runtimeArgs = { '-r', 'ts-node/register' }, - sourceMaps = true, - protocol = 'inspector', - console = 'integratedTerminal', - env = { TS_NODE_PROJECT = '${workspaceFolder}/tsconfig.json' }, - }) - - -- Attach to a running Node process (start node with --inspect or --inspect-brk) - table.insert(dap.configurations[language], { - type = 'pwa-node', - request = 'attach', - name = 'Attach to Node', - processId = require('dap.utils').pick_process, - cwd = '${workspaceFolder}', - }) - - -- Launch transpiled JS from dist (requires a build step) - table.insert(dap.configurations[language], { - type = 'pwa-node', - request = 'launch', - name = 'Launch built app (dist)', - program = '${workspaceFolder}/dist/index.js', - cwd = '${workspaceFolder}', - outFiles = { '${workspaceFolder}/dist/**/*.js' }, - sourceMaps = true, - console = 'integratedTerminal', - }) - - -- Debug a web app in Chrome (points to local dev server) - table.insert(dap.configurations[language], { - type = 'pwa-chrome', - request = 'launch', - name = 'Chrome: localhost', - url = 'http://localhost:3000', - webRoot = '${workspaceFolder}', - }) - end -end diff --git a/home/neovim/dap/default.nix b/home/neovim/dap/default.nix deleted file mode 100644 index 79dd6fff..00000000 --- a/home/neovim/dap/default.nix +++ /dev/null @@ -1,25 +0,0 @@ -{pkgs, ...}: { - programs.neovim.plugins = with pkgs.vimPlugins; [ - { - plugin = nvim-dap; # Debug Adapter Protocol - config = builtins.readFile ./dap.lua; - type = "lua"; - } - { - plugin = nvim-dap-ui; # DAP UI - config = builtins.readFile ./dap-ui.lua; - type = "lua"; - } - { - plugin = nvim-dap-virtual-text; # Virtual text showing values using Treesitter - config = '' - require("nvim-dap-virtual-text").setup() - ''; - type = "lua"; - } - # JavaScript/TypeScript DAP adapter - { - plugin = nvim-dap-vscode-js; - } - ]; -} diff --git a/home/neovim/default.nix b/home/neovim/default.nix deleted file mode 100644 index db8608f4..00000000 --- a/home/neovim/default.nix +++ /dev/null @@ -1,356 +0,0 @@ -{ - isImpermanent, - lib, - osConfig, - pkgs, - ... -}: let - isLightTheme = osConfig.specialisation != {}; -in { - home.persistence."/persist" = lib.mkIf isImpermanent { - directories = [ - ".local/share/nvim" # Data - ".local/state/nvim" # state - ".cache/nvim" - ]; - }; - - imports = - [ - ./avante # Cursor style AI IDE - ./carbon - ./cmp - ./comment-nvim - ./dadbod - ./dap - ./diffview-nvim - ./fidget # Sidebar notifications for LSP - ./folds - ./fugitive - ./git-conflict-nvim - ./gitsigns - ./jdtls - ./jj - ./lspsaga - ./lualine - # Ensure devicons module is available before mocking it with mini.icons - ./mason-lsp - ./mini-icons - ./mini-operators - ./neotest - ./noice # UI for commandline, messages and popupmenu - ./conform - ./notify # Pluggable Notifications - ./nui # UI Components - ./nvim-tree-lua # File Tree - ./obsidian-nvim - ./oil - ./otter # LSP for embedded code in markdown/quarto - ./overseer - ./plenary # LUA Functions - ./rainbow-csv - ./render-markdown - ./telescope - ./toggleterm - ./treesitter - ./trouble - ./undotree - ./vim-be-good # Vim Motion Learnenings - ./vim-terraform - ./vim-visual-multi - ./web-devicons - ./yank-file-line - ] - ++ lib.optionals isLightTheme [ - ./gruvbox - ]; - - programs.neovim = { - enable = true; - - extraConfig = '' - set mouse=a - set number - set clipboard=unnamedplus - set ignorecase - set smartcase - - " Defaults to be overwritten by vim-sleuth - set tabstop=4 - set shiftwidth=4 - - set grepprg=rg\ --vimgrep\ --no-heading\ --smart-case - - noremap h ; - noremap ; l - noremap l k - noremap k j - noremap j h - noremap ; l - noremap l k - noremap k j - noremap j h - noremap : L - noremap L K - noremap K J - noremap J H - - " Vertical Awesomeness - nnoremap zz - nnoremap zz - nnoremap G Gzz - - tnoremap h - tnoremap j - tnoremap k - tnoremap l - inoremap h - inoremap j - inoremap k - inoremap l - nnoremap h - nnoremap j - nnoremap k - nnoremap l - - set shell=/etc/profiles/per-user/farlion/bin/fish - - let mapleader = ' ' - let maplocalleader = ',' - - " Diff Settings - set diffopt+=internal,algorithm:patience - - " Quickfix Lists - nnoremap :cprev - nnoremap :cnext - - " Saving - use z. for centering the cursor instead - nnoremap zz :update - - " Applying a macro to lines matching in visual selection - " https://medium.com/@schtoeffel/you-don-t-need-more-than-one-cursor-in-vim-2c44117d51db - xnoremap @ :call ExecuteMacroOverVisualRange() - function! ExecuteMacroOverVisualRange() - echo "@".getcmdline() - execute ":'<,'>normal @".nr2char(getchar()) - endfunction - - " https://github.com/Saecki/crates.nvim - lua require('crates').setup() - - " Fugitive - " See https://github.com/tpope/vim-fugitive/issues/1510#issuecomment-660837020 - function! s:ftplugin_fugitive() abort - nnoremap cc :Git commit --quiet - nnoremap ca :Git commit --quiet --amend - nnoremap ce :Git commit --quiet --amend --no-edit - endfunction - augroup quiet_fugitive - autocmd! - autocmd FileType fugitive call s:ftplugin_fugitive() - augroup END - - " Vim Visual Multi - let g:VM_custom_motions = {'h': ';', ';': 'l', 'l': 'k', 'k': 'j', 'j': 'h'} - let g:VM_mouse_mappings = 1 - - " Background light/dark toggling - nmap i :let &bg=(&bg=='light'?'dark':'light') - - " Sudo powers with :w!! - cnoremap w!! execute 'silent! write !sudo tee % >/dev/null' edit! - ''; - - extraLuaConfig = '' - -- set termguicolors (24bit colors) to enable highlight groups - vim.opt.termguicolors = true - - -- Wrapped lines should follow the indent - vim.o.breakindent = true - - -- Remap for dealing with word wrap - vim.keymap.set('n', 'k', "v:count == 0 ? 'gj' : 'j'", { expr = true, silent = true }) - vim.keymap.set('n', 'l', "v:count == 0 ? 'gk' : 'k'", { expr = true, silent = true }) - - -- Save undo history - -- TODO: sync this if useful - vim.o.undofile = true - - -- Timeout and Updatetime settings - vim.o.timeout = true - vim.o.timeoutlen = 300 - vim.o.updatetime = 250 - - -- Set completeopt to have a better completion experience - vim.o.completeopt = 'menuone,noselect' - - -- Make faster - vim.keymap.set({ 'n', 'v' }, '', '', { silent = true }) - - -- Disable swapfiles - vim.opt.swapfile = false - - -- Terminal Mode shortcuts - vim.keymap.set('t', '', '', { silent = true }) - vim.keymap.set('t', '', [[]], { silent = true }) - - -- Faster exit shortcut - vim.keymap.set({ 'n', 'v', 't' }, 'ZQ', ':qa!') - - -- Disable F1 as help shortcut - vim.keymap.set({'n', 'i'}, '', '', { noremap = true, silent = true }) - ''; - - extraPackages = with pkgs; [ - harper # Grammar checker - nixd # Nix Language Server - nodejs # For vim to have npm for Mason etc... - prettierd # For yaml, html, json, markdown - pyright - shellcheck - shfmt - ]; - - plugins = with pkgs.vimPlugins; [ - argtextobj-vim - { - plugin = b64-nvim; # Base64 encoding/decoding - config = '' - local wk = require("which-key") - wk.add( - { - { - mode = { "v" }, - { "b", group = "[B]ase64" }, - { "bd", require("b64").decode, desc = "Base64 [D]ecode" }, - { "be", require("b64").decode, desc = "Base64 [E]ncode" }, - }, - } - ) - ''; - type = "lua"; - } - { - plugin = dressing-nvim; # Better UI for codeactions, code input etc... - config = '' - - ''; - type = "lua"; - } - { - plugin = friendly-snippets; # User-friendly snippets, work with LuaSnip and other engines - } - vim-highlightedyank - { - plugin = indent-blankline-nvim; # Indentation guides - config = '' - require("ibl").setup({ - exclude = { - filetypes = {"startify"}, - } - }) - local hooks = require "ibl.hooks" - hooks.register(hooks.type.ACTIVE, function(bufnr) - return vim.tbl_contains( - { "yaml", "html", "svelte" }, - vim.api.nvim_get_option_value("filetype", { buf = bufnr }) - ) - end) - local wk = require("which-key") - wk.add({ - { "[i", function() require("ibl").setup_buffer(0, {enabled = true}) end, desc = "Indentation Guides ON" }, - { "]i", function() require("ibl").setup_buffer(0, {enabled = false}) end, desc = "Indentation Guides OFF" }, - }) - ''; - type = "lua"; - } - { - plugin = nvim-lspconfig; # Defaults for loads of LSP languages - } - { - plugin = luasnip; # Snippet engine - } - { - plugin = markdown-preview-nvim; - config = '' - local wk = require("which-key") - wk.add({ - { "p", "MarkdownPreviewToggle", desc = "Toggle Markdown [P]review" }, - }) - ''; - type = "lua"; - } - vim-numbertoggle - { - plugin = vim-qf; # Quickfix improvements - config = ''''; - } - vim-rooter - vim-sleuth # Automatic shiftwidth and expandtab - { - plugin = vim-startify; - config = '' - let g:startify_change_to_dir = 0 - let g:startify_change_to_vcs_root = 1 - let g:startify_session_persistence = 1 - let g:startify_bookmarks = [ {'c': '~/nixos-config/home/neovim/default.nix'} ] - ''; - } - vim-surround - { - plugin = vim-suda; # Sudo support via :SudaRead and :SudaWrite - } - { - plugin = text-case-nvim; - config = '' - require("textcase").setup({ - prefix = "ga", - }) - require("telescope").load_extension("textcase") - local wk = require("which-key") - wk.add({ - { "ga.", "TextCaseOpenTelescope", desc = "Telescope" }, - }) - ''; - type = "lua"; - } - vim-textobj-entire - vim-toml - vim-unimpaired - { - plugin = which-key-nvim; - config = '' - require("which-key").setup { - } - ''; - type = "lua"; - } - - ## Language Specific Plugins - crates-nvim - dart-vim-plugin - elm-vim - vim-graphql - vim-jsonnet - { - plugin = neodev-nvim; # Nvim LUA development - config = '' - require("neodev").setup({ - library = { plugins = { "nvim-dap-ui", "neotest" }, types = true }, - }) - ''; - type = "lua"; - } - vim-flutter - vim-helm - vim-shellcheck - vim-solidity - vim-nix - ]; - - viAlias = true; - vimAlias = true; - vimdiffAlias = true; - }; -} diff --git a/home/neovim/diffview-nvim/default.nix b/home/neovim/diffview-nvim/default.nix deleted file mode 100644 index df54f0dc..00000000 --- a/home/neovim/diffview-nvim/default.nix +++ /dev/null @@ -1,9 +0,0 @@ -{pkgs, ...}: { - programs.neovim.plugins = with pkgs.vimPlugins; [ - { - plugin = diffview-nvim; - config = builtins.readFile ./diffview-nvim.lua; - type = "lua"; - } - ]; -} diff --git a/home/neovim/diffview-nvim/diffview-nvim.lua b/home/neovim/diffview-nvim/diffview-nvim.lua deleted file mode 100644 index f5802765..00000000 --- a/home/neovim/diffview-nvim/diffview-nvim.lua +++ /dev/null @@ -1,35 +0,0 @@ -local wk = require("which-key") -wk.add({ - { "v", group = "Diff[v]iew" }, - { "vo", ":DiffviewOpen", desc = "[O]pen" }, - { "vh", ":DiffviewFileHistory %", desc = "File [h]istory" }, - { "vH", ":DiffviewFileHistory .", desc = "Directory [H]istory" }, - { "vc", ":DiffviewClose", desc = "[C]lose" }, -}) - -require("diffview").setup({ - keymaps = { - view = { - { "n", "]c", false }, - { "n", "[c", false }, - { "n", "]x", false }, - { "n", "[x", false }, - { "n", "]l", require("diffview.actions").next_entry, { desc = "Next entry" } }, - { "n", "[l", require("diffview.actions").prev_entry, { desc = "Previous entry" } }, - }, - file_panel = { - { "n", "j", false }, - { "n", "k", false }, - { "n", "k", require("diffview.actions").next_entry, { desc = "Next entry" } }, - { "n", "l", require("diffview.actions").prev_entry, { desc = "Previous entry" } }, - { "n", "", require("diffview.actions").select_entry, { desc = "Open diff" } }, - }, - file_history_panel = { - { "n", "j", false }, - { "n", "k", false }, - { "n", "k", require("diffview.actions").next_entry, { desc = "Next entry" } }, - { "n", "l", require("diffview.actions").prev_entry, { desc = "Previous entry" } }, - { "n", "", require("diffview.actions").select_entry, { desc = "Open entry" } }, - }, - }, -}) diff --git a/home/neovim/fidget/default.nix b/home/neovim/fidget/default.nix deleted file mode 100644 index d7cbada2..00000000 --- a/home/neovim/fidget/default.nix +++ /dev/null @@ -1,12 +0,0 @@ -# Sidebar notifications for LSP -{pkgs, ...}: { - programs.neovim.plugins = with pkgs.vimPlugins; [ - { - plugin = fidget-nvim; - config = '' - require('fidget').setup() - ''; - type = "lua"; - } - ]; -} diff --git a/home/neovim/folds/default.nix b/home/neovim/folds/default.nix deleted file mode 100644 index 4a6a0065..00000000 --- a/home/neovim/folds/default.nix +++ /dev/null @@ -1,9 +0,0 @@ -{pkgs, ...}: { - programs.neovim.plugins = [ - { - plugin = pkgs.vimPlugins.nvim-ufo; - config = builtins.readFile ./ufo.lua; - type = "lua"; - } - ]; -} diff --git a/home/neovim/folds/ufo.lua b/home/neovim/folds/ufo.lua deleted file mode 100644 index 20ec576a..00000000 --- a/home/neovim/folds/ufo.lua +++ /dev/null @@ -1,9 +0,0 @@ -vim.o.foldcolumn = '0' -- '1' makes it visible, but is kinda ugly and interferes with stuff like lspsaga -vim.o.foldlevel = 99 -- Using ufo provider need a large value, feel free to decrease the value -vim.o.foldlevelstart = 99 -vim.o.foldenable = true - -vim.keymap.set('n', 'zR', require('ufo').openAllFolds) -vim.keymap.set('n', 'zM', require('ufo').closeAllFolds) - -require('ufo').setup() diff --git a/home/neovim/fugitive/default.nix b/home/neovim/fugitive/default.nix deleted file mode 100644 index 3ebf685a..00000000 --- a/home/neovim/fugitive/default.nix +++ /dev/null @@ -1,22 +0,0 @@ -{pkgs, ...}: { - programs.neovim.plugins = with pkgs.vimPlugins; [ - { - plugin = fugitive; - config = builtins.readFile ./fugitive.lua; - type = "lua"; - } - { - plugin = vim-fubitive; - config = '' - let g:fubitive_domain_pattern = 'bitbucket-ssh\.plansee-group\.com' - ''; - } - { - plugin = fugitive-gitlab-vim; - config = '' - let g:fugitive_gitlab_domains = ['https://git.datalabhell.at', 'https://gitlab.k8s.plansee-group.com'] - ''; - } - vim-rhubarb # github bindings for fugitive - ]; -} diff --git a/home/neovim/fugitive/fugitive.lua b/home/neovim/fugitive/fugitive.lua deleted file mode 100644 index 53bde8d8..00000000 --- a/home/neovim/fugitive/fugitive.lua +++ /dev/null @@ -1,63 +0,0 @@ -local wk = require("which-key") -wk.add( - { - { "g", group = "[G]it", silent = false }, - { "gB", ":Git blame", desc = "[B]lame", silent = false }, - { "gb", ":Git checkout -b", desc = "New [b]ranch", silent = false }, - { "gc", ":Git checkout", desc = "[C]heckout branch/tag", silent = false }, - { "gd", group = "[D]iff", silent = false }, - { "gdd", ":Gdiff", desc = "[D]iff", silent = false }, - { "gds", ":Gdiffsplit!", desc = "[S]plit diff", silent = false }, - { "ge", ":Gedit", desc = "Ch[e]ckout any branch/sha/file", silent = false }, - { "gh", ":0Gclog", desc = "[H]istory for entire file", silent = false }, - { "gl", ":Gclog", desc = "[L]og", silent = false }, - { "gm", ":GMove", desc = "[M]ove", silent = false }, - { "gp", group = "[P]ush/pull", silent = false }, - { - "gpf", - function() - vim.cmd( - 'TermExec cmd="git push --force-with-lease" | call fugitive#ReloadStatus()') - end, - desc = "[F]orce push with lease", - silent = false - }, - { "gpl", function() vim.cmd('TermExec cmd="git pull" | call fugitive#ReloadStatus()') end, desc = "[P]ull", silent = false }, - { - "gpn", - function() - vim.cmd( - 'TermExec cmd="git push -u origin HEAD" | call fugitive#ReloadStatus()') - end, - desc = "Push [n]ew branch", - silent = false - }, - { "gps", function() vim.cmd('TermExec cmd="git push" | call fugitive#ReloadStatus()') end, desc = "Pu[s]h", silent = false }, - { "gr", ":Gread", desc = "[R]evert to working tree/index copy of file", silent = false }, - { "gw", ":Gwrite", desc = "[W]rite to index", silent = false }, - } -) - -wk.add( - { - { "g", group = "[G]it", mode = "v" }, - { "gh", ":Gclog", desc = "[H]istory for selection", mode = "v" }, - } -) - - --- Fugitive only mappings -vim.api.nvim_create_autocmd("BufReadPost", { - pattern = "*", - callback = function() - local bufnr = vim.api.nvim_get_current_buf() - local bufname = vim.api.nvim_buf_get_name(bufnr) - - if string.match(bufname, "^fugitive://") then - vim.api.nvim_buf_set_keymap(bufnr, "n", "gj", ":diffget //2", - { noremap = true, silent = false }) - vim.api.nvim_buf_set_keymap(bufnr, "n", "g;", ":diffget //3", - { noremap = true, silent = false }) - end - end, -}) diff --git a/home/neovim/git-conflict-nvim/default.nix b/home/neovim/git-conflict-nvim/default.nix deleted file mode 100644 index 41e38cdc..00000000 --- a/home/neovim/git-conflict-nvim/default.nix +++ /dev/null @@ -1,11 +0,0 @@ -{pkgs, ...}: { - programs.neovim.plugins = with pkgs.vimPlugins; [ - { - plugin = git-conflict-nvim; - config = '' - require('git-conflict').setup({}) - ''; - type = "lua"; - } - ]; -} diff --git a/home/neovim/gitsigns/default.nix b/home/neovim/gitsigns/default.nix deleted file mode 100644 index cfc634dd..00000000 --- a/home/neovim/gitsigns/default.nix +++ /dev/null @@ -1,9 +0,0 @@ -{pkgs, ...}: { - programs.neovim.plugins = with pkgs.vimPlugins; [ - { - plugin = gitsigns-nvim; - config = builtins.readFile ./gitsigns.lua; - type = "lua"; - } - ]; -} diff --git a/home/neovim/gitsigns/gitsigns.lua b/home/neovim/gitsigns/gitsigns.lua deleted file mode 100644 index 11bc1a51..00000000 --- a/home/neovim/gitsigns/gitsigns.lua +++ /dev/null @@ -1,52 +0,0 @@ -require('gitsigns').setup { - on_attach = function(bufnr) - local gitsigns = require('gitsigns') - local wk = require("which-key") - - -- Navigation - vim.keymap.set('n', ']c', function() - if vim.wo.diff then - vim.cmd.normal({ ']c', bang = true }) - else - gitsigns.nav_hunk('next') - end - end, { buffer = bufnr, desc = "Next hunk" }) - - vim.keymap.set('n', '[c', function() - if vim.wo.diff then - vim.cmd.normal({ '[c', bang = true }) - else - gitsigns.nav_hunk('prev') - end - end, { buffer = bufnr, desc = "Previous hunk" }) - - -- Text object - vim.keymap.set({ 'o', 'x' }, 'ih', gitsigns.select_hunk, { buffer = bufnr, desc = "Select hunk" }) - - -- Which-key mappings for gitsigns - wk.add({ - { "h", group = "[H]unk", buffer = bufnr }, - { "hs", gitsigns.stage_hunk, desc = "[S]tage hunk", buffer = bufnr }, - { "hr", gitsigns.reset_hunk, desc = "[R]eset hunk", buffer = bufnr }, - { "hS", gitsigns.stage_buffer, desc = "[S]tage buffer", buffer = bufnr }, - { "hR", gitsigns.reset_buffer, desc = "[R]eset buffer", buffer = bufnr }, - { "hp", gitsigns.preview_hunk, desc = "[P]review hunk", buffer = bufnr }, - { "hi", gitsigns.preview_hunk_inline, desc = "Preview hunk [i]nline", buffer = bufnr }, - { "hb", function() gitsigns.blame_line({ full = true }) end, desc = "[B]lame line", buffer = bufnr }, - { "hd", gitsigns.diffthis, desc = "[D]iff this", buffer = bufnr }, - { "hD", function() gitsigns.diffthis('~') end, desc = "[D]iff this ~", buffer = bufnr }, - { "hQ", function() gitsigns.setqflist('all') end, desc = "Set [Q]uickfix list (all)", buffer = bufnr }, - { "hq", gitsigns.setqflist, desc = "Set [q]uickfix list", buffer = bufnr }, - { "ht", group = "[T]oggle", buffer = bufnr }, - { "htb", gitsigns.toggle_current_line_blame, desc = "Toggle [b]lame", buffer = bufnr }, - { "htw", gitsigns.toggle_word_diff, desc = "Toggle [w]ord diff", buffer = bufnr }, - }) - - -- Visual mode mappings - wk.add({ - { "h", group = "[H]unk", mode = "v", buffer = bufnr }, - { "hs", function() gitsigns.stage_hunk({ vim.fn.line('.'), vim.fn.line('v') }) end, desc = "[S]tage hunk", mode = "v", buffer = bufnr }, - { "hr", function() gitsigns.reset_hunk({ vim.fn.line('.'), vim.fn.line('v') }) end, desc = "[R]eset hunk", mode = "v", buffer = bufnr }, - }) - end -} diff --git a/home/neovim/gruvbox/default.nix b/home/neovim/gruvbox/default.nix deleted file mode 100644 index fa88fa86..00000000 --- a/home/neovim/gruvbox/default.nix +++ /dev/null @@ -1,18 +0,0 @@ -{pkgs, ...}: { - programs.neovim = { - extraConfig = '' - " Colorscheme - autocmd vimenter * ++nested colorscheme gruvbox - nnoremap [oh :call gruvbox#hls_show() - nnoremap ]oh :call gruvbox#hls_hide() - nnoremap coh :call gruvbox#hls_toggle() - - nnoremap * :let @/ = "":call gruvbox#hls_show()* - nnoremap / :let @/ = "":call gruvbox#hls_show()/ - nnoremap ? :let @/ = "":call gruvbox#hls_show()? - ''; - plugins = with pkgs.vimPlugins; [ - gruvbox - ]; - }; -} diff --git a/home/neovim/jdtls/default.nix b/home/neovim/jdtls/default.nix deleted file mode 100644 index 8bdd68cb..00000000 --- a/home/neovim/jdtls/default.nix +++ /dev/null @@ -1,11 +0,0 @@ -{pkgs, ...}: { - programs.neovim.plugins = [ - { - plugin = pkgs.vimPlugins.nvim-jdtls; - runtime = { - "ftplugin/java.lua".source = ./jdtls.lua; - }; - type = "lua"; - } - ]; -} diff --git a/home/neovim/jdtls/jdtls.lua b/home/neovim/jdtls/jdtls.lua deleted file mode 100644 index 17defc4a..00000000 --- a/home/neovim/jdtls/jdtls.lua +++ /dev/null @@ -1,99 +0,0 @@ -local root_dir = require('jdtls.setup').find_root({ '.git' }); -local project_name = vim.fn.fnamemodify(root_dir, ':p:h:t') -local data_dir = vim.fn.expand('$HOME/.cache/nvim/jdtls/workspaces/') .. project_name - -local jdtls_path = vim.fn.expand('$HOME/.local/share/nvim/mason/packages/jdtls') -local jdebug_path = vim.fn.expand('$HOME/.local/share/nvim/mason/packages/java-debug-adapter') -local jtest_path = vim.fn.expand('$HOME/.local/share/nvim/mason/packages/java-test') - - -local bundles = { - vim.fn.glob(jdebug_path .. "/extension/server/com.microsoft.java.debug.plugin-*.jar", true), -} -vim.list_extend(bundles, vim.split(vim.fn.glob(jtest_path .. "/extension/server/*.jar", true), "\n")) - -local extendedClientCapabilities = require('jdtls').extendedClientCapabilities -extendedClientCapabilities.resolveAdditionalTextEditsSupport = true - --- Java-specific LSP keybindings (common ones are in shared_lsp_config via LspAttach) -local on_attach = function(_, bufnr) - local nmap = function(keys, func, desc) - if desc then - desc = 'LSP: ' .. desc - end - - vim.keymap.set('n', keys, func, { buffer = bufnr, desc = desc }) - end - - local wk = require("which-key") - wk.add({ - { "e", group = "[E]xtract" }, - { "t", group = "[T]est" }, - }) - nmap('o', require('jdtls').organize_imports, '[O]rganize Imports') - nmap('ev', require('jdtls').extract_variable, '[V]ariable') - nmap('ec', require('jdtls').extract_constant, '[C]onstant') - nmap('em', require('jdtls').extract_method, '[M]ethod') - - -- DAP specific keybindings, since not yet compatible wit neotest - nmap('tc', require('jdtls').test_class, 'Debug Test [C]lass') - nmap('tn', require('jdtls').test_nearest_method, 'Debug Test [N]earest') - - require('jdtls').setup_dap({ hotcodereplace = "auto" }) - require('jdtls.dap').setup_dap_main_class_configs() - require('jdtls.setup').add_commands() -end - - --- See `:help vim.lsp.start_client` for an overview of the supported `config` options. -local config = { - -- The command that starts the language server - -- See: https://github.com/eclipse/eclipse.jdt.ls#running-from-the-command-line - cmd = { - 'java', -- or '/path/to/java17_or_newer/bin/java' - -- depends on if `java` is in your $PATH env variable and if it points to the right version. - - '-Declipse.application=org.eclipse.jdt.ls.core.id1', - '-Dosgi.bundles.defaultStartLevel=4', - '-Declipse.product=org.eclipse.jdt.ls.core.product', - '-Dlog.protocol=true', - '-Dlog.level=ALL', - '-Xmx1g', - '-javaagent:' .. jdtls_path .. '/lombok.jar', - '--add-modules=ALL-SYSTEM', - '--add-opens', 'java.base/java.util=ALL-UNNAMED', - '--add-opens', 'java.base/java.lang=ALL-UNNAMED', - '-jar', vim.fn.glob(jdtls_path .. '/plugins/org.eclipse.equinox.launcher_*.jar'), - '-configuration', jdtls_path .. '/config_linux', - '-data', data_dir, - }, - - on_attach = on_attach, - - -- This is the default if not provided, you can remove it. Or adjust as needed. - -- One dedicated LSP server & client will be started per unique root_dir - root_dir = root_dir, - - -- Here you can configure eclipse.jdt.ls specific settings - -- See https://github.com/eclipse/eclipse.jdt.ls/wiki/Running-the-JAVA-LS-server-from-the-command-line#initialize-request - -- for a list of options - settings = { - java = { - } - }, - - -- Language server `initializationOptions` - -- You need to extend the `bundles` with paths to jar files - -- if you want to use additional eclipse.jdt.ls plugins. - -- - -- See https://github.com/mfussenegger/nvim-jdtls#java-debug-installation - -- - -- If you don't plan on using the debugger or other eclipse.jdt.ls plugins you can remove this - init_options = { - bundles = bundles, - extendedClientCapabilities = extendedClientCapabilities, - }, -} --- This starts a new client & server, --- or attaches to an existing client & server depending on the `root_dir`. -require('jdtls').start_or_attach(config) diff --git a/home/neovim/jj/default.nix b/home/neovim/jj/default.nix deleted file mode 100644 index 54092451..00000000 --- a/home/neovim/jj/default.nix +++ /dev/null @@ -1,45 +0,0 @@ -{pkgs, ...}: let - jj-nvim = pkgs.vimUtils.buildVimPlugin { - name = "jj-nvim"; - src = pkgs.fetchFromGitHub { - owner = "NicolasGB"; - repo = "jj.nvim"; - rev = "v0.4.0"; - sha256 = "sha256-BY4wDMMQUdu6DHfMqP4lpHQdHhS+yL6+CUiKQJFJY2Q="; - }; - }; -in { - programs.neovim.plugins = with pkgs.vimPlugins; [ - { - plugin = toggleterm-nvim; - config = builtins.readFile ./jj.lua; - type = "lua"; - } - { - plugin = jj-nvim; - config = '' - require("jj").setup({ - diff = { - backend = "diffview", - }, - }) - - local wk = require("which-key") - local cmd = require("jj.cmd") - wk.add({ - { "j", group = "[J]ujutsu" }, - { "jl", cmd.log, desc = "[L]og" }, - { "js", cmd.status, desc = "[S]tatus" }, - { "jc", cmd.commit, desc = "[C]ommit" }, - { "jd", cmd.describe, desc = "[D]escribe" }, - { "jn", function() cmd.new({ show_log = true }) end, desc = "[N]ew change" }, - { "ju", cmd.undo, desc = "[U]ndo" }, - -- Bypass jj.nvim's push handler to use our custom jj push alias - { "jp", function() require("jj.ui.terminal").run("jj push") end, desc = "[P]ush" }, - { "jr", cmd.redo, desc = "[R]edo" }, - }) - ''; - type = "lua"; - } - ]; -} diff --git a/home/neovim/jj/jj.lua b/home/neovim/jj/jj.lua deleted file mode 100644 index ca029a06..00000000 --- a/home/neovim/jj/jj.lua +++ /dev/null @@ -1,21 +0,0 @@ --- F3 keybinding to toggle jjui in a floating terminal -local Terminal = require('toggleterm.terminal').Terminal -local jjui_term = Terminal:new({ - cmd = "jjui", - direction = "float", - hidden = true, - on_open = function(term) - vim.cmd("startinsert!") - -- Allow ESC to work inside jjui instead of exiting terminal mode - vim.keymap.set('t', '', '', { buffer = term.bufnr, noremap = true }) - end, -}) - -vim.keymap.set('n', '', function() - jjui_term:toggle() -end, { desc = "Toggle jjui in floating terminal" }) - -vim.keymap.set('t', '', function() - jjui_term:toggle() -end, { desc = "Toggle jjui in floating terminal" }) - diff --git a/home/neovim/lspsaga/default.nix b/home/neovim/lspsaga/default.nix deleted file mode 100644 index 10d4c4bb..00000000 --- a/home/neovim/lspsaga/default.nix +++ /dev/null @@ -1,16 +0,0 @@ -{pkgs, ...}: { - programs.neovim.plugins = with pkgs.vimPlugins; [ - { - plugin = lspsaga-nvim; - config = '' - require('lspsaga').setup({ - lightbulb = { - enable = true, - sign = false, -- disable the sign in signcolumn, which creates bouncy shit - }, - }) - ''; - type = "lua"; - } - ]; -} diff --git a/home/neovim/lualine/default.nix b/home/neovim/lualine/default.nix deleted file mode 100644 index 96239466..00000000 --- a/home/neovim/lualine/default.nix +++ /dev/null @@ -1,58 +0,0 @@ -# Status line for neovim -{pkgs, ...}: { - programs.neovim.plugins = with pkgs.vimPlugins; [ - { - plugin = lualine-nvim; - config = '' - require('lualine').setup({ - options = { - theme = 'gruvbox', - }, - extensions = { - 'fugitive', - 'mason', - 'nvim-tree', - 'oil', - 'overseer', - 'quickfix', - 'toggleterm', - 'trouble', - }, - sections = { - lualine_a = {'mode'}, - lualine_b = {'branch', 'diff', 'fugitive_branch', 'diagnostics'}, - lualine_c = {'filename'}, - lualine_x = { - { - require("noice").api.status.message.get_hl, - cond = require("noice").api.status.message.has, - }, - { - require("noice").api.status.command.get, - cond = require("noice").api.status.command.has, - color = { fg = "#ff9e64" }, - }, - { - require("noice").api.status.mode.get, - cond = require("noice").api.status.mode.has, - color = { fg = "#ff9e64" }, - }, - { - require("noice").api.status.search.get, - cond = require("noice").api.status.search.has, - color = { fg = "#ff9e64" }, - }, - { "overseer", colored = false }, - 'encoding', - 'fileformat', - 'filetype' - }, - lualine_y = {'progress'}, - lualine_z = {'location'} - }, - }) - ''; - type = "lua"; - } - ]; -} diff --git a/home/neovim/mason-lsp/default.nix b/home/neovim/mason-lsp/default.nix deleted file mode 100644 index e5272123..00000000 --- a/home/neovim/mason-lsp/default.nix +++ /dev/null @@ -1,84 +0,0 @@ -{ - isImpermanent, - lib, - pkgs, - ... -}: { - home.persistence."/persist" = lib.mkIf isImpermanent { - directories = [ - ".local/state/logrotate" # Logrotate state for nvim LSP logs - ]; - }; - - programs.neovim = { - extraLuaConfig = '' - -- LSP diagnostics: show inline virtual text - vim.diagnostic.config({ - virtual_text = { - spacing = 2, - prefix = "●", - }, - signs = true, -- keep signs in the gutter - underline = true, -- underline offending code - update_in_insert = false, -- reduce noise while typing - severity_sort = true, -- sort diagnostics by severity - float = { - border = "rounded", - source = "if_many", - }, - }) - ''; - - plugins = with pkgs.vimPlugins; [ - { - plugin = mason-nvim; # Automatically install LSP servers - config = builtins.readFile ./mason.lua; - runtime = { - "lua/shared_lsp_config.lua".source = ./shared_lsp_config.lua; - }; - type = "lua"; - } - { - plugin = mason-lspconfig-nvim; # Automatically install LSP servers - } - { - plugin = mason-nvim-dap-nvim; # Automatically configure DAP adapters - } - ]; - }; - - # User-level logrotate for nvim LSP logs (hm doesn't support that yet) - home.packages = [pkgs.logrotate]; - systemd.user.services.logrotate-nvim = { - Unit = { - Description = "Rotate nvim LSP log"; - }; - Service = { - Type = "oneshot"; - ExecStartPre = "${pkgs.coreutils}/bin/mkdir --parents %h/.local/state/logrotate"; - ExecStart = "${pkgs.logrotate}/bin/logrotate --state=%h/.local/state/logrotate/nvim.state %h/.config/logrotate/nvim.conf"; - }; - }; - systemd.user.timers.logrotate-nvim = { - Unit = { - Description = "Timer for nvim LSP log rotation"; - }; - Timer = { - OnCalendar = "hourly"; - Persistent = true; - }; - Install = { - WantedBy = ["timers.target"]; - }; - }; - home.file.".config/logrotate/nvim.conf".text = '' - /home/farlion/.local/state/nvim/lsp.log { - size 1M - rotate 5 - compress - copytruncate - missingok - notifempty - } - ''; -} diff --git a/home/neovim/mason-lsp/mason.lua b/home/neovim/mason-lsp/mason.lua deleted file mode 100644 index 52cd1a29..00000000 --- a/home/neovim/mason-lsp/mason.lua +++ /dev/null @@ -1,200 +0,0 @@ --- General Diagnostic keymaps -local wk = require("which-key") -local lspsaga = require("lspsaga") -wk.add( - { - { "d", vim.diagnostic.open_float, desc = "Open Floating [D]iagnostics" }, - { "l", vim.diagnostic.setloclist, desc = "Open Diagnostics in [L]ocation List" }, - { "q", vim.diagnostic.setqflist, desc = "Open Diagnostics in [Q]uickfix List" }, - { "[d", "Lspsaga diagnostic_jump_prev", desc = "Prev [D]iagnostic" }, - { "]d", "Lspsaga diagnostic_jump_next", desc = "Next [D]iagnostic" }, - } -) - --- Autoformat, from https://github.com/nvim-lua/kickstart.nvim/blob/master/lua/kickstart/plugins/autoformat.lua --- Switch for controlling whether you want autoformatting. --- Use :AutoFormatToggle to toggle autoformatting on or off -local format_is_enabled = true -vim.api.nvim_create_user_command('AutoFormatToggle', function() - format_is_enabled = not format_is_enabled - print('Setting autoformatting to: ' .. tostring(format_is_enabled)) -end, {}) - --- Create an augroup that is used for managing our formatting autocmds. --- We need one augroup per client to make sure that multiple clients --- can attach to the same buffer without interfering with each other. -local _augroups = {} -local get_augroup = function(client) - if not _augroups[client.id] then - local group_name = 'kickstart-lsp-format-' .. client.name - local id = vim.api.nvim_create_augroup(group_name, { clear = true }) - _augroups[client.id] = id - end - - return _augroups[client.id] -end - --- Whenever an LSP attaches to a buffer, we will run this function. --- --- See `:help LspAttach` for more information about this autocmd event. -vim.api.nvim_create_autocmd('LspAttach', { - group = vim.api.nvim_create_augroup('kickstart-lsp-attach-format', { clear = true }), - -- This is where we attach the autoformatting for reasonable clients - callback = function(args) - local client_id = args.data.client_id - local client = vim.lsp.get_client_by_id(client_id) - local bufnr = args.buf - - -- Only attach to clients that support document formatting - if not client.server_capabilities.documentFormattingProvider then - return - end - - -- Tsserver usually works poorly. Sorry you work with bad languages - -- You can remove this line if you know what you're doing :) - if client.name == 'tsserver' then - return - end - - -- Create an autocmd that will run *before* we save the buffer. - -- Run the formatting command for the LSP that has just attached. - vim.api.nvim_create_autocmd('BufWritePre', { - group = get_augroup(client), - buffer = bufnr, - callback = function() - if not format_is_enabled then - return - end - - vim.lsp.buf.format { - async = false, - filter = function(c) - return c.id == client.id - end, - } - end, - }) - end, -}) - --- Document workspace keymap -require('which-key').add( - { - { "w", group = "[W]orkspace" }, - { "w_", hidden = true }, - } -) - --- Mason setup -require('mason').setup() -require("mason-nvim-dap").setup({ - ensure_installed = { - "codelldb", - "javadbg", - "javatest", - }, -}) - --- Setup neovim lua configuration -require('neodev').setup() - --- nvim-cmp supports additional completion capabilities -local capabilities = vim.lsp.protocol.make_client_capabilities() -capabilities = require('cmp_nvim_lsp').default_capabilities(capabilities) - --- UFO code folding support -capabilities.textDocument.foldingRange = { - dynamicRegistration = false, - lineFoldingOnly = true -} - --- Global LSP configuration applied to all servers -vim.lsp.config('*', { - capabilities = capabilities, -}) - --- Server-specific configurations using vim.lsp.config (Neovim 0.11+) -vim.lsp.config('bashls', {}) -vim.lsp.config('jsonls', {}) -vim.lsp.config('julials', {}) -vim.lsp.config('ruff', {}) -vim.lsp.config('terraformls', {}) -vim.lsp.config('tflint', {}) -vim.lsp.config('ts_ls', {}) - -vim.lsp.config('lua_ls', { - settings = { - Lua = { - workspace = { checkThirdParty = false }, - telemetry = { enable = false }, - }, - }, -}) - -vim.lsp.config('rust_analyzer', { - settings = { - checkOnSave = { - command = 'clippy', - }, - }, -}) - -vim.lsp.config('yamlls', { - settings = { - schemas = { - kubernetes = "*.yaml", - ["http://json.schemastore.org/github-workflow"] = ".github/workflows/*", - ["http://json.schemastore.org/github-action"] = ".github/action.{yml,yaml}", - ["http://json.schemastore.org/ansible-stable-2.9"] = "roles/tasks/*.{yml,yaml}", - ["http://json.schemastore.org/prettierrc"] = ".prettierrc.{yml,yaml}", - ["http://json.schemastore.org/kustomization"] = "kustomization.{yml,yaml}", - ["http://json.schemastore.org/ansible-playbook"] = "*play*.{yml,yaml}", - ["http://json.schemastore.org/chart"] = "Chart.{yml,yaml}", - ["https://json.schemastore.org/dependabot-v2"] = ".github/dependabot.{yml,yaml}", - ["https://json.schemastore.org/gitlab-ci"] = "*gitlab-ci*.{yml,yaml}", - ["https://raw.githubusercontent.com/OAI/OpenAPI-Specification/main/schemas/v3.1/schema.json"] = "*api*.{yml,yaml}", - ["https://raw.githubusercontent.com/compose-spec/compose-spec/master/schema/compose-spec.json"] = - "*docker-compose*.{yml,yaml}", - ["https://raw.githubusercontent.com/argoproj/argo-workflows/master/api/jsonschema/schema.json"] = - "*flow*.{yml,yaml}", - }, - }, -}) - --- Language Servers managed outside of Mason -vim.lsp.config('pyright', {}) - -vim.lsp.config('nixd', { - settings = { - nixd = { - formatting = { - command = { "alejandra" }, - }, - }, - }, -}) - -vim.lsp.config('harper_ls', { - filetypes = { "markdown", "text", "gitcommit" }, -}) - --- Mason-lspconfig with automatic_enable (v2.x for Neovim 0.11+) --- Automatically enables installed servers via vim.lsp.enable() -require('mason-lspconfig').setup { - ensure_installed = { - 'bashls', 'jsonls', 'lua_ls', 'julials', 'ruff', - 'rust_analyzer', 'terraformls', 'tflint', 'ts_ls', 'yamlls', - 'jdtls', -- Managed by jdtls-nvim plugin - }, - automatic_enable = { - exclude = { 'jdtls' }, -- jdtls-nvim manages its own client - }, -} - --- Enable servers managed outside Mason -vim.lsp.enable('pyright') -vim.lsp.enable('nixd') -vim.lsp.enable('harper_ls') - --- Load shared LSP keybindings (gd, gr, K, etc.) -require('shared_lsp_config') diff --git a/home/neovim/mason-lsp/shared_lsp_config.lua b/home/neovim/mason-lsp/shared_lsp_config.lua deleted file mode 100644 index dd8b40ad..00000000 --- a/home/neovim/mason-lsp/shared_lsp_config.lua +++ /dev/null @@ -1,41 +0,0 @@ --- LSP keybindings applied to all LSP clients via LspAttach autocmd -vim.api.nvim_create_autocmd('LspAttach', { - group = vim.api.nvim_create_augroup('lsp-keybindings', { clear = true }), - callback = function(args) - local bufnr = args.buf - - local nmap = function(keys, func, desc) - if desc then - desc = 'LSP: ' .. desc - end - vim.keymap.set('n', keys, func, { buffer = bufnr, desc = desc }) - end - - nmap('r', vim.lsp.buf.rename, '[R]e[n]ame') - nmap('a', vim.lsp.buf.code_action, '[C]ode [A]ction') - nmap('x', function() vim.api.nvim_command('LspRestart') end, '[R]estart LSP Client') - - nmap('gd', require('telescope.builtin').lsp_definitions, '[G]oto [D]efinition') - nmap('gD', vim.lsp.buf.declaration, '[G]oto [D]eclaration') - nmap('gR', require('telescope.builtin').lsp_references, '[G]oto [R]eferences') - nmap('gI', require('telescope.builtin').lsp_implementations, '[G]oto [I]mplementation') - nmap('gy', require('telescope.builtin').lsp_type_definitions, '[G]oto T[y]pe Definition') - nmap('s', require('telescope.builtin').lsp_document_symbols, '[D]ocument [S]ymbols') - nmap('w', require('telescope.builtin').lsp_dynamic_workspace_symbols, '[W]orkspace [S]ymbols') - - nmap('K', vim.lsp.buf.hover, 'Hover Documentation') - nmap('', vim.lsp.buf.signature_help, 'Signature Documentation') - - -- Workspace Fu - nmap('wa', vim.lsp.buf.add_workspace_folder, '[W]orkspace [A]dd Folder') - nmap('wr', vim.lsp.buf.remove_workspace_folder, '[W]orkspace [R]emove Folder') - nmap('wl', function() - print(vim.inspect(vim.lsp.buf.list_workspace_folders())) - end, '[W]orkspace [L]ist Folders') - - -- Create a command `:Format` local to the LSP buffer - vim.api.nvim_buf_create_user_command(bufnr, 'Format', function(_) - vim.lsp.buf.format() - end, { desc = 'Format current buffer with LSP' }) - end, -}) diff --git a/home/neovim/mini-icons/default.nix b/home/neovim/mini-icons/default.nix deleted file mode 100644 index 2452163c..00000000 --- a/home/neovim/mini-icons/default.nix +++ /dev/null @@ -1,12 +0,0 @@ -{pkgs, ...}: { - programs.neovim.plugins = [ - { - plugin = pkgs.vimPlugins.mini-icons; - config = '' - require('mini.icons').setup() - require('mini.icons').mock_nvim_web_devicons() - ''; - type = "lua"; - } - ]; -} diff --git a/home/neovim/mini-operators/default.nix b/home/neovim/mini-operators/default.nix deleted file mode 100644 index cc5ddd91..00000000 --- a/home/neovim/mini-operators/default.nix +++ /dev/null @@ -1,31 +0,0 @@ -{pkgs, ...}: let - mini-operators = pkgs.vimUtils.buildVimPlugin { - name = "mini-operators"; - src = pkgs.fetchFromGitHub { - owner = "echasnovski"; - repo = "mini.operators"; - rev = "2edc808e32fbf3e0d4759bdef26a7a143a19f509"; - sha256 = "OFZyzhOTK+vUYejjdUMQoc905auZP/x6iqIZaS5KBVY="; - }; - }; -in { - programs.neovim.plugins = [ - { - plugin = mini-operators; - config = '' - -- Remove conflicting global default LSP keymaps - vim.keymap.del('n', 'grn') -- unset rename - vim.keymap.del({'n','v'}, 'gra') -- unset code_action - vim.keymap.del('n', 'grr') -- unset references - vim.keymap.del('n', 'gri') -- unset implementations - vim.keymap.del('n', 'grt') -- unset type_definition - require('mini.operators').setup({ - exchange = { - prefix = 'gX', -- default is 'gx' which overrides gx as open link from neovim/netRW - }, - }) - ''; - type = "lua"; - } - ]; -} diff --git a/home/neovim/neotest/default.nix b/home/neovim/neotest/default.nix deleted file mode 100644 index 75044bbc..00000000 --- a/home/neovim/neotest/default.nix +++ /dev/null @@ -1,21 +0,0 @@ -{pkgs, ...}: { - programs.neovim.plugins = with pkgs.vimPlugins; [ - { - plugin = FixCursorHold-nvim; - } - { - plugin = neotest; - config = builtins.readFile ./neotest.lua; - type = "lua"; - } - { - plugin = neotest-java; - } - { - plugin = neotest-rust; - } - { - plugin = nvim-nio; - } - ]; -} diff --git a/home/neovim/neotest/neotest.lua b/home/neovim/neotest/neotest.lua deleted file mode 100644 index c7f56126..00000000 --- a/home/neovim/neotest/neotest.lua +++ /dev/null @@ -1,31 +0,0 @@ -require("neotest").setup({ - adapters = { - require("neotest-rust") { - args = { "--no-capture" }, - dap_adapter = "codelldb", - }, - }, - consumers = { - overseer = require("neotest.consumers.overseer"), - }, -}) - -local wk = require("which-key") -wk.add( - { - { "t", group = "neo[T]est" }, - { "ta", require("neotest").run.attach, desc = "[A]ttach to nearest" }, - { "td", function() require("neotest").run.run({ strategy = "dap" }) end, desc = "[D]ebug nearest" }, - { "tf", function() require("neotest").run.run(vim.fn.expand("%")) end, desc = "[F]ile" }, - { "tn", require("neotest").run.run, desc = "[N]earest" }, - { - "to", - function() - require("neotest").output_panel.toggle() - vim.cmd("wincmd p") - end, - desc = "Toggle [O]utput Panel" - }, - { "ts", function() require("neotest").summary.toggle({ enter = true }) end, desc = "Toggle [S]ummary" }, - } -) diff --git a/home/neovim/noice/default.nix b/home/neovim/noice/default.nix deleted file mode 100644 index b95a6f9c..00000000 --- a/home/neovim/noice/default.nix +++ /dev/null @@ -1,9 +0,0 @@ -{pkgs, ...}: { - programs.neovim.plugins = with pkgs.vimPlugins; [ - { - plugin = noice-nvim; - config = builtins.readFile ./noice.lua; - type = "lua"; - } - ]; -} diff --git a/home/neovim/noice/noice.lua b/home/neovim/noice/noice.lua deleted file mode 100644 index d657e100..00000000 --- a/home/neovim/noice/noice.lua +++ /dev/null @@ -1,28 +0,0 @@ -require("noice").setup({ - lsp = { - -- override markdown rendering so that **cmp** and other plugins use **Treesitter** - override = { - ["vim.lsp.util.convert_input_to_markdown_lines"] = true, - ["vim.lsp.util.stylize_markdown"] = true, - ["cmp.entry.get_documentation"] = true, -- requires hrsh7th/nvim-cmp - }, - }, - -- you can enable a preset for easier configuration - presets = { - bottom_search = true, -- use a classic bottom cmdline for search - command_palette = true, -- position the cmdline and popupmenu together - long_message_to_split = true, -- long messages will be sent to a split - inc_rename = false, -- enables an input dialog for inc-rename.nvim - lsp_doc_border = false, -- add a border to hover docs and signature help - }, -}) - -local wk = require("which-key") -wk.add( - { - { "n", group = "[N]oice" }, - { "nd", "NoiceDismiss", desc = "[D]ismiss Notifications" }, - { "nl", "NoiceLast", desc = "[L]ast Notifiation" }, - { "nn", "Noice", desc = "Show all [N]otifications" }, - } -) diff --git a/home/neovim/notify/default.nix b/home/neovim/notify/default.nix deleted file mode 100644 index 2276cd57..00000000 --- a/home/neovim/notify/default.nix +++ /dev/null @@ -1,21 +0,0 @@ -{pkgs, ...}: { - programs.neovim = { - extraLuaConfig = '' - vim.notify = require("notify") - ''; - plugins = with pkgs.vimPlugins; [ - { - plugin = nvim-notify; - config = '' - require('notify').setup() - - local wk = require("which-key") - wk.add({ - { "nh", "Telescope notify", desc = "Notification [H]istory" }, - }) - ''; - type = "lua"; - } - ]; - }; -} diff --git a/home/neovim/nui/default.nix b/home/neovim/nui/default.nix deleted file mode 100644 index 2980c541..00000000 --- a/home/neovim/nui/default.nix +++ /dev/null @@ -1,10 +0,0 @@ -{pkgs, ...}: { - programs.neovim.plugins = with pkgs.vimPlugins; [ - { - plugin = nui-nvim; - config = '' - ''; - type = "lua"; - } - ]; -} diff --git a/home/neovim/nvim-tree-lua/default.nix b/home/neovim/nvim-tree-lua/default.nix deleted file mode 100644 index 4e9decbb..00000000 --- a/home/neovim/nvim-tree-lua/default.nix +++ /dev/null @@ -1,9 +0,0 @@ -{pkgs, ...}: { - programs.neovim.plugins = with pkgs.vimPlugins; [ - { - plugin = nvim-tree-lua; - config = builtins.readFile ./nvim-tree.lua; - type = "lua"; - } - ]; -} diff --git a/home/neovim/nvim-tree-lua/nvim-tree.lua b/home/neovim/nvim-tree-lua/nvim-tree.lua deleted file mode 100644 index f8e7bedf..00000000 --- a/home/neovim/nvim-tree-lua/nvim-tree.lua +++ /dev/null @@ -1,59 +0,0 @@ --- Ensure mini.icons mock is active before configuring nvim-tree -local ok_icons, Icons = pcall(require, 'mini.icons') -if ok_icons and Icons and Icons.mock_nvim_web_devicons then - -- Replace nvim-web-devicons so nvim-tree and others use mini.icons - pcall(Icons.mock_nvim_web_devicons) -end - -local function my_on_attach(bufnr) - local api = require "nvim-tree.api" - local function opts(desc) - return { desc = "nvim-tree: " .. desc, buffer = bufnr, noremap = true, silent = true, nowait = true } - end - -- default mappings - api.config.mappings.default_on_attach(bufnr) - -- custom mappings - vim.keymap.set('n', '', api.node.open.horizontal, opts('Open: Horizontal Split')) - vim.keymap.set('n', '?', api.tree.toggle_help, opts('Help')) -end -require("nvim-tree").setup({ - on_attach = my_on_attach, - disable_netrw = false, -- keeping netrw for :GBrowse from fugitive to work - hijack_netrw = true, -- once no longer needed, check :he nvim-tree-netrw - -- Ensure devicons are enabled so the mini.icons mock is used - renderer = { - icons = { - -- Use simple ASCII for folder glyphs to avoid NF v2/v3 codepoint mismatches - glyphs = { - folder = { - arrow_closed = "", - arrow_open = "", - default = "", - open = "", - empty = "", - empty_open = "", - symlink = "", - symlink_open = "", - }, - }, - }, - }, - -- Dynamic width - view = { - width = { - min = 30, - max = -1, - }, - }, -}) -local wk = require("which-key") -wk.add( - { - { "f", group = "[F]iles(NvimTree)" }, - { "fc", "NvimTreeCollapse", desc = "[C]ollapse NVimTree Node Recursively" }, - { "ff", "NvimTreeFindFile", desc = "Move the cursor in the tree for the current buffer, opening [f]olders if needed." }, - { "ft", "NvimTreeToggle", desc = "[T]oggle NvimTree" }, - { "", "NvimTreeToggle", desc = "Toggle NvimTree", mode = { "n", "v" } }, - { "", "NvimTreeToggle", desc = "Toggle NvimTree", mode = { "i" } }, - } -) diff --git a/home/neovim/obsidian-nvim/default.nix b/home/neovim/obsidian-nvim/default.nix deleted file mode 100644 index 20bd3deb..00000000 --- a/home/neovim/obsidian-nvim/default.nix +++ /dev/null @@ -1,31 +0,0 @@ -{pkgs, ...}: { - programs.neovim.plugins = with pkgs.vimPlugins; [ - { - plugin = obsidian-nvim; - config = '' - require("obsidian").setup({ - follow_img_func = function(img) - vim.fn.jobstart({"xdg-open", url}) - end, - legacy_commands = false, - -- Clashes with render-markdown.nvim - ui = { - enable = false, - }, - workspaces = { - { - name = "main", - path = "~/Obsidian", - } - }, - }) - - local wk = require("which-key") - wk.add({ - { "o", "Obsidian Search", desc = "Search [O]bsidian" }, - }) - ''; - type = "lua"; - } - ]; -} diff --git a/home/neovim/oil/default.nix b/home/neovim/oil/default.nix deleted file mode 100644 index f87a54cd..00000000 --- a/home/neovim/oil/default.nix +++ /dev/null @@ -1,27 +0,0 @@ -{pkgs, ...}: { - programs.neovim.plugins = with pkgs.vimPlugins; [ - { - plugin = oil-nvim; - config = '' - require('oil').setup({ - default_file_explorer = false, - delete_to_trash = true, - skip_confirm_for_simple_edits = true, - view_options = { - show_hidden = true, - natural_order = true, - is_always_hidden = function(name, _) - return name == '..' or name == '.git' - end, - }, - win_options = { - wrap = true, - }, - }) - - vim.keymap.set("n", "-", "Oil", { desc = "Open parent directory" }) - ''; - type = "lua"; - } - ]; -} diff --git a/home/neovim/otter/default.nix b/home/neovim/otter/default.nix deleted file mode 100644 index 526b48ef..00000000 --- a/home/neovim/otter/default.nix +++ /dev/null @@ -1,25 +0,0 @@ -{pkgs, ...}: { - programs.neovim.plugins = with pkgs.vimPlugins; [ - { - plugin = otter-nvim; - config = '' - require('otter').setup({ - lsp = { - hover = { - -- Border style for LSP hover windows in embedded code - border = { "╭", "─", "╮", "│", "╯", "─", "╰", "│" }, - }, - }, - }) - - local wk = require("which-key") - wk.add({ - { "O", group = "[O]tter" }, - { "Oa", function() require("otter").activate() end, desc = "[A]ctivate Otter" }, - { "Od", function() require("otter").deactivate() end, desc = "[D]eactivate Otter" }, - }) - ''; - type = "lua"; - } - ]; -} diff --git a/home/neovim/overseer/default.nix b/home/neovim/overseer/default.nix deleted file mode 100644 index 9a613669..00000000 --- a/home/neovim/overseer/default.nix +++ /dev/null @@ -1,25 +0,0 @@ -{pkgs, ...}: { - home.file = { - ".config/nvim/lua/overseer/template/user/gmailctl_apply.lua".source = ./templates/gmailctl_apply.lua; - - ".config/nvim/lua/overseer/template/user/java_gradle.lua".source = ./templates/java_gradle/init.lua; - - ".config/nvim/lua/overseer/template/user/java_maven.lua".source = ./templates/java_maven/init.lua; - - ".config/nvim/lua/overseer/template/user/nixos_rebuild_switch.lua".source = ./templates/nixos_rebuild_switch.lua; - ".config/nvim/lua/overseer/template/user/nixos_rebuild_boot.lua".source = ./templates/nixos_rebuild_boot.lua; - ".config/nvim/lua/overseer/template/user/nixos_update_secrets.lua".source = ./templates/nixos_update_secrets.lua; - ".config/nvim/lua/overseer/template/user/skaffold_dev.lua".source = ./templates/skaffold_dev.lua; - }; - - programs.neovim.plugins = [ - { - config = builtins.readFile ./overseer.lua; - plugin = pkgs.vimPlugins.overseer-nvim; - runtime = { - "lua/overseer_lib.lua".source = ./overseer_lib.lua; - }; - type = "lua"; - } - ]; -} diff --git a/home/neovim/overseer/overseer.lua b/home/neovim/overseer/overseer.lua deleted file mode 100644 index d93da1e2..00000000 --- a/home/neovim/overseer/overseer.lua +++ /dev/null @@ -1,29 +0,0 @@ -require('overseer').setup({ - templates = { - "builtin", - "user.gmailctl_apply", - "user.java_gradle", - "user.java_maven", - "user.nixos_rebuild_switch", - "user.nixos_rebuild_boot", - "user.nixos_update_secrets", - "user.skaffold_dev", - }, - component_aliases = { - default = { - "on_exit_set_status", - "on_complete_notify", - { "on_complete_dispose", require_view = { "SUCCESS", "FAILURE" } }, - { "open_output", direction = "dock", on_start = "always", focus = true }, - }, - }, -}) -local wk = require("which-key") -wk.add( - { - { "o", group = "[O]verseer" }, - { "or", "OverseerRun", desc = "[R]un" }, - { "ot", "OverseerToggle", desc = "[T]oggle List" }, - { "", "OverseerToggle", desc = "Toggle Overseer" }, - } -) diff --git a/home/neovim/overseer/overseer_lib.lua b/home/neovim/overseer/overseer_lib.lua deleted file mode 100644 index d6ee95ed..00000000 --- a/home/neovim/overseer/overseer_lib.lua +++ /dev/null @@ -1,25 +0,0 @@ -local M = {} - -M.is_gradle_project = function(dir) - while dir ~= "" and dir ~= "/" do - if vim.fn.filereadable(dir .. "/gradlew") == 1 then - return true - end - dir = vim.fn.fnamemodify(dir, ":h") - end - - return false -end - -M.is_maven_project = function(dir) - while dir ~= "" and dir ~= "/" do - if vim.fn.filereadable(dir .. "/pom.xml") == 1 then - return true - end - dir = vim.fn.fnamemodify(dir, ":h") - end - - return false -end - -return M diff --git a/home/neovim/overseer/templates/gmailctl_apply.lua b/home/neovim/overseer/templates/gmailctl_apply.lua deleted file mode 100644 index 7cd2fa29..00000000 --- a/home/neovim/overseer/templates/gmailctl_apply.lua +++ /dev/null @@ -1,12 +0,0 @@ -return { - name = "gmailctl apply", - builder = function() - return { - cmd = { "gmailctl" }, - args = { "apply" }, - } - end, - condition = { - filetype = { "jsonnet" }, - }, -} diff --git a/home/neovim/overseer/templates/java_gradle/init.lua b/home/neovim/overseer/templates/java_gradle/init.lua deleted file mode 100644 index 4fd493ab..00000000 --- a/home/neovim/overseer/templates/java_gradle/init.lua +++ /dev/null @@ -1,57 +0,0 @@ -local overseer_lib = require("overseer_lib") - -return { - generator = function(search) - if not overseer_lib.is_gradle_project(search.dir) then - return {} - end - - return { - { - name = "gradlew: build", - builder = function() - return { - cmd = { "./gradlew" }, - args = { "build" }, - } - end, - }, - { - name = "gradlew: test", - builder = function() - return { - cmd = { "./gradlew" }, - args = { "test" }, - } - end, - }, - { - name = "gradlew: clean", - builder = function() - return { - cmd = { "./gradlew" }, - args = { "clean" }, - } - end, - }, - { - name = "gradlew: bootRun", - builder = function() - return { - cmd = { "./gradlew" }, - args = { "bootRun" }, - } - end, - }, - { - name = "gradlew: spotlessApply", - builder = function() - return { - cmd = { "./gradlew" }, - args = { "spotlessApply" }, - } - end, - }, - } - end, -} diff --git a/home/neovim/overseer/templates/java_maven/init.lua b/home/neovim/overseer/templates/java_maven/init.lua deleted file mode 100644 index 32cb54ea..00000000 --- a/home/neovim/overseer/templates/java_maven/init.lua +++ /dev/null @@ -1,30 +0,0 @@ -local overseer_lib = require("overseer_lib") - -return { - generator = function(search) - if not overseer_lib.is_maven_project(search.dir) then - return {} - end - - return { - { - name = "mvn: test", - builder = function() - return { - cmd = { "mvn" }, - args = { "test" }, - } - end, - }, - { - name = "mvn: clean package", - builder = function() - return { - cmd = { "mvn" }, - args = { "clean", "package" }, - } - end, - }, - } - end, -} diff --git a/home/neovim/overseer/templates/nixos_rebuild_boot.lua b/home/neovim/overseer/templates/nixos_rebuild_boot.lua deleted file mode 100644 index c2fd6aeb..00000000 --- a/home/neovim/overseer/templates/nixos_rebuild_boot.lua +++ /dev/null @@ -1,12 +0,0 @@ -return { - name = "nixos rebuild boot", - builder = function() - return { - cmd = { "nh" }, - args = { "os", "boot" }, - } - end, - condition = { - dir = "~/code/nixos-config", - }, -} diff --git a/home/neovim/overseer/templates/nixos_rebuild_switch.lua b/home/neovim/overseer/templates/nixos_rebuild_switch.lua deleted file mode 100644 index 6cf2ce7a..00000000 --- a/home/neovim/overseer/templates/nixos_rebuild_switch.lua +++ /dev/null @@ -1,12 +0,0 @@ -return { - name = "nixos rebuild switch", - builder = function() - return { - cmd = { "nh" }, - args = { "os", "switch" }, - } - end, - condition = { - dir = "~/code/nixos-config", - }, -} diff --git a/home/neovim/overseer/templates/nixos_update_secrets.lua b/home/neovim/overseer/templates/nixos_update_secrets.lua deleted file mode 100644 index 24267e5f..00000000 --- a/home/neovim/overseer/templates/nixos_update_secrets.lua +++ /dev/null @@ -1,12 +0,0 @@ -return { - name = "update secrets", - builder = function() - return { - cmd = { "nix" }, - args = { "flake", "lock", "--update-input", "secrets" }, - } - end, - condition = { - dir = "~/code/nixos-config", - }, -} diff --git a/home/neovim/overseer/templates/skaffold_dev.lua b/home/neovim/overseer/templates/skaffold_dev.lua deleted file mode 100644 index 7e67baff..00000000 --- a/home/neovim/overseer/templates/skaffold_dev.lua +++ /dev/null @@ -1,12 +0,0 @@ -return { - name = "skaffold dev", - builder = function() - return { - cmd = { "skaffold" }, - args = { "dev" }, - } - end, - condition = { - filetype = "yaml", - }, -} diff --git a/home/neovim/plenary/default.nix b/home/neovim/plenary/default.nix deleted file mode 100644 index 6111b769..00000000 --- a/home/neovim/plenary/default.nix +++ /dev/null @@ -1,10 +0,0 @@ -{pkgs, ...}: { - programs.neovim.plugins = with pkgs.vimPlugins; [ - { - plugin = plenary-nvim; - config = '' - ''; - type = "lua"; - } - ]; -} diff --git a/home/neovim/rainbow-csv/default.nix b/home/neovim/rainbow-csv/default.nix deleted file mode 100644 index ffcd8b21..00000000 --- a/home/neovim/rainbow-csv/default.nix +++ /dev/null @@ -1,21 +0,0 @@ -{pkgs, ...}: let - rainbow-csv-nvim = pkgs.vimUtils.buildVimPlugin { - name = "rainbow-csv-nvim"; - src = pkgs.fetchFromGitHub { - owner = "cameron-wags"; - repo = "rainbow_csv.nvim"; - rev = "7f3fddfe813641035fac2cdf94c2ff69bb0bf0b9"; - sha256 = "sha256-/XHQd/+sqhVeeMAkcKNvFDKFuFecChrgp56op3KQAhs="; - }; - }; -in { - programs.neovim.plugins = [ - { - plugin = rainbow-csv-nvim; - config = '' - require('rainbow_csv').setup({}) - ''; - type = "lua"; - } - ]; -} diff --git a/home/neovim/render-markdown/default.nix b/home/neovim/render-markdown/default.nix deleted file mode 100644 index 2ef10c12..00000000 --- a/home/neovim/render-markdown/default.nix +++ /dev/null @@ -1,16 +0,0 @@ -{pkgs, ...}: { - programs.neovim.extraPackages = with pkgs; [ - python3Packages.pylatexenc - ]; - programs.neovim.plugins = with pkgs.vimPlugins; [ - { - plugin = render-markdown-nvim; - config = '' - require('render-markdown').setup({ - file_types = {'markdown', 'Avante'}, - }) - ''; - type = "lua"; - } - ]; -} diff --git a/home/neovim/telescope/default.nix b/home/neovim/telescope/default.nix deleted file mode 100644 index 2b097939..00000000 --- a/home/neovim/telescope/default.nix +++ /dev/null @@ -1,87 +0,0 @@ -{pkgs, ...}: { - programs.neovim.plugins = with pkgs.vimPlugins; [ - { - plugin = telescope-nvim; - config = '' - local builtin = require("telescope.builtin") - local utils = require("telescope.utils") - require("telescope").setup({ - defaults = { - mappings = { - i = { - [""] = require("telescope.actions").select_horizontal, - }, - n = { - [""] = require("telescope.actions").select_horizontal, - }, - }, - }, - pickers = { - find_files = { - hidden = true, - }, - }, - }) - require("telescope").load_extension("fzf") - local wk = require("which-key") - wk.add( - { - { "", group = "Find[ ](Telescope)" }, - { ".", function() builtin.find_files({ cwd = utils.buffer_dir() }) end, desc = "Files in CWD" }, - { "", "Telescope git_files", desc = "Version Controlled Files" }, - { "?", "Telescope keymaps", desc = "Vim Keymap Cheatsheet" }, - { "b", "Telescope buffers", desc = "[B]uffers" }, - { "c", "Telescope commands", desc = "[C]ommands" }, - { "d", "Telescope command_history", desc = "Comman[d] History" }, - { "e", "Telescope help_tags", desc = "H[e]lp Tags" }, - { "f", "Telescope find_files", desc = "All [F]iles" }, - { "g", "Telescope live_grep", desc = "[G]rep" }, - } - ) - ''; - type = "lua"; - } - { - plugin = telescope-fzf-native-nvim; - } - { - plugin = telescope-frecency-nvim; - config = '' - require("telescope").setup({ - extensions = { - frecency = { - show_scores = true, - auto_validate = false, -- manually gc with :FrecencyValidate - }, - }, - }) - require("telescope").load_extension("frecency") - local wk = require("which-key") - wk.add( - { - { "h", "Telescope frecency workspace=CWD", desc = "History (Frecency)" }, - } - ) - ''; - type = "lua"; - } - { - plugin = telescope-undo-nvim; - config = '' - require("telescope").setup({ - extensions = { - undo = {}; - }, - }) - require("telescope").load_extension("undo") - local wk = require("which-key") - wk.add( - { - { "u", "Telescope undo", desc = "[U]ndo Tree" }, - } - ) - ''; - type = "lua"; - } - ]; -} diff --git a/home/neovim/toggleterm/default.nix b/home/neovim/toggleterm/default.nix deleted file mode 100644 index 13616f02..00000000 --- a/home/neovim/toggleterm/default.nix +++ /dev/null @@ -1,14 +0,0 @@ -{pkgs, ...}: { - programs.neovim.plugins = with pkgs.vimPlugins; [ - { - plugin = toggleterm-nvim; - config = '' - require("toggleterm").setup({ - open_mapping = [[]], - direction = 'float', - }) - ''; - type = "lua"; - } - ]; -} diff --git a/home/neovim/treesitter/default.nix b/home/neovim/treesitter/default.nix deleted file mode 100644 index aa280bdc..00000000 --- a/home/neovim/treesitter/default.nix +++ /dev/null @@ -1,36 +0,0 @@ -{pkgs, ...}: { - programs.neovim.extraPackages = [ - pkgs.gcc - pkgs.tree-sitter - ]; - - programs.neovim.plugins = with pkgs.vimPlugins; [ - # TODO: This is Neovim-Native after 0.10, see https://github.com/nvim-treesitter/playground - { - plugin = playground; - config = '' - ''; - type = "lua"; - } - { - plugin = nvim-treesitter.withAllGrammars; - config = builtins.readFile ./treesitter.lua; - runtime = { - "after/queries/nix/injections.scm".source = ./queries/nix/injections.scm; - }; - type = "lua"; - } - { - plugin = nvim-treesitter-context; # ip, ap, etc... from treesitter! - config = '' - ''; - type = "lua"; - } - { - plugin = nvim-treesitter-textobjects; # ip, ap, etc... from treesitter! - config = '' - ''; - type = "lua"; - } - ]; -} diff --git a/home/neovim/treesitter/queries/nix/injections.scm b/home/neovim/treesitter/queries/nix/injections.scm deleted file mode 100644 index 6db97763..00000000 --- a/home/neovim/treesitter/queries/nix/injections.scm +++ /dev/null @@ -1,91 +0,0 @@ -;extends -; extraLuaConfig -> Lua -(binding - attrpath: (attrpath - (identifier) @_path) - expression: [ - (string_expression - ((string_fragment) @injection.content - (#set! injection.language "lua"))) - (indented_string_expression - ((string_fragment) @injection.content - (#set! injection.language "lua"))) - ] - (#match? @_path "^extraLuaConfig$") - (#set! injection.combined)) - -; neovim.extraConfig -> Vim -(binding - ( - (attrpath - (identifier) @_outer - (identifier) @_inner - ) - ) - (attrset_expression - (binding_set - (binding - attrpath: (attrpath - (identifier) @_path) - expression: [ - (string_expression - ((string_fragment) @injection.content - (#set! injection.language "vim"))) - (indented_string_expression - ((string_fragment) @injection.content - (#set! injection.language "vim"))) - ] - (#match? @_path "^extraConfig$") - (#match? @_inner "^neovim$") - (#set! injection.combined) - ) - ) - ) -) - -; inline vim plugin configs of type Lua -(binding_set - binding: (binding - attrpath: (attrpath - (identifier) @_path) - expression: [ - (string_expression - ((string_fragment) @injection.content - (#set! injection.language "lua"))) - (indented_string_expression - ((string_fragment) @injection.content - (#set! injection.language "lua"))) - ] - ) - binding: (binding - attrpath: (attrpath - (identifier) @_typearg) - expression: [ - (string_expression - ((string_fragment) @_typeval - )) - (indented_string_expression - ((string_fragment) @_typeval - )) - ] - ) - (#match? @_typearg "^type$") - (#match? @_typeval "^lua$") - (#match? @_path "^config$") - (#set! injection.combined) -) - -; style -> CSS -(binding - attrpath: (attrpath - (identifier) @_path) - expression: [ - (string_expression - ((string_fragment) @injection.content - (#set! injection.language "css"))) - (indented_string_expression - ((string_fragment) @injection.content - (#set! injection.language "css"))) - ] - (#match? @_path "^style$") - (#set! injection.combined)) diff --git a/home/neovim/treesitter/treesitter.lua b/home/neovim/treesitter/treesitter.lua deleted file mode 100644 index c1f7bbdd..00000000 --- a/home/neovim/treesitter/treesitter.lua +++ /dev/null @@ -1,49 +0,0 @@ -local function ts_disable_long_files(_, bufnr) - return vim.api.nvim_buf_line_count(bufnr) > 5000 -end - -local disabled_languages = { - "csv", -- In favor of rainbow-csv-nvim -} - --- Defer Treesitter setup after first render to improve startup time of 'nvim {filename}' -vim.defer_fn(function() - require('nvim-treesitter.configs').setup { - auto_install = false, - highlight = { - enable = true, - disable = function(lang, bufnr) - return vim.tbl_contains(disabled_languages, lang) or ts_disable_long_files(lang, bufnr) - end, - }, - indent = { enable = true }, - incremental_selection = { - enable = true, - keymaps = { - init_selection = '', - node_incremental = '', - scope_incremental = false, -- Disable to avoid 'grc' conflict with mini.operators - node_decremental = '', - }, - }, - } - - -- Add additional intuitive keybindings for treesitter selection - -- These complement the bindings and work in visual mode - vim.keymap.set('x', '+', function() - require('nvim-treesitter.incremental_selection').node_incremental() - end, { desc = 'Treesitter: Expand selection' }) - - vim.keymap.set('x', '_', function() - require('nvim-treesitter.incremental_selection').node_decremental() - end, { desc = 'Treesitter: Shrink selection' }) - - -- Document the keybindings with which-key - local wk = require("which-key") - wk.add({ - { "", desc = "Treesitter: Init/Expand selection", mode = {"n", "x"} }, - { "", desc = "Treesitter: Shrink selection", mode = "x" }, - { "+", desc = "Treesitter: Expand selection", mode = "x" }, - { "_", desc = "Treesitter: Shrink selection", mode = "x" }, - }) -end, 0) diff --git a/home/neovim/trouble/default.nix b/home/neovim/trouble/default.nix deleted file mode 100644 index 04e163fe..00000000 --- a/home/neovim/trouble/default.nix +++ /dev/null @@ -1,9 +0,0 @@ -{pkgs, ...}: { - programs.neovim.plugins = with pkgs.vimPlugins; [ - { - plugin = trouble-nvim; - config = builtins.readFile ./trouble.lua; - type = "lua"; - } - ]; -} diff --git a/home/neovim/trouble/trouble.lua b/home/neovim/trouble/trouble.lua deleted file mode 100644 index ab0f5545..00000000 --- a/home/neovim/trouble/trouble.lua +++ /dev/null @@ -1,19 +0,0 @@ -local wk = require("which-key") -wk.add( - { - { "x", group = "Trouble" }, - { "xx", "Trouble diagnostics toggle focus=false", desc = "Diagnostics", mode = { "n", "v" } }, - { "xX", "Trouble diagnostics toggle filter.buf=0", desc = "Buffer Diagnostics", mode = { "n", "v" } }, - { "xl", "Trouble loclist toggle", desc = "[L]ocation List" }, - { "xq", "Trouble quickfix toggle", desc = "[Q]uickfix" }, - { "xs", "Trouble symbols toggle focus=false", desc = "[S]ymbols" }, - } -) -require("trouble").setup({ - action_keys = { -- key mappings for actions in the trouble list - open_split = { "" }, -- open buffer in new split - open_vsplit = { "" }, -- open buffer in new vsplit - previous = "l", -- previous item - next = "k" -- next item - }, -}) diff --git a/home/neovim/undotree/default.nix b/home/neovim/undotree/default.nix deleted file mode 100644 index 331724cf..00000000 --- a/home/neovim/undotree/default.nix +++ /dev/null @@ -1,7 +0,0 @@ -{pkgs, ...}: { - programs.neovim.plugins = with pkgs.vimPlugins; [ - { - plugin = undotree; - } - ]; -} diff --git a/home/neovim/vim-be-good/default.nix b/home/neovim/vim-be-good/default.nix deleted file mode 100644 index a52a174a..00000000 --- a/home/neovim/vim-be-good/default.nix +++ /dev/null @@ -1,7 +0,0 @@ -{pkgs, ...}: { - programs.neovim.plugins = with pkgs.vimPlugins; [ - { - plugin = vim-be-good; - } - ]; -} diff --git a/home/neovim/vim-terraform/default.nix b/home/neovim/vim-terraform/default.nix deleted file mode 100644 index 3bfaedcf..00000000 --- a/home/neovim/vim-terraform/default.nix +++ /dev/null @@ -1,7 +0,0 @@ -{pkgs, ...}: { - programs.neovim.plugins = with pkgs.vimPlugins; [ - { - plugin = vim-terraform; - } - ]; -} diff --git a/home/neovim/vim-visual-multi/default.nix b/home/neovim/vim-visual-multi/default.nix deleted file mode 100644 index 4980a21b..00000000 --- a/home/neovim/vim-visual-multi/default.nix +++ /dev/null @@ -1,13 +0,0 @@ -{pkgs, ...}: { - programs.neovim.plugins = with pkgs.vimPlugins; [ - { - plugin = vim-visual-multi; - config = '' - let g:VM_maps = {} - let g:VM_maps['Motion ,'] = ',,' " Removes conflict with , as LSP Leader - let g:VM_maps['Goto Prev'] = '[[' " Removes conflict with vim-unimpaired - let g:VM_maps['Goto Next'] = ']]' " Removes conflict with vim-unimpaired - ''; - } - ]; -} diff --git a/home/neovim/web-devicons/default.nix b/home/neovim/web-devicons/default.nix deleted file mode 100644 index 5968cae5..00000000 --- a/home/neovim/web-devicons/default.nix +++ /dev/null @@ -1,15 +0,0 @@ -{pkgs, ...}: { - programs.neovim.plugins = [ - { - # Intentionally put a minimal web-devicons plugin config BEFORE nvim-tree - # so that nvim-tree sees a ready devicons provider (which is then mocked - # by mini.icons). This avoids lazy-loading races in some plugin managers. - plugin = pkgs.vimPlugins.nvim-web-devicons; - config = '' - -- Minimal setup; will be overridden by mini.icons.mock_nvim_web_devicons() - require('nvim-web-devicons').setup({ color_icons = true, default = true }) - ''; - type = "lua"; - } - ]; -} diff --git a/home/neovim/yank-file-line/default.nix b/home/neovim/yank-file-line/default.nix deleted file mode 100644 index 30305e61..00000000 --- a/home/neovim/yank-file-line/default.nix +++ /dev/null @@ -1,3 +0,0 @@ -{...}: { - programs.neovim.extraLuaConfig = builtins.readFile ./yank-file-line.lua; -} diff --git a/home/neovim/yank-file-line/yank-file-line.lua b/home/neovim/yank-file-line/yank-file-line.lua deleted file mode 100644 index 7dd2fb52..00000000 --- a/home/neovim/yank-file-line/yank-file-line.lua +++ /dev/null @@ -1,21 +0,0 @@ -vim.keymap.set('v', 'y', function() - local file = vim.fn.expand('%:p') - local git_root = vim.fn.systemlist('git rev-parse --show-toplevel')[1] - local relative_path - if git_root and vim.fn.isdirectory(git_root) == 1 then - relative_path = file:sub(#git_root + 2) - else - relative_path = vim.fn.expand('%:.') - end - local start_line = vim.fn.line('v') - local end_line = vim.fn.line('.') - local line_part - if start_line == end_line then - line_part = tostring(start_line) - else - line_part = math.min(start_line, end_line) .. '-' .. math.max(start_line, end_line) - end - local result = relative_path .. ':' .. line_part - vim.fn.setreg('+', result) - vim.notify('Copied: ' .. result) -end, { desc = '[Y]ank file:line to clipboard' }) diff --git a/home/networkmanager-dmenu/config.ini b/home/networkmanager-dmenu/config.ini deleted file mode 100644 index b4a52a67..00000000 --- a/home/networkmanager-dmenu/config.ini +++ /dev/null @@ -1,48 +0,0 @@ -[dmenu] -dmenu_command = fuzzel --dmenu -# # Note that dmenu_command can contain arguments as well like: -# # `dmenu_command = rofi -dmenu -i -theme nmdm` -# # `dmenu_command = rofi -dmenu -width 30 -i` -# # `dmenu_command = dmenu -i -l 25 -b -nb #909090 -nf #303030` -# # `dmenu_command = fuzzel --dmenu` -# # `dmenu_command = wofi --dmenu` -# active_chars = == -# highlight = # (Default: False) use highlighting instead of active_chars (only applicable to Rofi / Wofi) -# highlight_fg = # (Default: None) foreground color of active connection (only applicable to Wofi) -# highlight_bg = # (Default: None) background color of active connection (only applicable to Wofi) -# highlight_bold = # (Default: True) make active connection bold (only applicable to Wofi) -# compact = # (Default: False). Remove extra spacing from display -# pinentry = # (Default: None) e.g. `pinentry-gtk` -# wifi_chars = -# wifi_chars = ▂▄▆█ -# wifi_icons = -# wifi_icons = 󰤯󰤟󰤢󰤥󰤨 -# format = -# format = {name} {sec} {bars} -# # Available variables are: -# # * {name} - Access point name -# # * {sec} - Security type -# # * {signal} - Signal strength on a scale of 0-100 -# # * {bars} - Bar-based display of signal strength (see wifi_chars) -# # * {icon} - Icon-based display of signal strength (see wifi_icons) -# # * {max_len_name} and {max_len_sec} are the maximum lengths of {name} / {sec} -# # respectively and may be useful for formatting. -# list_saved = # (Default: False) list saved connections - -[dmenu_passphrase] -# # Uses the -password flag for Rofi, -x for bemenu. For dmenu, sets -nb and -# # -nf to the same color or uses -P if the dmenu password patch is applied -# # https://tools.suckless.org/dmenu/patches/password/ -# obscure = True -# obscure_color = #222222 - -[pinentry] -# description = (Default: Get network password) -# prompt = (Default: Password:) - -[editor] -# terminal = -# gui_if_available = (Default: True) - -[nmdm] -# rescan_delay = # (seconds to wait after a wifi rescan before redisplaying the results) diff --git a/home/networkmanager-dmenu/default.nix b/home/networkmanager-dmenu/default.nix deleted file mode 100644 index 2d88e28c..00000000 --- a/home/networkmanager-dmenu/default.nix +++ /dev/null @@ -1,4 +0,0 @@ -{pkgs, ...}: { - home.packages = [pkgs.networkmanager_dmenu]; - xdg.configFile."networkmanager-dmenu/config.ini".source = ./config.ini; -} diff --git a/home/nh/default.nix b/home/nh/default.nix deleted file mode 100644 index 05b1744f..00000000 --- a/home/nh/default.nix +++ /dev/null @@ -1,6 +0,0 @@ -{...}: { - programs.nh = { - enable = true; - flake = "/home/farlion/code/nixos-config"; - }; -} diff --git a/home/niri/default.nix b/home/niri/default.nix deleted file mode 100644 index 59c04146..00000000 --- a/home/niri/default.nix +++ /dev/null @@ -1,640 +0,0 @@ -{ - config, - isNvidia, - lib, - osConfig, - pkgs, - ... -}: -with lib; let - isNumenor = osConfig.networking.hostName == "numenor"; - - leftScreen = - if isNumenor - then "HDMI-A-2" - else null; - mainScreen = - if isNumenor - then "DP-1" - else "eDP-1"; - rightScreen = - if isNumenor - then "HDMI-A-1" - else null; - - locker = "${pkgs.bash}/bin/bash -c '${pkgs.procps}/bin/pgrep -x swaylock || ${pkgs.swaylock-effects}/bin/swaylock --daemonize'"; - suspender = "${pkgs.systemd}/bin/systemctl suspend-then-hibernate"; - - # Wallpaper, until stylix supports it :) - wallpaperSetter = pkgs.writeShellApplication { - name = "niri-set-wallpaper"; - runtimeInputs = [pkgs.swaybg pkgs.procps]; - text = builtins.readFile ./scripts/niri-set-wallpaper.sh; - }; - - # Window Picker a la rofi - windowPicker = pkgs.writeShellApplication { - name = "niri-pick-window"; - runtimeInputs = [pkgs.niri pkgs.unstable.fuzzel pkgs.jq]; - text = builtins.readFile ./scripts/niri-pick-window.sh; - }; - - # Calculator via fuzzel + qalc - fuzzelCalc = pkgs.writeShellApplication { - name = "niri-qalc"; - runtimeInputs = [pkgs.unstable.fuzzel pkgs.libqalculate pkgs.wl-clipboard pkgs.libnotify]; - text = builtins.readFile ./scripts/niri-qalc.sh; - }; - - # Workspace reorderer - maintains logical order after moving workspaces between monitors - workspaceReorderer = pkgs.writeShellApplication { - name = "niri-reorder-workspaces"; - runtimeInputs = [pkgs.niri pkgs.jq]; - text = builtins.readFile ./scripts/niri-reorder-workspaces.sh; - }; - - # Auto-column - consumes new windows into columns on vertical monitors - autoColumn = pkgs.writeShellApplication { - name = "niri-auto-column"; - runtimeInputs = [pkgs.niri pkgs.jq pkgs.coreutils]; - text = builtins.readFile ./scripts/niri-auto-column.sh; - }; - - # Open a command and move its window to a workspace once title matches - openOnWorkspace = pkgs.writeShellApplication { - name = "niri-open-on-workspace"; - runtimeInputs = [pkgs.niri pkgs.jq]; - text = builtins.readFile ./scripts/niri-open-on-workspace.sh; - }; - - niriBinds = { - suffixes, - prefixes, - substitutions ? {}, - }: let - replacer = replaceStrings (attrNames substitutions) (attrValues substitutions); - format = prefix: suffix: let - actual-suffix = - if isList suffix.action - then { - action = head suffix.action; - args = tail suffix.action; - } - else { - inherit (suffix) action; - args = []; - }; - - action = replacer "${prefix.action}-${actual-suffix.action}"; - in { - name = "${prefix.key}+${suffix.key}"; - value.action.${action} = actual-suffix.args; - }; - pairs = attrs: fn: - concatMap ( - key: - fn { - inherit key; - action = attrs.${key}; - } - ) (attrNames attrs); - in - listToAttrs (pairs prefixes (prefix: pairs suffixes (suffix: [(format prefix suffix)]))); -in { - home.packages = with pkgs; [ - brightnessctl # For brightness +/- keys - fuzzelCalc # niri-qalc - hyprmagnifier # Screen magnifier for Wayland - playerctl # For play/pause etc... controlling media players that implement MPRIS - qt5.qtwayland # Needed for QT_QPA_PLATFORM=wayland - swaybg # Minmal wallpaper setter for Sway - wallpaperSetter # Specialization-aware wallpaper setting - windowPicker # niri-pick-window - workspaceReorderer # niri-reorder-workspaces - xwayland-satellite # For apps that need Xwayland - ]; - - programs.swaylock = { - enable = true; - package = pkgs.swaylock-effects; - settings = { - debug = false; - show-failed-attempts = true; - ignore-empty-password = true; - screenshots = true; - effect-pixelate = 10; # Pixellation level (higher = more pixelated) - effect-blur = "7x5"; - }; - }; - - services.swayidle = { - enable = true; - events = [ - { - event = "before-sleep"; - command = "${locker}"; - } - { - event = "lock"; - command = "${locker}"; - } - ]; - timeouts = [ - { - timeout = 360; - command = "${locker}"; - } - { - timeout = 370; - command = "/run/current-system/sw/bin/niri msg action power-off-monitors"; - resumeCommand = "${pkgs.coreutils}/bin/sleep 1; /run/current-system/sw/bin/niri msg action power-on-monitors"; - } - { - timeout = 1800; - command = "${suspender}"; - } - ]; - }; - - # Fix swayidle service dependencies for Niri/Wayland session - # Fails to boot with default settings - systemd.user.services.swayidle = { - Unit = { - After = ["niri.service" "graphical-session.target"]; - Wants = ["graphical-session.target"]; - # Override the default ConditionEnvironment to be less strict - ConditionEnvironment = lib.mkForce []; - }; - Service = { - # Add a small delay to double-ensure Wayland display is ready - ExecStartPre = "${pkgs.coreutils}/bin/sleep 2"; - # Restart the service if it fails (useful for session restarts) - Restart = lib.mkForce "on-failure"; - RestartSec = "5"; - }; - }; - - # Auto-column service for vertical monitors - systemd.user.services.niri-auto-column = lib.mkIf isNumenor { - Unit = { - Description = "Auto-consume windows into columns on vertical monitors"; - After = ["niri.service" "graphical-session.target"]; - Wants = ["graphical-session.target"]; - }; - Service = { - ExecStart = "${autoColumn}/bin/niri-auto-column"; - Restart = "on-failure"; - RestartSec = "5"; - }; - Install = { - WantedBy = ["graphical-session.target"]; - }; - }; - - programs.wleave = { - enable = true; - }; - - # Wallpaper, until stylix supports it :) - home.file.".local/share/wallpapers/gruvbox-light.png".source = ./wallpapers/gruvbox-light-rainbow.png; - home.file.".local/share/wallpapers/gruvbox-dark.png".source = ./wallpapers/gruvbox-dark-rainbow.png; - - # TODO: Activate once the Niri flake supports niri 25.11 - # Per-output layout settings for vertical monitors (raw KDL - not exposed in niri-flake settings) - # programs.niri.config = - # lib.optionalString (leftScreen != null) '' - # output "${leftScreen}" { - # layout { - # default-column-width { proportion 1.0; } - # } - # } - # '' - # + lib.optionalString (rightScreen != null) '' - # output "${rightScreen}" { - # layout { - # default-column-width { proportion 1.0; } - # } - # } - # ''; - - programs.niri.settings = rec { - # Environment - environment = { - NIXOS_OZONE_WL = "1"; # Enable Ozone-Wayland for Electron apps and Chromium, see https://nixos.wiki/wiki/Wayland - }; - - # Input Settings - input = { - keyboard = { - xkb = { - layout = "us,de,ua,pt"; - options = "eurosign:e,terminate:ctrl_alt_bksp"; - }; - }; - touchpad = { - dwt = true; # Disable touchpad while typing - disabled-on-external-mouse = false; - natural-scroll = false; - tap = true; - tap-button-map = "left-right-middle"; - }; - focus-follows-mouse.enable = true; - }; - - # Cursor Settings - cursor = { - hide-after-inactive-ms = 3000; - hide-when-typing = true; - }; - - # Startup - spawn-at-startup = [ - {command = ["${pkgs.bash}/bin/bash" "-c" "sleep 10 && systemctl --user restart xdg-desktop-portal"];} # Hacks around a timing prob with xdg-desktop-portal on first boot, see https://github.com/sodiboo/niri-flake/issues/509 - {command = ["systemctl" "--user" "restart" "kanshi"];} - {command = ["systemctl" "--user" "restart" "app-blueman@autostart"];} - {command = ["systemctl" "--user" "start" "gnome-keyring-ssh"];} # Start GNOME Keyring SSH agent - {command = ["obsidian"];} - {command = ["ytmdesktop" "--password-store=gnome-libsecret"];} - # {command = ["seahorse"];} # To unlock keyring - {command = ["${wallpaperSetter}/bin/niri-set-wallpaper"];} # Set wallpaper - {command = ["wlsunset-waybar"];} - {command = ["${openOnWorkspace}/bin/niri-open-on-workspace" "${workspaces."00".name}" "ChatGPT" "zen" "--new-window" "https://chatgpt.com/"];} - {command = ["${openOnWorkspace}/bin/niri-open-on-workspace" "${workspaces."09".name}" "[Vv]ikunja" "zen" "--new-window" "https://vikunja.hyena-byzantine.ts.net/"];} - ]; - - # Window Rules - # Find app_id or title with `niri msg windows` - window-rules = [ - { - matches = [ - {app-id = "^obsidian$";} - ]; - open-on-workspace = " 7"; - } - { - matches = [ - {app-id = "^signal$";} - {app-id = "^teams-for-linux$";} - {app-id = "^org.telegram.desktop$";} - ]; - open-on-workspace = " 8"; - } - { - matches = [ - {app-id = "^YouTube Music Desktop App$";} - ]; - open-on-workspace = " 9"; - } - { - matches = [ - {title = ".*[Vv]ikunja.*";} - ]; - open-on-workspace = " 9"; - } - { - matches = [ - {title = ".*ChatGPT.*";} - ]; - open-on-workspace = " a"; - } - # Floating windows - { - matches = [ - {title = ".*Pavucontrol.*";} - {title = ".*zoom.*";} - ]; - open-floating = true; - } - # Block from screencasting - { - matches = [ - {app-id = "^Bitwarden$";} - {app-id = "^com.obsproject.Studio$";} - ]; - block-out-from = "screen-capture"; - } - # Screen Cast Target Highlight - { - matches = [ - {is-window-cast-target = true;} - ]; - border = { - active = {color = "#f38ba8";}; - inactive = {color = "#7d0d2d";}; - }; - shadow = { - color = "#7d0d2d70"; - }; - tab-indicator = { - active = {color = "#f38ba8";}; - inactive = {color = "#7d0d2d";}; - }; - } - ]; - - # Named Workspaces - workspaces = { - "00" = { - name = " a"; - open-on-output = rightScreen; - }; - "01" = { - name = " 1"; - open-on-output = leftScreen; - }; - "02" = { - name = " 2"; - open-on-output = mainScreen; - }; - "03" = { - name = " 3"; - open-on-output = rightScreen; - }; - "04" = { - name = " 4"; - open-on-output = mainScreen; - }; - "05" = { - name = " 5"; - open-on-output = mainScreen; - }; - "06" = { - name = " 6"; - open-on-output = mainScreen; - }; - "07" = { - name = " 7"; - open-on-output = rightScreen; - }; - "08" = { - name = " 8"; - open-on-output = mainScreen; - }; - "09" = { - name = " 9"; - open-on-output = leftScreen; - }; - "10" = { - name = " 10"; - open-on-output = mainScreen; - }; - }; - - # Layout - layout = { - border = { - enable = true; - width = 2; # Default 4 - }; - - default-column-width.proportion = 1. / 2.; - - gaps = 4; # Default 16 - - preset-column-widths = [ - {proportion = 1. / 2.;} - {proportion = 1. / 3.;} - {proportion = 2. / 3.;} - ]; - - shadow = { - enable = true; - }; - }; - - # Style - prefer-no-csd = true; - - # Animations - animations = { - workspace-switch.enable = false; - }; - - # Keybindings - hotkey-overlay.skip-at-startup = true; - binds = with config.lib.niri.actions; - lib.attrsets.mergeAttrsList [ - { - "Mod+Shift+Slash".action = show-hotkey-overlay; - - "Mod+Return".action = spawn "alacritty"; - "Mod+Return".hotkey-overlay.title = "Open a Terminal: alacritty"; - "Mod+D".action = spawn "fuzzel"; - "Mod+D".hotkey-overlay.title = "Run an Application: fuzzel"; - "Mod+Shift+D".action = spawn "${windowPicker}/bin/niri-pick-window"; - "Mod+Shift+D".hotkey-overlay.title = "Pick a Window: niri-pick-window"; - "Mod+Shift+X".action = spawn-sh "swaylock --daemonize && niri msg action power-off-monitors"; - "Mod+Shift+X".hotkey-overlay.title = "Lock screen and turn off monitors"; - "Mod+z".action = spawn "hyprmagnifier"; - "Mod+z".hotkey-overlay.title = "Screen magnifier"; - "Mod+Shift+z".action = power-off-monitors; - "Mod+Shift+z".hotkey-overlay.title = "Power off Monitors"; - - "XF86AudioRaiseVolume".action = spawn-sh "wpctl set-volume @DEFAULT_AUDIO_SINK@ 0.1+"; - "XF86AudioRaiseVolume".allow-when-locked = true; - "XF86AudioLowerVolume".action = spawn-sh "wpctl set-volume @DEFAULT_AUDIO_SINK@ 0.1-"; - "XF86AudioLowerVolume".allow-when-locked = true; - "XF86AudioMute".action = spawn-sh "wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle"; - "XF86AudioMute".allow-when-locked = true; - "XF86AudioMicMute".action = spawn-sh "wpctl set-mute @DEFAULT_AUDIO_SOURCE@ toggle"; - "XF86AudioMicMute".allow-when-locked = true; - "XF86MonBrightnessUp".action = spawn-sh "brightnessctl --class=backlight set 10%+"; - "XF86MonBrightnessUp".allow-when-locked = true; - - "XF86MonBrightnessDown".action = spawn-sh "brightnessctl --class=backlight set 10%-"; - "XF86MonBrightnessDown".allow-when-locked = true; - - "Mod+Shift+Q".action = close-window; - "Mod+Shift+Q".repeat = false; - } - (niriBinds { - suffixes."Left" = "column-left"; - suffixes."j" = "column-left"; - suffixes."Down" = "window-down"; - suffixes."k" = "window-down"; - suffixes."Up" = "window-up"; - suffixes."l" = "window-up"; - suffixes."Right" = "column-right"; - suffixes."semicolon" = "column-right"; - prefixes."Mod" = "focus"; - prefixes."Mod+Ctrl" = "move"; - prefixes."Mod+Shift" = "focus-monitor"; - prefixes."Mod+Shift+Ctrl" = "move-workspace-to-monitor"; - substitutions."monitor-column" = "monitor"; - substitutions."monitor-window" = "monitor"; - }) - (niriBinds { - suffixes."Home" = "first"; - suffixes."End" = "last"; - prefixes."Mod" = "focus-column"; - prefixes."Mod+Ctrl" = "move-column-to"; - }) - (niriBinds { - suffixes."U" = "workspace-down"; - suffixes."Page_Down" = "workspace-down"; - suffixes."I" = "workspace-up"; - suffixes."Page_Up" = "workspace-up"; - prefixes."Mod" = "focus"; - prefixes."Mod+Ctrl" = "move-window-to"; - prefixes."Mod+Shift" = "move"; - }) - (niriBinds { - suffixes = { - "a" = ["workspace" "${workspaces."00".name}"]; - "1" = ["workspace" "${workspaces."01".name}"]; - "2" = ["workspace" "${workspaces."02".name}"]; - "3" = ["workspace" "${workspaces."03".name}"]; - "4" = ["workspace" "${workspaces."04".name}"]; - "5" = ["workspace" "${workspaces."05".name}"]; - "6" = ["workspace" "${workspaces."06".name}"]; - "7" = ["workspace" "${workspaces."07".name}"]; - "8" = ["workspace" "${workspaces."08".name}"]; - "9" = ["workspace" "${workspaces."09".name}"]; - "0" = ["workspace" "${workspaces."10".name}"]; - }; - prefixes."Mod" = "focus"; - prefixes."Mod+Ctrl" = "move-column-to"; - }) - { - "Mod+BracketLeft".action = consume-or-expel-window-left; - "Mod+BracketRight".action = consume-or-expel-window-right; - - "Mod+Comma".action = consume-window-into-column; - "Mod+Period".action = expel-window-from-column; - - "Mod+R".action = switch-preset-column-width; - "Mod+Shift+R".action = switch-preset-window-height; - "Mod+Ctrl+R".action = reset-window-height; - - "Mod+F".action = maximize-column; - "Mod+Shift+F".action = fullscreen-window; - "Mod+Ctrl+F".action = expand-column-to-available-width; - - "Mod+C".action = center-column; - "Mod+Ctrl+C".action = center-visible-columns; - - "Mod+Minus".action = set-column-width "-10%"; - "Mod+Equal".action = set-column-width "+10%"; - "Mod+Shift+Minus".action = set-window-height "-10%"; - "Mod+Shift+Equal".action = set-window-height "+10%"; - - "Mod+V".action = toggle-window-floating; - "Mod+Shift+V".action = switch-focus-between-floating-and-tiling; - - "Mod+Shift+W".action = spawn-sh ( - builtins.concatStringsSep "; " [ - "systemctl --user restart waybar.service" - "${wallpaperSetter}/bin/niri-set-wallpaper" - ] - ); - "Mod+Shift+W".hotkey-overlay.title = "Restart Waybar"; - - "Mod+Space".action = switch-layout "next"; - "Mod+Shift+Space".action = switch-layout "prev"; - - "Print".action.screenshot = []; - "Print".hotkey-overlay.title = "Screenshot via Niri"; - "Mod+Print".action = spawn "satty-screenshot"; - "Mod+Print".hotkey-overlay.title = "Screenshot via Satty"; - "Mod+Shift+Print".action.screenshot-screen = []; - "Mod+Shift+Print".hotkey-overlay.title = "Instant Screenshot"; - - # Applications such as remote-desktop clients and software KVM switches may - # request that niri stops processing the keyboard shortcuts defined here - # so they may, for example, forward the key presses as-is to a remote machine. - # It's a good idea to bind an escape hatch to toggle the inhibitor, - # so a buggy application can't hold your session hostage. - # - # The allow-inhibiting=false property can be applied to other binds as well, - # which ensures niri always processes them, even when an inhibitor is active. - "Mod+Shift+Escape".action = toggle-keyboard-shortcuts-inhibit; - "Mod+Shift+Escape".allow-inhibiting = false; - - "Ctrl+Alt+Delete".action = quit; - } - - { - # Dynamic Cast ([G]rab Window or Screen) - "Mod+G".action = set-dynamic-cast-window; - "Mod+Shift+G".action = set-dynamic-cast-monitor; - "Mod+Delete".action = clear-dynamic-cast-target; - - # Fancy Moving - "Mod+Tab".action = focus-window-down-or-column-right; - "Mod+Shift+Tab".action = focus-window-up-or-column-left; - } - { - # Browser - "Mod+b".action = spawn-sh ( - if isNvidia - then "brave --profile-directory='Default' --enable-features=VaapiVideoDecoder,VaapiVideoEncoder --password-store=seahorse" - else "brave --profile-directory='Default' --password-store=seahorse" - ); - "Mod+b".hotkey-overlay.hidden = true; - "Mod+Shift+b".action = spawn "zen"; - "Mod+Shift+b".hotkey-overlay.hidden = true; - "Mod+h".action = spawn-sh ( - if isNvidia - then "brave --profile-directory='Profile 1' --enable-features=VaapiVideoDecoder,VaapiVideoEncoder --password-store=seahorse" - else "brave --profile-directory='Profile 1' --password-store=seahorse" - ); - "Mod+h".hotkey-overlay.hidden = true; - - # Cliphist via fuzzel - "Mod+p".action = spawn "cliphist-fuzzel-img"; - "Mod+p".hotkey-overlay.hidden = true; - # Single item clearing - "Mod+Shift+p".action = spawn-sh "cliphist list | fuzzel --dmenu | cliphist delete"; - "Mod+Shift+p".hotkey-overlay.hidden = true; - - # File Manager [n]avigate - "Mod+n".action = spawn-sh "alacritty -e fish -ic lf"; - "Mod+n".hotkey-overlay.hidden = true; - - # Calcu[M]athlator - "Mod+m".action = spawn "${fuzzelCalc}/bin/niri-qalc"; - "Mod+m".hotkey-overlay.title = "Calcu[M]athalor via qalculate"; - - # Logout and Power Menu - "Mod+Pause".action = spawn "wleave"; - - # Network ([W]ifi) Selection - "Mod+w".action = spawn "${pkgs.networkmanager_dmenu}/bin/networkmanager_dmenu"; - "Mod+w".hotkey-overlay.hidden = true; - - # Overview - "Mod+o".action = toggle-overview; - "Mod+o".repeat = false; - - # Reorder Workspaces (after moving them around) - "Mod+Shift+o".action = spawn "${workspaceReorderer}/bin/niri-reorder-workspaces"; - "Mod+Shift+o".hotkey-overlay.title = "Re[o]rder workspaces to maintain logical order"; - - # Rofi[e]moji - "Mod+e".action = spawn "rofimoji"; - "Mod+e".hotkey-overlay.hidden = true; - "Mod+Shift+e".action = spawn ["rofimoji" "--action" "clipboard"]; - "Mod+Shift+e".hotkey-overlay.hidden = true; - - # [S]ound Switcher - "Mod+s".action = spawn "sound-switcher"; - "Mod+s".hotkey-overlay.hidden = true; - } - { - # OBS Studio Controls - "Alt+F1".action = spawn "obs-main-scene"; - "Alt+F1".hotkey-overlay.title = "OBS: Switch to Main Scene"; - "Alt+F2".action = spawn "obs-screensharing"; - "Alt+F2".hotkey-overlay.title = "OBS: Switch to Screensharing"; - "Alt+F3".action = spawn "obs-catcam-toggle"; - "Alt+F3".hotkey-overlay.title = "OBS: Toggle Catcam"; - "Alt+F4".action = spawn "obs-recording-toggle"; - "Alt+F4".hotkey-overlay.title = "OBS: Start/Stop Recording"; - "Alt+F5".action = spawn "obs-recording-pause"; - "Alt+F5".hotkey-overlay.title = "OBS: Pause/Unpause Recording"; - "Alt+F6".action = spawn "obs-webcam-toggle"; - "Alt+F6".hotkey-overlay.title = "OBS: Toggle Webcam"; - } - ]; - }; -} diff --git a/home/niri/scripts/niri-auto-column.sh b/home/niri/scripts/niri-auto-column.sh deleted file mode 100644 index 83ecc98f..00000000 --- a/home/niri/scripts/niri-auto-column.sh +++ /dev/null @@ -1,71 +0,0 @@ -#!/usr/bin/env bash - -# Auto-consume windows into columns on vertical monitors -# Listens to niri event stream and consumes new windows on specified outputs - -set -euo pipefail - -# Outputs where windows should auto-stack into columns -VERTICAL_OUTPUTS=("HDMI-A-2" "HDMI-A-1") - -get_workspace_output() { - local workspace_id="$1" - niri msg --json workspaces | jq -r --argjson id "$workspace_id" \ - '.[] | select(.id == $id) | .output // empty' -} - -is_vertical_output() { - local output="$1" - for v in "${VERTICAL_OUTPUTS[@]}"; do - if [[ "$output" == "$v" ]]; then - return 0 - fi - done - return 1 -} - -get_column_window_count() { - local window_id="$1" - # Get the focused window's column info from the layout - niri msg --json windows | jq --argjson id "$window_id" ' - [.[] | select(.workspace_id == (.[] | select(.id == $id) | .workspace_id))] | length - ' 2>/dev/null || echo "1" -} - -# Main event loop -niri msg --json event-stream | while IFS= read -r event; do - event_type=$(echo "$event" | jq -r 'keys[0]') - - if [[ "$event_type" == "WindowOpenedOrChanged" ]]; then - window=$(echo "$event" | jq '.WindowOpenedOrChanged.window') - window_id=$(echo "$window" | jq -r '.id') - workspace_id=$(echo "$window" | jq -r '.workspace_id // empty') - is_focused=$(echo "$window" | jq -r '.is_focused') - - # Skip if no workspace (floating or special windows) - if [[ -z "$workspace_id" || "$workspace_id" == "null" ]]; then - continue - fi - - # Get the output for this workspace - output=$(get_workspace_output "$workspace_id") - - if [[ -z "$output" ]]; then - continue - fi - - # Check if this is a vertical output - if is_vertical_output "$output"; then - # Only act on focused windows (newly opened windows get focus) - if [[ "$is_focused" == "true" ]]; then - # Small delay to let niri finish placing the window - sleep 0.05 - # Move focus to the left column, then consume the new window from the right - niri msg action focus-column-left 2>/dev/null || true - niri msg action consume-window-into-column 2>/dev/null || true - # Focus the newly consumed window (inserted after current focus) - niri msg action focus-window-down 2>/dev/null || true - fi - fi - fi -done diff --git a/home/niri/scripts/niri-open-on-workspace.sh b/home/niri/scripts/niri-open-on-workspace.sh deleted file mode 100644 index a5c4de64..00000000 --- a/home/niri/scripts/niri-open-on-workspace.sh +++ /dev/null @@ -1,24 +0,0 @@ -#!/usr/bin/env bash -# Opens a command and moves its window to a specific workspace once the title matches - -set -euo pipefail - -workspace="$1" -title_pattern="$2" -shift 2 - -# Launch the command in background -"$@" & - -# Wait for window with matching title to appear (max 30 seconds) -for _ in {1..60}; do - sleep 0.5 - window_id=$(niri msg -j windows | jq -r ".[] | select(.title | test(\"$title_pattern\")) | .id" | head -n1) - if [[ -n "$window_id" ]]; then - niri msg action move-window-to-workspace --window-id "$window_id" "$workspace" - exit 0 - fi -done - -echo "Timeout waiting for window with title matching: $title_pattern" >&2 -exit 1 diff --git a/home/niri/scripts/niri-pick-window.sh b/home/niri/scripts/niri-pick-window.sh deleted file mode 100644 index 49ac2c00..00000000 --- a/home/niri/scripts/niri-pick-window.sh +++ /dev/null @@ -1,92 +0,0 @@ -# Grab the current windows from Niri (id, title, app_id, workspace_id, …) -wins_json="$(niri msg --json windows)" - -# Keep a parallel list of window IDs so we can map fuzzel's index → id. -mapfile -t IDS < <(jq -r '.[].id' <<<"$wins_json") - -# Resolve an icon name from .desktop files for a given app_id. -resolve_icon_from_desktop() { - # We try exact app_id.desktop and its last reverse-DNS segment. - # We return the Icon= value if found (prefer theme name without extension unless absolute path). - local appid="$1" - [ -z "$appid" ] && return 1 - local xdg_home="${XDG_DATA_HOME:-$HOME/.local/share}" - local xdg_dirs="${XDG_DATA_DIRS:-/usr/local/share:/usr/share}" - local -a search_dirs=("$xdg_home/applications") - IFS=: read -r -a _xdg_dirs <<<"$xdg_dirs" - for d in "${_xdg_dirs[@]}"; do - search_dirs+=("$d/applications") - done - local last_seg="${appid##*.}" - local name - for name in "$appid" "$last_seg"; do - for d in "${search_dirs[@]}"; do - if [ -f "$d/$name.desktop" ]; then - # Extract first Icon= value - local icon - icon="$(sed -n 's/^Icon=\(.*\)$/\1/p' "$d/$name.desktop" | head -n 1)" - if [ -n "$icon" ]; then - case "$icon" in - /*) printf '%s' "$icon" ;; - *.png|*.svg|*.xpm) printf '%s' "${icon%.*}" ;; - *) printf '%s' "$icon" ;; - esac - return 0 - fi - fi - done - done - return 1 -} - -# Build the fuzzel menu. We attach icons using the Rofi extended dmenu protocol: -# append a NUL, then "icon", then unit-separator, then the comma-separated icon names. -SEL_IDX="$( - # Create TAB-separated lines: label \t icon-candidates \t app_id - jq -r ' - def slug: (. // "") | ascii_downcase | gsub("[^a-z0-9]+"; "-"); - def hyphenate: (. // "") | ascii_downcase | gsub("[.]+"; "-"); - - .[] as $w - | ($w.app_id // "") as $app_raw - | ($app_raw | ascii_downcase) as $app - | ($app | split(".")) as $parts - | ($parts | length) as $len - | (if $len > 0 then $parts[$len-1] else "" end) as $last - | (if $len > 1 then $parts[$len-2] else "" end) as $penult - | ($app | hyphenate) as $app_hyph - | ($last | slug) as $last_slug - | ($penult | slug) as $penult_slug - | [ - $app, - $app_hyph, - (if $len > 1 then ($penult_slug + "-" + $last_slug) else null end), - $penult, - $last, - $penult_slug, - $last_slug, - "application-default-icon", - "application-x-executable" - ] - | map(select(. != null and . != "")) - | join(",") as $icons - | "\($w.title) — [ws \($w.workspace_id)] (\($w.app_id // "?"))\t\($icons)\t\($app_raw)" - ' <<<"$wins_json" | - # For each line, optionally prefix the candidate list with the .desktop Icon= value, - # then convert to the dmenu icon protocol with real NUL (0) and US (31) separators. - while IFS=$'\t' read -r label icons appid; do - resolved_icon="$(resolve_icon_from_desktop "$appid" 2>/dev/null || true)" - if [ -n "$resolved_icon" ]; then - icons="$resolved_icon,$icons" - fi - printf '%s\t%s\n' "$label" "$icons" - done | - awk -v FS='\t' 'BEGIN{ nul=sprintf("%c",0); us=sprintf("%c",31);} { printf "%s" nul "icon" us "%s\n", $1, $2 }' | - fuzzel --dmenu --index --icon-theme Papirus-Dark --log-level info 2>"${XDG_CACHE_HOME:-$HOME/.cache}"/niri-pick-window-fuzzel.log -)" - -# If the user cancelled, exit quietly. -[[ -z "${SEL_IDX}" ]] && exit 0 - -# Focus the selected window by ID. -niri msg action focus-window --id "${IDS[$SEL_IDX]}" diff --git a/home/niri/scripts/niri-qalc.sh b/home/niri/scripts/niri-qalc.sh deleted file mode 100644 index 8a9b8b44..00000000 --- a/home/niri/scripts/niri-qalc.sh +++ /dev/null @@ -1,53 +0,0 @@ -# Simple calculator wrapper for fuzzel --dmenu using qalc. -# - Prompts for an expression via fuzzel -# - Evaluates it with qalc -# - Copies the result to the clipboard -# - Shows a notification with the result - -prompt="calc> " - -# Prefer dunstify if available; otherwise fall back to notify-send. -NOTIFY_BIN="$(command -v dunstify || true)" -if [ -z "$NOTIFY_BIN" ]; then - NOTIFY_BIN="$(command -v notify-send || true)" -fi -ICON_NAME="accessories-calculator" - -notify() { - # Usage: notify "summary" "body" - local summary="$1" - local body="$2" - if [ -n "$NOTIFY_BIN" ]; then - # Set an app name for nicer presentation; both dunstify and notify-send support -a - "$NOTIFY_BIN" -a "Calc" -i "$ICON_NAME" "$summary" "$body" || true - fi -} - -# Ask the user for an expression using fuzzel's dmenu mode. -# We feed an empty list so that free-form input is returned. -expr_input="$(printf '%s' "" | fuzzel --dmenu --prompt "$prompt" --lines 0 2>/dev/null || true)" - -# Exit silently if the user cancelled or input is empty/whitespace. -if [ -z "${expr_input//[[:space:]]/}" ]; then - exit 0 -fi - -# Evaluate the expression using qalc in terse mode to get only the result. -# If qalc fails, we notify and exit with non-zero status. -result="$(qalc -t -- "$expr_input" 2>/dev/null || true)" -# Normalize whitespace/newlines -result="$(printf '%s' "$result" | tr '\n' ' ' | sed 's/^\s\+//; s/\s\+$//')" - -if [ -z "$result" ]; then - notify "Calc" "Invalid expression: $expr_input" - exit 1 -fi - -# Copy to clipboard -printf '%s' "$result" | wl-copy - -# Notify the user -notify "Calc" "$expr_input = $result (copied to clipboard)" - -# Print to stdout as well (useful for logs) -printf '%s\n' "$result" diff --git a/home/niri/scripts/niri-reorder-workspaces.sh b/home/niri/scripts/niri-reorder-workspaces.sh deleted file mode 100755 index 78f5ee3d..00000000 --- a/home/niri/scripts/niri-reorder-workspaces.sh +++ /dev/null @@ -1,76 +0,0 @@ -#!/usr/bin/env bash - -# Script to reorder Niri workspaces based on their names -# This ensures workspaces maintain their logical order even after being moved between monitors - -set -euo pipefail - -# Define the desired workspace order -declare -A WORKSPACE_ORDER=( - [" a"]=0 - [" 1"]=1 - [" 2"]=2 - [" 3"]=3 - [" 4"]=4 - [" 5"]=5 - [" 6"]=6 - [" 7"]=7 - [" 8"]=8 - [" 9"]=9 - [" 10"]=10 -) - -# Get all workspaces as JSON -workspaces_json=$(niri msg --json workspaces) - -# Get unique output names -outputs=$(echo "$workspaces_json" | jq -r '.[].output' | sort -u) - -# For each output/monitor -while IFS= read -r output; do - # Get workspaces on this output with their current indices and names - workspace_data=$(echo "$workspaces_json" | jq -r \ - --arg output "$output" \ - '.[] | select(.output == $output) | "\(.idx)|\(.name)"') - - # Build an array of workspaces with their sort order - declare -a workspace_list=() - - while IFS='|' read -r current_idx name; do - # Look up the desired order for this workspace name - if [[ -v WORKSPACE_ORDER["$name"] ]]; then - sort_order="${WORKSPACE_ORDER[$name]}" - # Store as: sort_order|current_idx|name - workspace_list+=("$sort_order|$current_idx|$name") - fi - done <<<"$workspace_data" - - # Sort workspaces by their logical order (first field) - mapfile -t sorted_workspaces < <(printf '%s\n' "${workspace_list[@]}" | sort -t'|' -k1 -n) - - # Assign sequential target indices (forward iteration) - for ((i = 0; i < ${#sorted_workspaces[@]}; i++)); do - target_indices[i]=$i - done - - # Move workspaces to their target positions (backward iteration to avoid displacement) - for ((i = ${#sorted_workspaces[@]} - 1; i >= 0; i--)); do - IFS='|' read -r sort_order current_idx name <<<"${sorted_workspaces[$i]}" - target_idx=${target_indices[i]} - - if [[ "$current_idx" != "$target_idx" ]]; then - # Focus the workspace by name first - niri msg action focus-workspace "$name" >/dev/null 2>&1 || true - - # Move it to the correct index - niri msg action move-workspace-to-index "$target_idx" >/dev/null 2>&1 || true - fi - done - - # Clear arrays for the next output - unset workspace_list - unset sorted_workspaces - unset target_indices -done <<<"$outputs" - -echo "Workspaces reordered successfully!" diff --git a/home/niri/scripts/niri-set-wallpaper.sh b/home/niri/scripts/niri-set-wallpaper.sh deleted file mode 100644 index 39d5b953..00000000 --- a/home/niri/scripts/niri-set-wallpaper.sh +++ /dev/null @@ -1,26 +0,0 @@ -wallpapersDir="${HOME}/.local/share/wallpapers" - -pkill swaybg || true - -# Read the current specialisation, default to "dark" if missing -if [ -r /etc/specialisation ]; then - SPEC=$(tr -d '\n' /dev/null) -else - SPEC=dark -fi - -case "$SPEC" in - -light) - swaybg -i "${wallpapersDir}/gruvbox-light.png" -m fill & - disown - ;; -dark) - swaybg -i "${wallpapersDir}/gruvbox-dark.png" -m fill & - disown - ;; -*) - swaybg -i "${wallpapersDir}/gruvbox-dark.png" -m fill & - disown - ;; -esac diff --git a/home/niri/wallpapers/gruvbox-dark-rainbow.png b/home/niri/wallpapers/gruvbox-dark-rainbow.png deleted file mode 100644 index b15ba5a97602c2e04138e96f0e48be21ff39e5d6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 185977 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 L{uKA4)sg=JgoI_M diff --git a/home/niri/wallpapers/gruvbox-light-rainbow.png b/home/niri/wallpapers/gruvbox-light-rainbow.png deleted file mode 100644 index 3217d92a564491f787d16bb44b79f3a46c2cd445..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 192946 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

=xE)K9{<4cEUj|~-RwRN*B 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 ZzcH`q(x)A=dr2l7^Iqt?+egky{uf^Cdo2I} diff --git a/home/nix-index/default.nix b/home/nix-index/default.nix deleted file mode 100644 index baa2a651..00000000 --- a/home/nix-index/default.nix +++ /dev/null @@ -1,19 +0,0 @@ -{ - inputs, - isImpermanent, - lib, - ... -}: { - home.persistence."/persist" = lib.mkIf isImpermanent { - files = [ - ".local/state/comma-choices" # For , - ]; - }; - imports = [ - inputs.nix-index-database.homeModules.nix-index - ]; - - programs.nix-index = { - enable = true; - }; -} diff --git a/home/nix-inspect/default.nix b/home/nix-inspect/default.nix deleted file mode 100644 index 32c0debf..00000000 --- a/home/nix-inspect/default.nix +++ /dev/null @@ -1,5 +0,0 @@ -{pkgs, ...}: { - home.packages = [ - pkgs.nix-inspect - ]; -} diff --git a/home/nushell/config.nu b/home/nushell/config.nu deleted file mode 100644 index 40a158c4..00000000 --- a/home/nushell/config.nu +++ /dev/null @@ -1,30 +0,0 @@ -# Nushell Config File -# -# Defaults: https://github.com/nushell/nushell/blob/main/docs/sample_config/default_config.nu - -# The default config record. This is where much of your global configuration is setup. -$env.config = { - history: { - max_size: 1_000_000 # Session has to be reloaded for this to take effect - } - - keybindings: [ - { - name: open_command_editor - modifier: control - keycode: char_e - mode: [emacs, vi_normal, vi_insert] - event: { send: openeditor } - } - { - name: copy_command_line - modifier: control - keycode: char_x - mode: [emacs, vi_normal, vi_insert] - event: [ - { edit: selectall } - { edit: copyselectionsystem } - ] - } - ] -} diff --git a/home/nushell/default.nix b/home/nushell/default.nix deleted file mode 100644 index c105e8f2..00000000 --- a/home/nushell/default.nix +++ /dev/null @@ -1,28 +0,0 @@ -{ - isImpermanent, - lib, - pkgs, - ... -}: let - # Custom nushell build with system-clipboard support for Ctrl+X keybinding - nushellWithClipboard = pkgs.unstable.nushell.overrideAttrs (oldAttrs: { - cargoBuildFeatures = (oldAttrs.cargoBuildFeatures or []) ++ ["system-clipboard"]; - }); -in { - home.persistence."/persist" = lib.mkIf isImpermanent { - directories = [ - ".config/nushell" - ]; - }; - home.file = { - ".config/nushell/.stignore" = { - source = ./syncthing/stignore-nushell; - }; - }; - programs.nushell = { - enable = true; - configFile.source = ./config.nu; - envFile.source = ./env.nu; - package = nushellWithClipboard; - }; -} diff --git a/home/nushell/env.nu b/home/nushell/env.nu deleted file mode 100644 index 889413ff..00000000 --- a/home/nushell/env.nu +++ /dev/null @@ -1 +0,0 @@ -# Nushell Environment Config File diff --git a/home/nushell/syncthing/stignore-nushell b/home/nushell/syncthing/stignore-nushell deleted file mode 100644 index 4605b98f..00000000 --- a/home/nushell/syncthing/stignore-nushell +++ /dev/null @@ -1,7 +0,0 @@ -// .stignore for ~/.config/nushell -// (?d) allows for removal when deleting parent dirs and only an ignored file/directory remains - -// Only sync nushell history -!history.txt -// Ignore everything else -* diff --git a/home/obs/default.nix b/home/obs/default.nix deleted file mode 100644 index 712904d8..00000000 --- a/home/obs/default.nix +++ /dev/null @@ -1,85 +0,0 @@ -{ - isImpermanent, - lib, - pkgs, - osConfig, - ... -}: let - isFlexbox = osConfig.networking.hostName == "flexbox"; - - # OBS Control Scripts - obsMainScene = pkgs.writeShellApplication { - name = "obs-main-scene"; - runtimeInputs = [pkgs.obs-cmd]; - text = builtins.readFile ./scripts/obs-main-scene.sh; - }; - - obsScreensharing = pkgs.writeShellApplication { - name = "obs-screensharing"; - runtimeInputs = [pkgs.obs-cmd]; - text = builtins.readFile ./scripts/obs-screensharing.sh; - }; - - obsCatcamToggle = pkgs.writeShellApplication { - name = "obs-catcam-toggle"; - runtimeInputs = [pkgs.obs-cmd]; - text = builtins.readFile ./scripts/obs-catcam-toggle.sh; - }; - - obsRecordingToggle = pkgs.writeShellApplication { - name = "obs-recording-toggle"; - runtimeInputs = [pkgs.obs-cmd]; - text = builtins.readFile ./scripts/obs-recording-toggle.sh; - }; - - obsRecordingPause = pkgs.writeShellApplication { - name = "obs-recording-pause"; - runtimeInputs = [pkgs.obs-cmd]; - text = builtins.readFile ./scripts/obs-recording-pause.sh; - }; - - obsWebcamToggle = pkgs.writeShellApplication { - name = "obs-webcam-toggle"; - runtimeInputs = [pkgs.obs-cmd]; - text = builtins.readFile ./scripts/obs-webcam-toggle.sh; - }; -in { - home.packages = [ - pkgs.obs-cmd - obsMainScene - obsScreensharing - obsCatcamToggle - obsRecordingToggle - obsRecordingPause - obsWebcamToggle - ]; - - home.persistence."/persist" = lib.mkIf isImpermanent { - directories = [ - ".config/obs-studio" - ]; - }; - programs.obs-studio = { - enable = true; - plugins = with pkgs.obs-studio-plugins; [ - obs-backgroundremoval - pkgs.unstable.obs-studio-plugins.obs-noise - pkgs.unstable.obs-studio-plugins.pixel-art - pkgs.unstable.obs-studio-plugins.obs-recursion-effect - pkgs.unstable.obs-studio-plugins.obs-retro-effects - obs-vintage-filter - ]; - }; - xdg.desktopEntries = lib.mkIf isFlexbox { - obs = { - name = "OBS Studio (NVIDIA GPU)"; - exec = "nvidia-offload obs"; - genericName = "Streaming/Recording Software"; - terminal = false; - type = "Application"; - categories = ["AudioVideo" "Recorder"]; - icon = "com.obsproject.Studio"; - startupNotify = true; - }; - }; -} diff --git a/home/obs/scripts/obs-catcam-toggle.sh b/home/obs/scripts/obs-catcam-toggle.sh deleted file mode 100644 index 82702ea7..00000000 --- a/home/obs/scripts/obs-catcam-toggle.sh +++ /dev/null @@ -1,2 +0,0 @@ -# Toggle Catcam source visibility -obs-cmd scene-item toggle "Virtual Cam" "Overlay: Cat Cam" diff --git a/home/obs/scripts/obs-main-scene.sh b/home/obs/scripts/obs-main-scene.sh deleted file mode 100644 index 7ca04626..00000000 --- a/home/obs/scripts/obs-main-scene.sh +++ /dev/null @@ -1,2 +0,0 @@ -# Switch to OBS Main Scene -obs-cmd scene switch "OBS Vintage Cam" diff --git a/home/obs/scripts/obs-recording-pause.sh b/home/obs/scripts/obs-recording-pause.sh deleted file mode 100644 index 92170fd1..00000000 --- a/home/obs/scripts/obs-recording-pause.sh +++ /dev/null @@ -1,2 +0,0 @@ -# Pause/Unpause Recording -obs-cmd recording toggle-pause diff --git a/home/obs/scripts/obs-recording-toggle.sh b/home/obs/scripts/obs-recording-toggle.sh deleted file mode 100644 index 11f0f70e..00000000 --- a/home/obs/scripts/obs-recording-toggle.sh +++ /dev/null @@ -1,2 +0,0 @@ -# Start/Stop Recording -obs-cmd recording toggle diff --git a/home/obs/scripts/obs-screensharing.sh b/home/obs/scripts/obs-screensharing.sh deleted file mode 100644 index 1debacd6..00000000 --- a/home/obs/scripts/obs-screensharing.sh +++ /dev/null @@ -1,2 +0,0 @@ -# Switch to Screensharing scene -obs-cmd scene switch "Screensharing" diff --git a/home/obs/scripts/obs-webcam-toggle.sh b/home/obs/scripts/obs-webcam-toggle.sh deleted file mode 100644 index 107a08fb..00000000 --- a/home/obs/scripts/obs-webcam-toggle.sh +++ /dev/null @@ -1,2 +0,0 @@ -# Toggle Webcam source visibility -obs-cmd scene-item toggle "OBS Vintage Cam" Webcam diff --git a/home/obsidian/default.nix b/home/obsidian/default.nix deleted file mode 100644 index 1166a28f..00000000 --- a/home/obsidian/default.nix +++ /dev/null @@ -1,17 +0,0 @@ -{ - lib, - isImpermanent, - pkgs, - ... -}: { - home.persistence."/persist" = lib.mkIf isImpermanent { - directories = [ - ".config/obsidian" - "Obsidian" - ]; - }; - - home.packages = [ - pkgs.obsidian - ]; -} diff --git a/home/onboard/default.nix b/home/onboard/default.nix deleted file mode 100644 index bb2c37a7..00000000 --- a/home/onboard/default.nix +++ /dev/null @@ -1,6 +0,0 @@ -# Onboard Keyboard Layout -{pkgs, ...}: { - home.packages = [ - pkgs.onboard - ]; -} diff --git a/home/pavucontrol/default.nix b/home/pavucontrol/default.nix deleted file mode 100644 index c024944b..00000000 --- a/home/pavucontrol/default.nix +++ /dev/null @@ -1,16 +0,0 @@ -{ - lib, - isImpermanent, - pkgs, - ... -}: { - home.persistence."/persist" = lib.mkIf isImpermanent { - files = [ - ".config/pavucontrol.ini" - ]; - }; - - home.packages = [ - pkgs.pavucontrol - ]; -} diff --git a/home/pgcli/default.nix b/home/pgcli/default.nix deleted file mode 100644 index d1029742..00000000 --- a/home/pgcli/default.nix +++ /dev/null @@ -1,5 +0,0 @@ -{...}: { - programs.pgcli = { - enable = true; - }; -} diff --git a/home/pomodoro-gtk/default.nix b/home/pomodoro-gtk/default.nix deleted file mode 100644 index 123edf85..00000000 --- a/home/pomodoro-gtk/default.nix +++ /dev/null @@ -1,5 +0,0 @@ -{pkgs, ...}: { - home.packages = [ - pkgs.pomodoro-gtk - ]; -} diff --git a/home/portfolio-performance/default.nix b/home/portfolio-performance/default.nix deleted file mode 100644 index 507400c8..00000000 --- a/home/portfolio-performance/default.nix +++ /dev/null @@ -1,16 +0,0 @@ -{ - lib, - isImpermanent, - pkgs, - ... -}: { - home.persistence."/persist" = lib.mkIf isImpermanent { - directories = [ - ".PortfolioPerformance" - ]; - }; - - home.packages = [ - pkgs.unstable.portfolio - ]; -} diff --git a/home/psql/default.nix b/home/psql/default.nix deleted file mode 100644 index e9215858..00000000 --- a/home/psql/default.nix +++ /dev/null @@ -1,6 +0,0 @@ -{pkgs, ...}: { - home.packages = [ - pkgs.postgresql - ]; - home.file.".psqlrc".source = ./psqlrc; -} diff --git a/home/psql/psqlrc b/home/psql/psqlrc deleted file mode 100644 index 7755ea63..00000000 --- a/home/psql/psqlrc +++ /dev/null @@ -1,2 +0,0 @@ -\x auto -\pset pager 0 diff --git a/home/pulsemixer/default.nix b/home/pulsemixer/default.nix deleted file mode 100644 index f59d347f..00000000 --- a/home/pulsemixer/default.nix +++ /dev/null @@ -1,9 +0,0 @@ -{pkgs, ...}: { - home.file = { - ".config/pulsemixer.cfg".source = ./pulsemixer.cfg; - }; - - home.packages = [ - pkgs.pulsemixer - ]; -} diff --git a/home/pulsemixer/pulsemixer.cfg b/home/pulsemixer/pulsemixer.cfg deleted file mode 100644 index cad6ed98..00000000 --- a/home/pulsemixer/pulsemixer.cfg +++ /dev/null @@ -1,7 +0,0 @@ -[keys] -;; To bind "special keys" such as arrows see "Key constant" table in -;; https://docs.python.org/3/library/curses.html#constants -up = l, KEY_UP, KEY_PPAGE -down = k, KEY_DOWN, KEY_NPAGE -left = j, KEY_LEFT -right = ';', KEY_RIGHT diff --git a/home/qalculate/default.nix b/home/qalculate/default.nix deleted file mode 100644 index 6499e684..00000000 --- a/home/qalculate/default.nix +++ /dev/null @@ -1,17 +0,0 @@ -{ - lib, - isImpermanent, - pkgs, - ... -}: { - home.persistence."/persist" = lib.mkIf isImpermanent { - directories = [ - ".config/qalculate" - ".local/share/qalculate" - ]; - }; - - home.packages = [ - pkgs.qalculate-gtk - ]; -} diff --git a/home/ripgrep-all/default.nix b/home/ripgrep-all/default.nix deleted file mode 100644 index 33858a52..00000000 --- a/home/ripgrep-all/default.nix +++ /dev/null @@ -1,5 +0,0 @@ -{...}: { - programs.ripgrep-all = { - enable = true; - }; -} diff --git a/home/ripgrep/default.nix b/home/ripgrep/default.nix deleted file mode 100644 index b7b71fb1..00000000 --- a/home/ripgrep/default.nix +++ /dev/null @@ -1,8 +0,0 @@ -{...}: { - programs.ripgrep = { - enable = true; - arguments = [ - "--smart-case" - ]; - }; -} diff --git a/home/rofimoji/default.nix b/home/rofimoji/default.nix deleted file mode 100644 index a9ad92d5..00000000 --- a/home/rofimoji/default.nix +++ /dev/null @@ -1,8 +0,0 @@ -{pkgs, ...}: { - home.packages = [ - pkgs.rofimoji - pkgs.wtype # insert emojis directly - ]; - - xdg.configFile."rofimoji.rc".source = ./rofimoji.rc; -} diff --git a/home/rofimoji/rofimoji.rc b/home/rofimoji/rofimoji.rc deleted file mode 100644 index 84825664..00000000 --- a/home/rofimoji/rofimoji.rc +++ /dev/null @@ -1,3 +0,0 @@ -files = [emojis, math, currency_symbols, combining_diacritical_marks, fontawesome6] -skin-tone = "neutral" -selector = "fuzzel" diff --git a/home/satty/default.nix b/home/satty/default.nix deleted file mode 100644 index 8c6431a1..00000000 --- a/home/satty/default.nix +++ /dev/null @@ -1,36 +0,0 @@ -{ - isImpermanent, - lib, - pkgs, - ... -}: let - sattyScreenshot = pkgs.writeShellApplication { - name = "satty-screenshot"; - runtimeInputs = with pkgs; [ - satty - grim - wl-clipboard - jq - niri - ]; - text = builtins.readFile ./scripts/satty-screenshot.sh; - }; -in { - home.persistence."/persist" = lib.mkIf isImpermanent { - directories = [ - ".cache/satty" - ]; - }; - - programs.satty = { - enable = true; - settings.general = { - fullscreen = true; - initial-tool = "crop"; - }; - }; - - home.packages = [ - sattyScreenshot - ]; -} diff --git a/home/satty/scripts/satty-screenshot.sh b/home/satty/scripts/satty-screenshot.sh deleted file mode 100644 index 6e897696..00000000 --- a/home/satty/scripts/satty-screenshot.sh +++ /dev/null @@ -1,30 +0,0 @@ -# Take a fullscreen screenshot of the current focused screen and open it with Satty - -temp_file=$(mktemp --suffix=".png") - -# Try to get the focused output, fallback to just taking a screenshot of all outputs -focused_output=$(niri msg --json focused-output 2>/dev/null | jq -r '.name' 2>/dev/null || echo "") - -# Take the screenshot -screenshot_success=false -if [ -n "$focused_output" ]; then - if grim -o "$focused_output" "$temp_file"; then - screenshot_success=true - fi -else - if grim "$temp_file"; then - screenshot_success=true - fi -fi - -if [ "$screenshot_success" = true ]; then - # Open the screenshot with Satty for editing - satty --filename "$temp_file" --copy-command "wl-copy" --early-exit - - # Clean up the temporary file - rm "$temp_file" -else - echo "Failed to take screenshot" >&2 - rm "$temp_file" - exit 1 -fi diff --git a/home/showmethekey/default.nix b/home/showmethekey/default.nix deleted file mode 100644 index f868b24d..00000000 --- a/home/showmethekey/default.nix +++ /dev/null @@ -1,6 +0,0 @@ -{pkgs, ...}: let -in { - home.packages = [ - pkgs.showmethekey - ]; -} diff --git a/home/signal/default.nix b/home/signal/default.nix deleted file mode 100644 index f2b41412..00000000 --- a/home/signal/default.nix +++ /dev/null @@ -1,16 +0,0 @@ -{ - lib, - isImpermanent, - pkgs, - ... -}: { - home.persistence."/persist" = lib.mkIf isImpermanent { - directories = [ - ".config/Signal" - ]; - }; - - home.packages = [ - pkgs.signal-desktop - ]; -} diff --git a/home/solaar/default.nix b/home/solaar/default.nix deleted file mode 100644 index 285c1c3a..00000000 --- a/home/solaar/default.nix +++ /dev/null @@ -1,17 +0,0 @@ -{ - lib, - isImpermanent, - pkgs, - ... -}: { - home.persistence."/persist" = lib.mkIf isImpermanent { - directories = [ - ".config/solaar" - ]; - }; - - home.packages = [ - pkgs.hicolor-icon-theme - pkgs.solaar - ]; -} diff --git a/home/sound-switcher/default.nix b/home/sound-switcher/default.nix deleted file mode 100644 index 131e98a2..00000000 --- a/home/sound-switcher/default.nix +++ /dev/null @@ -1,15 +0,0 @@ -# Rofi-based sound switcher -{ - pkgs, - osConfig, - ... -}: let - isNumenor = osConfig.networking.hostName == "numenor"; - sound-switcher = pkgs.writers.writeBashBin "sound-switcher" ( - if isNumenor - then (builtins.readFile ./scripts/sound-switcher-numenor.sh) - else (builtins.readFile ./scripts/sound-switcher-flexbox.sh) - ); -in { - home.packages = [sound-switcher]; -} diff --git a/home/sound-switcher/scripts/sound-switcher-flexbox.sh b/home/sound-switcher/scripts/sound-switcher-flexbox.sh deleted file mode 100644 index 08319848..00000000 --- a/home/sound-switcher/scripts/sound-switcher-flexbox.sh +++ /dev/null @@ -1,241 +0,0 @@ -chosen="$(echo -e "🔌local\n\ - buds(listen)\n\ - buds(talk)\n\ -🎧sony\n\ -🎧oh(localmic) -🎧🎙️oh(ohmic) -📢boombox\n\ - budsFE(listen)\n\ - budsFE(talk)\n\ -" | fuzzel --dmenu --prompt "🎶 [M]usic and 🎤 Switch")" - -localspeaker() { - local card_name_pattern="00_1f" - local potential_sinks=( - "alsa_output.pci-0000_00_1f.3-platform-sof_sdw.HiFi___ucm0003.hw_sofsoundwire_2__sink" - "alsa_output.pci-0000_00_1f.3-platform-sof_sdw.HiFi___ucm0005.hw_sofsoundwire_2__sink" - "alsa_output.pci-0000_00_1f.3-platform-sof_sdw.HiFi___ucm0007.hw_sofsoundwire_2__sink" - "alsa_output.pci-0000_00_1f.3-platform-sof_sdw.HiFi__hw_sofsoundwire_2__sink" - "alsa_output.pci-0000_00_1f.3-platform-sof_sdw.HiFi__Speaker__sink" - "alsa_output.pci-0000_00_1f.3.analog-stereo" - "alsa_output.pci-0000_00_1f.3.analog-stereo.2" - ) - local actual_sinks - local selected_sink - local card_profile="HiFi" - - actual_sinks=$(pactl list sinks) - for source in "${potential_sinks[@]}"; do - if [[ "$actual_sinks" == *"$source"* ]]; then - selected_sink=$source - break - fi - done - - if [ -z "$selected_sink" ]; then - echo "Local speaker not found" - return 1 - fi - - set_default_sink "$card_name_pattern" "$selected_sink" "$card_profile" - - localmike -} - -ohlocalmic() { - local card_name_pattern="Apple" - local sink="alsa_output.usb-Apple__Inc._USB-C_to_3.5mm_Headphone_Jack_Adapter_DWH84440324JKLTA7-00.analog-stereo" - local card_profile="HiFi" - - set_default_sink "$card_name_pattern" "$sink" "$card_profile" - - localmike -} - -ohohmic() { - local card_name_pattern="Apple" - local sink="alsa_output.usb-Apple__Inc._USB-C_to_3.5mm_Headphone_Jack_Adapter_DWH84440324JKLTA7-00.analog-stereo" - local card_profile="?" - - set_default_sink "$card_name_pattern" "$sink" "$card_profile" - - ohmike -} - -boombox() { - local card_name_pattern="04_21" - local sink="bluez_sink.04_21_44_B6_92_39.a2dp_sink" - local card_profile="?" - - local bd_address="04:21:44:B6:92:39" - local card_id - if [[ -z $card_id ]]; then - connect_bluetooth "$bd_address" - fi - - set_default_sink "$card_name_pattern" "$sink" "$card_profile" - - localmike -} - -budsfelisten() { - local card_name_pattern="34_E3" - local sink="bluez_output.34_E3_FB_C5_01_E0.1" - local card_profile="a2dp-sink-sbc" - - set_default_sink "$card_name_pattern" "$sink" "$card_profile" - - localmike -} - -budsfetalk() { - local card_name_pattern="34_E3" - local sink="bluez_output.34_E3_FB_C5_01_E0.1" - local card_profile="headset-head-unit" - - set_default_sink "$card_name_pattern" "$sink" "$card_profile" - - budsfemike -} - -budslisten() { - local card_name_pattern="DC_69" - local sink="bluez_output.DC_69_E2_9A_6E_30.1" - local card_profile="a2dp-sink-sbc" - - set_default_sink "$card_name_pattern" "$sink" "$card_profile" - - localmike -} - -budstalk() { - local card_name_pattern="DC_69" - local sink="bluez_output.DC_69_E2_9A_6E_30.1" - local card_profile="headset-head-unit" - - set_default_sink "$card_name_pattern" "$sink" "$card_profile" - - budsmike -} - -sony() { - local card_name_pattern="14_3F" - local sink="bluez_output.14_3F_A6_28_DC_51.1" - local card_profile="a2dp-sink" - - local bd_address="14:3F:A6:28:DC:51" - local card_id - card_id=$(get_card_id "$card_name_pattern") - if [[ -z $card_id ]]; then - connect_bluetooth "$bd_address" - fi - - set_default_sink "$card_name_pattern" "$sink" "$card_profile" - - localmike -} - -localmike() { - local card_name_pattern="00_1f" - local potential_sources=( - "alsa_input.pci-0000_00_1f.3-platform-sof_sdw.HiFi___ucm0003.hw_sofsoundwire_4__source" - "alsa_input.pci-0000_00_1f.3-platform-sof_sdw.HiFi___ucm0005.hw_sofsoundwire_4__source" - "alsa_input.pci-0000_00_1f.3-platform-sof_sdw.HiFi___ucm0007.hw_sofsoundwire_4__source" - "alsa_input.pci-0000_00_1f.3-platform-sof_sdw.HiFi__hw_sofsoundwire_4__source" - "alsa_input.usb-C-Media_Electronics_Inc._USB_PnP_Audio_Device-00.mono-fallback" - "alsa_input.pci-0000_00_1f.3-platform-sof_sdw.HiFi__Mic__source" - ) - local actual_sources - local selected_source - local card_profile="HiFi" - - actual_sources=$(pactl list sources) - for source in "${potential_sources[@]}"; do - if [[ "$actual_sources" == *"$source"* ]]; then - selected_source=$source - break - fi - done - - if [ -z "$selected_source" ]; then - echo "Local mike not found" - return 1 - fi - - set_default_source "$card_name_pattern" "$selected_source" "$card_profile" -} - -ohmike() { - local card_name_pattern="Apple" - local source="alsa_input.usb-Apple__Inc._USB-C_to_3.5mm_Headphone_Jack_Adapter_DWH84440324JKLTA7-00.mono-fallback" - local card_profile="?" - - set_default_source "$card_name_pattern" "$source" "$card_profile" -} - -budsfemike() { - local card_name_pattern="34_E3" - local source="bluez_input.34_E3_FB_C5_01_E0" - local card_profile="headset-head-unit" - - set_default_source "$card_name_pattern" "$source" "$card_profile" -} - -budsmike() { - local card_name_pattern="DC_69" - local source="bluez_input.DC:69:E2:9A:6E:30" - local card_profile="headset-head-unit" - - set_default_source "$card_name_pattern" "$source" "$card_profile" -} - -get_card_id() { - local card_name_pattern="$1" - nu -c "pactl list cards short | lines | parse \"{id}\t{name}\t{_}\" | where \$it.name =~ \"$card_name_pattern\" | get id | get 0" || true -} - -set_default_sink() { - local card_name_pattern="$1" - local sink="$2" - local card_profile="$3" - - local card_id - card_id=$(get_card_id "$card_name_pattern") - - pactl set-card-profile "$card_id" "$card_profile" - pactl set-default-sink "$sink" -} - -set_default_source() { - local card_name_pattern="$1" - local source="$2" - local card_profile="$3" - - local card_id - card_id=$(get_card_id "$card_name_pattern") - - pactl set-card-profile "$card_id" "$card_profile" - pactl set-default-source "$source" -} - -connect_bluetooth() { - local bd_address="$1" - - echo -e 'power on\nquit' | bluetoothctl - sleep 2 - echo -e "connect $bd_address\nquit" | bluetoothctl - sleep 10 -} - -case "$chosen" in -🔌local) localspeaker ;; -"🎧oh(localmic)") ohlocalmic ;; -"🎧🎙️oh(ohmic)") ohohmic ;; -🎧sony) sony ;; -" budsFE(listen)") budsfelisten ;; -" budsFE(talk)") budsfetalk ;; -" buds(listen)") budslisten ;; -" buds(talk)") budstalk ;; -📢boombox) boombox ;; -*) exit 1 ;; -esac diff --git a/home/sound-switcher/scripts/sound-switcher-numenor.sh b/home/sound-switcher/scripts/sound-switcher-numenor.sh deleted file mode 100644 index d5cb6833..00000000 --- a/home/sound-switcher/scripts/sound-switcher-numenor.sh +++ /dev/null @@ -1,156 +0,0 @@ -chosen="$(echo -e "🎧oh\n\ -🔊creative\n\ -🎧sony\n\ -🍿movie\n\ - buds(listen)\n\ - buds(talk)\n\ -📢boombox\n\ -" | fuzzel --dmenu --prompt "🎶 [M]usic and 🎤 Switch")" - -oh() { - local card_name_pattern="ThinkPad_Thunderbolt" - local sink="alsa_output.usb-Lenovo_ThinkPad_Thunderbolt_3_Dock_USB_Audio_000000000000-00.analog-stereo" - local card_profile="output:analog-stereo" - - set_default_sink "$card_name_pattern" "$sink" "$card_profile" - - localmike -} - -creative() { - local card_name_pattern="usb-Generic_USB_Audio-00" - local sink="alsa_output.usb-Generic_USB_Audio-00.analog-stereo" - local card_profile="output:analog-stereo" - - set_default_sink "$card_name_pattern" "$sink" "$card_profile" - - localmike -} - -movie() { - local card_name_pattern="0000_03_00" - local sink="alsa_output.pci-0000_03_00.1.hdmi-stereo-extra3" - local card_profile="output:hdmi-stereo-extra3" - - set_default_sink "$card_name_pattern" "$sink" "$card_profile" - - localmike -} - -boombox() { - local card_name_pattern="04_21" - local sink="bluez_sink.04_21_44_B6_92_39.a2dp_sink" - local card_profile="?" - - local bd_address="04:21:44:B6:92:39" - local card_id - if [[ -z $card_id ]]; then - connect_bluetooth "$bd_address" - fi - - set_default_sink "$card_name_pattern" "$sink" "$card_profile" - - localmike -} - -budslisten() { - local card_name_pattern="DC_69" - local sink="bluez_output.DC_69_E2_9A_6E_30.1" - local card_profile="a2dp-sink-sbc" - - set_default_sink "$card_name_pattern" "$sink" "$card_profile" - - localmike -} - -budstalk() { - local card_name_pattern="DC_69" - local sink="bluez_output.DC_69_E2_9A_6E_30.1" - local card_profile="headset-head-unit" - - set_default_sink "$card_name_pattern" "$sink" "$card_profile" - - budsmike -} - -sony() { - local card_name_pattern="14_3F" - local sink="bluez_output.14_3F_A6_28_DC_51.1" - local card_profile="a2dp-sink" - - local bd_address="14:3F:A6:28:DC:51" - local card_id - card_id=$(get_card_id "$card_name_pattern") - if [[ -z $card_id ]]; then - connect_bluetooth "$bd_address" - fi - - set_default_sink "$card_name_pattern" "$sink" "$card_profile" - - localmike -} - -localmike() { - local card_name_pattern="Blue_Microphones" - local source="alsa_input.usb-Generic_Blue_Microphones_LT_221104181411AD020101_111000-00.analog-stereo" - local card_profile="input:analog-stereo" - - set_default_source "$card_name_pattern" "$source" "$card_profile" -} - -budsmike() { - local card_name_pattern="DC_69" - local source="bluez_input.DC:69:E2:9A:6E:30" - local card_profile="headset-head-unit" - - set_default_source "$card_name_pattern" "$source" "$card_profile" -} - -get_card_id() { - local card_name_pattern="$1" - nu -c "pactl list cards short | lines | parse \"{id}\t{name}\t{_}\" | where \$it.name =~ \"$card_name_pattern\" | get id | get 0" || true -} - -set_default_sink() { - local card_name_pattern="$1" - local sink="$2" - local card_profile="$3" - - local card_id - card_id=$(get_card_id "$card_name_pattern") - - pactl set-card-profile "$card_id" "$card_profile" - pactl set-default-sink "$sink" -} - -set_default_source() { - local card_name_pattern="$1" - local source="$2" - local card_profile="$3" - - local card_id - card_id=$(get_card_id "$card_name_pattern") - - pactl set-card-profile "$card_id" "$card_profile" - pactl set-default-source "$source" -} - -connect_bluetooth() { - local bd_address="$1" - - echo -e 'power on\nquit' | bluetoothctl - sleep 2 - echo -e "connect $bd_address\nquit" | bluetoothctl - sleep 10 -} - -case "$chosen" in -🎧oh) oh ;; -🔊creative) creative ;; -🎧sony) sony ;; -🍿movie) movie ;; -" buds(listen)") budslisten ;; -" buds(talk)") budstalk ;; -📢boombox) boombox ;; -*) exit 1 ;; -esac diff --git a/home/ssh/README.md b/home/ssh/README.md deleted file mode 100644 index 4b394827..00000000 --- a/home/ssh/README.md +++ /dev/null @@ -1,75 +0,0 @@ -# SSH Agent Setup with GNOME Keyring - -This configuration sets up SSH agent integration with GNOME Keyring on your Niri NixOS system. This allows SSH key passphrases to be stored securely in GNOME Keyring and automatically provided when needed. - -## How it works - -1. **GNOME Keyring SSH Agent**: Instead of using the default ssh-agent, we use GNOME Keyring's SSH agent component which integrates with the keyring for secure passphrase storage. - -2. **Automatic Key Addition**: SSH is configured with `AddKeysToAgent yes` so keys are automatically added to the agent when first used. - -3. **Persistent Storage**: Passphrases are stored in GNOME Keyring and will be remembered between sessions. - -## Usage - -### First Time Setup - -1. **Rebuild your NixOS configuration**: - ```bash - sudo nixos-rebuild switch --flake . - ``` - -2. **Restart your session** or manually start the SSH agent: - ```bash - systemctl --user start gnome-keyring-ssh - ``` - -3. **Add your SSH keys** (optional, they'll be added automatically when first used): - ```bash - ssh-add-all # Adds all SSH keys from ~/.ssh - ``` - -### Daily Usage - -- **First SSH connection**: You'll be prompted to enter your key passphrase once per session -- **Subsequent connections**: No passphrase required - GNOME Keyring provides it automatically -- **Unlocking keyring**: If prompted to unlock the keyring, enter your user password - -### Useful Commands - -- **List loaded keys**: `ssh-add -l` -- **Add all keys manually**: `ssh-add-all` -- **Add specific key**: `ssh-add ~/.ssh/id_ed25519` -- **Remove all keys**: `ssh-add -D` -- **Check agent status**: `systemctl --user status gnome-keyring-ssh` - -### Troubleshooting - -If SSH agent isn't working: - -1. **Check if service is running**: - ```bash - systemctl --user status gnome-keyring-ssh - ``` - -2. **Check environment variable**: - ```bash - echo $SSH_AUTH_SOCK - # Should show: /run/user/1000/keyring/ssh - ``` - -3. **Restart the service**: - ```bash - systemctl --user restart gnome-keyring-ssh - ``` - -4. **Unlock GNOME Keyring**: - - Run `seahorse` (GNOME Passwords and Keys) - - Unlock the "Default" keyring if locked - -### Security Notes - -- Passphrases are stored encrypted in GNOME Keyring -- The keyring is protected by your user login password -- Keys are automatically removed from the agent when you log out -- You can view and manage stored passphrases using Seahorse (GNOME Passwords and Keys) diff --git a/home/ssh/default.nix b/home/ssh/default.nix deleted file mode 100644 index cf11f59e..00000000 --- a/home/ssh/default.nix +++ /dev/null @@ -1,36 +0,0 @@ -{ - lib, - isImpermanent, - pkgs, - ... -}: let - ssh-add-all = pkgs.writeShellApplication { - name = "ssh-add-all"; - runtimeInputs = with pkgs; [openssh coreutils]; - text = builtins.readFile ./ssh-add-all.sh; - }; -in { - home.persistence."/persist" = lib.mkIf isImpermanent { - directories = [ - ".ssh" - ]; - }; - - home.packages = [ssh-add-all]; - - programs.ssh = { - enable = true; - enableDefaultConfig = false; - matchBlocks."*" = { - addKeysToAgent = "yes"; - }; - }; - - # Disable default ssh-agent since we use gcr-ssh-agent (via services.gnome.gnome-keyring) - services.ssh-agent.enable = false; - - # Point to the new gcr SSH agent socket (NixOS 25.11+) - home.sessionVariables = { - SSH_AUTH_SOCK = "$XDG_RUNTIME_DIR/gcr/ssh"; - }; -} diff --git a/home/ssh/ssh-add-all.sh b/home/ssh/ssh-add-all.sh deleted file mode 100644 index cf17b5ca..00000000 --- a/home/ssh/ssh-add-all.sh +++ /dev/null @@ -1,74 +0,0 @@ -#!/usr/bin/env bash -# SSH Key Manager for GNOME Keyring -# This script adds all SSH keys from ~/.ssh to the GNOME Keyring SSH agent - -set -euo pipefail - -# Check if SSH agent is running -if [ -z "${SSH_AUTH_SOCK:-}" ]; then - echo "Error: SSH_AUTH_SOCK is not set. SSH agent might not be running." - echo "Make sure GNOME Keyring SSH agent is started." - exit 1 -fi - -# Find all SSH private keys in ~/.ssh directory -SSH_DIR="$HOME/.ssh" -if [ ! -d "$SSH_DIR" ]; then - echo "Error: SSH directory $SSH_DIR does not exist." - exit 1 -fi - -# Common SSH key patterns -KEY_PATTERNS=("id_rsa" "id_ed25519" "id_ecdsa" "id_dsa") - -echo "Looking for SSH keys in $SSH_DIR..." - -KEYS_FOUND=0 -for pattern in "${KEY_PATTERNS[@]}"; do - # Check for exact match first - if [ -f "$SSH_DIR/$pattern" ]; then - echo "Found key: $SSH_DIR/$pattern" - ssh-add "$SSH_DIR/$pattern" || echo "Warning: Failed to add $SSH_DIR/$pattern" - KEYS_FOUND=$((KEYS_FOUND + 1)) - fi - - # Check for numbered variants (e.g., id_rsa_1, id_rsa_2) - for key_file in "$SSH_DIR"/"${pattern}"_*; do - if [ -f "$key_file" ] && [[ ! "$key_file" == *.pub ]]; then - echo "Found key: $key_file" - ssh-add "$key_file" || echo "Warning: Failed to add $key_file" - KEYS_FOUND=$((KEYS_FOUND + 1)) - fi - done -done - -# Also look for any other files that look like private keys -for key_file in "$SSH_DIR"/*; do - if [ -f "$key_file" ] && [[ ! "$key_file" == *.pub ]] && [[ ! "$key_file" == *config* ]] && [[ ! "$key_file" == *known_hosts* ]]; then - # Skip if we already processed this key - basename_key=$(basename "$key_file") - already_processed=false - for pattern in "${KEY_PATTERNS[@]}"; do - if [[ "$basename_key" == "$pattern" ]] || [[ "$basename_key" == ${pattern}_* ]]; then - already_processed=true - break - fi - done - - if [ "$already_processed" = false ]; then - echo "Found potential key: $key_file" - ssh-add "$key_file" || echo "Warning: Failed to add $key_file" - KEYS_FOUND=$((KEYS_FOUND + 1)) - fi - fi -done - -if [ $KEYS_FOUND -eq 0 ]; then - echo "No SSH keys found in $SSH_DIR" - echo "You can create a new SSH key with: ssh-keygen -t ed25519 -C \"your_email@example.com\"" -else - echo "Processed $KEYS_FOUND SSH key(s)" - echo "" - echo "Current keys in SSH agent:" - ssh-add -l || echo "No keys currently loaded in SSH agent" -fi diff --git a/home/starship/default.nix b/home/starship/default.nix deleted file mode 100644 index 3825d636..00000000 --- a/home/starship/default.nix +++ /dev/null @@ -1,128 +0,0 @@ -{ - isImpermanent, - lib, - ... -}: { - home.persistence."/persist" = lib.mkIf isImpermanent { - directories = [ - ".cache/starship" - ]; - }; - - programs.starship = { - enable = true; - - enableTransience = true; - - settings = { - format = lib.concatStrings [ - "$username" - "$hostname" - "$localip" - "$shlvl" - "$singularity" - "$directory" - "$vcsh" - "$docker_context" - "$package" - "$buf" - "$c" - "$cmake" - "$cobol" - "$container" - "$daml" - "$dart" - "$deno" - "$dotnet" - "$elixir" - "$elm" - "$erlang" - "$golang" - "$haskell" - "$helm" - "$java" - "$julia" - "$kotlin" - "$lua" - "$nim" - "$nodejs" - "$ocaml" - "$perl" - "$php" - "$pulumi" - "$purescript" - "$python" - "$rlang" - "$red" - "$ruby" - "$rust" - "$scala" - "$swift" - "$terraform" - "$vlang" - "$vagrant" - "$zig" - "$nix_shell" - "$conda" - "$spack" - "$memory_usage" - "$aws" - "$gcloud" - "$kubernetes" - "$openstack" - "$azure" - "$env_var" - "$crystal" - "$custom" - "$sudo" - "$cmd_duration" - "$line_break" - "$jobs" - "$battery" - "$time" - "$status" - "$shell" - "$character" - ]; - - aws = { - disabled = true; - }; - - gcloud = { - disabled = true; - format = "on [$symbol$account(@$domain)|($project)](green) "; - }; - - kubernetes = { - disabled = false; - style = "green"; - contexts = [ - { - "context_pattern" = "kind-kind"; - "context_alias" = "kind"; - } - ]; - }; - - shell = { - disabled = false; - fish_indicator = "🐟"; - bash_indicator = "💩"; - nu_indicator = "🦀"; - }; - - status = { - disabled = false; - map_symbol = true; - pipestatus = false; - }; - - nix_shell = { - disabled = true; - format = "via [$symbol$state]($style) "; - impure_msg = ""; - }; - }; - }; -} diff --git a/home/stylix/default.nix b/home/stylix/default.nix deleted file mode 100644 index 35c0bb79..00000000 --- a/home/stylix/default.nix +++ /dev/null @@ -1,19 +0,0 @@ -{pkgs, ...}: { - home.packages = [ - pkgs.papirus-icon-theme - ]; - stylix = { - iconTheme = { - enable = true; - package = pkgs.papirus-icon-theme; - light = "Papirus-Light"; - dark = "Papirus-Dark"; - }; - targets = { - firefox = { - profileNames = ["main"]; - }; - neovim.enable = false; - }; - }; -} diff --git a/home/syncthing/default.nix b/home/syncthing/default.nix deleted file mode 100644 index 452f1be5..00000000 --- a/home/syncthing/default.nix +++ /dev/null @@ -1,30 +0,0 @@ -{ - isImpermanent, - lib, - ... -}: { - home.persistence."/persist" = lib.mkIf isImpermanent { - directories = [ - ".local/state/syncthing" # device keys and certificates - ".config/syncthing" # pre-v1.27.0 uses this instead of $XDG_STATE_HOME above, keeping for backward-compatibility - ]; - files = [ - ".config/syncthingtray.ini" - ]; - }; - - services.syncthing = { - enable = true; - tray = { - enable = true; - command = "syncthingtray --wait"; - }; - }; - - systemd.user.services.syncthingtray = { - Service = { - Restart = "on-failure"; - RestartSec = 5; - }; - }; -} diff --git a/home/systemd-errors-and-warnings-counter/default.nix b/home/systemd-errors-and-warnings-counter/default.nix deleted file mode 100644 index 2f962c2e..00000000 --- a/home/systemd-errors-and-warnings-counter/default.nix +++ /dev/null @@ -1,10 +0,0 @@ -# Display number of systemd errors and warnings in last 10 minutes -{pkgs, ...}: let - systemd-errors-and-warnings-counter = pkgs.writeShellApplication { - name = "systemd-errors-and-warnings-counter"; - runtimeInputs = [pkgs.systemd pkgs.coreutils]; - text = builtins.readFile ./scripts/systemd-errors-and-warnings-counter.sh; - }; -in { - home.packages = [systemd-errors-and-warnings-counter]; -} diff --git a/home/systemd-errors-and-warnings-counter/scripts/systemd-errors-and-warnings-counter.sh b/home/systemd-errors-and-warnings-counter/scripts/systemd-errors-and-warnings-counter.sh deleted file mode 100644 index 24691ce8..00000000 --- a/home/systemd-errors-and-warnings-counter/scripts/systemd-errors-and-warnings-counter.sh +++ /dev/null @@ -1,18 +0,0 @@ -WARNINGS=$(journalctl -p 4..4 --since "10 minutes ago" --boot --output json | wc -l) -ERRORS=$(journalctl -p 3..3 --since "10 minutes ago" --boot --output json | wc -l) - -WARNING_ICON="⚠️" -ERROR_ICON="❗" - -# Determine state based on number of errors -if [ "$ERRORS" -eq 0 ]; then - STATE="Good" -elif [ "$ERRORS" -le 2 ]; then - STATE="Info" -elif [ "$ERRORS" -le 5 ]; then - STATE="Warning" -else - STATE="Critical" -fi - -echo "{\"text\":\"${ERROR_ICON}${ERRORS} ${WARNING_ICON}${WARNINGS}\",\"short_text\":\"${ERRORS}\",\"state\":\"${STATE}\"}" diff --git a/home/tealdeer/default.nix b/home/tealdeer/default.nix deleted file mode 100644 index d31d3eba..00000000 --- a/home/tealdeer/default.nix +++ /dev/null @@ -1,20 +0,0 @@ -{ - lib, - isImpermanent, - ... -}: { - home.persistence."/persist" = lib.mkIf isImpermanent { - directories = [ - ".cache/tealdeer" - ]; - }; - - programs.tealdeer = { - enable = true; - settings = { - updates = { - auto_update = true; - }; - }; - }; -} diff --git a/home/telegram/default.nix b/home/telegram/default.nix deleted file mode 100644 index 16139d0e..00000000 --- a/home/telegram/default.nix +++ /dev/null @@ -1,16 +0,0 @@ -{ - lib, - isImpermanent, - pkgs, - ... -}: { - home.persistence."/persist" = lib.mkIf isImpermanent { - directories = [ - ".local/share/TelegramDesktop" - ]; - }; - - home.packages = [ - pkgs.telegram-desktop - ]; -} diff --git a/home/television/default.nix b/home/television/default.nix deleted file mode 100644 index 1d9c2acc..00000000 --- a/home/television/default.nix +++ /dev/null @@ -1,18 +0,0 @@ -{ - isImpermanent, - lib, - ... -}: { - home.persistence."/persist" = lib.mkIf isImpermanent { - directories = [ - ".config/television/cable" - ]; - }; - - programs.television = { - enable = true; - }; - programs.nix-search-tv = { - enable = true; - }; -} diff --git a/home/tomat/default.nix b/home/tomat/default.nix deleted file mode 100644 index d28be98f..00000000 --- a/home/tomat/default.nix +++ /dev/null @@ -1,5 +0,0 @@ -{...}: { - services.tomat = { - enable = true; - }; -} diff --git a/home/trash-cli/default.nix b/home/trash-cli/default.nix deleted file mode 100644 index e235870a..00000000 --- a/home/trash-cli/default.nix +++ /dev/null @@ -1,5 +0,0 @@ -{pkgs, ...}: { - home.packages = [ - pkgs.trash-cli - ]; -} diff --git a/home/tray-tui/default.nix b/home/tray-tui/default.nix deleted file mode 100644 index 7f4fc046..00000000 --- a/home/tray-tui/default.nix +++ /dev/null @@ -1,5 +0,0 @@ -{...}: { - programs.tray-tui = { - enable = true; - }; -} diff --git a/home/udiskie/default.nix b/home/udiskie/default.nix deleted file mode 100644 index 2704edbf..00000000 --- a/home/udiskie/default.nix +++ /dev/null @@ -1,27 +0,0 @@ -# Indicator icon for automounting USB drives -{ - lib, - pkgs, - ... -}: { - services.udiskie = { - enable = true; - automount = false; - }; - - # Ensure udiskie starts after the Niri session is up, to avoid tray race conditions - systemd.user.services.udiskie = { - Unit = { - After = ["niri.service" "graphical-session.target"]; - Wants = ["graphical-session.target"]; - # Relax environment conditions in case defaults are too strict for Niri - ConditionEnvironment = lib.mkForce []; - }; - Service = { - # Small delay to ensure Wayland environment and tray are ready - ExecStartPre = "${pkgs.coreutils}/bin/sleep 2"; - Restart = lib.mkForce "on-failure"; - RestartSec = "5"; - }; - }; -} diff --git a/home/urxvt/default.nix b/home/urxvt/default.nix deleted file mode 100644 index 9e2ddafa..00000000 --- a/home/urxvt/default.nix +++ /dev/null @@ -1,38 +0,0 @@ -{pkgs, ...}: { - programs.urxvt = { - enable = true; - - extraConfig = { - # Perl extensions - perl-ext-common = "default,matcher,resize-font,vtwheel,keyboard-select,-searchable-scrollback"; - - # Matcher (clickable URLs) - url-launcher = "${pkgs.xdg-utils}/bin/xdg-open"; - "matcher.button" = 1; - - # Messes with CTRL+SHIFT Keybindings, see https://wiki.archlinux.org/index.php/Rxvt-unicode#Perl_extensions - iso14755_52 = false; - - # https://github.com/muennich/urxvt-perls#keyboard-select - "keyboard-select.clipboard" = true; - }; - - fonts = ["xft:FiraCode Nerd Font Mono:size=8"]; - - # Messes with CTRL+SHIFT Keybindings, see https://wiki.archlinux.org/index.php/Rxvt-unicode#Perl_extensions - iso14755 = false; - - keybindings = { - "Shift-Control-C" = "eval:selection_to_clipboard"; - "Shift-Control-V" = "eval:paste_clipboard"; - - # https://github.com/muennich/urxvt-perls#keyboard-select - "Meta-Escape" = "perl:keyboard-select:activate"; - "Meta-Shift-S" = "perl:keyboard-select:search"; - }; - - package = pkgs.rxvt-unicode; - - scroll.bar.enable = false; - }; -} diff --git a/home/variety/default.nix b/home/variety/default.nix deleted file mode 100644 index 2190de6f..00000000 --- a/home/variety/default.nix +++ /dev/null @@ -1,9 +0,0 @@ -{pkgs, ...}: { - home.packages = [ - pkgs.variety - ]; - - home.file = { - ".config/variety/variety.conf".source = ./variety.conf; - }; -} diff --git a/home/variety/variety.conf b/home/variety/variety.conf deleted file mode 100644 index 57116dd5..00000000 --- a/home/variety/variety.conf +++ /dev/null @@ -1,225 +0,0 @@ -# change_on_start = -change_on_start = False - -# change_enabled = -change_enabled = True - -# change_interval = -change_interval = 86400 - -# safe_mode = -safe_mode = False - -# download_folder = - when not specified, the default is ~/.config/variety/Downloaded -download_folder = ~/.config/variety/Downloaded - -# download_preference_ratio - if we have "unconsumed" download sources, we'll prefer to show a newly -# downloades image instead of an existing one in this percentage of the cases -download_preference_ratio = 0.9 - -# Determine if the download folder sould not exceed a certain size (in megabytes) -# quota_enabled = -# quota_size = -quota_enabled = False -quota_size = 1000 - -# favorites_folder = - when not specified, the default is ~/.config/variety/Favorites -favorites_folder = ~/Pictures/variety/Favorites - -# Prefer Copy to Favorites or Move to Favorites operation (or both), depending on the folder of the current image -# favorites_operations = -# The default is: Downloaded:Copy;Fetched:Move;Others:Copy -# Order is important - the first matching entry will determine what operation(s) to show in the menu for a specific file -# Special folder names you can use: Downloaded, Fetched and Others (same as "/" - use it as last entry to determine the default operation) -# Example1: Downloaded:Copy;Fetched:Move;/pics/RandomImages:Move;/pics/OrganizedAlbums:Copy;Others:Copy -# Example2: Others:Both - always show both Copy and Move to Favorites, no matter which image is shown -# Move to Favorites is only shown when the user has write permissions over the file, otherwise we fallback to Copy -favorites_operations = Downloaded:Copy;Fetched:Move;Others:Copy - -# wallpaper_display_mode = <"os" | -# "smart" | "zoom" | "fill-with-black" | "fill-with-blur" | -# "gnome-zoom" | "gnome-centered" | "gnome-scaled" | "gnome-stretched" | "gnome-spanned", "gnome-wallpaper"> -wallpaper_display_mode = "smart" - -# fetch_folder = - when not specified, the default is ~/.config/variety/Fetched -fetched_folder = ~/.config/variety/Fetched - -# Clipboard monitoring settings -# clipboard_enabled = -# clipboard_use_whitelist = -# clipboard_hosts = -clipboard_enabled = False -clipboard_use_whitelist = True -clipboard_hosts = "wallhaven.cc,wallpapers.net,flickr.com,imgur.com,deviantart.com,interfacelift.com,vladstudio.com,imageshack.us,deviantart.net,imageshack.com" - -# Icon settings -# icon = -icon = Dark - -# Prefer only images with this color: -# desired_color_enabled = -# desired_color = -# DISCLAIMER: This feature is still experimental -desired_color_enabled = False -desired_color = 160 160 160 - -# Minimum size of images to use, as a percentage of the screen resolution -# min_size_enabled = -# min_size = -min_size_enabled = True -min_size = 80 - -# Should we use only landscape-oriented images? -# use_landscape_enabled = -use_landscape_enabled = True - -# Prefer light or dark images -# lightness_enabled = -# lightness_mode = <0 for Dark, 1 for Light> -lightness_enabled = True -lightness_mode = 0 - -# Use a filter by rating? -# min_rating_enabled = -# min_rating = <1 | 2 | 3 | 4 | 5> -min_rating_enabled = False -min_rating = 4 - -# What parts of the initial wizard have we covered -smart_notice_shown = False -smart_register_shown = False -stats_notice_shown = False - -# Are smart features enabled (i.e. data collection on Fav/Trash operations), also sync, and anonymous usage stats collection? -# smart_enabled = -smart_enabled = True -sync_enabled = True -stats_enabled = True - -# Folder to copy the wallpaper image to and make it world-readable. Provides LightDM support. -# copyto_enabled = , default is False -# copyto_folder = , the default is Default -# Default means to use the XDG Pictures folder when home folder is unencrypted and /usr/share/backgrounds when it is encrypted. -copyto_enabled = False -copyto_folder = Default - -# Clock settings -# clock_enabled = -# clock_font = , default is "Ubuntu Condensed, 70" -# clock_date_font = , default is "Ubuntu Condensed, 30" -clock_enabled = False -clock_font = "Ubuntu Condensed, 70" -clock_date_font = "Ubuntu Condensed, 30" - -# clock_filter = -# -# The filter defines the ImageMagick command that Variety uses to render the clock on the wallpaper. -# First some scaling is applied to get the image down to the screen size - this ensures -# the final drawn clock won't be rescaled by the desktop wallpaper system. -# Easiest way to see what's happening is to run variety with -v, enable clock and see what ImageMagick -# commands Variety dumps in the log. -# -# The user may want to customize the following aspects: -# fill - color of "filling" -# stroke - color of outline -# strokewidth - width of outline -# gravity - in which corner to display the clock - SouthEast, NorthEast, SouthWest, NorthWest -# annotate - these must be in the form 0x0+[%HOFFSET+X]+[%VOFFSET+Y], where you can edit X and Y - -# distance from the screen corner defined by gravity. Write them in even if they are 0. -# -# The %HOFFSET and %VOFFSET parameters are there for Variety to replace in order to compensate for the -# diferent dimensions of every image and screen. -# The several %FONT parameters are there for Variety to replace with the font settings from the GUI. -# -# The texts can contain these symbols: -# -# %H - hours (24), %I - zero-padded hours (12), %l - hours (12), %p - am or pm, %M - minutes, -# %A - day of week (full), %a - day of week abbreviation, %B - month name, %b - month abbreviation, %d - day of month, %Y - year. -# The full list for these can be seen here: http://docs.python.org/library/datetime.html#strftime-strptime-behavior -# Have in mind that Variety will not update the clock more often than once every minute, so using seconds (%S) for example is pointless -# -# A tutorial on "annotating" with ImageMagick that you may use as a reference: http://www.imagemagick.org/Usage/annotating/ -# You can get a very uniquely looking clock with some of the more advanced techniques (e.g. circle-shaped text, interesting colors and shading, etc....). - -clock_filter = "-density 100 -font `fc-match -f '%{file[0]}' '%CLOCK_FONT_NAME'` -pointsize %CLOCK_FONT_SIZE -gravity SouthEast -fill '#00000044' -annotate 0x0+[%HOFFSET+58]+[%VOFFSET+108] '%H:%M' -fill white -annotate 0x0+[%HOFFSET+60]+[%VOFFSET+110] '%H:%M' -font `fc-match -f '%{file[0]}' '%DATE_FONT_NAME'` -pointsize %DATE_FONT_SIZE -fill '#00000044' -annotate 0x0+[%HOFFSET+58]+[%VOFFSET+58] '%A, %B %d' -fill white -annotate 0x0+[%HOFFSET+60]+[%VOFFSET+60] '%A, %B %d'" - -# Quotes settings -# quotes_enabled = -# quotes_font = , default is Bitstream Charter 30 -# quotes_text_color = , default is 255 255 255 -# quotes_bg_color = , default is 80 80 80 -# quotes_bg_opacity = <0-100>, default is 55 -# quotes_width = <0-100>, default is 70 -# quotes_hpos = <0-100>, default is 100 -# quotes_vpos = <0-100>, default is 40 -# quotes_max_length = a positive integer, quotes above this length will not be displayed -# (as they often won't fit well on screen) -# quotes_text_shadow = , default is False -# quotes_disabled_sources = <|-separated list of disabled quote plugin names>, default is empty -# quotes_tags = , default is empty -# quotes_authors = , default is empty -# quotes_change_enabled = -# quotes_change_interval = , default is 300 -quotes_enabled = True -quotes_font = Fira Code 30 -quotes_text_color = 234 212 155 # #ead49b -quotes_bg_color = 30 39 43 # #1e272b -quotes_bg_opacity = 55 -quotes_text_shadow = False -quotes_width = 70 -quotes_hpos = 100 -quotes_vpos = 40 -quotes_max_length = 250 -quotes_disabled_sources = "Urban Dictionary" -quotes_tags = "" -quotes_authors = "" -quotes_change_enabled = False -quotes_change_interval = 86400 -quotes_favorites_file = ~/Pictures/variety/favorite_quotes.txt -quotes_favorites_format = fortune - -# Slideshow settings -slideshow_favorites_enabled = True -slideshow_sources_enabled = True -slideshow_downloads_enabled = False -slideshow_custom_enabled = False -slideshow_custom_folder = ~/Pictures -slideshow_sort_order = Random -slideshow_monitor = All -slideshow_mode = Fullscreen -slideshow_seconds = 6.0 -slideshow_fade = 0.4 -slideshow_zoom = 0.2 -slideshow_pan = 0.05 - -# List of sources -# Each source is srcX = -# location depends on type - path or url or search options, or just a name for unconfigurable sources -# Folders are included recursively -# BE CAREFUL: all keys below (src1, src2, etc.) MUST be different -[sources] -src1 = True|favorites|The Favorites folder -src2 = False|fetched|The Fetched folder -src3 = True|folder|/usr/share/backgrounds -src4 = False|flickr|user:www.flickr.com/photos/peter-levi/;user_id:93647178@N00; -src5 = True|apod|NASA's Astronomy Picture of the Day -src6 = True|bing|Bing Photo of the Day -src7 = True|chromeos|Chrome OS Wallpapers -src8 = True|desktoppr|Random wallpapers from Desktoppr.co -src9 = False|earth|World Sunlight Map - live wallpaper from Die.net -src10 = False|earthview|Google Earth View Wallpapers -src11 = True|unsplash|High-resolution photos from Unsplash.com -src12 = True|natgeo|National Geographic Photo of the Day - -# Image filters to apply randomly to every wallpaper (ImageMagick is used for this) -# Each filter is filterX = -# BE CAREFUL: all keys below (filter1, filter2, etc.) MUST be different -[filters] -filter1 = True|Keep original| -filter2 = False|Grayscale|-type Grayscale -filter3 = False|Heavy blur|-blur 120x40 -filter4 = False|Soft blur|-blur 20x7 -filter5 = True|Oil painting|-paint 8 -filter6 = False|Pointilism|-spread 10 -noise 3 -filter7 = False|Pixellate|-scale 3% -scale 3333% - diff --git a/home/virtual-cable/default.nix b/home/virtual-cable/default.nix deleted file mode 100644 index fb70f452..00000000 --- a/home/virtual-cable/default.nix +++ /dev/null @@ -1,21 +0,0 @@ -# Virtual inputs/outputs via Pipewire (for OBS and beyond) -{pkgs, ...}: let - obs-mic = pkgs.writers.writeBashBin "obs-mic" (builtins.readFile ./scripts/obs-mic.sh); -in { - home.packages = [obs-mic]; - - systemd.user.services.obs-mic = { - Unit = { - After = ["wireplumber.service"]; - Description = "Set up virtualMic and virtualSpeaker for OBS"; - Requires = ["wireplumber.service"]; - }; - Install.WantedBy = ["wireplumber.service"]; - Service = { - Environment = "PATH=$PATH:/run/current-system/sw/bin"; - ExecStartPre = "${pkgs.coreutils}/bin/sleep 5"; # TODO: Find a better way to wait for WirePlumber to fully start - ExecStart = "${obs-mic}/bin/obs-mic"; - Type = "oneshot"; - }; - }; -} diff --git a/home/virtual-cable/scripts/obs-mic.sh b/home/virtual-cable/scripts/obs-mic.sh deleted file mode 100644 index d63ca83d..00000000 --- a/home/virtual-cable/scripts/obs-mic.sh +++ /dev/null @@ -1,13 +0,0 @@ -set -euo pipefail - -# Create a virtual sink that can be set as a monitor in OBS -if ! pactl list short sinks | grep -q ObsSpeaker; then - pactl load-module module-null-sink sink_name=ObsSpeaker sink_properties=device.description=VirtualSpeaker -fi - -# Link it with a virtual source that is visible in pulseaudio apps like Zoom -if ! pactl list short sources | grep -q ObsMic; then - pactl load-module module-null-sink media.class=Audio/Source/Virtual sink_name=ObsMic channel_map=front-left,front-right - pw-link ObsSpeaker:monitor_FL ObsMic:input_FL - pw-link ObsSpeaker:monitor_FR ObsMic:input_FR -fi diff --git a/home/vlc/default.nix b/home/vlc/default.nix deleted file mode 100644 index c1ffcb7e..00000000 --- a/home/vlc/default.nix +++ /dev/null @@ -1,17 +0,0 @@ -{ - lib, - isImpermanent, - pkgs, - ... -}: { - home.persistence."/persist" = lib.mkIf isImpermanent { - directories = [ - ".config/vlc" - ".local/share/vlc" - ]; - }; - - home.packages = [ - pkgs.vlc - ]; -} diff --git a/home/waybar/default.nix b/home/waybar/default.nix deleted file mode 100644 index 8c8a2f71..00000000 --- a/home/waybar/default.nix +++ /dev/null @@ -1,578 +0,0 @@ -{ - config, - lib, - isNvidia, - osConfig, - pkgs, - ... -}: let - dunst-dnd-waybar = pkgs.writeShellApplication { - name = "dunst-dnd-waybar"; - runtimeInputs = [pkgs.dunst]; - text = builtins.readFile ./scripts/dunst-dnd-waybar.sh; - }; - hostName = osConfig.networking.hostName; - isNumenor = hostName == "numenor"; - isFlexbox = hostName == "flexbox"; - - leftSection = { - modules-left = [ - "niri/workspaces" - ]; - }; - - centerSection = { - modules-center = [ - "systemd-failed-units" - "group/cpu" - "memory" - "disk" - "group/gpu" - "group/network" - "group/screens" - "group/audio" - "bluetooth" - "group/power" - ]; - - systemd-failed-units = { - format = " {nr_failed} failed"; - format-ok = " 0"; - hide-on-ok = false; - on-click = "alacritty --command journalctl --pager-end --catalog --boot --priority 3..3 | lnav"; - on-click-right = "alacritty --command isd"; - }; - - "group/cpu" = { - modules = [ - "cpu" - "temperature#cpu" - "custom/cpu-profile-toggler" - ]; - orientation = "inherit"; - }; - - cpu = { - format = " {usage}%"; - states = { - info = 80; - }; - on-click = "alacritty --command btop"; - on-click-right = "alacritty --command btop"; - }; - - "temperature#cpu" = { - critical-threshold = 90; - format = " {temperatureC}°C"; - on-click = "alacritty --command btop"; - on-click-right = "alacritty --command btop"; - hwmon-path = - if isNumenor - then "/sys/devices/pci0000:00/0000:00:18.3/hwmon/hwmon2/temp1_input" - else "/sys/devices/platform/coretemp.0/hwmon/hwmon7/temp1_input"; - }; - - "custom/cpu-profile-toggler" = { - format = "{icon}"; - format-icons = { - performance = ""; - powersave = ""; - }; - exec = "cpu-profile-toggler"; - on-click = "auto-cpufreq-gtk"; - on-click-middle = "cpu-profile-toggler --toggle"; - on-click-right = "cpu-profile-toggler --reset"; - return-type = "json"; - interval = 5; - }; - - memory = { - format = " {percentage}%"; - states = { - warning = 60; - critical = 80; - }; - on-click = "alacritty --command btop"; - on-click-right = "alacritty --command btop"; - tooltip-format = "{used:0.1f}GiB mem used, {swapUsed:0.1f}GiB swap used"; - }; - - disk = { - format = " {percentage_used}%"; - on-click = "alacritty --command ncdu /"; - on-click-right = "alacritty --command btop"; - states = { - warning = 60; - critical = 80; - }; - }; - - "group/gpu" = { - modules = - [ - ( - if isNvidia - then "custom/nvidia" - else "custom/gpu-usage" - ) - ] - ++ lib.optional (!isNvidia) "temperature#gpu"; - orientation = "inherit"; - }; - - "custom/gpu-usage" = { - exec = "cat /sys/class/hwmon/hwmon1/device/gpu_busy_percent"; - format = " {}%"; - return-type = ""; - interval = 1; - on-click = "alacritty --command nvtop"; - on-click-right = "alacritty --command nvtop"; - }; - - "custom/nvidia" = { - exec = "nvidia-smi --query-gpu=utilization.gpu,temperature.gpu --format=csv,nounits,noheader | sed 's/\\([0-9]\\+\\), \\([0-9]\\+\\)/\\1%  \\2°C/g'"; - format = " {}"; - interval = 2; - on-click = "alacritty --command nvtop"; - on-click-right = "alacritty --command nvtop"; - }; - - "temperature#gpu" = { - critical-threshold = 90; - on-click = "alacritty --command nvtop"; - on-click-right = "alacritty --command nvtop"; - hwmon-path = - if isNumenor - then "/sys/devices/pci0000:00/0000:00:01.1/0000:01:00.0/0000:02:00.0/0000:03:00.0/hwmon/hwmon1/temp2_input" - else "TODO find me according to waybar docs similar to CPU temp hwmon path"; - }; - - "group/network" = { - modules = ["network" "network#tailscale" "custom/macgyver" "network#mullvad" "network#wireguard"]; - orientation = "inherit"; - }; - - "network" = { - interval = 3; - format = " "; - format-disconnected = " "; - format-ethernet = " "; - format-wifi = " "; - format-linked = " 🚧"; - format-alt = "{bandwidthDownBytes} {bandwidthUpBytes}"; - tooltip-format = "IF:{ifname} SSID:{essid} FREQ:{frequency} :{signalStrength} IP:{ipaddr} GW:{gwaddr} NM:{netmask} {bandwidthDownBytes} {bandwidthUpBytes}"; - tooltip-format-ethernet = "IF:{ifname} IP:{ipaddr} NM:{netmask} {bandwidthDownBytes} {bandwidthUpBytes}"; - tooltip-format-wifi = "IF:{ifname} SSID:{essid} FREQ:{frequency} :{signalStrength} IP:{ipaddr} GW:{gwaddr} NM:{netmask} {bandwidthDownBytes} {bandwidthUpBytes}"; - tooltip-format-linked = "IF:{ifname} IP:{ipaddr} Connected but no internet"; - on-click-right = "alacritty --command nmtui"; - }; - - "network#tailscale" = { - interface = "tailscale0"; - interval = 3; - format-linked = " "; - format = " "; - format-alt = " {bandwidthDownBytes} {bandwidthUpBytes}"; - tooltip-format = " Tailscale IP:{ipaddr} NM:{netmask} {bandwidthDownBytes} {bandwidthUpBytes}"; - tooltip-format-linked = " Tailscale down. Right click to connect."; - on-click-right = "tailscale up"; - on-click-middle = "tailscale down"; - }; - - "custom/macgyver" = { - exec = "macgyver-status"; - return-type = "json"; - interval = 3; - format = "{icon}"; - format-icons = { - up = ""; - down = ""; - error = "❌"; - }; - tooltip-format = " MacGyver is {text}"; - on-click-right = "sudo systemctl start macgyver"; - on-click-middle = "sudo systemctl stop macgyver"; - }; - - "network#mullvad" = { - interface = "wg0-mullvad"; - interval = 3; - format-disconnected = " "; - format-disabled = " "; - format-linked = " "; - format = " "; - format-alt = " {bandwidthDownBytes} {bandwidthUpBytes}"; - tooltip-format = " Mullvad IP:{ipaddr} NM:{netmask} {bandwidthDownBytes} {bandwidthUpBytes}"; - tooltip-format-linked = " Mullvad down. Right click to connect or double right click for GUI."; - tooltip-format-disabled = " Mullvad down. Rickt click to connect or double right click for GUI."; - on-click-right = "mullvad connect"; - on-double-click-right = "mullvad-gui"; - on-click-middle = "mullvad disconnect"; - }; - - "network#wireguard" = { - interface = "wg0"; - interval = 3; - format-disconnected = " "; - format-disabled = " "; - format-linked = " "; - format = " "; - format-alt = " {bandwidthDownBytes} {bandwidthUpBytes}"; - tooltip-format = " Wireguard IP:{ipaddr} GW:{gwaddr} NM:{netmask} {bandwidthDownBytes} {bandwidthUpBytes}"; - tooltip-format-linked = " Wireguard down."; - tooltip-format-disabled = " Wireguard down."; - }; - - "group/screens" = { - modules = - if isFlexbox - then ["backlight" "custom/wlsunset"] - else ["custom/ddc-backlight-left" "custom/ddc-backlight-middle" "custom/ddc-backlight-right" "custom/wlsunset"]; - orientation = "inherit"; - }; - - backlight = { - format = "{icon} {percent}%"; - format-icons = ["🌑" "🌘" "🌗" "🌖" "🌕"]; - }; - - # Direct ddcutil control - required for monitors that only expose VCP Feature 10 (Brightness) - # rather than the "Backlight Level White" feature that ddcci-driver-linux requires - # See https://gitlab.com/ddcci-driver-linux/ddcci-driver-linux - "custom/ddc-backlight-left" = { - format = "{icon} "; - tooltip-format = "Left {percentage}%"; - format-icons = ["🌑" "🌘" "🌗" "🌖" "🌕"]; - exec = "ddc-backlight 7"; # For i2c-7 - exec-on-event = false; - on-scroll-up = "flock /tmp/ddc_backlight.lock ddcutil setvcp 10 + 5 -b 7"; - on-scroll-down = "flock /tmp/ddc_backlight.lock ddcutil setvcp 10 - 5 -b 7"; - on-click = "kanshictl switch numenor-movie"; - on-click-middle = "wdisplays"; - on-click-right = "kanshictl switch numenor"; - return-type = "json"; - interval = 60; - }; - - "custom/ddc-backlight-middle" = { - format = "{icon} "; - tooltip-format = "Middle {percentage}%"; - format-icons = ["🌑" "🌘" "🌗" "🌖" "🌕"]; - exec = "ddc-backlight 9"; # For i2c-9 - exec-on-event = false; - on-scroll-up = "flock /tmp/ddc_backlight.lock ddcutil setvcp 10 + 5 -b 9"; - on-scroll-down = "flock /tmp/ddc_backlight.lock ddcutil setvcp 10 - 5 -b 9"; - on-click = "kanshictl switch numenor-movie"; - on-click-middle = "wdisplays"; - on-click-right = "kanshictl switch numenor"; - return-type = "json"; - interval = 60; - }; - - "custom/ddc-backlight-right" = { - format = "{icon}"; - tooltip-format = "Right {percentage}%"; - format-icons = ["🌑" "🌘" "🌗" "🌖" "🌕"]; - exec = "ddc-backlight 6"; # For i2c-6 - exec-on-event = false; - on-scroll-up = "flock /tmp/ddc_backlight.lock ddcutil setvcp 10 + 5 -b 6"; - on-scroll-down = "flock /tmp/ddc_backlight.lock ddcutil setvcp 10 - 5 -b 6"; - on-click = "kanshictl switch numenor-movie"; - on-click-middle = "wdisplays"; - on-click-right = "kanshictl switch numenor"; - return-type = "json"; - interval = 60; - }; - - "custom/wlsunset" = { - interval = 1; - exec = "if pgrep wlsunset >/dev/null 2>&1; then stdbuf -oL printf '{\"alt\": \"on\",\"class\": \"on\"}'; else stdbuf -oL printf '{\"alt\": \"off\",\"class\": \"off\"}'; fi"; - on-click = "wlsunset-waybar"; - return-type = "json"; - format = " {icon}"; - tooltip-format = "wlsunset: {alt}"; - signal = 1; # SIGRTMIN+1 or 35 for updating immediately from script - format-icons = { - on = ""; - off = ""; - }; - }; - - "group/audio" = { - modules = [ - "pulseaudio#in" - "pulseaudio#out" - "mpris" - ]; - orientation = "inherit"; - }; - - "pulseaudio#in" = { - format = "{format_source}"; - format-source = " {volume}%"; - format-source-muted = ""; - format-icons = { - "bluez_input.DC:69:E2:9A:6E:30" = ""; - "alsa_input.usb-Apple__Inc._USB-C_to_3.5mm_Headphone_Jack_Adapter_DWH84440324JKLTA7-00.mono-fallback" = ""; - default = ["" ""]; - }; - max-volume = 200; - scroll-step = 5; - on-scroll-up = "pactl set-source-volume @DEFAULT_SOURCE@ +5%"; - on-scroll-down = "pactl set-source-volume @DEFAULT_SOURCE@ -5%"; - on-click = "pavucontrol --tab=4"; - on-click-right = "alacritty --command pulsemixer"; - on-click-middle = "pactl set-source-mute @DEFAULT_SOURCE@ toggle"; - tooltip-format = "{format_source}"; - }; - - "pulseaudio#out" = { - format = "{icon} {volume}%"; - format-bluetooth = "{icon} {volume}%"; - format-muted = ""; - format-icons = { - "alsa_output.usb-Generic_USB_Audio-00.analog-stereo" = ""; - "alsa_output.usb-Lenovo_ThinkPad_Thunderbolt_3_Dock_USB_Audio_000000000000-00.analog-stereo" = ""; - "bluez_output.14_3F_A6_28_DC_51.1" = ""; - "alsa_output.pci-0000_03_00.1.hdmi-stereo-extra3" = "🍿"; - "bluez_output.DC_69_E2_9A_6E_30.1" = ""; - "bluez_sink.DC_69_E2_9A_6E_30.handsfree_head_unit" = ""; - "alsa_output.pci-0000_00_1f.3-platform-sof_sdw.HiFi___ucm0003.hw_sofsoundwire_2__sink" = ""; - "alsa_output.pci-0000_00_1f.3-platform-sof_sdw.HiFi___ucm0005.hw_sofsoundwire_2__sink" = ""; - "alsa_output.pci-0000_00_1f.3-platform-sof_sdw.HiFi___ucm0007.hw_sofsoundwire_2__sink" = ""; - "alsa_output.pci-0000_00_1f.3-platform-sof_sdw.HiFi__hw_sofsoundwire_2__sink" = ""; - "alsa_output.pci-0000_00_1f.3-platform-sof_sdw.HiFi__Speaker__sink" = ""; - "alsa_output.pci-0000_00_1f.3-platform-sof_sdw.HiFi__hw_sofsoundwire__sink" = ""; - "alsa_output.usb-Apple__Inc._USB-C_to_3.5mm_Headphone_Jack_Adapter_DWH84440324JKLTA7-00.analog-stereo" = ""; - "bluez_output.34_E3_FB_C5_01_E0.1" = ""; - "bluez_sink.34_E3_FB_C5_01_E0.handsfree_head_unit" = ""; - default = ["" ""]; - }; - max-volume = 200; - on-click = "pavucontrol --tab=3"; - on-click-right = "alacritty --command pulsemixer"; - on-click-middle = "pactl set-sink-mute @DEFAULT_SINK@ toggle"; - ignored-sinks = ["Easy Effects Sink"]; - }; - - mpris = { - format = "{player_icon}"; - format-paused = "{status_icon}"; - on-click-right = ''niri msg action focus-window --id $(niri msg --json windows | jq -r '.[] | select(.app_id == "YouTube Music Desktop App") | .id')''; - player-icons = { - default = "▶"; - mpv = ""; - chromium = ""; - }; - status-icons = { - paused = "⏸"; - }; - }; - - bluetooth = { - format = "{icon}"; - format-connected = "{icon} {num_connections}"; - format-connnected-battery = "{icon} {num_connections} {device_battery_percentage}%"; - format-icons = { - connected = ""; - on = ""; - off = ""; - disabled = ""; - disconnected = ""; - default = ""; - }; - on-click = "bluetoothctl power on"; - on-click-right = "bluetoothctl power off"; - on-click-middle = "blueman-manager"; - tooltip-format = "{status} {num_connections}"; - }; - - "group/power" = { - modules = [ - "battery" - ]; - orientation = "inherit"; - }; - - battery = { - events = { - on-discharging-warning = "notify-send -u normal 'Low Battery'"; - on-discharging-critical = "notify-send -u critical 'Very Low Battery'"; - on-charging-100 = "notify-send -u normal 'Battery is full'"; - }; - states = { - warning = 30; - critical = 15; - }; - format = " {icon} {capacity}%"; - format-icons = ["" "" "" "" ""]; - tooltip = true; - backend = "upower"; - }; - }; - - rightSection = { - modules-right = [ - "privacy" - "custom/dunst-dnd" - "custom/caffeinate" - "niri/language" - "clock" - "tray" - ]; - - "custom/dunst-dnd" = { - exec = "${dunst-dnd-waybar}/bin/dunst-dnd-waybar"; - return-type = "json"; - interval = 1; - format = "{icon}{text}"; - tooltip-format = "{text}"; - format-icons = { - running = ""; - dnd = ""; - }; - on-click = "dunstctl set-paused toggle"; - on-click-right = "dunstctl set-paused false"; - }; - - "custom/caffeinate" = { - exec = "if systemctl --user is-active swayidle >/dev/null 2>&1; then echo '{\"alt\": \"deactivated\", \"class\": \"deactivated\"}'; else echo '{\"alt\": \"activated\", \"class\": \"activated\"}'; fi"; - return-type = "json"; - interval = 1; - format = " {icon}"; - format-icons = { - activated = ""; - deactivated = ""; - }; - on-click = "systemctl --user stop swayidle"; - on-click-right = "systemctl --user start swayidle"; - on-click-middle = "systemctl --user start swayidle"; - }; - - "niri/language" = { - format = "{short}"; - on-click = "niri msg action switch-layout next"; - on-click-right = "niri msg action switch-layout prev"; - on-click-middle = "niri msg action switch-layout 0"; - }; - - clock = { - format = "{:%H:%M}"; - format-alt = "{:%A, %B %d, %Y (%R)}  "; - tooltip-format = "{calendar}"; - calendar = { - mode = "year"; - mode-mon-col = 3; - weeks-pos = "right"; - on-scroll = 1; - format = { - months = "{}"; - days = "{}"; - weeks = "W{}"; - weekdays = "{}"; - today = "{}"; - }; - }; - actions = { - on-click-right = "mode"; - on-scroll-up = "shift_up"; - on-scroll-down = "shift_down"; - }; - on-click-middle = "brave calendar.google.com"; - }; - - tray = { - show-passive-items = true; - spacing = 3; - }; - }; -in { - programs.waybar = { - enable = true; - settings = { - main = - { - layer = "top"; - position = "bottom"; - expand-center = true; - output = [ - "DP-1" # Numenor main screen - "eDP-1" # Flexbox - ]; - } - // leftSection // centerSection // rightSection; - - aux = - { - layer = "top"; - position = "bottom"; - output = [ - "HDMI-A-1" - "HDMI-A-2" - ]; - } - // leftSection // rightSection; - }; - - style = '' - .info { - color: @base0D; - } - .critical { - color: @base08; - } - .warning { - color: @base0A; - } - - #systemd-failed-units.degraded { - color: @base08; - } - - #network.ethernet, - #network.wifi { - color: @base0B; - } - - #custom-dunst-dnd.dnd { - color: @base0A; - } - - #custom-macgyver.up { - color: @base0B; - } - - #custom-wlsunset.off { - color: @base0A; - } - - #custom-caffeinate.activated { - color: @base0A; - } - - #language:not(.us) { - color: @base0A; - } - - /* Can remove once https://github.com/nix-community/stylix/pull/1919 is merged */ - tooltip label { - color: @base05; - } - ''; - - systemd = { - enable = true; - enableDebug = false; - enableInspect = false; - }; - }; - - systemd.user.services.waybar = { - # Give on-click commands access to binaries they need - Service.Environment = lib.mkForce "PATH=/run/wrappers/bin:${config.home.profileDirectory}/bin:/run/current-system/sw/bin"; - # Fix for niri startup - Install.WantedBy = lib.mkForce ["niri.service"]; - Unit.Requires = ["niri.service"]; - Unit.After = ["niri.service"]; - }; -} diff --git a/home/waybar/scripts/dunst-dnd-waybar.sh b/home/waybar/scripts/dunst-dnd-waybar.sh deleted file mode 100644 index ca4fa2d2..00000000 --- a/home/waybar/scripts/dunst-dnd-waybar.sh +++ /dev/null @@ -1,9 +0,0 @@ -if dunstctl is-paused | grep -q "true"; then - state="dnd" -else - state="running" -fi - -count=$(dunstctl count waiting) - -printf '{"alt":"%s","text":%d,"class":"%s"}\n' "$state" "$count" "$state" diff --git a/home/witr/default.nix b/home/witr/default.nix deleted file mode 100644 index ed9fe501..00000000 --- a/home/witr/default.nix +++ /dev/null @@ -1,3 +0,0 @@ -{pkgs, ...}: { - home.packages = [pkgs.unstable.witr]; -} diff --git a/home/wlsunset/default.nix b/home/wlsunset/default.nix deleted file mode 100644 index e97f6751..00000000 --- a/home/wlsunset/default.nix +++ /dev/null @@ -1,14 +0,0 @@ -# Day/night gamma adjustments for Wayland -{pkgs, ...}: let - # https://github.com/CyrilSLi/linux-scripts/blob/main/waybar/wlsunset.sh - wlsunset-waybar = pkgs.writeShellApplication { - name = "wlsunset-waybar"; - runtimeInputs = with pkgs; [wlsunset procps killall]; - text = builtins.readFile ./scripts/wlsunset-waybar.sh; - }; -in { - home.packages = [ - pkgs.wlsunset - wlsunset-waybar - ]; -} diff --git a/home/wlsunset/scripts/wlsunset-waybar.sh b/home/wlsunset/scripts/wlsunset-waybar.sh deleted file mode 100644 index c4fe1b0a..00000000 --- a/home/wlsunset/scripts/wlsunset-waybar.sh +++ /dev/null @@ -1,22 +0,0 @@ -# Originally looted from https://github.com/CyrilSLi/linux-scripts -if pgrep -x wlsunset; then - killall -9 wlsunset -else - RETRIES=30 - counter=0 - while true; do - if CONTENT=$(curl -s http://ip-api.com/json/); then - break - fi - counter=$((counter + 1)) - if [ $counter -eq $RETRIES ]; then - notify-send wlsunset.sh "Unable to connect to ip-api." - break - fi - sleep 2 - done - longitude=$(echo "$CONTENT" | jq .lon) - latitude=$(echo "$CONTENT" | jq .lat) - wlsunset -l "$latitude" -L "$longitude" & -fi -pkill -35 waybar diff --git a/home/wluma/default.nix b/home/wluma/default.nix deleted file mode 100644 index bb053958..00000000 --- a/home/wluma/default.nix +++ /dev/null @@ -1,12 +0,0 @@ -# Automatic brightness adjustment based on screen contents and ALS -{ - lib, - osConfig, - ... -}: let - isFlexbox = osConfig.networking.hostName == "flexbox"; -in { - services.wluma = lib.mkIf isFlexbox { - enable = true; - }; -} diff --git a/home/xdg/default.nix b/home/xdg/default.nix deleted file mode 100644 index 44e0479b..00000000 --- a/home/xdg/default.nix +++ /dev/null @@ -1,62 +0,0 @@ -{ - isImpermanent, - lib, - pkgs, - ... -}: { - home.persistence."/persist" = lib.mkIf isImpermanent { - directories = [ - ".xournal" # Other recently used files - ]; - # TODO: This somehow tries to replace the file after it's created by something else - # See https://github.com/nix-community/impermanence/issues/147 - # files = [ - # ".local/share/recently-used.xbel" # Recently used files - # ]; - }; - - home.packages = [ - pkgs.selectdefaultapplication # GUI XDG Default Application Chooser - ]; - - home.sessionVariables = { - XDG_CONFIG_HOME = "/home/farlion/.config"; - }; - - home.preferXdgDirectories = true; - - xdg = { - mimeApps = { - associations = { - added = { - "x-scheme-handler/tg" = "org.telegram.desktop.desktop"; - }; - }; - enable = true; - defaultApplications = { - "application/pdf" = ["okular.desktop"]; - "applications/x-www-browser" = ["brave-browser.desktop"]; - "image/bmp" = ["oculante.desktop"]; - "image/gif" = ["oculante.desktop"]; - "image/jpeg" = ["oculante.desktop"]; - "image/png" = ["oculante.desktop"]; - "image/svg+xml" = ["oculante.desktop"]; - "image/tiff" = ["oculante.desktop"]; - "image/webp" = ["oculante.desktop"]; - "inode/directory" = ["lf.desktop"]; - "text/html" = ["brave-browser.desktop"]; - "text/plain" = ["nvim.desktop"]; - "x-scheme-handler/about" = ["brave-browser.desktop"]; - "x-scheme-handler/http" = ["brave-browser.desktop"]; - "x-scheme-handler/https" = ["brave-browser.desktop"]; - "x-scheme-handler/mailto" = ["brave-browser.desktop"]; - "x-scheme-handler/msteams" = ["teams-for-linux.desktop"]; - "x-scheme-handler/slack" = ["slack.desktop"]; - "x-scheme-handler/tg" = ["org.telegram.desktop.desktop"]; - "x-scheme-handler/tonsite" = ["org.telegram.desktop.desktop"]; - "x-scheme-handler/unknown" = ["brave-browser.desktop"]; - "x-scheme-handler/webcal" = ["brave-browser.desktop"]; - }; - }; - }; -} diff --git a/home/ytmdesktop/default.nix b/home/ytmdesktop/default.nix deleted file mode 100644 index 0b94684e..00000000 --- a/home/ytmdesktop/default.nix +++ /dev/null @@ -1,31 +0,0 @@ -{ - lib, - isImpermanent, - pkgs, - ... -}: { - home.persistence."/persist" = lib.mkIf isImpermanent { - directories = [ - ".config/YouTube Music Desktop App" - ]; - }; - - home.packages = [ - pkgs.unstable.ytmdesktop - ]; - - # Override the desktop file to add --password-store flag for Last.fm integration - # See: https://github.com/ytmdesktop/ytmdesktop/issues/1428 - xdg.desktopEntries.ytmdesktop = { - name = "YouTube Music Desktop App"; - genericName = "Music Player"; - comment = "YouTube Music Desktop App"; - exec = "${pkgs.unstable.ytmdesktop}/bin/ytmdesktop --password-store=\"gnome-libsecret\" %U"; - icon = "ytmdesktop"; - terminal = false; - type = "Application"; - categories = ["Audio" "AudioVideo" "Player"]; - mimeType = ["x-scheme-handler/ytmd"]; - startupNotify = true; - }; -} diff --git a/home/yubico/default.nix b/home/yubico/default.nix deleted file mode 100644 index eb6fcce3..00000000 --- a/home/yubico/default.nix +++ /dev/null @@ -1,19 +0,0 @@ -{pkgs, ...}: { - imports = [ - ./modules/yubikey-touch-detector - ]; - - home.packages = with pkgs; [ - pam_u2f # U2F (via yubikey) support for PAM - yubikey-manager # ykman - yubioath-flutter # Yubikey management GUI - ]; - - services = { - yubikey-touch-detector.enable = true; - dunst.settings.yubikey_touch_detector_icon = { - summary = "YubiKey is waiting for a touch"; - new_icon = "${pkgs.yubikey-touch-detector}/share/icons/hicolor/128x128/apps/yubikey-touch-detector.png"; - }; - }; -} diff --git a/home/yubico/modules/yubikey-touch-detector/default.nix b/home/yubico/modules/yubikey-touch-detector/default.nix deleted file mode 100644 index de9ff892..00000000 --- a/home/yubico/modules/yubikey-touch-detector/default.nix +++ /dev/null @@ -1,66 +0,0 @@ -{ - config, - lib, - pkgs, - ... -}: -with lib; let - cfg = config.services.yubikey-touch-detector; -in { - options.services.yubikey-touch-detector = { - enable = mkEnableOption "a tool to detect when your YubiKey is waiting for a touch"; - - package = mkOption { - type = types.package; - default = pkgs.yubikey-touch-detector; - defaultText = "pkgs.yubikey-touch-detector"; - description = '' - Package to use. Binary is expected to be called "yubikey-touch-detector". - ''; - }; - - socket.enable = mkEnableOption "starting the process only when the socket is used"; - - extraArgs = mkOption { - type = types.listOf types.str; - default = ["--libnotify"]; - defaultText = literalExpression ''[ "--libnotify" ]''; - description = '' - Extra arguments to pass to the tool. The arguments are not escaped. - ''; - }; - }; - - config = mkIf cfg.enable { - home.packages = [cfg.package]; - - # Service description licensed under ISC - # See https://github.com/maximbaz/yubikey-touch-detector/blob/c9fdff7163361d6323e2de0449026710cacbc08a/LICENSE - # Author: Maxim Baz - systemd.user.sockets.yubikey-touch-detector = mkIf cfg.socket.enable { - Unit.Description = "Unix socket activation for YubiKey touch detector service"; - Socket = { - ListenFIFO = "%t/yubikey-touch-detector.sock"; - RemoveOnStop = true; - SocketMode = "0660"; - }; - Install.WantedBy = ["sockets.target"]; - }; - - # Same license thing for the description here - systemd.user.services.yubikey-touch-detector = { - Unit = { - Description = "Detects when your YubiKey is waiting for a touch"; - Requires = optionals cfg.socket.enable ["yubikey-touch-detector.socket"]; - }; - Service = { - ExecStart = "${cfg.package}/bin/yubikey-touch-detector ${concatStringsSep " " cfg.extraArgs}"; - Environment = ["PATH=${lib.makeBinPath [pkgs.gnupg]}"]; - Restart = "on-failure"; - RestartSec = "1sec"; - }; - Install.Also = optionals cfg.socket.enable ["yubikey-touch-detector.socket"]; - Install.WantedBy = ["default.target"]; - }; - }; -} diff --git a/home/zen/default.nix b/home/zen/default.nix deleted file mode 100644 index ae87bc7f..00000000 --- a/home/zen/default.nix +++ /dev/null @@ -1,54 +0,0 @@ -{ - lib, - isImpermanent, - inputs, - config, - pkgs, - ... -}: let - # Try to focus an existing Zen window on link open so the workspace comes to the foreground - zenNiriOpen = pkgs.writeShellApplication { - name = "zen-niri-open"; - runtimeInputs = [pkgs.niri pkgs.jq pkgs.coreutils config.programs.zen-browser.package]; - text = '' - zen_id=$(niri msg --json windows | jq -r '.[] | select(.app_id == "zen-browser" or .app_id == "zen") | .id' | head -n1 || true) - if [ -n "''${zen_id:-}" ]; then - niri msg action focus-window --id "$zen_id" >/dev/null 2>&1 || true - fi - exec ${config.programs.zen-browser.package}/bin/zen "$@" - ''; - }; -in { - home.persistence."/persist" = lib.mkIf isImpermanent { - directories = [ - ".zen" - ]; - }; - - home.packages = [zenNiriOpen]; - - imports = [ - inputs.zen-browser.homeModules.beta - ]; - - programs.zen-browser = { - enable = true; - profiles = { - main = { - extensions.packages = with pkgs.nur.repos.rycee.firefox-addons; [ - bitwarden - darkreader - ublock-origin - ]; - }; - }; - }; - - stylix.targets.zen-browser.profileNames = ["main"]; - - home.sessionVariables = { - BROWSER = "${zenNiriOpen}/bin/zen-niri-open"; - DEFAULT_BROWSER = "${zenNiriOpen}/bin/zen-niri-open"; - MOZ_LEGACY_PROFILES = 1; # Temporary fix, see https://github.com/0xc000022070/zen-browser-flake/issues/179 - }; -} diff --git a/home/zoom/default.nix b/home/zoom/default.nix deleted file mode 100644 index 26de6945..00000000 --- a/home/zoom/default.nix +++ /dev/null @@ -1,21 +0,0 @@ -{ - lib, - isImpermanent, - pkgs, - ... -}: { - home.persistence."/persist" = lib.mkIf isImpermanent { - files = [ - ".config/zoom.conf" - ".config/zoomus.conf" - ]; - directories = [ - ".zoom" - ".cache/zoom" - ]; - }; - - home.packages = [ - pkgs.zoom-us - ]; -} diff --git a/home/zoxide/default.nix b/home/zoxide/default.nix deleted file mode 100644 index fdc4e5b3..00000000 --- a/home/zoxide/default.nix +++ /dev/null @@ -1,16 +0,0 @@ -{ - lib, - isImpermanent, - ... -}: { - home.persistence."/persist" = lib.mkIf isImpermanent { - directories = [ - ".cache/zoxide" # Some stuff for nushell - ".local/share/zoxide" # Zoxide DB - ]; - }; - - programs.zoxide = { - enable = true; - }; -} diff --git a/machines/flexbox/system.nix b/machines/flexbox/system.nix deleted file mode 100644 index 453fa57c..00000000 --- a/machines/flexbox/system.nix +++ /dev/null @@ -1,51 +0,0 @@ -# Edit this configuration file to define what should be installed on -# your system. Help is available in the configuration.nix(5) man page -# and in the NixOS manual (accessible by running ‘nixos-help’). -{...}: { - # https://lore.kernel.org/linux-nvme/YnR%2FFiWbErNGXIx+@kbusch-mbp/T/ - boot.kernelParams = [ - "nvme_core.default_ps_max_latency_us=0" # Stability probs - "acpiphp.disable=1" # NVME disk power management probs - ]; - - # GPU - hardware.nvidia.prime = { - offload = { - enable = true; - enableOffloadCmd = true; - }; - intelBusId = "PCI:0:2:0"; - nvidiaBusId = "PCI:1:0:0"; - }; - - # Disable power saving for fixing Comet Lake Audio Card (SOF) breaking after suspend - services.udev.extraRules = '' - ACTION=="add|change", SUBSYSTEM=="pci", KERNELS=="0000:00:1f.3", ATTR{power/control}="on" - ''; - - # LVM on LUKS - boot.initrd.luks.devices = { - root = { - device = "/dev/disk/by-uuid/ae713884-749b-4edb-adbc-b16fe447e956"; - preLVM = true; - }; - }; - - networking.hostName = "flexbox"; - - # The global useDHCP flag is deprecated, therefore explicitly set to - # false here. Per-interface useDHCP will be mandatory in the future, - # so this generated config replicates the default behaviour. - networking.useDHCP = false; - #networking.interfaces.enp164s0u1.useDHCP = true; - networking.interfaces.wlp0s20f3.useDHCP = true; - - # This value determines the NixOS release from which the default - # settings for stateful data, like file locations and database - # versions on your system were taken. It‘s perfectly fine and - # recommended to leave this value at the release version of the first - # install of this system. Before changing this value read the - # documentation for this option (e.g. man configuration.nix or on - # https://nixos.org/nixos/options.html). - system.stateVersion = "22.05"; # Did you read the comment? -} diff --git a/machines/numenor/system.nix b/machines/numenor/system.nix deleted file mode 100644 index 3342933a..00000000 --- a/machines/numenor/system.nix +++ /dev/null @@ -1,55 +0,0 @@ -# Edit this configuration file to define what should be installed on -# your system. Help is available in the configuration.nix(5) man page, on -# https://search.nixos.org/options and in the NixOS manual (`nixos-help`). -{pkgs, ...}: { - # LVM on LUKS - boot.initrd.luks.devices = { - root = { - device = "/dev/nvme0n1p6"; - preLVM = true; - }; - }; - - # Needed for ddcutil - hardware.i2c.enable = true; - - # Plenty of RAM so... - boot.tmp.useTmpfs = true; - - networking.useDHCP = false; - networking.interfaces.enp74s0.useDHCP = true; - - networking.hostName = "numenor"; - - # Disable Wifi at boot - systemd.services.disable-wifi = { - enable = true; - description = "Disable Wi-Fi at boot"; - after = ["network.target" "NetworkManager.service"]; - wantedBy = ["multi-user.target"]; - path = with pkgs; [networkmanager]; - serviceConfig = { - Type = "oneshot"; - ExecStart = "${pkgs.networkmanager}/bin/nmcli radio wifi off"; - }; - }; - - # This option defines the first version of NixOS you have installed on this particular machine, - # and is used to maintain compatibility with application data (e.g. databases) created on older NixOS versions. - # - # Most users should NEVER change this value after the initial install, for any reason, - # even if you've upgraded your system to a new NixOS release. - # - # This value does NOT affect the Nixpkgs version your packages and OS are pulled from, - # so changing it will NOT upgrade your system - see https://nixos.org/manual/nixos/stable/#sec-upgrading for how - # to actually do that. - # - # This value being lower than the current NixOS release does NOT mean your system is - # out of date, out of support, or vulnerable. - # - # Do NOT change this value unless you have manually inspected all the changes it would make to your configuration, - # and migrated your data accordingly. - # - # For more information, see `man configuration.nix` or https://nixos.org/manual/nixos/stable/options#opt-system.stateVersion . - system.stateVersion = "24.11"; # Did you read the comment? -} diff --git a/nix/default.nix b/nix/default.nix deleted file mode 100644 index 0b9cdb4a..00000000 --- a/nix/default.nix +++ /dev/null @@ -1,26 +0,0 @@ -{pkgs, ...}: { - nix = { - settings = { - # trusted users for pulling from caches - trusted-users = ["root" "farlion" "@wheel" "@sudo"]; - substituters = [ - "https://cache.nixos.org/" - ]; - trusted-public-keys = [ - ]; - }; - - extraOptions = '' - experimental-features = nix-command flakes - ''; - - nixPath = [ - "nixpkgs=${pkgs.path}" - "nixos-unstable=${pkgs.unstable.path}" - ]; - }; - - nixpkgs = { - config.allowUnfree = true; - }; -} diff --git a/parts/hosts/flexbox/default.nix b/parts/_hosts/flexbox/default.nix similarity index 100% rename from parts/hosts/flexbox/default.nix rename to parts/_hosts/flexbox/default.nix diff --git a/machines/flexbox/hardware-scan.nix b/parts/_hosts/flexbox/hardware-scan.nix similarity index 100% rename from machines/flexbox/hardware-scan.nix rename to parts/_hosts/flexbox/hardware-scan.nix diff --git a/parts/hosts/numenor/default.nix b/parts/_hosts/numenor/default.nix similarity index 100% rename from parts/hosts/numenor/default.nix rename to parts/_hosts/numenor/default.nix diff --git a/machines/numenor/hardware-scan.nix b/parts/_hosts/numenor/hardware-scan.nix similarity index 100% rename from machines/numenor/hardware-scan.nix rename to parts/_hosts/numenor/hardware-scan.nix diff --git a/parts/features/apps/aichat.nix b/parts/features/apps/aichat.nix index c240f1e3..05a3bd96 100644 --- a/parts/features/apps/aichat.nix +++ b/parts/features/apps/aichat.nix @@ -1,12 +1,11 @@ -{config, lib, ...}: let - cfg = config; -in { +{...}: { flake.modules.homeManager.aichat = { + osConfig, lib, pkgs, ... }: { - home.persistence."/persist" = lib.mkIf cfg.dendrix.isImpermanent { + home.persistence."/persist" = lib.mkIf osConfig.dendrix.isImpermanent { directories = [ ".config/aichat" ]; diff --git a/parts/features/apps/ansible.nix b/parts/features/apps/ansible.nix index 446a7453..b30bddd8 100644 --- a/parts/features/apps/ansible.nix +++ b/parts/features/apps/ansible.nix @@ -1,8 +1,6 @@ -{config, lib, ...}: let - cfg = config; -in { - flake.modules.homeManager.ansible = {lib, ...}: { - home.persistence."/persist" = lib.mkIf cfg.dendrix.isImpermanent { +{...}: { + flake.modules.homeManager.ansible = {lib, osConfig, ...}: { + home.persistence."/persist" = lib.mkIf osConfig.dendrix.isImpermanent { directories = [".ansible"]; }; }; diff --git a/parts/features/apps/aws.nix b/parts/features/apps/aws.nix index 0d910485..12a2918a 100644 --- a/parts/features/apps/aws.nix +++ b/parts/features/apps/aws.nix @@ -1,12 +1,11 @@ -{config, lib, ...}: let - cfg = config; -in { +{...}: { flake.modules.homeManager.aws = { + osConfig, lib, pkgs, ... }: { - home.persistence."/persist" = lib.mkIf cfg.dendrix.isImpermanent { + home.persistence."/persist" = lib.mkIf osConfig.dendrix.isImpermanent { directories = [".aws"]; }; diff --git a/parts/features/apps/bash.nix b/parts/features/apps/bash.nix index 03fcb2c1..242c5af3 100644 --- a/parts/features/apps/bash.nix +++ b/parts/features/apps/bash.nix @@ -1,12 +1,11 @@ -{config, lib, ...}: let - cfg = config; -in { +{...}: { flake.modules.homeManager.bash = { + osConfig, lib, pkgs, ... }: { - home.persistence."/persist" = lib.mkIf cfg.dendrix.isImpermanent { + home.persistence."/persist" = lib.mkIf osConfig.dendrix.isImpermanent { files = [ ".bash_history" ]; diff --git a/parts/features/apps/brave-browser.nix b/parts/features/apps/brave-browser.nix index fe3c5c5a..5c480826 100644 --- a/parts/features/apps/brave-browser.nix +++ b/parts/features/apps/brave-browser.nix @@ -1,12 +1,11 @@ -{config, lib, ...}: let - cfg = config; -in { +{...}: { flake.modules.homeManager.brave-browser = { lib, pkgs, + osConfig, ... }: let - isNvidia = cfg.dendrix.hasNvidia; + isNvidia = osConfig.dendrix.hasNvidia; braveNiriOpen = pkgs.writeShellApplication { name = "brave-niri-open"; runtimeInputs = [pkgs.niri pkgs.jq pkgs.coreutils pkgs.brave]; @@ -25,7 +24,7 @@ in { ''; }; in { - home.persistence."/persist" = lib.mkIf cfg.dendrix.isImpermanent { + home.persistence."/persist" = lib.mkIf osConfig.dendrix.isImpermanent { directories = [ ".config/BraveSoftware" ".cache/BraveSoftware" diff --git a/parts/features/apps/calibre.nix b/parts/features/apps/calibre.nix index fe95b69d..ba6756c9 100644 --- a/parts/features/apps/calibre.nix +++ b/parts/features/apps/calibre.nix @@ -1,12 +1,11 @@ -{config, lib, ...}: let - cfg = config; -in { +{...}: { flake.modules.homeManager.calibre = { + osConfig, lib, pkgs, ... }: { - home.persistence."/persist" = lib.mkIf cfg.dendrix.isImpermanent { + home.persistence."/persist" = lib.mkIf osConfig.dendrix.isImpermanent { directories = [ "Calibre Library" ".config/calibre" diff --git a/parts/features/apps/discord.nix b/parts/features/apps/discord.nix index 1d4ee82b..9c47a1e6 100644 --- a/parts/features/apps/discord.nix +++ b/parts/features/apps/discord.nix @@ -1,8 +1,6 @@ -{config, lib, ...}: let - cfg = config; -in { - flake.modules.homeManager.discord = {lib, ...}: { - home.persistence."/persist" = lib.mkIf cfg.dendrix.isImpermanent { +{...}: { + flake.modules.homeManager.discord = {lib, osConfig, ...}: { + home.persistence."/persist" = lib.mkIf osConfig.dendrix.isImpermanent { directories = [ ".config/discord" ]; diff --git a/parts/features/apps/firefox.nix b/parts/features/apps/firefox.nix index 84be7dda..fd3d402e 100644 --- a/parts/features/apps/firefox.nix +++ b/parts/features/apps/firefox.nix @@ -1,12 +1,11 @@ -{config, lib, ...}: let - cfg = config; -in { +{...}: { flake.modules.homeManager.firefox = { + osConfig, lib, pkgs, ... }: { - home.persistence."/persist" = lib.mkIf cfg.dendrix.isImpermanent { + home.persistence."/persist" = lib.mkIf osConfig.dendrix.isImpermanent { directories = [ ".mozilla/firefox" ".cache/mozilla/firefox" diff --git a/parts/features/apps/fish.nix b/parts/features/apps/fish.nix index 417bebcd..dc8c7f58 100644 --- a/parts/features/apps/fish.nix +++ b/parts/features/apps/fish.nix @@ -1,7 +1,6 @@ -{config, lib, ...}: let - cfg = config; -in { +{...}: { flake.modules.homeManager.fish = { + osConfig, config, lib, pkgs, @@ -113,7 +112,7 @@ in { set fish_greeting # disable greeting ''; in { - home.persistence."/persist" = lib.mkIf cfg.dendrix.isImpermanent { + home.persistence."/persist" = lib.mkIf osConfig.dendrix.isImpermanent { directories = [ ".config/fish" ".local/share/fish" diff --git a/parts/features/apps/fix-flexbox-mike/default.nix b/parts/features/apps/fix-flexbox-mike/default.nix index 640f4e07..21e13935 100644 --- a/parts/features/apps/fix-flexbox-mike/default.nix +++ b/parts/features/apps/fix-flexbox-mike/default.nix @@ -1,12 +1,11 @@ -{config, ...}: let - cfg = config; -in { +{...}: { flake.modules.homeManager.fix-flexbox-mike = { lib, pkgs, + osConfig, ... }: let - isFlexbox = cfg.dendrix.hostname == "flexbox"; + isFlexbox = osConfig.dendrix.hostname == "flexbox"; xps-9700-mic-fixer = pkgs.writeShellApplication { name = "xps-9700-mic-fixer"; runtimeInputs = [pkgs.alsa-utils]; diff --git a/parts/features/apps/galaxy-buds-client.nix b/parts/features/apps/galaxy-buds-client.nix index 31b37c42..ba334a32 100644 --- a/parts/features/apps/galaxy-buds-client.nix +++ b/parts/features/apps/galaxy-buds-client.nix @@ -1,12 +1,11 @@ -{config, lib, ...}: let - cfg = config; -in { +{...}: { flake.modules.homeManager.galaxy-buds-client = { lib, pkgs, + osConfig, ... }: { - home.persistence."/persist" = lib.mkIf cfg.dendrix.isImpermanent { + home.persistence."/persist" = lib.mkIf osConfig.dendrix.isImpermanent { directories = [".local/share/GalaxyBudsClient"]; }; diff --git a/parts/features/apps/gimp.nix b/parts/features/apps/gimp.nix index 71567d95..1f6e4d18 100644 --- a/parts/features/apps/gimp.nix +++ b/parts/features/apps/gimp.nix @@ -1,12 +1,11 @@ -{config, lib, ...}: let - cfg = config; -in { +{...}: { flake.modules.homeManager.gimp = { + osConfig, lib, pkgs, ... }: { - home.persistence."/persist" = lib.mkIf cfg.dendrix.isImpermanent { + home.persistence."/persist" = lib.mkIf osConfig.dendrix.isImpermanent { directories = [ ".config/GIMP" ".cache/gimp" diff --git a/parts/features/apps/gnome-connections.nix b/parts/features/apps/gnome-connections.nix index 9a4cc24d..62942e86 100644 --- a/parts/features/apps/gnome-connections.nix +++ b/parts/features/apps/gnome-connections.nix @@ -1,12 +1,11 @@ -{config, lib, ...}: let - cfg = config; -in { +{...}: { flake.modules.homeManager.gnome-connections = { lib, pkgs, + osConfig, ... }: { - home.persistence."/persist" = lib.mkIf cfg.dendrix.isImpermanent { + home.persistence."/persist" = lib.mkIf osConfig.dendrix.isImpermanent { directories = [ ".config/freerdp" ".config/dconf" diff --git a/parts/features/apps/isd.nix b/parts/features/apps/isd.nix index 6d895f8e..ee4abc06 100644 --- a/parts/features/apps/isd.nix +++ b/parts/features/apps/isd.nix @@ -1,12 +1,11 @@ -{config, lib, ...}: let - cfg = config; -in { +{...}: { flake.modules.homeManager.isd = { + osConfig, lib, pkgs, ... }: { - home.persistence."/persist" = lib.mkIf cfg.dendrix.isImpermanent { + home.persistence."/persist" = lib.mkIf osConfig.dendrix.isImpermanent { directories = [ ".config/isd_tui" ".local/share/isd_tui" diff --git a/parts/features/apps/kubernetes-tools.nix b/parts/features/apps/kubernetes-tools.nix index 68de30d7..182b307a 100644 --- a/parts/features/apps/kubernetes-tools.nix +++ b/parts/features/apps/kubernetes-tools.nix @@ -1,12 +1,11 @@ -{config, lib, ...}: let - cfg = config; -in { +{...}: { flake.modules.homeManager.kubernetes-tools = { lib, pkgs, + osConfig, ... }: { - home.persistence."/persist" = lib.mkIf cfg.dendrix.isImpermanent { + home.persistence."/persist" = lib.mkIf osConfig.dendrix.isImpermanent { directories = [".kube"]; }; diff --git a/parts/features/apps/lf/default.nix b/parts/features/apps/lf/default.nix index 3364fda0..01837695 100644 --- a/parts/features/apps/lf/default.nix +++ b/parts/features/apps/lf/default.nix @@ -1,7 +1,6 @@ -{config, lib, ...}: let - cfg = config; -in { +{...}: { flake.modules.homeManager.lf = { + osConfig, lib, pkgs, ... @@ -34,7 +33,7 @@ in { fi ''; in { - home.persistence."/persist" = lib.mkIf cfg.dendrix.isImpermanent { + home.persistence."/persist" = lib.mkIf osConfig.dendrix.isImpermanent { directories = [ ".local/share/lf" ]; diff --git a/parts/features/apps/libation.nix b/parts/features/apps/libation.nix index c864236c..7c0cb009 100644 --- a/parts/features/apps/libation.nix +++ b/parts/features/apps/libation.nix @@ -1,12 +1,11 @@ -{config, lib, ...}: let - cfg = config; -in { +{...}: { flake.modules.homeManager.libation = { + osConfig, lib, pkgs, ... }: { - home.persistence."/persist" = lib.mkIf cfg.dendrix.isImpermanent { + home.persistence."/persist" = lib.mkIf osConfig.dendrix.isImpermanent { directories = [ "Libation" ".local/share/Libation" diff --git a/parts/features/apps/libreoffice.nix b/parts/features/apps/libreoffice.nix index faed0713..803cee37 100644 --- a/parts/features/apps/libreoffice.nix +++ b/parts/features/apps/libreoffice.nix @@ -1,12 +1,11 @@ -{config, lib, ...}: let - cfg = config; -in { +{...}: { flake.modules.homeManager.libreoffice = { + osConfig, lib, pkgs, ... }: { - home.persistence."/persist" = lib.mkIf cfg.dendrix.isImpermanent { + home.persistence."/persist" = lib.mkIf osConfig.dendrix.isImpermanent { directories = [ ".config/libreoffice" ]; diff --git a/parts/features/apps/lnav.nix b/parts/features/apps/lnav.nix index 40b82708..75340af6 100644 --- a/parts/features/apps/lnav.nix +++ b/parts/features/apps/lnav.nix @@ -1,12 +1,11 @@ -{config, lib, ...}: let - cfg = config; -in { +{...}: { flake.modules.homeManager.lnav = { + osConfig, lib, pkgs, ... }: { - home.persistence."/persist" = lib.mkIf cfg.dendrix.isImpermanent { + home.persistence."/persist" = lib.mkIf osConfig.dendrix.isImpermanent { directories = [".config/lnav"]; }; diff --git a/parts/features/apps/mic-levels-maintainer/default.nix b/parts/features/apps/mic-levels-maintainer/default.nix index e097c7be..1ee77a59 100644 --- a/parts/features/apps/mic-levels-maintainer/default.nix +++ b/parts/features/apps/mic-levels-maintainer/default.nix @@ -1,8 +1,6 @@ -{config, ...}: let - cfg = config; -in { - flake.modules.homeManager.mic-levels-maintainer = {pkgs, ...}: let - isNumenor = cfg.dendrix.hostname == "numenor"; +{...}: { + flake.modules.homeManager.mic-levels-maintainer = {pkgs, osConfig, ...}: let + isNumenor = osConfig.dendrix.hostname == "numenor"; mic-levels-maintainer = pkgs.writers.writeBashBin "mic-levels-maintainer" ( if isNumenor then (builtins.readFile ./_scripts/mic-levels-maintainer-numenor.sh) diff --git a/parts/features/apps/mpv.nix b/parts/features/apps/mpv.nix index 63f43290..e0f14ce5 100644 --- a/parts/features/apps/mpv.nix +++ b/parts/features/apps/mpv.nix @@ -1,12 +1,11 @@ -{config, lib, ...}: let - cfg = config; -in { +{...}: { flake.modules.homeManager.mpv = { + osConfig, lib, pkgs, ... }: { - home.persistence."/persist" = lib.mkIf cfg.dendrix.isImpermanent { + home.persistence."/persist" = lib.mkIf osConfig.dendrix.isImpermanent { directories = [ ".config/mpv" ".cache/mpv" diff --git a/parts/features/apps/nautilus.nix b/parts/features/apps/nautilus.nix index 98e2906d..9f4a00d1 100644 --- a/parts/features/apps/nautilus.nix +++ b/parts/features/apps/nautilus.nix @@ -1,12 +1,11 @@ -{config, lib, ...}: let - cfg = config; -in { +{...}: { flake.modules.homeManager.nautilus = { + osConfig, lib, pkgs, ... }: { - home.persistence."/persist" = lib.mkIf cfg.dendrix.isImpermanent { + home.persistence."/persist" = lib.mkIf osConfig.dendrix.isImpermanent { directories = [ ".config/nautilus" ".local/share/nautilus" diff --git a/parts/features/apps/nix-index.nix b/parts/features/apps/nix-index.nix index ff00fad3..5c6e4469 100644 --- a/parts/features/apps/nix-index.nix +++ b/parts/features/apps/nix-index.nix @@ -1,12 +1,10 @@ -{config, lib, inputs, ...}: let - cfg = config; -in { - flake.modules.homeManager.nix-index = {lib, ...}: { +{inputs, ...}: { + flake.modules.homeManager.nix-index = {lib, osConfig, ...}: { imports = [ inputs.nix-index-database.homeModules.nix-index ]; - home.persistence."/persist" = lib.mkIf cfg.dendrix.isImpermanent { + home.persistence."/persist" = lib.mkIf osConfig.dendrix.isImpermanent { files = [ ".local/state/comma-choices" ]; diff --git a/parts/features/apps/nushell/default.nix b/parts/features/apps/nushell/default.nix index bf4dd038..f46aded6 100644 --- a/parts/features/apps/nushell/default.nix +++ b/parts/features/apps/nushell/default.nix @@ -1,7 +1,6 @@ -{config, lib, ...}: let - cfg = config; -in { +{...}: { flake.modules.homeManager.nushell = { + osConfig, lib, pkgs, ... @@ -10,7 +9,7 @@ in { cargoBuildFeatures = (oldAttrs.cargoBuildFeatures or []) ++ ["system-clipboard"]; }); in { - home.persistence."/persist" = lib.mkIf cfg.dendrix.isImpermanent { + home.persistence."/persist" = lib.mkIf osConfig.dendrix.isImpermanent { directories = [ ".config/nushell" ]; diff --git a/parts/features/apps/obs/default.nix b/parts/features/apps/obs/default.nix index 74dc2d1b..16eb96a7 100644 --- a/parts/features/apps/obs/default.nix +++ b/parts/features/apps/obs/default.nix @@ -1,12 +1,11 @@ -{config, lib, ...}: let - cfg = config; -in { +{...}: { flake.modules.homeManager.obs = { lib, pkgs, + osConfig, ... }: let - isFlexbox = cfg.dendrix.hostname == "flexbox"; + isFlexbox = osConfig.dendrix.hostname == "flexbox"; obsMainScene = pkgs.writeShellApplication { name = "obs-main-scene"; @@ -54,7 +53,7 @@ in { obsWebcamToggle ]; - home.persistence."/persist" = lib.mkIf cfg.dendrix.isImpermanent { + home.persistence."/persist" = lib.mkIf osConfig.dendrix.isImpermanent { directories = [".config/obs-studio"]; }; diff --git a/parts/features/apps/obsidian.nix b/parts/features/apps/obsidian.nix index cc08645d..45ecbe94 100644 --- a/parts/features/apps/obsidian.nix +++ b/parts/features/apps/obsidian.nix @@ -1,12 +1,11 @@ -{config, lib, ...}: let - cfg = config; -in { +{...}: { flake.modules.homeManager.obsidian = { + osConfig, lib, pkgs, ... }: { - home.persistence."/persist" = lib.mkIf cfg.dendrix.isImpermanent { + home.persistence."/persist" = lib.mkIf osConfig.dendrix.isImpermanent { directories = [ ".config/obsidian" "Obsidian" diff --git a/parts/features/apps/portfolio-performance.nix b/parts/features/apps/portfolio-performance.nix index f00a213b..40a7a49b 100644 --- a/parts/features/apps/portfolio-performance.nix +++ b/parts/features/apps/portfolio-performance.nix @@ -1,12 +1,11 @@ -{config, lib, ...}: let - cfg = config; -in { +{...}: { flake.modules.homeManager.portfolio-performance = { lib, pkgs, + osConfig, ... }: { - home.persistence."/persist" = lib.mkIf cfg.dendrix.isImpermanent { + home.persistence."/persist" = lib.mkIf osConfig.dendrix.isImpermanent { directories = [".PortfolioPerformance"]; }; diff --git a/parts/features/apps/qalculate.nix b/parts/features/apps/qalculate.nix index 7e09c2e0..d0e4b343 100644 --- a/parts/features/apps/qalculate.nix +++ b/parts/features/apps/qalculate.nix @@ -1,12 +1,11 @@ -{config, lib, ...}: let - cfg = config; -in { +{...}: { flake.modules.homeManager.qalculate = { + osConfig, lib, pkgs, ... }: { - home.persistence."/persist" = lib.mkIf cfg.dendrix.isImpermanent { + home.persistence."/persist" = lib.mkIf osConfig.dendrix.isImpermanent { directories = [ ".config/qalculate" ".local/share/qalculate" diff --git a/parts/features/apps/satty/default.nix b/parts/features/apps/satty/default.nix index 04a421a9..2d9e9285 100644 --- a/parts/features/apps/satty/default.nix +++ b/parts/features/apps/satty/default.nix @@ -1,7 +1,6 @@ -{config, lib, ...}: let - cfg = config; -in { +{...}: { flake.modules.homeManager.satty = { + osConfig, lib, pkgs, ... @@ -18,7 +17,7 @@ in { text = builtins.readFile ./_scripts/satty-screenshot.sh; }; in { - home.persistence."/persist" = lib.mkIf cfg.dendrix.isImpermanent { + home.persistence."/persist" = lib.mkIf osConfig.dendrix.isImpermanent { directories = [ ".cache/satty" ]; diff --git a/parts/features/apps/signal.nix b/parts/features/apps/signal.nix index e46f08ed..c2a47528 100644 --- a/parts/features/apps/signal.nix +++ b/parts/features/apps/signal.nix @@ -1,12 +1,11 @@ -{config, lib, ...}: let - cfg = config; -in { +{...}: { flake.modules.homeManager.signal = { + osConfig, lib, pkgs, ... }: { - home.persistence."/persist" = lib.mkIf cfg.dendrix.isImpermanent { + home.persistence."/persist" = lib.mkIf osConfig.dendrix.isImpermanent { directories = [ ".config/Signal" ]; diff --git a/parts/features/apps/solaar.nix b/parts/features/apps/solaar.nix index c98c599f..e6cb2a48 100644 --- a/parts/features/apps/solaar.nix +++ b/parts/features/apps/solaar.nix @@ -1,12 +1,11 @@ -{config, lib, ...}: let - cfg = config; -in { +{...}: { flake.modules.homeManager.solaar = { + osConfig, lib, pkgs, ... }: { - home.persistence."/persist" = lib.mkIf cfg.dendrix.isImpermanent { + home.persistence."/persist" = lib.mkIf osConfig.dendrix.isImpermanent { directories = [".config/solaar"]; }; diff --git a/parts/features/apps/sound-switcher/default.nix b/parts/features/apps/sound-switcher/default.nix index 83fcf4fc..c21aa109 100644 --- a/parts/features/apps/sound-switcher/default.nix +++ b/parts/features/apps/sound-switcher/default.nix @@ -1,8 +1,6 @@ -{config, ...}: let - cfg = config; -in { - flake.modules.homeManager.sound-switcher = {pkgs, ...}: let - isNumenor = cfg.dendrix.hostname == "numenor"; +{...}: { + flake.modules.homeManager.sound-switcher = {pkgs, osConfig, ...}: let + isNumenor = osConfig.dendrix.hostname == "numenor"; sound-switcher = pkgs.writers.writeBashBin "sound-switcher" ( if isNumenor then (builtins.readFile ./_scripts/sound-switcher-numenor.sh) diff --git a/parts/features/apps/ssh/default.nix b/parts/features/apps/ssh/default.nix index 36e74d14..f1940a98 100644 --- a/parts/features/apps/ssh/default.nix +++ b/parts/features/apps/ssh/default.nix @@ -1,7 +1,6 @@ -{config, lib, ...}: let - cfg = config; -in { +{...}: { flake.modules.homeManager.ssh = { + osConfig, lib, pkgs, ... @@ -12,7 +11,7 @@ in { text = builtins.readFile ./_scripts/ssh-add-all.sh; }; in { - home.persistence."/persist" = lib.mkIf cfg.dendrix.isImpermanent { + home.persistence."/persist" = lib.mkIf osConfig.dendrix.isImpermanent { directories = [ ".ssh" ]; diff --git a/parts/features/apps/starship.nix b/parts/features/apps/starship.nix index c02817a7..b35acdff 100644 --- a/parts/features/apps/starship.nix +++ b/parts/features/apps/starship.nix @@ -1,6 +1,6 @@ -{config, lib, ...}: { - flake.modules.homeManager.starship = {...}: { - home.persistence."/persist" = lib.mkIf config.dendrix.isImpermanent { +{...}: { + flake.modules.homeManager.starship = {lib, osConfig, ...}: { + home.persistence."/persist" = lib.mkIf osConfig.dendrix.isImpermanent { directories = [".cache/starship"]; }; diff --git a/parts/features/apps/tealdeer.nix b/parts/features/apps/tealdeer.nix index 83ecd02a..893b2089 100644 --- a/parts/features/apps/tealdeer.nix +++ b/parts/features/apps/tealdeer.nix @@ -1,6 +1,6 @@ -{config, lib, ...}: { - flake.modules.homeManager.tealdeer = {...}: { - home.persistence."/persist" = lib.mkIf config.dendrix.isImpermanent { +{...}: { + flake.modules.homeManager.tealdeer = {lib, osConfig, ...}: { + home.persistence."/persist" = lib.mkIf osConfig.dendrix.isImpermanent { directories = [".cache/tealdeer"]; }; diff --git a/parts/features/apps/telegram.nix b/parts/features/apps/telegram.nix index c2a47450..6f8d4765 100644 --- a/parts/features/apps/telegram.nix +++ b/parts/features/apps/telegram.nix @@ -1,12 +1,11 @@ -{config, lib, ...}: let - cfg = config; -in { +{...}: { flake.modules.homeManager.telegram = { + osConfig, lib, pkgs, ... }: { - home.persistence."/persist" = lib.mkIf cfg.dendrix.isImpermanent { + home.persistence."/persist" = lib.mkIf osConfig.dendrix.isImpermanent { directories = [ ".local/share/TelegramDesktop" ]; diff --git a/parts/features/apps/thunderbird.nix b/parts/features/apps/thunderbird.nix index 4d73d31f..b9e431ed 100644 --- a/parts/features/apps/thunderbird.nix +++ b/parts/features/apps/thunderbird.nix @@ -1,8 +1,6 @@ -{config, lib, ...}: let - cfg = config; -in { - flake.modules.homeManager.thunderbird = {lib, ...}: { - home.persistence."/persist" = lib.mkIf cfg.dendrix.isImpermanent { +{...}: { + flake.modules.homeManager.thunderbird = {lib, osConfig, ...}: { + home.persistence."/persist" = lib.mkIf osConfig.dendrix.isImpermanent { directories = [ ".thunderbird" ".cache/thunderbird" diff --git a/parts/features/apps/vlc.nix b/parts/features/apps/vlc.nix index f28b8aea..b58423b2 100644 --- a/parts/features/apps/vlc.nix +++ b/parts/features/apps/vlc.nix @@ -1,12 +1,11 @@ -{config, lib, ...}: let - cfg = config; -in { +{...}: { flake.modules.homeManager.vlc = { + osConfig, lib, pkgs, ... }: { - home.persistence."/persist" = lib.mkIf cfg.dendrix.isImpermanent { + home.persistence."/persist" = lib.mkIf osConfig.dendrix.isImpermanent { directories = [ ".config/vlc" ".local/share/vlc" diff --git a/parts/features/apps/xdg.nix b/parts/features/apps/xdg.nix index 16c065cc..47cf2de5 100644 --- a/parts/features/apps/xdg.nix +++ b/parts/features/apps/xdg.nix @@ -1,12 +1,11 @@ -{config, lib, ...}: let - cfg = config; -in { +{...}: { flake.modules.homeManager.xdg = { + osConfig, lib, pkgs, ... }: { - home.persistence."/persist" = lib.mkIf cfg.dendrix.isImpermanent { + home.persistence."/persist" = lib.mkIf osConfig.dendrix.isImpermanent { directories = [ ".xournal" ]; diff --git a/parts/features/apps/zoom.nix b/parts/features/apps/zoom.nix index 066aee2b..254ef73d 100644 --- a/parts/features/apps/zoom.nix +++ b/parts/features/apps/zoom.nix @@ -1,12 +1,11 @@ -{config, lib, ...}: let - cfg = config; -in { +{...}: { flake.modules.homeManager.zoom = { + osConfig, lib, pkgs, ... }: { - home.persistence."/persist" = lib.mkIf cfg.dendrix.isImpermanent { + home.persistence."/persist" = lib.mkIf osConfig.dendrix.isImpermanent { files = [ ".config/zoom.conf" ".config/zoomus.conf" diff --git a/parts/features/apps/zoxide.nix b/parts/features/apps/zoxide.nix index 858bf9c7..c0682a15 100644 --- a/parts/features/apps/zoxide.nix +++ b/parts/features/apps/zoxide.nix @@ -1,6 +1,6 @@ -{config, lib, ...}: { - flake.modules.homeManager.zoxide = {...}: { - home.persistence."/persist" = lib.mkIf config.dendrix.isImpermanent { +{...}: { + flake.modules.homeManager.zoxide = {lib, osConfig, ...}: { + home.persistence."/persist" = lib.mkIf osConfig.dendrix.isImpermanent { directories = [ ".cache/zoxide" ".local/share/zoxide" diff --git a/parts/features/core/fonts/default.nix b/parts/features/core/fonts/default.nix index 5381c7e0..3d25bc10 100644 --- a/parts/features/core/fonts/default.nix +++ b/parts/features/core/fonts/default.nix @@ -1,6 +1,4 @@ -{config, lib, ...}: let - cfg = config; -in { +{...}: { flake.modules.nixos.fonts = {pkgs, ...}: let fontSmokeTest = pkgs.writers.writeBashBin "font-smoke-test" '' set -e @@ -65,8 +63,8 @@ in { }; }; - flake.modules.homeManager.fonts = {lib, ...}: { - home.persistence."/persist" = lib.mkIf cfg.dendrix.isImpermanent { + flake.modules.homeManager.fonts = {lib, osConfig, ...}: { + home.persistence."/persist" = lib.mkIf osConfig.dendrix.isImpermanent { directories = [ ".local/share/fonts" ".cache/fontconfig" diff --git a/parts/features/core/impermanence.nix b/parts/features/core/impermanence.nix index 33579adb..fd348774 100644 --- a/parts/features/core/impermanence.nix +++ b/parts/features/core/impermanence.nix @@ -1,5 +1,6 @@ {...}: { flake.modules.nixos.impermanence = { + config, lib, pkgs, ... @@ -35,7 +36,8 @@ umount /btrfs_tmp echo "Done with 🧨. Au revoir!" >/dev/kmsg ''; - in { + in + lib.mkIf config.dendrix.isImpermanent { boot.initrd.systemd = { extraBin = { grep = "${pkgs.gnugrep}/bin/grep"; diff --git a/parts/features/core/networking/default.nix b/parts/features/core/networking/default.nix index 7f389d50..aaf2ab4d 100644 --- a/parts/features/core/networking/default.nix +++ b/parts/features/core/networking/default.nix @@ -1,7 +1,6 @@ -{config, lib, ...}: let - cfg = config; -in { +{...}: { flake.modules.nixos.networking = { + config, lib, pkgs, ... @@ -10,7 +9,7 @@ in { builtins.readFile ./_scripts/tailscale-ip.sh ); in { - environment.persistence."/persist/system" = lib.mkIf cfg.dendrix.isImpermanent { + environment.persistence."/persist/system" = lib.mkIf config.dendrix.isImpermanent { directories = [ "/etc/NetworkManager/system-connections" "/var/lib/tailscale" @@ -49,7 +48,7 @@ in { networking.dhcpcd.enable = false; - programs.captive-browser = lib.mkIf cfg.dendrix.isLaptop { + programs.captive-browser = lib.mkIf config.dendrix.isLaptop { enable = true; bindInterface = false; }; @@ -57,8 +56,8 @@ in { systemd.network.wait-online.anyInterface = true; }; - flake.modules.homeManager.networking = {lib, ...}: { - home.persistence."/persist" = lib.mkIf cfg.dendrix.isImpermanent { + flake.modules.homeManager.networking = {lib, osConfig, ...}: { + home.persistence."/persist" = lib.mkIf osConfig.dendrix.isImpermanent { directories = [".config/tailscale"]; }; }; diff --git a/parts/features/desktop/cliphist.nix b/parts/features/desktop/cliphist.nix index eba0fb4e..818cd76a 100644 --- a/parts/features/desktop/cliphist.nix +++ b/parts/features/desktop/cliphist.nix @@ -1,12 +1,11 @@ -{config, lib, ...}: let - cfg = config; -in { +{...}: { flake.modules.homeManager.cliphist = { + osConfig, lib, pkgs, ... }: { - home.persistence."/persist" = lib.mkIf cfg.dendrix.isImpermanent { + home.persistence."/persist" = lib.mkIf osConfig.dendrix.isImpermanent { directories = [ ".cache/cliphist" ]; diff --git a/parts/features/desktop/dconf.nix b/parts/features/desktop/dconf.nix index 4c8d17ba..877d7b8f 100644 --- a/parts/features/desktop/dconf.nix +++ b/parts/features/desktop/dconf.nix @@ -1,8 +1,6 @@ -{config, lib, ...}: let - cfg = config; -in { - flake.modules.homeManager.dconf = {lib, ...}: { - home.persistence."/persist" = lib.mkIf cfg.dendrix.isImpermanent { +{...}: { + flake.modules.homeManager.dconf = {lib, osConfig, ...}: { + home.persistence."/persist" = lib.mkIf osConfig.dendrix.isImpermanent { directories = [ ".config/dconf" ]; diff --git a/parts/features/desktop/display-manager.nix b/parts/features/desktop/display-manager.nix index 8135b016..3605a897 100644 --- a/parts/features/desktop/display-manager.nix +++ b/parts/features/desktop/display-manager.nix @@ -1,12 +1,11 @@ -{config, lib, ...}: let - cfg = config; -in { +{...}: { flake.modules.nixos.display-manager = { + config, lib, pkgs, ... }: { - environment.persistence."/persist/system" = lib.mkIf cfg.dendrix.isImpermanent { + environment.persistence."/persist/system" = lib.mkIf config.dendrix.isImpermanent { files = ["/etc/ly/save.ini"]; }; diff --git a/parts/features/desktop/gtk-qt.nix b/parts/features/desktop/gtk-qt.nix index f6ec18b1..b8f3d386 100644 --- a/parts/features/desktop/gtk-qt.nix +++ b/parts/features/desktop/gtk-qt.nix @@ -1,12 +1,11 @@ -{config, lib, ...}: let - cfg = config; -in { +{...}: { flake.modules.homeManager.gtk-qt = { lib, pkgs, + osConfig, ... }: { - home.persistence."/persist" = lib.mkIf cfg.dendrix.isImpermanent { + home.persistence."/persist" = lib.mkIf osConfig.dendrix.isImpermanent { files = [ ".config/QtProject.conf" ]; diff --git a/parts/features/desktop/niri/default.nix b/parts/features/desktop/niri/default.nix index 798c084c..ed823c3e 100644 --- a/parts/features/desktop/niri/default.nix +++ b/parts/features/desktop/niri/default.nix @@ -1,15 +1,14 @@ -{config, lib, ...}: let - cfg = config; -in { +{...}: { flake.modules.homeManager.niri = { + osConfig, config, lib, pkgs, ... }: with lib; let - isNumenor = cfg.dendrix.hostname == "numenor"; - isNvidia = cfg.dendrix.hasNvidia; + isNumenor = osConfig.dendrix.hostname == "numenor"; + isNvidia = osConfig.dendrix.hasNvidia; leftScreen = if isNumenor diff --git a/parts/features/desktop/theming.nix b/parts/features/desktop/theming.nix index d08aeba5..c572b2fb 100644 --- a/parts/features/desktop/theming.nix +++ b/parts/features/desktop/theming.nix @@ -1,6 +1,4 @@ -{config, lib, ...}: let - cfg = config; -in { +{...}: { flake.modules.nixos.theming = { pkgs, lib, diff --git a/parts/features/desktop/waybar/default.nix b/parts/features/desktop/waybar/default.nix index fdfe967e..8c877443 100644 --- a/parts/features/desktop/waybar/default.nix +++ b/parts/features/desktop/waybar/default.nix @@ -1,7 +1,6 @@ -{config, lib, ...}: let - cfg = config; -in { +{...}: { flake.modules.homeManager.waybar = { + osConfig, config, lib, pkgs, @@ -12,9 +11,9 @@ in { runtimeInputs = [pkgs.dunst]; text = builtins.readFile ./_scripts/dunst-dnd-waybar.sh; }; - isNvidia = cfg.dendrix.hasNvidia; - isNumenor = cfg.dendrix.hostname == "numenor"; - isFlexbox = cfg.dendrix.hostname == "flexbox"; + isNvidia = osConfig.dendrix.hasNvidia; + isNumenor = osConfig.dendrix.hostname == "numenor"; + isFlexbox = osConfig.dendrix.hostname == "flexbox"; leftSection = { modules-left = [ diff --git a/parts/features/dev/claude-code/default.nix b/parts/features/dev/claude-code/default.nix index 610e5ee0..0f81add1 100644 --- a/parts/features/dev/claude-code/default.nix +++ b/parts/features/dev/claude-code/default.nix @@ -1,12 +1,11 @@ -{config, lib, ...}: let - cfg = config; -in { +{...}: { flake.modules.homeManager.claude-code = { lib, pkgs, + osConfig, ... }: { - home.persistence."/persist" = lib.mkIf cfg.dendrix.isImpermanent { + home.persistence."/persist" = lib.mkIf osConfig.dendrix.isImpermanent { directories = [ ".claude" ".cache/claude-cli-nodejs" diff --git a/parts/features/dev/codex.nix b/parts/features/dev/codex.nix index 35a8e9ff..d8badf00 100644 --- a/parts/features/dev/codex.nix +++ b/parts/features/dev/codex.nix @@ -1,12 +1,11 @@ -{config, lib, ...}: let - cfg = config; -in { +{...}: { flake.modules.homeManager.codex = { + osConfig, lib, pkgs, ... }: { - home.persistence."/persist" = lib.mkIf cfg.dendrix.isImpermanent { + home.persistence."/persist" = lib.mkIf osConfig.dendrix.isImpermanent { directories = [".codex"]; }; diff --git a/parts/features/dev/devenv.nix b/parts/features/dev/devenv.nix index 6012a9a4..b461e7e1 100644 --- a/parts/features/dev/devenv.nix +++ b/parts/features/dev/devenv.nix @@ -1,12 +1,11 @@ -{config, lib, ...}: let - cfg = config; -in { +{...}: { flake.modules.homeManager.devenv = { + osConfig, lib, pkgs, ... }: { - home.persistence."/persist" = lib.mkIf cfg.dendrix.isImpermanent { + home.persistence."/persist" = lib.mkIf osConfig.dendrix.isImpermanent { directories = [ ".local/share/devenv" ]; diff --git a/parts/features/dev/direnv.nix b/parts/features/dev/direnv.nix index 72b1abaa..d3aa8c62 100644 --- a/parts/features/dev/direnv.nix +++ b/parts/features/dev/direnv.nix @@ -1,6 +1,6 @@ -{config, lib, ...}: { - flake.modules.homeManager.direnv = {...}: { - home.persistence."/persist" = lib.mkIf config.dendrix.isImpermanent { +{...}: { + flake.modules.homeManager.direnv = {lib, osConfig, ...}: { + home.persistence."/persist" = lib.mkIf osConfig.dendrix.isImpermanent { directories = [".local/share/direnv"]; }; diff --git a/parts/features/dev/git/default.nix b/parts/features/dev/git/default.nix index 42cdadee..bce4117c 100644 --- a/parts/features/dev/git/default.nix +++ b/parts/features/dev/git/default.nix @@ -1,6 +1,6 @@ -{config, lib, ...}: { - flake.modules.homeManager.git = {pkgs, ...}: { - home.persistence."/persist" = lib.mkIf config.dendrix.isImpermanent { +{...}: { + flake.modules.homeManager.git = {pkgs, lib, osConfig, ...}: { + home.persistence."/persist" = lib.mkIf osConfig.dendrix.isImpermanent { directories = [".config/glab-cli"]; }; diff --git a/parts/features/dev/neovim/_avante/default.nix b/parts/features/dev/neovim/_avante/default.nix index 6aea934d..013cef41 100644 --- a/parts/features/dev/neovim/_avante/default.nix +++ b/parts/features/dev/neovim/_avante/default.nix @@ -1,11 +1,11 @@ # Cursor style AI IDE { - isImpermanent, lib, pkgs, + osConfig, ... }: { - home.persistence."/persist" = lib.mkIf isImpermanent { + home.persistence."/persist" = lib.mkIf osConfig.dendrix.isImpermanent { directories = [ ".config/avante.nvim" # Some Avante state like last used model ]; diff --git a/parts/features/dev/neovim/_dadbod/default.nix b/parts/features/dev/neovim/_dadbod/default.nix index 30f35172..592fa33a 100644 --- a/parts/features/dev/neovim/_dadbod/default.nix +++ b/parts/features/dev/neovim/_dadbod/default.nix @@ -1,10 +1,10 @@ { - isImpermanent, lib, pkgs, + osConfig, ... }: { - home.persistence."/persist" = lib.mkIf isImpermanent { + home.persistence."/persist" = lib.mkIf osConfig.dendrix.isImpermanent { directories = [ ".local/share/db_ui" ]; diff --git a/parts/features/dev/neovim/_mason-lsp/default.nix b/parts/features/dev/neovim/_mason-lsp/default.nix index e5272123..3fc085bf 100644 --- a/parts/features/dev/neovim/_mason-lsp/default.nix +++ b/parts/features/dev/neovim/_mason-lsp/default.nix @@ -1,10 +1,10 @@ { - isImpermanent, lib, pkgs, + osConfig, ... }: { - home.persistence."/persist" = lib.mkIf isImpermanent { + home.persistence."/persist" = lib.mkIf osConfig.dendrix.isImpermanent { directories = [ ".local/state/logrotate" # Logrotate state for nvim LSP logs ]; diff --git a/parts/features/dev/neovim/default.nix b/parts/features/dev/neovim/default.nix index a92ecd9f..e4071bab 100644 --- a/parts/features/dev/neovim/default.nix +++ b/parts/features/dev/neovim/default.nix @@ -1,6 +1,4 @@ -{config, lib, ...}: let - cfg = config; -in { +{...}: { flake.modules.homeManager.neovim = { osConfig, pkgs, @@ -9,7 +7,7 @@ in { }: let isLightTheme = osConfig.specialisation != {}; in { - home.persistence."/persist" = lib.mkIf cfg.dendrix.isImpermanent { + home.persistence."/persist" = lib.mkIf osConfig.dendrix.isImpermanent { directories = [ ".local/share/nvim" ".local/state/nvim" diff --git a/parts/features/hardware/audio.nix b/parts/features/hardware/audio.nix index e4917a0c..fa5a619b 100644 --- a/parts/features/hardware/audio.nix +++ b/parts/features/hardware/audio.nix @@ -1,13 +1,11 @@ -{config, lib, ...}: let - cfg = config; -in { +{...}: { flake.modules.nixos.audio = { config, lib, pkgs, ... }: { - home-manager.users.farlion.home.persistence."/persist" = lib.mkIf cfg.dendrix.isImpermanent { + home-manager.users.farlion.home.persistence."/persist" = lib.mkIf config.dendrix.isImpermanent { directories = [ ".local/state/wireplumber" ".config/rncbc.org" @@ -74,9 +72,10 @@ in { flake.modules.homeManager.audio = { lib, pkgs, + osConfig, ... }: { - home.persistence."/persist" = lib.mkIf cfg.dendrix.isImpermanent { + home.persistence."/persist" = lib.mkIf osConfig.dendrix.isImpermanent { directories = [ ".config/easyeffects" ]; diff --git a/parts/features/hardware/bluetooth.nix b/parts/features/hardware/bluetooth.nix index eb54314d..0c721327 100644 --- a/parts/features/hardware/bluetooth.nix +++ b/parts/features/hardware/bluetooth.nix @@ -1,8 +1,6 @@ -{config, lib, ...}: let - cfg = config; -in { - flake.modules.nixos.bluetooth = {lib, ...}: { - environment.persistence."/persist/system" = lib.mkIf cfg.dendrix.isImpermanent { +{...}: { + flake.modules.nixos.bluetooth = {config, lib, ...}: { + environment.persistence."/persist/system" = lib.mkIf config.dendrix.isImpermanent { directories = [ "/var/lib/bluetooth" ]; diff --git a/parts/features/hardware/btrfs.nix b/parts/features/hardware/btrfs.nix index c14e0958..32bc603b 100644 --- a/parts/features/hardware/btrfs.nix +++ b/parts/features/hardware/btrfs.nix @@ -1,8 +1,6 @@ -{config, lib, ...}: let - cfg = config; -in { - flake.modules.nixos.btrfs = {lib, ...}: { - environment.persistence."/persist/system" = lib.mkIf cfg.dendrix.isImpermanent { +{...}: { + flake.modules.nixos.btrfs = {config, lib, ...}: { + environment.persistence."/persist/system" = lib.mkIf config.dendrix.isImpermanent { directories = ["/var/lib/btrfs"]; }; diff --git a/parts/features/hardware/firmware.nix b/parts/features/hardware/firmware.nix index 2012c28e..8bf5c5cb 100644 --- a/parts/features/hardware/firmware.nix +++ b/parts/features/hardware/firmware.nix @@ -1,8 +1,6 @@ -{config, lib, ...}: let - cfg = config; -in { - flake.modules.nixos.firmware = {lib, ...}: { - environment.persistence."/persist/system" = lib.mkIf cfg.dendrix.isImpermanent { +{...}: { + flake.modules.nixos.firmware = {config, lib, ...}: { + environment.persistence."/persist/system" = lib.mkIf config.dendrix.isImpermanent { directories = ["/var/lib/fwupd"]; }; diff --git a/parts/features/hardware/power.nix b/parts/features/hardware/power.nix index 46eea35b..5d44c16c 100644 --- a/parts/features/hardware/power.nix +++ b/parts/features/hardware/power.nix @@ -1,12 +1,11 @@ -{config, lib, ...}: let - cfg = config; -in { +{...}: { flake.modules.nixos.power = { + config, lib, pkgs, ... }: let - isFlexbox = cfg.dendrix.hostname == "flexbox"; + isFlexbox = config.dendrix.hostname == "flexbox"; in { services.thermald.enable = true; diff --git a/parts/features/security/bitwarden.nix b/parts/features/security/bitwarden.nix index d56d3c63..c6df77d5 100644 --- a/parts/features/security/bitwarden.nix +++ b/parts/features/security/bitwarden.nix @@ -1,12 +1,11 @@ -{config, lib, ...}: let - cfg = config; -in { +{...}: { flake.modules.homeManager.bitwarden = { + osConfig, lib, pkgs, ... }: { - home.persistence."/persist" = lib.mkIf cfg.dendrix.isImpermanent { + home.persistence."/persist" = lib.mkIf osConfig.dendrix.isImpermanent { directories = [ ".config/Bitwarden" ]; diff --git a/parts/features/security/security.nix b/parts/features/security/security.nix index f61981f3..d00e47a9 100644 --- a/parts/features/security/security.nix +++ b/parts/features/security/security.nix @@ -1,18 +1,17 @@ -{config, lib, ...}: let - cfg = config; -in { +{...}: { flake.modules.nixos.security = { + config, lib, pkgs, ... }: { - environment.persistence."/persist/system" = lib.mkIf cfg.dendrix.isImpermanent { + environment.persistence."/persist/system" = lib.mkIf config.dendrix.isImpermanent { directories = [ "/var/lib/boltd" "/run/sudo" ]; }; - home-manager.users.farlion.home.persistence."/persist" = lib.mkIf cfg.dendrix.isImpermanent { + home-manager.users.farlion.home.persistence."/persist" = lib.mkIf config.dendrix.isImpermanent { directories = [ ".local/share/keyrings" ".gnupg" diff --git a/parts/features/services/localsend.nix b/parts/features/services/localsend.nix index 4e44e43d..5a156448 100644 --- a/parts/features/services/localsend.nix +++ b/parts/features/services/localsend.nix @@ -1,12 +1,10 @@ -{config, lib, ...}: let - cfg = config; -in { +{...}: { flake.modules.nixos.localsend = {...}: { programs.localsend.enable = true; }; - flake.modules.homeManager.localsend = {lib, ...}: { - home.persistence."/persist" = lib.mkIf cfg.dendrix.isImpermanent { + flake.modules.homeManager.localsend = {lib, osConfig, ...}: { + home.persistence."/persist" = lib.mkIf osConfig.dendrix.isImpermanent { directories = [".local/share/org.localsend.localsend_app"]; }; }; diff --git a/parts/features/services/scrutiny.nix b/parts/features/services/scrutiny.nix index 5ba8fa20..d98ff271 100644 --- a/parts/features/services/scrutiny.nix +++ b/parts/features/services/scrutiny.nix @@ -1,8 +1,6 @@ -{config, lib, ...}: let - cfg = config; -in { - flake.modules.nixos.scrutiny = {lib, ...}: { - environment.persistence."/persist/system" = lib.mkIf cfg.dendrix.isImpermanent { +{...}: { + flake.modules.nixos.scrutiny = {config, lib, ...}: { + environment.persistence."/persist/system" = lib.mkIf config.dendrix.isImpermanent { directories = [ { directory = "/var/lib/private"; diff --git a/parts/features/services/syncthing.nix b/parts/features/services/syncthing.nix index f8ed46aa..ca459979 100644 --- a/parts/features/services/syncthing.nix +++ b/parts/features/services/syncthing.nix @@ -1,4 +1,4 @@ -{config, lib, ...}: { +{...}: { flake.modules.nixos.syncthing = {pkgs, ...}: { # Prevent syncthing from preventing sleep powerManagement.powerDownCommands = '' @@ -11,8 +11,8 @@ ''; }; - flake.modules.homeManager.syncthing = {...}: { - home.persistence."/persist" = lib.mkIf config.dendrix.isImpermanent { + flake.modules.homeManager.syncthing = {lib, osConfig, ...}: { + home.persistence."/persist" = lib.mkIf osConfig.dendrix.isImpermanent { directories = [ ".local/state/syncthing" ".config/syncthing" diff --git a/parts/features/services/virtualisation/default.nix b/parts/features/services/virtualisation/default.nix index e2a90e04..d3ecdb01 100644 --- a/parts/features/services/virtualisation/default.nix +++ b/parts/features/services/virtualisation/default.nix @@ -1,6 +1,4 @@ -{config, lib, ...}: let - cfg = config; -in { +{...}: { flake.modules.nixos.virtualisation = { config, lib, @@ -23,14 +21,14 @@ in { text = builtins.readFile ./_scripts/reset-container-state.sh; }; in { - environment.persistence."/persist/system" = lib.mkIf cfg.dendrix.isImpermanent { + environment.persistence."/persist/system" = lib.mkIf config.dendrix.isImpermanent { directories = [ "/var/lib/containers" "/var/lib/docker" "/var/lib/libvirt" ]; }; - home-manager.users.farlion.home.persistence."/persist" = lib.mkIf cfg.dendrix.isImpermanent { + home-manager.users.farlion.home.persistence."/persist" = lib.mkIf config.dendrix.isImpermanent { directories = [ ".local/share/containers" ]; diff --git a/parts/hosts.nix b/parts/hosts.nix index 0c4b3c13..f5339bbb 100644 --- a/parts/hosts.nix +++ b/parts/hosts.nix @@ -19,7 +19,46 @@ }; }; + # NixOS module that defines dendrix options for host-specific configuration + dendrixOptionsModule = {lib, ...}: { + options.dendrix = { + hostname = lib.mkOption { + type = lib.types.str; + description = "Hostname of this machine"; + }; + isLaptop = lib.mkOption { + type = lib.types.bool; + default = false; + description = "Whether this is a laptop"; + }; + isImpermanent = lib.mkOption { + type = lib.types.bool; + default = false; + description = "Whether this machine uses impermanence (ephemeral root)"; + }; + hasNvidia = lib.mkOption { + type = lib.types.bool; + default = false; + description = "Whether this machine has an NVIDIA GPU"; + }; + hasAmd = lib.mkOption { + type = lib.types.bool; + default = false; + description = "Whether this machine has an AMD GPU"; + }; + stateVersion = lib.mkOption { + type = lib.types.str; + description = "NixOS state version for this host"; + }; + homeStateVersion = lib.mkOption { + type = lib.types.str; + description = "Home Manager state version for this host"; + }; + }; + }; + commonNixosModules = [ + dendrixOptionsModule { nixpkgs.overlays = [ (_: _: commonOverlays) @@ -44,8 +83,8 @@ ++ [ "${impermanence}/home-manager.nix" nur.modules.homeManager.default - stylix.homeManagerModules.stylix - niri.homeModules.niri + # Note: stylix home-manager module is injected by stylix.nixosModules.stylix + # Note: niri home-manager module is injected by niri.nixosModules.niri ]; }; @@ -89,7 +128,7 @@ in { flake.nixosConfigurations = { flexbox = mkHost { hostname = "flexbox"; - hostModule = ./hosts/flexbox; + hostModule = ./_hosts/flexbox; dendrixConfig = { hostname = "flexbox"; isLaptop = true; @@ -103,7 +142,7 @@ in { numenor = mkHost { hostname = "numenor"; - hostModule = ./hosts/numenor; + hostModule = ./_hosts/numenor; dendrixConfig = { hostname = "numenor"; isLaptop = false; diff --git a/parts/hosts/flexbox/hardware-scan.nix b/parts/hosts/flexbox/hardware-scan.nix deleted file mode 100644 index 0423c4fe..00000000 --- a/parts/hosts/flexbox/hardware-scan.nix +++ /dev/null @@ -1,29 +0,0 @@ -# Do not modify this file! It was generated by ‘nixos-generate-config’ -# and may be overwritten by future invocations. Please make changes -# to /etc/nixos/configuration.nix instead. -{lib, ...}: { - boot.initrd.availableKernelModules = ["xhci_pci" "nvme" "usbhid" "usb_storage" "sd_mod" "rtsx_pci_sdmmc"]; - boot.initrd.kernelModules = ["dm-snapshot"]; - boot.kernelModules = ["kvm-intel"]; - boot.extraModulePackages = []; - - fileSystems."/" = { - device = "/dev/disk/by-uuid/e5687086-9188-42e8-aa57-423df9cbb863"; - fsType = "ext4"; - options = ["noatime"]; - }; - - fileSystems."/boot" = { - device = "/dev/disk/by-uuid/8483-92D7"; - fsType = "vfat"; - options = ["fmask=0022" "dmask=0022"]; - }; - - hardware.cpu.intel.updateMicrocode = true; - - swapDevices = [{device = "/dev/disk/by-uuid/0fb837c4-ba4e-437d-a54c-ff25312af20c";}]; - - nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; - - powerManagement.cpuFreqGovernor = lib.mkDefault "powersave"; -} diff --git a/parts/hosts/numenor/hardware-scan.nix b/parts/hosts/numenor/hardware-scan.nix deleted file mode 100644 index 8cea533a..00000000 --- a/parts/hosts/numenor/hardware-scan.nix +++ /dev/null @@ -1,37 +0,0 @@ -{lib, ...}: { - boot.initrd.availableKernelModules = ["thunderbolt" "xhci_pci" "ahci" "nvme" "usbhid" "usb_storage" "sd_mod"]; - boot.initrd.kernelModules = ["dm-snapshot"]; - boot.kernelModules = ["kvm-amd"]; - boot.extraModulePackages = []; - - fileSystems."/" = { - device = "/dev/disk/by-uuid/d601a8b7-17a4-46b5-a95e-ab29e94790ef"; - fsType = "btrfs"; - options = ["subvol=root" "compress=zstd" "noatime"]; - }; - - fileSystems."/nix" = { - device = "/dev/disk/by-uuid/d601a8b7-17a4-46b5-a95e-ab29e94790ef"; - fsType = "btrfs"; - options = ["subvol=nix" "compress=zstd" "noatime"]; - }; - - fileSystems."/persist" = { - device = "/dev/disk/by-uuid/d601a8b7-17a4-46b5-a95e-ab29e94790ef"; - fsType = "btrfs"; - options = ["subvol=persist" "compress=zstd" "noatime"]; - }; - - fileSystems."/boot" = { - device = "/dev/disk/by-uuid/12CE-A600"; - fsType = "vfat"; - options = ["fmask=0022" "dmask=0022"]; - }; - - swapDevices = [ - {device = "/dev/disk/by-uuid/daee540c-201b-4ccd-9315-7d8c44c57af6";} - ]; - - nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; - hardware.cpu.amd.updateMicrocode = true; -} diff --git a/parts/options.nix b/parts/options.nix deleted file mode 100644 index beeccad6..00000000 --- a/parts/options.nix +++ /dev/null @@ -1,42 +0,0 @@ -{lib, ...}: { - options.dendrix = { - hostname = lib.mkOption { - type = lib.types.str; - description = "Hostname of this machine"; - }; - - isLaptop = lib.mkOption { - type = lib.types.bool; - default = false; - description = "Whether this is a laptop"; - }; - - isImpermanent = lib.mkOption { - type = lib.types.bool; - default = false; - description = "Whether this machine uses impermanence (ephemeral root)"; - }; - - hasNvidia = lib.mkOption { - type = lib.types.bool; - default = false; - description = "Whether this machine has an NVIDIA GPU"; - }; - - hasAmd = lib.mkOption { - type = lib.types.bool; - default = false; - description = "Whether this machine has an AMD GPU"; - }; - - stateVersion = lib.mkOption { - type = lib.types.str; - description = "NixOS state version for this host"; - }; - - homeStateVersion = lib.mkOption { - type = lib.types.str; - description = "Home Manager state version for this host"; - }; - }; -} diff --git a/specialisations/light/default.nix b/specialisations/light/default.nix deleted file mode 100644 index 421881d3..00000000 --- a/specialisations/light/default.nix +++ /dev/null @@ -1,53 +0,0 @@ -{ - lib, - pkgs, - ... -}: { - specialisation.light.configuration = { - environment.etc."specialisation".text = "light"; # this is for 'nh' to correctly recognise the specialisation - - # System - stylix = { - base16Scheme = lib.mkForce "${pkgs.base16-schemes}/share/themes/catppuccin-latte.yaml"; - image = lib.mkForce ../../system/stylix/gruvbox-light-rainbow.png; - polarity = lib.mkForce "light"; - }; - - # Home Manager - home-manager.users.farlion = { - # Aichat Light Theme - home.sessionVariables = { - AICHAT_LIGHT_THEME = 1; - }; - - # Dunst - services.dunst.iconTheme.name = lib.mkForce "Papirus-Light"; - - # GTK - gtk.gtk3.extraConfig.gtk-application-prefer-dark-theme = lib.mkForce false; - - # QT - qt.enable = lib.mkForce false; - - # Neovim - programs.neovim = { - extraLuaConfig = '' - -- Override lualine theme for light mode - if require('lualine') then - local lualine_config = require('lualine').get_config() - lualine_config.options.theme = 'gruvbox-light' - require('lualine').setup(lualine_config) - end - ''; - }; - - stylix.targets = { - # Neovim - neovim.enable = lib.mkForce true; - }; - - # K9s - programs.k9s.settings.k9s.ui.skin = lib.mkForce "gruvbox-light"; - }; - }; -} diff --git a/system/amd/default.nix b/system/amd/default.nix deleted file mode 100644 index e630ef92..00000000 --- a/system/amd/default.nix +++ /dev/null @@ -1,39 +0,0 @@ -# See: https://wiki.nixos.org/wiki/AMD_GPU -# Also see: https://wiki.archlinux.org/title/Hardware_video_acceleration -{pkgs, ...}: { - hardware.amdgpu = { - initrd.enable = true; - opencl.enable = true; - }; - - # Disable AMD GPU power management to see if it prevents feezes on S3/s2idle - boot.kernelParams = [ - "amdgpu.runpm=0" - ]; - - environment.systemPackages = with pkgs; [ - lact # GUI for overclocking, undervolting, setting fan curves, etc. - libva-utils - mesa-demos - nvtopPackages.full # nvtop - vulkan-tools - ]; - services.xserver.videoDrivers = ["amdgpu"]; - hardware.graphics = { - enable = true; - enable32Bit = true; - }; - - # # AMDVLK drivers (programs will choose whether to use this over Mesa RADV drivers) - # hardware.graphics.extraPackages = with pkgs; [ - # amdvlk - # ]; - # # For 32 bit applications - # hardware.opengl.extraPackages32 = with pkgs; [ - # driversi686Linux.amdvlk - # ]; - - # GUI for overclocking, undervolting, setting fan curves, etc. - systemd.packages = with pkgs; [lact]; - systemd.services.lactd.wantedBy = ["multi-user.target"]; -} diff --git a/system/audio/default.nix b/system/audio/default.nix deleted file mode 100644 index ad820b65..00000000 --- a/system/audio/default.nix +++ /dev/null @@ -1,73 +0,0 @@ -{ - config, - lib, - pkgs, - ... -}: let -in { - home-manager.users.farlion.home.persistence."/persist" = lib.mkIf config.home-manager.extraSpecialArgs.isImpermanent { - directories = [ - ".local/state/wireplumber" # Wireplumber state - ".config/rncbc.org" # qpwgraph config file - ".config/pulse" # pulseaudio cookie - ]; - }; - - environment.systemPackages = with pkgs; [ - alsa-utils - pulseaudioFull - qpwgraph # More extensive patchbay for Pipewire - ]; - - users.users.farlion.extraGroups = ["audio"]; - - # PipeWire! - security.rtkit.enable = true; - services.pipewire = { - enable = true; - alsa.enable = true; - alsa.support32Bit = true; - pulse.enable = true; - - extraConfig.pipewire."92-adjust-clock-quantum" = { - "context.properties" = { - "default.clock.quantum" = 2048; # Larger buffers should prevent xruns - "default.clock.min-quantum" = 512; # Larger buffers should prevent xruns - "default.clock.max-quantum" = 8192; # Matches Windows Settings - }; - }; - extraConfig.pipewire."93-disable-autosuspend" = { - "context.properties" = { - "session.suspend-timeout-seconds" = 0; # Prevent autosuspend of ALSA nodes, causing xruns and crashes - }; - }; - - wireplumber.extraConfig = { - # Enable Fancy Blueooth Codecs - "monitor.bluez.properties" = { - "bluez5.enable-sbc-xq" = true; - "bluez5.enable-msbc" = true; - "bluez5.enable-hw-volume" = true; - "bluez5.roles" = ["hsp_hs" "hsp_ag" "hfp_hf" "hfp_ag"]; - }; - - # Disable unused sinks and sources - "disable-unused-nodes" = { - "monitor.alsa.rules" = [ - { - matches = [ - { - "device.nick" = "HDA NVidia"; - } - ]; - actions = { - update-props = { - "device.disabled" = true; - }; - }; - } - ]; - }; - }; - }; -} diff --git a/system/bluetooth/default.nix b/system/bluetooth/default.nix deleted file mode 100644 index d6cebb3d..00000000 --- a/system/bluetooth/default.nix +++ /dev/null @@ -1,13 +0,0 @@ -{ - lib, - isImpermanent, - ... -}: { - environment.persistence."/persist/system" = lib.mkIf isImpermanent { - directories = [ - "/var/lib/bluetooth" - ]; - }; - services.blueman.enable = true; - hardware.bluetooth.enable = true; -} diff --git a/system/boot/default.nix b/system/boot/default.nix deleted file mode 100644 index dd29ef7c..00000000 --- a/system/boot/default.nix +++ /dev/null @@ -1,17 +0,0 @@ -{...}: let -in { - boot = { - loader.systemd-boot = { - enable = true; - memtest86.enable = true; - }; - loader.efi.canTouchEfiVariables = true; - consoleLogLevel = 7; - - initrd = { - systemd = { - enable = true; - }; - }; - }; -} diff --git a/system/btrfs/default.nix b/system/btrfs/default.nix deleted file mode 100644 index 2a0d19e1..00000000 --- a/system/btrfs/default.nix +++ /dev/null @@ -1,17 +0,0 @@ -{ - lib, - isImpermanent, - ... -}: { - environment.persistence."/persist/system" = lib.mkIf isImpermanent { - directories = [ - "/var/lib/btrfs" # Scrub reports - ]; - }; - - services.btrfs.autoScrub = { - enable = true; - interval = "monthly"; - fileSystems = ["/"]; # Subvols of the same mount point don't need to be scrubbed - }; -} diff --git a/system/cachix/default.nix b/system/cachix/default.nix deleted file mode 100644 index d6f0c3f9..00000000 --- a/system/cachix/default.nix +++ /dev/null @@ -1,5 +0,0 @@ -{pkgs, ...}: { - environment.systemPackages = [ - pkgs.cachix - ]; -} diff --git a/system/default.nix b/system/default.nix deleted file mode 100644 index dc5bd67e..00000000 --- a/system/default.nix +++ /dev/null @@ -1,46 +0,0 @@ -{ - lib, - isImpermanent, - pkgs, - secrets, - ... -}: let - systemSecrets = - if secrets ? systemSecrets - then secrets.systemSecrets {inherit isImpermanent lib pkgs;} - else {}; -in { - imports = - [ - ./audio - ./bluetooth - ./boot - ./cachix - ./desktop - ./dns - ./firmware - ./fonts - ./io - ./kernel - ./kind-killer - ./localsend # Apple Airdrop OSS - ./networking - ./nix-ld - ./performance - ./power - ./printing - ./scrutiny # Hard Drive S.M.A.R.T Monitoring, historical trends - ./security - ./smb - ./stylix - ./syncthing - ./systemd - ./users - ./various - ./video - ./virtualisation - ./wireshark - ] - ++ lib.lists.optionals isImpermanent [./impermanence] - ++ [systemSecrets]; -} diff --git a/system/desktop/default.nix b/system/desktop/default.nix deleted file mode 100644 index e4316672..00000000 --- a/system/desktop/default.nix +++ /dev/null @@ -1,68 +0,0 @@ -{ - isImpermanent, - lib, - pkgs, - ... -}: { - environment.persistence."/persist/system" = lib.mkIf isImpermanent { - files = [ - "/etc/ly/save.ini" # Selected user and session - ]; - }; - - services.displayManager = { - defaultSession = "niri"; - ly = { - enable = true; - settings = { - animation = "doom"; - hide_borders = true; - }; - }; - }; - - # Mounting Android phone from Files - services.gvfs.enable = true; - - programs.niri = { - enable = true; - }; - # XDG Portal Settings For Niri - xdg.portal = { - enable = true; - config = { - common = { - default = ["gnome" "gtk"]; - }; - niri = { - default = ["gnome" "gtk"]; - "org.freedesktop.impl.portal.ScreenCast" = ["gnome"]; - "org.freedesktop.impl.portal.Screenshot" = ["gnome"]; - "org.freedesktop.impl.portal.FileChooser" = ["gtk"]; - }; - }; - extraPortals = [ - pkgs.xdg-desktop-portal-gnome - pkgs.xdg-desktop-portal-gtk - ]; - }; - - # Fix niri portals autostart order - # See https://github.com/sodiboo/niri-flake/issues/509 - systemd.user.services.xdg-desktop-portal = { - after = ["xdg-desktop-autostart.target"]; - }; - systemd.user.services.xdg-desktop-portal-gtk = { - after = ["xdg-desktop-autostart.target"]; - }; - systemd.user.services.xdg-desktop-portal-gnome = { - after = ["xdg-desktop-autostart.target"]; - }; - systemd.user.services.niri-flake-polkit = { - after = ["xdg-desktop-autostart.target"]; - }; - - programs.sway = { - enable = true; - }; -} diff --git a/system/dns/default.nix b/system/dns/default.nix deleted file mode 100644 index 4a0daccd..00000000 --- a/system/dns/default.nix +++ /dev/null @@ -1,12 +0,0 @@ -{...}: { - services.resolved = { - enable = true; - llmnr = "false"; # https://www.blackhillsinfosec.com/how-to-disable-llmnr-why-you-want-to/ - extraConfig = '' - MulticastDNS=false - DNSStubListenerExtra=172.17.0.1 - ''; - fallbackDns = []; # Ensure we always go through the configured DNS, no magic defaults - }; - networking.networkmanager.dns = "systemd-resolved"; -} diff --git a/system/firmware/default.nix b/system/firmware/default.nix deleted file mode 100644 index 37f95369..00000000 --- a/system/firmware/default.nix +++ /dev/null @@ -1,14 +0,0 @@ -# Linux Firmware Updates -{ - lib, - isImpermanent, - ... -}: { - environment.persistence."/persist/system" = lib.mkIf isImpermanent { - directories = [ - "/var/lib/fwupd" - ]; - }; - - services.fwupd.enable = true; -} diff --git a/system/fonts/default.nix b/system/fonts/default.nix deleted file mode 100644 index 0ed5b6e3..00000000 --- a/system/fonts/default.nix +++ /dev/null @@ -1,78 +0,0 @@ -{ - config, - lib, - pkgs, - ... -}: let - # Looted from https://gist.github.com/elijahmanor/c10e5787bf9ac6b8c276e47e6745826c, much obliged - fontSmokeTest = pkgs.writers.writeBashBin "font-smoke-test" '' - set -e - - printf "%b\n" "Normal" - printf "%b\n" "\033[1mBold\033[22m" - printf "%b\n" "\033[3mItalic\033[23m" - printf "%b\n" "\033[3;1mBold Italic\033[0m" - printf "%b\n" "\033[4mUnderline\033[24m" - printf "%b\n" "== === !== >= <= =>" - printf "%b\n" "   󰾆   󱑥 󰒲 󰗼" - ''; - # Patch Fira Code with Nerd Fonts plus local Font Awesome 6 Pro glyphs into ~/.local/share/fonts - patchFiraWithFA6Pro = pkgs.writeShellApplication { - name = "patch-fira-with-fa6-pro"; - runtimeInputs = [ - pkgs.fira-code - pkgs.fontforge - pkgs.findutils - pkgs.coreutils - pkgs.fontconfig - pkgs.nerd-font-patcher - ]; - runtimeEnv = { - SRC_DIR = "${pkgs.fira-code}/share/fonts/truetype"; - }; - text = builtins.readFile ./scripts/patch-fira-with-fa6-pro.sh; - }; -in { - home-manager.users.farlion.home.persistence."/persist" = lib.mkIf config.home-manager.extraSpecialArgs.isImpermanent { - directories = [ - ".local/share/fonts" # Locally persisted fonts (not nixos-managed) - ".cache/fontconfig" # Fontconfig cache - ]; - }; - - environment.systemPackages = [ - fontSmokeTest - patchFiraWithFA6Pro - ]; - - # Run the patcher during Home Manager activation so that fonts are ready after switch - home-manager.users.farlion.home.activation.patchFiraWithFA6Pro = '' - OUT_DIR="$HOME/.local/share/fonts/NerdPatched/FiraCodeFAPro" - if [ ! -d "$OUT_DIR" ] || [ -z "$(ls -A "$OUT_DIR" 2>/dev/null)" ]; then - echo "[patch-fira-with-fa6-pro] Patched fonts not found or directory empty, running patcher..." - "${patchFiraWithFA6Pro}/bin/patch-fira-with-fa6-pro" - else - echo "[patch-fira-with-fa6-pro] Patched fonts already exist in $OUT_DIR, skipping..." - fi - ''; - - fonts = { - enableDefaultPackages = false; - packages = [ - pkgs.fira-code - pkgs.fira-code-symbols - pkgs.dejavu_fonts - pkgs.font-awesome_5 - pkgs.font-awesome_6 - pkgs.unstable.font-awesome - pkgs.noto-fonts-color-emoji # emoji font - ]; - fontconfig = { - defaultFonts = { - sansSerif = ["DejaVu Sans"]; - serif = ["DejaVu Serif"]; - monospace = ["FiraCode Nerd Font" "Fira Code"]; - }; - }; - }; -} diff --git a/system/fonts/scripts/patch-fira-with-fa6-pro.sh b/system/fonts/scripts/patch-fira-with-fa6-pro.sh deleted file mode 100644 index c0b655b6..00000000 --- a/system/fonts/scripts/patch-fira-with-fa6-pro.sh +++ /dev/null @@ -1,130 +0,0 @@ -# This script is executed by a Nix-built wrapper (pkgs.writeShellApplication) -# Required tools are provided via runtimeInputs. Do not add Nix-specific paths here. -set -euo pipefail - -FA_DIR="$HOME/.local/share/fonts/Font Awesome v6.5.1" -if [ ! -d "$FA_DIR" ]; then - echo "[patch-fira-with-fa6-pro] Font Awesome 6 Pro not found at: $FA_DIR" - echo "[patch-fira-with-fa6-pro] Skipping patch step." - exit 0 -fi - -OUT_DIR="$HOME/.local/share/fonts/NerdPatched/FiraCodeFAPro" -mkdir -p "$OUT_DIR" - -# Fix ownership and permissions to avoid PermissionError from nerd-font-patcher -echo "[patch-fira-with-fa6-pro] Ensuring proper permissions for output directory..." - -# Ensure the directory and all its contents are owned by the current user -if [ -d "$OUT_DIR" ]; then - # Change ownership if needed (may require sudo, but let's try without first) - if ! [ -O "$OUT_DIR" ]; then - echo "[patch-fira-with-fa6-pro] WARNING: Output directory not owned by current user" - echo "[patch-fira-with-fa6-pro] You may need to run: sudo chown -R \"$USER\":\"$USER\" \"$OUT_DIR\"" - fi - - # Ensure directory is writable - chmod u+w "$OUT_DIR" 2>/dev/null || { - echo "[patch-fira-with-fa6-pro] ERROR: Cannot make output directory writable: $OUT_DIR" >&2 - echo "[patch-fira-with-fa6-pro] Suggested fix: sudo chown -R \"$USER\":\"$USER\" \"$OUT_DIR\"" >&2 - echo "[patch-fira-with-fa6-pro] Then run: chmod -R u+w \"$OUT_DIR\"" >&2 - exit 1 - } - - # Make existing files writable - find "$OUT_DIR" -type f -exec chmod u+w {} \; 2>/dev/null || { - echo "[patch-fira-with-fa6-pro] ERROR: Cannot make existing files writable in $OUT_DIR" >&2 - echo "[patch-fira-with-fa6-pro] Suggested fix: sudo chown -R \"$USER\":\"$USER\" \"$OUT_DIR\"" >&2 - exit 1 - } -fi - -# Ensure created files are world-readable -umask 022 - -# Use a cache-backed temp base to avoid any /tmp quirks -CACHE_DIR="${XDG_CACHE_HOME:-$HOME/.cache}/nerd-font-patcher" -mkdir -p "$CACHE_DIR" - -# Try to locate a suitable FA6 Pro Regular font file (otf or ttf) -FA_PRO_FILE="$(find "$FA_DIR" -type f \( -iname '*Pro-Regular-400.*' -o -iname '*Pro-Regular.*' \) | head -n 1 || true)" -if [ -z "${FA_PRO_FILE:-}" ]; then - echo "[patch-fira-with-fa6-pro] Could not find a 'Font Awesome 6 Pro Regular' font file in: $FA_DIR" - echo "[patch-fira-with-fa6-pro] Skipping patch step." - exit 0 -fi - -# The wrapper sets SRC_DIR to the absolute path for Fira Code TTFs -if [ -z "${SRC_DIR:-}" ] || [ ! -d "$SRC_DIR" ]; then - echo "[patch-fira-with-fa6-pro] ERROR: SRC_DIR not set or not a directory (expected Fira Code .ttf source)." >&2 - exit 1 -fi - -echo "[patch-fira-with-fa6-pro] Using FA6 Pro: $FA_PRO_FILE" -echo "[patch-fira-with-fa6-pro] Patching Fira Code fonts from: $SRC_DIR -> $OUT_DIR" - -failures=0 -set +e -for font in "$SRC_DIR"/*.ttf; do - base="$(basename "$font")" - echo "[patch-fira-with-fa6-pro] Patching $base ..." - - # Create a temporary directory for this operation to avoid permission issues - temp_dir=$(mktemp -d "$CACHE_DIR/patch.XXXXXX") - temp_output="$temp_dir/output" - mkdir -p "$temp_output" - - # Copy source font into temp dir to avoid nerd-font-patcher opening read-only Nix store paths with r+b - # Use a .woff extension to bypass the patcher's head-table tweaking step that opens files r+b - base_woff="${base%.ttf}.woff" - src_copy="$temp_dir/$base_woff" - cp "$font" "$src_copy" - chmod u+rw "$src_copy" 2>/dev/null || true - - # Run patcher and capture output (do not echo log by default) - patch_log="$temp_dir/patch.log" - nerd-font-patcher \ - "$src_copy" \ - --complete \ - --custom "$FA_PRO_FILE" \ - --careful \ - --extension ttf \ - -out "$temp_output" >"$patch_log" 2>&1 - rc=$? - - if [ "$rc" -eq 0 ]; then - # Move the patched font from temp directory to final destination - if ls "$temp_output"/*.ttf 1>/dev/null 2>&1; then - # Show a concise success summary per font - for f in "$temp_output"/*.ttf; do - echo "[patch-fira-with-fa6-pro] Generated $(basename "$f")" - done - mv "$temp_output"/*.ttf "$OUT_DIR/" || { - echo "[patch-fira-with-fa6-pro] ERROR: Failed to move patched font for $base" >&2 - rc=1 - } - else - echo "[patch-fira-with-fa6-pro] ERROR: No patched font found for $base" >&2 - rc=1 - fi - fi - - # Clean up temp directory - rm -rf "$temp_dir" - - if [ "$rc" -ne 0 ]; then - echo "[patch-fira-with-fa6-pro] ERROR: Patching failed for $base (exit $rc). Log at: $patch_log" >&2 - failures=$((failures + 1)) - fi -done -set -e - -# Refresh the font cache so newly patched fonts are available -fc-cache -f "$HOME/.local/share/fonts" || true - -if [ "$failures" -gt 0 ]; then - echo "[patch-fira-with-fa6-pro] Completed with $failures failure(s). See log(s) referenced above." >&2 - exit 1 -fi - -echo "[patch-fira-with-fa6-pro] Done." diff --git a/system/impermanence/default.nix b/system/impermanence/default.nix deleted file mode 100644 index 04775b02..00000000 --- a/system/impermanence/default.nix +++ /dev/null @@ -1,105 +0,0 @@ -# General impermanence setup -# Note: specifics should live with their respective modules, where possible! -{ - lib, - pkgs, - ... -}: let - rootExplosion = '' - echo "Time to 🧨" >/dev/kmsg - mkdir /btrfs_tmp - mount /dev/mapper/nixos--vg-root /btrfs_tmp - - # Root impermanence - if [[ -e /btrfs_tmp/root ]]; then - mkdir -p /btrfs_tmp/persist/old_roots - timestamp=$(date --date="@$(stat -c %Y /btrfs_tmp/root)" "+%Y-%m-%d_%H:%M:%S") - if [[ ! -e /btrfs_tmp/persist/old_roots/$timestamp ]]; then - mv /btrfs_tmp/root "/btrfs_tmp/persist/old_roots/$timestamp" - else - btrfs subvolume delete /btrfs_tmp/root - fi - fi - - ### - # GC - ### - latest_snapshot=$(find /btrfs_tmp/persist/old_roots/ -mindepth 1 -maxdepth 1 -type d | sort -r | head -n 1) - # Only delete old snapshots if there's at least one that will remain after deletion - if [ -n "$latest_snapshot" ]; then - for i in $(find /btrfs_tmp/persist/old_roots/ -mindepth 1 -maxdepth 1 -mtime +30 | grep -v -e "$latest_snapshot"); do - btrfs subvolume delete -R "$i" - done - fi - - btrfs subvolume create /btrfs_tmp/root - umount /btrfs_tmp - echo "Done with 🧨. Au revoir!" >/dev/kmsg - ''; -in { - # Explode / on every boot and resume, see https://grahamc.com/blog/erase-your-darlings/ - boot.initrd.systemd = { - extraBin = { - grep = "${pkgs.gnugrep}/bin/grep"; - }; - services = { - root-explode = { - enableStrictShellChecks = false; - wantedBy = ["initrd-root-device.target"]; - wants = ["lvm2-activation.service"]; - # See https://github.com/nix-community/impermanence/issues/250#issuecomment-2603848867 - after = ["lvm2-activation.service" "local-fs-pre.target"]; - before = ["sysroot.mount"]; - # Run on cold boot only, never on resume from hibernation - unitConfig = { - ConditionKernelCommandLine = ["!resume="]; - RequiresMountsFor = ["/dev/mapper/nixos--vg-root"]; - }; - serviceConfig = { - StandardOutput = "journal+console"; - StandardError = "journal+console"; - Type = "oneshot"; - }; - script = rootExplosion; - }; - }; - }; - - boot.tmp.cleanOnBoot = true; - - fileSystems."/persist".neededForBoot = true; - - environment.persistence."/persist/system" = { - enable = true; - hideMounts = true; - directories = [ - "/root/.cache/nix" - "/var/lib/logrotate" # See https://github.com/nix-community/impermanence/issues/270 - "/var/lib/nixos" - "/var/lib/systemd/coredump" - "/var/lib/systemd/timers" - "/var/lib/udisks2" - "/var/log" - ]; - files = [ - "/etc/machine-id" - ]; - }; - # Workaround for /etc/ file timings not working with impermanence - environment.etc = { - # Timezone data linked by tzupdate - "localtime".source = "/persist/system/etc/localtime"; - }; - - # Woraround for logrotate, see https://github.com/nix-community/impermanence/issues/270 - services.logrotate.extraArgs = lib.mkAfter ["--state" "/var/lib/logrotate/logrotate.status"]; - - # home-manager's impermanence module doesn't have permissions to bootstrap these dirs, so we do it here: - system.activationScripts.bootstrapPersistHome.text = '' - mkdir -p /persist/home/farlion - chown farlion:users /persist/home/farlion - chmod 0700 /persist/home/farlion - ''; - - programs.fuse.userAllowOther = true; # Needed for home-manager's impermanence allowOther option to work -} diff --git a/system/io/default.nix b/system/io/default.nix deleted file mode 100644 index cb5f57f5..00000000 --- a/system/io/default.nix +++ /dev/null @@ -1,45 +0,0 @@ -{pkgs, ...}: { - hardware.logitech.wireless = { - enable = true; - enableGraphical = true; - }; - - # Keyd remappenings - environment.systemPackages = with pkgs; [ - keyd - ]; - services.keyd = { - enable = true; - keyboards.default = { - ids = ["*"]; - settings = { - main = { - # Tap = Esc, hold = enter the fkeys layer - capslock = "overload(fkeys, esc)"; - }; - fkeys = { - "1" = "f1"; - "2" = "f2"; - "3" = "f3"; - "4" = "f4"; - "5" = "f5"; - "6" = "f6"; - "7" = "f7"; - "8" = "f8"; - "9" = "f9"; - "0" = "f10"; - minus = "f11"; - equal = "f12"; - }; - }; - }; - }; - - # Improves palm-rejection with the keyd virtual keyboard - environment.etc."libinput/local-overrides.quirks".text = '' - [Serial Keyboards] - MatchUdevType=keyboard - MatchName=keyd*keyboard - AttrKeyboardIntegration=internal - ''; -} diff --git a/system/kernel/default.nix b/system/kernel/default.nix deleted file mode 100644 index 142453d1..00000000 --- a/system/kernel/default.nix +++ /dev/null @@ -1,22 +0,0 @@ -{pkgs, ...}: { - # Writes to /etc/sysctl.d/60-nixos.conf - boot.kernel.sysctl = { - # Enable all magic sysrq commands (NixOS sets this to 16, which enables sync only) - "kernel.sysrq" = 1; - "vm.swappiness" = 20; # balanced setting favoring RAM usage, Default=60 - }; - - boot.kernelPackages = pkgs.linuxPackages_zen; # Optimized for desktop use - environment.systemPackages = with pkgs; [ - perf - linuxKernel.packages.linux_zen.cpupower - ]; - - boot.initrd.verbose = true; - # Keep console visible during teardown - boot.kernelParams = [ - "systemd.show_status=1" - "i915.enable_psr=0" # Intel PSR often blanks the console on transitions - "i915.fastboot=0" # avoid early/quiet KMS handover - ]; -} diff --git a/system/kind-killer/default.nix b/system/kind-killer/default.nix deleted file mode 100644 index 42ad9f64..00000000 --- a/system/kind-killer/default.nix +++ /dev/null @@ -1,13 +0,0 @@ -{pkgs, ...}: { - systemd.services.kind-killer = { - description = "Kill kind cluster on shutdown"; - after = ["docker.service"]; # Ensures docker is still running when trying to delete the cluster, since systemd reverses the ordering during shutdown - requires = ["docker.service"]; - wantedBy = ["multi-user.target"]; - serviceConfig = { - Environment = "PATH=$PATH:/run/current-system/sw/bin"; - ExecStart = "${pkgs.coreutils}/bin/sleep infinity"; - ExecStop = "${pkgs.kind}/bin/kind delete cluster"; - }; - }; -} diff --git a/system/localsend/default.nix b/system/localsend/default.nix deleted file mode 100644 index 33839316..00000000 --- a/system/localsend/default.nix +++ /dev/null @@ -1,15 +0,0 @@ -{ - config, - lib, - ... -}: { - home-manager.users.farlion.home.persistence."/persist" = lib.mkIf config.home-manager.extraSpecialArgs.isImpermanent { - directories = [ - ".local/share/org.localsend.localsend_app" - ]; - }; - - programs.localsend = { - enable = true; - }; -} diff --git a/system/networking/default.nix b/system/networking/default.nix deleted file mode 100644 index 67f914b1..00000000 --- a/system/networking/default.nix +++ /dev/null @@ -1,91 +0,0 @@ -{ - config, - lib, - isImpermanent, - isLaptop, - pkgs, - ... -}: let - # Get the current tailscale ip if tailscale is up - tailscale-ip = pkgs.writers.writeBashBin "tailscale-ip" '' - set -euo pipefail - - isOnline=$(tailscale status --json | jq -r '.Self.Online') - if [[ "$isOnline" == "true" ]]; then - tailscaleIp=$(tailscale status --json | jq -r '.Self.TailscaleIPs[0]') - echo "{\"icon\": \"tailscale_up\", \"text\": \"$tailscaleIp\", \"state\": \"Good\"}" - else - echo "{\"icon\": \"tailscale_down\", \"text\": \"\", \"state\": \"Idle\"}" - fi - ''; -in { - environment.persistence."/persist/system" = lib.mkIf isImpermanent { - directories = [ - "/etc/NetworkManager/system-connections" - "/var/lib/tailscale" - "/var/lib/NetworkManager" - ]; - }; - home-manager.users.farlion.home.persistence."/persist" = lib.mkIf config.home-manager.extraSpecialArgs.isImpermanent { - directories = [ - ".config/tailscale" # Tailscale known hosts - ]; - }; - - environment.systemPackages = [ - pkgs.pwru # eBPF-based linux kernel networking debugger - tailscale-ip # Get the current tailscale IP if tailscale is up - ]; - - networking.firewall = { - # if packets are dropped, they will show up in dmesg - logReversePathDrops = true; - logRefusedPackets = true; - # logRefusedUnicastsOnly = false; - }; - - # Tailscale - services.tailscale.enable = true; - services.tailscale.package = pkgs.unstable.tailscale; - services.tailscale.useRoutingFeatures = "client"; - - # Allow for dynamic hosts file override (by root) - environment.etc.hosts.mode = "0644"; - - networking.firewall.allowedTCPPorts = [ - 22000 # Syncthing TCP - ]; - - networking.firewall.allowedUDPPorts = [ - 22000 # Syncthing QUIC - 21027 # Syncthing discovery broadcasts on IPv4 and multicasts on IPv6 - ]; - - # BBR -> Better performance over weak/jittery links - boot.kernel.sysctl = { - "net.core.default_qdisc" = "fq"; - "net.ipv4.tcp_congestion_control" = "bbr"; - }; - - networking.networkmanager = { - enable = true; - }; - users.users.farlion.extraGroups = ["networkmanager"]; - - # IPv6 - # TODO: Temporarily enabled to allow buggy Hoppscotch to work - #networking.enableIPv6 = false; - #boot.kernelParams = ["ipv6.disable=1"]; - - # Disabling DHCPCD in favor of NetworkManager - networking.dhcpcd.enable = false; - - # Captive Browser - programs.captive-browser = lib.mkIf isLaptop { - enable = true; - bindInterface = false; - }; - - # Only wait for a single interface to come up - systemd.network.wait-online.anyInterface = true; -} diff --git a/system/nix-ld/default.nix b/system/nix-ld/default.nix deleted file mode 100644 index 7720e1b3..00000000 --- a/system/nix-ld/default.nix +++ /dev/null @@ -1,3 +0,0 @@ -{...}: { - programs.nix-ld.enable = true; -} diff --git a/system/nvidia/default.nix b/system/nvidia/default.nix deleted file mode 100644 index 17d61608..00000000 --- a/system/nvidia/default.nix +++ /dev/null @@ -1,50 +0,0 @@ -# See: https://nixos.wiki/wiki/Nvidia -{pkgs, ...}: { - boot.blacklistedKernelModules = ["nouveau"]; - environment.systemPackages = [ - pkgs.nvtopPackages.full # nvtop - pkgs.mesa-demos - pkgs.vulkan-tools - pkgs.libva-utils - pkgs.nvidia-vaapi-driver # VA-API implementation using NVIDIA's NVDEC - ]; - - # Enable VAAPI for NVIDIA - environment.sessionVariables = { - LIBVA_DRIVER_NAME = "nvidia"; - NVD_BACKEND = "direct"; # Use direct backend for better performance - }; - - services.xserver.videoDrivers = ["nvidia"]; - hardware.graphics = { - enable = true; - }; - - hardware.nvidia = { - # Modesetting is required. - modesetting.enable = true; - - # Nvidia power management. Experimental, and can cause sleep/suspend to fail. - # Enable this if you have graphical corruption issues or application crashes after waking - # up from sleep. This fixes it by saving the entire VRAM memory to /tmp/ instead - # of just the bare essentials. - powerManagement.enable = false; - - # Fine-grained power management. Turns off GPU when not in use. - # Experimental and only works on modern Nvidia GPUs (Turing or newer). - powerManagement.finegrained = true; - - # Use the NVidia open source kernel module (not to be confused with the - # independent third-party "nouveau" open source driver). - # Support is limited to the Turing and later architectures. Full list of - # supported GPUs is at: - # https://github.com/NVIDIA/open-gpu-kernel-modules#compatible-gpus - # Only available from driver 515.43.04+ - # Currently alpha-quality/buggy, so false is currently the recommended setting. - open = false; - - # Enable the Nvidia settings menu, - # accessible via `nvidia-settings`. - nvidiaSettings = true; - }; -} diff --git a/system/performance/default.nix b/system/performance/default.nix deleted file mode 100644 index 74a79b54..00000000 --- a/system/performance/default.nix +++ /dev/null @@ -1,6 +0,0 @@ -{...}: { - documentation.man = { - enable = true; - generateCaches = false; # Used for apropos and the -k option of man, but significantly slows down builds - }; -} diff --git a/system/power/default.nix b/system/power/default.nix deleted file mode 100644 index 28d972fb..00000000 --- a/system/power/default.nix +++ /dev/null @@ -1,52 +0,0 @@ -{ - config, - lib, - pkgs, - ... -}: let - isFlexbox = config.networking.hostName == "flexbox"; -in { - # This will save you money and possibly your life! - services.thermald.enable = true; - - services.logind = { - settings = { - Login = { - HandleLidSwitch = "suspend-then-hibernate"; - HandleLidSwitchDocked = "lock"; - HandleLidSwitchExternalPower = "lock"; - }; - }; - }; - systemd.sleep.extraConfig = '' - HibernateDelaySec=1h - ''; - - environment.systemPackages = - [] - ++ lib.lists.optional isFlexbox pkgs.libsmbios; # Dell-specific power management - - services.auto-cpufreq = { - enable = true; - settings = {}; - }; - - security.sudo.extraRules = [ - { - users = ["farlion"]; - commands = [ - { - command = "${pkgs.auto-cpufreq}/bin/auto-cpufreq --force *"; - options = ["NOPASSWD" "SETENV"]; - } - { - command = "/run/current-system/sw/bin/auto-cpufreq --force *"; - options = ["NOPASSWD" "SETENV"]; - } - ]; - } - ]; - - # Dbus Service provding historical battery stats, access to external device batteries... etc. - services.upower.enable = true; -} diff --git a/system/printing/default.nix b/system/printing/default.nix deleted file mode 100644 index 47585ce3..00000000 --- a/system/printing/default.nix +++ /dev/null @@ -1,16 +0,0 @@ -{pkgs, ...}: { - services.printing = { - enable = true; - drivers = [ - pkgs.gutenprint - pkgs.hplip - ]; - listenAddresses = ["127.0.0.1:631"]; - }; - - services.avahi = { - enable = true; - nssmdns4 = true; - openFirewall = true; - }; -} diff --git a/system/scripts/nh-eval-profile.nix b/system/scripts/nh-eval-profile.nix deleted file mode 100644 index ada7d594..00000000 --- a/system/scripts/nh-eval-profile.nix +++ /dev/null @@ -1,68 +0,0 @@ -{pkgs}: -pkgs.writeShellApplication { - name = "nh-eval-profile"; - runtimeInputs = with pkgs; [ - perf - flamegraph - gnugrep - coreutils - gawk - findutils - util-linux - git - which - gzip - ]; - text = '' - set -euo pipefail - - if [ $# -lt 1 ]; then - echo "Usage: nh-eval-profile [extra nh args]" >&2 - exit 1 - fi - - host="$1" - shift || true - - outdir="result-profile" - mkdir -p "$outdir" - - # nh os switch syntax: nh os switch [FLAGS] [INSTALLABLE] [-- EXTRA_ARGS] - # We use --dry (-n) to avoid building/activating, only evaluate - cmd=(nh os switch --dry ".#nixosConfigurations.$host") - - if [ "$#" -gt 0 ]; then - cmd+=(--) - cmd+=("$@") - fi - - perfdata="$outdir/perf.data" - echo "Profiling evaluation with perf..." - echo "Running: ''${cmd[*]}" - sleep 1 - if ! perf record -F 997 -g -o "$perfdata" -- "''${cmd[@]}"; then - echo "perf record failed; you may need to run: sudo sysctl kernel.perf_event_paranoid=1" >&2 - exit 1 - fi - sleep 1 - - echo "Generating folded stacks..." - folded="$outdir/stacks.folded" - if ! perf script -i "$perfdata" 2>/dev/null | stackcollapse-perf.pl > "$folded"; then - echo "Failed to collapse stacks." >&2 - exit 1 - fi - - echo "Rendering flamegraph SVG..." - svg="$outdir/nh-eval-flamegraph.svg" - if ! flamegraph.pl --countname=samples --title "nh os switch eval flamegraph ($host)" "$folded" > "$svg"; then - echo "Failed to render flamegraph." >&2 - exit 1 - fi - - echo "" - echo "Flamegraph written to: $svg" - echo "Perf data: $perfdata" - echo "You can open the SVG in your browser to inspect hotspots." - ''; -} diff --git a/system/scrutiny/default.nix b/system/scrutiny/default.nix deleted file mode 100644 index f0b4861b..00000000 --- a/system/scrutiny/default.nix +++ /dev/null @@ -1,26 +0,0 @@ -{ - lib, - isImpermanent, - ... -}: { - environment.persistence."/persist/system" = lib.mkIf isImpermanent { - directories = [ - { - directory = "/var/lib/private"; - mode = "0700"; - } - "/var/lib/private/scrutiny" - ]; - }; - - services.scrutiny = { - enable = true; - settings.web.listen.port = 8081; - }; - - systemd.services.scrutiny.enableStrictShellChecks = false; - - systemd.tmpfiles.rules = [ - "d /var/lib/private 0700 root root -" - ]; -} diff --git a/system/security/default.nix b/system/security/default.nix deleted file mode 100644 index ff52d823..00000000 --- a/system/security/default.nix +++ /dev/null @@ -1,65 +0,0 @@ -{ - config, - lib, - isImpermanent, - pkgs, - ... -}: { - environment.persistence."/persist/system" = lib.mkIf isImpermanent { - directories = [ - "/var/lib/boltd" # Boltd state - "/run/sudo" # Sudo timestamp (to not show the lecture message) - ]; - }; - home-manager.users.farlion.home.persistence."/persist" = lib.mkIf config.home-manager.extraSpecialArgs.isImpermanent { - directories = [ - ".local/share/keyrings" # Gnome Keyrings - ".gnupg" # PGP keys - ]; - }; - - # Thunderbolt security daemon - services.hardware.bolt.enable = true; - - services.gnome.gnome-keyring.enable = true; - environment.systemPackages = with pkgs; [ - libsecret # Already in home packages but ensuring it's available system-wide - ]; - - programs.gnupg.agent = { - enable = true; - enableSSHSupport = false; # Let GNOME Keyring handle SSH agent - pinentryPackage = pkgs.pinentry-gnome3; - }; - - programs.seahorse.enable = true; - - # Writes to /etc/sudoers - security.sudo.extraConfig = '' - Defaults:root,%wheel timestamp_timeout=30 - ''; - users.users.farlion.extraGroups = ["wheel"]; - - # Yubikeys - services.pcscd.enable = true; # Smartcard services for Yubikeys - # Sudo via U2F (Yubikey) - security.pam = { - u2f = { - enable = true; - control = "sufficient"; - settings = { - origin = "pam://farlion-realm"; # Overridde host-dependent realm to share yubikey - appid = "pam://farlion-realm"; # keep equal to origin for compatibility - cue = false; # CLI message to show touch is needed, not needed since using system-wide notification - }; - }; - services = { - login.u2fAuth = false; - ly.u2fAuth = false; - sudo.u2fAuth = true; - swaylock.u2fAuth = true; - }; - }; - # Enable system-wide Yubikey Support - services.udev.packages = [pkgs.yubikey-personalization]; -} diff --git a/system/smb/default.nix b/system/smb/default.nix deleted file mode 100644 index 0468f0cd..00000000 --- a/system/smb/default.nix +++ /dev/null @@ -1,4 +0,0 @@ -{pkgs, ...}: { - boot.supportedFilesystems = ["cifs"]; - environment.systemPackages = [pkgs.cifs-utils]; -} diff --git a/system/stylix/default.nix b/system/stylix/default.nix deleted file mode 100644 index bd795114..00000000 --- a/system/stylix/default.nix +++ /dev/null @@ -1,37 +0,0 @@ -{pkgs, ...}: { - stylix = { - enable = true; - base16Scheme = "${pkgs.base16-schemes}/share/themes/gruvbox-dark-medium.yaml"; - cursor = { - name = "Bibata-Modern-Ice"; - package = pkgs.bibata-cursors; - size = 24; - }; - fonts = { - emoji = { - package = pkgs.noto-fonts-color-emoji; - name = "Noto Color Emoji"; - }; - monospace = { - package = pkgs.fira-code; - name = "Fira Code"; - }; - serif = { - package = pkgs.dejavu_fonts; - name = "DejaVu Serif"; - }; - sansSerif = { - package = pkgs.dejavu_fonts; - name = "DejaVu Sans"; - }; - sizes = { - applications = 9; - desktop = 9; - terminal = 8; - popups = 9; - }; - }; - image = ./gruvbox-dark-rainbow.png; - polarity = "dark"; - }; -} diff --git a/system/stylix/gruvbox-dark-rainbow.png b/system/stylix/gruvbox-dark-rainbow.png deleted file mode 100644 index b15ba5a97602c2e04138e96f0e48be21ff39e5d6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 185977 zcmeEvcT`l@8t3Xg zprBL%8KlgBBH&O(dVhP*=$vhC&L6yG)-(5owXX5H_St8jul&B>SI*(OvZCC&@3wzO zAQ09aKXycgKwt-d{l4?t<={V}qnDn5|NQIxF)dpH;fOT+-!d_wo@gV z*g2lHF(x=VI`W!XTi6<&J#WlQv@s1GlGqLwZGwvq+1s5X+7MLFo;BXF+s4?)$jolf zj%O9Noz;z30JNT#j z;K`q`#PxXc$J-xoJ)ZoRx*kvdzd_&l?;pI|;%$Sc#ig#t(<0vfcWrGIPN5#;+~$`cmGGCw@Hh z`8KkmmhD?;k>7sEWq-T;Uo_+V;~#jZ!;>!FdOTxY>UzAV!P_5iJ)X4iuxqL7*WiI2 zPNK0?c`kK5o_zjS<&P(RJpJOW$5Gdpq7q*UjQ%d_{eR_-e{=PIZQhQDhF_a{zmT`% ziT_J^FW&x31?Q!%$5R&`n&7R+GY35JFLgbh_u}o3xBee6r_sAFrQWa29R4Qi{ZihJ zC;tCc^?o65#}ofQU{25dmI}^GU5^LOUr4?GFmt*Z@z4QJT}xfRRCO(N{Xby-KOL*T zkU8LixtG}zhurYY|9>@@{^jmvH_-meT42JZJ3RYc-B$jaj!J*{6Hk43iOf>h<7p3X zf4ud0*6~+^Dc=4|^`51!|BI~yPyAn-dcQVv_=h^t@B`0$ma49$uE+DnrJ@6#H{$J& zw;sEc04rv+SL1{yd6*cc;=nc0BRpnGfE2Ja1g;dOUUE?T@z}PhCr0k7o{l6ZL*=-i{~!uT8yp=Cf3D zzyas4t!MDHc{`r?@yrKrJ)XLjx_9ArtPoI`SH~Cm8thjVLP7q@yrKrJ)Uzebv>SQ;_Z*O9#36MU5{rDf3f#2RlT@n zi~m*m)Y!Y!^?$K?zcz2j6aUwyUOe;pN4+#u!c*6m@^(D&iWNl*M6xOjVJ!EO}$^6IsAV{!M>C^;CbWMrd~V_fQJq^=75(F zeJSt7+kdI*TIzZ{b>X22-g-Q9z!U#c*W;-RZ-2b?IO_dU6zofx1D^Q5HuZjO=I}RB z@0ap+Jn{d=g!2XOrMk;f*Z)oA|BrjobE^MQ^?oV$`ci0%7wqud7jHeDx|X^gFF4}u zkGK9W_I5n+e{Jf;Lz92hOG6nvb^XJY=pejQ?_KKp|3}{YrPPaOK6vPW=Z!Linpb%% zXusIx&;sewnH_)rJ5H7;ExglxeNVr%Up=!_>{{x2yioI{j2mzNC93yJ<%M|0if2A} z>+y`+V8cJJ>OnMJsyvsv9#8&D)fb+-;O&pM9?xBtx_+tdvefl|F;o27&=ybpUz>XI z%x9_U{pQ6JitdBs7h>I67g!qwtQytr!>Pf)Jihew*}s2z^>41?f3@u0aP9kxHTebb zXSJT=q_u^+7JQ=^eEI8!4-2msnTeUDT%do)8b(hE)x0e%E zm8wba3v)bQ)f->2FKxZ~;4Skq?+-6{rPCh0`7KR4G1p0KC7n{iKaGATV80zKokzSx z{h(lPQS87sgsW}UYOMLjZUYx*Tln=#20X6Z5KiMwe^j!s%c6Oc4ryY2Uyf?|WQzDB z({Ry+xy*vq;~BR3>5?V3%EY{c`5}e%LuEm^($2>Hk;RV^$9*kASC8w2RxG@~a%r|I zw0vRVPW|E8$5zqO9rYp!D>6A3=iYL*vGBe_+L>=lk;Ad5h>EOvCRW0|yi>aRMBHIh zA5Ff5^HT4R@!LpL%Ak&MtaLq$4@cehTDJw2nX1%i z)%i`O^%>TQB^+CC>p3V2GY*g-xdLkyOT-VX?^&J^uI{^9S-+|$He&F>?}_cMeN-~R z?@qepL(v_%>Ee#QDOzfn5eb@Lzsb)_FtJr9YnAQ7X;+_~E|twP?vnl0);*&^4RsC& z{emNwi+lh!D6HI@u5_ja`@MkX)rh8vyyBM%y;5>-4-)z;Y8f3?2z z+fd(?AI}Pr zTY4Gy#l3pdrCa!gT9_Cz=qpDqZ`=^EyX}&+XNuCMR4SowpsG2GKceJz@dYaZFV3Dv zm#NJK+b=mUv}RgMFg8foh6u4;WBiKoGA*5CJ;Hdl!v*`vp>}ZolU!Stv2NoiiV}Q~ zo6bQb?hRJNY{_aX_S+2&wB+?!!lw=0Q_t}#?D3j$>AD;S1yGW2W|ssc*v@-eo&7G` zyU}JAKH#XIezMOZY6wyzzt)x^*;ZPEBRGl8pPxMkl^{^Z%GCLwPwC09zO+zhZu)$t zFEF!DI}jpQAtwDmDsc9S6-|+?YAcoXT}i&CQl5L}-Q*0X=QfqT&Kx}`&0ALA9PtW% zM~VJ(C2Se?OACM6Nl|sUa$%Vkai93ImzthCf$!5anM)k_=KS5gA&SzEtn5zL>Nnqe zwdT_fgexJ)7HMhTuXSZeZ?+oDFBJIMTE zM1IB&TQyc;h26W?$MT{C3xQ)A)rYJHj_GX7Gdit64Q&=$;Z#lHO&g*}8uh04-fP0B z|CQUw5hm2S%8I>GbX54fX2d+s+V>6}g_6v+@FuW_^658j&u?o^cM#I3QDbPc^u+|XZ`5nXC( zl3n)h=yz^%B8&?P1Q%yo9fVIHYHGj2NiA-6q*-{HZ5wGQlugvpcpF0sYd0VkX?aZD zs>eS&_gr{L5^$=vJw?!<^oJ}{LK2rdy$yHOa7?JvFL5WoI>Ojs|Br|?&fdGUl!3#x3fl6y#00|aNYa)v^YSl{GTb==2%pZ!;BQTX6c~V?c z)7oA<)GnA|a%wYn^S#K;Q?A>|x%c{yk4M>`h#~a#U-ln1f$lKBFM5<~h10P%MQYQ) z-1v1K9qb6D{D>W}R4NuR|2BRxgGI*u36TRXw@9H=V=kGiWRI+K&h!v;5RPfJZPoQ7BN2 ztreNpxb0ZU$XRu63_Y5&>s})sNWd% zOkJi57i_Q9*J+->^camY(q@gKOXZ%i?y{rRFg`M;aWhq$08x_jEZ+WlSzSg^%EP#7 zu)pJvn8tbvc@PkvE@#-kTSy-(&LA^^_;hxaTFd0kDxGCoii-+-;_;XcKfBJ!TyQ~V zwxmHF!l|GBU60Jfb2q^O!d9IUI!1l~+&qo0re*q!)U6PQ|BQ9iT}1ss?Fb;An{A3XOWR zQ-Ly{W@PUGM*yJ(9znYJLW=YTWtKYes;jz8xqMdU7E!-1U)bXl;SDY6(4 z3t?e@sLMf-RA%KhJf=zd1Ls7{CFg{~USJ`fT@bORGa;37l0ccs=hFN($+%ldB|dYT zRhg-usDIkH$6(66Gb6``#Mw7&y)8@_b8Lz2s6Y5ksnxse1O^pWM za2uS1)*;bzXMFcecWrr6FgIftrz5CU?rdoGAsKQk21=cFm|6C+rA;UYMhU6;Uo}c! zv^rEi;vq#3k%O|ZNGbOOL1;eSf~yvbn)yF%UiPxN!I{dHD-6|{CX)8;*8i-DZ$U}fo6&~g81Q4#pT*7N6WS}C#YFibImqpeR1_=_@7wns@E0W7zkg|&y zV(9z<^$S(*^|Qd92BVzal0dYm@~0(JG)K_;ZYz64K@!!*{`4OKPU2g{CaRCjoT(T4 zH&AFYNJg?vj;Xnjr^CGVUY(5%3U9=Is}uXLh$WgNk8tKL@`MFc0;YArCz&3jU{-#6 zmwIVw=)Gf}ImXpBefu4Nk8WgE$3!@fQZ7Kf?SHKBjAhz1=mFwn>nM$RgHvzY|33Ue z`6G*_v%_7QIT*gr8Y6MKS&htDw8*2YGY%eIwvoCz*B82jDzr{QC@#{$eI-inPKtcFcV$)5clx;^-cQ|D9#t!!uq})uMqY-If2>H zB6RT2A!&P9c1fX8jPh%V5HZxA8GTJ36?b2=MW5jF*#jLPobczFUs7J+p zY}q6F)Hd1CDO#9H`530=E#(Yb3ODU{DxQytThp{*P_B(d!HvKWrX7r1JFmy;GVjYX1T=x|^{4?{1>wn`9-egF|FdB~fgUzr|7d@(&F<$7jO&fW z5yD!oR{I)wKwwn%ZgA6Vdn>+CaB#j{KgDs?(lfJ90{2ZOM7P5Xl#G=VY*;bgZovJf z%h=T#Jbk=o*Rq$bY)a-dE1JJC;w5Td-}j+3#qcHTSc*UaL-I0L5dUdc8SinM)69=P z7ydoqtM;S=-3yXhM16T!I5YA1?k*>=ic2izXQFyyJ|=XZp2RB!(ZT7E2F=xmi<&OF zE&qxnQC!VvsZ%O*_KKco12Y$d6GR6-!!z_+r$a4l_W-EQK~SYfCmRZ_sG_K^v5M7R zA+FIscXqi2ZvoNa?Y+&$pAJCy4K2&W$CwZA@LiPW*rOc)0L`|p4+_G4wAG~a)MU?^ zwlpPM3ek!^6szj+qrkrN4V$s)iwV!zeppu#B>R`-Inxs1kd3a(2PaL7{*D-r}%V;VAR2Uf9eR^l&6U)CSXB8Dl^cQsapc%?qR%3)3ul*ULg++H)< zxheUMN;DT>7H0vKS}#t^d=5|B(FC7H8T&s#n#?|AqtiE&h<8#CQ5FL!Dh|sNvO!S{ z7WiB$${k8KOkB(?us*rsRYlr4EW&3aw%FNiZ2BHp;wbdPePKZ!Hm>jxW{crB1^g42 z``rx`XyS96X)u>5aI(i7;-w{miUKOx#H}DK`EN;m4vJ%Y`U`@AF?JN@Y&-wN?cIkQ zp2pG%0BPe~7^==7LFt9R6S0N;&b+=Et;qS@V~%>K9^U@W{t7MBVbIX>d+}o)69(_v=0whm!8d@e|aG&_WrwZX1hPX`hAwU+dCkFBH7Uk zFc+t#&f>6|LC>1J%8csmW)`g0!Ck^7IX_EA@3Ujr(D_Ks-9iK?1lBsu2b+5BX(big z6-lD5Zz+Bs5?7)Lk;F(JRK0EDNzAVyleRs;9@l#T1jM#nA^(%#NN9i}IW^><-F(wYSUP5S^jb1< zg!y9}d)ms17kR8wT>#NJ@?=<7`p)!RtX)}`%QFAR-4&aMjva1=9>Tc(urT6Hq$JHt zK$RA`7r8q(h?#iIw5;z?TIV=f<7avL6!J7^d8JitD76`6A*76rGO0yI zhlOEfV?HQnIs1J_{RRi|q(h&RwXIi>Q&99A`T*mxI$;d3&66L5!}?Ff6&YmV7{?bk`>0}34NK7CY zvxZ*~YcLRdqbi%627=|jL}r;(_qMx<8N~ipz0$Jt0rhT8X+hRVZ)OD=BPYxY%RyiU zj2Seb64Ep8XwFU=fkfEdQO6L}R3s9D6Q|;JhpX_4o(d0$$nd0YE&k<1a(8ZI^NG1ULmH%Gn%p)y)D_fUTmy znjD9=i=I8Z`8|mDr^$J3jw<5=r325(n`9aGuwNO868FL@-JJ&(<%jpSZ3JN|vu=PE zrlvkPl&+Y18@Nw6YWw6L0PYaNnL%A4JSwaX(v|L~9cP1-;t;mz| zrtV*~grh=oN3%v4M=+26ai?d3ZGZ8Fb1=qZPS*d z*8|+rN}bP3d-mlV_Jpg_p_cBPAC3Wx4Uuiq zEyx7sSnR1|_*(5de%pbIWBt0m)f^>RjQMq>H6* zH0mh}%H{W*XmHQu>`mLtpzU6wsACQqbM=nso9Wk|VFm>DV+W&mIHBWdLXhPT6bf=eCn?t2j59i$mu5`@g=qP%9zPLK*;dzIV5nq)H!s_i>gh%5Fx4}#X%I}Fz^{jp{ZOO2NG zAsnDY)%qX`_Ad6Epep6uI5~02Mdx6c$N9E%JxaPC`>c#dSo;ilgxnaK76(BaCwt<4 zRa-FA&+_6*EKKHu_PvgUw$#3j-i!+k&Le1W*L%vTrPdiKc6Of_uL|?MxB5UVo#b2$ z(JqL|cXb@{KQl82dd;7H3|=7Hyt-Ri4X6fl5E?s<$sHm)}-~O_4&RJn{ zV4JA%afEGjBBv*Ei;Ma%%FlZD1VhRLszbT3I^?&fKY>d}E;SnTStW?n>|RFNVoT~haR15MVb=j~oC$CV_BWJ|C`#J=vg+-T8J|?cU};OLT$>!TQv9d$6ATOx z?(5{xQsV}SD%_x`(hAy+)owdg^FK`OOt@(p(K4PC+ore;OTkt-BVZ_dv-nJw4Lhjj z=w$WCf#ZW-@MN8kP586h3qSY2dVAzM^RuvnrPy(>o5DfaPl~|cWR*Lz(LQxPfCpx# zpp8VLJbV~7tsHl-z(XS8@}yqhrMPzS{o*#1%AJhkZ=FM&h*qYw1&1isI;a^7@(+3m zfwMRD1hoRB-f^n?--6oXP)ES5;T@^-S_oaagKWcl%ozG&6)dJqR0~uHL{#0TIGyF% zYU3&_EZ|w*0Gp9~378sw*p4v1b)S4uLLd;J0TBFXs-Y;Ki9D#2-OGsi?h2`fYf{3H z>I|BTpB}^OHL`=j$r$kuF#XWanFXGegS;KM2+GxQpmUyNOX-hjIIt1w>6yOl3iD|o*tqiMPeK0mY zoU-mpWqibo%DH;^SyPt&pg=4ty+!cLZQ%Tm+z4um@SBtgQ~2}A%wYIF@&f%;|+s7dz-gfxWmS*|WK$l&nIe`-=>GYm^H zajJ~Vl`kQe>uEahcPs|h$^)j@6md=Z(b>JdyH1)dS{lx0@Nace(&`vL6B`!qi$#R& ztzK6=jeB`tCFeIRGL`t$NYfPF`E@8*>Gd$!Yzp%E|j#C+*tK;1cwUB8zJ)3vj6Hu$Okz)32F zCFJoyjuHR7n=9w&;lPE7J2xL=69LK*$a93Nf_m6uV48v~A=_axFtwUXFxJAK=c3kt zE_1Gc^eJj-^^09RST{6M5n(9R{!{WTl@Jrki;Sas;Zfz2=`2*AMVTH{QvzA6~o8`iSMB$lYxQ9UOTd(}bM zPgfZ;$8i?Smkhoism}--1&mv!{!AF8DCQEyjuq!?+d_a39`p+dx~SC?w{gZ#)#YhE zR;^ZUMr2TXoMsCBRlu2Zx_{(Jt}JrYZ~vD`!1ISwq%Cb@l|{pr+rovnFf8FE3Twg| zWQgeYuxoLYbHduPr|`j^!BBSXf|Ru;zM3ihVhU!B|C(o997#bW$hwibPzY+H{+k95 z5$qjmPjxQ@r^pG#&RU;am06awlImEnU5hpRtrDX|ix%VRQf8p!gw^IjFewWHPTYFi zTBP_}lV6l9-#f;%w+TyTIcQ-u{B>)lc#J*&DYRitUEeCXT7!cN zZ{luN`zz0M`;})n?_pg34DACSda}BT#*9|T+SjL-5kdDjjU_{{BH25E7A;MOAM1!x6IqM?W`zKyaL zd%eVTG9S4ZIg$$QHAGl%-?nc3^-O>6$-1{51~h|W+kug(oYJX{r2L$kx;Tg}vmihkA=7IBIzZ<_0lNiney7&r^V!lHyD8C)hq?Bp zVVsH!9h-nRV|(e=zHRjs=6x=V+dI1(-falRY4@wbpN} zb9sd1!|-|6?EyyD>Lnqwbvfw4jO zdc+p@9;b#n10gyF4T1#4@~PU)xZlxQ@$d%y4hjCP>%y<;C=Q5krOKkrIKB>1qodk9 z497aj9stkYWEKP~Im_!P4XyO7E_^sud*^kvlI#rW&gt@k z$frxDZ^LP?nUnJqhArcDjCZwR5AYi__$bku}Mk z7u@>1HF}tLN{UI^Ro=q-<|2;}C7f4L`{;{p-~?t0$uJ`Exyn0&`H=-rUa@?M{QVOowNvIpuGjV}Qbn zUVr-ER2G^NnNy(>K}ebgA!#y) zie{xNcy|e;?+rO7-6C{v`uH(V!|m*!j^3$^4n;B4Cn;+|D`&sjv9O?Fm|mG5VGW)4 z;$q(*vps*wYDjFKBEcCqXmWITGE|d1`?@g)qa;0MB;;(`Zh3rJJgO$Lj!f))YWD$o$Sennu zj>um`O5N34qZW{o0yuu*@FuG7HCc<#Lmo8EH#-+BJSrCW?X&4|k$Z^x-(O4$f>3G( zDxcZHdM}>4jj87UtiB;HWb2a>EB4wsLJX1k8J}fEXLV0+1+4%YrO1@E0A(JX{ox*V zrkuTGB`O#hVP`oKuIJ{^yzCf@(rye1%TO20joS(HbA=|RNK#HjLzUZ%YOA|8--pbf zlV--(&kk1>L3;a1e*`&n=3v!LsZ%*HKOfqoU9}USX!Hip3ysHW`y(2Zas{_2#XYN* z<0YCdkYn8ie6x|M>CR(l7ht9OO~^|dk^nE&eGnzGKVW=S!q}ZP;x_|q{kSJ*n|Nl2 zv^y|T>xT}R7G^Uv7zZ`@MN%F-~hBgrbmbl{Ms~-H?;&<)sBo zZ%wdk>f708{n%-yK8!>OboF%XfA(qzLx^`bBNp&re{4Fa^FVHYd+<4|c{&@8kj1aq zQdR^mOiw^6oIP=6R9q^{j(R|rvB!Q_lvTyie9+DmY7y|6I=6qTK@y&j4kkUAhHK|H zDnLA8Tx_x#@qx8Fr8GWiQBL-|ND_PD!{AZwgt00%U*l1gmoJ&q&5Re^L1wp(E%yPk z2@A4Gih??=#sYc011ZC%!;aJz*&t4GjPeso;dVPiRqw|dy`=+a!C5$v2BM%fm<2d# z_N0Dmtuu>St8k-;yVqM5C^&TXHXOKq!OwR=3@zR8+{{EN2%EkMiG z=&bmv4IJEUkkL$TuGtLgjUgr?6n5Khp@E9)(1)ID9ZK_1SYoBWWyU%9u^0Tnj~Zq zUCs?=@b|VQnMRG07Utm=4aMMr5j11erv#$_ANK$*wWIp04{1_7&rXX<9|VnS;h1 zx+%n9Z}+qxJ=W8qF!P#JesKf~=GFFyA&YRTyN&{8 zucr&M3qxi#ra_>{UED>Jw;ZZhHpY*;?KP`9jz#iFcI5o;Tj`t>^pC)RFf6j$+fe=; zIB}9GEHA~o#j5_u%=4Vr)g`ybOhbVZFBWvc^fFnqq$yp6N@#X261&y+d z%KTa4x$=Ptzws-rfv&TrS88>Trm#IaGf$>fjH!L#4Hi;Pczczbrdq4he>P+`(aBM; z=ML(npls~+A*dA@f!Q&d8|d%R83iL`_1C0ZL~f0yC5#R3D+@3@Anrb&Z_=YLH#1mU zUazXo(1x-!BE?7fbVUXh0cKAAV6%9F)F0L0Q#VvTVB0lvS&6f#6B(vdRzNP@>N_P< z4?7R}CFjy^YywST%fsTm_NS=1;w(J9ng>EptbNlV#ALdl8$-0(7S4)|g_@%QDL&qY zRwuE5lp+U&;+oo{wJgyMtNAP{EI-`JERgcH8@zx;17#v|1}Ak|)nAMUGD04bR;W5@ zFk+i_ZeiAQ-kR`Y8!Idy`0P!#z5aGYkjsGz;jtEWP%I8G97)|*Cd%h4PfO@cF8k|I zYUgy0`71Jo6+XfOfsFxDD`ul>FCS)R!V$0P+=y!V(@#8D&HC>I&6?UQeh&(_$SYXE zsO=a%>8;d&tvAg|(j38j2oP`4VPE-<7JdohUcbotYbB4K*D2>sHd>YWaACFH-%v(( zCfFMS0Tq&ou;Q$C;l^jq_G&IIqGS=9oUn$`f5lkEBd-~xARuUP@Qozh34e*o<5ma4 zbLBJZEfnLPx7O^sJH5y6*OgsVIY(^+kfM**a9*lsSkDe|MEoM6^z2$sANpWy0F}Az zOoDF{13Y ztIZ)#n>Y(>J)NnBEUgSEl*vK7_`#2{#2z?O9CMBdq}C7X$NY1B-xkVn&$qDjejIn|z^q4ucUy4m(U8HE4NRKg`P*z`_f=_l2D(c}00P7Z&SEL`W_2?46$40hN-FNf1-=!Tmv1GQg@#lz2-X zBoW?+;c$w8=UKCk6J0lAjT!n!g|Ohrx32&`KyNI+mv*RBYS8H3L^}hMbMuw_>wPot z1kT3UdY+}S^7y%omoKm2M9nf+Z$8^4C_yG(>c~Wc5A#<}oN#m86bk zTKPWRh|!_WMPxF?Yo9u;KvE9fuwU~IDDY6Y0*6HMI99iT+8(6jLSQ)LdxIP>NbP5RQB}rqsxi@aCVTT+EkW93Djx_!{nUFGTsd%L##DPonLUVR=xM{kE)+A74 z*A|V{7N_PX3-%`QOiJ0yVo=uUk2IZ1M-p2>g$aZqiW(gH14mvUy}p+#AFHI_;(h70 zfM$+FT==;yO$-Y}aEQRiO;=z%P+&pVTaO-}*anb(I=PV2_cB$#UAWP}(~LFy2;peg zcklHvUmz~}jMz2EC5{e|UsXFlRGSIaIl3x(pQSMs9!HuqrKdmDMZkbj6sU`|f;6nR zP=|ZouI+u)^-W5YThGTv2YsvcmGT#_m@qaeRYg3(YdoCrxc}vcwIOW?A0h*x zjPB)RxmdQ^FFcSp0`Ui7hzZk-;Mf z;XTN$_n!EaSO>sjbI5GZc+I__6R{-)_C}W9d%gsPCil_vJ;Yt}jaHn7(TE#TQ9IrT zUgrS)cUo;Ee%~Iz;%z7bfezuVKGHqLy>^nf?YfcId^#f$953C`0Ny>M4Wd+$-asW5 z@D05!GzCi3F&r`SuE>S7KvA4pSyZRnghgYKYe-u5fR~P?>0sEf6)4?ju-q!po>=@~ zqyKOhOKWh6|JeJX`y01lDG6aU>ckXnI0=E0A)&dVF53g%2MJ8}nUc1Wj_uWoX=@(Cw79 zk{e`d+^HcZwcuiDvJl8C-*}!Dx#{873)HxCo(h5^-DKp965F`TXJ}ZZhtgkJ?Zq z0)PBtYvQ~JGHucsOrP~|hs4Flj~76txGVSZ{GL}k8ItYXkGcnFYX;Fu9|b<7BLu-o zDvyq{b-4U3$WgFMuAwqnM+5RN!mbk<-CAk2ha`M-ECr?vKtuJ>__tw1MY?(P^E;Eb>1{l->+&N z50?!5(f#cQ2gW6(DahQ4SHB9a9uW%*yF76X>5d2c@}0Sl!_=vA8cUr%zlhN!1~px+ z7;wO+ruO|}zzkeQz-!x|e!R4hrY^xWhMw&xz`mx?foq;^5@$-F6mo@_l>D%yy}AJf zg_BJ+AXjNsJ*ae29fZiP5!rbYrCrBCo&oAPStqY==+sBGtwqqKx*$|pr zjt^pPwn)}XNK2y8C2>f(>C+&FX+&@~kNnh!PCF49Tt{TE)fc=PK+87c&#`UZ14c4P z+sJuRK-#U&<`};-SdWqeYGQlnB&fG$fY<6%L8XJknk~2h8g@yMvC;nRpHxKHUx6ew zoq@)}a3oQwUSc2YSCu9G><2w{ef3)1!VIk8e%JPMfy0h1P2i>nK@fc-n3^X7PB#Op zw2b?dvZBOwkd7gT!CRdcT)au_6v+x9pjA-EU@eHmqTJnRUE zpg4@#=}Q|#*1QU|p&h>@4w=-Gz7>wcTf?p3jXd+Mj4Tf#7uh2hQFI;P0OAl&h+I4< zq>yvsq}!l_2eGMQpKy8Ugj_+2u~C9h3SXPFpX~IlX~~3mRUMehP^VWb8h;d$^dKaH z0eBPGzoR8*rcZl-(C+IVuHZ|-AlqCTAp{DX?wqh)PzFc2YTP>;CM@p)C@q?4$4HRO zPl$m&$fJ#o&+*U|8k5gzff-oq zG-43<%p8#bZyF6nbdAAy77Is=XOa8VF^F&rMqSUap)wf{j)?UP-kSwS|$g*&F}PPvj!vw zszGZ0CxzGdLP^u>)0l;}plRIi$MpGVeR}ZL%q3vdY|PnAz0j!hEL^cmf>E6Ung&M$ z@?qwy@Ka-5uJHOgc%KL&3p-ML_Nqo{roGLSgJfwblc;AKCE9_+hAlEFJl^uD6)_b`%i%N>oF!d37!8!xn*6V3$5A{2Z{yaF0fKt-U$82 z-J$@YQ3+2}M3jYFgFk@7ySYVWOd82i^V=80bFx zl*#!QC@3`3d!~}I{qPNS3s6zC0oJ!${CLN|*OOn!G_Cx#$Q$E^Fjh zBtiQgX{Qhx>DBy;a9Ypjrv{~*b&JDLaG%Wtu!5hNPSKD0!G%bRqXASmpvJ?u$y z@S1}pULGV---8J5ycMnEVx0z|1kA0>^xRw&f=NS#>>xvCUWZYZ1lrchS+th}^m4Yq z@JK7pt<`c5{4f5peg%4~qui4{;3EZ+>Cn0(@-mF4)NjQp^WPC@mL#8>PG z*b?Yl*>t#oMKrxw9*pdZ@e5(pSHul2GfoB!RqcvUOBUl&M6%A+}-@79Fml zpZIyDMMG0w@H%6*kl>x-5_^%lCe7pdvz3TZXm242Z+Ck4!IO9SVE zGpJyQj3GBx^uq$3eQHLas6f_+Rt<+9J?jPJMxC1( zDaHXPX)xm~3|>b}0Z;T<^PP~1mfKIWQz0or{4nI=XWX5Nemfy zX`%CnmdP~C?guY*r=A22Ibo(|S6~Gc+vC^^2nG{qNjTusz@Q@>lQOpkL*m<^4baEd zF`oF@WW|H~bgPB|k}RA~B-w+Tgu5R_GP5lxP!03aN~V*WQe(jwfd#!_*q1xQeSFbv z_Sw`9Or_QTK?N71HuxO2&QF0-?GSi~c#pF5TW|!0@%RQL^gf_LK`+hr?181(JBo4o zmc*B4^|Ci zD=IKzy*f8j(RQ@&z#R8+IAF&(+WuJ-*ha1u(2Jh*GDYrL^;4IC7r>@BN|g6=p@C6> zJ~)vF9a_IQPPF-|{;tp3++L#Sr)JvK>4^n>XbFI)rvE^A88DhZ5SN}!$g_N!)6-J{ zgs%X^!r*9VW?*!=5czsTDIDln0KabX@h-Wr;R{ptMn5$Qkag7;_3M5N_<{EuN2cO$ zaywbt|Fg=mIfbv^WZ?2<67!bhq_t@U;A;rI?Rn+f*WBz2A4=*Kjc8WZ)BhwTFZ~O0 z^+|AGRFp+@$L3{ftx?ldA|D6)lh;5v&#q&mDTGVt8+3bp#>QPhFN))tocJ=e_A4v2 zSJ2GKVf;m{D#mP4huW&l%sdzZuHlN4@RDa4ell4bA$}SfRMma#JvlFQ4wBF#D-rHb zf}LYa(p?Ujr$uJHbAi-fAQnqMI_E@j!UEscbBN^{SXEj8Fw)h?T9J^?rD(Ob@_q7; zVR>>}K0P-r(8Z~H>kB`d)}V1R*0abw z!Sf0@-$pK9tP+7r!Mu&LVRRhy-iG#tEK?)1T@{=)0ykQi@4K(-Adfv0rdcm`kv-i^ z-G(}iMb4uWQNLR6(Qdv|f2Gj=cs*r=cW-O&rWU_kUSqCUw+itejOAhqZ+OpFohwlr z__tYw4x8C2?)Zc|p&v}3ZR~4#b|uRFIJ4MdQ<-bC*mx7CXS3K(-Eww$D^!a;x$|4C z)5GQSNe#z*R2*5DaysTlrlNhW&YlH|9Xiv9|6>&_rBth#^;$;uNhZz^T-S76Yv&^QecOAbK z)1|_$`+nS>GgBPEqUmrjhVY0$T@37FOg)_kly3caeC7mjux|15S|gdhhcmN5Xy_1e z{qfI~_kx9~*RZ5`lI!@bA9Yo-qSsIg9PBh;)Q+XzzZBGsqX&_09X$)$tz5(`Qm$<> z1~hwNr1CxmvX=tNLCiG~AA9$U;*+bH^&MHXyODJcMz66JdDPVP(e&?BD`9t&M6MG_ zeWqthyIJckU)H-HcDFronya13D`EvqVclx%y9ERn#4JI%Z`y5ad~)GOAVL40=&n=6 z0gg2;IY1bEh0a4yuus;>@F8MM+Y7okv;&5nGOAyxFXA2}3}J1q4>SJA)d+{<+3C({ zVOjGk0^Db;yYQjvZQ}6Lr%GwmnZD#7=Sh2f8Db}3SIH3D!-R7^hM}_ZbI!>!7mnY3 zmkAUvGU))uSops7-Pt==nldQ7ASm&Vh{9tz(8M3okKV(|rMJSd} zch>)GsY4e;ZjWL8N==RzLk;kB-Nt3A$Z&ucI_Fiv+%hpZ56t3tMT|tH5as%CxO6TH z6vcub# znR~q-@6^~H-+#jkVtsAb>*`^A^9Ayfx0~@5F90ZnHl-Q@8H0 z@j76FuFZZJ>U<`OJ5kwPuAbnj8U|$r@;eteE97AS^2{?oH+>Nsbdg~~a7S{dq<%R~ z!Suj-Dksr-q&H~&@DvC{x{hF4{nL*Z1=BHsSXWWmN;{#{U4MrtH|C*6%42BkMQeH$ z?Jz=2kVNdy@0e^J{d~`5x9Gl~6Xg`=2VNgPbO-bL&m^_lo^wZf0gd&7P)gIRpo}gJ$vbTfXV>v}uvL8HK{S{GHUT#EFkFlZ= zcr{JIIhuujFM*b4eaBAasH;--)3>*h0K;&3pJ4LmH;ePpn55tA>W7E#F19gQST{oZ zYcf78UW1G_j3HisnvL4RJ4`b`3l(SHUFkCyd)^Tmo<+cE1^cN#v;EA z*P9j7=ZJJy1eW;pW|ZY>ULKE}3-88ZR6fjg1IPZdZjam0-F^@8D0AWL$>{V zwO#i-`A|(We6o&`^N?*t=4>q(>VP3&i1~uk)nlW{ zk{1rU7BY;a6#bg2g(`)KZX)ggH4GZ-4Fw>Ln$%p&7ap-ZA?>*{HBnqgprEegm9tzA zBaDrCVCT4d4S?g|RoY3+6ohQfaYtFM>5VPPb9*+H8dEi4u~ONrIV_}RuhgP^=&;4U zV2lHeA?=IP`dPE4Gy|GBEhWa@UGVdwMvWtJmwWHrO+|uwj`@Wd%Hh=Dr@i{awV9a= ziMSx63gC0!$y(9rbcYmB-D2E-#BFjeFPmHxIQC)eUbJR6kcl|2S)HY1iHWpZOx|K2 z0~lrM5YGW*s>GLOmHM?TYogsMQY!U=)2QHa{KH-W9=N_kpy-jAN&mF)#E5UIA|q?| z(nCK7nQ==6J8Ic#(0*voEujJY8IqiuSh4>q)3!_#IxPPj1>t7 zomSJQJ?Z{YXUtg;yR$N<|MxKtmMeWi?mSdK!5RYhV2xa_z-%q?m8zpqd=It@83~i` zZ%>ZW-6h9uZ+>SnXGnG{kO>zvlak^$%4gSbb+x!^gH3cA*Tow%lx#=Dl)Tk{>ak5)zpMh3kqYk*+)$2_j%r{eZ>VC$wkDDn2L2 zEa6yttQ%O#yk*ym1qB}<4tLEgQ=zcj?Ce==SpGKh)ho-r+L!nzAT5*(^xdnlr_$k- z_nTPX%@M_cV}6De;2d2OJSL=jxzT(bq!o(2MMDwf z7cL1&K&WX_k!&)tx(;WgGP?@N?!)&K|W#H{m zLSW8f-&mPk2spd6v#kXJNE1i{Ym`$eNO+YC4G3D50dFsM={aWX05tqA$LPmsu{5#=yg|yxC&D@f!jbEG;wojccs7;l6rrG3 z!ox%$oKFHNoj{~owNq04IxR|2UqheKC2mhH1;UUnGIDx+gs@pil&{!9&cY-+uYE|I zZ_TGY43JT1FL56YV>%ddsX97j>&x87&wS&EjtJ|8v7JG+#d*LHn;mq*;^H0pT{*| zLHy3K*Kl(iZIfCBt=m?G8>Jr^40#Pv3?40L1W?rM^l=Ngv%6T?;wc(5L! zSC@)j5nZMhT80;ZOk10#c^X%Uf`_T^I=Uhu>#zf#Ui-^|KEjyoWY(5_jNGpi`K+ba z$T9!!=)iW`QLK4^-$Y2J9ykyEW;*G9_Zk&i>@#f6HW3ObAg7v|F!Wpa8q@CsDPwgu z+7?2loUZWz6We}&BiFok9SJDdg2^0MYA@@}x)g!QNM<3yNiFP`-#8(^ZN%V|ynfC0 z%@n$9YviKWu#1^ndO=I0T(;#BgFYO>(eWr*FtfHjR4U^>+b12D_9J#8yd|}gPUb3@ zfoRQl!rbE$KM>0k-3$OnagCY5x;=Uh4TqdRT~A0yV%ETRYRmQ;bWE(-J{s*7G}yfT z8d>MK(!Ev?X&iL!6i+H=R;+lTL~aSWhrPi!HI4vD>h$T8bVIB1ak!nj@nLs+o_jF> zRymfQfxHB;55?U~DDzqSY@AXpg91+lVp|xTtn3${qhf%t28c5bPb%lSsm0;Nfp&{G zA(yD1jS1e@qeU%X5_HtP!`KALlG3;PPo0y}PNsVerEr_>`{x02vkm}?^mT;_8w)qd z*q^*nVM?^Du{=p5Gj%jIyL1->E>c=0#LN%IB(Aamjvl};x64sO5$Gf1@G^= znOt^u5VtPb`AMo?+c1NNU6{prH)-7rN4jz0mTFELy^ccV<;KJDMaOL9f~fm|u= z0INUkf~2ygg0jgu^njOtTehXgzk)+wqFoaht6q4x?UPDS9xUieu{80_zJwb9lSpB>1n)Lk%Au= zb4#*?BS=(l`R&Qr-InouOi6Qn%@FY2M#nl3etG=sOi6cUGuQZ4GTLS4NQWOJ<2x-1 z#q41Sr(Son^SC|Sa~KS!0&{=f$O0_&!{w2h*-&?JLQ!`y=@yoIC?j9F?reyf=b@hh z6xdGXTvwbSuj#F=1Y(V_zLz-&qACZ>521+(`svHpbleku6fB#YUJ;@}*| zl}vrRL8=r#5K>bKo7c zkB7}kCFnEx`oL$z=U=#)=r}8jb-iHtOeFH1+|q&%51X|LVBKNtv0KWAbf_lhn+bf5k5WfB?Uh}TK&;y z#*(1VOx$)eQFnfjPaVUgdJB=NQ%uE&`u{`McLzjqt#1z+jfFNB31*rQ@TTPKAW>(>OP5N6dVv6Wd zLQ^3%-F#FI7DS$c9tEuA3%qHm2a=^a%~lNsy#U~B!VUs($>T=mL_>@?E5D?pA{Yx% zO)gZCYlAAb6XI+V+;c5Wcr-BYblVr;Iq6)KZ6FzFBilTvEqgN+YPG_2VZ-F{m2o2H z3yM%YZIMGDITn9l7$yUQUeD`qU!Nn#jB|E{#q#RdDt-PsN0u&&)at}D$X8i-CsyfyI zfYGfv`;FSw1Z{Sn08Fae4&XNO*1$KJwvlRwvss%{fa zu^jE>A2|1Oif+`LqoF*XqF9NLv-sLV*SFC|00bcKv}yva*?aSWp5<|eRI@v>as}J5 zshGXnaHzJrcwboZw#a9Wm?5IV<49Sw^yFK;SdFGx;gf?|ILVb;VAM8A(xb zE!U$FIWp_GSQ!9tQAapg7COz$>u+0jF)6nIr>%T>u;H!#_`MUFuP{QggqtdO!#?@9 zL~{hq<~5Q%&I1}QcK_ZQXdY-t0*V$$NC7Ai{&>poPS4WAf)lJO7lBM zaUL%BDYDsUqY5O?eIp*oF_ZSc9TwA6;>yP%G2`IK4E>KOUp9VKUm%(o~cXJ3uG~Z;8C)aX0S?`g*foNmR zBg`fh!LRWqcQ(Ilzd4s!Zzmn%aTf%Mgo7p(9Ap~EKXj~qkqqeAcwES`D3t3u1NWY* z+R{|E+niv(ltB64A~w4enn=&XiPn9(ga8^sI|wD)@4l7>S`ga$ODZ*mn>B!?F=g)- zF!uNR3k-e-(JLD>xH8=Rs~)p9GXbdje4G4J1VbG$mg`jwJ zC5Z#oe)dr{KiWb5mJpRJnNQO#a=HWDw>wG*;1Gy;p!`M6CdT2*2`RXUH?n)OH|Lbb zI+Zv9sKkZo+74}rl_3C$JSJ~airzs;T&r8D2j37|Orxwk-|$^x6K-B4K|np_91Rgc zH4j#Jhc-7S$^m~F|2GL(S$)?GK;^s)VjQ1aB^G<{;)WO-57(rmkZBMCTD@q*1HJ1M zU}A|UID`FR%eY0rlv=Wql)EZr(c6Vt>PbGFr5?1kpwK|Xq~hX^mmm`usQ{Ut1^6zB zS$j69NyIlDBxei?vb`eRbHoaqRrWaF?^HG(bf@Wrr>scyT5gAE#I@;Ooxyp5eIQN& zL|mASZwQp6l%1ISX3vHtd1RbC3J*%WcAu-HxlFAh+np8@vV&i5;p zK)ZgNExWqu%ix;D6@Mh>`fpH)H!pVI$)*-3!S;TKh;#TZDM9|gmjFM=YnzfOJV6+~ z&){CP{^q64X`az^+Ho3o$N$knYlfqpd&sPgWtnJ!HRfOZ6U&2Qp;|@Mj+N$Gj!0gieWCHO?;E(tPe3DB;1j zd1?{`On|TV=A^FgBg-ervJ@}%JdCB65(aQHejm(^3C+*b0w$no&;RI-UTPg&Ax6s-wG4RbFR+en}o!K)P4r1U- zaU+EIC!Uxbdhu}~+<1Q^Ez0qm9e)l~swGw~( zaMLB4ubVfY-JsmbW&i_I=F1Ev*7#Oe_Y}DFM-BrRGj8Cji(3RYi9sDQXdoQf`Z4Cq zpctzU{L-%u{Ux7`5_IIb344YEp)`JKx8Lky(~-jN^afO~%{Djrh<{ELFIfqLZyAo{ zVoW{X3MbG0h&T?KS?rLp^&0KbO7REtAJqF_s$MVh64$JX$G*4(WSw@76KJgo-bRQPt)myKyAHifk^Thuwuj8LVS^v9NskYaooM@&U)QtH>SFTz;w z)|G2%z@}8-?SN8!p-lraO4Hq()}$;lF^;*y48uPB5)=0&RLC^I5r)Y3$#&4}1P^r9 zhlOKm$ZCIKZ8CQm&+rr3^2gSE80NIUqPyBTFi{ah!@heKl*Th4f#RDts|Oz_T3Tg! z*6$jHEPYKVt(oT@s@{~$ormX>HUzq6Lw8MjIHbnVRKs0fl=XmTvTeGb0v+~SrwX## zqve}spGl0HcB6m0L>o7H4`wZ5)`O!gz&@^&WA=BlAok^H3Z^>z`AeweK9Y5H_o6Pr zUf$vxy-9M!D78|U^=)~jfBYu1TLEj_Um6NfgQ z!zCNk-=b;ua5UFOYab12{@kK^w%qx~8qQZG_@;~OZYf#h)noLlQx!+Q_ITua2o9ZO zpbNPN3(;U;F?R_`F|7XI%nCUrjTk3yY-~-xbeD%41O$T`!zpySpmB1iv(w;x2t6rt z2Fxez$IkHuv~AG~vbuy-gC>sQ%uBvRxZxg+j)L|@J}4>;&);i+iuH7PcJ%0`H+$?8 zuSh!R`2fGK3o73-O;3HOxE#!#P1jO`R(5!cmL1jtJz#)N=WgD1Qz(ZDKHdesWt^py zvSH)+LSN^?f!O|aj_~3*Xyr_;M7WXwMOYghdK(n=0>5%eWXh!J#9&!NzGlGg1w0C{USZGYAUA= z=b*B@rweFxeBc$(_f~)dS+Lojbec6(HQ}7Zc={GSu5=wtoC+;;Ke@4c&`2$;Vm)Ol zy=WzK!E2OqJ^-R{Fv0#1G5ALA$y{6Kj&h!1zI0NbJeC#LJ*2k_z~mSO4UOaogNsdl zu2GUX1{n}}7VSx!2XdJ!Dwiyn)KvF{&;^0J*EIL<%nH?*42vB#)sP^xgrOv*^2Bf2 zCwEGzj^<@8d^_j}U}s#sQIm9zzK98Z3+>m=QmqGM!5Xi*OJS2QF<3+q$}$0TE3*c> zIa^i%g3ID=<&o&OZixpKCtWnm;Ex~vS?!k0^&xcuKpvdIqbA)#+oo*~mfqTiRPqde zku5(sM<3`g#Mu;hhew&T^8?y0a(#q-{(g~6Ud}*?ACFklPAT@|Z`gJ6!s@Aj>#UT= zPs(i=mlQu8b2BOGQd(--BOaT^V;rL`7r>fX!>X@j0Af2v7Qp5W%% zz3De5iQwI6C7gK@Ge@9I15!L3!~RXyvR8_33GR+&l9b3mfM5ozHF zosRV|suj5_wq7QqLtuPK9f;N0vZ<=>?_WZ~eRbd9$8j zq*z&U=g(#JzI3Pp-vKZEjV{+abQ1w@M7FTi4M=N;Ml$%pOSt$6XJ!Tk%>kXzcZGOE7J*1fM4or@ZHW2x<-v`(&L^nsl>Ql ztYsMEz<;P>tR$dCm}aJ+E9P?GLX(8;lmQF|&)hgzZpMN_LBFZtb?_x_*oQj%WP|zS zOVN9``MKAO+aJ-kk(C5kAS_~8(O{5A=Zt>kg$syAf0yp`5dVIo?ys0Y^E+`C7Pi>v zwvA?CeQ`;uppZS!T^$GY`WYk`X`kM0xi{??KLk(^Hloz%iOyEsXbgp|$<2(mNZ8^H zFB9_vu+)l9b%Ub7#Kkd*qp?Ha)AY8Nv3F10?8IsHK-Z*0s@J+ePxM|(W0^CBkmHMz3b=QqfiH=qM&$f;r53kySDOHM!GmMt0B-3@J`T(i`+{9EOTn)Mji~iY7 z3tLLrBFzX2VT-!tjA+~9u?rigk&?tM@{M=Aodz3@XF(b6wd}*1aqV;I5K8ZX9AhQ# z*@@yIz<7?D8o1L(z?X2*5!4iX+^sCvVNd`xpLnzH3i43BVFznh(C(f2Xx%ENdsA|S z7=1u)ppvfFbJ+&g_UmyaP}u6llw)t%Md&8OJ50CKX-Dk}X>3gBUr7?`Xiz^*Z#*yI z0wg-aGINu*3ot+kYF2QpHX6EXrRsKmomZQNOxpb4ReXuRaCw5R1gQVPsFa(Puv0-MmMvSM|p{w$xR&oG_%01JM8q z8NG<1XA15cn?e7w_JpM*)6Ovr#=gW%E!RpO#sl`Xe*NOTr=Wc}yYMQSEu>;1y=g^{ zkeyy$NLDW5pbhk`9A|rCpGB8I4KFk0b4o^ z%I8244pgls!;GE|ftRAJmR>*4#}-bs%K%lY24FJt+U*#bd=pQ%v5Xvp$}!qjU6C zmZ_Q5XF6uEV)73?O8eq=VYWM9`7X^_g3CBq4qS*9-KkN*6%F}9MX;KbC3*bC+%O;^ z9ro`@)3335WK{}X7&g`t6xH=TT!)MhZO_2OEkqN1`eUcUW$AGx<8rVoiVMANh8qY5 zlPm3JbfzE*Dy!W`UD3pG^}}7M-j~*0UjsBWGO2uAnW`8yuNtLqVXylPn0StvhH#n#3_&Xj}4{9bNYnAK)okMyO6D z96lLHJvkl>XCqB&fn>g&!q8l59_RDuyo#e3El7tH7Zrx-O&4{$3vegE*R6s1#)B$- zOxGV&W;Ue(EA7b1BN^Y?*oRa)eWA|6oTmPDiOPW{ZU1OJs#U-^tTx5m9KSyJM7AXb z+>x}_rk8hJ>EdVMv<^ zt1NSr;yWAfZN3w=`{bJh5#EkTP^!(eS9f8s?k9=gtTI*)@fKX; z1H;9cl`)vB;K%Ro%T{w#t<$em(3_QO7eqq>+P~lW^-*>tyO1}qb4R`N80`t|VKV5< zYs_R>`(xbUK|$ig#?Od4y7c#)@WgBz+MI|kvGn&H1p|IQpv9iv)zN>`E z7QD1FavF+2;t#gkI9HS#$e|1rH2D@rLGG(5MJ7_=V5xWXfV^aaTNCTP9 zZm2mY>U0LHJ1t0C^giORzIk4~yK??)lsKS*b@gUT6NXX}tuV1OuD>}LNZc6RA${9d*nrvQijwq7zQm2cQI!_0n zArHrd)9)+SxAJ_7cukGXb#5h+3EC-XS1D6NGxNM}!Z+YOS>eBKY=6ReJ3X;CB6$_l zwlJ2+_O6=kW%Np_*dVZszO+6cyL`b^JFD5|3h*8`IdwcYrDsC1Dn7CVWtrVsUVY>o&3Mc1}{QRm;-#!0$q*rcjoy1yQp_*h5& zJmKSRUp(}Dnf96p>2|IQxvYt8;Eue|lJ7|lGRN;e<*8z{A{W$PiZ zifORojtq5)rt2j@siL+PA{!f^A7Z~+`kmg-I6i zyuK;nrL?t|-4`IIoHWe%>BtJ#*`Dg8C^89-P{*}-Qvz{ODaLGW#%(e2;iAKXPsLcc zr3)ASh+|+leH(=6J?U zO=FqQRz+T@*Pf?(1Kj+M5rN+jx7s~y>V#rw6W+avL(jlod{rT-q1-tlu}#Z3`Uejx zc$jwAIVBOb*UD%9g%9mrdW2n zVIc59<695)F&4)tJ6FZTFMJwH5cJwbYs}UL4D-$U$o4YiCBT^46tUEV?i%Q+)FpDK ztgLH*6Z(m5{b^;Zk6fkQGI&&2)ct~^m3u$u zMj{3TjE5??I#jl{dS9son7O=_aC-VrD;!oQ5@-CVi4XhVT>+ax|NgJ-`CWLt3xIHx z>G7XdUOctbt0dG|_vO``VPzK;`;Mc)H4MCdkDt`HMcC{NHDdWhX(3CrW<*--$CXhsw0YYv;kEV%dLDx=5Ep7^D5g z&yKKK3868!s{U+53daQ1!qkY@0~|7!+zXEY|3V)zZm=bh4~8X)Y$t_$sxIZ9Ax^^2 zz;&;u#QaEh9l4fL(1u3GocN9^Z(0*3sXHuP;*AC>SaAH3=0kf9c+xG#Cp8_6l@zJ* zngTgUyAKnINbRL?#{LYL+U8h{x&B|>j%%Iz1He(L{$1YAydeYE@!(@e&Vhjy35~sC z;@Bk-jxQKa!-wx}3SM1(ghoo8Q4_u%D9g44jqZ=>fo5!(kFb8bTm zUwQr4tDMP$T~mv`ez+z0N$h5#c5DQ< znW>Q+3?iNP^P&r4{%mf~j12@9W7jaIxUtMDKAitgJSu;t2rdljNZyZ$k2s7Blv8An zph5 zD)N6YUyf<$VkvTY4(J^SF_=}a;Nk?4VprO*Bk;=N3ZJ8mj4D!f^eU(J>Mhk8aC}#j z)nU^9KQ(-mf0d+B|Go5A7cAn~48rUaCj(Z{lCT|Is_x!Q%kK|;elZ%46<}ZS;KX@^%C8x$|6G|@GtAC%=BOU# z&`vnu$RD*}J1ha>uAJXaWJW7QOA>Xs2j(IJwL_$Zp|&rd!8y)b`(U`ppw-{wO*%wY z?w0^@aix!LN0w42&&N>B-}6F5&K6rruS*UcZ%#>my|AciH+l6z50;tkm&VDX^K*%Y z5-`sWvFbCnp9hf8M0>q!zXQ*&Bc$)0xmNH@uQKGs5wK0GFAmiGn&J9>3@c5FeJ(pHg)g{8d?<2>9#R-$ZxLQV@FiBkr&T&Mc@~E`` zUDvp+j-}G9-q6Iy+qEzpnkvBI&=9HFcdpfQYEgBmHDT8*;N+LSwqEm2&k9fk(aF6- z^yI*KN@e^Jr#0^rAq*KZgD|q$;;w>IknN^w{&!hvGjYa2Zx&^${7NN%hEz5G>fWJx z)nSc~tK|kpOBnX?G@aEpYxydK`IU0uCWl-NE7vA(qTFHL>TEhCC3IdaCk@r=)W_S> z8W<;HKn(E=QwwMs5!ol)c!Ulhm+A@AEYMwd3GaTaZK|w4SJMRDBwiRx2#E~lH7xC( z?J%VX_fb_d%Ov$l-LPqVY#;<`HR`dfu4rNUUm_9;}uMBST)NdLB%dmc#%YTrC zIg`z>Y+=SVXk9RHrHZBAaB^_$HUP)L5g+pn%VI!`s`lokg^$e8$ay-fQdMFv{DfTP z(O$i#3aQ^9pnl{k6P9Do!8Uv=*)CdRSM{VAw(%{36T-N!ytt^v$Y+E|{no~}72>#Q zUc&B~W25m+yI6O_joPcKd>;WH6kN=)S@{c!^rL0KW@Jscpd~r4tpoLxZmsfB{yzoG z9dtz?^u#Z}FyY5w!wm-;QkC)9@GO;FV#4N^^pSk(U~wQC+S(VNg!=B4Jdo{>`(^=n zieT*bJ*6zGuui?#kByGh|He7{K)Abk1QIzV;~TZ$Va! z-A%yjV}Om_v(CGq%lD@nsjfR|7m9>!>0aMQ!iqGvqgmXSq1&0&K0=5gM&|mn%v!R% zz})r6_x-o0aW29ef^iBf`!h=n#6)h>lXYZ1E|<^?InFUn0ytS}(>Q5pMhvu$8 z6qK>{{t*hU2JDD*So01Z5p8Rt>_jF?o5WJQAicQ%=kLXS_jFSl1dceadAE=79uM@# z(hY{4@I_U~0faFLPCtZn`l`6t+)_ew(L63w|C6a4Jzqf~=2u{+gqBjw!0?tXWkl|c zT^@(g-tkst+pHY{=~PX+f3-IX4R7)ZTzh*8W7N>_Hea!)a7X3$&7JH*IRqreCg;zF zOvEnFWc>+4J#|G&M>OHr9w`|@?gO(^5U~wR4sSSaF)O_$h3pkfoz4vFhhFF2o+XBK zHk>xSG^?{iFk%G|(e~CnHck6wmFp1J!L9JdcFfvwiIkLEVEYF_sM(rHmt9ZYw;>Cb zgwzjc8CQh7TT>}av^(MqYF}9*7-K+iyO`3YG(KNv3|v}HN=Uw0D5%7w(kd~&_5n}R z?tUa$*jb={n{@um##x9fxG)PT!|mm2h=tZWBwMSSflLCL#N(lEMN|RZAB`)F?vT{z=Xt6`o z(HAmhK@8qs8*P%@X8?CXP9r&!*)#>UhD#tWgE~W8!-kb1=4a{YAdLr$3#*|%}FG?L6)iCP7aFC(dCHDE&AV?hwA1RIU$1@?Sg-e%vVa4Rh;m42p zjMuz|0?;_8TETwAtqeQK6ulOV5KX3iAswV>N(v*LSC;ztH!A|sNRA8%Tiy`NxD6;_ zYZ4mh2A*Oi0|w(b8AtApKBy177~5Kwn&5+ zdz;>EFf$$RP-Nv8>nZPrfE<zbR4F%{p>JeOmD~hj^WrM7O7Fx78s(}+ZdWOI zO5gFVJPLtufVV8j3j@L)eH^A6MODfI102l&-`C5(uAKO#mmiIB9UUEK-w{|i`W@{{ zq2{H9yf*?1!k`gc;$%Bc=AX4g^6N>r9ePK{!hveVd{}pI=z+VR&{?|ty53i8oP@ZK zUe-oBJ6~JEr}Q?IZ$mQJazWMyLqd`CQu)4X+nsdzXBSGoLW$n1Ect<6?FK&dy9Gf& zCNI0KG9eAcJryGztilinbDgG%ox*9lYKP%ANZBs@v)|taV3W`?AkV+k^9CUr^{=-Y zBER-_3ZFz<4UiF*`29ey?F+n#!8x#?BAPTr0Sg#jGFn*-?t{dCd~~EkvGjjB4V$gK zb^$ydZ`1g`uNab=qpZ16qTghhl|nv9Kk+kC{7C&XOTgA}KxY6^t{reYzEJPDAjJzq%Tyo62^n1_HGVZ)%RL-~ zT8X@6J+cZ5Qv7U-?lH+xIZ!hsTlaQ$s-{}Wp*T2F@TFqz`!f9;qX8Ko%Mn@ddr$c| zE=XPMVzcj!y}vRcV`TE&tX%_QU|U+~uNy183c>N?tK6rSdb91IV%W`^_8_m$bU)Rj zI(*>m1+}BmmaSX!QdeV3Ap{C=3s8(U;x!_|K`+GR+mE$|0PwLJT=?>H!NsjePh~VG z%Jnr8`Iz(msScX#@(Tyv7C?An>lur!v4|_?<#&Cpg(uM}75WM3QPd!;-B(4K%e=J^ zNI3u-%8u{?oKiH8g!N1q4pL`C0;w>XKFz&-CaT`D37ImiO+~r>*y5MYet*HYOBYct z2>M~C3X(U(!GJzD8~*1F_3C=2pBd?Cu{PsG!y7H%=+s}X^MK*)9(CvkTFr4Ru5CjB zFr@WCoJ#B#ut?yw`jCD1(C}t3+u5m~afcS(795|@D`t!y`*t>fhJo7tVov6Wl-b0i z>yIHAuV)<-)B##S48XNYWdcSB8PMlU(bWuxu4?EV2RYNWA~U}pY)Q$Jtb%1YyCpZK zkJN4ePKD&Y`B@?gMqBP4WNCqXXoXVSXT0*(Jdk<;=5KJ3Q{Ml2DE&%QN;o|{kd!i zg3VTrysyvRd6;AOJH)_}#ZUiud>;cpEIy5ZiUqV`3o`Tbta?szgfomR0`o$w_r4w= zjCZJB0oY?1&xdtr7z{MXgiHP*;WeZ!Q@QrTAP`IGBspwEw*nRxk2i-KR3VznOWZIv zEB`)gv8S{KL%mwHl_A93UeFzhgg`uczxMN6wL@XrE{W}0s9xWwV%;SM_7v&Hu?(^< z=y2mXj%J8d$eHLf%ku?j`X-;qx%+D)t%$X>@J(?;o>B>TuCOMHX7^}l10^hC?m$`B zM_wSC^z3DRF4gBhZR2@OaL#%IL2~u>t-gP-=FWae9MiucXkrD~^TG>|oG-m!@1(4O znAvhVl+CfDz}g35Bx{EnR=Qz0iTW_VPK&cMbjYsSumPs zT~$TDTQHiufs(i#WcUqj=dz|K9+0y%eR(nvwqC}{b&`+P#wz*6)i`QiVchBig*Dp~ zvBfiTD-!+>^G97yIspm(0VR+;T^pygc24>_?BuL*rq=>)}yOg#zt3LA^dzv>qN|6v& zYh~QXoDao}%kB@DXN(rGlG0OwNc!i7uRzUiPI*y%w9L;7lqVqsPJQfpm4>N?fd~#v z1whSm-fjIa@+xM$RS0dKt*(}XGSEP;A!(t`17+5rIfI!7Ly-RbElfLW7)AVDE$$RU z5<*li|LywfSC2?9YMx?c&ByA}w%kzv|F0(ZDh$Uta;E3V5JgLm3Y2pT^CJ6AV6O)z zZ(yt-k~Q&SVtuvE#x+Cl@XG9dWFNRhRvUBOr-3sBtuAp70Q`Qd1R(A8to0%uKatQH;6O-wa?dUNXs zDCoF01^ppmOYA0OArbUrHCh7D0->pqX|#0WbV3{IFYVqx@Ru9*MM}~YkO<~Fbt)T? z4};3ytv0ks8EqtY%FcUB!yU7^Lm<`2wbV(9KfIyZ{n9w(I7c#7g2d!Yof;Fe5|V2- zoe!OsHZAhb7nIjrXgwP5Ge1ym>b33@A%I*1Fs||`0EhkJ zVa<1`bL|Hp_>tCTf*q?Y58ch68aJpWist0BX_1R#mS~d(0&Sw!A6L0Nzn?V?M^?%} z%9^qSNUzh=3d%_0JX&$dwJjwUlb6l-jsn^ax77?9{g2kqa@?={UB z{(r?dMji-KCg`v(M|60Qe1ZOyVP-V84Wdbgd1M54M@BjtR8pco+&9E3;0!w{ZGp2_mz9x?=;$Tnu{C-ixd{__`0^Jpi~0( zQ4q`gMX-jHfC|*oUSwk*^tmR4xbnWi(0!DAbfbJF_KX>nv$12qwje$&*I*R} zA}%5Q4R;1SfnF5F~*J#awRgPrI#yl4OF>m4Eglm5nGoiIGlf_GgLIbIRK7r&pfjQF>@5Sq zgb%-)Ox8XA0*jY?{Vcnrv1Si~Ba}Twg|wa%Yh24dB!ADD9RB5&)pFQR06G3%)yC%m zC6G>paUR10HU8()_C~|q%sj9WNU)!2E&l!dW+dZvRzDjIOp>Ex>3W)n6W)9cOD^sA z1h^nCt}tLgzhsT88W+1CEEPhVuO~pCCV!7g;uj;0V{&Z>hlzQa2d1c9GeD}L89oLbL47=j%qU|;QyMQcE_@4g1r^E?!c zuwC_Iovby`hJFc_5A*b>+bY;J8Wa_1-*^NwyonG1oB z@B7--*C^UWs~w?jn)aPYKIwz?-BTp6s)5xhj?twDO~dR^vpU(?jf&W9A%<;?X<0}^ z)UU{N0mgCBaHoLrP)G%U8w-0X-{kw%sz<2D_LdoLoPyC~E$bRpc$fJY$ZSH6{90y;*?UB0Nd5=>Gbzw;r%rs$GP?+8I+2{ zs?{~R0_NG)xq_zfk?*69ihO`4ASFYYmevR&a+21anH>cl7?$7!#@)lJcf=*YCXiga zCYCed#UP2xnIgK`k8b1q4Uv)%&-qZ54mS2B;&E8@Me9NreW=q)3C$7X?+bH|U)>W% zu4H3f1j(#cahGhaZ&d|84j34#S?Rm#3KM>4!KOMt@RN(%2OY)+GSOBwE1?dyXQYCS z{Zxix0iIFgZl7(A`?+4&4sJt7TpQPmz&oqQ8P0SVyG;E>BmuhHPR%hnj)R(QZamf7 zrp{^T5--H2yO2@;K&eI}p8+d}ZX!YIz7Y?qlKY+e++uR-+vrkCe8Ko2yU@0m7l+aM6&h3+ z2f7%PV;V$030=jmI}Jh1jg{@^SegBo3W2MDhEv1#*o$FYZ3>rRiCstQ`|54hP|vd* zcnjq^T~y)zo9J-_+%&LvN-`@$uP;;^bW4Bc>qm)8(Kuf!2@CqTj`ypBMJlZ@kT$0q z$O8Q~fas<#O>GCZy=G`uTSYm}G0G)|`mA6IonPazqX?He4KvG;NU1*|Rh-6el*dMa zg6CfKUnmZ#|UE?5yXpoGk%X0s3YU-6hoq0c_VH<(%(O z`MyBuy(XyInN!`HkpYwTOo#hsfz&H-gowig9nVGcrjddt6>eCqgMoT9I(5H*XK^$d z`wtSz&Oz~69bM~dw*+uZ8)0;{ng>-Z@PGIm#xf^-RG8AGXHLN)c2<8Ef%zi4s05KO z?O>!_PT<(zVY0t*C2C&+qiqDMcXdC2LAm%Al*kJ?gZz%HLS{=e9qrHnwyrZ~!d>(F zLKxZ13|8_}?;8qkNR;6qZ-fk6K^syLdS<(|8LZ@o3TvE#lfC0$Kwm7<_gyuZY?cL5 zC+q5emxpOCcJ`fzk>?I<(S*(~*AzZllmtPC*U-cyk&1O2k!3`BdW5FrrhLRf`*ztQyj zE(z%Ou@S1@pwjQNhN7ypxp6DB+zJ~tlLZ$6hBOd9guZ$PDlgT7kKa{aw7e@2Bn$k- zaWz;`hOl8Kc$w@I0j)Ram2V@4HzSv%K%>S$b(%x~gF9f_8w~E8ZC;E=wLA4&{l)_L zlT7JO{aY>2QBUjCe0v4}8mvr2o1K+25XZ4TcRPz%H@U9^Tr$=i6=f zL#Mpew}K#wQ{YC3W-L%`QMP}J#=9h1B@5=O^(;?#!@h5)x?jBpQQB!NsUBOu2~67s zdU%6IP1X@$G;Yzo2B|G<%4ktem|m2_Z^GR!eh$q0LW%;WGyDmrAbTEM?2P%SN(F}N zSVS~Pb)(pHJwnT6UzuIbH)Ev+{4yR|EGjT)b8F{;($67RbdDWrh=ksFTcxobI;tW)e8_JnY5&h#wqiTcBGlu*PqaC zNi)%%Om%GTuyh>j&e))ooq2ZeNu$hBiLmtKbbskefBv6LNcd3e%TH|p%E#4&_9s*7 zwR0^=uV6m35Pdu1*A0cfI*5yHfjZ=aP#0zuH3;%6MZuM)qrQJE5Y$Q}70-l6>{GL! zZbxO%8{GU`Sjooo5&X~Cn z$e)ul&u%6fJ|uoDpj#|^6Vj@pc;5nL1|HV$6W3%V9<$jl&hSYJZkpFx>_*R{Thy|+2A65RXt_0%+Cld zl>}wAwzq;Z6}73F_lp>~?b)82;jCw(tiL!%f?l@l&W3rJIc}bw$jLbeEit6fp<-5=sQ<%BqRY1Zz zA*psYZp}>YE=Zf?j8pqCCuL(9B4 z5TxZt2Wu60r6Xg!7rF{i<<3_$>@dV~(c+!BA}Kh>8;~qyWj=65K#}w!$(!19Ll(IE zy|#g@;^wu(XxuWHzVclYmC{fuwU*PQ<FGx{#|S2hkKg&&`s7?>)D%Jp=iY(?^8tD5)b<>bwCf@t9U;9Wzwo1)(6CrTDH zAwB{rrHKA{0Q{6L@j;N5Kp@Ru3X`VeU1h;$hDQ7p91a2x;dj~kH>J?pTW9RD-5Q@( z$8{_bE#8BZM|MQq+IvRkTIxQ>6N-K#Z&#i@_u|7Wb$t^C7GcXM4 z-dtRWh8XHTCZZG#uC#QL-Vnmq66JD&VSa1)dve-cJ9G@f_<|!Q4E(5H)eVz{uD3-H zL({X(~pGGv9FBa5>hF*eSzuXz(O9{ zjwT?8jaHU=sq_8tK0$DYNH7ez?okyAT0)SE#atH`*Y-e!oV_N(F~dLpsS8>WHc&UX+bhe@`6p@~e^ zDF+L<>>?kr@;YEd$R2{{5YS2tIv0l}PYk0WR|h$4V`(14Cmn2TYOoC<3g4Y>%u+oA zQoG~(02ZFgnxSFg*K$kDSn*X#sR+fz&I%=HXWqLanGq?r+@z#&Drh1&4J*jnD~X)G z9{u^KJUbM;WY&!V1AeSU%TRIUj4Znh;n1uIz+rK5-N%SL@oUr0Aa@E=df`DTw-|yE zGMk-lrTB&92`l*oOyK zP-QSV7)F=1Xg*fb4j|IFpkS5d4xny*%8W~#>psm~OF`Jh>mz^JFjd4{5EowJ16W~r znXAwSanM@oyr7e@>NwQ~;z2P)AImmU6@Gs-SYWMgK1l_ss}uEj7wm7RS&!v#L~wgY$MRKIfT``_Ej>1Xi0S z;Vzhu>^Wcr^a;f|e3$Zls~9bh?|>5sKw2xA!PTtWe@2L6^4vlp z3WTKuQtd@L31d+0WRO;RmKj<&c3iowVIhMct^Ci9vMaXp4DX6vx`5(fRxo(!K~_dQ z7G8*&xB)qv$~oP&yem2Jwf)RUzLxTHn_KogJUwTZYjw$m+m2nJv|D5hP-DI9=gdv? z={Fd0td_WPL-0Y?V&bpkp37OW^`N-Ys>PB$wAL5SY5qdXUwD6Vn!}Z^RMqF{W)HMB zWPvaEE>^czEqEW4U!oqHyz9P?9YN+l9aWjNI4>8kLr^&LA!(nVq4B?o;_4IB>m`np z-~Kv}C8PLl>=Q}5=?%A0_|y^T)%~S0AN6YzhkQ?XvsltzHL=vVcDM;WMP6(Zbo3&w z>}{s30nz|uk*Qy)$y2B21}uJfp6=a4I?s=V`Eq~=rS>2wfBUV4gN ze$zFz?wEmxT^*?9hvDsh;;6sES!ubq?g=A2Y60RoGc}ehHxIWJ41+{u{SQ|>Dt0%F zn5rh|uQ+?#3?HckJj!9=qfhQyF{_ocL)_iZ`GCG0Jo*Bjbv#5MRS>gu{9z7iM3$cc zhjG-KAG`wT@8ZeW6cFDs4oMaVg(z{VX^4fP61A1X;v0inPl4|j1{4V_P>=PRT6P3V z7(Yaip0CTk^VXN06qf5ZlQlR?JfeLH7YcW6q3T4mMpf>Pp;tR_X@YsU{oq!r&f)ei z^`z>^1z>kCrlLFe{1OmhP?c3 zF!ub`9Y7{4wh!;dt4=*`NNHJ8KA>A5+VzBQ3(L)jR#Ff>u;4XQB9_KI2PDE3m@N)U za?wfZYkmYWmnTp7+LB(P?fKz@M#A&ESDn4hD|Mo|nzb?bVF3Mt5G${KUJT3@uT>P6iBb{px4AnoLUtAlt4_LlPxw!pANA6vwxN!U1O5e5B z%&Ct-M}gvOvhSV%ma%;0yr6bdQ_JN=r;$Xt8UH4=7jfiOscPuC1ujqKDD?P-%LNyc ztZJ@K1DW;jkf6o4)w_ceOL-!LQ4ZAE_B*QwjaZI&!KZ*!>bow-Q|{`jLs;^nCjM$x z{pK?8d*`K5Kh5gwq(A+D7_=M=gKX~u=0QC9|kZF6?;!OZz z=@-+z*Jf;7W2YSJ!p;~SG_q%}Uk3lV&yDZ<2Bu}g1sKB^5UBl{X61le1&FmFS^<*z z*B6}z`{(COP5(9CZpcfWxcw1IB$Dt0cPZb#3=v4*H;xs^RMY7EqUw&BIh9<2=ChG| z)$HwLf~bj#V^3m91w8bOl)-INF1{qUIo86bjP7D@@mB{%wq|`(@uP+a)zR9bqqsTa zZG>-v2EsQe7Z-!INf`Vs#=GR`T<|n-7n5Ki0R-XxkN3a&X>$*5R9HA$zH4|{u~gh_ z&kEk#;BDUF6jRkozZ%G}j8&N?>b5<(V}=k7SzlzHAEqvaSDHK7H`J_okoG7IL){uh z`eLOHyi(l%Ea&eKc>rz5I(xY(r*eM6HKshYz%b+S;K#|-e?S`1*SV0T8|eRikueAh+io?45Lh~#*6PlNQqcF zHw<@N8XrV~TouZ_gO?IDEvR^u@3}P-w=0IW# zCs>+Dbl?3!4z+3l-i;-7o8wq-NMl=n@Q6FfN?A*9RMsBt8<|O7H!#6EHVkuFLUMkv zKZ(_}_7h^IDQ&CsNx7*BW_l)bZ>IPNmqC)|nj(Xl7sDQmbZdp(g5*I?!2g>VP>bR$ zFpIIi?yUGlwe#Ny_;#aWmy z_}Uxlzodf@LmqfgOf-aG4=*S}-7ZvsS@2hB>Bl+lTelZ2#h(}CD(@|>1Cg$M5uJ^k zn#1N^5d1*-1f`rACXB#)LGJsNvrc)f{5*O5)7p)q$lV8w+)dxZxlw|3rd4q$J-&P| zf0~!m8Z-E9FR+lnH|iO+h;qIP$Ur+Poqa{et5S44KQAnhP9D4k1h!kQ70&X|4YC zw^?V4DLG(ZizMK-AjrWCO6JH9d}XeWG7he?fLek2Njo5`i4e!TvUy^Y5)_@l0l~NA z-F`7DT`a6<&0}0r9jo6kR2zadGtv7Yk*>^}K$-Bavc{midxKuCq)O%gm^?_1F2n1k z1}?Gi@0S{0j*n!mdrE6l@HMU=CUBd#XK1C_7`SZwd2&kt@RT{q6srImynO)lgT)ty zowTQ{-hjQ9x_2bF!aLF_r(UV?ZSzH<;+g+d6U!r=fX+ysCOrnxYyA&D?@O%Tr4L8v zb1hf?(og~^+(cfBWb~W*25I)VE5J(}Z;xl9;cdmaZ(B5V*wbvrF-|^lkX=oK zKt@|e5m8oijfxuwVVH0`3GVgyooRrA2L-JPZg7(qv9Xj$PNs6&@(jzn&vKl34;YN$ zzlj8uOW=;*?8q@Jjd~S}8;JsG6znT$silJ#4BFJw0$iWvxVz;YClkHVg_0$-%FIxk zW0)DfSvYYDYyqCx>0w_p=>8y}K4)WSH9Bn1Gu*JFZkzFO=}6I*l1gnkP$lHjQN!X3 zW66Qf+kI3d0GR5Mz17$w`GoV-?uG8+r(!GRWe1uLaki-Fwxp2)4(xe7cBCQAgfyR) zekCRkv>+4?>3jN#jL#2G?{%9XB*D3`2_Zq>Zgx=0ezK^`88zrKnyCYH#Iuaa~M^b)4|pvHzpqP`j_AvFZsA?l!;dRFM$n zsD?iG#FE1`-}WpLTs-gfzgsEHd=joM6#qfb@N{{|jX=S%4h{nL(!8~P`is*MUlkKs zcs>t8)MkX(ax#`c71rl$?^;Qc$WG8XWYY4#6|KN3??d2gv3ly@{ItJLD*c`3Z%#h6 zDSE+Q#GXj7s~plW9nXo#?mLm$n^vZo;k1;aVOrm#=5q8ZxtGl?K-{7(L&J3G-&5UB zcjN_aO;2r?>s90>YMg%S_*sUl?Vk3Ux2ct8fP}d*g50;4$S}{>Xp*3WgbWG3jsNd+ zj>diRl3tnF*&(kF1*v;(R8oml0(Qw|VlC)sjkrT}{|WKMvP{18)_FO?RC%|rS!UwC z%yA25G1E+Wo{WiaZBb^KtYf0Kj-_u~20bjZ&7vy2HAGcf?V^0*vV+>@HnXU-R+uiQ zskxZyr#qI{HJP2RSi4)kPjJkNgDNmRyn|R%Fl+_LdwM)MVqv+6v;E=P4R?Ny|6b0{ zIAz@+EqVB|-Qbn(;@`h)m=*ogG%Kp5N6Rnuw?}|4QO>P+&pmn!%<9m?it?Pvxg@96 zO9lB?PW>uqdSkM$KBjTi>rk|j4pup$+ZFY#<}t^`V#mS29Ir!{nc3q&P54(u-aXFd zIw8VuBq?jrO_!RpS?|Q^%_zMNZ^-8Ce<`q0-JD3Iud`3{!|5PU8DxOr}MXBJYL?(9d%+{7$EP1;L}@tIXxssSY(S z5oG_pj@H(BXERVttDI98KgRPs#;d!O%g?X{oabK4|Nh#L3jJla-0InU|BtWl0E_C{ z+8(c8^j;CUi6{yJ8jXkuh=52Z5(6p-Qbef+RC@0nW56JxDj*dMndau%Z z@65mU8D`G-efpp0K2P%8FlW|Y7w;a#h=d1O&=mFO=;cg58U+OuB{;7VzSt*eEnZ>r0Bgxc4| z;fD2@x8>69gT||g%&?Zxp{DZmNs5u{KT<;LmCe{Qt0|2u0WagOi8nW+9k7L$k9m2C z`Oe8&VvPmaKYa`p$yhN^QJzM+t$EN!7DNFbO;x9q>a@8sXmw2!-lJi85a}gZ{ZUxK z`bNV>`jX7Y-|NNf&Zupoi0IsV_4pg}b4|*}J z#n^AIA`A1KWA!vhd@nFv+4yNH?!;xsgTv%rgET%WuyjAua*XA)Lcj@)4vSMz(mp89 zJwTjLk~G*IC7zS-dSY_qlM}5sQb*NsZ{rkPt)&#Tp4Iu%8W!H7_}Uh%qxrgy|DLoX zV1=%zxtxwrOC<5jop&Sm-K866a_stMWsH&ES`nMo$-1?!rMyZ0G@L7$Rwu2g?Jg4p zp|Htq#f`DPZuTQ?F1KBDPE5{fj`=so z4gtQKT)4m)ma{mlCDd3D17;SBoiR|6okHt+qeC(C*i*_4$Wbu~qaAFlSBAd;CbaYE z{0b{t-muf{QKFTYe)i1krSqIsj*Tr?NLBC!#mGhYoRnv`@{f^%M{&J2_(}{2F?H+g z&%|8ahK#L^cazS?^}~h^7&ss(FzpOWpqy)nm!w3X+w}(z#a#P7(qm2wIv)Nf0=}!$ zIPzwLIPG|?t7U9UVV}FSlA)s0v_)()5=SUY1e(RzBe983hPE;le1f6D!iq-`gy4Zg z{I6D|*ciuL2y2oY>r(YK$(2oSM!-?HMI!WB$#)=2XyC7?V&NLnyb0Ua4kJ1rbczvVO?o`(b-2^6zjdAose?YTNEv=7M0Z_AykH`UmNx zXNUNL-$ zhir@nQ^A#5B2Mh#k0Fui_iPM;t28A&8DLvp zOn9(k#LM!Wf7UX~$L38WOPZ}f4YL-xsENwKv2v+KEtG_nfybAXKMjI@4<<7OCoL`x zN4E78B&h%M8)t~B%tr)qk;1{8l=3PbA6f7AhBHMj(q4olO56KU5M^?ue8`1glu%@U zk?SXA_6ikY-qE)Il?k)oQhd#*CsVhv|s6ak~^RCQYV z+=!v%ACh9*&f+$PkBPP;*6b%y4DdWKF@JnY!it)dV@oGtp&*#<@0X%kqQP%JgTtC= z8XxJ}cIg;4>+q+jm5XYb5`;#=-yHFU1 z@6IH5Ba}EPKr0cWzSW+--hicLn<`BxDI1e5*i9y;6eV}o>FVnKtj{VIAv=$3<8_kZ zU)yVmzlH;xB#lZeDR#Exb@R|ESA({U&#NWEYE0v`;zcELF-rgZmJ+Tky^7pKYxKhn zO21o)85d-|G)K2q>vA7P;PU3zHqswM?r2|LUEDO#COEuXQ9qHG@KaAdw+@1WF0XmY zYM3Z5DFyZzV>t(@(AroGP`1(C+_+3!xJiC+yjH8HkvqV~NqH*rBuclwEc!-M5PCifjNE+?stVI2#PNzbDSRgp zAKuX`Ss+J}CR{ZGydeJg&ai%!eaorsJ4S5JF#Y$kqqgmmI3`V!hWF#&>B-4GeiyD? z>xQ9iWLp06E=9H){NA}uoL?<`ytc$L`47FTKx%bl`m(2pIS!C6#mxA~*Ugt|;Qpp} zTBX>0!-ABRJx1q2vknUrKE=ux2+kJwPX45Px-72t4sm%5GNmd{5jh!_cHvVnFF>&; zgn=8|awK=)6%a%;R9pn=nnc6R)kSCL(*V{%tL{Wh|IV8VIOpk2#WT=erq-p2RSr@H z5)e+SW#mVy(PCBWDoNZGrQ%zC={cMpSP$kU_8@753V$YJWNDW+g_hcB4-}ICU#fW; znl)qX@%PKbh1%qQ0ZVt+fu&uXw`eil&im@N?_x?HJm^tr2LTuk!EoL!2 zGXg<=dMdK#Cd$m_`7JNs0O=WtHXpb$JB9o|46w9vHi!f@18~k8#%v)8!&nFl*(rmDPb)2n4@< z9VhQiPp!>Q9~l>YnRm!DR6KpfVOdSJ2ogA}cp$m&+v|g?IE#n__dqQiU6Ki-19*zDMRGq#}iwpDUop4y8C5->Ls{}L-)hwV+jbG#iiuFkQ2 zsmbCc`MGj=^dH-;<+hAv5rdu<@zd8QH*lgVaD@7umSyd2St^D4#O-B8nyGaRUM`sj z1>5GdeB#NIZj1_A>3bKFTYwz+T5=7!2&rqpHPe!Fgv8_WO&6i(aWt@9?NNzsVc$MF z3D-ZI0lbUCEOXDI+CnqG{(^-x4;geL@ND)};9h?vndG`yO?gJApc*ktNSw`*4am=i zQkv%j8vpqJyc-x~Gc{jCjJoSFxj7c~5cixQgnz;>2=)k6&fW zq#FYg+&k2fts_N)7yl+7Pzt~!`%q)&+-8GsEEaW~A!j)uA@v%Dt##esF(TQJff?I| z-Etk_l>RtgB7VfVf>m;704b5w7)t@dZ^n-pe(v0!t?<1YfVuB*3trAV zqOkVft_~m4YQnXO;YdSoiJsx?T$nErb8 z7nfQ2>5e0ATkk_%{IgP>^MpxJZJ%M@|FVc#{f@E+d2AavG9XyUVw@ho!cfMVl z=Vl)3QuVxJtl?Mk4l(M{@!)fTlpPUMoT=7{y_#&BS0T|%6C2G)K?5kYOFNeRl{ZcQ zAUL#qF*=bLld$q&H?OS=S`)Ks1i5Y3>y6_t3-p;u>W$8ZQ_BRCkFSFIS)b|Isg2jx zPK+>JE_ij!R^|UD$r-BovofrLOZO_WNf-_UO`o;(Ak@)GQ{gQu%>bH9MroIh&-=$; zmwY6Uc5kW~4;Sit)*wgEZch~q-PWN1J5hR87>dV96e3w_Inq5qV2+qWfa#S;F75XK3G@<6( zy&Dt`PsGQ?n^}C!C&BmfqzDV70KWvuJ+Ag^-p!G&v$v;%uADIJ32+LO`9CSLw+D9_ z4_YHf=vI={3#G-$9Jox9AYB7RfE|=rlaDR@<8zw(d3}{WV{9m0h{A?SaG+9e%MvFU zx;_zMohM_x`o^SA5wUi0nAKz&3|+{nrHuJp42SpeT?}NVi7TWEny~kV7fFHu)R1~> zep$Sk=ZKEbjsn&zEW+wZYOXbJs{uzRA$c6!9?M(I&X(N|aBxDfuBE{>EQj|d1t@yX_FFIfVu_NixKp1&!7 znyp?x*My~koGMCK`_;k@ux22s5mqA<`SUD=Jr}>e6$M>@pf(-9%Ru z)8T57Dwd?{!AUO>~c}vU}E1BD_fI+awO$eW< zxr;y7iMa5Bq$*S+92PwWs=AlWSGLThYk)DcN%bdW^+Xj@hK0HL1geqL6Vdvb8$J^h zt{Il}8MV+CUPv+S&Lxut`CMG3E79+?3R}ZT4em~NHmMvq`$~wv^}>VRRQ+S)6biij zEJ2D+itw3r)7>s-NP*WXY6u8xaBI2PNER-F4|u5(Vf5_6a|&15#D|ws$jRE!Y$a!4 zEac%(e$$J6i&LRm$d{*u1IV;Ks)kDcc^fhBmPynoCE^_HAV%GTq?9)wvW77bj##`r zkHc*aZ5xvJvUWQQA&pGle3BN1X=L$g2$lZvya78%V$MUeBrFJHZi)3iv>&XUx$AsI z1Kr&*eJtgu2T}Adh6}m7c|sba#rcIcx?pY2@y;hnnb@~&41_HGN)C+14N8cfwO@&+ zG*u!5ZDX8!qcD}YpuHL)jQ!G0e;`+I^5eMW)@>t5-_|bfYLC9nvBzIs18eK66fnkl zb5YD)fPX0QW9D{i+2Tv_l|1Np$Y%!0a5m2(JFm5Vl-c%30>2Pt1B@?_LrZ)~f>b|e zcs4-P7~F_C0(7mBR5J@Fk!xlN$Yx}Cl{%PmjYLD2mvmt1*+#^Ar!LGrP|=i1X+`Sb z;=TISxHh67fU@24*AiS%Mc_9yGn{RcQcOny>XY_~q78hyX6fzE_K@oz`#l*EDXS?ZzJyz&N)r`KNhAW+bGi6Q=~i8cK%Bqja=+DvyC>a>V;Ypg0qk_!d1i@YX}Xp zF;&n}Y7Tj-jMXH&-A22{jSl+DS4Omk%aUT@H4ga@vA%;u-W>2~YGS{!u(e7H~}M!piNyI@k$<6unT zrK(3Leger%z6UcdQw6tx%4sazw%+%Tcj;s8VmZ+#`uda;9r9k3Sd~anT3hM1v=%|% zc0)Ge0D_WFF)JIZG9)|1+Pjm5ba(=TBw5??Xg1GJ{c!(nt@hys*30)!K1w+&Xng4E zAJ0AB@OgfspK;*k<>j??Oy?4k&gW&o7q~KNj1~ zIe=meY&QDJt+vpngMjJ1=dk}rdYVKj>(jKKu$tUNf1yx#bAkzME}z}5_LeoG_T>yR zYPV*5$Jroq%7MTm&%Sf(&hcrvH`UmR)&AMb(%AQndwN)LAzTQ5OgVua?@c-7VrDL{O9Ix>=BRsJgFu;uNZPm9^J*lt$g%}`H+%HPh&UbGfyX&)gLh=tzp6A zvI5=*x_8ml5pqSPT%`){HgFN*n<%=Nnb^{4TE|u$rgdm~3VKQM+4=1mu1@Ta-y#Ve z#$CD+qm9U4XJAe7WUK6~&Ay>Z<$NS%rZ6i~W3}dmcE1{=9)~SGNy>*DDIase`3ojzW*nN zOUy|vfF?H&sx0%z&SO?_OefcA1brq-63$&ZlDL7nLuKb?bj_4smQVKh$zhWN4i3QB zp4>8(TH;P4>8HC;Mc{KJB@)^xhu|d~Eh|maN^bU5f^w~lJMQ~sor=^lU;LeiicCsi~=QaAKZ3KdX9!uR?xfRkrKFpT%ja?$?0nGe*>BebaZ*RHVutAP9iy~ z+x=s68AvgbRxIE0Ig}!Y(C)hJ7fNtFDz-LB)kc0g>aWZsSwF|j{5W&gb#GJ!xB9+3 zXcM@d`}_IKB2x&-be<`=>Eb@_c1#(H8fnOcYjICBBK7!RbqCktRfiu zQ}2wDBFVKM&M&UQdr40{?lTAJBGR&uUR574wCwZoc$vM=mwwn33jT%n)otpAY9PyR z+4LDD&gUPKoK`Obnlq$_qS?~hQp;LHQ!0%Z#<=#{NvqOddZAm(Fi=lSb?w=LKlco^ z&pH;4$vQi~NcO}P75p6wJ{6~jkqc;se7oGF3VC|R$4W>z|rEoOYM$@m6)XKV!$wZ zkAJw-=a{)|>F9)V@@qCsan*$0_m8og-GL>DVL5f0yJxLd^mw?6BJ)`tAg`24nHi{U zV;HFagEjf49N3v zZXtR*zic*8jBRI&uV^r3J(!4$?czER<1^IkmzC-r2I}3(FX&oet%nx1o3A<8c|enK z+t~Nwg(>;Q7Qf3MOcSZ@axVl6ruXHO$Mo}thCB@gyv#=*oOf7L|NA*CpY{DPcT1cl z0!EVwQ!pR)l&<4b%qFz*{t(2HK*8{UIu}DgbFQu_50~?6p&MyXN6r)*Yqf3Xqb|#k zpo+h5_k&x$eVUd(1_-&1`|Un4B`kvV&Us?_h`UmN1hdv$yABe6(Y8|Sdz45!d~rwh1V zxE{HfMJvT(yyCUZRcY1Kn7jSuR)6jsNw;Kpt`3~AlsK5wvK`gIOMH+wv8VS1{!5n} zpR_X-XwA+86Grrxj_Er)E*}_B$gocBfzq$n)!s;F8!#Ekf>FTkKwUBKpGTlxww38KOL8Uisd$fiR z{)F)&6&7LUPq#-#AR0t0aI+lMA3bp zR0wHLPk4diW6Rtn0Y@Hme~)PRCB97|sWQ zEVjn`_wOLMHFjL+UZ}Z<#qww^x2{7w8Cm?!QeJYD;Zl#70P#l>fBUoup&Zog$;4ZE z){UjWjQtC2+PcwuJ)fD}R_y464+SlsJfMW(EBibB-gdK+SOhR!Q>VLIS28WZ!^J7r z6_yK%Rhak?v`x0U1{$!yfVA%NSpnRPUmM;v9~ZyM*(J=WL0RXAsrST=#u=?vR*G#-ZS#%&pDc zpvMG0;!R0XhHhXOBkM%o1ox6^W?$zz%*YQ%g++}4-zLif%U)+yVOfzC0`6tiO;eju z6OwML9j!UmD3$&x0g7^?e$iSPY#J7?Ln%5uy!`+Q{LaF@+~@Z#!hzay3r*?cwk+&yd7`x(;Nt3{DQPGAcEipv!s5lWW}T9LJ6HhMb` z4`f>w@%bq%!{@HL&qi$dWd+^8|1nRE&WRu@$QwC50=jL?f=iAKxnr#`R1Y;GZ;+Q# z{cdGDA95j3=POyied>Y#{AajY!JvdT4i$wtYAyYYKr^lFA(9ack# zSfcYu1-Iq=G+559!C4;jNq?a#@4uJeRjLcCmD|-=h!hh!mS=9`irIa`c%=tZO!&Nc z>Rz=k5f5_#Bx9QLY&3u*4^3!v;HfZYh#Ws6cDSPeNm*yb6v8ibI3UQ-FzjhWQt6I` zM@a(DFCK#`NOI5W%)A0A6I$6NQYd90{?oTpOSD{NUPP=eq}g2yp#%EVR!^*Q$eD%| z-slI#WWy>7(w>M^-{)j8l=e`3zBg~Pg1CrKY3rP$>+4Lm6Djt$Z(D5Hl&;NjhbJZ2_hGG}!Ts-&7ib&}IK~%@uU%{WtXS4J)ZdZR_ z6P*KF45rNGhnykFow?y59>0=0KY%)r+~ zj~qD?zu<$d%JbK^gmV4fj>3^LZc&HRPu`U3$k7idST_Or0@Lh~6|dixrMy~(o*cwc z^|-I*F0)+gn1!=s;x(Ob8y;pnUDK1Azr)IW>V~BpdQIY9>xV7VcNDPBg(-Jq z3R5+i8$`|FuVSuFDJk00PK*UBX*lVbqAd7KNbR4iO|3JZQ4&kcu*(r6aksfy53*|U zFmCDx{y8cLdRc&)fp2*Jn0~ln3q;Ohvl!1|u+2|l)?2U`&E-a*C=zADOY+-1@++!C^@_+6ajWPYUr+~>3>@nZ zFV^n~4}Y9#PP;dXEq2&qauOuj)7<^j){GM=kh64+6~D0{zQ(rA;JkHykxe+kIO;4V zd3Y~YremSj z%cdG688*$`yASMny53I9Zo6C2-YcY2Dqp*M*s7{lpAXCc>!NKBujjat*t%R=Ok}vmm zb4OT((%hk1&@axD;c3;K3HMPjTNXt88*0=MX&$a7n+Lw4KY}QPT2^Ce5}h5pNTIX1 z-?v*@cicC?+?CY#f?kBrKhTS4*&yU!fTHjYl(I7tvitaoinhz{dCjgzTi*zw_J(J* z#DzItWl`jDGx^}TU}e$uJ3L%5(VsKren(}KomsJ63@Mzgpc_h7F77MYW6+yPT3$it z#cL|^&Q*B{3m8G=v(T81@?h_dwvu8VQb%Kq#yUKO+|$6T4TCnIpK0aDIHvEt6kqHo z7pIE+ZV|7=!VOKJZF#2PqS!`%0;yIQZI$%?#(UJTqA)oh>2{e#oas}PX-kB*`W3Yz zVe~_*psv6oZ<52YR<#UUe&Y>2^SgaiS`bi{RCTkCP3*hOVPz{< z2VEz1(J-=;BSSeLk6T&#K?K%JR{D&FkBvwc3 z3{wgP98+Fata2744I-VUrHb|ha6@hC4YjF4s3DUUc*)I!hEk#3nk0xUa-k+Vc>Em| zoy+U=QsnL>NB{)pHjlpQnIVcn;4YY|D-_UCPz2WzvpD>3*-Lu0d z%QV8yGYkaepEm}xJZXzgh$Xe;rz0w}&QtO+)ne*&eKZojAoBtj&3}{bmldCfYEm99 z{r(}DRM^rW$e&MfpXt!$B|){MqU`^*O}+ke+up_1lB8BF4<5Pj0;uAqe<`& zfa-XK3WaRpftRN~1x=Vo zp@?7@Y8#_GENVYW>|{0Es1H1qHvk{WJLP1%-H^=BNu$sl{2j!xzVyIAOQaGSw$z8` zM!E|JHTHcN>zX@J=R2Sh@V*=%eSXoh*{KIx&g(t% zZprs|`U19!Wz@g%c;d@V^bdC|&Ewb;byg^7SPd=)#s23V|Ib*wsf4#-xZ@|+6er16 z{~Rl0`&8F;Z73-YR9ML={^3xf#K{;c*AU9Hx;U`sjdA3&9)AA92fXuA!(aXs<`=is zzig)xG&q%7v&+`icxraYC{%OuQ*k%5=Bh;d>{XTELD*&{WrbSGrV-%=E#tZ_EBaAM zj)h#;82{teM1H+ilj^nUZq}s9cG{*eK3O>86m9*YzGL&i+KR$y)(=)jH?BnWCtOca ziu>Kpdpt<>{J+zT2NZ%2_E{U=l9}%ii*o+dv(%quRWeEA@iN~;OElkaDA&32{W9AG zb7;`F#4xy#vSc;tBW{P%b=K6*0IjIDFZ$vuZplNux@>``e<2Y55-K>W@&?@*@OU0N zb=yzm5z5wql~JRSQU%L(#+JO6#;Hx6?5NsTKR6F$IhBrNKd7kC|FFV*Jg&@u*xL56 zqSm`U-IJz9PVHdQc&18EXy*AV%R|O?uk@}aN2GMlI}LW9D!OIaYr0YtXl2{I_9>8q zExpO0V=9itPq{!R?tchwM>jhdI9A{{^$xZbBnspL)%T+3%bace@&=bnNU znJTyl^K&%Ku^)^Lo1OpOnb9s_0tDSjf+45*clfoxi-@Ae8S?%IfpCs$s%}kM*TH$X zpH9cZ=2Z%>l4^Roxs_4Bi@z}h_7Aq7J9zh) zaAtJMRb=t(5L{1bHrnp@XYl}=c>j)DJBPVWTn2|+Av*P`T7QA7I4!ikBgxe`lQQ@v zf3c0t&)#Kb4S%{H5ImZ6cl8nKN9s>M%Krd&3QkXd3B~V1BOIoh;pGz6!CBB zU7EffpY>AyP`*?4&+9tgorgHkPmbM)m+}s|Y#DLQfsA^x#^hDNeT}$2qKcK)+OipR z;3|l;NnvJ%x*QYdALu@eb!Kn^X)1Z0o^*Z=e6l)y>;xVocc=y+cD5IC55Zpyd#-m? zr$pC3@|HcGd-C*a@#c{)lL~6EjoVu?s$Wf9G-(9aDQZg$d;qPQ?MK3fQsxpQHa-&tfq8*D44_vBiB1NWQ?Po|QC$~`x#qrG_G%9BV<=jh^_ zd%&<`aFRK^e8(;Ccc>9Uygex2<(PRL{zO1CY0Q9fK$<|vzza)4Gac7I;C_>;uYZ0S zMf@`QWT}EN-|m+amth@|CoZov+aaTl&Mk$K*FgAc5z+E1HSQfqklM(?9~J5f^~@7@ z-^orz^nQg+s+kleOGe6+bM)Zeb+~(9C^E1_F*e)y?vjRcbbWxf`N*e5rR567JpSu? zs7?Oa@XW)W;-@G`CU2^KJ4o~rOjjnWRghJ=Cxi|v)D{2HupelFVMQu|@ZX}3&iwu$ zA>3FBd}aHg4t0@|@ta5pIvv{%rm%}K2N;>8%1=g?ZryzGIJYufV+Y}=_D<&2isk2U zC&qNm4bF-0X!Cbr2NpT;M{p@dxLPLv%P8HR`)oE6H;A5!=oPFb^31C++jh&0$~UQF zmA4`dixAh@5bfyyo=zz)(6urcy3FF&ly&KZ#oQ1@Vj(pgkI(km`eA6X#&55}3_kb_ew38WtZ*9DB!pzYY0#%8z*kLmP zfbZP-TSf)|pP%*gKM-dJTLIJZKj(j23R}x@t&>v~aB+WZF7sY?y`I;r?4XDuT`f>V zx#dHHpW*fzSIZnB%E$c@@H8;fTiW&%@Wj-luwK0fRN2}oA|$p*52^?cO_-jfB@lkR zS@+m=_*WFA)sD)Wli!Zg(oe;Gxv{KeAcs#%>wgvMGKsy4;ztd87xMg0>>%7OUY`gY z`+&eX;yda*cDdNa<{W~Il=%kti^r5yolSfGOb9u1#ILE)4&v--OAdF67l8QYntP&$ zg&4k|aC|{#Mr9u8YeMgTmN&m#?>eOZJBn0?@-MhfvScXWkGbU7cA1 zFQatkgZ6@DEqj4*KDE^pzP=v?$)KGqSqj2e2~DvgwH#dtV?G(%Fbe5gC4BB*> z4P5(sU01B?)JarR+wq&K7^=fx^J#^b#n#allp^4=2LPH1PjC%_D= z5CpR_sW$<{wjb(5qOO{I9C?M^+UG~z(enD21NJ@>jGWy}_b}}|-3T`ex(TL6)4QxX zp?sEQd>Ja~?dPj}_99``SH~91XA^>l73%Vx%ANu8>5MNC2xlw0+BNngF&1LR$e$)i z#NtV)G|5p8LCzMROIlLGFG{M>>MX@BhSv~Fu`g)shStbXa(B+mP?tIa$jNo(cN*Ub zlz^$NiUwbl&VrjK|II$qneV)h*{{iQMGwrH$r7I80|?$FCJ$$8w;yVnBOUPNYFxQC zSWP@{&MEKa-oP6MhD_m4Bhh&+d0p z!<}0r9UPk1sHME~~VwimyN*Ugi29YLpW91GXP7;RwCiI1giG?rGb$^L5l z-95^|C{lb)4||H9cp)+)pq72_<+mj{Ti3k0_T>R0ewM<%9`sqM>iluQRNC`|VJScI z?lw3M1UEA-33t&DD!RlfY{8D)>tT9Q5_$>ZSfKt!&kb^oMLmuFld0^T+KJ^_6`^7T!W(DH#ak#+Hv zGJ%XwYd-ZvVM46uEkoFskm78m?cf5~ho!U+ue@pI5$Eo@^o9GT00c@s7_LX^(@#VRw5xPC!!3$%E)A8L-HI?m*3JKltBTH&L<2eYXz z*fa%gWuF`E9BN0@GdNWR$E$Nxw`Oa0T8kh}wj{Jg=hQ%;MxV9os~71Y0bl14ct>o^ zF=CvG1;SQa7A4N9O8iaKf*iD35{Yo3pWjdkZFe~PGRnGX%-&w&#&Y*2WL6zb5d{qS zM$v$#?dL1xqhT|}kk4{HaA?g#Uf+Ff%|A?M9xCL75RYzXUHBb-(Pcd?@;8h>*&J+A zcck=~310#EbiXn}x8s#959zI@S_OUSJ}_Qz1|AOy!=qLs0R?J!m-@HUNIZ9-i_Kyg zQf6+A9D_pZN|3P7L7DD|9?PI{>X+!0uAFkhA(thL$!FPL{|@rS#Y}SVUq;ABx9=G(SoN^y7q?`e zYBhjxMeDncvR?qP_A?leckaMhsN#c;F2WZ@pxA6wT8t=ArM;SkM?M1M8&HgCZiZUm zi51^4an1no1Aslr@bAFh*p~k`KLFmdAMn?~SP5ACkqgi{jR+`UOF~ilc%4cL>fmxe zv09$@5h;^9wM0qljQbUiMuC4ikN8fyC41a|17f`AoJ@1HJwFBxxGtPGwDxU%dIpA} z5O8EjgF>P`Tlno}`mS0nnLVKXng99aGUyc}DSiCbIBHE$dRYXwA&YmWro}%Y+BP?u ze&X`Qm_Q-0YV~_?&&o%zW!?K9q1X9b|NqiRBy&I-gbx<X50U}^smmg z%TT2fSBQbCDrq1E`-Svqtllj%Y{DHwhAN#Etk=GWk3&_XTGz&;Q0Lm;=nAtDU+C;F zD~Dtze_eL5Z`qcFe7Z>om%e=4rdJ(zZ5KwO;3U$&HoUz=93ZNUwP&-zo^B)WZbRh0 zwXD>=7^>#OiOX}@nU9g<^!OGvH`mdh=47Y$;L=)0;}c*-Yg3TVBqn_j&WrwbLW8Tch+vbg zl1F*d8cwl(Cm^qSdmq<%%u=ydVyOE16tsr!FflZT5Kqtje=4Nd9A>x|{)_PuReFWG zBHhS>^sOF`RQ0Qmzzt@81iQZL5F~0{>i%AFRC-%&nCWpQ5~D=WisxliXP2lD|A0yI zvf{c2H1KG zTuxN+7s!djm5J{O5ZbN-JJ5IrHxE~B4h?Zs4?;$}oWN%_nExVO?4}|w?IwE5PF1MV zY@3NH*O$i`5*a_?D2%t#33n>;_&YX0jE6y~kO+ESeXP03`uu(-LjY>xu)b$VRfe0g z=ay2E!RNQ1I}h>VDofxz(R?G7n5I1yHXOT$y~@U`x*8IJX8D>KKeq80VMP8-T;yk{Y&6-~Q&rHfe|Z!tZ9ZULGRd*anMTss7ETB07p zSLG3Yeu5BWwJaXtptmFWX+Z%|24YsOcBJtic+(YTbSlejxvxA`6?q3o1^Nx%_7j4i zb|YvBSyv+40(*=Y%E8LTv1HeDG3^)o8)9;DKor+8y_%A(P-5Eisl}E=p)hLW;=6Kg zn^$ijy``G89#E*uxD#TZep+D~ZC~{g7kaI{Q50pE&{F%3Fm}`OhaxM1~KH~ zu;{*~&90=XaGF-Ds82olO49{CU`<;LmAjzv2!Ar>BJ!ByAikKxREq)6S_K(wxK*LM zl&29f4&Vru1XNCHcpchgP9Xm&Rbu+{r*(A zS~;@v1m2=H{z(~DQX*Iw+l)db;VLx*;wRJGq#km?7288Ba-!;;U91Xqmc4#z>8HCt zq|9EFl!Pu9-PqODp2DYaHF;H$bBV!g4l3N)hu6lU8wHP> z+)q%v!|xc*|7JF7UZ8K`Jbv}!9-$ng#gonZ^|mR!#Czyb6(u}F-vI5??BjUIQ#)9x zo>Xm^A|2{&liE~`?dOGfCS{Y^6gxt#cM$$=9reye-?96v3W>_IA_ZNlQJB!}TdXU8}Y%;Dlo?v+AkEz$~|)5C6se>vfKKE{e#NN3_R&;H*@6`r~*) zqwAQFG{DvSFTBA?2&W5zT3{<}`^lhMMt+zYQN+9l>0^>6m&W~KeAdN05vR?d{pk@m zs=eUS$fJxML5)~qv*V=d!qQVoP(n-w2}~zT^`w8TXr5$w@9>Dcg`hQ*KWMFCv z&vMO!#4_jaSe4XngNPquVG&_fkjI(;OGldt#5(vNb*5_d0=Osmz*r?+j7yFafzT~;f7`q2Rs8PL zmF>*-H16PXQ_*}W%4`E6V;9MrdO%jFjasznhg3=o;6L_5O45z6eH@Ck&kFodtv2)` ztur15nS3$URH8Bn733T;8h6sMfaJ-u+{8Pef5!Z=#pZ`&jQ>I>>u2L+%mH8)3GV@FjVG#fE37ii7v~ZUa|p2NtYZ zE>hCJzU%cXdv#88y6?pf!czv8hyv*+>k`|CYt=wDl}p7qec3M`d)+Iy-hOhy zc3hqg+@NhL5`b`zUoXFD9YD1!NF{-0n`J#fZ?4W8=ub5_89sC8XG0q$oOr<|HKBdt!Wz&^i5W`V1pV#IR_@Ba$mKr7N7fiO_^Yq#awIwuG z4>hR)CQK(Rq3YcP8mvPes4P9 zwHcgR)k#ci6akV`x;NeY`mtFk-rWr?DWwth%uhGpBgNSC=0dZ}G7pyc$M3iO*lKh#2)(|K3=98F}CqSJb$FQ3e}ubVM^6v|bd zE@&56Oiv8uqdVmr9vV<2z|RN~KKN>O#s($Bn4=SBd*EOR%w_y6!d>e-)n%^+)K{;U# zGo+}3qc1h$;bS^v(w+r8vb#2(lA{)pPp8(%MBR7dOt}Z15neg^HgyEL%C)&@uJ(s`kI#1F|t(& z)PqM`Gw&!Pg>~Q0|3{3-(}FtHnHY z#lD)(@|vo!Hlx*an}8R1Lfy!33E7-rk`V(>@xo^d(Df;^;+Mp=I4Nh#R^iL@`k5LVtQY`2~cpJoM>ZEnxvPgVEu_>TP>DSD6Psv`mjfiC1V~ z&j!tf6|wLhTxsLwN5Pb3O?V&ztoljvJfrEMN$EUl>Vq@R<&o+X4wKPwn zR~&a7Lz6e)hzYI>>VI-nt1Ei71_G}2|%T{VUzdbIKfRSK3BB6 zSP=n-!@P}b0{LPV7~Muy2Z-bipy{cj{rSv1w5Pj7CHE`p1NgzV$xedZUt&(F$icF# zFFTXhK%jQ8vyDyjOYceZdA00gqm>>dR%Wcm)x6vw28JGllg2aB$(lD;IyTXOUN)|p z@5GAzgaOE)-%*$Glm$A5v9Qy+#;xh2%|me0zfsj6rh_R{yeB-={Dof$lQ2$;vTad;3%y@~N;2`88+kPbip`lkXcnA&C*s^i0X@7I^ zn^t|5to!EO$KA+*1-L|SRb|*Ih3?wDpGdp{Nct~Ad?M{TY{u|<9KJXD6@H$n)D#zv z07bNCnOzo9Et2w$1C#FJ(yByPiYLB&TDEM`f}n59O81(r+P6)5q0mXA9}wf+L+*%7^2D1qwO`{$s`G#GY#Y1*q88`yG9jpuslp<7FI+yJw6aK zGz6y!U**KUoz_ge40`~ZE2E*5n}Ogo5`{0i9SLc5I14ermw(q)9WDu%ggSeGCFx2KsvcRKyuKjiHH6b?=pQOyMX4 zYpJ~Lrq(nYGOAh1Ns39RXVa{-ey&6SELquHt`i6ZgMljsV(j2EF$UOgDP3R8OR_`* zrCjp_bj?k1g;GzHy4h253dP8x<^HlGM!I2ZyMF?ca$XJo0e-SOp?N(Lc`hVqiU8CD zROG8Nrq!QaLE9y~tGBEFeDmQUU<6VpOfUgJ1jn!}Gwx&1P~#&WGN2u4yd4?ZjMo7+$s z6L;m|fMYr<1sP|GEizA{R8`X@xT)bzd5PNwzH4*4CqNnT5bg-Zj~Qp?63w?Z`aBZ= za}>rOvHc6)vM(j!Dqw;46ctaQo;-VcaLzYXG5!;&ro8HNzSE_C zhEx86)(;8i8 zEjBuGnF*)v&8DPd*@RUqgf}gla;lm@{hDWh;3#4}byT!>B`z$|%E_RphonFYNAtqF zZw5oi<`))mQB*-4?|LbGTXRE|Xd$_5nrf||nRylAm&zW{e5 zLP?i}#%CT1lov_(;52e(q2>kBX~N_~o$}MUIs3e?p#(oP*~v`sD~zLSLh+o#nSvj) zq4qEjA;<0rJ5J=tm0{f3e0=3H&3XEk+opY2I7M*#i`JT9%Yqxtt){M#s0UZWH7X@R zuv(#F3!N&nTX}^uV~fbmd(gSM|EwXgNj^iuoCTdTj$W+9+b!dsPnb!o zyYOB*^^h|OOUXf90ZkcFO6&FPzW;P`C{iRGKv>mo^4<-u-GnNIK#Prq5G+o)Ba#xH z(BR30Dk+tI$$5b62E5DXfB34#Sr|*gQA%rtly*A^9gRUaZ+iDT(AU$wSTVbf+!u^H zX`=7N2m8EXAO<62*qPjH5JO1R*gba|3scP!<;Qn%DX3E#o393J zgOC)0b{7b@oAX>9u=*=)dH9T${I?_I{Jt~S&>6(uPrQK&f(rG;HqJ<$=D)fUO3!3i zL~W5!kNZdx&f}>g>`GbxGM9KDcvd@4;mGg*QXW#Mjzvqrj!U%+YK`d4KfI2`l+Z|7X%@(Rsb^Kph=nl`k zS3&_|xL!kWJ8WX%igkp>1J=m#0qp~-oUFgRvE4o>Ih@zoj%jS@E8o}Yv#nQBX!I+KceshmW=-LaTlEw_-I z(X=w|idcXa;ZuWWB}WNI1%j5Eh``^Wz-&AIo%9i-wDq}Z7%_tNpyWN>FSI4!y&ca* zT?d*P%?}x82uE3qEi5t6{r{CihD^3dm&H!^8s9E%>TAsYhNUq0O^n--3#4Y0)jg_N z=hQJ;*U-KNhdU7t0N~tMSlT^(HRvu)O@thB&hA6(=lTAJAaVomM+um=&}ULq>PAi9 zx8BU792UG3u}93Uym>~L=%R+p_zS~yA(N_FZxSWJ5o5b`>I+33Wjpn}dQ=&p%korC-=6RDZ|fvTz= z5@d+;!!rUi{Y?>xaYwc&+7Dk)cH3?eCVl#@V;XxLjvp0is8A0JPko|ya~ zyvtM$D=<-;5js-wsb|7qCzqVc(s>BI{(7nJ(<0I^g&N;6q3W7aPx*}$vEfIltkLKA z8@~93rR^FbAKeRLcfy1<9s|F{t!Hd&-(fdP(Sv9iTE2z#-K|Gte5W>d2Y^NPE7EGf z&te*kqBy$q!a$+<5O)--Qs<#l3|CDxU4&4!F=&dt-Tnlu`a2tnlzF*ld;T9^-yIg! zwY5L$RldZ+O>7aQB&aBepn@pvIvAsv3E3n zw+RWZ++>ivR+NGoFw_|@e(K2!WJfb0Wxe`~FoC*u;iH*Z3rP;aumAhd-_O0gIu(GH zu-wW3F?6qluqzi$2jTzLFT6FRMQ-L56~Yyy+;j(` zo*VpkqPIiBBpjteAFD!*`S@<1ON3$;+f_g4#>B}IqSf!_j3W}ya>&%P3TkZO*@*f zmNI@Bqsw~_0))d-n%i0h73{rBwb25=#?`5I8whj_YmF~dg8(I9rPa6+IM#3yR(@bK z7xC~Cf}Bx)63?01+7=mw0a!$P75-Ky=8R=jhKzySp$w+FUy6-juCZK=sO%>m5^XF8tk*7NN z?&jy;L|_JnsIM&DVW-=rlK&vk2OoQ6YqU|tDb{uWj%z_B%-;Zn>+%Jl#lj4X+tJAG zZg`QZRSdr8ZUf)JJDp>D2|-S?NJ@rY*zeC`=gU&pc*@;m_YDMAQc>b$b;oOn6@5%R z_+kDUO{-ggS{8d`AgO)VCzbxW$3S1X^(fZZNdtD5#b@S6O^t)tGH|x(<}vsgRf1qM zdmetYxHi&SD1yur5?;dj&e*f;4$FHYz7m8p%@@g$P}4&qr;ZBkxRwOuvzuXZ1T68l z%H}kkBZTvY#~%XQL!spFogxC>ve-p6sIlCf^pbi{qh1bPfZ=rWEG5GEzwS_75U(ui zh?@DCjIUf^aPijC?JSZcb;{G*PT<|P(5o%Kr|(_M&rpj+Sj|rJPFImG3UaxCV3;73 zF(+lS1NTFS9S~;0lBe!8+PkAV_Cz7Ra8x*! zfVW}*UCx(>+J9m*rN1|d@Mz=a!g_`@I%-{dBD}#Uj#!zA=m8oSP&qND#O|-O((>_D zHB1U_aIVQ()tPiiNa3^mzdy;LD(4av*=BJgzY%=5;Xt&`<0u7Fb|~v%JEQQ`3NminNHLe zntTB8SBW&O`s7iyrU@z=Q_;A_x>T4`EGiMV)9xw>b$D{G0A)n5q8F1 zLcJ36E#cD-n%k!;2W?SAMWNuoyU6Z`U3n|I$UIw2OK*S3IA$6NE;7=dt4Mfy_Rt*L zMPQ7idgbvy=+tLC6Y11Jb;4O%h9|z9-K0kxrNkjrUJg|Hq9}cGvJpvhDDoeo2r90< zBBAZV+j!dpbccucg*{bYZ?1g$8s2S3x!KZUy3^lNB1|L28lKv0s+7H86>qprr!k$b zvffyE`sLKNW~8efNeQ@40x!nVLR@Rerx%66rZTSHw0ZLOiqj0LT+f)tvwHd`-|;*x zSO4f{`I4QNHJZqv7tz+PCn6Y8QaJ6Vgsf`nmBH_QF81v~Y|Ml4w5O?B4hb5l6!d?y zp&V=qrTFe|XAv&0jY%Dl6bGVtnUinxiJv;PnQ-zV(eg`{B$IB?4&xt-KLsyUZIw~> z$+h*iemP)b**FXaXP$j3%hk zH^IeCbG0y-9_NcsydBH1_Ozd1PS6;>?Wtdj` zRsr~1_LPoB%<=B7Ps;9cV3E?&K6$^I{nL%b)GE)N&tZ50idPHTd;>1LzFk^K_YtSz zjAZVmLc@RrJ}`%-k6u?pkgG;Pj>1ZSL<3>s%;Zb%E$|-+*x(eU<6+c!TL^1LQoAOV zgTlgi9DHLCM_3ykz;46egyLA)qCqZs(yN&D!nZ zi*}fQU?&8|HwP}GDK_lV!~9DnlP52A(%j`qqOd~a&}09!Lc>-? z)|bB9My~LVmzI*@=Qg3qrU>@Y z!Q2}zN?^{1Ub7i#s!SgMY1q#;y2FPm>3Sgy^Ze)Be#d6+jqpAf?$+l<1y`G3~j{U^&H?%4(t zVivIw+XUWMZc?J$t*-t8^>^q?^;z0$vO08H|W)6 zI=UbXB`!byr@u$d%l!^wA7Zz zJnch{14sGQ42_29!W3V~ht`%1C|pMC>&{_5PZ%@@Lxscp#eVBYJW zs7eF;LdY6LQO2Gch4|ODHxWh&vCmTe&+g1xH4{$s9DlFh6}r4IYz1E+~xQ zW)awIlCUWxQczRsb7G1Mm=zv_ir{l)vfC9gXcI}Z8lIJvaX)elr46F@4w44%DvB8fs1TqY& zIo=2iR<~_jbZa`3qhWK_HE*bquU*AtA?|@}D%O`O9nMWCbV4MsE>ED8Ce$^{u1A8o zA49JGqGvkO!`~Iz|4J4qNzOH&+c}!VovhdWXY07%6qMeFXU~UR-QZ_Z123BaLcvQQ zuUfStj(zH>3`dIbp4-aUzMU%))-soB5I8j|zy1|*#phmc^W&6-dDJB&VDbQg<2!zl zkGAAWKC!75$xp4H+0U|rS3B0O$$3n;ZwtwvE#U=XC=z}1gdb{bC_c%_I{4bQLaqVJ8VQ;Q^ElhqqhsuhavWzgyQ@ej@9A#&GspXEIp1N%jdFkUE!8+s{ z72V)Q%VL%?WgQpD(KL!gHo1?D!>jwU3;94wrs8J*x5TlyeoY;+sU z*yQ(8-Tno}mM&`luRcRKO@bYLf)ii1?hq9F^!u7_hZ#R!;vNW5>?z2#vSOGWh-d=b zzB&Ewrh&G~HyvBB(^x*(W9y$V*bLHbyv(1H(uQ=5@ z3l1DFaBq`iisfnv8x{rRU$yEdKicQ*&UP6;ulz!EatG&fi{ip6A-iC;Ryu;yY|yv) zx~w3{aDTR!1jlROa~zFxpPcSIljjH{I1wid?3+*olzWwE-+1khwQ??W z8y?t>j{7?JSgV?`VQBancE~(IsT;F(sF0g5KpqhfwfCeSwHSCx?$PBWDu)xsSML1z zD31e)Sw$vYvdZf_>AsB_hj3+@WQ1V+1Pnu*etX(NHQt$oC^LIxs1Qbme$m^${Z5Vd z=S{{4TDOf(H~zT(7!^I7vt)QO-`{UeZ~=0*Klk5Kn_OTvgq^YE9ZRrVe*E-5YbG`# zJ7NN@y0t6e6lUmqU8CMqK3)GNWH%cq+#m5iJYCbE2wK1{H6@JsO#Y37K6;0!iqrSHC9{Eq&I9^jQb#1lw=J)GQu~@>CbCX`2Gk*&z|IfT8 ze|8`jC$a1HFs8iTQGbvi7TgmURXse!4qW!WSp1E}zI;Y7h11jp3TDh8`;J((-gwP_ zjkL1^pGj8XllN;5ylTQgmFKmq9*e+~%285b92o3!YF>wg-G=n@sXF`e&xEmAb;My> zrYcR5b!CEsXU;2D-0gIKgAsw~%SXNG)0gNzs8aS;+@i_G9NsTMDrTwZnm9OoF>&Y{ z;^1l&>x%bJKVeV#j6KDo{?CK-Y2f#hBk3?kWHDEcCPxB+Y3{t_JG1v^nrWdVJJtfX7Uodl(v zlf%p&Y(1-lzPbuRfwuxSUZcV62)lAqY49^`yz`RV*qVv-RxMq{LX99+WhJO)jj`mx zLcV+;YUB>`e6mHuBT(lBJ$3u~U-{`LUA>Txw|SKZIPtE-Ck>0ehM1Y4Q5xs*92Su& zu9!D!sIn27uNPnr#>K8>Ph+N)4Y-a_+ZrQTj97B-;A+?p$0s~Pla|b}8qNV>;+v!S z#{<|JE;6;J|6!ZAYW3w7hhGhkEpmOQxK{uJ`a!MEg(wJl?P1gn<=0Je#E^dBfG%AV zYXh&|Hoq@xgv6tuFrMqe-N&)RZlM`HIDWsG$v!)!Coty9ap8SNseh4~SJ?RY<n zfpJ^?xPgL8e+koA0i6;@5?rkT_FUOrNBJPl;6;5zc6S~8_xc|-UQGWrfEE!-k;HNU zM=ar@0Bw%ya+@-T@7wVtv&rclAr3f0(@+XY<^0y|~?7LnKe zQ0xo8)QV5o8P>@S8^8TptjvOxHQL${Q7qhMy5v0Hn@${GawTO)4ULP*DinV@)6B?I zE?paYD}Hn)*RfX_!c>uiSH@dwdzJ6?^72M4cbdZOHM)77_n0Y=5!z{KJnwAEBZc6StAM3#h+o35T z+{c7r$2Sw`6N-9$tErEZ+rPW$mTr)A6cv%kD^^z2S0X-)@FQ#dzd&0Zb^O;ZO`NZF zKCUj>@163LZrPzs&bxe!XO~%6>{hKPag;88XSB1@6o1wGFt?kmu@o ze7@8;D_XF)=z5ea`So$5J_u3H!|KNIKgU+|FU*nR`Zy9%Ubz*I&6`~x!GI&Ee)h{^ z`O5-7m%-v30`nn!IcO_jx<`}4A4yc>-Ivxl`*!FytzE|0+ZqJ^dwX_|cqbJJEZ^)L zi-gguHnY~DtBC3B@xp~H$RW$E^BfUf4KR!Zt`$T zKCK%j|0W^}{Ao;PHtTRY2g?3d9vtr zaK)eE%@3gvHsV{J`P*-0t$@RhoUr-S_>n)EhRbjuN;m6s&JA~D zUcX!?W8PmfG2_5}J3rMg8x}b&HX6r#TO1mqpZHT~iV-2P zn^t4~ZzFj}>BR(&iG_Kc;aW&pDYk?iM@>TGR#Q<^qu8J!$4%`WibyS6ZNgMz#ex@@ zyhVRXIlL{6y zc`{IrEZHdOV>*I962-a7+OW--b$KT>&X;<)H2V`G-#=IML=L-@IsQk|_H74v1<6w! zsxX)TluH%*95542Z@acS>`OA92fxi`nAIdbCPe;pRljtyD)k4*OP3bLZMC(n#(Vnv zS~x;o>f{YT=N51-VO;WYI>$p}bi&WYwyKE`X)?dG9a-3>dyju^YPJ4YLuMqc1r(z| zY$Z4r*Dt+V)iR~;B{VwqF;uMIkx(Nc5qj^K=@EpcG79^R+6qJ$S;yGsHM{*JS zrYY-Nw*5wkEq>nN`8DWvV9ewDw5GPbLdpwk>kyE8j;#ZC=2xR*f4YXGEDMFVUKHL4 zu_`%K?}dTuY@c0mr8;O?jejWbGv_$%?0ccmghuW{uHfvozP4weOK5cR!S)Roo=wn3 zk&z7uDDN{$)bG8gJjD*xvo&_@LD)iWVn)`bv_=+MM++Z1p3jCT?!H~E?J{^DKXGM6P$E|u#nL)HC( z=uj}aK?3S8yK_sm)kWZZrM2rLj=NP!c!oQXlXzi7$-?-PykkBDmUz$iC1tI@zw7&K z{n4}oRe<;ew7E9%Kmh~5Ok2i$a(?Fx0KoCT?#<+SY<#+h)>-I3)rM#b;2?@`uH&jY zpK2nI&!VW{$qkbaaJhz}hQ4eY(-7jzR~CF#EjfAI0QdOuLSw-X$rEt@fr!(=Tv`77 zznCyqCjV+2aEI8IT<}>xev6cEg`M4dS^M3P88`9=j&GXzfw(*;dUm-TZDy%OQr!+_ zsMaplCk!`63RYRQ+4TpOEeo=(TnP2{b0ajQlC4@1zS6!If-9%S>3fJSqVO1-((3gm z!0TI>S|!I7+P8r`rf08*#csHemvLE8ft-q@N*tapYpu}x(hbaZ3^OYrVl<~@xCb3{bm`aX5f1ztS5~=q) z3o9sC97u_hN183lH^2o1H(cXpXnbg;^7DMGJ2`2badm^VZ;QCWZkTl09+~$fq|!fL z+IL=gn(eUDEf1FixN4EaY1X>gKD>H9)yHeagHUxqvwpL6^5Q7`W{;!hU!Q>ttm z)Phyik;oUtLb+C6_!P5Kppx$v+v;bOn(FW8iFj|?ApLA^^X<)1=#AH|3q(7Anu(=a zHAk^c*r{?0X&C%jRIPjghu3<~Gz3%IuX2g+v|Bckg~M`nnK6mfzWjk*{;AM*D2(7b zi`PLcN4Pm(oD=UOG+N_O(ALrUjmo8j>WO4O&0R|@ao?_F#;j`74uRurSvc0cs!_lF z6E~_98(>{u!m4Qp`Q+TYAP8=bj1WSYA-&0t6Wsh%K~KOKX5Qwa(wy_S>bL6xos_{! z>%}xp$qOCJhJMHLb+zi@0mjs0`5v#(UM#Z(jZ6v-*)TY+;u&?oG#wKt?kJ)+dScqg zisa5NTiWp%?^mfGH7B)mn^6@m%i*I5U3}tMH4lqrMD-RPVO^ruPt%6DCl zX=I~$DyG*b-($%0SJ92}nIb>NREsJEw(I|~q2*3iFc80geD>iQTgWKkxXS9in8LyX z>((Ls6DHLsvBNc5onDdisY+4Vd9Lqn5+o7|YlMC31q^^*iuAICGu~hqjW+B_wGc2vSwk~xRdq{L5 zbyeFTe@14mG>n4#DvSna)HaVHPZl5QEiMx=X8;bC9>pQt1b5xIGT3JJ>V27ZR$> z8Qw`3f3T4cOAXj*Lga5lfl7MPRk8{jyx*s#MAe@;whIPuHWCqWb zdi*+7L2!I+-8+Dmu{o|rHB7as(<5%5G8>G|JYu-CLkd1PxGrCd#{4@`+U=_W5aRki zFbLBJsk(QMnX{Af%b5yknHEy+3pP&P>~O8Pk|8bigbP9!aC0|qIgkwovi(~VtOvl-RNTY}ieY$ql?LhC@KJ(Yl zv^@E=Ob4=bIY*|2Sckv93X4xLjvKev+^2+T2oYkdaPz=KiwO#F_*(qNmTFdZe4B~~bRT82{*TGRTc7RtA!uw_a$ z<&GOlSz=Gdwr_I%gpIqeF*2FSq729xD@muml zkpOFw4CK7vRp_R&JV%o@IA2+0r=(g~fvt-bHAOOqb@-V-$5+lp1>e2P<%8F7@vXgm zx`zx8id?*JD$Enz6}BpLP8zXFpS`IwTU;I%>D!_|(lZUPXoAvV%jo_{b<^lCQTPSy)|UF1GbMo}paU5Dy0E zV%02DUmLxD?@#;UF+G%SW6WmQt@#JPT9?Q5Qy2_N<;+}s$5T7HrvbFmsTs~HVo+bd z&|m|gtCRGzyBwAHO&r2Nqt+SQ1u71lYwi*oTV1UF&1plQX-s;$Qmb1Dh;zP`;ZJKx z@9h-jY^GsuLCxlK&-yAThpu9D@LouYfCc)dO@*yl^Ie$^aw_Gy6OFeAn&xigr$1{a9 ztMN;0f}YEID{ZZXDdiKk9d?aCbYjm4a|KEsH&U85mMwStyc>2hzve9--}&^$DBTZ= zauF9kb6ht5B-h|oW^j=qYwr2s27*Ud9SzpfT%l*q^bxmVmY?*G^`|v=&9d1~8r{0+ zD2>J)PRPKWZZ>33Uq}z9@9JZ&B-X#O3ET37*l%nH=b@)K7X_p035Ps9pW-YdxdU59 zA}-X{6EpXGVXgqnulVf+VLI8NG&v==FgRm!#5Y6dKG24zRtxJ<0k7Z_m_(v4AL~+< z^l5oXqb_DU){jK%C33hKp@A~49sw~L4S1?1R?91!{b?UH0!p9?(2KmL-wQPZz-O#dc-P~*c#L3h+Ss`auy?UZXS;+^mL%b$T#*3&B2+K(B7yp6S z(NXR&L9XJkAn#?Ynx&5evbNF6X=k!eYj*neY88Tea}kNGk36Q?A(%)jYfar*-n_uc zM>}~n;Qf=eOGOaJkmnzpRaX&~8cok_EX&JeGCeF$yoW_}QrmvukOp&iPBJ>4%aw#M z>PM_S%;Iex9cXFAyVXTW`-0|^i6Rs)jd}?7SMv&kb%lyd$0zOsYuIHz%n6hc^BU{7 z65MfE*4s8WXhHDyfFjm(GI8-ie0G;Q-)ZLqvBf5IuNEvS?BP~7`yOD5&Cp9IA~SqL z3YC=$Cv{>j?+|XTptV9O8#@GE*YxKdf7-iuZVSVq94O57N#|0JC(0Ovymc533lUUt zFv>mvYHiE39BG2Ua_sVBY2PH%oG`C197DGE6BF(3)qcHj>3#FM$3#}Z zlIz5Sq!=6Mm$B#^&VXTkEE>ENOxKn>Jza6uv-O zVIdHPt3Vi7YwP&jaRAE~rfV?b@|fD%@Z+W-5%E*tupPu^?ZH+3x|Lp0%damKt|)Uj zi=grm2{SHeT>KwQ9T(ZHCgT0&8PUN*70?Gy*1P7?;NYt{1JHBM`#@S#bEwz!WD%83 zTV(7*xlaE8*ACUMGFe#s&~d0pnXGh+1i39?+8+8E^+kojYi*h)tq3({FULNa@9UnQ z!Jza7&Q&~@wPY6wOYc{$AyBrq=P;()PC5b>7uf$~MMY(XmbH~coC)VL(p|oomCja= ztW=uNWyU#SuDNliN@2|KN?@F|t+)7kuO`#QWLkR-J{DZ+l*HHd8~q37b=~c`o%$`u?Fa|}~bP;U9(`9bCEB~?$_ z9+l)6cALi9l@s3(&EL)o#Rl=&VQqNOQWGgqnwyp$K86|VUsBm`zT&BsJZ2=I(#f!I zY2AkCi+03)aF>qk;9c%>C=Y~K$(05sO_g`vGqrbO!NfRatUlwI#6+c2pAWzzfT;i6 zBq!f%P;_L7y#x=2%lzQ_W(b>x*8h{jtez;^w;ZiDQ3C~_yIHc%hGKEHq4rMYW?d8DSgYmuyG&pcTVrAH8#}5WrZ$^Lx$uvew0iYTt0=k;}m3 z!5YMzKD(f|`%!xo*|En1$o1$rzs-eHi{STTyTwI_p5Qb&IDANp}phUh;dVA9zqc)m+`4q=EW{qsV++2SS0q8%s zbior!4IkJrt0B+J^MnLel~I8>ekQO-`(AUS+}rez4`N889Q*4 zB8EK)1|4%aJuh0tlD>}jiYqNnH0{*1-&p(Yu#N}I^Iy`9+yhc2?3|l3kJBVH<>BkT z25wVXcSM$2#L`Zj9QHPk5-}_b)aXjhzLodC8f+isH4r1sZs9uD7H(LjoXcBgS@-x} z*%CcpZ6c`BLX$K-mEPoVknx!Qhgi0he~`l%a!&YS4z~CmJlOq%P4r_HtBWO{OVg#d zM>p7-7^~K3f68W{}L(Fx@VU9`khGW50yVS$de9U|5>7#q2p-L;=00Ky&Ter&4!&fO&cfcjguRdr;WK9k|1CdG3fx0yf~nD<+u z$H*ogCwTjO93WIAyG-OiD+FIBj_1DlebDUblqFj&F<4ia;wgyTZ`S50HP09C^r(HiQ`c=FewbryOm-K4g3qcexX9JW45i=FhP)gRVoq*efONbnGb?!yDV>=6*gl zTEp@juG+jwWJ8c?*W-?>VJI?=Ss7p2>E4!odrZ5<%kq!A20^!%y{K6+5)>Vc z^czEe-JjM3$T>qwjg3DteTt~xo~;;I!bUFl84Uj%_hS-;k28{UySqAlJuT^l&Y&IQxLBSEHk?NGcylO^k$lfC@OJS`9bqS&^`u(K( ztN>NfL;R4@J4BdH_0slntjsjeXn2(SZi+Aqv-s%3*f~~|*Ffi%XjugXSs87I1bZwjC2GztA%h?`VzrgkoqcQg2tA?5X2MOW?d!e$@~1 z8yidG%rA^`1e+%$E+N5D9A3ClGn{8kW=3f^RFCZYpXi1<>2XM^|ML{o>otAB z*o5ERB=tn>%wNd;GF%k6KoXsRQ;(r_4Ou(?*5Ibvn&htC07Rc6XS$QR)JF_66%xAp z4dRA5a-E6`4hvhiPeOtcmf0)hxRweeE3+yWL*>JbHy)-XCEG7FwD4Fj>DLV{-fwMc zDr@V$=(yVCyq^svdnC2EMDDN!wx8?C#D%>2nyzxf?7Pj08xQAI2PX<;fKULGUVW_< z72(P;c#RZY?EV|r{ePXYE;qkSW-6CPB~;nMI$AR`KW_~cEQUvH-*nqQYhYkuVA&>P z9Yyx>Z(ZL{bT+16VU2nR-pdO!n`*^X1-D0!ExC^QNC5(D7nBRQX4Gdl>UP4LW2#OV z10#HmgAu{eeJh|8W;|n%mlXLw(PMn~?h5t6DkRbef9^~>+PQ3De3b3~%9p7bS=7wIRqP zY>wW+YI~m&Ann#?Xa$O8guPzi`0aEr28H!jn1v15*e}m-O)1P_T!dhEVl-8`-6!~U z=H{&;4mNx#g=RzSZJ@A_hlK?jY0Opjn`XqO&=dg#iMDsOpEKWoF;L?>>{7t)CpaH9UyRE%KNwH!SbFpO)}3m{*MopQA2vO9*cn?h;f)=U zzu@Mu_Vyz6x}lGiE~Xu9dXOjd@H@6Up1OfW_QP(t8;1nCrUtX%w;bj>-~29+7ho&N zUYw9u5bjmKJ3BC3BlzC_iIfJ4)#O#&&x!u=6KwdACi`$xK$RDmVhJi?I|P+HM3EX` z02qZNll;^1og90Zb;9(pnHTpvb~AfB7v~ZW&?L?H^d`q<^o-a{C%G$O8!n>mI)js( z6=S=Ib#>R`Wa0te$f!3q_K)+oZ~H(CU*tq$QLRH+zDwPy zR>+Y!Nm<|67{j5zNqlr@fB4h<(QyN{u%|bM#vkU(oGLNs>f<Pr&G<~3%yd)BZe_E)d5)vC-}#5%0?40f zg7nTG%VfXaA6qyf}$bMM7m6jIUGt=29aFCcu~SZHPBk7ST(@hb{k z2guHx>?r#P_lKg-W7!oUIyT3BcI9V(1S^gcSDG4jxx*Va;>~0-r{vN7>OdvtyFs{3 z4Rz+nEP&&V7-xN-(B1u|Z=MtD(P2ev*J1qMzoC!vhd({)1BwM2IqK>0gM*7pxwUyK zY5>$Zc+4#xSig_*11?peNNX<73q4OjKh>3|Tqix9>1;IJQ+Z~7DZJc-uAk6)Psl)t znUw3zufpC(8TNR&MtD zD3gbms1@B7>%U95a{}j*z(FpIgBQyvubeOLxPJXnZ0tx=WAN;psviG7wUUyT302Sd zodyr;*|khtEk4K&>|{x~Ke=}rym0t&dn7hP$eiyRFl1Tpv|lidWpL)mG7~N8NtG>rt_K` z#JJkb@eO?wi=jH@@IpbBvh6GQiqiVEh?P(Yl)2x2D|vP2+INUVeE!kI+?-& z;-Md$!BWB9g6n$_w%K>qJ*R^ynbPDaNsXgZ?@G_Ym;>GCLI?KR1|bJ~Pk})3AkDY0 zo~t?ozmk*3I|AKpE4%UB!!X(am2hnDCoFNc^XlGX=^5DjUDvU%g-JC9Pt;*XkGx{a zFQkph7&iz)pj4-(maOQU^aGTba!d8LkfJ2{`jyhjyH{Dkk?zO1?oP1!6URIfY^PT~ z4v;~a3sZrh%vOdjOw<@>DdGMed*PTs@Gzj-2ZNMdYCdgwLQ9@lm|K%^^9X~h7fKUu zIE|p^xjZ)RNj(AEA12DaOxRe~`rBT_vx!jafiwPSqDQP=7l2(+!*Q7CYAPw|$x?m@ zFE`Z`8FIm!aQ!%LHy8El4IDBiK%0kZB6)>L2FYwozPlZ>Py#6;bt&|j4im`zahE8uKyb81s;@hE76v?RhYQU`x-fnKh7zs zxJf;N>W=*ty%4)Lg`eViLQ8l+>XL*bl2#WqV1R(D%IFrXRYy=MExX=3bwv>Uisxi@ zXZ=o;-pmJH0v=$CL43BE~?6yEfd{UkTE22?gGBO%W@dpc?ltI=XrU zqdeypf^kfijnjX>E-sO=ZUC&Mhs;^IqTGAsW@(+KRa)UiUc}jJZ>S z5`A)@oR+qEF$5T$-dk$L3M@tcVO_zgmZH->;9uPUmR8h+o{0Ge;L6IY#-mu#gMhV} z36yJ}WzNv9_#B~wDa!~}XFa>}<3yyF*eb)}Gs}E^93|& zdG7J%CwX^bbm1+FrJ1PKPdEOn1dbLlUHH}AVQniq&3(Fn$%6OIS%(3W;f*Csm-w~y z>(R%a=gmhy2ba+_Ei~3cV!nA~Hw;ssa=>X5r~S8&RObW^kHfOOiA{hRkE<6(!VxYH znm4t!aj7-|Cua-y4BqY3r{-dID`IL+B%ua*`Auc5kp;g1G|An1pre zPi$9i1-ncT>-5SSf-^E^9BAkx>gyNIX%>nY3R708V9mA)W;bL%{%D?+51A8x_@K-~&b#lVY8I6-I_(kMd1om85R$8&k zO-=}TCP*3;6wc1ua{hnpzh5vsIg@m)!#lkq+-m2>175k!<3r;wEM+UM{AGODM$&m3D0bG@N>tbr$fs@g@1%Awi^)x6s>c`n*AR9B`X)%;lM^woHsL`)R< zhIr~n^tzInKCNsGw^4IGzDyLS=*ZtZtlIgW(CrqkFrX4S7-*2pDyobNc>P7B z6lzaGs~@&x1Wdd-7yR3A+|^O`e#Ft)S^JiysB7>u<1zh9aNui9ldZLO)WHH^4@Yrl zeoOw2qnC$A7)>2HMdnJu2Yk)5cd4{UxTXb_l4Ig(#71!+)%p(0*C>MyLzAD$nOTn6?jEa~Rt{GTKA_o^A7PLP^1kzs zEpO(gbtMuAIKg$h^T~TM%_XDM1C~hRJD{gPbE9jYiVlVmgr|+8n2sp8{kRgnxF1-7hrib6R^h)jMfatL$3P4or}Fox#53kg?+J;5R#*G1jUus7 z=d}+fyy)X{trJOJpIa`$NY}WhI~8t>kdHc8$PyP&2*OO&>sQ=O!Zo5PmsyTzdGEZT zx=yo|@nMy|26Iqm(dw>aoWkok?yhK3{eYw*lDMQZgcr~&I1uuqesN4k#e>#3b9mt4 zJy5-xk_I-!r?`5JaCN?e-bT@{Q}npJPmr5I5f<`s!Yi(Q_ukxlQ8%DL<~Vd@G&QZY zl{CQWJl+Q2wj+pNSd((Cnb%|^^1MsU_I>VxD)AjrH9CSo^^_7}UY6@elXQG0l$uqo zn9_eqO@}@pu_4IV+}vy7Rvqj|(kHmzoqJDl(G}c|a${qoddK1q*bH=D{(Svk7j3O; zuHL7^L12$@p2xx`YGpI={IXH>X}D*y`wQ5Qv2Pda`(dz!FFZyh?0~Ui6t0#9PlBSJ}3ihmu!7a?*26IfRM{`7X8$1Qp{S zJ;HRlVvQ4>Mc;?=y;-215qlbxH_PM4%B|I4JL2YvxI2n)>QV8wdR>sQ(u45llB~Vz zFCYUFJr3;6t`%o*E0VZh0ed@U>i!wo8*^M9>@70Vjpcvg-GZ&N$J;c5pDKGU`?19JtT>B!oYToouf@G=vLeoztKGhd0W zyTKjsA-u*l5eT=JdGj;CeRMo+a+DOlRf!*O4@T}&u&Tu!swO;{#^JB7r)S$kUb6wD z(v?4BK++xbL+DqS87Gu5TzoQtyXR5CVpAnTUm5G>%@=JiU7A{`e?3o*aqtqyK;*m= z&H{4dV$I8ur7aCa7`{?ASvkNJ+;avvUOf7-ph^tW-7k7Fm-kbwmGxNGQIto9d6;X{83jbgV zt&qiqELvyh+>h2SC?u$Mo!+Suzx(XUQWo+XA)m{`;cy$?)CzB1lR?om_YhJJ z)kI_pwm%oat=kczFW`1lD|7sKn~_l!0-N|z+3A&&^I!o%Fo z8heqRK=i?R!L*0vKQ}u zghVsX766=PZMLmBL}Ee5@ICH^i$eRuOpVPT55gT_)2oM&O~3aOhhWFG1fmOW zbtN@sh7Zv_*AfL(;^BZN6bj}itZ{#i>zfk7(np(ykfDu~P!B%jgqWben>sx~4C1;i|GYeLMaQ+uKmG!YH!VO0Fb@e+d_Jn5cF{)6NGI73YRO`LYVpw zjP8K2nXYVMlgu&KdE1J2gQl)70D&g-GehO|NZJN#(pFx{(ZQ89l9F+<`%c;O#V2HK z)#}Y3tOzl#V{YhooS8r3e#Zmn5Z1#rT? zxa$(VUHw;NaOt-$5n|?AOWc-@0)*Q9ilf$s+i|zl7C9OGfb6ZQVDY6H=tsXW1i|5~ z(N*-p?X`CM|dg_9uQ3}{me-iA#|J9c0V2{0$xWAVq|IOO$)m;JHrCoZj^|=%Jg9oSTqeKxY z@Cew>i@ysW<2j5ah@EMgWC1VWH>-?fv)z%S|8&omd7<-ObGo)9{gO_((CNKTjOPbu zJVYouCQQF|`!2!eatM+(xMkX|u8x1?xnC2h{$5mT4`b<5M^2FP@6ulIiIkXA())#! zwGglj*Q6_OM^FfE`*50;aviwQb30Cl=o8<1L-psb0SPto*YW8(Li@jtZa8LMg#y|R zAq-{RzTj@IRg|%t)E(){k!RjhKsku^;-&LD_a1|dLyA3|!p`~J4Q-?`Pc!So>9TLJ zp^bh($wiElSxyzX_-cQ0)z@JP>yQut3n+by0N5b;Du#=a_PFgYWzkobJG9H2#)pPw z>zRkr9{7l+=x;ilqTnaA3NIF#4}b2hm^{C3u!Q2Rf5XVnjk!fn7RutKeVA8PBH$ne z&#C`ZM4g2VL9QPj;md)f5S9o=>D<1-?O)1k?B|iKadmZ$P>^Q&zgy+eVV*#uynYHI zPPHSVYW3E^zTs)y6;KA{afE>J?nO(rde2O3UF{2zDeb<-kxvoJN67na78XXqNV_k3 zt(-<&XKzu(GzGOeE3*-pEq3nV^L_bqH`b zF}WWHO2R3Pu?`)YUUj-*xvnCt{pp#$sZ+443L*6oqoVJ*MU&h)R}9uB8}S%$vy0g< ze<6kqgI-Fn;yTYSny8&5O$;{L0$ja{`U||*1DfG3$Hse$7+$@jF_yEZM?8Ac6LlU2KFb z=wZZBAX+x{0~pcjuEY&rsWgA+yJ3BBYTqTBoAknk-=~f32Ie|~l*6PQN1UOE(-pNk z{tGezNpc{LtrzdbbJhIAhf+Gudll=3<#(v6AJF91q{+fIJ*7X2G=8FGL;Ht|rfW z$-ENPj$7FtvmQ8n7JAtr22)>CQ``kmYGiO;0IyuM#PokSrxEkzRcWudcy6A_jK&eN zs?AXG3r>B84WUaVSvWtcIf;8h@8GcmN(N$_#L`U=DvBD58fZzzEENF4qNhv1mApN1 z_LqXQzvwf0)tBQNvg|w+MBQm}-lO&vLYMgDola47;2kbrz)&bOkJHm%VgVLch$=3+ zoKWB{KlMV#W~qc)Hsj_4<(`lQ(coO`Ye3hX2Gc)4UKkjMTRZs_ZtY;H1%CjB>5PAf z5m!nYOW?U^)@ZxJ^kc_$FF1!DL*E4+yyDn(&~Kv-2bXkuiJMWD%FgGd2Tb3C(`D=- zWY0~o(@XnKTsFeQQ*l)-_>TH>U0X?|H&B{-c-*VUs-jEZwn}0b9D^0qN-A>LWUMy7 zP+tMuWc?~;;qw{aDdgxqy|3$v3pY*ushby0U5p7*hEuIj{AsfN7|7;yg$#R~%i0zo%jwTn@7GMD^EZasW3MQD|DA< z#~@UMyN4JzuX6J299FGR!&$BhwWz3IK^UH51C<-M`+OoIV6{QY+0t*}ko%ZSYlj0s zzdH)UG5UQ3cYEzN-%BrJBT*y8F=Qg4Y_i@(I@HG13;8G|~m)?%;5 z&d?OqNHBjz#i@7akonVBk0fHb3gv%s)r9Dw3HvIELrMx_zEO%oDY{Osrajuij2mt+ z87x1e&nD6XR1CV$-^0ZVRWtaGYu}p&Gvj35Z6%4Pd?tRZNDx;de_i-%DyZv6ZY4IaOB03NX``#LySds6dXC$I$0_?0 zr^Fa`o!=&^ejc*zFh9R|=Jn@#2Z$NmVibM#Ef)2Hp5pFCv8sCYgSBc*IT582iE3SN zq`UG1PK~xBhi&=eE!?xU2tgsZyYKGUukLNBJCc-C649a%m3!-CKgmBfxuXmP9otjA zt3{|tS1=!^PQ@HQ=n3u#YrK{Bk-CVec4N;;L zDbc)T3jn?YSrnNLGzN09@3yF@;eXv>S?kqH9kAFWkF&2n=PE}{pH#E7t_IZw2Cmf+ zg;p~H2DzYB9EPjHQ(k^<3^O_JrKO89?xsHq?c~2DAC32ng=DBBHxPw7h`fnKl|?m z-t`lNpqFXyi)`m3uGE`^FIbfkY0uh7JB4_IW9{1?DfrQBh9>=ky0nn??%f5_?obdO zqX1c+w?1&!br}*2E%El3&7w?QjQ8|7)Rgqn%%LMfV{!5I)YeeYed^RgpAF)h+CCw; zmc!d?cA4M01S6vIz zMLpw`xRt^>Nd8d6&)vmkttQHxev5D4CH{dEVc2LB|CV6rD?QQ~4SV`@Jn8kyhq~_n z*WQkP95YSg7%>z==+mM@QbwJuNA;;2r%^SqbWdwuSk1Lfb6WYK7-qrVSefR-UHB)IH;iVk_bsm%w>EI!8J+nsx~prFzJ=2~>dzz-k%;z{q1c6*I( zioN<#x^1OC{T2IH?=z4%&tUG2wslwn;(MyhhksopX|5_p1`o609y3BG_yGhZA3m(5 zX%Un6EH$+Kw2on^eJz1uo@Z}`OA{D2x*3(d6ct}w+espH{XVP!+LPYD!*&)kn2ynm zdnI6meV%+HeB4GF;h{x{5qj12*7^aCdeGP|9qYrrtMZxEcawc9w?Y-%pQwTxkCgvT zNbW!e=dza~B`J>zIWu7o*y2-Z!+Eiqn#5o~-%txN7aRR%KBt^B z4=|R)XN~ms#xkdn4VPiS;bMD}4v~aqTk)$^iIxlBw6M^uS>6ZHpySgeb=~?5`KhMn zU$9#P!D^x0XHi8K^_yVS)yavi^lQJxU4JQXM6(DX3JdQ% z7qUZ^FGXFJ4C#wSA0VC}uRAtXk8agdQN^q;zb@Oh-3#ntT3At>g))U*q}t|8f>?$= zf*}B6eZgfXMcm%tW-IkY?+sRrY~|6S0JCLjX;49OR_pIrC;pI@c0zJfK;DQ6R82xu zQDZ2s{J1&+-LM1g90?+CR{xR?eKAm?`jtc(Q(T!0VyY&sB-1_({zw7Mwc3zy;#^e- zgQ8q#5j{(y?oJeTJL?D?K1XGr(Ia6*{@;lFG=(#0{6wjhaam36^|7;4y$>7;y8+p! z+OXvE?2Spr)uD{@eDvrbpx1sqIz%s3p>rN5%C~iR0i=NF?hWy4{&tlir1s^bdeiRO zez)s}wHmAB*^iHkXYpo$^oXQcbiOX23Nay4`fwjnxq>h#B`g2b{1NUQ+KZUc!*qJ$ z7QJX_Ayrv6K4~?r-Y{SI)e}g(VBb!D;-x}XoYqPr(u3KTi>f^{Bs+ciPF!R#_#_;k z%9%mHS9j;<`W7R_M@dMZk+xdML_`Cj%)jTMVPinh6!jBtQs-zbs9pdEPMrIRn1f)e zl5MZnSx6Wa#vf4d;`&A@IQQjM{VMJ>u&F?3!GYn-$2jEnIrjjfT>c;JHrH9mOU!X; zGOtz*F>twL2+c$Flt0qb6|;QX^R!@oi0_4(O5Y3tW%ieoK*TLTIjE>;cf(NZSqhbV z1X@J8ygd<6{)0H=fkPuaKhlKD_D6;uJoq7dTkl4CAGA`8rgFj{nX|9Z?sbR&z7Du( zqzX^JdHdWunsOX84D4)qOy?L9H9oEZ>_Dx>I}~x)O$hF;Ls$tb)qrl_#EDvK7%Sv*Z~YZCHN4k5BVc$dqe2l*Kmj7hP4U{rclCV zj?^ubKh?n48|C_of$iQ)yB)!K4-7o1oHv|+-9{5Io*}A!j~UrNM?u~-DStDOI&WAc zETJw2wwK|{x4kt;#bF4|+%AKgfR2NRBaO&dY{r?o>b6m5wXnGW~va(**e$8;Ih z{TrNsSRTwy7*#g~5n!jZ;;Re_QU8N_ap@w@(5yL-JX60SqNkoZGJ2_^qR`n>ltkZ1 zudjMub!@Ks!TD_yebUTecJTEH>YX>;S9&sudqejShcO&4b7i86(v&TWnsTNZDx^Uw zB3t?Ua2aE=zQst*xQA&%X77U{$P0AZm2LAiY=kcr4&{Ihf9Bnf7=#0QWs-Yu7D4u* z=0bwL)OW_XwiiMnfVYnFu(g>^NHUe!xUlas};(&XuJMq zC=AL zar}t!Wm_ASHdSBEjUg~4`5+{pxc_nsa(u=Eowupy2l)%tugeNct`Up>M!v3Uk8g<*Xx}w*Fn@$s3QZON6RLzAX)e@TE~Gf4WMmcNGgJ^4Lr% zkM_oflOpOgLik5_>}rFF*7YHKzCQ!-fSLNc6PQMLJCn=ZJ^Cj$No84hEq5b*u!T z&2Fj<;eIMhyDnVS)L@Y2Ch0hH9oKbGuaKL)wLAx^S1Y}_ zhcXrRKR1A0~Eg^6qWy}w=*~YD3l_<9dDv=3yw%926B1TlaxVs}2pnQ7e!i(gm z#H@h5$=kY(t;4E$On%gQ&(a#1)`&&(&Rh8*daf%$`{hdegpMf2F*+{Xkl!MVf4KgcTFx^1nxRJJlvVSg`#k(3t)8Xbwce`hxmxL>)8bo%NmQ}5|V z5@Rs>^9d;CMX+F4@H3fsV&YMW2slUgDXqGYPP;xo(3=sO3*MWUUZh0~SMu67>lCK6 zyht{syhz?@%YOh*dqfPE5%))oyWHqm`KDMU6AS_KH(7Rcs}^GN#jFL!SQ_ohki08q zAL4m$AP@zyQA z6jK!ryw(h<121p~0#!d}bdJ>@R}CJWyppgxt?b&G7I45jHpNNDkS6NxuZ|6*&f~fg_wI|g_Cv8cip2a{g?G~9 zXSq%=3`iSV!7e#+q~Xcca>`&W?Tqd;5_ku0S1R4!!-s zo`9V{d{=yYgQ?EaIF0pjYx4~qQ(SKELLiMt(G{X*&0*5tK_RdQ7 zvfTAr+e`O;?qwVQVDT}rA-`R9=ifd*B}^C9fTe!Xy+V^NruxEVUvfoiO6_O!WFq?R zM^f5jVpL&g_dk|F-IRME8tMH!-Hm8rh+Wy~75ij8A>^QowMt%I_c#0Ii}{tuih=_5 z?!BP2H{E|Clgo{Fe7WbFkw-{E=Z)wp?lnf7QaM6(;lszONq<}Ci}F+=Zo%Mnt#QDu z(yWU^zyY&L?W-gP?M_D!%x1v?Hp}l@Ju}+6sQk|}0v#A`eb0aNj$aqxo@5eNIx#n% zT~__1BM7QzWhv4lve0lruzZDU^N$t`Iab4osauR0*+UN>GsCKs=L-j`NovGp_O`8+ zAEMo}Urb(HhFt7*fT2eXAK~C|6AZ)WXlsi}!U-*(<`W zDp+RAIT&A6w*W>FKL%FEn5>M;_pzHv%evYK5tZeg!x3RJ|i7NYXMD z4O^$4U)*v(a?5NDcWB8v0x&!F+K?9Eh{lxk3%VSYvXg;+2DWsTt>dz)1#{9J*j0>$ zUCoc@YPfHEw{EIESeUb(4vuTlWViJP-LEHZ$QLb2lX^#jZ=4q z4=j>0w8=(^#8t-M}d z0vA_1Br~O~gwI%TOk4ZUi@^+{mu0aj>=OT)1Lr9B^lKvnjBAk6Mwrs70#j3Z*)|%z zm3zk{`4KMgy9`j86>1g^&syMv85y^y;O6%Z$SaAl>1Y5+FB1E1{~;cQ@iV;E<8cF zH?N!SBFFbo1?6OSU?y5z1{m$Wc**y;y!kW}`EsAUBbGrU&Z*Bcf(@AF6GbvHY&G%# zXSSwROc(bhFfBDj*-FBb9YdADq|QL|Xm(+RTJaBjWoFrr#bN@_PNezCav;8HntZBhcCq28(325ir+sxx9!Wzrg}1v`ox zJHk0IAe8aUX7A2kt7Fi#~vQZ>i*@>_cWY-lM=zDx)@bt&K=V{Pw27fS(1_m0(FA`rh zxD-8A4gLIhPNt)iTFT-#u3baCl|mahac;7glCR{^`Z6R4^6Y0samAim}phoH2UW}s>z9y+R-jHOTvOdY(*e8 z_umbOZ$o+&)gOtI#$E?^6TU6>*63l zeDqr-&)p6Hpk**@({hprEq@_WOZN6IDYz?^N8@unDJCwVZLUbzsq&(M4RqK;+I=f0 zAhv-UpTw{n5kV^z!Eviv-p%C4zPlcadD>xgPfL4Vr!wsz+2*9BSbZg0oC;h zMby6s6#^f~sxOPsXln2YMpBA{o*r1>CB4m{i`^oiKSCmlY{401cHJ&`e29DqCK6xN;6E~cl%`;^s+$#kX%XiP2oMe>sq?81as-e+IN?xi4sRu9M_n#{U3vD1e{EtYx0+nTvwGzAJw+IE-ZdZ-E`f^Tq zmGV->x|fB^rb>Ypndd>VqVowE)f^f^LaP-AU-WIT^zx0Al-t$itRbXb*k;C<;+|@- zy#>Omm?&xYf%M`ngMOT@U}Qsf4-s^etzjfPmmwuPZt|ZWwxZ$Hw~`o}Bd!__c$c`t8HRn#(!nt^Iz-H--vJWx+|egCf+%_V^^; zF47gbeu0Fhxi-lSLg%QR`yw`l?w#ZqNwc?aYBTU|F^2fMNK+G3d7{wyb60sVr4^%~ zFmj3w#TDJTtG+C;=Wn(qZM%Q`WXG#;=-d?dn+04?GlVA$WO5bj+ zVFB!ejC(z2cXV=V#IrJS4fjk}*@_|XX|J5k)Zs@w3h$YbgU$(+0@fbN#_4L852n zjoULOrXLjdDCuux=;?S4lK1yRAR&y=f40Zsgzxcu%W1jchu58$>Rw)O<8?Z5)`?~4 z;Hx1?K($ozj7>@mI%-Q-+22$=lsr{7d3K1ei_64znc>8{RovehJg`*O;>Fc$DyI~9 zFgn1t(nWX>rlg{jnA9E@?qx8Pvu;9fF=#=Ky?FpdQ-qloQUKCv75D7SW^~u$Nc(O~(Bn zXhbOFWGpdnuN-@3Zvnpo^ymwztmPcvjO&1E15pNvb4U1yyn$67=uKy+nODK%Wbp|% zR{*Z$v}_e~>-D3wFTGc-TIo^;<)c1V@&V9`CHS#fPtPo^=;Z6>65mddIX)aQ=EPex z?u8x6EMbf9q168sW21=D6v3f)R7y*+F8M@FJQcCO$_g$H2ns%}0JxyuHCOy$AEQp5 zWFR^*R#N!buW9xQ#evrSuw|6~Liz>3!l~~429?cfV9@ou+fP_Cw*sQ|4Q*BOLx0^Rx+4JS;P5JJy%>NoI7{1vd{n1cIj z%^XV#y}mXYkkmrYy*Ka=d&#D}bL62C=w0{x7F(h?P_=*C3Hf4Z)ah?Ze*PSCqDzt! z=yaCK>N(&Lug_Uu0jH0p=pcOq^wpJqt_;b%X`We>tKyqFL!oLnrW7ru0F8uQdRunP4;=<4$}{=Uzu{Q zE78(7Eo}sdM!mw7<~zF{-CC}=kGuQxuRPs^rVNT{frkTZ*KjAQmO<1K_-f#-&Y_R~ z^sjo>y_;LoHg!}Cz$rqM`FU4g+V)HtT&(2@HMZRNM+w}&6aQr=*<@R(g+$b7W@+{( ze4lho8fsRX^5GZ~o*|SiawpW9zw~)U$ysNJJ$v9)p6nNBT!JSv)j@7_~iUO z<~F>SueAy(gMWh}O=8ZCc>aAIcoNv-?PmO`Rm|99EE2s&-CvuJUcDA6n;<<`S|ygv zjF~p={xWtgw|f!wtL)Sc?XThf=~Q2s{vLS%MDLPajFQ48JI6h{=!^WrFEo}V%6kmGmRB}tHU5#Pm_U9}TY8&%vG&lQ2?R#( zmg1Av-qTR2Dyn_eC+x8 zTQ1sH?sdT^4N9%K@rBktYe5l}v*f$F$qEDF#p>sD=>~Qr{41I$ig2ZlZwy(^P5*A# zCsNix^|{Obg*BXnnu$0f^zvofjpG@8?ySfb>RmXDNBy_q47)1+1mT(~y~zj6*1Ck8 zc)i`NM~Fq9;7vi5@dW?5*^ZruSk5UeUsN4!D$6XLIG_2Q7l^*LG*B}CZ(ai0K|p!v z4FOogvlleoXB=?j6iIU;$f=t$cwFn~hI3#^!$r%pfJM^ko5>B*&?PQiH7)HtdRtM|zJieLt0$#U>=IkUTHAKt+I6G}A-R1mlZ75ZI@+vl(ra1lEX;zBULRN2X?fGdqWz*OQryji)4_0Qz z7Fv^`A&MrwE1+2dHLA;Nl!@Ft_IQ$MVA{~1Rq>~w7OV$S+-ckX%1IhDDX?;5d*c0( z3?DVfC7zm)l59A$>9TsFtVeNSiY+6@auyw`*x=hV+~u+^I^OM02vL)VUf|~=FM%ji zt`8{TQ|2Xu8Yuf;xm>U;(DlHzD*Mw4j_r;Ro35UzS9xth`CPRvWRip;dhO3f?2Vai zSJ-v3$w>y_%&n3S=qXJd%+O-r+(}*OWuMYA$D`RJgtJ*p?49=LwGN6z*E*C~P-U88 zWp~CR&Ae4qQ!MM?0uSEhl4@yc%7pUf^6MAh{qQUW-P`u%^!&{kZgs5guh>`(=JWR&d4yDAR zX8vTlT)FOL*|wtwZ%XDRI;C7LQOFOKhz8M$OMrjaTS0qj-EWfRW@^((Chdqe$$0fe z=Doi1Lo{SbpP5*O%V!z1`fmuh?j&8H;1R@^r>%eQ_N{5}MmCv%gqTw0gKh?SE5TF5<;UCnV`mp`)v0+O^lKz;%bWcwyOGstdL7d zNvj6-J--@mi62c*C6%W0- zp(?i8At_-fTeU1b3+fgO0$uZ8%E^}~K5R5iA_c| znIs*9Jcae>@s+-Q+XV}5+8tU5{O|;*HMC!Q|MtK4H?EHUdU#?5)ED3RqfuE?Hw-PEUMi7nhCd;P<2tV zcS?x6^YV1Drlw`kia3S7%AJ2*Pw$7jLiuO#{sRgA=gVKTr_8JU>`U?vUuldK+^py$0EV`~RYsB6sQ^_nBU;MT{{3n;GfCSIKS2r6Dd=>-*+p!7I#jgfdMxb^=b zb-=NIyoqOq#aS2NQp49=z{*M^Ur4BZ05I#}E zE2~RNRBOaNBLBg0MNrHUlpd#Kf-3Q{_pCLae8jM_;N*ofazW|eH;7DrK$0}Z&`UomsLFqBpj${8PFdqhbLB%B~{Rd+0IBUeI503s5m=CMf z7+LRl^VMUe4me-B0y!d*48-7ng7Q;PdJKAwH~#;(nb%mM?FS;>u`(|~(HUosIQ9!l zkF!SH`Z)S==uH1rH+=_zRFiwnDr=T{jRLJVzu=@X-lUBKmrv5>3lb-;v5KT|?8m7O zjvgm2LFsYEiCZ5>k27XL>2b#Y3ETPV`LT)@r#=Fz!~3>g-1>rAub}ieYaA{O9Yxpy(+my`bhI zDE<2uFK+#R$Q*I(A1m|1tuLr^6qFukjbo(_IB|_L@qWsThMh7_9dP0jlpd!JpE9FQ znbEKY^8bC$>VN~=j}^?{xAnsMU#T*r2+>L9Ryuo4B|k&ui*xuNL0yWV^zZvE-?LJV zl?xhgN{n+6<4wFc_4$Wf)+dY_Mh%?$2r4c?=|2!_$Hn_N^}*5OtWi+e-9V=_c zu^*>CIC>n|3QCU?7jAtVJx*ML(&NT!f?BVj z^f+;im9^v8k5eBUJx*ML(tjYC}uY_NPRuKX1Q69UcZPq(K zjK+x@XPr3f5tLp~=?O~zfmqvEX$Ow|<4wFc^$}FOg3@Eu0muH2)wklm&;chdLFsYofMdU) z^#5gGUZsQCg%Bq%96tr6$I0uzjQ?YWwm9~Wm3iUT$EgEOyn@o>)ZvpeI6c*mJK;MhM_){9$TQ1J>%kF!P`n&9XK6_=p&A4sNzWBci>B&bb-m$8mjg=R{u^(rqIC`A81f_r9&gFBqyK`r|l6@y(Jlg9w L{uKA4)sg=JgoI_M diff --git a/system/stylix/gruvbox-light-rainbow.png b/system/stylix/gruvbox-light-rainbow.png deleted file mode 100644 index 3217d92a564491f787d16bb44b79f3a46c2cd445..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 192946 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

=xE)K9{<4cEUj|~-RwRN*B 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 ZzcH`q(x)A=dr2l7^Iqt?+egky{uf^Cdo2I} diff --git a/system/syncthing/default.nix b/system/syncthing/default.nix deleted file mode 100644 index 86259875..00000000 --- a/system/syncthing/default.nix +++ /dev/null @@ -1,11 +0,0 @@ -{pkgs, ...}: { - # Prevent syncthing from preventing sleep - powerManagement.powerDownCommands = '' - export XDG_RUNTIME_DIR=/run/user/1000 - ${pkgs.systemd}/bin/machinectl shell farlion@ /run/current-system/sw/bin/systemctl --user stop syncthing.service - ''; - powerManagement.resumeCommands = '' - export XDG_RUNTIME_DIR=/run/user/1000 - ${pkgs.systemd}/bin/machinectl shell farlion@ /run/current-system/sw/bin/systemctl --user start syncthing.service - ''; -} diff --git a/system/systemd/default.nix b/system/systemd/default.nix deleted file mode 100644 index 26907e05..00000000 --- a/system/systemd/default.nix +++ /dev/null @@ -1,3 +0,0 @@ -{pkgs, ...}: { - systemd.enableStrictShellChecks = true; -} diff --git a/system/users/default.nix b/system/users/default.nix deleted file mode 100644 index 58e61eae..00000000 --- a/system/users/default.nix +++ /dev/null @@ -1,26 +0,0 @@ -{ - lib, - pkgs, - ... -}: { - users.mutableUsers = false; - - users = { - users.farlion = { - description = "Florian Peter"; - extraGroups = ["disk"]; - group = "users"; - hashedPassword = lib.mkDefault ""; # For CI, otherwise gets overwritten by parent `secrets` flake - isNormalUser = true; - shell = pkgs.fish; - }; - }; - - # Default editor for root - programs.vim = { - defaultEditor = true; - enable = true; - }; - # Enable fish for root - programs.fish.enable = true; -} diff --git a/system/various/default.nix b/system/various/default.nix deleted file mode 100644 index d052eb0e..00000000 --- a/system/various/default.nix +++ /dev/null @@ -1,25 +0,0 @@ -{pkgs, ...}: { - environment.systemPackages = with pkgs; [comma]; - - services.atd.enable = true; - - boot.supportedFilesystems = ["ntfs"]; - - services.tzupdate = { - enable = true; # Oneshot systemd service, run with `sudo systemctl start tzupdate` - timer.enable = false; # Disable automatic TZ updates - }; - # Fix tzupdate networking dependency issue - systemd.services.tzupdate = { - after = ["network-online.target"]; - wants = ["network-online.target"]; - serviceConfig = { - # Add retry logic in case network is still not fully ready - Restart = "on-failure"; - RestartSec = "30s"; - RestartMode = "direct"; - }; - }; - - i18n.defaultLocale = "en_US.UTF-8"; -} diff --git a/system/video/default.nix b/system/video/default.nix deleted file mode 100644 index 2de8d367..00000000 --- a/system/video/default.nix +++ /dev/null @@ -1,12 +0,0 @@ -{pkgs, ...}: { - programs.obs-studio = { - enable = true; - enableVirtualCamera = true; - }; - - environment.systemPackages = [ - pkgs.v4l-utils # Video4Linux2 -> configuring webcam - ]; - - users.users.farlion.extraGroups = ["video"]; -} diff --git a/system/virtualisation/default.nix b/system/virtualisation/default.nix deleted file mode 100644 index 9d0a940c..00000000 --- a/system/virtualisation/default.nix +++ /dev/null @@ -1,102 +0,0 @@ -{ - config, - isImpermanent, - lib, - pkgs, - ... -}: { - environment.persistence."/persist/system" = lib.mkIf isImpermanent { - directories = [ - "/var/lib/containers" # Podman - "/var/lib/docker" - "/var/lib/libvirt" # Virt-Manager - ]; - }; - home-manager.users.farlion.home.persistence."/persist" = lib.mkIf config.home-manager.extraSpecialArgs.isImpermanent { - directories = [ - ".local/share/containers" # Podman (userspace) - ]; - }; - - environment.systemPackages = with pkgs; [ - podman-compose # docker-compose rewritten with podman backend - virt-manager # Desktop user interface for managing virtual machines - (pkgs.callPackage ./scripts/benchmark-containers.nix {}) - (pkgs.callPackage ./scripts/benchmark-heavy-containers.nix {}) - (pkgs.callPackage ./scripts/reset-container-state.nix {}) - ]; - virtualisation.docker = { - enable = true; - # Explicitly use overlay2 for best performance and stability - storageDriver = "overlay2"; - daemon.settings = { - # Attach to resolved instead of using default Docker DNS servers - dns = ["172.17.0.1"]; - # Have containers listen on localhost instead of 0.0.0.0, - # see https://github.com/NixOS/nixpkgs/issues/111852#issuecomment-1954656069 - ip = "127.0.0.1"; - ipv6 = false; - ip6tables = false; - iptables = true; - }; - }; - # Allow connecting to resolved DNS from inside Docker containers - networking.firewall.interfaces.docker0.allowedTCPPorts = [53]; - networking.firewall.interfaces.docker0.allowedUDPPorts = [53]; - - # Allow DNS on all Docker bridge interfaces (br-*) - networking.firewall.extraCommands = '' - # Allow DNS (port 53) on all Docker bridge interfaces - for iface in $(${pkgs.iproute2}/bin/ip link show | grep -o 'br-[a-f0-9]\{12\}' || true); do - if [ -n "$iface" ]; then - # Insert before default REJECT so these rules are effective - iptables -I nixos-fw 1 -i "$iface" -p tcp --dport 53 -j ACCEPT - iptables -I nixos-fw 1 -i "$iface" -p udp --dport 53 -j ACCEPT - fi - done - - # Allow cross-network DNS resolution between Docker networks - # This allows containers on any Docker network to reach DNS servers on other Docker networks - iptables -I FORWARD 1 -s 172.16.0.0/12 -d 172.16.0.0/12 -p tcp --dport 53 -j ACCEPT - iptables -I FORWARD 1 -s 172.16.0.0/12 -d 172.16.0.0/12 -p udp --dport 53 -j ACCEPT - - # Fix MTU issues for Docker -> Tailscale traffic - # Clamp MSS to account for Tailscale's MTU of 1280 - # Without this, HTTPS connections from Docker to Tailscale frequently fail. - iptables -t mangle -A FORWARD -s 172.17.0.0/16 -d 100.64.0.0/10 -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu - iptables -t mangle -A FORWARD -s 172.18.0.0/16 -d 100.64.0.0/10 -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu - iptables -t mangle -A FORWARD -s 172.17.0.0/16 -d 100.100.0.0/16 -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu - iptables -t mangle -A FORWARD -s 172.18.0.0/16 -d 100.100.0.0/16 -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu - ''; - - virtualisation.libvirtd.enable = true; - - virtualisation.podman = { - enable = true; - }; - - # Configure Podman to use overlay with optimizations - virtualisation.containers.storage.settings = { - storage = { - driver = "overlay"; - runroot = "/run/containers/storage"; - graphroot = "/var/lib/containers/storage"; - options = { - # Pull images in parallel for better performance - pull_options = { - enable_partial_images = "true"; - use_hard_links = "false"; - ostree_repos = ""; - }; - overlay = { - # Use native overlay with metacopy for better performance - # metacopy=on allows fast copy-up of large files - mountopt = "nodev,metacopy=on"; - force_mask = "0000"; - }; - }; - }; - }; - - users.users.farlion.extraGroups = ["libvirtd" "kvm" "docker"]; -} diff --git a/system/virtualisation/scripts/benchmark-containers.nix b/system/virtualisation/scripts/benchmark-containers.nix deleted file mode 100644 index 99980c77..00000000 --- a/system/virtualisation/scripts/benchmark-containers.nix +++ /dev/null @@ -1,6 +0,0 @@ -{pkgs, ...}: -pkgs.writeShellApplication { - name = "benchmark-containers"; - runtimeInputs = with pkgs; [docker podman coreutils]; - text = builtins.readFile ./benchmark-containers.sh; -} diff --git a/system/virtualisation/scripts/benchmark-containers.sh b/system/virtualisation/scripts/benchmark-containers.sh deleted file mode 100644 index 4e82f967..00000000 --- a/system/virtualisation/scripts/benchmark-containers.sh +++ /dev/null @@ -1,53 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -# Container Performance Benchmark Script -# Tests image pull, container start, and filesystem I/O performance - -echo "=== Container Performance Benchmark ===" -echo "" - -# Check storage drivers -echo "Storage Configuration:" -echo " Docker: $(docker info 2>/dev/null | grep 'Storage Driver' | awk '{print $3}')" -echo " Podman: $(podman info --format=json 2>/dev/null | grep -oP '"graphDriverName": "\K[^"]+')" -echo "" - -# Test 1: Image Pull Speed -echo "Test 1: Image Pull Speed (alpine:latest)" -docker rmi alpine:latest 2>/dev/null || true -time docker pull alpine:latest -echo "" - -# Test 2: Container Start Time (10 iterations) -echo "Test 2: Container Start Time (10 iterations)" -total=0 -for _ in {1..10}; do - start=$(date +%s%N) - docker run --rm alpine:latest echo "test" > /dev/null - end=$(date +%s%N) - elapsed=$(((end - start) / 1000000)) - total=$((total + elapsed)) -done -avg=$((total / 10)) -echo " Average start time: ${avg}ms" -echo "" - -# Test 3: Filesystem I/O Performance -echo "Test 3: Filesystem I/O (writing 1GB)" -docker run --rm alpine:latest sh -c 'dd if=/dev/zero of=/tmp/test bs=1M count=1024 2>&1 | grep -E "copied|MB/s"' -echo "" - -# Test 4: Build Performance -echo "Test 4: Build Performance (simple Dockerfile)" -tmpdir=$(mktemp -d) -cat > "$tmpdir/Dockerfile" <<'EOF' -FROM alpine:latest -RUN apk add --no-cache curl git -RUN dd if=/dev/zero of=/tmp/test bs=1M count=100 -EOF -time docker build -q "$tmpdir" > /dev/null -rm -rf "$tmpdir" -echo "" - -echo "=== Benchmark Complete ===" diff --git a/system/virtualisation/scripts/benchmark-heavy-containers.nix b/system/virtualisation/scripts/benchmark-heavy-containers.nix deleted file mode 100644 index 463502dd..00000000 --- a/system/virtualisation/scripts/benchmark-heavy-containers.nix +++ /dev/null @@ -1,6 +0,0 @@ -{pkgs, ...}: -pkgs.writeShellApplication { - name = "benchmark-heavy-containers"; - runtimeInputs = with pkgs; [docker podman coreutils]; - text = builtins.readFile ./benchmark-heavy-containers.sh; -} diff --git a/system/virtualisation/scripts/benchmark-heavy-containers.sh b/system/virtualisation/scripts/benchmark-heavy-containers.sh deleted file mode 100644 index a0dad8ce..00000000 --- a/system/virtualisation/scripts/benchmark-heavy-containers.sh +++ /dev/null @@ -1,138 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -# Heavy Container Performance Benchmark Script -# Tests with realistic workloads: large images, many containers, heavy I/O - -echo "=== Heavy Container Performance Benchmark ===" -echo "This will take 5-10 minutes to complete..." -echo "" - -# Check storage drivers -echo "Storage Configuration:" -echo " Docker: $(docker info 2>/dev/null | grep 'Storage Driver' | awk '{print $3}')" -echo " Podman: $(podman info --format=json 2>/dev/null | grep -oP '"graphDriverName": "\K[^"]+')" -echo "" - -# Test 1: Large Image Pulls -echo "Test 1: Large Image Pull Speed (postgres, node, python)" -docker rmi postgres:latest node:latest python:latest 2>/dev/null || true -echo " Pulling postgres..." -time docker pull postgres:latest > /dev/null -echo " Pulling node..." -time docker pull node:latest > /dev/null -echo " Pulling python..." -time docker pull python:latest > /dev/null -echo "" - -# Test 2: Many Container Starts -echo "Test 2: Container Start Time (100 iterations)" -total=0 -for _ in {1..100}; do - start=$(date +%s%N) - docker run --rm alpine:latest echo "test" > /dev/null 2>&1 - end=$(date +%s%N) - elapsed=$(((end - start) / 1000000)) - total=$((total + elapsed)) -done -avg=$((total / 100)) -echo " Average start time: ${avg}ms (100 runs)" -echo "" - -# Test 3: Heavy Filesystem I/O -echo "Test 3: Heavy Filesystem I/O" -echo " Writing 10GB sequential..." -docker run --rm alpine:latest sh -c 'dd if=/dev/zero of=/tmp/test bs=1M count=10240 2>&1 | grep -E "copied|MB/s"' -echo " Random write performance (1000 files of 10MB each)..." -time docker run --rm alpine:latest sh -c 'for i in $(seq 1 1000); do dd if=/dev/urandom of=/tmp/file$i bs=1M count=10 2>/dev/null; done' -echo "" - -# Test 4: Complex Multi-stage Build -echo "Test 4: Complex Multi-stage Build" -tmpdir=$(mktemp -d) -cat > "$tmpdir/Dockerfile" <<'EOF' -FROM node:latest AS builder -WORKDIR /app -RUN dd if=/dev/zero of=/tmp/dummy1 bs=1M count=500 -RUN npm install -g npm@latest -RUN dd if=/dev/zero of=/tmp/dummy2 bs=1M count=500 - -FROM python:latest AS python-builder -WORKDIR /app -RUN dd if=/dev/zero of=/tmp/dummy3 bs=1M count=500 -RUN pip install --upgrade pip -RUN dd if=/dev/zero of=/tmp/dummy4 bs=1M count=500 - -FROM alpine:latest -WORKDIR /app -COPY --from=builder /tmp/dummy1 /app/ -COPY --from=python-builder /tmp/dummy3 /app/ -RUN dd if=/dev/zero of=/tmp/final bs=1M count=100 -EOF -time docker build -q "$tmpdir" > /dev/null -rm -rf "$tmpdir" -echo "" - -# Test 5: Layer Creation Performance -echo "Test 5: Layer Creation (50 layers)" -tmpdir=$(mktemp -d) -cat > "$tmpdir/Dockerfile" <<'EOF' -FROM alpine:latest -EOF -for i in $(seq 1 50); do - echo "RUN dd if=/dev/zero of=/tmp/layer$i bs=1M count=20 && rm /tmp/layer$i" >> "$tmpdir/Dockerfile" -done -time docker build -q "$tmpdir" > /dev/null -rm -rf "$tmpdir" -echo "" - -# Test 6: Concurrent Container Operations -echo "Test 6: Concurrent Container Starts (20 parallel)" -time for _ in {1..20}; do - docker run --rm -d alpine:latest sleep 10 > /dev/null -done -docker ps -q | xargs -r docker stop > /dev/null 2>&1 || true -echo "" - -# Test 7: Volume Operations -echo "Test 7: Volume I/O Performance" -vol_name="benchmark-vol-$(date +%s)" -docker volume create "$vol_name" > /dev/null -echo " Writing 5GB to volume..." -docker run --rm -v "$vol_name":/data alpine:latest sh -c 'dd if=/dev/zero of=/data/test bs=1M count=5120 2>&1 | grep -E "copied|MB/s"' -echo " Reading 5GB from volume..." -docker run --rm -v "$vol_name":/data alpine:latest sh -c 'dd if=/data/test of=/dev/null bs=1M 2>&1 | grep -E "copied|MB/s"' -docker volume rm "$vol_name" > /dev/null -echo "" - -# Test 8: Image Layer Cache Performance -echo "Test 8: Build Cache Performance (rebuild same image 5 times)" -tmpdir=$(mktemp -d) -cat > "$tmpdir/Dockerfile" <<'EOF' -FROM python:latest -RUN pip install requests flask numpy pandas -RUN dd if=/dev/zero of=/tmp/data bs=1M count=200 -EOF -echo " First build (no cache):" -time docker build -q "$tmpdir" > /dev/null -echo " Rebuilds (with cache):" -for i in {1..4}; do - echo " Build $i:" - time docker build -q "$tmpdir" > /dev/null -done -rm -rf "$tmpdir" -echo "" - -# Test 9: Snapshot/Copy Performance -echo "Test 9: Container Commit Performance" -cid=$(docker run -d postgres:latest sleep 30) -time docker commit "$cid" benchmark-snapshot:latest > /dev/null -docker stop "$cid" > /dev/null 2>&1 || true -docker rm "$cid" > /dev/null 2>&1 || true -docker rmi benchmark-snapshot:latest > /dev/null 2>&1 || true -echo "" - -echo "=== Heavy Benchmark Complete ===" -echo "" -echo "Summary: Check the timing results above to compare storage drivers." -echo "Key metrics: Large image pulls, multi-stage builds, layer operations, and volume I/O." diff --git a/system/virtualisation/scripts/reset-container-state.nix b/system/virtualisation/scripts/reset-container-state.nix deleted file mode 100644 index 57435040..00000000 --- a/system/virtualisation/scripts/reset-container-state.nix +++ /dev/null @@ -1,6 +0,0 @@ -{pkgs, ...}: -pkgs.writeShellApplication { - name = "reset-container-state"; - runtimeInputs = with pkgs; [docker podman coreutils util-linux systemd]; - text = builtins.readFile ./reset-container-state.sh; -} diff --git a/system/virtualisation/scripts/reset-container-state.sh b/system/virtualisation/scripts/reset-container-state.sh deleted file mode 100644 index a54cdfc2..00000000 --- a/system/virtualisation/scripts/reset-container-state.sh +++ /dev/null @@ -1,96 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -# Reset container state for fair benchmarking -# This clears all images, containers, volumes, caches, and storage backends -# Works when switching between overlay2 and btrfs drivers - -echo "=== Resetting Container State ===" -echo "" - -# Check current storage driver before cleanup -echo "Current storage configuration:" -docker info 2>/dev/null | grep 'Storage Driver' || echo " Docker: not running" -podman info --format=json 2>/dev/null | grep -oP '"graphDriverName": "\K[^"]+' | sed 's/^/ Podman: /' || echo " Podman: not running" -echo "" - -# Stop all running containers (if services are running) -echo "Stopping all containers..." -containers=$(docker ps -aq 2>/dev/null || true) -if [ -n "$containers" ]; then - docker stop "$containers" 2>/dev/null || true - docker rm -f "$containers" 2>/dev/null || true -fi -podman stop -a 2>/dev/null || true -podman rm -a -f 2>/dev/null || true - -# Remove all images via API (cleans metadata properly) -echo "Removing all images..." -images=$(docker images -aq 2>/dev/null || true) -if [ -n "$images" ]; then - docker rmi -f "$images" 2>/dev/null || true -fi -podman rmi -a -f 2>/dev/null || true - -# Remove all volumes -echo "Removing all volumes..." -volumes=$(docker volume ls -q 2>/dev/null || true) -if [ -n "$volumes" ]; then - docker volume rm "$volumes" 2>/dev/null || true -fi -podman volume rm -a -f 2>/dev/null || true - -# Prune everything to clean build cache and metadata -echo "Pruning system..." -docker system prune -a -f --volumes 2>/dev/null || true -podman system prune -a -f --volumes 2>/dev/null || true - -# Stop services before cleaning storage -echo "Stopping Docker and Podman services..." -sudo systemctl stop docker.socket docker.service 2>/dev/null || true -sudo systemctl stop podman.socket podman.service 2>/dev/null || true - -# Wait for services to fully stop -sleep 2 - -# Remove all Docker storage (both overlay2 and btrfs) -echo "Removing all Docker storage backends..." -sudo rm -rf /var/lib/docker/* 2>/dev/null || true - -# Remove all Podman storage -echo "Removing all Podman storage..." -sudo rm -rf /var/lib/containers/storage/* 2>/dev/null || true -rm -rf ~/.local/share/containers/storage/* 2>/dev/null || true - -# Podman system reset (if podman can start) -echo "Resetting Podman state..." -podman system reset -f 2>/dev/null || true - -# Restart services with clean storage -echo "Restarting Docker and Podman services..." -sudo systemctl start docker.service -sudo systemctl start podman.service - -# Wait for services to be ready -sleep 3 - -# Verify clean state -echo "" -echo "Verifying clean state..." -docker images 2>/dev/null && echo " Docker: Clean (no images)" || echo " Docker: Service starting..." -podman images 2>/dev/null && echo " Podman: Clean (no images)" || echo " Podman: Service starting..." - -# Drop system caches for fair benchmarking -echo "" -echo "Dropping system caches..." -sudo sync -echo 3 | sudo tee /proc/sys/vm/drop_caches > /dev/null - -echo "" -echo "=== Container State Reset Complete ===" -echo "All storage backends (overlay2, btrfs) have been cleared." -echo "New storage driver configuration:" -docker info 2>/dev/null | grep 'Storage Driver' || echo " Docker: initializing..." -podman info --format=json 2>/dev/null | grep -oP '"graphDriverName": "\K[^"]+' | sed 's/^/ Podman: /' || echo " Podman: initializing..." -echo "" -echo "Ready to run benchmarks with clean storage!" diff --git a/system/wireshark/default.nix b/system/wireshark/default.nix deleted file mode 100644 index f3841246..00000000 --- a/system/wireshark/default.nix +++ /dev/null @@ -1,7 +0,0 @@ -{pkgs, ...}: { - environment.systemPackages = [pkgs.wireshark]; - programs.wireshark = { - enable = true; - }; - users.users.farlion.extraGroups = ["wireshark"]; -} From ceb6254c3db4b8e398458ce637f9b7d213ca26fe Mon Sep 17 00:00:00 2001 From: workflow <4farlion@gmail.com> Date: Sat, 31 Jan 2026 01:29:16 +0000 Subject: [PATCH 18/26] fix(dendritic): make GPU modules conditional on dendrix options AMD module now requires config.dendrix.hasAmd = true NVIDIA module now requires config.dendrix.hasNvidia = true --- parts/features/hardware/amd.nix | 5 +++-- parts/features/hardware/nvidia.nix | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/parts/features/hardware/amd.nix b/parts/features/hardware/amd.nix index d68f1d93..77819dd2 100644 --- a/parts/features/hardware/amd.nix +++ b/parts/features/hardware/amd.nix @@ -1,6 +1,7 @@ {...}: { - flake.modules.nixos.amd = {pkgs, ...}: { - hardware.amdgpu = { + flake.modules.nixos.amd = {config, lib, pkgs, ...}: + lib.mkIf config.dendrix.hasAmd { + hardware.amdgpu = { initrd.enable = true; opencl.enable = true; }; diff --git a/parts/features/hardware/nvidia.nix b/parts/features/hardware/nvidia.nix index 8e6af39c..27471cd3 100644 --- a/parts/features/hardware/nvidia.nix +++ b/parts/features/hardware/nvidia.nix @@ -1,6 +1,7 @@ {...}: { - flake.modules.nixos.nvidia = {pkgs, ...}: { - boot.blacklistedKernelModules = ["nouveau"]; + flake.modules.nixos.nvidia = {config, lib, pkgs, ...}: + lib.mkIf config.dendrix.hasNvidia { + boot.blacklistedKernelModules = ["nouveau"]; environment.systemPackages = [ pkgs.nvtopPackages.full pkgs.mesa-demos From e16760a158608f1d18d1c9d0e8f1a721a216f6ce Mon Sep 17 00:00:00 2001 From: workflow <4farlion@gmail.com> Date: Sat, 31 Jan 2026 02:16:27 +0000 Subject: [PATCH 19/26] refactor(secrets): switch to dendritic pattern as well --- flake.lock | 80 +++++++++++++++++++++++++++++++++---------------- parts/hosts.nix | 14 +++++++++ 2 files changed, 68 insertions(+), 26 deletions(-) diff --git a/flake.lock b/flake.lock index 20d49f50..918f9817 100644 --- a/flake.lock +++ b/flake.lock @@ -218,6 +218,24 @@ } }, "flake-parts_4": { + "inputs": { + "nixpkgs-lib": "nixpkgs-lib_2" + }, + "locked": { + "lastModified": 1768135262, + "narHash": "sha256-PVvu7OqHBGWN16zSi6tEmPwwHQ4rLPU9Plvs8/1TUBY=", + "owner": "hercules-ci", + "repo": "flake-parts", + "rev": "80daad04eddbbf5a4d883996a73f3f542fa437ac", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "flake-parts", + "type": "github" + } + }, + "flake-parts_5": { "inputs": { "nixpkgs-lib": [ "stylix", @@ -414,6 +432,21 @@ "type": "github" } }, + "import-tree_2": { + "locked": { + "lastModified": 1763762820, + "narHash": "sha256-ZvYKbFib3AEwiNMLsejb/CWs/OL/srFQ8AogkebEPF0=", + "owner": "vic", + "repo": "import-tree", + "rev": "3c23749d8013ec6daa1d7255057590e9ca726646", + "type": "github" + }, + "original": { + "owner": "vic", + "repo": "import-tree", + "type": "github" + } + }, "niri": { "inputs": { "niri-stable": "niri-stable", @@ -588,6 +621,21 @@ "type": "github" } }, + "nixpkgs-lib_2": { + "locked": { + "lastModified": 1765674936, + "narHash": "sha256-k00uTP4JNfmejrCLJOwdObYC9jHRrr/5M/a/8L2EIdo=", + "owner": "nix-community", + "repo": "nixpkgs.lib", + "rev": "2075416fcb47225d9b68ac469a5c4801a9c4dd85", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "nixpkgs.lib", + "type": "github" + } + }, "nixpkgs-regression": { "locked": { "lastModified": 1643052045, @@ -807,20 +855,21 @@ "nur": "nur", "rmob": "rmob", "secrets": "secrets", - "sops-nix": "sops-nix_2", + "sops-nix": "sops-nix", "stylix": "stylix", "zen-browser": "zen-browser" } }, "secrets": { "inputs": { + "flake-parts": "flake-parts_4", + "import-tree": "import-tree_2", "nixpkgs": [ "nixpkgs" - ], - "sops-nix": "sops-nix" + ] }, "locked": { - "narHash": "sha256-inUTNigfTrWwN6eW7gRLUK9FZJF5VMUUU8mcwL2paJQ=", + "narHash": "sha256-PIdEfPF/1myftasCBQKGVwFU+yiNC7/djYXOELYZBhA=", "path": "/home/farlion/code/nixos-secrets", "type": "path" }, @@ -830,27 +879,6 @@ } }, "sops-nix": { - "inputs": { - "nixpkgs": [ - "secrets", - "nixpkgs" - ] - }, - "locked": { - "lastModified": 1764021963, - "narHash": "sha256-1m84V2ROwNEbqeS9t37/mkry23GBhfMt8qb6aHHmjuc=", - "owner": "Mic92", - "repo": "sops-nix", - "rev": "c482a1c1bbe030be6688ed7dc84f7213f304f1ec", - "type": "github" - }, - "original": { - "owner": "Mic92", - "repo": "sops-nix", - "type": "github" - } - }, - "sops-nix_2": { "inputs": { "nixpkgs": [ "nixpkgs" @@ -877,7 +905,7 @@ "base16-helix": "base16-helix", "base16-vim": "base16-vim", "firefox-gnome-theme": "firefox-gnome-theme", - "flake-parts": "flake-parts_4", + "flake-parts": "flake-parts_5", "gnome-shell": "gnome-shell", "nixpkgs": "nixpkgs_8", "nur": "nur_2", diff --git a/parts/hosts.nix b/parts/hosts.nix index f5339bbb..d0d4af05 100644 --- a/parts/hosts.nix +++ b/parts/hosts.nix @@ -12,6 +12,17 @@ # All dendritic modules for home-manager homeManagerModules = builtins.attrValues config.flake.modules.homeManager; + # Secrets modules (CI-safe: when overridden with nixpkgs, these are empty) + secretNixosModules = + if (inputs.secrets ? modules.nixos) + then builtins.attrValues inputs.secrets.modules.nixos + else []; + + secretHomeModules = + if (inputs.secrets ? modules.homeManager) + then builtins.attrValues inputs.secrets.modules.homeManager + else []; + commonOverlays = { unstable = import inputs.nixos-unstable { system = "x86_64-linux"; @@ -80,9 +91,11 @@ backupFileExtension = "home-manager-backup"; sharedModules = homeManagerModules + ++ secretHomeModules ++ [ "${impermanence}/home-manager.nix" nur.modules.homeManager.default + sops-nix.homeManagerModules.sops # Note: stylix home-manager module is injected by stylix.nixosModules.stylix # Note: niri home-manager module is injected by niri.nixosModules.niri ]; @@ -102,6 +115,7 @@ modules = commonNixosModules ++ nixosModules + ++ secretNixosModules ++ [ # Host-specific hardware and settings hostModule From 372a4ed426ccda32bc43468f024a6f4548bedab3 Mon Sep 17 00:00:00 2001 From: workflow <4farlion@gmail.com> Date: Sat, 31 Jan 2026 02:21:38 +0000 Subject: [PATCH 20/26] feat(dendritic): add missing home-manager modules Modules that weren't migrated from home/: - asciinema, ddc-backlight, mullvad-browser, nix-inspect - pavucontrol, television, tomat, tray-tui, virtual-cable - witr, wluma, ytmdesktop, zen home-cleanup-todo.nix contains packages/settings from home/default.nix --- flake.lock | 2 +- parts/features/apps/asciinema.nix | 7 ++ parts/features/apps/ddc-backlight/default.nix | 11 ++ .../ddc-backlight/scripts/ddc-backlight.sh | 49 ++++++++ parts/features/apps/mullvad-browser.nix | 13 ++ parts/features/apps/nix-inspect.nix | 7 ++ parts/features/apps/pavucontrol.nix | 13 ++ parts/features/apps/television.nix | 16 +++ parts/features/apps/tomat.nix | 7 ++ parts/features/apps/tray-tui.nix | 7 ++ parts/features/apps/virtual-cable/default.nix | 22 ++++ .../apps/virtual-cable/scripts/obs-mic.sh | 13 ++ parts/features/apps/witr.nix | 5 + parts/features/apps/wluma.nix | 7 ++ parts/features/apps/ytmdesktop.nix | 26 ++++ parts/features/apps/zen.nix | 54 +++++++++ parts/features/core/home-cleanup-todo.nix | 114 ++++++++++++++++++ 17 files changed, 372 insertions(+), 1 deletion(-) create mode 100644 parts/features/apps/asciinema.nix create mode 100644 parts/features/apps/ddc-backlight/default.nix create mode 100644 parts/features/apps/ddc-backlight/scripts/ddc-backlight.sh create mode 100644 parts/features/apps/mullvad-browser.nix create mode 100644 parts/features/apps/nix-inspect.nix create mode 100644 parts/features/apps/pavucontrol.nix create mode 100644 parts/features/apps/television.nix create mode 100644 parts/features/apps/tomat.nix create mode 100644 parts/features/apps/tray-tui.nix create mode 100644 parts/features/apps/virtual-cable/default.nix create mode 100644 parts/features/apps/virtual-cable/scripts/obs-mic.sh create mode 100644 parts/features/apps/witr.nix create mode 100644 parts/features/apps/wluma.nix create mode 100644 parts/features/apps/ytmdesktop.nix create mode 100644 parts/features/apps/zen.nix create mode 100644 parts/features/core/home-cleanup-todo.nix diff --git a/flake.lock b/flake.lock index 918f9817..aad0eb5a 100644 --- a/flake.lock +++ b/flake.lock @@ -869,7 +869,7 @@ ] }, "locked": { - "narHash": "sha256-PIdEfPF/1myftasCBQKGVwFU+yiNC7/djYXOELYZBhA=", + "narHash": "sha256-txRuC5TI7WtW3jC/qAAu9s+iEokW0REEdDeXWRwIJbg=", "path": "/home/farlion/code/nixos-secrets", "type": "path" }, diff --git a/parts/features/apps/asciinema.nix b/parts/features/apps/asciinema.nix new file mode 100644 index 00000000..c3cd64fc --- /dev/null +++ b/parts/features/apps/asciinema.nix @@ -0,0 +1,7 @@ +{...}: { + flake.modules.homeManager.asciinema = {...}: { + programs.asciinema = { + enable = true; + }; + }; +} diff --git a/parts/features/apps/ddc-backlight/default.nix b/parts/features/apps/ddc-backlight/default.nix new file mode 100644 index 00000000..0c66b63d --- /dev/null +++ b/parts/features/apps/ddc-backlight/default.nix @@ -0,0 +1,11 @@ +{...}: { + flake.modules.homeManager.ddc-backlight = {pkgs, ...}: let + ddc-backlight = pkgs.writeShellApplication { + name = "ddc-backlight"; + runtimeInputs = [pkgs.ddcutil pkgs.coreutils pkgs.util-linux]; + text = builtins.readFile ./scripts/ddc-backlight.sh; + }; + in { + home.packages = [ddc-backlight pkgs.ddcutil]; + }; +} diff --git a/parts/features/apps/ddc-backlight/scripts/ddc-backlight.sh b/parts/features/apps/ddc-backlight/scripts/ddc-backlight.sh new file mode 100644 index 00000000..5921aa3a --- /dev/null +++ b/parts/features/apps/ddc-backlight/scripts/ddc-backlight.sh @@ -0,0 +1,49 @@ +# Usage: ./ddc_backlight.sh +BUS="$1" + +LOCK_FILE="/tmp/ddc_backlight.lock" + +# Deterministic delay based on bus number to stagger execution +# Each bus will delay a different amount (0-59 seconds) +DELAY=$((BUS * 7 % 60)) +sleep "$DELAY" + +# Prevent parallel execution, which can crash the kernel  +if ! flock --nonblock 9; then + # Return a temporary placeholder instead of waiting + echo "{\"percentage\":0}" + exit 0 +fi 9>"$LOCK_FILE" + +# Check if monitor is connected and turned on - with better error handling +# 1. Attempt to read the power state of the monitor using VCP code 0xD6 (Power Mode) +{ + timeout 2 ddcutil getvcp D6 -b "$BUS" >/dev/null + power_status=$? +} || { + power_status=1 +} + +if [ $power_status -ne 0 ]; then + # Failed to read power state -> no monitor or unresponsive + echo "{\"percentage\":0}" + exit 0 +fi + +# Otherwise, we can safely get brightness value without overloading the kernel... +{ + output=$(timeout 2 ddcutil getvcp 10 -b "$BUS" 2>&1) + status=$? +} || { + status=1 +} + +if [ $status -ne 0 ]; then + echo "{\"percentage\":0}" + exit 0 +fi + +# Extract percentage +percent=$(echo "$output" | awk -F'=' '/current value/ {gsub(/,.*$/, "", $2); print $2+0}') + +echo "{\"percentage\":${percent}}" diff --git a/parts/features/apps/mullvad-browser.nix b/parts/features/apps/mullvad-browser.nix new file mode 100644 index 00000000..41473b1f --- /dev/null +++ b/parts/features/apps/mullvad-browser.nix @@ -0,0 +1,13 @@ +{...}: { + flake.modules.homeManager.mullvad-browser = {lib, osConfig, pkgs, ...}: { + home.persistence."/persist" = lib.mkIf osConfig.dendrix.isImpermanent { + directories = [ + ".mullvad" + ]; + }; + + home.packages = [ + pkgs.mullvad-browser + ]; + }; +} diff --git a/parts/features/apps/nix-inspect.nix b/parts/features/apps/nix-inspect.nix new file mode 100644 index 00000000..65a0073c --- /dev/null +++ b/parts/features/apps/nix-inspect.nix @@ -0,0 +1,7 @@ +{...}: { + flake.modules.homeManager.nix-inspect = {pkgs, ...}: { + home.packages = [ + pkgs.nix-inspect + ]; + }; +} diff --git a/parts/features/apps/pavucontrol.nix b/parts/features/apps/pavucontrol.nix new file mode 100644 index 00000000..b7183694 --- /dev/null +++ b/parts/features/apps/pavucontrol.nix @@ -0,0 +1,13 @@ +{...}: { + flake.modules.homeManager.pavucontrol = {lib, osConfig, pkgs, ...}: { + home.persistence."/persist" = lib.mkIf osConfig.dendrix.isImpermanent { + files = [ + ".config/pavucontrol.ini" + ]; + }; + + home.packages = [ + pkgs.pavucontrol + ]; + }; +} diff --git a/parts/features/apps/television.nix b/parts/features/apps/television.nix new file mode 100644 index 00000000..0e1c63e0 --- /dev/null +++ b/parts/features/apps/television.nix @@ -0,0 +1,16 @@ +{...}: { + flake.modules.homeManager.television = {lib, osConfig, ...}: { + home.persistence."/persist" = lib.mkIf osConfig.dendrix.isImpermanent { + directories = [ + ".config/television/cable" + ]; + }; + + programs.television = { + enable = true; + }; + programs.nix-search-tv = { + enable = true; + }; + }; +} diff --git a/parts/features/apps/tomat.nix b/parts/features/apps/tomat.nix new file mode 100644 index 00000000..1ff37482 --- /dev/null +++ b/parts/features/apps/tomat.nix @@ -0,0 +1,7 @@ +{...}: { + flake.modules.homeManager.tomat = {...}: { + services.tomat = { + enable = true; + }; + }; +} diff --git a/parts/features/apps/tray-tui.nix b/parts/features/apps/tray-tui.nix new file mode 100644 index 00000000..82dbc6c6 --- /dev/null +++ b/parts/features/apps/tray-tui.nix @@ -0,0 +1,7 @@ +{...}: { + flake.modules.homeManager.tray-tui = {...}: { + programs.tray-tui = { + enable = true; + }; + }; +} diff --git a/parts/features/apps/virtual-cable/default.nix b/parts/features/apps/virtual-cable/default.nix new file mode 100644 index 00000000..092291ca --- /dev/null +++ b/parts/features/apps/virtual-cable/default.nix @@ -0,0 +1,22 @@ +{...}: { + flake.modules.homeManager.virtual-cable = {pkgs, ...}: let + obs-mic = pkgs.writers.writeBashBin "obs-mic" (builtins.readFile ./scripts/obs-mic.sh); + in { + home.packages = [obs-mic]; + + systemd.user.services.obs-mic = { + Unit = { + After = ["wireplumber.service"]; + Description = "Set up virtualMic and virtualSpeaker for OBS"; + Requires = ["wireplumber.service"]; + }; + Install.WantedBy = ["wireplumber.service"]; + Service = { + Environment = "PATH=$PATH:/run/current-system/sw/bin"; + ExecStartPre = "${pkgs.coreutils}/bin/sleep 5"; + ExecStart = "${obs-mic}/bin/obs-mic"; + Type = "oneshot"; + }; + }; + }; +} diff --git a/parts/features/apps/virtual-cable/scripts/obs-mic.sh b/parts/features/apps/virtual-cable/scripts/obs-mic.sh new file mode 100644 index 00000000..d63ca83d --- /dev/null +++ b/parts/features/apps/virtual-cable/scripts/obs-mic.sh @@ -0,0 +1,13 @@ +set -euo pipefail + +# Create a virtual sink that can be set as a monitor in OBS +if ! pactl list short sinks | grep -q ObsSpeaker; then + pactl load-module module-null-sink sink_name=ObsSpeaker sink_properties=device.description=VirtualSpeaker +fi + +# Link it with a virtual source that is visible in pulseaudio apps like Zoom +if ! pactl list short sources | grep -q ObsMic; then + pactl load-module module-null-sink media.class=Audio/Source/Virtual sink_name=ObsMic channel_map=front-left,front-right + pw-link ObsSpeaker:monitor_FL ObsMic:input_FL + pw-link ObsSpeaker:monitor_FR ObsMic:input_FR +fi diff --git a/parts/features/apps/witr.nix b/parts/features/apps/witr.nix new file mode 100644 index 00000000..d11b9242 --- /dev/null +++ b/parts/features/apps/witr.nix @@ -0,0 +1,5 @@ +{...}: { + flake.modules.homeManager.witr = {pkgs, ...}: { + home.packages = [pkgs.unstable.witr]; + }; +} diff --git a/parts/features/apps/wluma.nix b/parts/features/apps/wluma.nix new file mode 100644 index 00000000..49548e8d --- /dev/null +++ b/parts/features/apps/wluma.nix @@ -0,0 +1,7 @@ +{...}: { + flake.modules.homeManager.wluma = {lib, osConfig, ...}: { + services.wluma = lib.mkIf osConfig.dendrix.isLaptop { + enable = true; + }; + }; +} diff --git a/parts/features/apps/ytmdesktop.nix b/parts/features/apps/ytmdesktop.nix new file mode 100644 index 00000000..4239b9bc --- /dev/null +++ b/parts/features/apps/ytmdesktop.nix @@ -0,0 +1,26 @@ +{...}: { + flake.modules.homeManager.ytmdesktop = {lib, osConfig, pkgs, ...}: { + home.persistence."/persist" = lib.mkIf osConfig.dendrix.isImpermanent { + directories = [ + ".config/YouTube Music Desktop App" + ]; + }; + + home.packages = [ + pkgs.unstable.ytmdesktop + ]; + + xdg.desktopEntries.ytmdesktop = { + name = "YouTube Music Desktop App"; + genericName = "Music Player"; + comment = "YouTube Music Desktop App"; + exec = "${pkgs.unstable.ytmdesktop}/bin/ytmdesktop --password-store=\"gnome-libsecret\" %U"; + icon = "ytmdesktop"; + terminal = false; + type = "Application"; + categories = ["Audio" "AudioVideo" "Player"]; + mimeType = ["x-scheme-handler/ytmd"]; + startupNotify = true; + }; + }; +} diff --git a/parts/features/apps/zen.nix b/parts/features/apps/zen.nix new file mode 100644 index 00000000..7542a07f --- /dev/null +++ b/parts/features/apps/zen.nix @@ -0,0 +1,54 @@ +{inputs, ...}: { + flake.modules.homeManager.zen = { + config, + lib, + osConfig, + pkgs, + ... + }: let + zenNiriOpen = pkgs.writeShellApplication { + name = "zen-niri-open"; + runtimeInputs = [pkgs.niri pkgs.jq pkgs.coreutils config.programs.zen-browser.package]; + text = '' + zen_id=$(niri msg --json windows | jq -r '.[] | select(.app_id == "zen-browser" or .app_id == "zen") | .id' | head -n1 || true) + if [ -n "''${zen_id:-}" ]; then + niri msg action focus-window --id "$zen_id" >/dev/null 2>&1 || true + fi + exec ${config.programs.zen-browser.package}/bin/zen "$@" + ''; + }; + in { + home.persistence."/persist" = lib.mkIf osConfig.dendrix.isImpermanent { + directories = [ + ".zen" + ]; + }; + + home.packages = [zenNiriOpen]; + + imports = [ + inputs.zen-browser.homeModules.beta + ]; + + programs.zen-browser = { + enable = true; + profiles = { + main = { + extensions.packages = with pkgs.nur.repos.rycee.firefox-addons; [ + bitwarden + darkreader + ublock-origin + ]; + }; + }; + }; + + stylix.targets.zen-browser.profileNames = ["main"]; + + home.sessionVariables = { + BROWSER = "${zenNiriOpen}/bin/zen-niri-open"; + DEFAULT_BROWSER = "${zenNiriOpen}/bin/zen-niri-open"; + MOZ_LEGACY_PROFILES = 1; + }; + }; +} diff --git a/parts/features/core/home-cleanup-todo.nix b/parts/features/core/home-cleanup-todo.nix new file mode 100644 index 00000000..a28ed32f --- /dev/null +++ b/parts/features/core/home-cleanup-todo.nix @@ -0,0 +1,114 @@ +{inputs, ...}: { + flake.modules.homeManager.home-cleanup-todo = { + config, + lib, + osConfig, + pkgs, + ... + }: { + home.file."nixos-config" = { + source = config.lib.file.mkOutOfStoreSymlink "${config.home.homeDirectory}/code/nixos-config"; + target = "nixos-config"; + }; + + home.file.".config/home-manager/flake.nix" = { + source = config.lib.file.mkOutOfStoreSymlink "${config.home.homeDirectory}/code/nixos-config/flake.nix"; + }; + + home.packages = with pkgs; [ + alejandra + ast-grep + bc + bind + dconf + difftastic + dive + dmidecode + dnstracer + efivar + fast-cli + fastfetch + fd + ffmpeg-full + file + find-cursor + fortune + glow + gomatrix + google-chrome + gucharmap + hardinfo2 + home-manager + httpie + iftop + imagemagick + iotop-c + jq + kind + kdePackages.kruler + lazydocker + libnotify + libsecret + lm_sensors + lolcat + lsof + ncdu + nmap + nethogs + net-tools + neo-cowsay + nix-tree + oculante + kdePackages.okular + openssl + pdftk + pstree + q-text-as-data + inputs.rmob.defaultPackage.x86_64-linux + screenkey + smartmontools + s-tui + stress + tcpdump + traceroute + tree + unzip + usbutils + wdisplays + wf-recorder + wget + wireguard-tools + whois + wl-clipboard + xournalpp + yq + yt-dlp + zip + ]; + + home.sessionVariables = + { + PATH = "$HOME/bin:$PATH"; + NIXOS_CONFIG = "$HOME/code/nixos-config/"; + GC_INITIAL_HEAP_SIZE = "8G"; + DIRENV_LOG_FORMAT = ""; + NIXOS_OZONE_WL = "1"; + } + // lib.optionalAttrs osConfig.dendrix.hasNvidia { + LIBVA_DRIVER_NAME = "nvidia"; + }; + + programs.bat = { + enable = true; + }; + + programs.man = { + enable = true; + generateCaches = false; + }; + + programs.vscode = { + enable = true; + }; + }; +} From 0fc26bc879d8c8e04e3c58390915011f5b2640ac Mon Sep 17 00:00:00 2001 From: workflow <4farlion@gmail.com> Date: Sat, 31 Jan 2026 02:40:55 +0000 Subject: [PATCH 21/26] fix(dendritic): make btrfs and ddc-backlight conditional - Add isBtrfs dendrix option - btrfs module now requires config.dendrix.isBtrfs = true - ddc-backlight module now requires !osConfig.dendrix.isLaptop --- parts/features/apps/ddc-backlight/default.nix | 9 +++++---- parts/features/hardware/btrfs.nix | 19 ++++++++++--------- parts/hosts.nix | 7 +++++++ 3 files changed, 22 insertions(+), 13 deletions(-) diff --git a/parts/features/apps/ddc-backlight/default.nix b/parts/features/apps/ddc-backlight/default.nix index 0c66b63d..f4dfb129 100644 --- a/parts/features/apps/ddc-backlight/default.nix +++ b/parts/features/apps/ddc-backlight/default.nix @@ -1,11 +1,12 @@ {...}: { - flake.modules.homeManager.ddc-backlight = {pkgs, ...}: let + flake.modules.homeManager.ddc-backlight = {lib, osConfig, pkgs, ...}: let ddc-backlight = pkgs.writeShellApplication { name = "ddc-backlight"; runtimeInputs = [pkgs.ddcutil pkgs.coreutils pkgs.util-linux]; text = builtins.readFile ./scripts/ddc-backlight.sh; }; - in { - home.packages = [ddc-backlight pkgs.ddcutil]; - }; + in + lib.mkIf (!osConfig.dendrix.isLaptop) { + home.packages = [ddc-backlight pkgs.ddcutil]; + }; } diff --git a/parts/features/hardware/btrfs.nix b/parts/features/hardware/btrfs.nix index 32bc603b..2ceaa76b 100644 --- a/parts/features/hardware/btrfs.nix +++ b/parts/features/hardware/btrfs.nix @@ -1,13 +1,14 @@ {...}: { - flake.modules.nixos.btrfs = {config, lib, ...}: { - environment.persistence."/persist/system" = lib.mkIf config.dendrix.isImpermanent { - directories = ["/var/lib/btrfs"]; - }; + flake.modules.nixos.btrfs = {config, lib, ...}: + lib.mkIf config.dendrix.isBtrfs { + environment.persistence."/persist/system" = lib.mkIf config.dendrix.isImpermanent { + directories = ["/var/lib/btrfs"]; + }; - services.btrfs.autoScrub = { - enable = true; - interval = "monthly"; - fileSystems = ["/"]; + services.btrfs.autoScrub = { + enable = true; + interval = "monthly"; + fileSystems = ["/"]; + }; }; - }; } diff --git a/parts/hosts.nix b/parts/hosts.nix index d0d4af05..5e482cb6 100644 --- a/parts/hosts.nix +++ b/parts/hosts.nix @@ -57,6 +57,11 @@ default = false; description = "Whether this machine has an AMD GPU"; }; + isBtrfs = lib.mkOption { + type = lib.types.bool; + default = false; + description = "Whether this machine uses btrfs filesystem"; + }; stateVersion = lib.mkOption { type = lib.types.str; description = "NixOS state version for this host"; @@ -149,6 +154,7 @@ in { isImpermanent = false; hasNvidia = true; hasAmd = false; + isBtrfs = false; stateVersion = "22.05"; homeStateVersion = "22.05"; }; @@ -163,6 +169,7 @@ in { isImpermanent = true; hasNvidia = false; hasAmd = true; + isBtrfs = true; stateVersion = "24.11"; homeStateVersion = "24.11"; }; From 1bb77a485968a6ce387502ddded361af336fef8d Mon Sep 17 00:00:00 2001 From: workflow <4farlion@gmail.com> Date: Sat, 31 Jan 2026 02:47:25 +0000 Subject: [PATCH 22/26] fix(dendritic): update secrets --- flake.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flake.lock b/flake.lock index aad0eb5a..c8cf190c 100644 --- a/flake.lock +++ b/flake.lock @@ -869,7 +869,7 @@ ] }, "locked": { - "narHash": "sha256-txRuC5TI7WtW3jC/qAAu9s+iEokW0REEdDeXWRwIJbg=", + "narHash": "sha256-FNbZwVL02VrYCWCRaJR0kOgbfpxpQlqkeacQIGB/lYA=", "path": "/home/farlion/code/nixos-secrets", "type": "path" }, From a5123bd049aca2b6338445cebcc62ac08d2d7dcc Mon Sep 17 00:00:00 2001 From: workflow <4farlion@gmail.com> Date: Sat, 31 Jan 2026 02:50:29 +0000 Subject: [PATCH 23/26] fix(dendritic): comments and icons that disappeared in the migration --- flake.lock | 2 +- parts/features/desktop/niri/default.nix | 222 +++++++++++++++++----- parts/features/desktop/waybar/default.nix | 183 +++++++++--------- 3 files changed, 266 insertions(+), 141 deletions(-) diff --git a/flake.lock b/flake.lock index c8cf190c..684a33dc 100644 --- a/flake.lock +++ b/flake.lock @@ -869,7 +869,7 @@ ] }, "locked": { - "narHash": "sha256-FNbZwVL02VrYCWCRaJR0kOgbfpxpQlqkeacQIGB/lYA=", + "narHash": "sha256-9NRZ+HEqpm5UBPIzGgfPwewMTkjR64VW12ZzUswPzH0=", "path": "/home/farlion/code/nixos-secrets", "type": "path" }, diff --git a/parts/features/desktop/niri/default.nix b/parts/features/desktop/niri/default.nix index ed823c3e..ff591ba8 100644 --- a/parts/features/desktop/niri/default.nix +++ b/parts/features/desktop/niri/default.nix @@ -26,36 +26,42 @@ locker = "${pkgs.bash}/bin/bash -c '${pkgs.procps}/bin/pgrep -x swaylock || ${pkgs.swaylock-effects}/bin/swaylock --daemonize'"; suspender = "${pkgs.systemd}/bin/systemctl suspend-then-hibernate"; + # Wallpaper, until stylix supports it :) wallpaperSetter = pkgs.writeShellApplication { name = "niri-set-wallpaper"; runtimeInputs = [pkgs.swaybg pkgs.procps]; text = builtins.readFile ./_scripts/niri-set-wallpaper.sh; }; + # Window Picker a la rofi windowPicker = pkgs.writeShellApplication { name = "niri-pick-window"; runtimeInputs = [pkgs.niri pkgs.unstable.fuzzel pkgs.jq]; text = builtins.readFile ./_scripts/niri-pick-window.sh; }; + # Calculator via fuzzel + qalc fuzzelCalc = pkgs.writeShellApplication { name = "niri-qalc"; runtimeInputs = [pkgs.unstable.fuzzel pkgs.libqalculate pkgs.wl-clipboard pkgs.libnotify]; text = builtins.readFile ./_scripts/niri-qalc.sh; }; + # Workspace reorderer - maintains logical order after moving workspaces between monitors workspaceReorderer = pkgs.writeShellApplication { name = "niri-reorder-workspaces"; runtimeInputs = [pkgs.niri pkgs.jq]; text = builtins.readFile ./_scripts/niri-reorder-workspaces.sh; }; + # Auto-column - consumes new windows into columns on vertical monitors autoColumn = pkgs.writeShellApplication { name = "niri-auto-column"; runtimeInputs = [pkgs.niri pkgs.jq pkgs.coreutils]; text = builtins.readFile ./_scripts/niri-auto-column.sh; }; + # Open a command and move its window to a workspace once title matches openOnWorkspace = pkgs.writeShellApplication { name = "niri-open-on-workspace"; runtimeInputs = [pkgs.niri pkgs.jq]; @@ -96,16 +102,16 @@ listToAttrs (pairs prefixes (prefix: pairs suffixes (suffix: [(format prefix suffix)]))); in { home.packages = with pkgs; [ - brightnessctl - fuzzelCalc - hyprmagnifier - playerctl - qt5.qtwayland - swaybg - wallpaperSetter - windowPicker - workspaceReorderer - xwayland-satellite + brightnessctl # For brightness +/- keys + fuzzelCalc # niri-qalc + hyprmagnifier # Screen magnifier for Wayland + playerctl # For play/pause etc... controlling media players that implement MPRIS + qt5.qtwayland # Needed for QT_QPA_PLATFORM=wayland + swaybg # Minmal wallpaper setter for Sway + wallpaperSetter # Specialization-aware wallpaper setting + windowPicker # niri-pick-window + workspaceReorderer # niri-reorder-workspaces + xwayland-satellite # For apps that need Xwayland ]; programs.swaylock = { @@ -116,7 +122,7 @@ show-failed-attempts = true; ignore-empty-password = true; screenshots = true; - effect-pixelate = 10; + effect-pixelate = 10; # Pixellation level (higher = more pixelated) effect-blur = "7x5"; }; }; @@ -150,19 +156,25 @@ ]; }; + # Fix swayidle service dependencies for Niri/Wayland session + # Fails to boot with default settings systemd.user.services.swayidle = { Unit = { After = ["niri.service" "graphical-session.target"]; Wants = ["graphical-session.target"]; + # Override the default ConditionEnvironment to be less strict ConditionEnvironment = lib.mkForce []; }; Service = { + # Add a small delay to double-ensure Wayland display is ready ExecStartPre = "${pkgs.coreutils}/bin/sleep 2"; + # Restart the service if it fails (useful for session restarts) Restart = lib.mkForce "on-failure"; RestartSec = "5"; }; }; + # Auto-column service for vertical monitors systemd.user.services.niri-auto-column = lib.mkIf isNumenor { Unit = { Description = "Auto-consume windows into columns on vertical monitors"; @@ -174,24 +186,50 @@ Restart = "on-failure"; RestartSec = "5"; }; - Install.WantedBy = ["graphical-session.target"]; + Install = { + WantedBy = ["graphical-session.target"]; + }; }; programs.wleave.enable = true; + # Wallpaper, until stylix supports it :) home.file.".local/share/wallpapers/gruvbox-light.png".source = ./_wallpapers/gruvbox-light-rainbow.png; home.file.".local/share/wallpapers/gruvbox-dark.png".source = ./_wallpapers/gruvbox-dark-rainbow.png; + # TODO: Activate once the Niri flake supports niri 25.11 + # Per-output layout settings for vertical monitors (raw KDL - not exposed in niri-flake settings) + # programs.niri.config = + # lib.optionalString (leftScreen != null) '' + # output "${leftScreen}" { + # layout { + # default-column-width { proportion 1.0; } + # } + # } + # '' + # + lib.optionalString (rightScreen != null) '' + # output "${rightScreen}" { + # layout { + # default-column-width { proportion 1.0; } + # } + # } + # ''; programs.niri.settings = rec { - environment.NIXOS_OZONE_WL = "1"; + # Environment + environment = { + NIXOS_OZONE_WL = "1"; # Enable Ozone-Wayland for Electron apps and Chromium, see https://nixos.wiki/wiki/Wayland + }; + # Input Settings input = { - keyboard.xkb = { - layout = "us,de,ua,pt"; - options = "eurosign:e,terminate:ctrl_alt_bksp"; + keyboard = { + xkb = { + layout = "us,de,ua,pt"; + options = "eurosign:e,terminate:ctrl_alt_bksp"; + }; }; touchpad = { - dwt = true; + dwt = true; # Disable touchpad while typing disabled-on-external-mouse = false; natural-scroll = false; tap = true; @@ -200,28 +238,35 @@ focus-follows-mouse.enable = true; }; + # Cursor Settings cursor = { hide-after-inactive-ms = 3000; hide-when-typing = true; }; + # Startup spawn-at-startup = [ - {command = ["${pkgs.bash}/bin/bash" "-c" "sleep 10 && systemctl --user restart xdg-desktop-portal"];} + {command = ["${pkgs.bash}/bin/bash" "-c" "sleep 10 && systemctl --user restart xdg-desktop-portal"];} # Hacks around a timing prob with xdg-desktop-portal on first boot, see https://github.com/sodiboo/niri-flake/issues/509 {command = ["systemctl" "--user" "restart" "kanshi"];} {command = ["systemctl" "--user" "restart" "app-blueman@autostart"];} - {command = ["systemctl" "--user" "start" "gnome-keyring-ssh"];} + {command = ["systemctl" "--user" "start" "gnome-keyring-ssh"];} # Start GNOME Keyring SSH agent {command = ["obsidian"];} {command = ["ytmdesktop" "--password-store=gnome-libsecret"];} - {command = ["${wallpaperSetter}/bin/niri-set-wallpaper"];} + # {command = ["seahorse"];} # To unlock keyring + {command = ["${wallpaperSetter}/bin/niri-set-wallpaper"];} # Set wallpaper {command = ["wlsunset-waybar"];} {command = ["${openOnWorkspace}/bin/niri-open-on-workspace" "${workspaces."00".name}" "ChatGPT" "zen" "--new-window" "https://chatgpt.com/"];} {command = ["${openOnWorkspace}/bin/niri-open-on-workspace" "${workspaces."09".name}" "[Vv]ikunja" "zen" "--new-window" "https://vikunja.hyena-byzantine.ts.net/"];} ]; + # Window Rules + # Find app_id or title with `niri msg windows` window-rules = [ { - matches = [{app-id = "^obsidian$";}]; - open-on-workspace = " 7"; + matches = [ + {app-id = "^obsidian$";} + ]; + open-on-workspace = " 7"; } { matches = [ @@ -229,20 +274,27 @@ {app-id = "^teams-for-linux$";} {app-id = "^org.telegram.desktop$";} ]; - open-on-workspace = " 8"; + open-on-workspace = " 8"; } { - matches = [{app-id = "^YouTube Music Desktop App$";}]; - open-on-workspace = " 9"; + matches = [ + {app-id = "^YouTube Music Desktop App$";} + ]; + open-on-workspace = " 9"; } { - matches = [{title = ".*[Vv]ikunja.*";}]; - open-on-workspace = " 9"; + matches = [ + {title = ".*[Vv]ikunja.*";} + ]; + open-on-workspace = " 9"; } { - matches = [{title = ".*ChatGPT.*";}]; - open-on-workspace = " a"; + matches = [ + {title = ".*ChatGPT.*";} + ]; + open-on-workspace = " a"; } + # Floating windows { matches = [ {title = ".*Pavucontrol.*";} @@ -250,6 +302,7 @@ ]; open-floating = true; } + # Block from screencasting { matches = [ {app-id = "^Bitwarden$";} @@ -257,90 +310,110 @@ ]; block-out-from = "screen-capture"; } + # Screen Cast Target Highlight { - matches = [{is-window-cast-target = true;}]; + matches = [ + {is-window-cast-target = true;} + ]; border = { - active.color = "#f38ba8"; - inactive.color = "#7d0d2d"; + active = {color = "#f38ba8";}; + inactive = {color = "#7d0d2d";}; + }; + shadow = { + color = "#7d0d2d70"; }; - shadow.color = "#7d0d2d70"; tab-indicator = { - active.color = "#f38ba8"; - inactive.color = "#7d0d2d"; + active = {color = "#f38ba8";}; + inactive = {color = "#7d0d2d";}; }; } ]; + # Named Workspaces workspaces = { "00" = { - name = " a"; + name = " a"; open-on-output = rightScreen; }; "01" = { - name = " 1"; + name = " 1"; open-on-output = leftScreen; }; "02" = { - name = " 2"; + name = " 2"; open-on-output = mainScreen; }; "03" = { - name = " 3"; + name = " 3"; open-on-output = rightScreen; }; "04" = { - name = " 4"; + name = " 4"; open-on-output = mainScreen; }; "05" = { - name = " 5"; + name = " 5"; open-on-output = mainScreen; }; "06" = { - name = " 6"; + name = " 6"; open-on-output = mainScreen; }; "07" = { - name = " 7"; + name = " 7"; open-on-output = rightScreen; }; "08" = { - name = " 8"; + name = " 8"; open-on-output = mainScreen; }; "09" = { - name = " 9"; + name = " 9"; open-on-output = leftScreen; }; "10" = { - name = " 10"; + name = " 10"; open-on-output = mainScreen; }; }; + # Layout layout = { border = { enable = true; - width = 2; + width = 2; # Default 4 }; + default-column-width.proportion = 1. / 2.; - gaps = 4; + + gaps = 4; # Default 16 + preset-column-widths = [ {proportion = 1. / 2.;} {proportion = 1. / 3.;} {proportion = 2. / 3.;} ]; - shadow.enable = true; + + shadow = { + enable = true; + }; }; + # Style prefer-no-csd = true; - animations.workspace-switch.enable = false; - hotkey-overlay.skip-at-startup = true; + # Animations + animations = { + workspace-switch.enable = false; + }; + + # Keybindings + hotkey-overlay.skip-at-startup = true; binds = with config.lib.niri.actions; lib.attrsets.mergeAttrsList [ { "Mod+Shift+Slash".action = show-hotkey-overlay; + "Mod+Return".action = spawn "alacritty"; "Mod+Return".hotkey-overlay.title = "Open a Terminal: alacritty"; "Mod+D".action = spawn "fuzzel"; @@ -353,6 +426,7 @@ "Mod+z".hotkey-overlay.title = "Screen magnifier"; "Mod+Shift+z".action = power-off-monitors; "Mod+Shift+z".hotkey-overlay.title = "Power off Monitors"; + "XF86AudioRaiseVolume".action = spawn-sh "wpctl set-volume @DEFAULT_AUDIO_SINK@ 0.1+"; "XF86AudioRaiseVolume".allow-when-locked = true; "XF86AudioLowerVolume".action = spawn-sh "wpctl set-volume @DEFAULT_AUDIO_SINK@ 0.1-"; @@ -363,8 +437,10 @@ "XF86AudioMicMute".allow-when-locked = true; "XF86MonBrightnessUp".action = spawn-sh "brightnessctl --class=backlight set 10%+"; "XF86MonBrightnessUp".allow-when-locked = true; + "XF86MonBrightnessDown".action = spawn-sh "brightnessctl --class=backlight set 10%-"; "XF86MonBrightnessDown".allow-when-locked = true; + "Mod+Shift+Q".action = close-window; "Mod+Shift+Q".repeat = false; } @@ -419,22 +495,29 @@ { "Mod+BracketLeft".action = consume-or-expel-window-left; "Mod+BracketRight".action = consume-or-expel-window-right; + "Mod+Comma".action = consume-window-into-column; "Mod+Period".action = expel-window-from-column; + "Mod+R".action = switch-preset-column-width; "Mod+Shift+R".action = switch-preset-window-height; "Mod+Ctrl+R".action = reset-window-height; + "Mod+F".action = maximize-column; "Mod+Shift+F".action = fullscreen-window; "Mod+Ctrl+F".action = expand-column-to-available-width; + "Mod+C".action = center-column; "Mod+Ctrl+C".action = center-visible-columns; + "Mod+Minus".action = set-column-width "-10%"; "Mod+Equal".action = set-column-width "+10%"; "Mod+Shift+Minus".action = set-window-height "-10%"; "Mod+Shift+Equal".action = set-window-height "+10%"; + "Mod+V".action = toggle-window-floating; "Mod+Shift+V".action = switch-focus-between-floating-and-tiling; + "Mod+Shift+W".action = spawn-sh ( builtins.concatStringsSep "; " [ "systemctl --user restart waybar.service" @@ -442,26 +525,43 @@ ] ); "Mod+Shift+W".hotkey-overlay.title = "Restart Waybar"; + "Mod+Space".action = switch-layout "next"; "Mod+Shift+Space".action = switch-layout "prev"; + "Print".action.screenshot = []; "Print".hotkey-overlay.title = "Screenshot via Niri"; "Mod+Print".action = spawn "satty-screenshot"; "Mod+Print".hotkey-overlay.title = "Screenshot via Satty"; "Mod+Shift+Print".action.screenshot-screen = []; "Mod+Shift+Print".hotkey-overlay.title = "Instant Screenshot"; + + # Applications such as remote-desktop clients and software KVM switches may + # request that niri stops processing the keyboard shortcuts defined here + # so they may, for example, forward the key presses as-is to a remote machine. + # It's a good idea to bind an escape hatch to toggle the inhibitor, + # so a buggy application can't hold your session hostage. + # + # The allow-inhibiting=false property can be applied to other binds as well, + # which ensures niri always processes them, even when an inhibitor is active. "Mod+Shift+Escape".action = toggle-keyboard-shortcuts-inhibit; "Mod+Shift+Escape".allow-inhibiting = false; + "Ctrl+Alt+Delete".action = quit; } + { + # Dynamic Cast ([G]rab Window or Screen) "Mod+G".action = set-dynamic-cast-window; "Mod+Shift+G".action = set-dynamic-cast-monitor; "Mod+Delete".action = clear-dynamic-cast-target; + + # Fancy Moving "Mod+Tab".action = focus-window-down-or-column-right; "Mod+Shift+Tab".action = focus-window-up-or-column-left; } { + # Browser "Mod+b".action = spawn-sh ( if isNvidia then "brave --profile-directory='Default' --enable-features=VaapiVideoDecoder,VaapiVideoEncoder --password-store=seahorse" @@ -476,29 +576,49 @@ else "brave --profile-directory='Profile 1' --password-store=seahorse" ); "Mod+h".hotkey-overlay.hidden = true; + + # Cliphist via fuzzel "Mod+p".action = spawn "cliphist-fuzzel-img"; "Mod+p".hotkey-overlay.hidden = true; + # Single item clearing "Mod+Shift+p".action = spawn-sh "cliphist list | fuzzel --dmenu | cliphist delete"; "Mod+Shift+p".hotkey-overlay.hidden = true; + + # File Manager [n]avigate "Mod+n".action = spawn-sh "alacritty -e fish -ic lf"; "Mod+n".hotkey-overlay.hidden = true; + + # Calcu[M]athlator "Mod+m".action = spawn "${fuzzelCalc}/bin/niri-qalc"; "Mod+m".hotkey-overlay.title = "Calcu[M]athalor via qalculate"; + + # Logout and Power Menu "Mod+Pause".action = spawn "wleave"; + + # Network ([W]ifi) Selection "Mod+w".action = spawn "${pkgs.networkmanager_dmenu}/bin/networkmanager_dmenu"; "Mod+w".hotkey-overlay.hidden = true; + + # Overview "Mod+o".action = toggle-overview; "Mod+o".repeat = false; + + # Reorder Workspaces (after moving them around) "Mod+Shift+o".action = spawn "${workspaceReorderer}/bin/niri-reorder-workspaces"; "Mod+Shift+o".hotkey-overlay.title = "Re[o]rder workspaces to maintain logical order"; + + # Rofi[e]moji "Mod+e".action = spawn "rofimoji"; "Mod+e".hotkey-overlay.hidden = true; "Mod+Shift+e".action = spawn ["rofimoji" "--action" "clipboard"]; "Mod+Shift+e".hotkey-overlay.hidden = true; + + # [S]ound Switcher "Mod+s".action = spawn "sound-switcher"; "Mod+s".hotkey-overlay.hidden = true; } { + # OBS Studio Controls "Alt+F1".action = spawn "obs-main-scene"; "Alt+F1".hotkey-overlay.title = "OBS: Switch to Main Scene"; "Alt+F2".action = spawn "obs-screensharing"; diff --git a/parts/features/desktop/waybar/default.nix b/parts/features/desktop/waybar/default.nix index 8c877443..d8f61047 100644 --- a/parts/features/desktop/waybar/default.nix +++ b/parts/features/desktop/waybar/default.nix @@ -36,8 +36,8 @@ ]; systemd-failed-units = { - format = " {nr_failed} failed"; - format-ok = " 0"; + format = " {nr_failed} failed"; + format-ok = " 0"; hide-on-ok = false; on-click = "alacritty --command journalctl --pager-end --catalog --boot --priority 3..3 | lnav"; on-click-right = "alacritty --command isd"; @@ -53,7 +53,7 @@ }; cpu = { - format = " {usage}%"; + format = " {usage}%"; states = { info = 80; }; @@ -63,7 +63,7 @@ "temperature#cpu" = { critical-threshold = 90; - format = " {temperatureC}°C"; + format = " {temperatureC}°C"; on-click = "alacritty --command btop"; on-click-right = "alacritty --command btop"; hwmon-path = @@ -75,8 +75,8 @@ "custom/cpu-profile-toggler" = { format = "{icon}"; format-icons = { - performance = ""; - powersave = ""; + performance = ""; + powersave = ""; }; exec = "cpu-profile-toggler"; on-click = "auto-cpufreq-gtk"; @@ -87,7 +87,7 @@ }; memory = { - format = " {percentage}%"; + format = " {percentage}%"; states = { warning = 60; critical = 80; @@ -98,7 +98,7 @@ }; disk = { - format = " {percentage_used}%"; + format = " {percentage_used}%"; on-click = "alacritty --command ncdu /"; on-click-right = "alacritty --command btop"; states = { @@ -122,7 +122,7 @@ "custom/gpu-usage" = { exec = "cat /sys/class/hwmon/hwmon1/device/gpu_busy_percent"; - format = " {}%"; + format = " {}%"; return-type = ""; interval = 1; on-click = "alacritty --command nvtop"; @@ -130,8 +130,8 @@ }; "custom/nvidia" = { - exec = "nvidia-smi --query-gpu=utilization.gpu,temperature.gpu --format=csv,nounits,noheader | sed 's/\\([0-9]\\+\\), \\([0-9]\\+\\)/\\1% \\2°C/g'"; - format = " {}"; + exec = "nvidia-smi --query-gpu=utilization.gpu,temperature.gpu --format=csv,nounits,noheader | sed 's/\\([0-9]\\+\\), \\([0-9]\\+\\)/\\1%  \\2°C/g'"; + format = " {}"; interval = 2; on-click = "alacritty --command nvtop"; on-click-right = "alacritty --command nvtop"; @@ -154,15 +154,15 @@ "network" = { interval = 3; - format = " "; - format-disconnected = " "; - format-ethernet = " "; - format-wifi = " "; - format-linked = " 🚧"; - format-alt = "{bandwidthDownBytes} {bandwidthUpBytes}"; - tooltip-format = "IF:{ifname} SSID:{essid} FREQ:{frequency} :{signalStrength} IP:{ipaddr} GW:{gwaddr} NM:{netmask} {bandwidthDownBytes} {bandwidthUpBytes}"; - tooltip-format-ethernet = "IF:{ifname} IP:{ipaddr} NM:{netmask} {bandwidthDownBytes} {bandwidthUpBytes}"; - tooltip-format-wifi = "IF:{ifname} SSID:{essid} FREQ:{frequency} :{signalStrength} IP:{ipaddr} GW:{gwaddr} NM:{netmask} {bandwidthDownBytes} {bandwidthUpBytes}"; + format = " "; + format-disconnected = " "; + format-ethernet = " "; + format-wifi = " "; + format-linked = " 🚧"; + format-alt = "{bandwidthDownBytes} {bandwidthUpBytes}"; + tooltip-format = "IF:{ifname} SSID:{essid} FREQ:{frequency} :{signalStrength} IP:{ipaddr} GW:{gwaddr} NM:{netmask} {bandwidthDownBytes} {bandwidthUpBytes}"; + tooltip-format-ethernet = "IF:{ifname} IP:{ipaddr} NM:{netmask} {bandwidthDownBytes} {bandwidthUpBytes}"; + tooltip-format-wifi = "IF:{ifname} SSID:{essid} FREQ:{frequency} :{signalStrength} IP:{ipaddr} GW:{gwaddr} NM:{netmask} {bandwidthDownBytes} {bandwidthUpBytes}"; tooltip-format-linked = "IF:{ifname} IP:{ipaddr} Connected but no internet"; on-click-right = "alacritty --command nmtui"; }; @@ -170,11 +170,11 @@ "network#tailscale" = { interface = "tailscale0"; interval = 3; - format-linked = " "; - format = " "; - format-alt = " {bandwidthDownBytes} {bandwidthUpBytes}"; - tooltip-format = " Tailscale IP:{ipaddr} NM:{netmask} {bandwidthDownBytes} {bandwidthUpBytes}"; - tooltip-format-linked = " Tailscale down. Right click to connect."; + format-linked = " "; + format = " "; + format-alt = " {bandwidthDownBytes} {bandwidthUpBytes}"; + tooltip-format = " Tailscale IP:{ipaddr} NM:{netmask} {bandwidthDownBytes} {bandwidthUpBytes}"; + tooltip-format-linked = " Tailscale down. Right click to connect."; on-click-right = "tailscale up"; on-click-middle = "tailscale down"; }; @@ -185,11 +185,11 @@ interval = 3; format = "{icon}"; format-icons = { - up = ""; - down = ""; - error = "❌"; + up = ""; + down = ""; + error = "❌"; }; - tooltip-format = " MacGyver is {text}"; + tooltip-format = " MacGyver is {text}"; on-click-right = "sudo systemctl start macgyver"; on-click-middle = "sudo systemctl stop macgyver"; }; @@ -197,14 +197,14 @@ "network#mullvad" = { interface = "wg0-mullvad"; interval = 3; - format-disconnected = " "; - format-disabled = " "; - format-linked = " "; - format = " "; - format-alt = " {bandwidthDownBytes} {bandwidthUpBytes}"; - tooltip-format = " Mullvad IP:{ipaddr} NM:{netmask} {bandwidthDownBytes} {bandwidthUpBytes}"; - tooltip-format-linked = " Mullvad down. Right click to connect or double right click for GUI."; - tooltip-format-disabled = " Mullvad down. Rickt click to connect or double right click for GUI."; + format-disconnected = " "; + format-disabled = " "; + format-linked = " "; + format = " "; + format-alt = " {bandwidthDownBytes} {bandwidthUpBytes}"; + tooltip-format = " Mullvad IP:{ipaddr} NM:{netmask} {bandwidthDownBytes} {bandwidthUpBytes}"; + tooltip-format-linked = " Mullvad down. Right click to connect or double right click for GUI."; + tooltip-format-disabled = " Mullvad down. Rickt click to connect or double right click for GUI."; on-click-right = "mullvad connect"; on-double-click-right = "mullvad-gui"; on-click-middle = "mullvad disconnect"; @@ -213,14 +213,14 @@ "network#wireguard" = { interface = "wg0"; interval = 3; - format-disconnected = " "; - format-disabled = " "; - format-linked = " "; - format = " "; - format-alt = " {bandwidthDownBytes} {bandwidthUpBytes}"; - tooltip-format = " Wireguard IP:{ipaddr} GW:{gwaddr} NM:{netmask} {bandwidthDownBytes} {bandwidthUpBytes}"; - tooltip-format-linked = " Wireguard down."; - tooltip-format-disabled = " Wireguard down."; + format-disconnected = " "; + format-disabled = " "; + format-linked = " "; + format = " "; + format-alt = " {bandwidthDownBytes} {bandwidthUpBytes}"; + tooltip-format = " Wireguard IP:{ipaddr} GW:{gwaddr} NM:{netmask} {bandwidthDownBytes} {bandwidthUpBytes}"; + tooltip-format-linked = " Wireguard down."; + tooltip-format-disabled = " Wireguard down."; }; "group/screens" = { @@ -236,11 +236,14 @@ format-icons = ["🌑" "🌘" "🌗" "🌖" "🌕"]; }; + # Direct ddcutil control - required for monitors that only expose VCP Feature 10 (Brightness) + # rather than the "Backlight Level White" feature that ddcci-driver-linux requires + # See https://gitlab.com/ddcci-driver-linux/ddcci-driver-linux "custom/ddc-backlight-left" = { format = "{icon} "; tooltip-format = "Left {percentage}%"; format-icons = ["🌑" "🌘" "🌗" "🌖" "🌕"]; - exec = "ddc-backlight 7"; + exec = "ddc-backlight 7"; # For i2c-7 exec-on-event = false; on-scroll-up = "flock /tmp/ddc_backlight.lock ddcutil setvcp 10 + 5 -b 7"; on-scroll-down = "flock /tmp/ddc_backlight.lock ddcutil setvcp 10 - 5 -b 7"; @@ -255,7 +258,7 @@ format = "{icon} "; tooltip-format = "Middle {percentage}%"; format-icons = ["🌑" "🌘" "🌗" "🌖" "🌕"]; - exec = "ddc-backlight 9"; + exec = "ddc-backlight 9"; # For i2c-9 exec-on-event = false; on-scroll-up = "flock /tmp/ddc_backlight.lock ddcutil setvcp 10 + 5 -b 9"; on-scroll-down = "flock /tmp/ddc_backlight.lock ddcutil setvcp 10 - 5 -b 9"; @@ -270,7 +273,7 @@ format = "{icon}"; tooltip-format = "Right {percentage}%"; format-icons = ["🌑" "🌘" "🌗" "🌖" "🌕"]; - exec = "ddc-backlight 6"; + exec = "ddc-backlight 6"; # For i2c-6 exec-on-event = false; on-scroll-up = "flock /tmp/ddc_backlight.lock ddcutil setvcp 10 + 5 -b 6"; on-scroll-down = "flock /tmp/ddc_backlight.lock ddcutil setvcp 10 - 5 -b 6"; @@ -288,10 +291,10 @@ return-type = "json"; format = " {icon}"; tooltip-format = "wlsunset: {alt}"; - signal = 1; + signal = 1; # SIGRTMIN+1 or 35 for updating immediately from script format-icons = { - on = ""; - off = ""; + on = ""; + off = ""; }; }; @@ -306,12 +309,12 @@ "pulseaudio#in" = { format = "{format_source}"; - format-source = " {volume}%"; - format-source-muted = ""; + format-source = " {volume}%"; + format-source-muted = ""; format-icons = { - "bluez_input.DC:69:E2:9A:6E:30" = ""; - "alsa_input.usb-Apple__Inc._USB-C_to_3.5mm_Headphone_Jack_Adapter_DWH84440324JKLTA7-00.mono-fallback" = ""; - default = ["" ""]; + "bluez_input.DC:69:E2:9A:6E:30" = ""; + "alsa_input.usb-Apple__Inc._USB-C_to_3.5mm_Headphone_Jack_Adapter_DWH84440324JKLTA7-00.mono-fallback" = ""; + default = ["" ""]; }; max-volume = 200; scroll-step = 5; @@ -325,25 +328,25 @@ "pulseaudio#out" = { format = "{icon} {volume}%"; - format-bluetooth = "{icon} {volume}%"; - format-muted = ""; + format-bluetooth = "{icon} {volume}%"; + format-muted = ""; format-icons = { - "alsa_output.usb-Generic_USB_Audio-00.analog-stereo" = ""; - "alsa_output.usb-Lenovo_ThinkPad_Thunderbolt_3_Dock_USB_Audio_000000000000-00.analog-stereo" = ""; - "bluez_output.14_3F_A6_28_DC_51.1" = ""; + "alsa_output.usb-Generic_USB_Audio-00.analog-stereo" = ""; + "alsa_output.usb-Lenovo_ThinkPad_Thunderbolt_3_Dock_USB_Audio_000000000000-00.analog-stereo" = ""; + "bluez_output.14_3F_A6_28_DC_51.1" = ""; "alsa_output.pci-0000_03_00.1.hdmi-stereo-extra3" = "🍿"; - "bluez_output.DC_69_E2_9A_6E_30.1" = ""; - "bluez_sink.DC_69_E2_9A_6E_30.handsfree_head_unit" = ""; - "alsa_output.pci-0000_00_1f.3-platform-sof_sdw.HiFi___ucm0003.hw_sofsoundwire_2__sink" = ""; - "alsa_output.pci-0000_00_1f.3-platform-sof_sdw.HiFi___ucm0005.hw_sofsoundwire_2__sink" = ""; - "alsa_output.pci-0000_00_1f.3-platform-sof_sdw.HiFi___ucm0007.hw_sofsoundwire_2__sink" = ""; - "alsa_output.pci-0000_00_1f.3-platform-sof_sdw.HiFi__hw_sofsoundwire_2__sink" = ""; - "alsa_output.pci-0000_00_1f.3-platform-sof_sdw.HiFi__Speaker__sink" = ""; - "alsa_output.pci-0000_00_1f.3-platform-sof_sdw.HiFi__hw_sofsoundwire__sink" = ""; - "alsa_output.usb-Apple__Inc._USB-C_to_3.5mm_Headphone_Jack_Adapter_DWH84440324JKLTA7-00.analog-stereo" = ""; - "bluez_output.34_E3_FB_C5_01_E0.1" = ""; - "bluez_sink.34_E3_FB_C5_01_E0.handsfree_head_unit" = ""; - default = ["" ""]; + "bluez_output.DC_69_E2_9A_6E_30.1" = ""; + "bluez_sink.DC_69_E2_9A_6E_30.handsfree_head_unit" = ""; + "alsa_output.pci-0000_00_1f.3-platform-sof_sdw.HiFi___ucm0003.hw_sofsoundwire_2__sink" = ""; + "alsa_output.pci-0000_00_1f.3-platform-sof_sdw.HiFi___ucm0005.hw_sofsoundwire_2__sink" = ""; + "alsa_output.pci-0000_00_1f.3-platform-sof_sdw.HiFi___ucm0007.hw_sofsoundwire_2__sink" = ""; + "alsa_output.pci-0000_00_1f.3-platform-sof_sdw.HiFi__hw_sofsoundwire_2__sink" = ""; + "alsa_output.pci-0000_00_1f.3-platform-sof_sdw.HiFi__Speaker__sink" = ""; + "alsa_output.pci-0000_00_1f.3-platform-sof_sdw.HiFi__hw_sofsoundwire__sink" = ""; + "alsa_output.usb-Apple__Inc._USB-C_to_3.5mm_Headphone_Jack_Adapter_DWH84440324JKLTA7-00.analog-stereo" = ""; + "bluez_output.34_E3_FB_C5_01_E0.1" = ""; + "bluez_sink.34_E3_FB_C5_01_E0.handsfree_head_unit" = ""; + default = ["" ""]; }; max-volume = 200; on-click = "pavucontrol --tab=3"; @@ -358,8 +361,8 @@ on-click-right = ''niri msg action focus-window --id $(niri msg --json windows | jq -r '.[] | select(.app_id == "YouTube Music Desktop App") | .id')''; player-icons = { default = "▶"; - mpv = ""; - chromium = ""; + mpv = ""; + chromium = ""; }; status-icons = { paused = "⏸"; @@ -371,12 +374,12 @@ format-connected = "{icon} {num_connections}"; format-connnected-battery = "{icon} {num_connections} {device_battery_percentage}%"; format-icons = { - connected = ""; - on = ""; - off = ""; - disabled = ""; - disconnected = ""; - default = ""; + connected = ""; + on = ""; + off = ""; + disabled = ""; + disconnected = ""; + default = ""; }; on-click = "bluetoothctl power on"; on-click-right = "bluetoothctl power off"; @@ -402,7 +405,7 @@ critical = 15; }; format = " {icon} {capacity}%"; - format-icons = ["" "" "" "" ""]; + format-icons = ["" "" "" "" ""]; tooltip = true; backend = "upower"; }; @@ -425,8 +428,8 @@ format = "{icon}{text}"; tooltip-format = "{text}"; format-icons = { - running = ""; - dnd = ""; + running = ""; + dnd = ""; }; on-click = "dunstctl set-paused toggle"; on-click-right = "dunstctl set-paused false"; @@ -438,8 +441,8 @@ interval = 1; format = " {icon}"; format-icons = { - activated = ""; - deactivated = ""; + activated = ""; + deactivated = ""; }; on-click = "systemctl --user stop swayidle"; on-click-right = "systemctl --user start swayidle"; @@ -455,7 +458,7 @@ clock = { format = "{:%H:%M}"; - format-alt = "{:%A, %B %d, %Y (%R)} "; + format-alt = "{:%A, %B %d, %Y (%R)}  "; tooltip-format = "{calendar}"; calendar = { mode = "year"; @@ -493,8 +496,8 @@ position = "bottom"; expand-center = true; output = [ - "DP-1" - "eDP-1" + "DP-1" # Numenor main screen + "eDP-1" # Flexbox ]; } // leftSection // centerSection // rightSection; @@ -565,7 +568,9 @@ }; systemd.user.services.waybar = { + # Give on-click commands access to binaries they need Service.Environment = lib.mkForce "PATH=/run/wrappers/bin:${config.home.profileDirectory}/bin:/run/current-system/sw/bin"; + # Fix for niri startup Install.WantedBy = lib.mkForce ["niri.service"]; Unit.Requires = ["niri.service"]; Unit.After = ["niri.service"]; From 18ae4f621744c2ece530bca7f4292a374d9f5577 Mon Sep 17 00:00:00 2001 From: workflow <4farlion@gmail.com> Date: Tue, 3 Feb 2026 09:26:06 +0000 Subject: [PATCH 24/26] fix(dendritic): restore remaining comments and LF icons from migration --- flake.lock | 2 +- parts/features/apps/alacritty.nix | 2 +- parts/features/apps/brave-browser.nix | 3 +- parts/features/apps/calibre.nix | 1 + .../apps/cpu-profile-toggler/default.nix | 1 + parts/features/apps/fish.nix | 10 +- .../apps/fix-flexbox-mike/default.nix | 1 + parts/features/apps/gnome-connections.nix | 6 +- parts/features/apps/hoppscotch.nix | 5 +- parts/features/apps/hwatch.nix | 1 + parts/features/apps/isd.nix | 1 + parts/features/apps/jqp.nix | 1 + .../apps/kind-with-local-registry/default.nix | 3 + parts/features/apps/kubernetes-tools.nix | 4 +- parts/features/apps/lf/default.nix | 330 +++++++++--------- parts/features/apps/libation.nix | 1 + parts/features/apps/lnav.nix | 1 + .../apps/mic-levels-maintainer/default.nix | 1 + parts/features/apps/mpv.nix | 1 + parts/features/apps/nautilus.nix | 1 + parts/features/apps/nix-index.nix | 2 +- parts/features/apps/nushell/default.nix | 1 + parts/features/apps/obs/default.nix | 1 + parts/features/apps/onboard.nix | 1 + parts/features/apps/pavucontrol.nix | 1 + parts/features/apps/pgcli.nix | 1 + parts/features/apps/psql/default.nix | 1 + parts/features/apps/qalculate.nix | 1 + parts/features/apps/ripgrep-all.nix | 1 + parts/features/apps/rofimoji/default.nix | 2 +- parts/features/apps/satty/default.nix | 1 + parts/features/apps/showmethekey.nix | 1 + parts/features/apps/solaar.nix | 1 + .../features/apps/sound-switcher/default.nix | 1 + parts/features/apps/ssh/default.nix | 2 + .../default.nix | 1 + parts/features/apps/television.nix | 1 + parts/features/apps/tray-tui.nix | 1 + parts/features/apps/urxvt.nix | 4 + parts/features/apps/variety/default.nix | 1 + parts/features/apps/virtual-cable/default.nix | 3 +- parts/features/apps/witr.nix | 1 + parts/features/apps/wluma.nix | 1 + parts/features/apps/xdg.nix | 9 +- parts/features/apps/ytmdesktop.nix | 2 + parts/features/apps/zen.nix | 3 +- parts/features/apps/zoxide.nix | 4 +- parts/features/core/dns.nix | 4 +- parts/features/core/fonts/default.nix | 9 +- parts/features/core/home-cleanup-todo.nix | 99 +++--- parts/features/core/impermanence.nix | 30 +- parts/features/core/kernel.nix | 11 +- parts/features/core/networking/default.nix | 31 +- parts/features/core/performance.nix | 2 +- parts/features/core/users.nix | 4 +- parts/features/desktop/cliphist.nix | 3 +- parts/features/desktop/gtk-qt.nix | 9 +- parts/features/desktop/kanshi.nix | 1 + parts/features/desktop/udiskie.nix | 4 + parts/features/desktop/wlsunset/default.nix | 2 + parts/features/dev/claude-code/default.nix | 7 +- parts/features/dev/devenv.nix | 1 + parts/features/dev/direnv.nix | 2 +- parts/features/dev/git-worktree-switcher.nix | 1 + parts/features/dev/git/default.nix | 9 +- parts/features/dev/git/gh.config.yml | 5 + parts/features/dev/jujutsu.nix | 2 +- parts/features/dev/k9s/default.nix | 1 + parts/features/dev/neovim/default.nix | 53 +-- parts/features/hardware/amd.nix | 17 +- parts/features/hardware/audio.nix | 22 +- parts/features/hardware/bluetooth.nix | 1 + parts/features/hardware/btrfs.nix | 6 +- parts/features/hardware/firmware.nix | 1 + parts/features/hardware/io.nix | 3 + parts/features/hardware/nvidia.nix | 28 +- parts/features/hardware/power.nix | 4 +- parts/features/hardware/video.nix | 4 +- parts/features/security/security.nix | 25 +- parts/features/security/yubico/default.nix | 6 +- parts/features/services/kind-killer.nix | 2 +- parts/features/services/syncthing.nix | 4 +- .../services/virtualisation/default.nix | 26 +- 83 files changed, 540 insertions(+), 324 deletions(-) diff --git a/flake.lock b/flake.lock index 684a33dc..5c0e8d6f 100644 --- a/flake.lock +++ b/flake.lock @@ -869,7 +869,7 @@ ] }, "locked": { - "narHash": "sha256-9NRZ+HEqpm5UBPIzGgfPwewMTkjR64VW12ZzUswPzH0=", + "narHash": "sha256-pd7VsNIiRrgwdD/4NDMfW8h55H+6AFA5brwOen2u6Fc=", "path": "/home/farlion/code/nixos-secrets", "type": "path" }, diff --git a/parts/features/apps/alacritty.nix b/parts/features/apps/alacritty.nix index b47b9ded..62e15b1f 100644 --- a/parts/features/apps/alacritty.nix +++ b/parts/features/apps/alacritty.nix @@ -51,7 +51,7 @@ ]; env = { - TERM = "xterm-256color"; + TERM = "xterm-256color"; # Better color support in some apps }; scrolling = { diff --git a/parts/features/apps/brave-browser.nix b/parts/features/apps/brave-browser.nix index 5c480826..51209043 100644 --- a/parts/features/apps/brave-browser.nix +++ b/parts/features/apps/brave-browser.nix @@ -6,6 +6,7 @@ ... }: let isNvidia = osConfig.dendrix.hasNvidia; + # Try to focus an existing Brave window on link open so the workspace comes to the foreground braveNiriOpen = pkgs.writeShellApplication { name = "brave-niri-open"; runtimeInputs = [pkgs.niri pkgs.jq pkgs.coreutils pkgs.brave]; @@ -18,7 +19,7 @@ fi exec ${pkgs.brave}/bin/brave ${ if isNvidia - then "--enable-features=VaapiVideoDecoder,VaapiVideoEncoder --password-store=seahorse" + then "" else "--password-store=seahorse" } "$@" ''; diff --git a/parts/features/apps/calibre.nix b/parts/features/apps/calibre.nix index ba6756c9..74bd8606 100644 --- a/parts/features/apps/calibre.nix +++ b/parts/features/apps/calibre.nix @@ -1,3 +1,4 @@ +# Ebook reader {...}: { flake.modules.homeManager.calibre = { osConfig, diff --git a/parts/features/apps/cpu-profile-toggler/default.nix b/parts/features/apps/cpu-profile-toggler/default.nix index 005c4558..e26e273e 100644 --- a/parts/features/apps/cpu-profile-toggler/default.nix +++ b/parts/features/apps/cpu-profile-toggler/default.nix @@ -1,3 +1,4 @@ +# Toggle CPU profiles {...}: { flake.modules.homeManager.cpu-profile-toggler = {pkgs, ...}: let cpu-profile-toggler = pkgs.writeShellApplication { diff --git a/parts/features/apps/fish.nix b/parts/features/apps/fish.nix index dc8c7f58..a6f4c475 100644 --- a/parts/features/apps/fish.nix +++ b/parts/features/apps/fish.nix @@ -36,6 +36,10 @@ bind --mode insert '$' __history_previous_command_arguments ''; + ## Wrap LF to add ability to quit with Q in current directory + ## + ## Adapted for fish from https://github.com/gokcehan/lf/wiki/Tips#cd-to-current-directory-on-quit + ## lf = /* fish @@ -69,6 +73,8 @@ | pup 'textarea#translated json{}' | jq -r '.[0].text' ''; + # Source .env files + # Source: http://lewandowski.io/2016/10/fish-env/ posix-source = /* fish @@ -115,7 +121,7 @@ home.persistence."/persist" = lib.mkIf osConfig.dendrix.isImpermanent { directories = [ ".config/fish" - ".local/share/fish" + ".local/share/fish" # contains some unecessary state, but https://github.com/fish-shell/fish-shell/issues/10730 prevents us from only syncing the history file (.local/share/fish/fish_history) ]; }; @@ -126,6 +132,8 @@ shellAbbrs = config.home.shellAliases // { + # Fish/bash-specific aliases that aren't compatible with nushell + # Use bashInteractive to ensure bind command is available bash = "${config.programs.bash.package}/bin/bash"; cc = "tee /dev/tty | wl-copy"; dark-theme = "nh os test --no-specialisation && niri-set-wallpaper"; diff --git a/parts/features/apps/fix-flexbox-mike/default.nix b/parts/features/apps/fix-flexbox-mike/default.nix index 21e13935..a19ad346 100644 --- a/parts/features/apps/fix-flexbox-mike/default.nix +++ b/parts/features/apps/fix-flexbox-mike/default.nix @@ -1,3 +1,4 @@ +# Fix ALSA not detecting microphone on XPS 9700, see https://github.com/NixOS/nixpkgs/issues/130882#issuecomment-2584286824 {...}: { flake.modules.homeManager.fix-flexbox-mike = { lib, diff --git a/parts/features/apps/gnome-connections.nix b/parts/features/apps/gnome-connections.nix index 62942e86..ce256487 100644 --- a/parts/features/apps/gnome-connections.nix +++ b/parts/features/apps/gnome-connections.nix @@ -7,10 +7,10 @@ }: { home.persistence."/persist" = lib.mkIf osConfig.dendrix.isImpermanent { directories = [ - ".config/freerdp" - ".config/dconf" + ".config/freerdp" # RDP server certificates/keys + ".config/dconf" # GNOME settings database (GSettings/dconf) ]; - files = [".config/connections.db"]; + files = [".config/connections.db"]; # GNOME Connections connection profiles database }; home.packages = [pkgs.gnome-connections]; diff --git a/parts/features/apps/hoppscotch.nix b/parts/features/apps/hoppscotch.nix index be2a7be1..27013ace 100644 --- a/parts/features/apps/hoppscotch.nix +++ b/parts/features/apps/hoppscotch.nix @@ -1,4 +1,5 @@ {...}: { + # Wrap Hoppscotch with Wayland-friendly flags flake.modules.homeManager.hoppscotch = {pkgs, ...}: let hoppscotch-wrapped = pkgs.symlinkJoin { name = "hoppscotch-wrapped"; @@ -13,8 +14,8 @@ }; in { home.persistence."/persist".directories = [ - ".local/share/io.hoppscotch.desktop" - ".config/io.hoppscotch.desktop" + ".local/share/io.hoppscotch.desktop" # Auth tokens, collections, requests, workspaces + ".config/io.hoppscotch.desktop" # App settings, bundles, window state ]; home.packages = [hoppscotch-wrapped]; diff --git a/parts/features/apps/hwatch.nix b/parts/features/apps/hwatch.nix index a3db9bd8..8d0f232c 100644 --- a/parts/features/apps/hwatch.nix +++ b/parts/features/apps/hwatch.nix @@ -1,3 +1,4 @@ +# Modern watch alternative {...}: { flake.modules.homeManager.hwatch = {pkgs, ...}: { home.packages = [pkgs.hwatch]; diff --git a/parts/features/apps/isd.nix b/parts/features/apps/isd.nix index ee4abc06..12c927df 100644 --- a/parts/features/apps/isd.nix +++ b/parts/features/apps/isd.nix @@ -1,3 +1,4 @@ +# Interactive Systemd TUI in Python {...}: { flake.modules.homeManager.isd = { osConfig, diff --git a/parts/features/apps/jqp.nix b/parts/features/apps/jqp.nix index ea5ac80f..54c6fec5 100644 --- a/parts/features/apps/jqp.nix +++ b/parts/features/apps/jqp.nix @@ -1,3 +1,4 @@ +# TUI Playground for interacting with jq {...}: { flake.modules.homeManager.jqp = {...}: { programs.jqp.enable = true; diff --git a/parts/features/apps/kind-with-local-registry/default.nix b/parts/features/apps/kind-with-local-registry/default.nix index fbd80db1..24cb35ca 100644 --- a/parts/features/apps/kind-with-local-registry/default.nix +++ b/parts/features/apps/kind-with-local-registry/default.nix @@ -1,3 +1,6 @@ +# Local registry for faster image iteration, i.e. with Skaffold +# See https://kind.sigs.k8s.io/docs/user/local-registry/ +# To use local registry, prefix images with localhost:5001/ and make sure `docker push` is enabled {...}: { flake.modules.homeManager.kind-with-local-registry = {pkgs, ...}: let kind-with-local-registry = pkgs.writers.writeBashBin "kind-with-local-registry" ( diff --git a/parts/features/apps/kubernetes-tools.nix b/parts/features/apps/kubernetes-tools.nix index 182b307a..752500b9 100644 --- a/parts/features/apps/kubernetes-tools.nix +++ b/parts/features/apps/kubernetes-tools.nix @@ -11,8 +11,8 @@ home.packages = [ pkgs.kubectl - pkgs.kubectx - pkgs.stern + pkgs.kubectx # Kubectl Context switcher + pkgs.stern # Multi pod and container log tailing for Kubernetes ]; }; } diff --git a/parts/features/apps/lf/default.nix b/parts/features/apps/lf/default.nix index 01837695..fbe87b57 100644 --- a/parts/features/apps/lf/default.nix +++ b/parts/features/apps/lf/default.nix @@ -5,6 +5,7 @@ pkgs, ... }: let + # Provides the ability to download a file by dropping it into a window dlfile = pkgs.writers.writeBashBin "dlfile" '' url=$(dragon -t -x) @@ -40,10 +41,10 @@ }; home.packages = with pkgs; [ - chafa - dlfile - imagemagick - pistol + chafa # Images to terminal pixels, used by pistol + dlfile # Provides the ability to download a file by dropping it into a window + imagemagick # Image conversion for clipboard operations + pistol # Image previewer ripdrag ]; @@ -246,172 +247,173 @@ settings = { icons = true; + # Set IFS to newline to allow commands to work with spaces in filenames ifs = "\n"; }; }; home.sessionVariables = { LF_ICONS = '' - tw=:\ - st=:\ - ow=:\ - dt=:\ - di=:\ - fi=:\ - ln=:\ - or=:\ - ex=:\ - *.c=:\ - *.cc=:\ - *.clj=:\ - *.coffee=:\ - *.cpp=:\ - *.css=:\ - *.d=:\ - *.dart=:\ - *.erl=:\ - *.exs=:\ - *.fs=:\ - *.go=:\ - *.h=:\ - *.hh=:\ - *.hpp=:\ - *.hs=:\ - *.html=:\ - *.java=:\ - *.jl=:\ - *.js=:\ - *.json=:\ - *.lua=:\ - *.md=:\ - *.php=:\ - *.pl=:\ - *.pro=:\ - *.py=:\ - *.rb=:\ - *.rs=:\ - *.scala=:\ - *.ts=:\ - *.vim=:\ - *.cmd=:\ - *.ps1=:\ - *.sh=:\ - *.bash=:\ - *.zsh=:\ - *.fish=:\ - *.tar=:\ - *.tgz=:\ - *.arc=:\ - *.arj=:\ - *.taz=:\ - *.lha=:\ - *.lz4=:\ - *.lzh=:\ - *.lzma=:\ - *.tlz=:\ - *.txz=:\ - *.tzo=:\ - *.t7z=:\ - *.zip=:\ - *.z=:\ - *.dz=:\ - *.gz=:\ - *.lrz=:\ - *.lz=:\ - *.lzo=:\ - *.xz=:\ - *.zst=:\ - *.tzst=:\ - *.bz2=:\ - *.bz=:\ - *.tbz=:\ - *.tbz2=:\ - *.tz=:\ - *.deb=:\ - *.rpm=:\ - *.jar=:\ - *.war=:\ - *.ear=:\ - *.sar=:\ - *.rar=:\ - *.alz=:\ - *.ace=:\ - *.zoo=:\ - *.cpio=:\ - *.7z=:\ - *.rz=:\ - *.cab=:\ - *.wim=:\ - *.swm=:\ - *.dwm=:\ - *.esd=:\ - *.jpg=:\ - *.jpeg=:\ - *.mjpg=:\ - *.mjpeg=:\ - *.gif=:\ - *.bmp=:\ - *.pbm=:\ - *.pgm=:\ - *.ppm=:\ - *.tga=:\ - *.xbm=:\ - *.xpm=:\ - *.tif=:\ - *.tiff=:\ - *.png=:\ - *.svg=:\ - *.svgz=:\ - *.mng=:\ - *.pcx=:\ - *.mov=:\ - *.mpg=:\ - *.mpeg=:\ - *.m2v=:\ - *.mkv=:\ - *.webm=:\ - *.ogm=:\ - *.mp4=:\ - *.m4v=:\ - *.mp4v=:\ - *.vob=:\ - *.qt=:\ - *.nuv=:\ - *.wmv=:\ - *.asf=:\ - *.rm=:\ - *.rmvb=:\ - *.flc=:\ - *.avi=:\ - *.fli=:\ - *.flv=:\ - *.gl=:\ - *.dl=:\ - *.xcf=:\ - *.xwd=:\ - *.yuv=:\ - *.cgm=:\ - *.emf=:\ - *.ogv=:\ - *.ogx=:\ - *.aac=:\ - *.au=:\ - *.flac=:\ - *.m4a=:\ - *.mid=:\ - *.midi=:\ - *.mka=:\ - *.mp3=:\ - *.mpc=:\ - *.ogg=:\ - *.ra=:\ - *.wav=:\ - *.oga=:\ - *.opus=:\ - *.spx=:\ - *.xspf=:\ - *.pdf=:\ - *.nix=: + tw=:\ + st=:\ + ow=:\ + dt=:\ + di=:\ + fi=:\ + ln=:\ + or=:\ + ex=:\ + *.c=:\ + *.cc=:\ + *.clj=:\ + *.coffee=:\ + *.cpp=:\ + *.css=:\ + *.d=:\ + *.dart=:\ + *.erl=:\ + *.exs=:\ + *.fs=:\ + *.go=:\ + *.h=:\ + *.hh=:\ + *.hpp=:\ + *.hs=:\ + *.html=:\ + *.java=:\ + *.jl=:\ + *.js=:\ + *.json=:\ + *.lua=:\ + *.md=:\ + *.php=:\ + *.pl=:\ + *.pro=:\ + *.py=:\ + *.rb=:\ + *.rs=:\ + *.scala=:\ + *.ts=:\ + *.vim=:\ + *.cmd=:\ + *.ps1=:\ + *.sh=:\ + *.bash=:\ + *.zsh=:\ + *.fish=:\ + *.tar=:\ + *.tgz=:\ + *.arc=:\ + *.arj=:\ + *.taz=:\ + *.lha=:\ + *.lz4=:\ + *.lzh=:\ + *.lzma=:\ + *.tlz=:\ + *.txz=:\ + *.tzo=:\ + *.t7z=:\ + *.zip=:\ + *.z=:\ + *.dz=:\ + *.gz=:\ + *.lrz=:\ + *.lz=:\ + *.lzo=:\ + *.xz=:\ + *.zst=:\ + *.tzst=:\ + *.bz2=:\ + *.bz=:\ + *.tbz=:\ + *.tbz2=:\ + *.tz=:\ + *.deb=:\ + *.rpm=:\ + *.jar=:\ + *.war=:\ + *.ear=:\ + *.sar=:\ + *.rar=:\ + *.alz=:\ + *.ace=:\ + *.zoo=:\ + *.cpio=:\ + *.7z=:\ + *.rz=:\ + *.cab=:\ + *.wim=:\ + *.swm=:\ + *.dwm=:\ + *.esd=:\ + *.jpg=:\ + *.jpeg=:\ + *.mjpg=:\ + *.mjpeg=:\ + *.gif=:\ + *.bmp=:\ + *.pbm=:\ + *.pgm=:\ + *.ppm=:\ + *.tga=:\ + *.xbm=:\ + *.xpm=:\ + *.tif=:\ + *.tiff=:\ + *.png=:\ + *.svg=:\ + *.svgz=:\ + *.mng=:\ + *.pcx=:\ + *.mov=:\ + *.mpg=:\ + *.mpeg=:\ + *.m2v=:\ + *.mkv=:\ + *.webm=:\ + *.ogm=:\ + *.mp4=:\ + *.m4v=:\ + *.mp4v=:\ + *.vob=:\ + *.qt=:\ + *.nuv=:\ + *.wmv=:\ + *.asf=:\ + *.rm=:\ + *.rmvb=:\ + *.flc=:\ + *.avi=:\ + *.fli=:\ + *.flv=:\ + *.gl=:\ + *.dl=:\ + *.xcf=:\ + *.xwd=:\ + *.yuv=:\ + *.cgm=:\ + *.emf=:\ + *.ogv=:\ + *.ogx=:\ + *.aac=:\ + *.au=:\ + *.flac=:\ + *.m4a=:\ + *.mid=:\ + *.midi=:\ + *.mka=:\ + *.mp3=:\ + *.mpc=:\ + *.ogg=:\ + *.ra=:\ + *.wav=:\ + *.oga=:\ + *.opus=:\ + *.spx=:\ + *.xspf=:\ + *.pdf=:\ + *.nix=: ''; }; }; diff --git a/parts/features/apps/libation.nix b/parts/features/apps/libation.nix index 7c0cb009..46e9fc01 100644 --- a/parts/features/apps/libation.nix +++ b/parts/features/apps/libation.nix @@ -1,3 +1,4 @@ +# Audible liberator {...}: { flake.modules.homeManager.libation = { osConfig, diff --git a/parts/features/apps/lnav.nix b/parts/features/apps/lnav.nix index 75340af6..9356241b 100644 --- a/parts/features/apps/lnav.nix +++ b/parts/features/apps/lnav.nix @@ -1,3 +1,4 @@ +# Log File Navigator {...}: { flake.modules.homeManager.lnav = { osConfig, diff --git a/parts/features/apps/mic-levels-maintainer/default.nix b/parts/features/apps/mic-levels-maintainer/default.nix index 1ee77a59..141d84d8 100644 --- a/parts/features/apps/mic-levels-maintainer/default.nix +++ b/parts/features/apps/mic-levels-maintainer/default.nix @@ -1,3 +1,4 @@ +# Maintain input gain levels {...}: { flake.modules.homeManager.mic-levels-maintainer = {pkgs, osConfig, ...}: let isNumenor = osConfig.dendrix.hostname == "numenor"; diff --git a/parts/features/apps/mpv.nix b/parts/features/apps/mpv.nix index e0f14ce5..837e8e83 100644 --- a/parts/features/apps/mpv.nix +++ b/parts/features/apps/mpv.nix @@ -1,3 +1,4 @@ +# Media Player {...}: { flake.modules.homeManager.mpv = { osConfig, diff --git a/parts/features/apps/nautilus.nix b/parts/features/apps/nautilus.nix index 9f4a00d1..b0c7f5dd 100644 --- a/parts/features/apps/nautilus.nix +++ b/parts/features/apps/nautilus.nix @@ -1,3 +1,4 @@ +# Gnome File Manager {...}: { flake.modules.homeManager.nautilus = { osConfig, diff --git a/parts/features/apps/nix-index.nix b/parts/features/apps/nix-index.nix index 5c6e4469..0196e43e 100644 --- a/parts/features/apps/nix-index.nix +++ b/parts/features/apps/nix-index.nix @@ -6,7 +6,7 @@ home.persistence."/persist" = lib.mkIf osConfig.dendrix.isImpermanent { files = [ - ".local/state/comma-choices" + ".local/state/comma-choices" # For , ]; }; diff --git a/parts/features/apps/nushell/default.nix b/parts/features/apps/nushell/default.nix index f46aded6..e0c96743 100644 --- a/parts/features/apps/nushell/default.nix +++ b/parts/features/apps/nushell/default.nix @@ -5,6 +5,7 @@ pkgs, ... }: let + # Custom nushell build with system-clipboard support for Ctrl+X keybinding nushellWithClipboard = pkgs.unstable.nushell.overrideAttrs (oldAttrs: { cargoBuildFeatures = (oldAttrs.cargoBuildFeatures or []) ++ ["system-clipboard"]; }); diff --git a/parts/features/apps/obs/default.nix b/parts/features/apps/obs/default.nix index 16eb96a7..aef079d5 100644 --- a/parts/features/apps/obs/default.nix +++ b/parts/features/apps/obs/default.nix @@ -7,6 +7,7 @@ }: let isFlexbox = osConfig.dendrix.hostname == "flexbox"; + # OBS Control Scripts obsMainScene = pkgs.writeShellApplication { name = "obs-main-scene"; runtimeInputs = [pkgs.obs-cmd]; diff --git a/parts/features/apps/onboard.nix b/parts/features/apps/onboard.nix index 45a0ac95..c9b24d7c 100644 --- a/parts/features/apps/onboard.nix +++ b/parts/features/apps/onboard.nix @@ -1,3 +1,4 @@ +# Onboard Keyboard Layout {...}: { flake.modules.homeManager.onboard = {pkgs, ...}: { home.packages = [pkgs.onboard]; diff --git a/parts/features/apps/pavucontrol.nix b/parts/features/apps/pavucontrol.nix index b7183694..3ab255b1 100644 --- a/parts/features/apps/pavucontrol.nix +++ b/parts/features/apps/pavucontrol.nix @@ -1,3 +1,4 @@ +# Pulse Audio Volume Control GUI {...}: { flake.modules.homeManager.pavucontrol = {lib, osConfig, pkgs, ...}: { home.persistence."/persist" = lib.mkIf osConfig.dendrix.isImpermanent { diff --git a/parts/features/apps/pgcli.nix b/parts/features/apps/pgcli.nix index 792944fd..2d0f18ae 100644 --- a/parts/features/apps/pgcli.nix +++ b/parts/features/apps/pgcli.nix @@ -1,3 +1,4 @@ +# Actually usable PostgreSQL CLI {...}: { flake.modules.homeManager.pgcli = {...}: { programs.pgcli.enable = true; diff --git a/parts/features/apps/psql/default.nix b/parts/features/apps/psql/default.nix index e228ad97..0d110ccf 100644 --- a/parts/features/apps/psql/default.nix +++ b/parts/features/apps/psql/default.nix @@ -1,3 +1,4 @@ +# Postgresql Client with nicer config {...}: { flake.modules.homeManager.psql = {pkgs, ...}: { home.packages = [pkgs.postgresql]; diff --git a/parts/features/apps/qalculate.nix b/parts/features/apps/qalculate.nix index d0e4b343..75c8fd41 100644 --- a/parts/features/apps/qalculate.nix +++ b/parts/features/apps/qalculate.nix @@ -1,3 +1,4 @@ +# Calculator {...}: { flake.modules.homeManager.qalculate = { osConfig, diff --git a/parts/features/apps/ripgrep-all.nix b/parts/features/apps/ripgrep-all.nix index 53183512..b23eddb7 100644 --- a/parts/features/apps/ripgrep-all.nix +++ b/parts/features/apps/ripgrep-all.nix @@ -1,3 +1,4 @@ +# Like rg, but also search in Office documents, PDFs etc...; rga-fzf is AMAZING! {...}: { flake.modules.homeManager.ripgrep-all = {...}: { programs.ripgrep-all.enable = true; diff --git a/parts/features/apps/rofimoji/default.nix b/parts/features/apps/rofimoji/default.nix index 8097c49f..62dca9a1 100644 --- a/parts/features/apps/rofimoji/default.nix +++ b/parts/features/apps/rofimoji/default.nix @@ -2,7 +2,7 @@ flake.modules.homeManager.rofimoji = {pkgs, ...}: { home.packages = [ pkgs.rofimoji - pkgs.wtype + pkgs.wtype # insert emojis directly ]; xdg.configFile."rofimoji.rc".source = ./rofimoji.rc; diff --git a/parts/features/apps/satty/default.nix b/parts/features/apps/satty/default.nix index 2d9e9285..ad1a751c 100644 --- a/parts/features/apps/satty/default.nix +++ b/parts/features/apps/satty/default.nix @@ -1,3 +1,4 @@ +# Screenshot Annotation tool written in Rust {...}: { flake.modules.homeManager.satty = { osConfig, diff --git a/parts/features/apps/showmethekey.nix b/parts/features/apps/showmethekey.nix index 3979d989..63b565f2 100644 --- a/parts/features/apps/showmethekey.nix +++ b/parts/features/apps/showmethekey.nix @@ -1,3 +1,4 @@ +# screenkey for Wayland, show key presses {...}: { flake.modules.homeManager.showmethekey = {pkgs, ...}: { home.packages = [pkgs.showmethekey]; diff --git a/parts/features/apps/solaar.nix b/parts/features/apps/solaar.nix index e6cb2a48..fd25dee3 100644 --- a/parts/features/apps/solaar.nix +++ b/parts/features/apps/solaar.nix @@ -1,3 +1,4 @@ +# Linux devices manager for the Logitech Unifying Receiver {...}: { flake.modules.homeManager.solaar = { osConfig, diff --git a/parts/features/apps/sound-switcher/default.nix b/parts/features/apps/sound-switcher/default.nix index c21aa109..8cc5652a 100644 --- a/parts/features/apps/sound-switcher/default.nix +++ b/parts/features/apps/sound-switcher/default.nix @@ -1,3 +1,4 @@ +# Rofi-based sound switcher {...}: { flake.modules.homeManager.sound-switcher = {pkgs, osConfig, ...}: let isNumenor = osConfig.dendrix.hostname == "numenor"; diff --git a/parts/features/apps/ssh/default.nix b/parts/features/apps/ssh/default.nix index f1940a98..e3ad2195 100644 --- a/parts/features/apps/ssh/default.nix +++ b/parts/features/apps/ssh/default.nix @@ -27,9 +27,11 @@ }; }; + # Disable default ssh-agent since we use gcr-ssh-agent (via services.gnome.gnome-keyring) services.ssh-agent.enable = false; home.sessionVariables = { + # Point to the new gcr SSH agent socket (NixOS 25.11+) SSH_AUTH_SOCK = "$XDG_RUNTIME_DIR/gcr/ssh"; }; }; diff --git a/parts/features/apps/systemd-errors-and-warnings-counter/default.nix b/parts/features/apps/systemd-errors-and-warnings-counter/default.nix index 35b2c8aa..f9a619cf 100644 --- a/parts/features/apps/systemd-errors-and-warnings-counter/default.nix +++ b/parts/features/apps/systemd-errors-and-warnings-counter/default.nix @@ -1,3 +1,4 @@ +# Display number of systemd errors and warnings in last 10 minutes {...}: { flake.modules.homeManager.systemd-errors-and-warnings-counter = {pkgs, ...}: let systemd-errors-and-warnings-counter = pkgs.writeShellApplication { diff --git a/parts/features/apps/television.nix b/parts/features/apps/television.nix index 0e1c63e0..b77ce95a 100644 --- a/parts/features/apps/television.nix +++ b/parts/features/apps/television.nix @@ -1,3 +1,4 @@ +# Fuzzy-finder in Rust with nixpkgs integration {...}: { flake.modules.homeManager.television = {lib, osConfig, ...}: { home.persistence."/persist" = lib.mkIf osConfig.dendrix.isImpermanent { diff --git a/parts/features/apps/tray-tui.nix b/parts/features/apps/tray-tui.nix index 82dbc6c6..27808e40 100644 --- a/parts/features/apps/tray-tui.nix +++ b/parts/features/apps/tray-tui.nix @@ -1,3 +1,4 @@ +# TUI for tray icons {...}: { flake.modules.homeManager.tray-tui = {...}: { programs.tray-tui = { diff --git a/parts/features/apps/urxvt.nix b/parts/features/apps/urxvt.nix index 370b5ba2..e720079c 100644 --- a/parts/features/apps/urxvt.nix +++ b/parts/features/apps/urxvt.nix @@ -3,11 +3,15 @@ programs.urxvt = { enable = true; + # Perl extensions extraConfig = { perl-ext-common = "default,matcher,resize-font,vtwheel,keyboard-select,-searchable-scrollback"; + # Matcher (clickable URLs) url-launcher = "${pkgs.xdg-utils}/bin/xdg-open"; "matcher.button" = 1; + # Messes with CTRL+SHIFT Keybindings, see https://wiki.archlinux.org/index.php/Rxvt-unicode#Perl_extensions iso14755_52 = false; + # https://github.com/muennich/urxvt-perls#keyboard-select "keyboard-select.clipboard" = true; }; diff --git a/parts/features/apps/variety/default.nix b/parts/features/apps/variety/default.nix index d92a74b3..a9f3fea4 100644 --- a/parts/features/apps/variety/default.nix +++ b/parts/features/apps/variety/default.nix @@ -1,3 +1,4 @@ +# Wallpaper Switcher/Randomizer with Quotes {...}: { flake.modules.homeManager.variety = {pkgs, ...}: { home.packages = [pkgs.variety]; diff --git a/parts/features/apps/virtual-cable/default.nix b/parts/features/apps/virtual-cable/default.nix index 092291ca..59ff2aca 100644 --- a/parts/features/apps/virtual-cable/default.nix +++ b/parts/features/apps/virtual-cable/default.nix @@ -1,3 +1,4 @@ +# Virtual inputs/outputs via Pipewire (for OBS and beyond) {...}: { flake.modules.homeManager.virtual-cable = {pkgs, ...}: let obs-mic = pkgs.writers.writeBashBin "obs-mic" (builtins.readFile ./scripts/obs-mic.sh); @@ -13,7 +14,7 @@ Install.WantedBy = ["wireplumber.service"]; Service = { Environment = "PATH=$PATH:/run/current-system/sw/bin"; - ExecStartPre = "${pkgs.coreutils}/bin/sleep 5"; + ExecStartPre = "${pkgs.coreutils}/bin/sleep 5"; # TODO: Find a better way to wait for WirePlumber to fully start ExecStart = "${obs-mic}/bin/obs-mic"; Type = "oneshot"; }; diff --git a/parts/features/apps/witr.nix b/parts/features/apps/witr.nix index d11b9242..18c51af7 100644 --- a/parts/features/apps/witr.nix +++ b/parts/features/apps/witr.nix @@ -1,3 +1,4 @@ +# Why is this running? {...}: { flake.modules.homeManager.witr = {pkgs, ...}: { home.packages = [pkgs.unstable.witr]; diff --git a/parts/features/apps/wluma.nix b/parts/features/apps/wluma.nix index 49548e8d..498c6e10 100644 --- a/parts/features/apps/wluma.nix +++ b/parts/features/apps/wluma.nix @@ -1,3 +1,4 @@ +# Automatic brightness adjustment based on screen contents and ALS {...}: { flake.modules.homeManager.wluma = {lib, osConfig, ...}: { services.wluma = lib.mkIf osConfig.dendrix.isLaptop { diff --git a/parts/features/apps/xdg.nix b/parts/features/apps/xdg.nix index 47cf2de5..085480d9 100644 --- a/parts/features/apps/xdg.nix +++ b/parts/features/apps/xdg.nix @@ -7,12 +7,17 @@ }: { home.persistence."/persist" = lib.mkIf osConfig.dendrix.isImpermanent { directories = [ - ".xournal" + ".xournal" # Other recently used files ]; + # TODO: This somehow tries to replace the file after it's created by something else + # See https://github.com/nix-community/impermanence/issues/147 + # files = [ + # ".local/share/recently-used.xbel" # Recently used files + # ]; }; home.packages = [ - pkgs.selectdefaultapplication + pkgs.selectdefaultapplication # GUI XDG Default Application Chooser ]; home.sessionVariables = { diff --git a/parts/features/apps/ytmdesktop.nix b/parts/features/apps/ytmdesktop.nix index 4239b9bc..ada9439f 100644 --- a/parts/features/apps/ytmdesktop.nix +++ b/parts/features/apps/ytmdesktop.nix @@ -10,6 +10,8 @@ pkgs.unstable.ytmdesktop ]; + # Override the desktop file to add --password-store flag for Last.fm integration + # See: https://github.com/ytmdesktop/ytmdesktop/issues/1428 xdg.desktopEntries.ytmdesktop = { name = "YouTube Music Desktop App"; genericName = "Music Player"; diff --git a/parts/features/apps/zen.nix b/parts/features/apps/zen.nix index 7542a07f..a537d151 100644 --- a/parts/features/apps/zen.nix +++ b/parts/features/apps/zen.nix @@ -6,6 +6,7 @@ pkgs, ... }: let + # Try to focus an existing Zen window on link open so the workspace comes to the foreground zenNiriOpen = pkgs.writeShellApplication { name = "zen-niri-open"; runtimeInputs = [pkgs.niri pkgs.jq pkgs.coreutils config.programs.zen-browser.package]; @@ -48,7 +49,7 @@ home.sessionVariables = { BROWSER = "${zenNiriOpen}/bin/zen-niri-open"; DEFAULT_BROWSER = "${zenNiriOpen}/bin/zen-niri-open"; - MOZ_LEGACY_PROFILES = 1; + MOZ_LEGACY_PROFILES = 1; # Temporary fix, see https://github.com/0xc000022070/zen-browser-flake/issues/179 }; }; } diff --git a/parts/features/apps/zoxide.nix b/parts/features/apps/zoxide.nix index c0682a15..3f7a33e1 100644 --- a/parts/features/apps/zoxide.nix +++ b/parts/features/apps/zoxide.nix @@ -2,8 +2,8 @@ flake.modules.homeManager.zoxide = {lib, osConfig, ...}: { home.persistence."/persist" = lib.mkIf osConfig.dendrix.isImpermanent { directories = [ - ".cache/zoxide" - ".local/share/zoxide" + ".cache/zoxide" # Some stuff for nushell + ".local/share/zoxide" # Zoxide DB ]; }; diff --git a/parts/features/core/dns.nix b/parts/features/core/dns.nix index 8661ba30..ef5c511a 100644 --- a/parts/features/core/dns.nix +++ b/parts/features/core/dns.nix @@ -2,12 +2,12 @@ flake.modules.nixos.dns = {...}: { services.resolved = { enable = true; - llmnr = "false"; + llmnr = "false"; # https://www.blackhillsinfosec.com/how-to-disable-llmnr-why-you-want-to/ extraConfig = '' MulticastDNS=false DNSStubListenerExtra=172.17.0.1 ''; - fallbackDns = []; + fallbackDns = []; # Ensure we always go through the configured DNS, no magic defaults }; networking.networkmanager.dns = "systemd-resolved"; }; diff --git a/parts/features/core/fonts/default.nix b/parts/features/core/fonts/default.nix index 3d25bc10..fc99dbb4 100644 --- a/parts/features/core/fonts/default.nix +++ b/parts/features/core/fonts/default.nix @@ -1,5 +1,6 @@ {...}: { flake.modules.nixos.fonts = {pkgs, ...}: let + # Looted from https://gist.github.com/elijahmanor/c10e5787bf9ac6b8c276e47e6745826c, much obliged fontSmokeTest = pkgs.writers.writeBashBin "font-smoke-test" '' set -e @@ -11,6 +12,7 @@ printf "%b\n" "== === !== >= <= =>" printf "%b\n" " 󰾆 󱑥 󰒲 󰗼" ''; + # Patch Fira Code with Nerd Fonts plus local Font Awesome 6 Pro glyphs into ~/.local/share/fonts patchFiraWithFA6Pro = pkgs.writeShellApplication { name = "patch-fira-with-fa6-pro"; runtimeInputs = [ @@ -32,6 +34,7 @@ patchFiraWithFA6Pro ]; + # Run the patcher during Home Manager activation so that fonts are ready after switch home-manager.users.farlion.home.activation.patchFiraWithFA6Pro = '' OUT_DIR="$HOME/.local/share/fonts/NerdPatched/FiraCodeFAPro" if [ ! -d "$OUT_DIR" ] || [ -z "$(ls -A "$OUT_DIR" 2>/dev/null)" ]; then @@ -51,7 +54,7 @@ pkgs.font-awesome_5 pkgs.font-awesome_6 pkgs.unstable.font-awesome - pkgs.noto-fonts-color-emoji + pkgs.noto-fonts-color-emoji # emoji font ]; fontconfig = { defaultFonts = { @@ -66,8 +69,8 @@ flake.modules.homeManager.fonts = {lib, osConfig, ...}: { home.persistence."/persist" = lib.mkIf osConfig.dendrix.isImpermanent { directories = [ - ".local/share/fonts" - ".cache/fontconfig" + ".local/share/fonts" # Locally persisted fonts (not nixos-managed) + ".cache/fontconfig" # Fontconfig cache ]; }; }; diff --git a/parts/features/core/home-cleanup-todo.nix b/parts/features/core/home-cleanup-todo.nix index a28ed32f..32c9132a 100644 --- a/parts/features/core/home-cleanup-todo.nix +++ b/parts/features/core/home-cleanup-todo.nix @@ -6,6 +6,7 @@ pkgs, ... }: { + # Symlink flake for `home-manager news` CLI to find homeConfigurations home.file."nixos-config" = { source = config.lib.file.mkOutOfStoreSymlink "${config.home.homeDirectory}/code/nixos-config"; target = "nixos-config"; @@ -16,72 +17,72 @@ }; home.packages = with pkgs; [ - alejandra - ast-grep - bc - bind - dconf - difftastic - dive - dmidecode + alejandra # Nix Formatter + ast-grep # Pure Magic + bc # calculator + bind # Provides dig + dconf # Gnome configuration database + difftastic # structural diff difft, see https://github.com/Wilfred/difftastic + dive # Analyze docker images + dmidecode # Hardware info read from Bios dnstracer - efivar - fast-cli - fastfetch - fd + efivar # Tools and Libraries to manipulate EFI variables + fast-cli # Fast.com CLI `fast` + fastfetch # neofetch sucessor, system information tool + fd # Better find, written in Rust ffmpeg-full - file + file # CLI program to show the type of a file find-cursor fortune - glow - gomatrix + glow # Terminal markdown renderer + gomatrix # The Matrix google-chrome - gucharmap - hardinfo2 - home-manager + gucharmap # Unicode Character Map + hardinfo2 # Hardware/System Info + home-manager # CLI for managing home-manager, needed for `home-manager news` httpie - iftop + iftop # Net top tool, see also nethogs imagemagick iotop-c jq - kind - kdePackages.kruler - lazydocker - libnotify - libsecret - lm_sensors - lolcat - lsof - ncdu - nmap - nethogs - net-tools + kind # Kubernetes In Docker + kdePackages.kruler # Screen ruler + lazydocker # kind for vanilla Docker, kind of + libnotify # Provides notify-send + libsecret # `secret-tool` for interacting with gnome-keyring + lm_sensors # Tools for reading hardware sensors + lolcat # Pipe and See + lsof # Tool to list open file + ncdu # Disk Space Usage Visualization + nmap # Port Scanner + nethogs # Net top tool, see also iftop + net-tools # Things like arp, ifconfig, route, netstat etc... neo-cowsay nix-tree - oculante - kdePackages.okular + oculante # img viewer written in Rust + kdePackages.okular # KDE document viewer openssl - pdftk - pstree - q-text-as-data + pdftk # PDF Manipulation Toolkit + pstree # Show the set of running processes as a tree + q-text-as-data # https://github.com/harelba/q inputs.rmob.defaultPackage.x86_64-linux - screenkey - smartmontools - s-tui - stress + screenkey # Screencast tool to display your keys inspired by Screenflick + smartmontools # Tools for monitoring the health of hard drives + s-tui # Processor monitor/stress test + stress # Simple workload generator for POSIX systems. It imposes a configurable amount of CPU, memory, I/O, and disk stress on the system tcpdump traceroute tree unzip - usbutils - wdisplays - wf-recorder + usbutils # Provides lsusb + wdisplays # arandr for wayland - external display/screen GUI + wf-recorder # Screen recorder for Wayland, useful for quick testing screen stuff wget wireguard-tools whois wl-clipboard - xournalpp - yq + xournalpp # PDF Annotations, useful for saving Okular annotations as well + yq # Command-line YAML/XML/TOML processor - jq wrapper for YAML, XML, TOML documents yt-dlp zip ]; @@ -90,9 +91,9 @@ { PATH = "$HOME/bin:$PATH"; NIXOS_CONFIG = "$HOME/code/nixos-config/"; - GC_INITIAL_HEAP_SIZE = "8G"; - DIRENV_LOG_FORMAT = ""; - NIXOS_OZONE_WL = "1"; + GC_INITIAL_HEAP_SIZE = "8G"; # Slightly improve nix eval times + DIRENV_LOG_FORMAT = ""; # Disable verbose direnv output showing env variables changed + NIXOS_OZONE_WL = "1"; # Enable Ozone-Wayland for Electron apps and Chromium } // lib.optionalAttrs osConfig.dendrix.hasNvidia { LIBVA_DRIVER_NAME = "nvidia"; @@ -104,7 +105,7 @@ programs.man = { enable = true; - generateCaches = false; + generateCaches = false; # Speed up builds }; programs.vscode = { diff --git a/parts/features/core/impermanence.nix b/parts/features/core/impermanence.nix index fd348774..36812518 100644 --- a/parts/features/core/impermanence.nix +++ b/parts/features/core/impermanence.nix @@ -1,4 +1,23 @@ +# General impermanence setup +# Note: specifics should live with their respective modules, where possible! {...}: { + flake.modules.homeManager.impermanence = { + osConfig, + lib, + ... + }: { + home.persistence."/persist" = lib.mkIf osConfig.dendrix.isImpermanent { + directories = [ + ".cache/nix" + ".config/helm" # Helm repositories + ".config/nix" # cachix repositories and such + ".local/share/home-manager" # home-manager news read state + ".local/share/nix" # Nix Repl History + ".local/state/home-manager" # home-manager generations and GC roots + ]; + }; + }; + flake.modules.nixos.impermanence = { config, lib, @@ -38,6 +57,7 @@ ''; in lib.mkIf config.dendrix.isImpermanent { + # Explode / on every boot and resume, see https://grahamc.com/blog/erase-your-darlings/ boot.initrd.systemd = { extraBin = { grep = "${pkgs.gnugrep}/bin/grep"; @@ -47,8 +67,10 @@ enableStrictShellChecks = false; wantedBy = ["initrd-root-device.target"]; wants = ["lvm2-activation.service"]; + # See https://github.com/nix-community/impermanence/issues/250#issuecomment-2603848867 after = ["lvm2-activation.service" "local-fs-pre.target"]; before = ["sysroot.mount"]; + # Run on cold boot only, never on resume from hibernation unitConfig = { ConditionKernelCommandLine = ["!resume="]; RequiresMountsFor = ["/dev/mapper/nixos--vg-root"]; @@ -72,7 +94,7 @@ hideMounts = true; directories = [ "/root/.cache/nix" - "/var/lib/logrotate" + "/var/lib/logrotate" # See https://github.com/nix-community/impermanence/issues/270 "/var/lib/nixos" "/var/lib/systemd/coredump" "/var/lib/systemd/timers" @@ -81,18 +103,22 @@ ]; files = ["/etc/machine-id"]; }; + # Workaround for /etc/ file timings not working with impermanence environment.etc = { + # Timezone data linked by tzupdate "localtime".source = "/persist/system/etc/localtime"; }; + # Woraround for logrotate, see https://github.com/nix-community/impermanence/issues/270 services.logrotate.extraArgs = lib.mkAfter ["--state" "/var/lib/logrotate/logrotate.status"]; + # home-manager's impermanence module doesn't have permissions to bootstrap these dirs, so we do it here: system.activationScripts.bootstrapPersistHome.text = '' mkdir -p /persist/home/farlion chown farlion:users /persist/home/farlion chmod 0700 /persist/home/farlion ''; - programs.fuse.userAllowOther = true; + programs.fuse.userAllowOther = true; # Needed for home-manager's impermanence allowOther option to work }; } diff --git a/parts/features/core/kernel.nix b/parts/features/core/kernel.nix index 8221f525..e0a753a1 100644 --- a/parts/features/core/kernel.nix +++ b/parts/features/core/kernel.nix @@ -1,21 +1,24 @@ {...}: { flake.modules.nixos.kernel = {pkgs, ...}: { + # Writes to /etc/sysctl.d/60-nixos.conf boot.kernel.sysctl = { + # Enable all magic sysrq commands (NixOS sets this to 16, which enables sync only) "kernel.sysrq" = 1; - "vm.swappiness" = 20; + "vm.swappiness" = 20; # balanced setting favoring RAM usage, Default=60 }; - boot.kernelPackages = pkgs.linuxPackages_zen; + boot.kernelPackages = pkgs.linuxPackages_zen; # Optimized for desktop use environment.systemPackages = with pkgs; [ perf linuxKernel.packages.linux_zen.cpupower ]; boot.initrd.verbose = true; + # Keep console visible during teardown boot.kernelParams = [ "systemd.show_status=1" - "i915.enable_psr=0" - "i915.fastboot=0" + "i915.enable_psr=0" # Intel PSR often blanks the console on transitions + "i915.fastboot=0" # avoid early/quiet KMS handover ]; }; } diff --git a/parts/features/core/networking/default.nix b/parts/features/core/networking/default.nix index aaf2ab4d..148331a8 100644 --- a/parts/features/core/networking/default.nix +++ b/parts/features/core/networking/default.nix @@ -5,6 +5,7 @@ pkgs, ... }: let + # Get the current tailscale ip if tailscale is up tailscale-ip = pkgs.writers.writeBashBin "tailscale-ip" ( builtins.readFile ./_scripts/tailscale-ip.sh ); @@ -18,26 +19,36 @@ }; environment.systemPackages = [ - pkgs.pwru - tailscale-ip + pkgs.pwru # eBPF-based linux kernel networking debugger + tailscale-ip # Get the current tailscale IP if tailscale is up ]; networking.firewall = { + # if packets are dropped, they will show up in dmesg logReversePathDrops = true; logRefusedPackets = true; + # logRefusedUnicastsOnly = false; }; + # Tailscale services.tailscale = { enable = true; package = pkgs.unstable.tailscale; useRoutingFeatures = "client"; }; + # Allow for dynamic hosts file override (by root) environment.etc.hosts.mode = "0644"; - networking.firewall.allowedTCPPorts = [22000]; - networking.firewall.allowedUDPPorts = [22000 21027]; + networking.firewall.allowedTCPPorts = [ + 22000 # Syncthing TCP + ]; + networking.firewall.allowedUDPPorts = [ + 22000 # Syncthing QUIC + 21027 # Syncthing discovery broadcasts on IPv4 and multicasts on IPv6 + ]; + # BBR -> Better performance over weak/jittery links boot.kernel.sysctl = { "net.core.default_qdisc" = "fq"; "net.ipv4.tcp_congestion_control" = "bbr"; @@ -46,19 +57,29 @@ networking.networkmanager.enable = true; users.users.farlion.extraGroups = ["networkmanager"]; + # IPv6 + # TODO: Temporarily enabled to allow buggy Hoppscotch to work + #networking.enableIPv6 = false; + #boot.kernelParams = ["ipv6.disable=1"]; + + # Disabling DHCPCD in favor of NetworkManager networking.dhcpcd.enable = false; + # Captive Browser programs.captive-browser = lib.mkIf config.dendrix.isLaptop { enable = true; bindInterface = false; }; + # Only wait for a single interface to come up systemd.network.wait-online.anyInterface = true; }; flake.modules.homeManager.networking = {lib, osConfig, ...}: { home.persistence."/persist" = lib.mkIf osConfig.dendrix.isImpermanent { - directories = [".config/tailscale"]; + directories = [ + ".config/tailscale" # Tailscale known hosts + ]; }; }; } diff --git a/parts/features/core/performance.nix b/parts/features/core/performance.nix index 65790739..1524bdad 100644 --- a/parts/features/core/performance.nix +++ b/parts/features/core/performance.nix @@ -2,7 +2,7 @@ flake.modules.nixos.performance = {...}: { documentation.man = { enable = true; - generateCaches = false; + generateCaches = false; # Used for apropos and the -k option of man, but significantly slows down builds }; }; } diff --git a/parts/features/core/users.nix b/parts/features/core/users.nix index 08009ae8..13b30e6d 100644 --- a/parts/features/core/users.nix +++ b/parts/features/core/users.nix @@ -10,15 +10,17 @@ description = "Florian Peter"; extraGroups = ["disk"]; group = "users"; - hashedPassword = lib.mkDefault ""; + hashedPassword = lib.mkDefault ""; # For CI, otherwise gets overwritten by parent `secrets` flake isNormalUser = true; shell = pkgs.fish; }; + # Default editor for root programs.vim = { defaultEditor = true; enable = true; }; + # Enable fish for root programs.fish.enable = true; }; } diff --git a/parts/features/desktop/cliphist.nix b/parts/features/desktop/cliphist.nix index 818cd76a..0a5c084e 100644 --- a/parts/features/desktop/cliphist.nix +++ b/parts/features/desktop/cliphist.nix @@ -15,6 +15,7 @@ enable = true; }; + # Fix cliphist systemd service to start after Niri is ready systemd.user.services.cliphist = { Install.WantedBy = lib.mkForce ["niri.service"]; Unit.Requires = ["niri.service"]; @@ -26,6 +27,6 @@ Unit.After = ["niri.service"]; }; - home.packages = [pkgs.xdg-utils]; + home.packages = [pkgs.xdg-utils]; # For image copy/pasting }; } diff --git a/parts/features/desktop/gtk-qt.nix b/parts/features/desktop/gtk-qt.nix index b8f3d386..0a71ba79 100644 --- a/parts/features/desktop/gtk-qt.nix +++ b/parts/features/desktop/gtk-qt.nix @@ -7,7 +7,7 @@ }: { home.persistence."/persist" = lib.mkIf osConfig.dendrix.isImpermanent { files = [ - ".config/QtProject.conf" + ".config/QtProject.conf" # Stuff like history and lastVisited ]; }; @@ -27,11 +27,12 @@ }; home.packages = with pkgs; [ - lxappearance - libsForQt5.qt5ct - qt6Packages.qt6ct + lxappearance # GTK Theme testing + tweaking + libsForQt5.qt5ct # Qt 5 Theme testing + tweaking + qt6Packages.qt6ct # Qt 6 Theme testing + tweaking ]; + # https://wiki.archlinux.org/title/HiDPI home.sessionVariables = { QT_AUTO_SCREEN_SCALE_FACTOR = "1"; QT_ENABLE_HIGHDPI_SCALING = "1"; diff --git a/parts/features/desktop/kanshi.nix b/parts/features/desktop/kanshi.nix index 36a11b65..5d8ed467 100644 --- a/parts/features/desktop/kanshi.nix +++ b/parts/features/desktop/kanshi.nix @@ -1,3 +1,4 @@ +# Wayland autorandr {...}: { flake.modules.homeManager.kanshi = {...}: { services.kanshi = { diff --git a/parts/features/desktop/udiskie.nix b/parts/features/desktop/udiskie.nix index c8861c8c..532a7d6a 100644 --- a/parts/features/desktop/udiskie.nix +++ b/parts/features/desktop/udiskie.nix @@ -4,18 +4,22 @@ pkgs, ... }: { + # Indicator icon for automounting USB drives services.udiskie = { enable = true; automount = false; }; + # Ensure udiskie starts after the Niri session is up, to avoid tray race conditions systemd.user.services.udiskie = { Unit = { After = ["niri.service" "graphical-session.target"]; Wants = ["graphical-session.target"]; + # Relax environment conditions in case defaults are too strict for Niri ConditionEnvironment = lib.mkForce []; }; Service = { + # Small delay to ensure Wayland environment and tray are ready ExecStartPre = "${pkgs.coreutils}/bin/sleep 2"; Restart = lib.mkForce "on-failure"; RestartSec = "5"; diff --git a/parts/features/desktop/wlsunset/default.nix b/parts/features/desktop/wlsunset/default.nix index 6a9b9360..61a43702 100644 --- a/parts/features/desktop/wlsunset/default.nix +++ b/parts/features/desktop/wlsunset/default.nix @@ -1,5 +1,7 @@ +# Day/night gamma adjustments for Wayland {...}: { flake.modules.homeManager.wlsunset = {pkgs, ...}: let + # https://github.com/CyrilSLi/linux-scripts/blob/main/waybar/wlsunset.sh wlsunset-waybar = pkgs.writeShellApplication { name = "wlsunset-waybar"; runtimeInputs = with pkgs; [wlsunset procps killall]; diff --git a/parts/features/dev/claude-code/default.nix b/parts/features/dev/claude-code/default.nix index 0f81add1..8b996d6f 100644 --- a/parts/features/dev/claude-code/default.nix +++ b/parts/features/dev/claude-code/default.nix @@ -7,11 +7,11 @@ }: { home.persistence."/persist" = lib.mkIf osConfig.dendrix.isImpermanent { directories = [ - ".claude" - ".cache/claude-cli-nodejs" + ".claude" # Claude Code global settings, agents, and credentials + ".cache/claude-cli-nodejs" # Claude Code cache ]; files = [ - ".claude.json" + ".claude.json" # Claude Code runtime state (credentials, project settings, etc.) ]; }; @@ -42,6 +42,7 @@ }; }; + # See https://dylancastillo.co/til/fix-claude-code-shift-enter-alacritty.html programs.alacritty.settings.keyboard.bindings = [ { key = "Return"; diff --git a/parts/features/dev/devenv.nix b/parts/features/dev/devenv.nix index b461e7e1..f97d878e 100644 --- a/parts/features/dev/devenv.nix +++ b/parts/features/dev/devenv.nix @@ -1,3 +1,4 @@ +# devenv.sh {...}: { flake.modules.homeManager.devenv = { osConfig, diff --git a/parts/features/dev/direnv.nix b/parts/features/dev/direnv.nix index d3aa8c62..e2a41179 100644 --- a/parts/features/dev/direnv.nix +++ b/parts/features/dev/direnv.nix @@ -7,7 +7,7 @@ programs.direnv = { enable = true; nix-direnv.enable = true; - config.strict_env = true; + config.strict_env = true; # Forces all .envrc scripts through set -euo pipefail }; }; } diff --git a/parts/features/dev/git-worktree-switcher.nix b/parts/features/dev/git-worktree-switcher.nix index 0b8e2632..cb019a9e 100644 --- a/parts/features/dev/git-worktree-switcher.nix +++ b/parts/features/dev/git-worktree-switcher.nix @@ -1,3 +1,4 @@ +# Provides wt {...}: { flake.modules.homeManager.git-worktree-switcher = {...}: { programs.git-worktree-switcher.enable = true; diff --git a/parts/features/dev/git/default.nix b/parts/features/dev/git/default.nix index bce4117c..dec16cde 100644 --- a/parts/features/dev/git/default.nix +++ b/parts/features/dev/git/default.nix @@ -5,7 +5,7 @@ }; home.packages = with pkgs; [ - delta + delta # Syntax highlighter for git github-cli glab ]; @@ -39,12 +39,18 @@ settings = { alias = { c = "commit"; + + # Difftastic dlog = "-c diff.external=difft log --ext-diff"; dshow = "-c diff.external=difft show --ext-diff"; ddiff = "-c diff.external=difft diff"; + # `git log` with patches shown with difftastic. dl = "-c diff.external=difft log -p --ext-diff"; + # Show the most recent commit with difftastic. ds = "-c diff.external=difft show --ext-diff"; + # `git diff` with difftastic. dft = "-c diff.external=difft diff"; + p = "push"; rim = "rebase -i main"; rimm = "rebase -i master"; @@ -63,6 +69,7 @@ autoStash = true; autoSquash = true; }; + # https://github.com/NixOS/nixpkgs/blob/master/doc/languages-frameworks/javascript.section.md#git-protocol-error url."https://github.com".insteadOf = "git://github.com"; user.email = "4farlion@gmail.com"; user.name = "workflow"; diff --git a/parts/features/dev/git/gh.config.yml b/parts/features/dev/git/gh.config.yml index 016fae1d..ea32c1ac 100644 --- a/parts/features/dev/git/gh.config.yml +++ b/parts/features/dev/git/gh.config.yml @@ -1,7 +1,12 @@ +# What protocol to use when performing git operations. Supported values: ssh, https git_protocol: ssh +# What editor gh should run when creating issues, pull requests, etc. If blank, will refer to environment. editor: +# When to interactively prompt. This is a global config that cannot be overridden by hostname. Supported values: enabled, disabled prompt: enabled +# A pager program to send command output to, e.g. "less". Set the value to "cat" to disable the pager. pager: +# Aliases allow you to create nicknames for gh commands aliases: co: pr checkout version: 1 diff --git a/parts/features/dev/jujutsu.nix b/parts/features/dev/jujutsu.nix index 41f5d596..b96ab153 100644 --- a/parts/features/dev/jujutsu.nix +++ b/parts/features/dev/jujutsu.nix @@ -18,7 +18,7 @@ signing = { backend = "gpg"; key = "24575DB93F6CEC16"; - behavior = "own"; + behavior = "own"; # sign commits you authored on modify }; aliases = { bt = ["bookmark" "track"]; diff --git a/parts/features/dev/k9s/default.nix b/parts/features/dev/k9s/default.nix index bc4d5153..a31b34b3 100644 --- a/parts/features/dev/k9s/default.nix +++ b/parts/features/dev/k9s/default.nix @@ -16,6 +16,7 @@ settings = { k9s = { ui = { + # Default to gruvbox-dark, override in light specialisation skin = lib.mkDefault "gruvbox-dark"; }; }; diff --git a/parts/features/dev/neovim/default.nix b/parts/features/dev/neovim/default.nix index e4071bab..d6f624e6 100644 --- a/parts/features/dev/neovim/default.nix +++ b/parts/features/dev/neovim/default.nix @@ -9,22 +9,22 @@ in { home.persistence."/persist" = lib.mkIf osConfig.dendrix.isImpermanent { directories = [ - ".local/share/nvim" - ".local/state/nvim" + ".local/share/nvim" # Data + ".local/state/nvim" # state ".cache/nvim" ]; }; imports = [ - ./_avante + ./_avante # Cursor style AI IDE ./_carbon ./_cmp ./_comment-nvim ./_dadbod ./_dap ./_diffview-nvim - ./_fidget + ./_fidget # Sidebar notifications for LSP ./_folds ./_fugitive ./_git-conflict-nvim @@ -34,19 +34,20 @@ ./_lspsaga ./_lualine ./_mason-lsp + # Ensure devicons module is available before mocking it with mini.icons ./_mini-icons ./_mini-operators ./_neotest - ./_noice + ./_noice # UI for commandline, messages and popupmenu ./_conform - ./_notify - ./_nui - ./_nvim-tree-lua + ./_notify # Pluggable Notifications + ./_nui # UI Components + ./_nvim-tree-lua # File Tree ./_obsidian-nvim ./_oil - ./_otter + ./_otter # LSP for embedded code in markdown/quarto ./_overseer - ./_plenary + ./_plenary # LUA Functions ./_rainbow-csv ./_render-markdown ./_telescope @@ -54,7 +55,7 @@ ./_treesitter ./_trouble ./_undotree - ./_vim-be-good + ./_vim-be-good # Vim Motion Learnenings ./_vim-terraform ./_vim-visual-multi ./_web-devicons @@ -135,6 +136,7 @@ lua require('crates').setup() " Fugitive + " See https://github.com/tpope/vim-fugitive/issues/1510#issuecomment-660837020 function! s:ftplugin_fugitive() abort nnoremap cc :Git commit --quiet nnoremap ca :Git commit --quiet --amend @@ -175,10 +177,10 @@ ''; extraPackages = with pkgs; [ - harper - nixd - nodejs - prettierd + harper # Grammar checker + nixd # Nix Language Server + nodejs # For vim to have npm for Mason etc... + prettierd # For yaml, html, json, markdown pyright shellcheck shfmt @@ -187,7 +189,7 @@ plugins = with pkgs.vimPlugins; [ argtextobj-vim { - plugin = b64-nvim; + plugin = b64-nvim; # Base64 encoding/decoding config = '' local wk = require("which-key") wk.add( @@ -204,14 +206,14 @@ type = "lua"; } { - plugin = dressing-nvim; + plugin = dressing-nvim; # Better UI for codeactions, code input etc... config = ""; type = "lua"; } - {plugin = friendly-snippets;} + {plugin = friendly-snippets;} # User-friendly snippets, work with LuaSnip and other engines vim-highlightedyank { - plugin = indent-blankline-nvim; + plugin = indent-blankline-nvim; # Indentation guides config = '' require("ibl").setup({ exclude = { @@ -233,8 +235,8 @@ ''; type = "lua"; } - {plugin = nvim-lspconfig;} - {plugin = luasnip;} + {plugin = nvim-lspconfig;} # Defaults for loads of LSP languages + {plugin = luasnip;} # Snippet engine { plugin = markdown-preview-nvim; config = '' @@ -247,11 +249,11 @@ } vim-numbertoggle { - plugin = vim-qf; + plugin = vim-qf; # Quickfix improvements config = ""; } vim-rooter - vim-sleuth + vim-sleuth # Automatic shiftwidth and expandtab { plugin = vim-startify; config = '' @@ -262,7 +264,7 @@ ''; } vim-surround - {plugin = vim-suda;} + {plugin = vim-suda;} # Sudo support via :SudaRead and :SudaWrite { plugin = text-case-nvim; config = '' @@ -288,13 +290,14 @@ ''; type = "lua"; } + ## Language Specific Plugins crates-nvim dart-vim-plugin elm-vim vim-graphql vim-jsonnet { - plugin = neodev-nvim; + plugin = neodev-nvim; # Nvim LUA development config = '' require("neodev").setup({ library = { plugins = { "nvim-dap-ui", "neotest" }, types = true }, diff --git a/parts/features/hardware/amd.nix b/parts/features/hardware/amd.nix index 77819dd2..b8cbcdd8 100644 --- a/parts/features/hardware/amd.nix +++ b/parts/features/hardware/amd.nix @@ -1,3 +1,5 @@ +# See: https://wiki.nixos.org/wiki/AMD_GPU +# Also see: https://wiki.archlinux.org/title/Hardware_video_acceleration {...}: { flake.modules.nixos.amd = {config, lib, pkgs, ...}: lib.mkIf config.dendrix.hasAmd { @@ -6,15 +8,16 @@ opencl.enable = true; }; + # Disable AMD GPU power management to see if it prevents feezes on S3/s2idle boot.kernelParams = [ "amdgpu.runpm=0" ]; environment.systemPackages = with pkgs; [ - lact + lact # GUI for overclocking, undervolting, setting fan curves, etc. libva-utils mesa-demos - nvtopPackages.full + nvtopPackages.full # nvtop vulkan-tools ]; services.xserver.videoDrivers = ["amdgpu"]; @@ -23,6 +26,16 @@ enable32Bit = true; }; + # # AMDVLK drivers (programs will choose whether to use this over Mesa RADV drivers) + # hardware.graphics.extraPackages = with pkgs; [ + # amdvlk + # ]; + # # For 32 bit applications + # hardware.opengl.extraPackages32 = with pkgs; [ + # driversi686Linux.amdvlk + # ]; + + # GUI for overclocking, undervolting, setting fan curves, etc. systemd.packages = with pkgs; [lact]; systemd.services.lactd.wantedBy = ["multi-user.target"]; }; diff --git a/parts/features/hardware/audio.nix b/parts/features/hardware/audio.nix index fa5a619b..12edda7d 100644 --- a/parts/features/hardware/audio.nix +++ b/parts/features/hardware/audio.nix @@ -7,20 +7,21 @@ }: { home-manager.users.farlion.home.persistence."/persist" = lib.mkIf config.dendrix.isImpermanent { directories = [ - ".local/state/wireplumber" - ".config/rncbc.org" - ".config/pulse" + ".local/state/wireplumber" # Wireplumber state + ".config/rncbc.org" # qpwgraph config file + ".config/pulse" # pulseaudio cookie ]; }; environment.systemPackages = with pkgs; [ alsa-utils pulseaudioFull - qpwgraph + qpwgraph # More extensive patchbay for Pipewire ]; users.users.farlion.extraGroups = ["audio"]; + # PipeWire! security.rtkit.enable = true; services.pipewire = { enable = true; @@ -30,18 +31,19 @@ extraConfig.pipewire."92-adjust-clock-quantum" = { "context.properties" = { - "default.clock.quantum" = 2048; - "default.clock.min-quantum" = 512; - "default.clock.max-quantum" = 8192; + "default.clock.quantum" = 2048; # Larger buffers should prevent xruns + "default.clock.min-quantum" = 512; # Larger buffers should prevent xruns + "default.clock.max-quantum" = 8192; # Matches Windows Settings }; }; extraConfig.pipewire."93-disable-autosuspend" = { "context.properties" = { - "session.suspend-timeout-seconds" = 0; + "session.suspend-timeout-seconds" = 0; # Prevent autosuspend of ALSA nodes, causing xruns and crashes }; }; wireplumber.extraConfig = { + # Enable Fancy Blueooth Codecs "monitor.bluez.properties" = { "bluez5.enable-sbc-xq" = true; "bluez5.enable-msbc" = true; @@ -49,6 +51,7 @@ "bluez5.roles" = ["hsp_hs" "hsp_ag" "hfp_hf" "hfp_ag"]; }; + # Disable unused sinks and sources "disable-unused-nodes" = { "monitor.alsa.rules" = [ { @@ -85,6 +88,7 @@ }; home.file = { + # IRS file from the same repo above ".config/easyeffects/irs/Razor Surround ((48k Z-Edition)) 2.Stereo +20 bass.irs".source = ./audio/_presets/irs/razor-surround-48k-z-edition-stereo-plus20-bass.irs; ".config/pulsemixer.cfg".source = ./audio/pulsemixer.cfg; }; @@ -94,8 +98,10 @@ pkgs.pulsemixer ]; + # GUI for PipeWire effects services.easyeffects = { enable = true; + # Preset from https://github.com/JackHack96/EasyEffects-Presets/blob/master/Bass%20Enhancing%20%2B%20Perfect%20EQ.json preset = "bass-enhancing-perfect-eq"; extraPresets = { "bass-enhancing-perfect-eq" = builtins.fromJSON (builtins.readFile ./audio/_presets/output/bass-enhancing-perfect-eq.json); diff --git a/parts/features/hardware/bluetooth.nix b/parts/features/hardware/bluetooth.nix index 0c721327..64841364 100644 --- a/parts/features/hardware/bluetooth.nix +++ b/parts/features/hardware/bluetooth.nix @@ -1,3 +1,4 @@ +# Bluetooth TUI {...}: { flake.modules.nixos.bluetooth = {config, lib, ...}: { environment.persistence."/persist/system" = lib.mkIf config.dendrix.isImpermanent { diff --git a/parts/features/hardware/btrfs.nix b/parts/features/hardware/btrfs.nix index 2ceaa76b..532712f5 100644 --- a/parts/features/hardware/btrfs.nix +++ b/parts/features/hardware/btrfs.nix @@ -2,13 +2,15 @@ flake.modules.nixos.btrfs = {config, lib, ...}: lib.mkIf config.dendrix.isBtrfs { environment.persistence."/persist/system" = lib.mkIf config.dendrix.isImpermanent { - directories = ["/var/lib/btrfs"]; + directories = [ + "/var/lib/btrfs" # Scrub reports + ]; }; services.btrfs.autoScrub = { enable = true; interval = "monthly"; - fileSystems = ["/"]; + fileSystems = ["/"]; # Subvols of the same mount point don't need to be scrubbed }; }; } diff --git a/parts/features/hardware/firmware.nix b/parts/features/hardware/firmware.nix index 8bf5c5cb..08e05e40 100644 --- a/parts/features/hardware/firmware.nix +++ b/parts/features/hardware/firmware.nix @@ -1,3 +1,4 @@ +# Linux Firmware Updates {...}: { flake.modules.nixos.firmware = {config, lib, ...}: { environment.persistence."/persist/system" = lib.mkIf config.dendrix.isImpermanent { diff --git a/parts/features/hardware/io.nix b/parts/features/hardware/io.nix index 03d3992f..6b5b5f7a 100644 --- a/parts/features/hardware/io.nix +++ b/parts/features/hardware/io.nix @@ -5,6 +5,7 @@ enableGraphical = true; }; + # Keyd remappenings environment.systemPackages = [pkgs.keyd]; services.keyd = { enable = true; @@ -12,6 +13,7 @@ ids = ["*"]; settings = { main = { + # Tap = Esc, hold = enter the fkeys layer capslock = "overload(fkeys, esc)"; }; fkeys = { @@ -32,6 +34,7 @@ }; }; + # Improves palm-rejection with the keyd virtual keyboard environment.etc."libinput/local-overrides.quirks".text = '' [Serial Keyboards] MatchUdevType=keyboard diff --git a/parts/features/hardware/nvidia.nix b/parts/features/hardware/nvidia.nix index 27471cd3..86bfb37b 100644 --- a/parts/features/hardware/nvidia.nix +++ b/parts/features/hardware/nvidia.nix @@ -1,18 +1,20 @@ +# See: https://nixos.wiki/wiki/Nvidia {...}: { flake.modules.nixos.nvidia = {config, lib, pkgs, ...}: lib.mkIf config.dendrix.hasNvidia { boot.blacklistedKernelModules = ["nouveau"]; environment.systemPackages = [ - pkgs.nvtopPackages.full + pkgs.nvtopPackages.full # nvtop pkgs.mesa-demos pkgs.vulkan-tools pkgs.libva-utils - pkgs.nvidia-vaapi-driver + pkgs.nvidia-vaapi-driver # VA-API implementation using NVIDIA's NVDEC ]; + # Enable VAAPI for NVIDIA environment.sessionVariables = { LIBVA_DRIVER_NAME = "nvidia"; - NVD_BACKEND = "direct"; + NVD_BACKEND = "direct"; # Use direct backend for better performance }; services.xserver.videoDrivers = ["nvidia"]; @@ -21,10 +23,30 @@ }; hardware.nvidia = { + # Modesetting is required. modesetting.enable = true; + + # Nvidia power management. Experimental, and can cause sleep/suspend to fail. + # Enable this if you have graphical corruption issues or application crashes after waking + # up from sleep. This fixes it by saving the entire VRAM memory to /tmp/ instead + # of just the bare essentials. powerManagement.enable = false; + + # Fine-grained power management. Turns off GPU when not in use. + # Experimental and only works on modern Nvidia GPUs (Turing or newer). powerManagement.finegrained = true; + + # Use the NVidia open source kernel module (not to be confused with the + # independent third-party "nouveau" open source driver). + # Support is limited to the Turing and later architectures. Full list of + # supported GPUs is at: + # https://github.com/NVIDIA/open-gpu-kernel-modules#compatible-gpus + # Only available from driver 515.43.04+ + # Currently alpha-quality/buggy, so false is currently the recommended setting. open = false; + + # Enable the Nvidia settings menu, + # accessible via `nvidia-settings`. nvidiaSettings = true; }; }; diff --git a/parts/features/hardware/power.nix b/parts/features/hardware/power.nix index 5d44c16c..a4aa6173 100644 --- a/parts/features/hardware/power.nix +++ b/parts/features/hardware/power.nix @@ -7,6 +7,7 @@ }: let isFlexbox = config.dendrix.hostname == "flexbox"; in { + # This will save you money and possibly your life! services.thermald.enable = true; services.logind = { @@ -24,7 +25,7 @@ environment.systemPackages = [] - ++ lib.lists.optional isFlexbox pkgs.libsmbios; + ++ lib.lists.optional isFlexbox pkgs.libsmbios; # Dell-specific power management services.auto-cpufreq = { enable = true; @@ -47,6 +48,7 @@ } ]; + # Dbus Service provding historical battery stats, access to external device batteries... etc. services.upower.enable = true; }; } diff --git a/parts/features/hardware/video.nix b/parts/features/hardware/video.nix index 7a83926f..cde8ccd3 100644 --- a/parts/features/hardware/video.nix +++ b/parts/features/hardware/video.nix @@ -5,7 +5,9 @@ enableVirtualCamera = true; }; - environment.systemPackages = [pkgs.v4l-utils]; + environment.systemPackages = [ + pkgs.v4l-utils # Video4Linux2 -> configuring webcam + ]; users.users.farlion.extraGroups = ["video"]; }; diff --git a/parts/features/security/security.nix b/parts/features/security/security.nix index d00e47a9..40adf508 100644 --- a/parts/features/security/security.nix +++ b/parts/features/security/security.nix @@ -7,46 +7,50 @@ }: { environment.persistence."/persist/system" = lib.mkIf config.dendrix.isImpermanent { directories = [ - "/var/lib/boltd" - "/run/sudo" + "/var/lib/boltd" # Boltd state + "/run/sudo" # Sudo timestamp (to not show the lecture message) ]; }; home-manager.users.farlion.home.persistence."/persist" = lib.mkIf config.dendrix.isImpermanent { directories = [ - ".local/share/keyrings" - ".gnupg" + ".local/share/keyrings" # Gnome Keyrings + ".gnupg" # PGP keys ]; }; + # Thunderbolt security daemon services.hardware.bolt.enable = true; services.gnome.gnome-keyring.enable = true; environment.systemPackages = with pkgs; [ - libsecret + libsecret # Already in home packages but ensuring it's available system-wide ]; programs.gnupg.agent = { enable = true; - enableSSHSupport = false; + enableSSHSupport = false; # Let GNOME Keyring handle SSH agent pinentryPackage = pkgs.pinentry-gnome3; }; programs.seahorse.enable = true; + # Writes to /etc/sudoers security.sudo.extraConfig = '' Defaults:root,%wheel timestamp_timeout=30 ''; users.users.farlion.extraGroups = ["wheel"]; - services.pcscd.enable = true; + # Yubikeys + services.pcscd.enable = true; # Smartcard services for Yubikeys + # Sudo via U2F (Yubikey) security.pam = { u2f = { enable = true; control = "sufficient"; settings = { - origin = "pam://farlion-realm"; - appid = "pam://farlion-realm"; - cue = false; + origin = "pam://farlion-realm"; # Overridde host-dependent realm to share yubikey + appid = "pam://farlion-realm"; # keep equal to origin for compatibility + cue = false; # CLI message to show touch is needed, not needed since using system-wide notification }; }; services = { @@ -56,6 +60,7 @@ swaylock.u2fAuth = true; }; }; + # Enable system-wide Yubikey Support services.udev.packages = [pkgs.yubikey-personalization]; }; } diff --git a/parts/features/security/yubico/default.nix b/parts/features/security/yubico/default.nix index 105221a8..4f2fbb94 100644 --- a/parts/features/security/yubico/default.nix +++ b/parts/features/security/yubico/default.nix @@ -5,9 +5,9 @@ ]; home.packages = with pkgs; [ - pam_u2f - yubikey-manager - yubioath-flutter + pam_u2f # U2F (via yubikey) support for PAM + yubikey-manager # ykman + yubioath-flutter # Yubikey management GUI ]; services = { diff --git a/parts/features/services/kind-killer.nix b/parts/features/services/kind-killer.nix index 342c9579..30dcbcb4 100644 --- a/parts/features/services/kind-killer.nix +++ b/parts/features/services/kind-killer.nix @@ -2,7 +2,7 @@ flake.modules.nixos.kind-killer = {pkgs, ...}: { systemd.services.kind-killer = { description = "Kill kind cluster on shutdown"; - after = ["docker.service"]; + after = ["docker.service"]; # Ensures docker is still running when trying to delete the cluster, since systemd reverses the ordering during shutdown requires = ["docker.service"]; wantedBy = ["multi-user.target"]; serviceConfig = { diff --git a/parts/features/services/syncthing.nix b/parts/features/services/syncthing.nix index ca459979..3b3b986d 100644 --- a/parts/features/services/syncthing.nix +++ b/parts/features/services/syncthing.nix @@ -14,8 +14,8 @@ flake.modules.homeManager.syncthing = {lib, osConfig, ...}: { home.persistence."/persist" = lib.mkIf osConfig.dendrix.isImpermanent { directories = [ - ".local/state/syncthing" - ".config/syncthing" + ".local/state/syncthing" # device keys and certificates + ".config/syncthing" # pre-v1.27.0 uses this instead of $XDG_STATE_HOME above, keeping for backward-compatibility ]; files = [ ".config/syncthingtray.ini" diff --git a/parts/features/services/virtualisation/default.nix b/parts/features/services/virtualisation/default.nix index d3ecdb01..b78b5d3e 100644 --- a/parts/features/services/virtualisation/default.nix +++ b/parts/features/services/virtualisation/default.nix @@ -23,20 +23,20 @@ in { environment.persistence."/persist/system" = lib.mkIf config.dendrix.isImpermanent { directories = [ - "/var/lib/containers" + "/var/lib/containers" # Podman "/var/lib/docker" - "/var/lib/libvirt" + "/var/lib/libvirt" # Virt-Manager ]; }; home-manager.users.farlion.home.persistence."/persist" = lib.mkIf config.dendrix.isImpermanent { directories = [ - ".local/share/containers" + ".local/share/containers" # Podman (userspace) ]; }; environment.systemPackages = [ - pkgs.podman-compose - pkgs.virt-manager + pkgs.podman-compose # docker-compose rewritten with podman backend + pkgs.virt-manager # Desktop user interface for managing virtual machines benchmark-containers benchmark-heavy-containers reset-container-state @@ -44,9 +44,13 @@ virtualisation.docker = { enable = true; + # Explicitly use overlay2 for best performance and stability storageDriver = "overlay2"; daemon.settings = { + # Attach to resolved instead of using default Docker DNS servers dns = ["172.17.0.1"]; + # Have containers listen on localhost instead of 0.0.0.0, + # see https://github.com/NixOS/nixpkgs/issues/111852#issuecomment-1954656069 ip = "127.0.0.1"; ipv6 = false; ip6tables = false; @@ -54,20 +58,28 @@ }; }; + # Allow connecting to resolved DNS from inside Docker containers networking.firewall.interfaces.docker0.allowedTCPPorts = [53]; networking.firewall.interfaces.docker0.allowedUDPPorts = [53]; networking.firewall.extraCommands = '' + # Allow DNS (port 53) on all Docker bridge interfaces for iface in $(${pkgs.iproute2}/bin/ip link show | grep -o 'br-[a-f0-9]\{12\}' || true); do if [ -n "$iface" ]; then + # Insert before default REJECT so these rules are effective iptables -I nixos-fw 1 -i "$iface" -p tcp --dport 53 -j ACCEPT iptables -I nixos-fw 1 -i "$iface" -p udp --dport 53 -j ACCEPT fi done + # Allow cross-network DNS resolution between Docker networks + # This allows containers on any Docker network to reach DNS servers on other Docker networks iptables -I FORWARD 1 -s 172.16.0.0/12 -d 172.16.0.0/12 -p tcp --dport 53 -j ACCEPT iptables -I FORWARD 1 -s 172.16.0.0/12 -d 172.16.0.0/12 -p udp --dport 53 -j ACCEPT + # Fix MTU issues for Docker -> Tailscale traffic + # Clamp MSS to account for Tailscale's MTU of 1280 + # Without this, HTTPS connections from Docker to Tailscale frequently fail. iptables -t mangle -A FORWARD -s 172.17.0.0/16 -d 100.64.0.0/10 -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu iptables -t mangle -A FORWARD -s 172.18.0.0/16 -d 100.64.0.0/10 -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu iptables -t mangle -A FORWARD -s 172.17.0.0/16 -d 100.100.0.0/16 -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu @@ -80,18 +92,22 @@ enable = true; }; + # Configure Podman to use overlay with optimizations virtualisation.containers.storage.settings = { storage = { driver = "overlay"; runroot = "/run/containers/storage"; graphroot = "/var/lib/containers/storage"; options = { + # Pull images in parallel for better performance pull_options = { enable_partial_images = "true"; use_hard_links = "false"; ostree_repos = ""; }; overlay = { + # Use native overlay with metacopy for better performance + # metacopy=on allows fast copy-up of large files mountopt = "nodev,metacopy=on"; force_mask = "0000"; }; From 555bca1bde034e5462a71be8ab33138ecfb6e44a Mon Sep 17 00:00:00 2001 From: workflow <4farlion@gmail.com> Date: Tue, 3 Feb 2026 12:09:10 +0000 Subject: [PATCH 25/26] fix(dendrites): update secrets --- flake.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flake.lock b/flake.lock index 5c0e8d6f..ed891036 100644 --- a/flake.lock +++ b/flake.lock @@ -869,7 +869,7 @@ ] }, "locked": { - "narHash": "sha256-pd7VsNIiRrgwdD/4NDMfW8h55H+6AFA5brwOen2u6Fc=", + "narHash": "sha256-4h200ww4RVC/wAq80j8Jq5pC7CgPUFPg5WvfV7U3COk=", "path": "/home/farlion/code/nixos-secrets", "type": "path" }, From 667a6bab9e0bf2497f7945266e47bcfcbb0fb68a Mon Sep 17 00:00:00 2001 From: workflow <4farlion@gmail.com> Date: Wed, 4 Feb 2026 14:14:55 +0000 Subject: [PATCH 26/26] fix(impermanence): remove duplicate persistence paths --- parts/features/apps/gnome-connections.nix | 1 - parts/features/hardware/audio.nix | 3 --- 2 files changed, 4 deletions(-) diff --git a/parts/features/apps/gnome-connections.nix b/parts/features/apps/gnome-connections.nix index ce256487..2ee20af0 100644 --- a/parts/features/apps/gnome-connections.nix +++ b/parts/features/apps/gnome-connections.nix @@ -8,7 +8,6 @@ home.persistence."/persist" = lib.mkIf osConfig.dendrix.isImpermanent { directories = [ ".config/freerdp" # RDP server certificates/keys - ".config/dconf" # GNOME settings database (GSettings/dconf) ]; files = [".config/connections.db"]; # GNOME Connections connection profiles database }; diff --git a/parts/features/hardware/audio.nix b/parts/features/hardware/audio.nix index 12edda7d..f82ad6e5 100644 --- a/parts/features/hardware/audio.nix +++ b/parts/features/hardware/audio.nix @@ -82,9 +82,6 @@ directories = [ ".config/easyeffects" ]; - files = [ - ".config/pavucontrol.ini" - ]; }; home.file = {

=xE)K9{<4cEUj|~-RwRN*B zJIC?uZu+TwM6D*d)YMNN)J|QUSyct^ybI)*1)sh!12$*O;RGQJkbRDil@L3{wvls~ z(&TE@1-DX+R{_e&!~NZggl8vIGDxZ)1+WVYxh+}svx7W%kh0I}N9KhR7h=Y?09KSV}Dmph?&ay_#YQg;D#?1>lKTtoL8{DL&-pT)@9^ z>u^N;8Ha+UM~*Fpk95&R=kx$)2qbG^H*X60@sB|x7`F)D%8P^(w~b3d&lfO)J=qs4 z)L1P6xdCbgsmUqxJ0!=lrxh8iDRt_J?P438uUz%)8LyC^y3Hzz*M26h)ju6EsCk(e zny3WNDUgX-fzCi0=nSxz{4(9@k;8dKn5jX96R$jT`&LNPFi6)A;Xe>RP1_L**yn!+?h9 zSt%!Wr4rCsi00END`VBL{T)p=jwrin2AVFwaqh|%aRSFt5DVz`Hzc}rYY;0r^v;Nr zn3a7X;}wYE?-A{hyiWY>dBa-y;%C(8PF<>-ravj^xSx=>1pAq{Z@(h0; z@`54MUz=5BB4`(qEYR*S&~AOv?qho}Mm^%$bBEQ>O_sqoliS71)au(kc#TinCeH^1 zEW~?u8dWIF+=ko-8eIiAflIYLC0&tF(ZSv4lF320D>~O!n%~>hfzZDc@2S2RGYYct z#BF}AOPe`RBCMVP;|~Voy_bkdBv!Gt2(;1IgKy4l6)5NALs=>kw7SjTXUo@`F$yua zDnTdHBTt7!Q{K$D8xs5&0e4wTfFA^fod>@koM_&0eHIt|b9_KNA zu~^aFeHuQ32XkaV7!>n3eGt0fhlHkW6#lr1Se;PfUa9o#0Yf4X#s)oU2xHH2vWT?v z5Y=>|D!VrY=<}6n<~47`-cnqs_f*Z!xY?W44D1c?4g8Y$aIlfYv-nv>!AI5skBA9n zd$3-g*RyBq>7YZ%ne(>E0EI1dd3MTp_?jsG)3Zs<0T3qJ?{&wf%h3>%&QI^BJ?UuG}}?Bf{L}!2q4r?GCF)lG>8>=BT$xE&hB_Mz)b`AbX)31Ya=Y)BakO2 zpu8>fd3V+WALM-4pRB9$&Cz#^W97S*c#{I8jXjOLA!j8uP*7Z$79 z?{t+b&q#(}J-2lDf_e|@;z)VsVq%1gw>NV!;&v_Pfq#XVBs6N)Ehsk)ih&(b!0hba z=Iyux7kc=S_DW^rZY(S98&=x2g48MV0UJF5D*&=R?NYlUKEDL|Haw`g3Ppi-+xq>) zG%VB?hO@xy_|fqUHj84JB<|65h%h@7 zqAhe>o!ww=&?^0Fz049O$r(2??(xnGx2Dru_6_Vss7*yUeIfwrA*opOdV9246W>cv zp1nftpzPY3^B`Nu#~1aH9uXQ=I*&^azUd@iKP=w%=Li&Bm>75D!@*N#rht(t|QAK&fnqEYdp*N4Y%aFr#nf82g-1 zhQUo`N#^dboM!3#T=*Fbt}{P&eO4U%tANz5{kbFcOu}Kiv6AFEOj9{Z2W$0E6!CgT zM{s9DN<) zqVXN9hcqAPW5bq){M@HEg)feAmPl*R_?oNG196Nw*2Ii!oFkW0TC(JpOhbAS1?JIi z63a#xwP}1!?5P|!Zx;?Oo1gf@$$OA_b>+TZ8Q?$?C!-F?DV>hbKP|Cy5?B_M%6lrI zjxtEub1>+puFeKc!gw*Zy0XdU+Q{7xvU~f4EE0cM8a8o$DY^M2XCdaR4ErIbovXk^ zdiGsyqWVSDokK-J4liZdpDp2ReZ{iTU$`iy&l(E$@U49-cZZ_N^29w2ZRW*Vme=x( z#4b~q5&a>yH0NND>#WkqY7>>oOnBR704l}hNbda_L#VUB+L~%NIR4FrqVEePQrLQy zD9C?r!{}hR;-*SLCP&)#^WT$H^<$#Ear11Da}qZ; zH<%cdjZP^<#`pK7`;uO`7Vh)NhT|?D0fC+{@$;!+tci%Hxz<(}iumo-NAz5T`MtN)ZEU#6>Ee&ldEA8c z5qxA&LNvChblszQP)Xw?fcT2q@Hp8q#!n>RBxFP z4G?h&y+sbhGm}tD6I(pi&f){Ony;|;315ek+=P4ckB)pXGkPN#dy<= z{TH$#9Bt;4uV~h5HGJu*Y~P0u3T66R>!M#Z#BHRGp}QOC#NxU;@D9t1sR$&7KHtdb zUOY|t3l$7YO2fZZK5c>1Te>>8j3k0OzWe@mF3C72i|FtXdG&wbb(9ItP-f^3845L4Xv$6bXA*pFN z(O)2YZm_vBkZgWl^smap8-V{}G|k~-87f}*Q?~ayJyFSmoJ{Bb?(Vn%YeBLJI$f$H< zzBD@$TsN&qTdvnfS1_GbM2>z0&ZS-U@oNkCLYAn&*uMO0JF13;;NRN>zx-xP96FpG%NE)k_eD@M}q6X&Udvcf@(-sZK6# z&B=!uzB@KBZ0Kp8Qvbuc*x{ZDVUJWj1>n!mR5slTdTQubKkX|bx*hkxTDfdSRtJZY zg^zL3h~~bSdvOL@N819wxSQAoC(K)^H;!$g^{<{KV2Mrm3XsG zkK_5r!xmqJF@u|B%vxtI$7!7g;g0Tba)cl1`4jM6_nd_>kSD)%5LH%eweRG|DA)dR zxgU2$Nw_ef{8cVSJ_}S>b*?1eE8T z1U`717wzk+d>tGY#tR@iTP15GA)FCB#m!&r^@6x?MeboEMAvO~?P*T5b7$TZk#32~ ztC>H2WO;qy)lPaGDDlb76%Mq~#n2s$(F*UH-+e~oh{^6JA)GH6ScxWxQfM*px9y+2 znQJmGU36`2rtv;!oIda*5V*6Bf!t`ZG-pTL>;SyV*Is_sHR7KKiN2#(U@`8XG(}@{Qk;9mWA_nBMV%Vt*}Q~A<-vuUKZR_3JNVUTTgN06>gln0?q zotA4hH{<)#0z((Ty^*&D~je7g7ymq=7&L z#Kn_YYKq^7T21~8UzR7(r33x2UN;mdE0it_?sfEFG*>vyFv-H(zW4Tw6TiWOEqbF< zXHo0>C4BmB*B(a)+X2X=TAe0RW`~^?>DO);3{a-(3e(N+IIT}8p zE73@-nI4+rWhn#mXo2U#>YRqKq)z6hOon}?Cuq&ECL;rP0zg+H_zu3(bQoZe;D*cQAA(>hN;1@jnxHxAF?M6~*UIY+nTaLX5HKgt=Zk z^?k4^jWSKl`R45G(#Daz3dTyak89jBed^lx2hQPYFXoyHj1#yk4du9Y+Z;rrGWY*f{KaH_kW6jr#%Gu{taR39|F(DdURd z>g>N0$CjNSfcLr~5vp93)Bm6lxjb=Y5wv%(3 z^UYgyso%N@o|k8dv#fNT6>{tXllz);2IIi7Ri)=e`;-iB61Fog4U-P2#~TDrP~gKt z%|-WVKW_a}nSH4J@98z19~3G7DB&tZ;vDFgx7OJ|oRdx1KQBRr5##p`A^UJii4y)eM5K zKKdv{hO6@KABm!7%>%Xd8js9pn?wgjUyU<#AL~$mw>LO7+QcOy1zf*SEst{xNfw7+WpAO-kS1NS+fr2XW4VO-D${ zvSWhJv1r9nQkc*6A-n7E%AUK;&G;;5F7h>VztC~;ZE#?Be!bqymfT2x5I2KYqK?U1 zmlGzt0togeRxq#`oCS^9<4ZItolH}WEnq;*vn7v9CuWl4zs z-klBTf?F@DHoPnE00l%V{AQurf4!qfO!wu8tOwvhpoyAqWuwx3W)7W8+@As*T5j!} ziKHtK<^f2wQemM{WQ*nd)QqTKA_w})8j^B(IF2rZh|rrRXvRqm&UB1=#YE#DxI8?o zu6>qprC9}-nsr!z;|t0DVGgc0zqDfd=`nqSbRXHa$qMa0Hbrmzb&b~kB!cmNW`RYi z?U;#w?BeR3cb>67wGCWm8~-k~mUVeRwS@L~OaUHP+*Tn`f0eKm5qQA#o(|kpBc(Cp zs82ue<%%vCB~I|5M$_9A2%iE7HLZDm!w5$gVXy!BK4JaKi?9S+ByJc+dSSk(u>a=< z|Cp2#L=}7z7h0Mv%iy;H;j%F&R^PsFG`1QLkKkAW?esgOCyA5?%x(wbSa9Ir)#&iKhqLNb-G>BRo8ZU`cXLW&IzCS~rM)y~RFbeMN6jzyn45^L_mNROc; zv8}JB1Vc1UWwg?6g17o43}>q&I|$|_H4eMPz`$mRZGRtk*8;1*Z&E7hmz4>3emd(r zzi^}_zcpwSP5*Hdv5bsItgu0o2<5BuYKDXggd`m9zf}fSLy4M8370-HOFC7u2c5u( zlJuVu7XXDbXPmp+vIOn(%^>WwStem8&h@a*SVCMS0F&NHwpF2dt9@x-nU{t=9FYnA zFHHI?wf0^tG*<;#%*L$RJKeE1acGs%B=HIX!#OKl*!?(^6sQt@{N_59`n_?q?2=wU zgBOn9nf};oEo0LIz)GiRCEtRNky`os-u9*>V00Kc=M1sEijyA_kW_LE$yR8K>ZWpc zHG67LoV@doZ|MN_G-lX#{w=8aYRr`WvWX7gzFd`&BSo+gnD;{Ak*YV1rAqxuwxM6B z2VUue`e{rk$ySPu2hsYflI^=os9IKR)+O*B>g`|jF_@LnSW)UeRbRsBe0}oZ4mmZx zH@o7kH_pI0@zpaZ7j6;Cx0foE5;x@SHO}r_1J1r)WlAniYj;ka4p0yBw;Kq)(tbD= zu~pHK_DQTsktj-D;c-Xv0**ytb~R#mA55@)cvaK6YGg;tUh@(42y89n5nNi`Q^aGc zB+GtkYKKdvlt9&%t*+c{ASzfXS}siRPnH|APnG}xL(jxnjxVGgo=ZVMlsSr3+i7+P zNMxofjL8NYB%Chc@Fh+_o}0k;z)R*2iphCrIgaZ8`9Q%jo?~H08!JGA;n=gA1rt>l zhn<%zOr7knKhYv86x=x@V>@ZtzILO^A2IvKsZxgQtd?GHxJz$7F8Tah8sx35#(~#a z@QG=zjazxdFEi8gXa!V&duvqFrd$ln=rvosu(Hf3jsf{zq%?QQ4{WxsDfp#U~fAVV8DwT(VRFa=S1e_-xJ252hYXW7C{V zNQ;xSvJk|`<($^w4~vQwOhRh3&jc}1<(%cXzuZv`Fy*-Fj3+NQpMss%B>E|rC-8=1dj44mA!%axyi z_j{e`bE>|2o9`P*AwM3#4f$dpr?hYj7sY4CT3jxZWT$$h4jm!7z{xO0Gj-&Pz?*<5 zycDl8@nP@`=wM9m`I&O$shAQ(o@ORE(MW9u&CKcne z%!m4u^*^C-vrhF6N96*52jtTQC~2p@N2huv3|G9E45x@*rUV3f5bw1BNeCVzy^meH zD|l$!bc2P18Fgy_N`$5wP;V4#j5IXE20<)~EqB!bQD<QoBly^RKdE?A_8E` z>m%G0P!S87cxOx!LsT7P-N$_Iw7qPYA%213x+>~brU2ESCcg!CDYZnlqZb> zf|vn=BsF1t0?iiyUOB*XRu7a8686!|!^GXGO)`x+{ek~mmB%w?QSwkPZDgJTV$H!l z?g<{wh&~+v*yZw3Uj(`-%H_;Cg2}*&A)NluFS$u2%QErTT4K!uPow0|NZhln3J0$J zNPB8Z7&uf%ex?v;Ae{OmVc3Lg$co055NhZn2Vu4hRpB?XXWqV1dhkJgN;isXG%=hG zlR!G3moyJF0IsB>gVUdS^DUCj0L4LK>xKILSJ@zbu&Y&v53te za{9SL%ix<<+dp`c)(434CreBE-Ku=^d0PwAJ8+#eh~CXJklCy+Nz=arQey-PN$ed@{=h-nVI+jw;3WR zx?E`zWNt&|wE*qOQSfZf|#XtJJp{{6w}J}l|> zPhS(86_NI(IVv=F&jgU#D?msqhgke|us&$Kof8SW1nVM<}yqVXy zl#OBER+x+cJ*Z-X*=Iq0 zhVQ)xUa|9DW+wyoljY6JN~_NL1)sR;o!ELO%Nu0#@=bR5%Lcl*+3{&?>rnk_+}G!A zFNDtT#&$^38MQGYsVwsqORt0*;A*OqS;e!;|R6|Y>r{)qnYff zRQjC_KW3LVg|i)H*`U!WleQF@LR#G-2TyxD_v#Ex4uIAT9_4=7T@IIL~HfZGa zm&UKI-JZWx-?P(|Hw`zc3uY$NE;v&#v#~IE)U>;6LIR?r>k@CVXJhlKhc^9FUXq<$ zWULMtYBC&LvZSQ+bf+szCzs9NG%O=LcdOxG{_Vn#j1P)(Q*u6gxFNVOa(>;7BW#bl zx=VRR)~ydB9-Mc+Q=`+#`;YFoeACqn_lxq%O4*OGn0D+in3k}IU8f&jZZz1Y-(Az= z^w2<`K{4hPa}G}%u$Hxf3qg_lk`|1wTXl;KkIfA>=S-#3$=Z^W3F!i@yWNQFJE-gO zbeDzEk=JF}{xE6U3L1;@JDB zvEKG~@K-h(yIOyL%XtVO&%x)8%fE76xBtX-ExTIYp`GjGShmha!`|{Qo!5HTA*6Fn zy6|7_d?@O+PQ`cA%f?7qBorUvJ7zk!nX)MCKScxa5gzeL#RL9zfPNhjkK{t}5gy4! z#Ur^;e1xaUMa3&EFN&|pYj-7*i&r`z`V+h!T@I;sq2f{cYxZ&!X`~mj3l*<$wN;C} zyzGVS%d0sGCa-92NA!y(FRye^*uA33i>k@9Dz9K}NA!!Lb`r zQ?r+S#zcClrI~t|y?9kywaCkBR(cAz|9Q-}Sh7fGYhG~ixy#PClpI?#$0rKghPN%h zJ?AxY2^b-%Sw_X9qJw4(gjY)zBl=PLAUu%kSv?(9i@bul9l4R$h=<}+-Al!zbU^e| z@yLxRKEfmSQt=AA9nsHA-dWwXiC=2KR6ePA)Etq%2#@SS#Us0*_y|w63l*=hy+o_F zhIP8@$f`1OD?tO#><(-8Qc(;$dmS zt4SdGMUxk$Pg_+H)Fk$5@9x?Q3$mj&gW2iP?B!@b3a5joZKzQ-7p;0ys{^XGD187P zr2}#!6_4mg@ev-$Ma84$h~gtWRW2$X$fZ4MbQDRdTvR-gOR#i6Zsauzqxe+!Qt?!| zsCbpg%ggPEe$nJrdoj-;?sPQ%9n~D!5zR7Gyh@rWN`LL$T}PTw?Lx&P{!#fvc&Quh zjP>p(-F0%4$uhd5#q|f|9KVYFQ?N8fzh+y~C}Ycc`8e90AlU_)*?0{N9#*Azr30d0 zGW(#hI79S}}jRSqY^NRbDC{q=Tmw zb3{Kc_oDbzxu|#`FE6*FUW(EO;nAc`#Ur^;da-sA=c!ft)hun zKQH&9_-!OFFSjH5QTiafR?Hn$gPIOnF}L%E(ue9^Djvzj%k3T}FSR;Q<)Y%1mKViG zyyh2_7ZJ$M)Zp&FRyfH ZzcH`q(x)A=dr2l7^Iqt?+egky{uf^Cdo2I} literal 0 HcmV?d00001 diff --git a/parts/features/desktop/niri/default.nix b/parts/features/desktop/niri/default.nix new file mode 100644 index 00000000..798c084c --- /dev/null +++ b/parts/features/desktop/niri/default.nix @@ -0,0 +1,519 @@ +{config, lib, ...}: let + cfg = config; +in { + flake.modules.homeManager.niri = { + config, + lib, + pkgs, + ... + }: + with lib; let + isNumenor = cfg.dendrix.hostname == "numenor"; + isNvidia = cfg.dendrix.hasNvidia; + + leftScreen = + if isNumenor + then "HDMI-A-2" + else null; + mainScreen = + if isNumenor + then "DP-1" + else "eDP-1"; + rightScreen = + if isNumenor + then "HDMI-A-1" + else null; + + locker = "${pkgs.bash}/bin/bash -c '${pkgs.procps}/bin/pgrep -x swaylock || ${pkgs.swaylock-effects}/bin/swaylock --daemonize'"; + suspender = "${pkgs.systemd}/bin/systemctl suspend-then-hibernate"; + + wallpaperSetter = pkgs.writeShellApplication { + name = "niri-set-wallpaper"; + runtimeInputs = [pkgs.swaybg pkgs.procps]; + text = builtins.readFile ./_scripts/niri-set-wallpaper.sh; + }; + + windowPicker = pkgs.writeShellApplication { + name = "niri-pick-window"; + runtimeInputs = [pkgs.niri pkgs.unstable.fuzzel pkgs.jq]; + text = builtins.readFile ./_scripts/niri-pick-window.sh; + }; + + fuzzelCalc = pkgs.writeShellApplication { + name = "niri-qalc"; + runtimeInputs = [pkgs.unstable.fuzzel pkgs.libqalculate pkgs.wl-clipboard pkgs.libnotify]; + text = builtins.readFile ./_scripts/niri-qalc.sh; + }; + + workspaceReorderer = pkgs.writeShellApplication { + name = "niri-reorder-workspaces"; + runtimeInputs = [pkgs.niri pkgs.jq]; + text = builtins.readFile ./_scripts/niri-reorder-workspaces.sh; + }; + + autoColumn = pkgs.writeShellApplication { + name = "niri-auto-column"; + runtimeInputs = [pkgs.niri pkgs.jq pkgs.coreutils]; + text = builtins.readFile ./_scripts/niri-auto-column.sh; + }; + + openOnWorkspace = pkgs.writeShellApplication { + name = "niri-open-on-workspace"; + runtimeInputs = [pkgs.niri pkgs.jq]; + text = builtins.readFile ./_scripts/niri-open-on-workspace.sh; + }; + + niriBinds = { + suffixes, + prefixes, + substitutions ? {}, + }: let + replacer = replaceStrings (attrNames substitutions) (attrValues substitutions); + format = prefix: suffix: let + actual-suffix = + if isList suffix.action + then { + action = head suffix.action; + args = tail suffix.action; + } + else { + inherit (suffix) action; + args = []; + }; + action = replacer "${prefix.action}-${actual-suffix.action}"; + in { + name = "${prefix.key}+${suffix.key}"; + value.action.${action} = actual-suffix.args; + }; + pairs = attrs: fn: + concatMap ( + key: + fn { + inherit key; + action = attrs.${key}; + } + ) (attrNames attrs); + in + listToAttrs (pairs prefixes (prefix: pairs suffixes (suffix: [(format prefix suffix)]))); + in { + home.packages = with pkgs; [ + brightnessctl + fuzzelCalc + hyprmagnifier + playerctl + qt5.qtwayland + swaybg + wallpaperSetter + windowPicker + workspaceReorderer + xwayland-satellite + ]; + + programs.swaylock = { + enable = true; + package = pkgs.swaylock-effects; + settings = { + debug = false; + show-failed-attempts = true; + ignore-empty-password = true; + screenshots = true; + effect-pixelate = 10; + effect-blur = "7x5"; + }; + }; + + services.swayidle = { + enable = true; + events = [ + { + event = "before-sleep"; + command = "${locker}"; + } + { + event = "lock"; + command = "${locker}"; + } + ]; + timeouts = [ + { + timeout = 360; + command = "${locker}"; + } + { + timeout = 370; + command = "/run/current-system/sw/bin/niri msg action power-off-monitors"; + resumeCommand = "${pkgs.coreutils}/bin/sleep 1; /run/current-system/sw/bin/niri msg action power-on-monitors"; + } + { + timeout = 1800; + command = "${suspender}"; + } + ]; + }; + + systemd.user.services.swayidle = { + Unit = { + After = ["niri.service" "graphical-session.target"]; + Wants = ["graphical-session.target"]; + ConditionEnvironment = lib.mkForce []; + }; + Service = { + ExecStartPre = "${pkgs.coreutils}/bin/sleep 2"; + Restart = lib.mkForce "on-failure"; + RestartSec = "5"; + }; + }; + + systemd.user.services.niri-auto-column = lib.mkIf isNumenor { + Unit = { + Description = "Auto-consume windows into columns on vertical monitors"; + After = ["niri.service" "graphical-session.target"]; + Wants = ["graphical-session.target"]; + }; + Service = { + ExecStart = "${autoColumn}/bin/niri-auto-column"; + Restart = "on-failure"; + RestartSec = "5"; + }; + Install.WantedBy = ["graphical-session.target"]; + }; + + programs.wleave.enable = true; + + home.file.".local/share/wallpapers/gruvbox-light.png".source = ./_wallpapers/gruvbox-light-rainbow.png; + home.file.".local/share/wallpapers/gruvbox-dark.png".source = ./_wallpapers/gruvbox-dark-rainbow.png; + + programs.niri.settings = rec { + environment.NIXOS_OZONE_WL = "1"; + + input = { + keyboard.xkb = { + layout = "us,de,ua,pt"; + options = "eurosign:e,terminate:ctrl_alt_bksp"; + }; + touchpad = { + dwt = true; + disabled-on-external-mouse = false; + natural-scroll = false; + tap = true; + tap-button-map = "left-right-middle"; + }; + focus-follows-mouse.enable = true; + }; + + cursor = { + hide-after-inactive-ms = 3000; + hide-when-typing = true; + }; + + spawn-at-startup = [ + {command = ["${pkgs.bash}/bin/bash" "-c" "sleep 10 && systemctl --user restart xdg-desktop-portal"];} + {command = ["systemctl" "--user" "restart" "kanshi"];} + {command = ["systemctl" "--user" "restart" "app-blueman@autostart"];} + {command = ["systemctl" "--user" "start" "gnome-keyring-ssh"];} + {command = ["obsidian"];} + {command = ["ytmdesktop" "--password-store=gnome-libsecret"];} + {command = ["${wallpaperSetter}/bin/niri-set-wallpaper"];} + {command = ["wlsunset-waybar"];} + {command = ["${openOnWorkspace}/bin/niri-open-on-workspace" "${workspaces."00".name}" "ChatGPT" "zen" "--new-window" "https://chatgpt.com/"];} + {command = ["${openOnWorkspace}/bin/niri-open-on-workspace" "${workspaces."09".name}" "[Vv]ikunja" "zen" "--new-window" "https://vikunja.hyena-byzantine.ts.net/"];} + ]; + + window-rules = [ + { + matches = [{app-id = "^obsidian$";}]; + open-on-workspace = " 7"; + } + { + matches = [ + {app-id = "^signal$";} + {app-id = "^teams-for-linux$";} + {app-id = "^org.telegram.desktop$";} + ]; + open-on-workspace = " 8"; + } + { + matches = [{app-id = "^YouTube Music Desktop App$";}]; + open-on-workspace = " 9"; + } + { + matches = [{title = ".*[Vv]ikunja.*";}]; + open-on-workspace = " 9"; + } + { + matches = [{title = ".*ChatGPT.*";}]; + open-on-workspace = " a"; + } + { + matches = [ + {title = ".*Pavucontrol.*";} + {title = ".*zoom.*";} + ]; + open-floating = true; + } + { + matches = [ + {app-id = "^Bitwarden$";} + {app-id = "^com.obsproject.Studio$";} + ]; + block-out-from = "screen-capture"; + } + { + matches = [{is-window-cast-target = true;}]; + border = { + active.color = "#f38ba8"; + inactive.color = "#7d0d2d"; + }; + shadow.color = "#7d0d2d70"; + tab-indicator = { + active.color = "#f38ba8"; + inactive.color = "#7d0d2d"; + }; + } + ]; + + workspaces = { + "00" = { + name = " a"; + open-on-output = rightScreen; + }; + "01" = { + name = " 1"; + open-on-output = leftScreen; + }; + "02" = { + name = " 2"; + open-on-output = mainScreen; + }; + "03" = { + name = " 3"; + open-on-output = rightScreen; + }; + "04" = { + name = " 4"; + open-on-output = mainScreen; + }; + "05" = { + name = " 5"; + open-on-output = mainScreen; + }; + "06" = { + name = " 6"; + open-on-output = mainScreen; + }; + "07" = { + name = " 7"; + open-on-output = rightScreen; + }; + "08" = { + name = " 8"; + open-on-output = mainScreen; + }; + "09" = { + name = " 9"; + open-on-output = leftScreen; + }; + "10" = { + name = " 10"; + open-on-output = mainScreen; + }; + }; + + layout = { + border = { + enable = true; + width = 2; + }; + default-column-width.proportion = 1. / 2.; + gaps = 4; + preset-column-widths = [ + {proportion = 1. / 2.;} + {proportion = 1. / 3.;} + {proportion = 2. / 3.;} + ]; + shadow.enable = true; + }; + + prefer-no-csd = true; + animations.workspace-switch.enable = false; + hotkey-overlay.skip-at-startup = true; + + binds = with config.lib.niri.actions; + lib.attrsets.mergeAttrsList [ + { + "Mod+Shift+Slash".action = show-hotkey-overlay; + "Mod+Return".action = spawn "alacritty"; + "Mod+Return".hotkey-overlay.title = "Open a Terminal: alacritty"; + "Mod+D".action = spawn "fuzzel"; + "Mod+D".hotkey-overlay.title = "Run an Application: fuzzel"; + "Mod+Shift+D".action = spawn "${windowPicker}/bin/niri-pick-window"; + "Mod+Shift+D".hotkey-overlay.title = "Pick a Window: niri-pick-window"; + "Mod+Shift+X".action = spawn-sh "swaylock --daemonize && niri msg action power-off-monitors"; + "Mod+Shift+X".hotkey-overlay.title = "Lock screen and turn off monitors"; + "Mod+z".action = spawn "hyprmagnifier"; + "Mod+z".hotkey-overlay.title = "Screen magnifier"; + "Mod+Shift+z".action = power-off-monitors; + "Mod+Shift+z".hotkey-overlay.title = "Power off Monitors"; + "XF86AudioRaiseVolume".action = spawn-sh "wpctl set-volume @DEFAULT_AUDIO_SINK@ 0.1+"; + "XF86AudioRaiseVolume".allow-when-locked = true; + "XF86AudioLowerVolume".action = spawn-sh "wpctl set-volume @DEFAULT_AUDIO_SINK@ 0.1-"; + "XF86AudioLowerVolume".allow-when-locked = true; + "XF86AudioMute".action = spawn-sh "wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle"; + "XF86AudioMute".allow-when-locked = true; + "XF86AudioMicMute".action = spawn-sh "wpctl set-mute @DEFAULT_AUDIO_SOURCE@ toggle"; + "XF86AudioMicMute".allow-when-locked = true; + "XF86MonBrightnessUp".action = spawn-sh "brightnessctl --class=backlight set 10%+"; + "XF86MonBrightnessUp".allow-when-locked = true; + "XF86MonBrightnessDown".action = spawn-sh "brightnessctl --class=backlight set 10%-"; + "XF86MonBrightnessDown".allow-when-locked = true; + "Mod+Shift+Q".action = close-window; + "Mod+Shift+Q".repeat = false; + } + (niriBinds { + suffixes."Left" = "column-left"; + suffixes."j" = "column-left"; + suffixes."Down" = "window-down"; + suffixes."k" = "window-down"; + suffixes."Up" = "window-up"; + suffixes."l" = "window-up"; + suffixes."Right" = "column-right"; + suffixes."semicolon" = "column-right"; + prefixes."Mod" = "focus"; + prefixes."Mod+Ctrl" = "move"; + prefixes."Mod+Shift" = "focus-monitor"; + prefixes."Mod+Shift+Ctrl" = "move-workspace-to-monitor"; + substitutions."monitor-column" = "monitor"; + substitutions."monitor-window" = "monitor"; + }) + (niriBinds { + suffixes."Home" = "first"; + suffixes."End" = "last"; + prefixes."Mod" = "focus-column"; + prefixes."Mod+Ctrl" = "move-column-to"; + }) + (niriBinds { + suffixes."U" = "workspace-down"; + suffixes."Page_Down" = "workspace-down"; + suffixes."I" = "workspace-up"; + suffixes."Page_Up" = "workspace-up"; + prefixes."Mod" = "focus"; + prefixes."Mod+Ctrl" = "move-window-to"; + prefixes."Mod+Shift" = "move"; + }) + (niriBinds { + suffixes = { + "a" = ["workspace" "${workspaces."00".name}"]; + "1" = ["workspace" "${workspaces."01".name}"]; + "2" = ["workspace" "${workspaces."02".name}"]; + "3" = ["workspace" "${workspaces."03".name}"]; + "4" = ["workspace" "${workspaces."04".name}"]; + "5" = ["workspace" "${workspaces."05".name}"]; + "6" = ["workspace" "${workspaces."06".name}"]; + "7" = ["workspace" "${workspaces."07".name}"]; + "8" = ["workspace" "${workspaces."08".name}"]; + "9" = ["workspace" "${workspaces."09".name}"]; + "0" = ["workspace" "${workspaces."10".name}"]; + }; + prefixes."Mod" = "focus"; + prefixes."Mod+Ctrl" = "move-column-to"; + }) + { + "Mod+BracketLeft".action = consume-or-expel-window-left; + "Mod+BracketRight".action = consume-or-expel-window-right; + "Mod+Comma".action = consume-window-into-column; + "Mod+Period".action = expel-window-from-column; + "Mod+R".action = switch-preset-column-width; + "Mod+Shift+R".action = switch-preset-window-height; + "Mod+Ctrl+R".action = reset-window-height; + "Mod+F".action = maximize-column; + "Mod+Shift+F".action = fullscreen-window; + "Mod+Ctrl+F".action = expand-column-to-available-width; + "Mod+C".action = center-column; + "Mod+Ctrl+C".action = center-visible-columns; + "Mod+Minus".action = set-column-width "-10%"; + "Mod+Equal".action = set-column-width "+10%"; + "Mod+Shift+Minus".action = set-window-height "-10%"; + "Mod+Shift+Equal".action = set-window-height "+10%"; + "Mod+V".action = toggle-window-floating; + "Mod+Shift+V".action = switch-focus-between-floating-and-tiling; + "Mod+Shift+W".action = spawn-sh ( + builtins.concatStringsSep "; " [ + "systemctl --user restart waybar.service" + "${wallpaperSetter}/bin/niri-set-wallpaper" + ] + ); + "Mod+Shift+W".hotkey-overlay.title = "Restart Waybar"; + "Mod+Space".action = switch-layout "next"; + "Mod+Shift+Space".action = switch-layout "prev"; + "Print".action.screenshot = []; + "Print".hotkey-overlay.title = "Screenshot via Niri"; + "Mod+Print".action = spawn "satty-screenshot"; + "Mod+Print".hotkey-overlay.title = "Screenshot via Satty"; + "Mod+Shift+Print".action.screenshot-screen = []; + "Mod+Shift+Print".hotkey-overlay.title = "Instant Screenshot"; + "Mod+Shift+Escape".action = toggle-keyboard-shortcuts-inhibit; + "Mod+Shift+Escape".allow-inhibiting = false; + "Ctrl+Alt+Delete".action = quit; + } + { + "Mod+G".action = set-dynamic-cast-window; + "Mod+Shift+G".action = set-dynamic-cast-monitor; + "Mod+Delete".action = clear-dynamic-cast-target; + "Mod+Tab".action = focus-window-down-or-column-right; + "Mod+Shift+Tab".action = focus-window-up-or-column-left; + } + { + "Mod+b".action = spawn-sh ( + if isNvidia + then "brave --profile-directory='Default' --enable-features=VaapiVideoDecoder,VaapiVideoEncoder --password-store=seahorse" + else "brave --profile-directory='Default' --password-store=seahorse" + ); + "Mod+b".hotkey-overlay.hidden = true; + "Mod+Shift+b".action = spawn "zen"; + "Mod+Shift+b".hotkey-overlay.hidden = true; + "Mod+h".action = spawn-sh ( + if isNvidia + then "brave --profile-directory='Profile 1' --enable-features=VaapiVideoDecoder,VaapiVideoEncoder --password-store=seahorse" + else "brave --profile-directory='Profile 1' --password-store=seahorse" + ); + "Mod+h".hotkey-overlay.hidden = true; + "Mod+p".action = spawn "cliphist-fuzzel-img"; + "Mod+p".hotkey-overlay.hidden = true; + "Mod+Shift+p".action = spawn-sh "cliphist list | fuzzel --dmenu | cliphist delete"; + "Mod+Shift+p".hotkey-overlay.hidden = true; + "Mod+n".action = spawn-sh "alacritty -e fish -ic lf"; + "Mod+n".hotkey-overlay.hidden = true; + "Mod+m".action = spawn "${fuzzelCalc}/bin/niri-qalc"; + "Mod+m".hotkey-overlay.title = "Calcu[M]athalor via qalculate"; + "Mod+Pause".action = spawn "wleave"; + "Mod+w".action = spawn "${pkgs.networkmanager_dmenu}/bin/networkmanager_dmenu"; + "Mod+w".hotkey-overlay.hidden = true; + "Mod+o".action = toggle-overview; + "Mod+o".repeat = false; + "Mod+Shift+o".action = spawn "${workspaceReorderer}/bin/niri-reorder-workspaces"; + "Mod+Shift+o".hotkey-overlay.title = "Re[o]rder workspaces to maintain logical order"; + "Mod+e".action = spawn "rofimoji"; + "Mod+e".hotkey-overlay.hidden = true; + "Mod+Shift+e".action = spawn ["rofimoji" "--action" "clipboard"]; + "Mod+Shift+e".hotkey-overlay.hidden = true; + "Mod+s".action = spawn "sound-switcher"; + "Mod+s".hotkey-overlay.hidden = true; + } + { + "Alt+F1".action = spawn "obs-main-scene"; + "Alt+F1".hotkey-overlay.title = "OBS: Switch to Main Scene"; + "Alt+F2".action = spawn "obs-screensharing"; + "Alt+F2".hotkey-overlay.title = "OBS: Switch to Screensharing"; + "Alt+F3".action = spawn "obs-catcam-toggle"; + "Alt+F3".hotkey-overlay.title = "OBS: Toggle Catcam"; + "Alt+F4".action = spawn "obs-recording-toggle"; + "Alt+F4".hotkey-overlay.title = "OBS: Start/Stop Recording"; + "Alt+F5".action = spawn "obs-recording-pause"; + "Alt+F5".hotkey-overlay.title = "OBS: Pause/Unpause Recording"; + "Alt+F6".action = spawn "obs-webcam-toggle"; + "Alt+F6".hotkey-overlay.title = "OBS: Toggle Webcam"; + } + ]; + }; + }; +} diff --git a/parts/features/desktop/theming.nix b/parts/features/desktop/theming.nix new file mode 100644 index 00000000..d08aeba5 --- /dev/null +++ b/parts/features/desktop/theming.nix @@ -0,0 +1,104 @@ +{config, lib, ...}: let + cfg = config; +in { + flake.modules.nixos.theming = { + pkgs, + lib, + ... + }: { + stylix = { + enable = true; + base16Scheme = "${pkgs.base16-schemes}/share/themes/gruvbox-dark-medium.yaml"; + cursor = { + name = "Bibata-Modern-Ice"; + package = pkgs.bibata-cursors; + size = 24; + }; + fonts = { + emoji = { + package = pkgs.noto-fonts-color-emoji; + name = "Noto Color Emoji"; + }; + monospace = { + package = pkgs.fira-code; + name = "Fira Code"; + }; + serif = { + package = pkgs.dejavu_fonts; + name = "DejaVu Serif"; + }; + sansSerif = { + package = pkgs.dejavu_fonts; + name = "DejaVu Sans"; + }; + sizes = { + applications = 9; + desktop = 9; + terminal = 8; + popups = 9; + }; + }; + image = ./theming/_wallpapers/gruvbox-dark-rainbow.png; + polarity = "dark"; + }; + + specialisation.light.configuration = { + environment.etc."specialisation".text = "light"; + + stylix = { + base16Scheme = lib.mkForce "${pkgs.base16-schemes}/share/themes/catppuccin-latte.yaml"; + image = lib.mkForce ./theming/_wallpapers/gruvbox-light-rainbow.png; + polarity = lib.mkForce "light"; + }; + + home-manager.users.farlion = { + home.sessionVariables = { + AICHAT_LIGHT_THEME = 1; + }; + + services.dunst.iconTheme.name = lib.mkForce "Papirus-Light"; + + gtk.gtk3.extraConfig.gtk-application-prefer-dark-theme = lib.mkForce false; + + qt.enable = lib.mkForce false; + + programs.neovim = { + extraLuaConfig = '' + -- Override lualine theme for light mode + if require('lualine') then + local lualine_config = require('lualine').get_config() + lualine_config.options.theme = 'gruvbox-light' + require('lualine').setup(lualine_config) + end + ''; + }; + + stylix.targets = { + neovim.enable = lib.mkForce true; + }; + + programs.k9s.settings.k9s.ui.skin = lib.mkForce "gruvbox-light"; + }; + }; + }; + + flake.modules.homeManager.theming = {pkgs, ...}: { + home.packages = [ + pkgs.papirus-icon-theme + ]; + stylix = { + iconTheme = { + enable = true; + package = pkgs.papirus-icon-theme; + light = "Papirus-Light"; + dark = "Papirus-Dark"; + }; + targets = { + firefox = { + profileNames = ["main"]; + }; + neovim.enable = false; + }; + }; + }; +} diff --git a/parts/features/desktop/theming/_wallpapers/gruvbox-dark-rainbow.png b/parts/features/desktop/theming/_wallpapers/gruvbox-dark-rainbow.png new file mode 100644 index 0000000000000000000000000000000000000000..b15ba5a97602c2e04138e96f0e48be21ff39e5d6 GIT binary patch literal 185977 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 L{uKA4)sg=JgoI_M literal 0 HcmV?d00001 diff --git a/parts/features/desktop/theming/_wallpapers/gruvbox-light-rainbow.png b/parts/features/desktop/theming/_wallpapers/gruvbox-light-rainbow.png new file mode 100644 index 0000000000000000000000000000000000000000..3217d92a564491f787d16bb44b79f3a46c2cd445 GIT binary patch literal 192946 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