new modules, migrate to easy-hosts, format nixfmt-rfc-style

+16
flake.lock
··· 48 48 "type": "github" 49 49 } 50 50 }, 51 + "easy-hosts": { 52 + "locked": { 53 + "lastModified": 1755470564, 54 + "narHash": "sha256-KB1ZryVDoQcbIsItOf4WtxkHhh3ppj+XwMpSnt/2QHc=", 55 + "owner": "tgirlcloud", 56 + "repo": "easy-hosts", 57 + "rev": "d0422bc7b3db26268982aa15d07e60370e76ee1d", 58 + "type": "github" 59 + }, 60 + "original": { 61 + "owner": "tgirlcloud", 62 + "repo": "easy-hosts", 63 + "type": "github" 64 + } 65 + }, 51 66 "fenix": { 52 67 "inputs": { 53 68 "nixpkgs": [ ··· 585 600 "root": { 586 601 "inputs": { 587 602 "catppuccin": "catppuccin", 603 + "easy-hosts": "easy-hosts", 588 604 "flake-parts": "flake-parts", 589 605 "ghostty": "ghostty", 590 606 "helix": "helix",
+54 -46
flake.nix
··· 46 46 inputs.nixpkgs.follows = "nixpkgs"; 47 47 }; 48 48 flake-parts.url = "github:hercules-ci/flake-parts"; 49 + easy-hosts.url = "github:tgirlcloud/easy-hosts"; 49 50 }; 50 - outputs = { 51 - self, 52 - nixpkgs, 53 - flake-parts, 54 - ... 55 - } @ inputs: 56 - flake-parts.lib.mkFlake {inherit inputs;} ( 57 - {withSystem, ...}: { 51 + outputs = 52 + { 53 + self, 54 + nixpkgs, 55 + flake-parts, 56 + ... 57 + }@inputs: 58 + flake-parts.lib.mkFlake { inherit inputs; } ( 59 + { withSystem, config, ... }: 60 + { 58 61 systems = [ 59 62 "x86_64-linux" 60 63 "aarch64-linux" 61 64 ]; 62 65 63 - perSystem = {pkgs, ...}: { 64 - packages = { 65 - pokego = pkgs.callPackage ./pkgs/pokego.nix {}; 66 - http-nu = pkgs.callPackage ./pkgs/http-nu.nix {}; 67 - topiary-nu = pkgs.callPackage ./pkgs/topiary-nu.nix { 68 - inherit (inputs) tree-sitter-nu topiary-nushell; 66 + imports = [ ./systems/default.nix ]; 67 + 68 + perSystem = 69 + { pkgs, ... }: 70 + { 71 + packages = { 72 + pokego = pkgs.callPackage ./pkgs/pokego.nix { }; 73 + http-nu = pkgs.callPackage ./pkgs/http-nu.nix { }; 74 + topiary-nu = pkgs.callPackage ./pkgs/topiary-nu.nix { 75 + inherit (inputs) tree-sitter-nu topiary-nushell; 76 + }; 77 + 78 + wakuna-image = self.lib.sdImageFromSystem self.nixosConfigurations.wakuna; 69 79 }; 70 - 71 - wakuna-image = self.lib.sdImageFromSystem self.nixosConfigurations.wakuna; 80 + formatter = pkgs.nixfmt-rfc-style; 72 81 }; 73 - formatter = pkgs.alejandra; 74 - }; 75 82 76 - flake = let 77 - inherit (nixpkgs) lib; 78 - in { 79 - lib = { 80 - sdImageFromSystem = system: system.config.system.build.sdImage; 83 + flake = 84 + let 85 + inherit (nixpkgs) lib; 86 + in 87 + { 88 + lib = { 89 + sdImageFromSystem = system: system.config.system.build.sdImage; 81 90 82 - mkSystem' = system: hostname: 83 - withSystem system ( 84 - { 85 - inputs', 86 - self', 87 - ... 88 - }: 91 + mkSystem' = 92 + system: hostname: 93 + withSystem system ( 94 + { inputs', self', ... }: 89 95 lib.nixosSystem { 90 96 specialArgs = { 91 97 inherit ··· 96 102 ; 97 103 }; 98 104 modules = [ 99 - {networking.hostName = hostname;} 105 + { networking.hostName = hostname; } 100 106 ./modules/core.nix 101 107 ./modules/nixos 102 108 ./hosts/${hostname} 109 + config.flake.nixosModules.dev 110 + config.flake.nixosModules.desktop 103 111 ]; 104 112 } 105 - ); 113 + ); 106 114 107 - mkSystem = system: hostname: {${hostname} = self.lib.mkSystem' system hostname;}; 108 - mkSystems = system: hosts: lib.mergeAttrsList (map (self.lib.mkSystem system) hosts); 109 - }; 115 + mkSystem = system: hostname: { ${hostname} = self.lib.mkSystem' system hostname; }; 116 + mkSystems = system: hosts: lib.mergeAttrsList (map (self.lib.mkSystem system) hosts); 117 + }; 110 118 111 - nixosConfigurations = inputs.nixpkgs.lib.concatMapAttrs self.lib.mkSystems { 112 - "x86_64-linux" = [ 113 - "ozen" 114 - "kiwi" 115 - "reg" 116 - "belaf" 117 - ]; 118 - "aarch64-linux" = ["wakuna"]; 119 + overlays.default = import ./overlays; 120 + 121 + homeModules = { 122 + dev = import ./modules/dev/home.nix; 123 + desktop = import ./modules/desktop/home.nix; 124 + }; 125 + 126 + nixosModules = { 127 + dev = import ./modules/dev/nixos.nix; 128 + desktop = import ./modules/desktop/nixos.nix; 129 + }; 119 130 }; 120 - 121 - overlays.default = import ./overlays; 122 - }; 123 131 } 124 132 ); 125 133 nixConfig = {
+5 -56
hosts/belaf/default.nix
··· 1 + { pkgs, ... }: 1 2 { 2 - pkgs, 3 - lib, 4 - inputs, 5 - ... 6 - }: { 7 - imports = [ 8 - inputs.lanzaboote.nixosModules.lanzaboote 9 - inputs.catppuccin.nixosModules.catppuccin 10 - ../../modules/home 11 - ./hardware.nix 12 - ]; 13 - catppuccin = { 14 - enable = true; 15 - flavor = "macchiato"; 16 - }; 17 - time.timeZone = "Europe/Paris"; 18 - desktop.enable = true; 3 + imports = [ ./hardware.nix ]; 19 4 system.stateVersion = "25.11"; 20 5 21 6 boot = { 22 - loader.systemd-boot = { 23 - enable = lib.mkForce false; 24 - 25 - configurationLimit = 10; 26 - }; 27 - lanzaboote = { 28 - enable = true; 29 - pkiBundle = "/etc/secureboot"; 30 - }; 31 - supportedFilesystems = ["bcachefs"]; 7 + supportedFilesystems = [ "bcachefs" ]; 32 8 kernelPackages = pkgs.linuxPackages_latest; 33 9 }; 34 10 35 - networking.networkmanager.enable = true; 36 - 37 - services = { 38 - tailscale.enable = true; 39 - tailscale.useRoutingFeatures = "client"; 40 - touchegg.enable = true; 41 - auto-cpufreq.enable = true; 42 - blueman.enable = true; 43 - udev.packages = [pkgs.via]; 44 - }; 45 - 46 - hardware.keyboard.qmk.enable = true; 47 - 48 - security = { 49 - sudo.wheelNeedsPassword = false; 50 - rtkit.enable = true; 51 - }; 52 - 53 - environment = with pkgs; { 54 - systemPackages = [ 55 - sbctl 56 - ]; 57 - }; 58 - 59 - virtualisation.docker = { 60 - enable = true; 61 - daemon.settings = { 62 - data-root = "/docker"; 63 - }; 11 + virtualisation.docker.daemon.settings = { 12 + data-root = "/docker"; 64 13 }; 65 14 }
+7 -6
hosts/belaf/hardware.nix
··· 6 6 lib, 7 7 modulesPath, 8 8 ... 9 - }: { 10 - imports = [(modulesPath + "/installer/scan/not-detected.nix")]; 9 + }: 10 + { 11 + imports = [ (modulesPath + "/installer/scan/not-detected.nix") ]; 11 12 12 13 boot.initrd.availableKernelModules = [ 13 14 "xhci_pci" ··· 17 18 "usbhid" 18 19 "sd_mod" 19 20 ]; 20 - boot.initrd.kernelModules = []; 21 - boot.kernelModules = ["kvm-intel"]; 22 - boot.extraModulePackages = []; 21 + boot.initrd.kernelModules = [ ]; 22 + boot.kernelModules = [ "kvm-intel" ]; 23 + boot.extraModulePackages = [ ]; 23 24 24 25 fileSystems."/" = { 25 26 device = "UUID=d584e71f-2c5d-41e2-95e7-ed41f0833e25"; ··· 36 37 fsType = "ext4"; 37 38 }; 38 39 39 - swapDevices = []; 40 + swapDevices = [ ]; 40 41 41 42 # Enables DHCP on each ethernet and wireless interface. In case of scripted networking 42 43 # (the default) this is the recommended approach. When using systemd-networkd it's
+16 -43
hosts/kiwi/default.nix
··· 1 1 { 2 - inputs, 3 - pkgs, 4 2 config, 3 + pkgs, 4 + lib, 5 5 ... 6 - }: { 7 - imports = [ 8 - inputs.catppuccin.nixosModules.catppuccin 9 - ../../modules/home 10 - ./hardware.nix 11 - ]; 6 + }: 7 + { 8 + imports = [ ./hardware.nix ]; 12 9 13 - yubikey.enable = true; 14 - catppuccin = { 15 - enable = true; 16 - flavor = "macchiato"; 17 - }; 18 - time.timeZone = "Europe/Paris"; 19 - desktop.enable = true; 20 10 system.stateVersion = "25.11"; 21 11 22 - home-manager.users.${config.my.username}.imports = [ 23 - ./home-upf.nix 24 - ./desktop.nix 25 - ]; 12 + home-manager.users.${config.my.username} = { 13 + nixpkgs.config.allowUnfreePredicate = pkg: builtins.elem (lib.getName pkg) [ "hayase" ]; 14 + 15 + home.packages = [ 16 + pkgs.signal-desktop-bin 17 + pkgs.obs-studio 18 + pkgs.hayase 19 + ]; 20 + 21 + programs.waybar.settings.mainBar.battery.bat = lib.mkForce "BAT0"; 22 + }; 26 23 27 24 boot = { 28 25 # https://gitlab.freedesktop.org/drm/amd/-/issues/3925 ··· 34 31 configurationLimit = 10; 35 32 }; 36 33 }; 37 - 38 - hardware.keyboard.qmk.enable = true; 39 - 40 - networking.networkmanager.enable = true; 41 - 42 - services = { 43 - tailscale = { 44 - enable = true; 45 - useRoutingFeatures = "client"; 46 - }; 47 - touchegg.enable = true; 48 - blueman.enable = true; 49 - auto-cpufreq.enable = true; 50 - udev.packages = [pkgs.via]; 51 - }; 52 - 53 - security = { 54 - sudo.wheelNeedsPassword = false; 55 - rtkit.enable = true; 56 - }; 57 - 58 - virtualisation.docker.enable = true; 59 - 60 - programs._1password.enable = true; 61 34 }
-39
hosts/kiwi/desktop.nix
··· 1 - { 2 - lib, 3 - pkgs, 4 - ... 5 - }: { 6 - nixpkgs.config.allowUnfreePredicate = pkg: 7 - builtins.elem (lib.getName pkg) [ 8 - "hayase" 9 - ]; 10 - home.packages = [ 11 - pkgs.signal-desktop-bin 12 - pkgs.obs-studio 13 - pkgs.hayase 14 - ]; 15 - 16 - programs = { 17 - waybar.settings.mainBar.battery.bat = lib.mkForce "BAT0"; 18 - opencode.settings.mcp = { 19 - linear = { 20 - type = "remote"; 21 - url = "https://mcp.linear.app/mcp"; 22 - enabled = true; 23 - headers = { 24 - Authorization = "Bearer {env:LINEAR_API_KEY}"; 25 - }; 26 - }; 27 - sentry = { 28 - type = "local"; 29 - enabled = true; 30 - command = [ 31 - "${pkgs.bun}/bin/bun" 32 - "x" 33 - "mcp-remote@latest" 34 - "https://mcp.sentry.dev/mcp" 35 - ]; 36 - }; 37 - }; 38 - }; 39 - }
+7 -6
hosts/kiwi/hardware.nix
··· 6 6 lib, 7 7 modulesPath, 8 8 ... 9 - }: { 10 - imports = [(modulesPath + "/installer/scan/not-detected.nix")]; 9 + }: 10 + { 11 + imports = [ (modulesPath + "/installer/scan/not-detected.nix") ]; 11 12 12 13 boot.initrd.availableKernelModules = [ 13 14 "nvme" ··· 17 18 "usbhid" 18 19 "sd_mod" 19 20 ]; 20 - boot.initrd.kernelModules = []; 21 - boot.kernelModules = ["kvm-amd"]; 22 - boot.extraModulePackages = []; 21 + boot.initrd.kernelModules = [ ]; 22 + boot.kernelModules = [ "kvm-amd" ]; 23 + boot.extraModulePackages = [ ]; 23 24 24 25 fileSystems."/" = { 25 26 device = "/dev/disk/by-uuid/8039878e-c1a8-4b46-924a-0d42d4e49d24"; ··· 35 36 ]; 36 37 }; 37 38 38 - swapDevices = []; 39 + swapDevices = [ ]; 39 40 40 41 # Enables DHCP on each ethernet and wireless interface. In case of scripted networking 41 42 # (the default) this is the recommended approach. When using systemd-networkd it's
-10
hosts/kiwi/home-upf.nix
··· 1 - _: { 2 - # [includeIf "hasconfig:remote.*.url:git+ssh://git@github/upfluence/**"] 3 - # path = "~/upf/.gitconfig" 4 - xdg.configFile."git/config".text = '' 5 - [includeIf "hasconfig:remote.*.url:git+ssh://git@github.com/upfluence/**"] 6 - path = "~/upf/.gitconfig" 7 - [includeIf "hasconfig:remote.*.url:git@github.com:upfluence/**"] 8 - path = "~/upf/.gitconfig" 9 - ''; 10 - }
+5 -14
hosts/ozen/default.nix
··· 1 1 { 2 - inputs, 3 2 pkgs, 4 3 lib, 5 4 config, 6 5 ... 7 - }: let 6 + }: 7 + let 8 8 inherit (lib) mkForce; 9 - in { 9 + in 10 + { 10 11 my.username = "nixos"; 11 12 12 - imports = [ 13 - inputs.catppuccin.nixosModules.catppuccin 14 - inputs.nixos-wsl.nixosModules.default 15 - ../../modules/home 16 - ]; 17 - 18 - catppuccin = { 19 - enable = true; 20 - flavor = "macchiato"; 21 - }; 22 13 wsl.enable = true; 23 14 wsl.defaultUser = config.my.username; 24 15 system.stateVersion = "25.11"; ··· 40 31 41 32 environment = { 42 33 variables.BROWSER = mkForce "wsl-open"; 43 - systemPackages = [pkgs.wsl-open]; 34 + systemPackages = [ pkgs.wsl-open ]; 44 35 }; 45 36 46 37 nixpkgs.hostPlatform = "x86_64-linux";
+8 -14
hosts/reg/default.nix
··· 3 3 pkgs, 4 4 inputs, 5 5 ... 6 - }: { 6 + }: 7 + { 7 8 my.username = "root"; 8 9 9 10 imports = [ ··· 15 16 16 17 boot.tmp.cleanOnBoot = true; 17 18 zramSwap.enable = true; 18 - sops.age.sshKeyPaths = ["/etc/ssh/ssh_host_ed25519_key"]; 19 - services = { 20 - tailscale.enable = true; 21 - tailscale.useRoutingFeatures = "server"; 22 - openssh.enable = true; 23 - 24 - atuin = { 25 - enable = true; 26 - host = "0.0.0.0"; 27 - }; 19 + sops.age.sshKeyPaths = [ "/etc/ssh/ssh_host_ed25519_key" ]; 20 + services.atuin = { 21 + enable = true; 22 + host = "0.0.0.0"; 28 23 }; 29 24 30 25 users.users = { 31 - ${config.my.username}.openssh.authorizedKeys.keyFiles = [inputs.ssh-keys]; 26 + ${config.my.username}.openssh.authorizedKeys.keyFiles = [ inputs.ssh-keys ]; 32 27 }; 33 28 34 - environment.systemPackages = with pkgs; [helix]; 35 - server = true; 29 + environment.systemPackages = with pkgs; [ helix ]; 36 30 37 31 system.stateVersion = "25.05"; 38 32 }
+4 -3
hosts/reg/hardware.nix
··· 1 - {modulesPath, ...}: { 2 - imports = [(modulesPath + "/profiles/qemu-guest.nix")]; 1 + { modulesPath, ... }: 2 + { 3 + imports = [ (modulesPath + "/profiles/qemu-guest.nix") ]; 3 4 boot.loader.grub = { 4 5 efiSupport = true; 5 6 efiInstallAsRemovable = true; ··· 15 16 "xen_blkfront" 16 17 "vmw_pvscsi" 17 18 ]; 18 - boot.initrd.kernelModules = ["nvme"]; 19 + boot.initrd.kernelModules = [ "nvme" ]; 19 20 fileSystems."/" = { 20 21 device = "/dev/sda1"; 21 22 fsType = "ext4";
+7 -9
hosts/reg/pds-backup.nix
··· 1 - { 2 - config, 3 - pkgs, 4 - ... 5 - }: let 1 + { config, pkgs, ... }: 2 + let 6 3 restoreScript = pkgs.writeShellScriptBin "pds-restore" '' 7 4 set -e 8 5 ··· 74 71 75 72 echo "$(date): Backup completed." >> "$LOG_FILE" 76 73 ''; 77 - in { 74 + in 75 + { 78 76 sops.secrets.s3 = { 79 77 format = "dotenv"; 80 78 sopsFile = ../../secrets/pds-backup-s3.env; 81 79 }; 82 80 83 - environment.systemPackages = [restoreScript]; 81 + environment.systemPackages = [ restoreScript ]; 84 82 85 83 systemd.services.pds-backup = { 86 84 description = "Backup PDS data to S3"; ··· 98 96 "TAR_CMD=${pkgs.gnutar}/bin/tar" 99 97 "AWS_CMD=${pkgs.awscli2}/bin/aws" 100 98 ]; 101 - EnvironmentFile = [config.sops.secrets.s3.path]; 99 + EnvironmentFile = [ config.sops.secrets.s3.path ]; 102 100 User = "root"; 103 101 Type = "oneshot"; 104 102 }; 105 103 }; 106 104 107 105 systemd.timers.pds-backup = { 108 - wantedBy = ["timers.target"]; 106 + wantedBy = [ "timers.target" ]; 109 107 timerConfig = { 110 108 OnCalendar = "daily"; 111 109 Persistent = true;
+15 -36
hosts/reg/pds.nix
··· 1 - {config, ...}: { 1 + { config, ... }: 2 + { 3 + imports = [ ../../modules/nixos/services/acme-nginx.nix ]; 2 4 sops = { 3 5 secrets.pds = { 4 6 format = "dotenv"; 5 7 sopsFile = ../../secrets/pds.env; 6 - restartUnits = ["bluesky-pds.service"]; 8 + restartUnits = [ "bluesky-pds.service" ]; 7 9 }; 8 10 secrets.cloudflare-api = { 9 11 format = "dotenv"; ··· 16 18 settings = { 17 19 PDS_HOSTNAME = "0xf.fr"; 18 20 }; 19 - environmentFiles = [config.sops.secrets.pds.path]; 21 + environmentFiles = [ config.sops.secrets.pds.path ]; 20 22 }; 21 23 22 - networking.firewall.allowedTCPPorts = [ 23 - 80 24 - 443 25 - ]; 26 - 27 - security.acme = { 28 - defaults.email = "netop@0xf.fr"; 29 - acceptTerms = true; 30 - 31 - certs."0xf.fr" = { 32 - dnsProvider = "cloudflare"; 33 - credentialsFile = config.sops.secrets.cloudflare-api.path; 34 - inherit (config.services.nginx) group; 35 - 36 - domain = "0xf.fr"; 37 - extraDomainNames = ["*.0xf.fr"]; 38 - reloadServices = ["nginx"]; 39 - }; 40 - }; 41 - 42 - services.nginx = let 43 - pass = { 44 - useACMEHost = "0xf.fr"; 45 - forceSSL = true; 46 - locations."/" = { 47 - proxyPass = "http://127.0.0.1:${toString config.services.bluesky-pds.settings.PDS_PORT}"; 48 - proxyWebsockets = true; 49 - }; 50 - }; 51 - in { 24 + services.acme-nginx = { 52 25 enable = true; 53 - recommendedProxySettings = true; 54 - recommendedTlsSettings = true; 55 - virtualHosts."~(.*)\\.0xf\\.fr$" = pass; 26 + email = "netop@0xf.fr"; 27 + credentialsFile = config.sops.secrets.cloudflare-api.path; 28 + hosts = [ 29 + { 30 + domain = "0xf.fr"; 31 + extraDomainNames = [ "*.0xf.fr" ]; 32 + proxyPort = config.services.bluesky-pds.settings.PDS_PORT; 33 + } 34 + ]; 56 35 }; 57 36 }
+6 -11
hosts/wakuna/default.nix
··· 2 2 inputs, 3 3 lib, 4 4 modulesPath, 5 + config, 5 6 ... 6 - }: { 7 + }: 8 + { 7 9 imports = [ 8 10 (modulesPath + "/installer/sd-card/sd-image-aarch64-installer.nix") 9 11 ./torrent.nix 10 12 ]; 11 13 12 14 sdImage.compressImage = false; 13 - 15 + my.username = "root"; 14 16 nixpkgs.hostPlatform = "aarch64-linux"; 15 17 system.stateVersion = "24.11"; 16 18 ··· 23 25 ]; 24 26 }; 25 27 26 - users.users.root.openssh.authorizedKeys.keyFiles = [inputs.ssh-keys]; 27 - services.openssh = { 28 - enable = true; 29 - settings.PermitRootLogin = "yes"; 30 - }; 28 + users.users.${config.my.username}.openssh.authorizedKeys.keyFiles = [ inputs.ssh-keys ]; 31 29 32 - services.tailscale = { 33 - enable = true; 34 - useRoutingFeatures = "server"; 35 - }; 30 + services.openssh.settings.PermitRootLogin = "yes"; 36 31 }
+3 -2
hosts/wakuna/torrent.nix
··· 1 - {config, ...}: { 1 + { config, ... }: 2 + { 2 3 systemd.services.flood.serviceConfig = { 3 - SupplementaryGroups = [config.services.rtorrent.group]; 4 + SupplementaryGroups = [ config.services.rtorrent.group ]; 4 5 }; 5 6 services = { 6 7 flood = {
+14 -1
modules/core.nix
··· 1 - {lib, ...}: { 1 + { lib, config, ... }: 2 + { 2 3 options.my.username = lib.mkOption { 3 4 type = lib.types.str; 4 5 description = "The username for the current user."; 5 6 default = "kar"; 7 + }; 8 + 9 + config = lib.mkIf (config.my.username != "root") { 10 + users.users.${config.my.username} = { 11 + home = "/home/${config.my.username}"; 12 + isNormalUser = true; 13 + extraGroups = [ 14 + "networkmanager" 15 + "docker" 16 + "wheel" 17 + ]; 18 + }; 6 19 }; 7 20 }
+13
modules/desktop/apps/browser.nix
··· 1 + { 2 + lib, 3 + config, 4 + pkgs, 5 + ... 6 + }: 7 + { 8 + config = lib.mkIf config.desktop.apps.enable { 9 + home = { 10 + packages = [ pkgs.firefox-devedition ]; 11 + }; 12 + }; 13 + }
+6
modules/desktop/apps/default.nix
··· 1 + { 2 + imports = [ 3 + ./browser.nix 4 + ./discord.nix 5 + ]; 6 + }
+4
modules/desktop/apps/discord.nix
··· 1 + { lib, config, ... }: 2 + { 3 + config = lib.mkIf config.desktop.apps.enable { programs.vesktop.enable = true; }; 4 + }
+6
modules/desktop/audio/default.nix
··· 1 + { 2 + imports = [ 3 + ./easyeffects.nix 4 + ./rnnoise.nix 5 + ]; 6 + }
+9
modules/desktop/audio/easyeffects.nix
··· 1 + { lib, config, ... }: 2 + { 3 + config = lib.mkIf config.desktop.audio.enable { 4 + xdg.configFile."easyeffects/output".source = ./easyeffects; 5 + services.easyeffects = { 6 + enable = true; 7 + }; 8 + }; 9 + }
+18
modules/desktop/default.nix
··· 1 + { config, self, ... }: 2 + { 3 + imports = [ 4 + self.nixosModules.desktop 5 + self.nixosModules.dev 6 + ../locale.nix 7 + ../nixos/desktop-common.nix 8 + ../hardware/peripherals.nix 9 + ]; 10 + 11 + desktop.enable = true; 12 + dev.enable = true; 13 + 14 + home-manager.users.${config.my.username}.imports = [ 15 + self.homeModules.desktop 16 + self.homeModules.dev 17 + ]; 18 + }
+47
modules/desktop/home.nix
··· 1 + { 2 + lib, 3 + osConfig ? { }, 4 + pkgs, 5 + ... 6 + }: 7 + let 8 + inherit (lib) mkEnableOption mkOption types; 9 + in 10 + { 11 + config.desktop = { 12 + inherit (osConfig.desktop or { }) 13 + enable 14 + wm 15 + terminal 16 + audio 17 + apps 18 + ; 19 + }; 20 + options.desktop = { 21 + enable = mkEnableOption "all desktop tools"; 22 + 23 + wm.enable = mkEnableOption "window manager and interface tools"; 24 + terminal.enable = mkEnableOption "terminal tools"; 25 + audio.enable = mkEnableOption "audio tools"; 26 + apps.enable = mkEnableOption "desktop applications"; 27 + browser.default = mkOption { 28 + description = "default browser xdg file"; 29 + default = "firefox-devedition.desktop"; 30 + type = types.str; 31 + }; 32 + wallpaper = lib.mkOption { 33 + default = pkgs.fetchurl { 34 + url = "https://raw.githubusercontent.com/HoulFloof/wallpapers/f23c1010b93cb97baa7ad7c94fd552f7601496d2/misc/waves_right_colored.png"; 35 + hash = "sha256-NqqE+pGnCIWAitH86sxu1EudVEEaSO82y3NqbhtDh9k="; 36 + }; 37 + type = lib.types.path; 38 + description = "the wallpaper to use"; 39 + }; 40 + }; 41 + imports = [ 42 + ./wm 43 + ./terminal 44 + ./audio 45 + ./apps 46 + ]; 47 + }
+33
modules/desktop/ipcam.nix
··· 1 + { 2 + config, 3 + lib, 4 + pkgs, 5 + ... 6 + }: 7 + { 8 + config = lib.mkIf config.desktop.ipcam.enable { 9 + boot = { 10 + extraModulePackages = with config.boot.kernelPackages; [ v4l2loopback ]; 11 + kernelModules = [ "v4l2loopback" ]; 12 + extraModprobeConfig = '' 13 + options v4l2loopback video_nr=9 card_label=IP-Webcam exclusive_caps=1 14 + ''; 15 + }; 16 + 17 + environment.systemPackages = 18 + let 19 + port = 9696; 20 + ipcam = pkgs.writeShellScriptBin "ipcam" '' 21 + ${lib.getExe' pkgs.android-tools "adb"} wait-for-usb-device 22 + ${lib.getExe' pkgs.android-tools "adb"} forward tcp:${toString port} tcp:8080 23 + ${lib.getExe pkgs.ffmpeg} -i http://localhost:${toString port}/video -vf format=yuv420p -f v4l2 /dev/video9 24 + ${lib.getExe' pkgs.android-tools "adb"} forward --remove tcp:${toString port} 25 + ''; 26 + in 27 + [ 28 + pkgs.ffmpeg 29 + pkgs.android-tools 30 + ipcam 31 + ]; 32 + }; 33 + }
+37
modules/desktop/nixos.nix
··· 1 + { config, lib, ... }: 2 + let 3 + cfg = config.desktop; 4 + inherit (lib) mkIf mkEnableOption; 5 + in 6 + { 7 + options.desktop = { 8 + enable = mkEnableOption "all desktop tools"; 9 + 10 + wm.enable = mkEnableOption "window manager and interface tools"; 11 + terminal.enable = mkEnableOption "terminal tools"; 12 + audio.enable = mkEnableOption "audio tools"; 13 + apps.enable = mkEnableOption "desktop applications"; 14 + ipcam.enable = mkEnableOption "IP camera support"; 15 + yubikey.enable = mkEnableOption "YubiKey support"; 16 + locale.enable = mkEnableOption "locale and timezone settings"; 17 + }; 18 + 19 + imports = [ 20 + ./desktop.nix 21 + ./sound.nix 22 + ./yubikey.nix 23 + ./fonts.nix 24 + ./locale.nix 25 + ./ipcam.nix 26 + ]; 27 + 28 + config = { 29 + desktop.wm.enable = mkIf cfg.enable true; 30 + desktop.terminal.enable = mkIf cfg.enable true; 31 + desktop.audio.enable = mkIf cfg.enable true; 32 + desktop.apps.enable = mkIf cfg.enable true; 33 + desktop.ipcam.enable = mkIf cfg.enable true; 34 + desktop.yubikey.enable = mkIf cfg.enable true; 35 + desktop.locale.enable = mkIf cfg.enable true; 36 + }; 37 + }
+1
modules/desktop/terminal/default.nix
··· 1 + { imports = [ ./ghostty.nix ]; }
+4
modules/desktop/wm/dunst.nix
··· 1 + { config, lib, ... }: 2 + { 3 + services.dunst = lib.mkIf config.desktop.wm.enable { enable = true; }; 4 + }
+9
modules/desktop/wm/fuzzel.nix
··· 1 + { config, lib, ... }: 2 + { 3 + programs.fuzzel = lib.mkIf config.desktop.wm.enable { 4 + enable = true; 5 + settings.main = { 6 + terminal = "ghostty"; 7 + }; 8 + }; 9 + }
+12
modules/desktop/wm/hyprpaper.nix
··· 1 + { config, lib, ... }: 2 + { 3 + config = lib.mkIf config.desktop.wm.enable { 4 + services.hyprpaper = { 5 + enable = true; 6 + settings = { 7 + preload = [ "${config.desktop.wallpaper}" ]; 8 + wallpaper = [ ", ${config.desktop.wallpaper}" ]; 9 + }; 10 + }; 11 + }; 12 + }
+265
modules/desktop/wm/niri.nix
··· 1 + { 2 + config, 3 + lib, 4 + pkgs, 5 + ... 6 + }: 7 + { 8 + config = lib.mkIf config.desktop.wm.enable { 9 + home.packages = [ pkgs.nautilus ]; # xdg-desktop-portal-gnome wants it 10 + programs.niri = { 11 + settings = { 12 + environment = { 13 + NIXOS_OZONE_WL = "1"; 14 + ELECTRON_OZONE_PLATFORM_HINT = "auto"; 15 + QT_QPA_PLATFORMTHEME = "qt5ct"; 16 + QT_QPA_PLATFORM = "wayland"; 17 + DISPLAY = ":0"; 18 + GTK_IM_MODULE = "simple"; 19 + }; 20 + 21 + screenshot-path = null; 22 + prefer-no-csd = true; 23 + 24 + input = { 25 + focus-follows-mouse = { 26 + enable = true; 27 + max-scroll-amount = "80%"; 28 + }; 29 + keyboard = { 30 + repeat-delay = 300; 31 + repeat-rate = 5; 32 + xkb = { 33 + layout = "us"; 34 + variant = "intl"; 35 + }; 36 + }; 37 + 38 + mouse = { 39 + accel-profile = "flat"; 40 + accel-speed = 0.5; 41 + }; 42 + 43 + touchpad = { 44 + tap = true; 45 + dwt = true; 46 + natural-scroll = true; 47 + click-method = "clickfinger"; 48 + }; 49 + }; 50 + 51 + spawn-at-startup = [ { command = [ "systemctl --user restart waybar.service" ]; } ]; 52 + 53 + layout = { 54 + gaps = 16; 55 + always-center-single-column = true; 56 + empty-workspace-above-first = true; 57 + default-column-width = { 58 + proportion = 0.5; 59 + }; 60 + }; 61 + 62 + window-rules = [ 63 + { 64 + geometry-corner-radius = 65 + let 66 + radius = 8.0; 67 + in 68 + { 69 + bottom-left = radius; 70 + bottom-right = radius; 71 + top-left = radius; 72 + top-right = radius; 73 + }; 74 + clip-to-geometry = true; 75 + } 76 + { 77 + matches = [ { title = "Picture-in-Picture"; } ]; 78 + open-floating = true; 79 + default-floating-position = { 80 + x = 16; 81 + y = 16; 82 + relative-to = "bottom-right"; 83 + }; 84 + } 85 + ]; 86 + 87 + outputs = rec { 88 + eDP-1 = { 89 + mode = null; 90 + position = { 91 + x = HDMI-A-1.mode.width; 92 + y = 0; 93 + }; 94 + }; 95 + HDMI-A-1 = { 96 + mode = { 97 + width = 2560; 98 + height = 1440; 99 + }; 100 + position = { 101 + x = 0; 102 + y = 0; 103 + }; 104 + }; 105 + }; 106 + 107 + binds = 108 + with config.lib.niri.actions; 109 + let 110 + # programs.niri.settings.binds."Mod+Q".action.close-window = [] 111 + toAction = 112 + act: dir: 113 + (lib.mapAttrs' ( 114 + argName: argValue: 115 + lib.nameValuePair "${argName}+${dir.name}" { 116 + action = { 117 + "${argValue}-${dir.value}" = [ ]; 118 + }; 119 + } 120 + ) act); 121 + windowMoves = lib.mergeAttrsList ( 122 + (map 123 + (toAction { 124 + "Mod" = "focus"; 125 + "Mod+Ctrl" = "move"; 126 + }) 127 + ( 128 + lib.attrsToList { 129 + "Up" = "window-up"; 130 + "k" = "window-up"; 131 + "Down" = "window-down"; 132 + "j" = "window-down"; 133 + "Left" = "column-left"; 134 + "h" = "column-left"; 135 + "Right" = "column-right"; 136 + "l" = "column-right"; 137 + "I" = "workspace-down"; 138 + "U" = "workspace-up"; 139 + } 140 + ) 141 + ) 142 + ++ (map 143 + (toAction { 144 + "Mod+Shift" = "focus"; 145 + "Mod+Ctrl+Shift" = "move-window-to"; 146 + }) 147 + ( 148 + lib.attrsToList { 149 + "Up" = "monitor-up"; 150 + "K" = "monitor-up"; 151 + "Down" = "monitor-down"; 152 + "J" = "monitor-down"; 153 + "Left" = "monitor-left"; 154 + "H" = "monitor-left"; 155 + "Right" = "monitor-right"; 156 + "L" = "monitor-right"; 157 + "I" = "workspace-down"; 158 + "U" = "workspace-up"; 159 + } 160 + ) 161 + ) 162 + ); 163 + in 164 + { 165 + "Mod+O".action = show-hotkey-overlay; 166 + "Mod+Q".action.spawn = "${lib.getExe pkgs.ghostty}"; 167 + "Mod+R".action.spawn = "${lib.getExe pkgs.fuzzel}"; 168 + "Mod+C".action.close-window = [ ]; 169 + 170 + "Mod+Comma".action = consume-window-into-column; 171 + "Mod+Period".action = expel-window-from-column; 172 + 173 + "Mod+T".action = switch-preset-column-width; 174 + "Mod+F".action = maximize-column; 175 + "Mod+Shift+F".action = fullscreen-window; 176 + "Mod+D".action = center-column; 177 + "Mod+B".action = toggle-window-floating; 178 + 179 + "Mod+Minus".action = set-column-width "-10%"; 180 + "Mod+Equal".action = set-column-width "+10%"; 181 + "Mod+Shift+Minus".action = set-window-height "-10%"; 182 + "Mod+Shift+Equal".action = set-window-height "+10%"; 183 + 184 + "Mod+Shift+Escape".action = toggle-keyboard-shortcuts-inhibit; 185 + "Mod+Shift+E".action = quit; 186 + "Mod+Shift+P".action = power-off-monitors; 187 + "Mod+Shift+Ctrl+T".action = toggle-debug-tint; 188 + 189 + "Mod+Shift+WheelScrollDown".action = focus-workspace-down; 190 + "Mod+Shift+WheelScrollUp".action = focus-workspace-up; 191 + "Mod+WheelScrollDown".action = focus-column-right; 192 + "Mod+WheelScrollUp".action = focus-column-left; 193 + 194 + "Mod+Shift+S".action.spawn = [ 195 + (lib.getExe pkgs.bash) 196 + "-c" 197 + ''${lib.getExe pkgs.slurp} -d | ${lib.getExe pkgs.grim} -t ppm -g - - | ${lib.getExe pkgs.satty} -f - --copy-command=${lib.getExe' pkgs.wl-clipboard "wl-copy"} --actions-on-escape="save-to-clipboard,exit"'' 198 + ]; 199 + "Mod+S".action.screenshot = { }; 200 + 201 + "XF86MonBrightnessDown".action.spawn = [ 202 + (lib.getExe pkgs.brightnessctl) 203 + "set" 204 + "5%-" 205 + ]; 206 + "XF86MonBrightnessUp".action.spawn = [ 207 + (lib.getExe pkgs.brightnessctl) 208 + "set" 209 + "+5%" 210 + ]; 211 + "XF86AudioLowerVolume".action.spawn = [ 212 + (lib.getExe' pkgs.wireplumber "wpctl") 213 + "set-volume" 214 + "@DEFAULT_AUDIO_SINK@" 215 + "2%-" 216 + ]; 217 + "XF86AudioRaiseVolume".action.spawn = [ 218 + (lib.getExe' pkgs.wireplumber "wpctl") 219 + "set-volume" 220 + "@DEFAULT_AUDIO_SINK@" 221 + "2%+" 222 + ]; 223 + } 224 + // windowMoves; 225 + 226 + animations = 227 + let 228 + vm = { 229 + kind.spring = { 230 + damping-ratio = 0.75; 231 + stiffness = 200; 232 + epsilon = 0.0001; 233 + }; 234 + }; 235 + in 236 + { 237 + horizontal-view-movement = vm; 238 + workspace-switch = vm; 239 + window-resize = vm; 240 + 241 + window-open = { 242 + kind.easing = { 243 + duration-ms = 200; 244 + curve = "linear"; 245 + }; 246 + custom-shader = '' 247 + vec4 open_color(vec3 coords_geo, vec3 size_geo) { 248 + vec3 coords_tex = niri_geo_to_tex * coords_geo; 249 + vec4 color = texture2D(niri_tex, coords_tex.st); 250 + 251 + vec2 coords = (coords_geo.xy - vec2(0.5, 0.5)) * size_geo.xy * 2.0; 252 + coords = coords / length(size_geo.xy); 253 + float p = niri_clamped_progress; 254 + if (p * p <= dot(coords, coords)) 255 + color = vec4(0.0); 256 + 257 + return color; 258 + } 259 + ''; 260 + }; 261 + }; 262 + }; 263 + }; 264 + }; 265 + }
+55
modules/desktop/wm/xdg.nix
··· 1 + { config, lib, ... }: 2 + { 3 + config = lib.mkIf config.desktop.wm.enable { 4 + xdg.mimeApps = 5 + let 6 + editor = "Helix.desktop"; 7 + browser = config.desktop.browser.default; 8 + in 9 + { 10 + enable = true; 11 + defaultApplications = { 12 + "x-scheme-handler/http " = browser; 13 + "x-scheme-handler/https" = browser; 14 + "x-scheme-handler/chrome" = browser; 15 + "text/html" = browser; 16 + "binary/octet-stream" = browser; 17 + "image/jpeg" = browser; 18 + "application/x-extension-htm" = browser; 19 + "application/x-extension-html" = browser; 20 + "application/x-extension-shtml" = browser; 21 + "application/xhtml+xml" = browser; 22 + "application/x-extension-xhtml" = browser; 23 + "application/x-extension-xht" = browser; 24 + "x-scheme-handler/about" = browser; 25 + "x-scheme-handler/unknown" = browser; 26 + "x-scheme-handler/discord" = "legcord.desktop"; 27 + "text/markdown" = editor; 28 + "text/plain" = editor; 29 + }; 30 + associations = { 31 + added = { 32 + "x-scheme-handler/http" = browser; 33 + "x-scheme-handler/https" = browser; 34 + "text/html" = browser; 35 + "binary/octet-stream" = browser; 36 + "image/jpeg" = browser; 37 + } 38 + // lib.mergeAttrsList ( 39 + map 40 + (lang: { 41 + "text/x-${lang}" = editor; 42 + "application/x-${lang}" = editor; 43 + }) 44 + [ 45 + "python" 46 + "go" 47 + "mod" 48 + "ruby" 49 + "yaml" 50 + ] 51 + ); 52 + }; 53 + }; 54 + }; 55 + }
+1
modules/dev/editor/default.nix
··· 1 + { imports = [ ./helix.nix ]; }
+556
modules/dev/editor/helix.nix
··· 1 + { 2 + lib, 3 + pkgs, 4 + inputs', 5 + self', 6 + config, 7 + ... 8 + }: 9 + let 10 + jj-patch = pkgs.fetchurl { 11 + url = "https://patch-diff.githubusercontent.com/raw/helix-editor/helix/pull/14519.patch"; 12 + hash = "sha256-e4xaKcOhAKKYbJXhYHbjdFk6CwLubmCp+m7y//MmQFw="; 13 + }; 14 + helix = inputs'.helix.packages.default.overrideAttrs (_: { 15 + patches = jj-patch; 16 + }); 17 + global-tools = with pkgs; [ 18 + nixfmt-rfc-style 19 + biome 20 + golangci-lint 21 + gotools 22 + gopls 23 + sql-formatter 24 + nodePackages.prettier 25 + ]; 26 + in 27 + lib.mkIf config.dev.editor.enable { 28 + home.packages = global-tools; 29 + programs.helix = { 30 + enable = true; 31 + defaultEditor = true; 32 + package = helix; 33 + extraPackages = 34 + with pkgs; 35 + [ 36 + golangci-lint-langserver 37 + nixd 38 + marksman 39 + nodePackages.typescript-language-server 40 + vscode-langservers-extracted 41 + yaml-language-server 42 + typos-lsp 43 + nil 44 + ] 45 + ++ global-tools; 46 + 47 + ignores = [ 48 + ".zig-cache" 49 + "node_modules" 50 + ".direnv" 51 + "!/notes" 52 + ]; 53 + 54 + settings = { 55 + keys = 56 + let 57 + plusMenu = { 58 + g = '' 59 + :sh ${pkgs.nushell}/bin/nu -c ' 60 + let line = ("%{selection_line_start}" | default "%{cursor_line}") 61 + let line_end = (if ("%{selection_line_end}" | is-not-empty) {$"-L%{selection_line_end}"} else "") 62 + let root = (${pkgs.jujutsu}/bin/jj workspace root | str trim) 63 + let rel_path = ("%{file_path_absolute}" | path relative-to $root) 64 + let ref = (${pkgs.jujutsu}/bin/jj log -r `heads(::@ & bookmarks())` -T `remote_bookmarks` | parse -r `(?<branch>[^\s]+)@(?<remote>[^\s]+)` | sort-by remote -r | get branch.0) 65 + let remote_url = (${pkgs.jujutsu}/bin/jj git remote list | parse "{remote} {url}" | where remote == origin | get url.0 | if ($in | str contains '://') {$in} else $"https://($in | str replace ':' '/')" | url parse) 66 + let url = $"https://($remote_url.host)($remote_url.path | str replace ".git" "")/blob/($ref)/($rel_path)#L($line)($line_end)" 67 + $url | ${pkgs.wl-clipboard}/bin/wl-copy 68 + ' 69 + ''; 70 + b = ":echo %sh{git blame -L %{cursor_line},+1 %{buffer_name}}"; 71 + p = ":sh echo %{buffer_name} | ${pkgs.wl-clipboard}/bin/wl-copy"; 72 + }; 73 + goMenu = { 74 + "8" = [ 75 + "move_prev_word_start" 76 + "move_next_word_end" 77 + ]; 78 + "c" = caseMenu; 79 + }; 80 + caseMenu = { 81 + p = ":pipe ${lib.getExe pkgs.sttr} pascal"; 82 + c = ":pipe ${lib.getExe pkgs.sttr} camel"; 83 + k = ":pipe ${lib.getExe pkgs.sttr} kebab"; 84 + K = ":pipe ${lib.getExe pkgs.sttr} kebab | ${lib.getExe pkgs.sttr} upper"; 85 + s = ":pipe ${lib.getExe pkgs.sttr} snake"; 86 + S = ":pipe ${lib.getExe pkgs.sttr} snake | ${lib.getExe pkgs.sttr} upper"; 87 + t = ":pipe ${lib.getExe pkgs.sttr} title"; 88 + }; 89 + runMenu = { 90 + f = [ 91 + ":sh golangci-lint run --issues-exit-code=0 --fix %{buffer_name}" 92 + ":reload" 93 + ]; 94 + }; 95 + scrollFast = { 96 + "C-j" = lib.replicate 5 "move_visual_line_down"; 97 + "C-k" = lib.replicate 5 "move_visual_line_up"; 98 + }; 99 + in 100 + { 101 + normal = { 102 + "+" = plusMenu; 103 + "-" = runMenu; 104 + "g" = goMenu; 105 + } 106 + // scrollFast; 107 + select = { 108 + "+" = plusMenu; 109 + "-" = runMenu; 110 + "." = goMenu; 111 + } 112 + // scrollFast; 113 + }; 114 + 115 + editor = { 116 + scrolloff = 10; 117 + text-width = 120; 118 + rulers = [ 120 ]; 119 + bufferline = "multiple"; 120 + color-modes = true; 121 + auto-format = true; 122 + auto-save = true; 123 + lsp = { 124 + snippets = true; 125 + display-color-swatches = true; 126 + display-messages = true; 127 + }; 128 + soft-wrap = { 129 + enable = true; 130 + }; 131 + statusline = { 132 + left = [ 133 + "mode" 134 + "spacer" 135 + "diagnostics" 136 + "version-control" 137 + "file-name" 138 + "read-only-indicator" 139 + "file-modification-indicator" 140 + "spinner" 141 + ]; 142 + right = [ 143 + "file-encoding" 144 + "file-type" 145 + "selections" 146 + "position" 147 + ]; 148 + }; 149 + gutters = [ 150 + "line-numbers" 151 + "diagnostics" 152 + "diff" 153 + ]; 154 + end-of-line-diagnostics = "hint"; 155 + inline-diagnostics = { 156 + cursor-line = "warning"; # show warnings and errors on the cursorline inline 157 + }; 158 + cursor-shape = { 159 + insert = "bar"; 160 + normal = "block"; 161 + select = "underline"; 162 + }; 163 + whitespace.render.tab = "all"; 164 + indent-guides = { 165 + render = true; 166 + character = "┊"; 167 + skip-levels = 1; 168 + }; 169 + }; 170 + }; 171 + 172 + languages = { 173 + language-server = { 174 + biome = { 175 + command = "biome"; 176 + args = [ "lsp-proxy" ]; 177 + }; 178 + nu-lsp = { 179 + command = "nu"; 180 + args = [ 181 + "--lsp" 182 + "--no-config-file" 183 + ]; 184 + }; 185 + typos = { 186 + command = "typos-lsp"; 187 + config = { 188 + diagnosticSeverity = "Warning"; 189 + }; 190 + }; 191 + yaml-language-server = { 192 + config = { 193 + enabled = true; 194 + enabledForFilesGlob = "*.{yaml,yml}"; 195 + diagnosticsLimit = 50; 196 + showDiagnosticsDirectly = false; 197 + config = { 198 + schemas = { 199 + kubernetes = "templates/**"; 200 + }; 201 + completion = true; 202 + hover = true; 203 + }; 204 + }; 205 + }; 206 + golangci-lint-lsp = { 207 + command = "golangci-lint-langserver"; 208 + config = { 209 + command = [ 210 + "nu" 211 + "-c" 212 + '' 213 + let args = [ 214 + --output.json.path=stdout 215 + --path-mode=abs 216 + --issues-exit-code=1 217 + --show-stats=false 218 + ] 219 + 220 + if ($env.GOLANGCI_LINT_CONFIG? | is-not-empty) { 221 + golangci-lint run --config $env.GOLANGCI_LINT_CONFIG ...$args 222 + } else { 223 + golangci-lint run ...$args 224 + } 225 + '' 226 + ]; 227 + }; 228 + }; 229 + rubocop = { 230 + command = "rubocop"; 231 + args = [ "--lsp" ]; 232 + }; 233 + ruby-lsp = { 234 + command = "ruby-lsp"; 235 + config = { 236 + diagnostics = true; 237 + formatting = true; 238 + config = { 239 + initializationOptions = { 240 + enabledFeatures = { 241 + codeActions = true; 242 + codeLens = true; 243 + completion = true; 244 + definition = true; 245 + diagnostics = true; 246 + documentHighlights = true; 247 + documentLink = true; 248 + documentSymbols = true; 249 + foldingRanges = true; 250 + formatting = true; 251 + hover = true; 252 + inlayHint = true; 253 + onTypeFormatting = true; 254 + selectionRanges = true; 255 + semanticHighlighting = true; 256 + signatureHelp = true; 257 + typeHierarchy = true; 258 + workspaceSymbol = true; 259 + }; 260 + featuresConfiguration = { 261 + inlayHint = { 262 + implicitHashValue = true; 263 + implicitRescue = true; 264 + }; 265 + }; 266 + }; 267 + }; 268 + }; 269 + }; 270 + thriftls = { 271 + command = "thriftls"; 272 + except-features = [ "format" ]; 273 + }; 274 + }; 275 + 276 + language = 277 + let 278 + defaults = [ "typos" ]; 279 + in 280 + map 281 + ( 282 + lang: 283 + lang 284 + // { 285 + language-servers = if lang ? language-servers then lang.language-servers ++ defaults else defaults; 286 + } 287 + ) 288 + ( 289 + [ 290 + { 291 + name = "nix"; 292 + language-servers = [ 293 + "nixd" 294 + "nil" 295 + ]; 296 + formatter = { 297 + command = "nixfmt"; 298 + args = [ 299 + "-s" 300 + "-w" 301 + "120" 302 + ]; 303 + }; 304 + auto-format = true; 305 + } 306 + { 307 + name = "go"; 308 + language-servers = [ 309 + "gopls" 310 + "golangci-lint-lsp" 311 + ]; 312 + formatter = { 313 + command = "goimports"; 314 + }; 315 + auto-format = true; 316 + } 317 + { 318 + name = "ruby"; 319 + language-servers = [ 320 + "ruby-lsp" 321 + "rubocop" 322 + ]; 323 + auto-format = true; 324 + } 325 + { 326 + name = "html"; 327 + language-servers = [ "vscode-html-language-server" ]; 328 + formatter = { 329 + command = "prettier"; 330 + args = [ 331 + "--stdin-filepath" 332 + "file.html" 333 + ]; 334 + }; 335 + auto-format = true; 336 + } 337 + { 338 + name = "javascript"; 339 + language-servers = [ 340 + { 341 + name = "typescript-language-server"; 342 + except-features = [ "format" ]; 343 + } 344 + "biome" 345 + ]; 346 + auto-format = true; 347 + } 348 + { 349 + name = "json"; 350 + language-servers = [ 351 + { 352 + name = "vscode-json-language-server"; 353 + except-features = [ "format" ]; 354 + } 355 + "biome" 356 + ]; 357 + formatter = { 358 + command = "biome"; 359 + args = [ 360 + "format" 361 + "--stdin-file-path" 362 + "file.json" 363 + ]; 364 + }; 365 + auto-format = true; 366 + } 367 + { 368 + name = "graphql"; 369 + formatter = { 370 + command = "biome"; 371 + args = [ 372 + "format" 373 + "--stdin-file-path" 374 + "file.gql" 375 + ]; 376 + }; 377 + auto-format = true; 378 + } 379 + { 380 + name = "jsonc"; 381 + language-servers = [ 382 + { 383 + name = "vscode-json-language-server"; 384 + except-features = [ "format" ]; 385 + } 386 + "biome" 387 + ]; 388 + formatter = { 389 + command = "biome"; 390 + args = [ 391 + "format" 392 + "--stdin-file-path" 393 + "file.jsonc" 394 + ]; 395 + }; 396 + file-types = [ 397 + "jsonc" 398 + "hujson" 399 + ]; 400 + auto-format = true; 401 + } 402 + { 403 + name = "jsx"; 404 + language-servers = [ 405 + { 406 + name = "typescript-language-server"; 407 + except-features = [ "format" ]; 408 + } 409 + "biome" 410 + ]; 411 + formatter = { 412 + command = "biome"; 413 + args = [ 414 + "format" 415 + "--stdin-file-path" 416 + "file.jsx" 417 + ]; 418 + }; 419 + auto-format = true; 420 + } 421 + { 422 + name = "tsx"; 423 + language-servers = [ 424 + { 425 + name = "typescript-language-server"; 426 + except-features = [ "format" ]; 427 + } 428 + "biome" 429 + ]; 430 + formatter = { 431 + command = "biome"; 432 + args = [ 433 + "format" 434 + "--stdin-file-path" 435 + "file.tsx" 436 + ]; 437 + }; 438 + auto-format = true; 439 + } 440 + { 441 + name = "typescript"; 442 + language-servers = [ 443 + { 444 + name = "typescript-language-server"; 445 + except-features = [ "format" ]; 446 + } 447 + "biome" 448 + ]; 449 + formatter = { 450 + command = "biome"; 451 + args = [ 452 + "format" 453 + "--stdin-file-path" 454 + "file.ts" 455 + ]; 456 + }; 457 + auto-format = true; 458 + } 459 + { 460 + name = "yaml"; 461 + language-servers = [ "yaml-language-server" ]; 462 + formatter = { 463 + command = "prettier"; 464 + args = [ 465 + "--stdin-filepath" 466 + "file.yaml" 467 + ]; 468 + }; 469 + auto-format = true; 470 + } 471 + { 472 + name = "helm"; 473 + language-servers = [ "helm_ls" ]; 474 + } 475 + { 476 + name = "typst"; 477 + language-servers = [ "tinymist" ]; 478 + } 479 + { 480 + name = "markdown"; 481 + language-servers = [ 482 + "marksman" 483 + # "vale-ls" 484 + ]; 485 + text-width = 100; 486 + rulers = [ 100 ]; 487 + soft-wrap = { 488 + enable = true; 489 + wrap-at-text-width = true; 490 + }; 491 + formatter = { 492 + command = "prettier"; 493 + args = [ 494 + "--stdin-filepath" 495 + "file.md" 496 + ]; 497 + }; 498 + auto-format = true; 499 + } 500 + { 501 + name = "sql"; 502 + formatter = { 503 + command = "sql-formatter"; 504 + args = [ 505 + "-c" 506 + (builtins.toJSON { 507 + keywordCase = "upper"; 508 + functionCase = "upper"; 509 + dataTypeCase = "upper"; 510 + identifierCase = "lower"; 511 + language = "postgresql"; 512 + expressionWidth = 80; 513 + tabWidth = 2; 514 + }) 515 + ]; 516 + }; 517 + auto-format = false; 518 + } 519 + { 520 + name = "nu"; 521 + language-servers = [ "nu-lsp" ]; 522 + formatter = { 523 + command = "${lib.getExe self'.packages.topiary-nu}"; 524 + args = [ 525 + "format" 526 + "--language" 527 + "nu" 528 + ]; 529 + }; 530 + auto-format = true; 531 + } 532 + { 533 + name = "thrift"; 534 + language-servers = [ "thriftls" ]; 535 + formatter = { 536 + command = "thriftls"; 537 + args = [ 538 + "format" 539 + "-indent" 540 + "2space" 541 + ]; 542 + }; 543 + auto-format = true; 544 + } 545 + ] 546 + ++ map (lang: { name = lang; }) [ 547 + "git-attributes" 548 + "git-commit" 549 + "git-config" 550 + "git-ignore" 551 + "git-rebase" 552 + ] 553 + ); 554 + }; 555 + }; 556 + }
+25
modules/dev/home.nix
··· 1 + { 2 + osConfig ? { }, 3 + lib, 4 + ... 5 + }: 6 + let 7 + inherit (lib) mkEnableOption; 8 + in 9 + { 10 + config.dev = osConfig.dev or { }; 11 + options.dev = { 12 + enable = mkEnableOption "all development tools"; 13 + 14 + shell.enable = mkEnableOption "shell-related tools"; 15 + editor.enable = mkEnableOption "editor tools"; 16 + vcs.enable = mkEnableOption "version control tools"; 17 + tools.enable = mkEnableOption "development utilities"; 18 + }; 19 + imports = [ 20 + ./shell 21 + ./editor 22 + ./vcs 23 + ./tools 24 + ]; 25 + }
+32
modules/dev/nixos.nix
··· 1 + { 2 + config, 3 + lib, 4 + pkgs, 5 + ... 6 + }: 7 + let 8 + cfg = config.dev; 9 + inherit (lib) mkIf mkEnableOption mkDefault; 10 + in 11 + { 12 + options.dev = { 13 + enable = mkEnableOption "all development tools"; 14 + 15 + shell.enable = mkEnableOption "shell-related tools"; 16 + editor.enable = mkEnableOption "editor tools"; 17 + vcs.enable = mkEnableOption "version control tools"; 18 + tools.enable = mkEnableOption "development utilities"; 19 + }; 20 + 21 + config = { 22 + dev.shell.enable = mkIf cfg.enable true; 23 + dev.editor.enable = mkIf cfg.enable true; 24 + dev.vcs.enable = mkIf cfg.enable true; 25 + dev.tools.enable = mkIf cfg.enable true; 26 + 27 + users.defaultUserShell = mkIf (cfg.enable || cfg.shell.enable) pkgs.nushell; 28 + environment.shells = mkIf (cfg.enable || cfg.shell.enable) [ pkgs.nushell ]; 29 + 30 + programs.nano.enable = mkDefault (!(cfg.enable || cfg.editor.enable)); 31 + }; 32 + }
+14
modules/dev/shell/atuin.nix
··· 1 + { config, lib, ... }: 2 + { 3 + config = lib.mkIf config.dev.shell.enable { 4 + programs.atuin = { 5 + enable = true; 6 + flags = [ "--disable-up-arrow" ]; 7 + settings = { 8 + enter_accept = false; 9 + style = "compact"; 10 + sync_address = "http://reg.dolly-ruffe.ts.net:8888"; 11 + }; 12 + }; 13 + }; 14 + }
+8
modules/dev/shell/default.nix
··· 1 + { 2 + imports = [ 3 + ./atuin.nix 4 + ./nushell.nix 5 + ./starship.nix 6 + ./zellij.nix 7 + ]; 8 + }
+39
modules/dev/shell/nushell.nix
··· 1 + { 2 + config, 3 + lib, 4 + pkgs, 5 + ... 6 + }: 7 + { 8 + config = lib.mkIf config.dev.shell.enable { 9 + programs.nushell = { 10 + enable = true; 11 + shellAliases = { 12 + k = "kubectl"; 13 + fg = "job unfreeze"; 14 + nn = "exec $env.EDITOR ~/notes"; 15 + }; 16 + configFile.text = '' 17 + $env.config = { 18 + show_banner: false, 19 + } 20 + 21 + if ("~/.profile.nu" | path exists) { 22 + source-env "~/.profile.nu" 23 + } 24 + 25 + ${lib.meta.getExe pkgs.pokego} -l french 26 + ''; 27 + 28 + extraLogin = '' 29 + bash -c ". /etc/profile && env" 30 + | parse "{n}={v}" 31 + | where n not-in $env or v != ($env | get $it.n) 32 + | where n not-in ["_", "LAST_EXIT_CODE", "DIRS_POSITION"] 33 + | transpose --header-row 34 + | into record 35 + | load-env 36 + ''; 37 + }; 38 + }; 39 + }
+108
modules/dev/shell/starship.nix
··· 1 + { 2 + config, 3 + inputs', 4 + lib, 5 + ... 6 + }: 7 + { 8 + config = lib.mkIf config.dev.shell.enable { 9 + xdg.configFile."starship-jj/starship-jj.toml".text = '' 10 + "$schema"="https://gitlab.com/Lanastara/lanastara_foss/-/raw/v0.3.0/schema.json?ref_type=tags" 11 + module_separator = " " 12 + timeout = 1000 13 + [bookmarks] 14 + search_depth = 100 15 + exclude = [] 16 + 17 + [[module]] 18 + type = "Commit" 19 + empty_text = "" 20 + [module.change] 21 + fg = "magenta" 22 + 23 + [[module]] 24 + type = "Bookmarks" 25 + separator = " " 26 + color = "Magenta" 27 + behind_symbol = "⇡" 28 + 29 + [[module]] 30 + type = "State" 31 + separator = " " 32 + 33 + [module.conflict] 34 + disabled = true 35 + text = "(CONFLICT)" 36 + color = "Red" 37 + 38 + [module.divergent] 39 + disabled = true 40 + text = "(DIVERGENT)" 41 + color = "Cyan" 42 + 43 + [module.empty] 44 + disabled = false 45 + text = "(EMPTY)" 46 + color = "Yellow" 47 + 48 + [module.immutable] 49 + disabled = false 50 + text = "(IMMUTABLE)" 51 + color = "Yellow" 52 + 53 + [module.hidden] 54 + disabled = false 55 + text = "(HIDDEN)" 56 + color = "Yellow" 57 + 58 + [[module]] 59 + type = "Metrics" 60 + template = "[{changed} {added}{removed}]" 61 + color = "Magenta" 62 + 63 + [module.changed_files] 64 + prefix = "" 65 + suffix = "" 66 + color = "Cyan" 67 + 68 + [module.added_lines] 69 + prefix = "+" 70 + suffix = "" 71 + color = "Green" 72 + 73 + [module.removed_lines] 74 + prefix = "-" 75 + suffix = "" 76 + color = "Red" 77 + ''; 78 + programs.starship = { 79 + enable = true; 80 + settings = { 81 + format = lib.concatMapStrings (s: s) [ 82 + "$directory" 83 + "$nix_shell" 84 + "$custom" 85 + "$cmd_duration" 86 + "$line_break" 87 + "$character" 88 + ]; 89 + nix_shell = { 90 + format = "[$symbol]($style)"; 91 + }; 92 + custom = { 93 + jj = { 94 + command = ''${lib.getExe' inputs'.starship-jj.packages.default "starship-jj"} --ignore-working-copy starship prompt''; 95 + format = "[$symbol](blue bold) $output"; 96 + symbol = "󱗆"; 97 + when = "jj root --ignore-working-copy"; 98 + }; 99 + git_branch = { 100 + when = true; 101 + command = "jj root >/dev/null 2>&1 || starship module git_branch"; 102 + description = "Only show git_branch if we're not in a jj repo"; 103 + }; 104 + }; 105 + }; 106 + }; 107 + }; 108 + }
+36
modules/dev/tools/default.nix
··· 1 + { 2 + config, 3 + lib, 4 + pkgs, 5 + ... 6 + }: 7 + { 8 + config = lib.mkIf config.dev.tools.enable { 9 + home.packages = [ 10 + pkgs.sd 11 + pkgs.fd 12 + pkgs.uutils-coreutils-noprefix 13 + ]; 14 + 15 + programs = { 16 + zoxide.enable = true; 17 + carapace.enable = true; 18 + 19 + ripgrep.enable = true; 20 + bat.enable = true; 21 + less = { 22 + enable = true; 23 + config = '' 24 + #env 25 + LESS = -S -R -i 26 + ''; 27 + }; 28 + }; 29 + }; 30 + 31 + imports = [ 32 + ./direnv.nix 33 + ./opencode.nix 34 + ./yazi.nix 35 + ]; 36 + }
+25
modules/dev/tools/direnv.nix
··· 1 + { config, lib, ... }: 2 + { 3 + config = lib.mkIf config.dev.tools.enable { 4 + programs.direnv = { 5 + enable = true; 6 + nix-direnv.enable = true; 7 + silent = true; 8 + stdlib = '' 9 + alias() { 10 + if [ ! $PWD/.direnv/bin ]; then 11 + mkdir $PWD/.direnv/bin 12 + fi 13 + 14 + echo "#!/usr/bin/env sh 15 + $2 \$@" > "$PWD/.direnv/bin/$1" 16 + chmod +x "$PWD/.direnv/bin/$1" 17 + } 18 + ''; 19 + }; 20 + 21 + programs.nushell.extraConfig = '' 22 + $env.DIRENV_LOG_FORMAT = "" 23 + ''; 24 + }; 25 + }
+72
modules/dev/tools/opencode.nix
··· 1 + { 2 + config, 3 + lib, 4 + pkgs, 5 + ... 6 + }: 7 + { 8 + config = lib.mkIf config.dev.tools.enable { 9 + programs.opencode = 10 + let 11 + opencodePkg = pkgs.symlinkJoin { 12 + name = "opencode-wrapped"; 13 + paths = [ 14 + pkgs.opencode 15 + pkgs.nixd 16 + pkgs.alejandra 17 + ]; 18 + buildInputs = [ pkgs.makeWrapper ]; 19 + postBuild = '' 20 + wrapProgram $out/bin/opencode \ 21 + --set SHELL ${pkgs.bash}/bin/bash 22 + ''; 23 + }; 24 + in 25 + { 26 + enable = true; 27 + package = opencodePkg; 28 + enableMcpIntegration = true; 29 + settings = { 30 + theme = "catppuccin-macchiato"; 31 + formatter = { 32 + alejandra = { 33 + command = [ "alejandra" ]; 34 + extensions = [ ".nix" ]; 35 + }; 36 + }; 37 + agent = { 38 + stack-analyst = { 39 + description = "Analyzes stack traces to map errors to code paths and identify root causes"; 40 + prompt = "You are a stack trace analyst. Analyze the provided stack trace to identify the root cause and suggest fixes."; 41 + mode = "primary"; 42 + tools = { 43 + read = true; 44 + glob = true; 45 + grep = true; 46 + write = true; 47 + edit = false; 48 + bash = true; 49 + }; 50 + permissions = { 51 + bash = { 52 + "git status" = "allow"; 53 + "git log" = "allow"; 54 + "*" = "ask"; 55 + }; 56 + }; 57 + }; 58 + }; 59 + mcp = { 60 + gopls = { 61 + type = "local"; 62 + enabled = true; 63 + command = [ 64 + "gopls" 65 + "mcp" 66 + ]; 67 + }; 68 + }; 69 + }; 70 + }; 71 + }; 72 + }
+8
modules/dev/tools/yazi.nix
··· 1 + { config, lib, ... }: 2 + { 3 + config = lib.mkIf config.dev.tools.enable { 4 + programs.yazi = { 5 + enable = true; 6 + }; 7 + }; 8 + }
+6
modules/dev/vcs/default.nix
··· 1 + { 2 + imports = [ 3 + ./git.nix 4 + ./jj.nix 5 + ]; 6 + }
+82
modules/dev/vcs/git.nix
··· 1 + { 2 + config, 3 + lib, 4 + pkgs, 5 + ... 6 + }: 7 + { 8 + config = lib.mkIf config.dev.vcs.enable { 9 + home.packages = [ pkgs.gh ]; 10 + programs.git = { 11 + enable = true; 12 + ignores = [ 13 + "/notes" 14 + "/tmp" 15 + ".direnv" 16 + ".envrc" 17 + ]; 18 + 19 + signing = { 20 + key = "~/.ssh/id_ed25519.pub"; 21 + signByDefault = true; 22 + }; 23 + 24 + settings = { 25 + user = { 26 + name = "karitham"; 27 + email = "kar@karitham.dev"; 28 + }; 29 + 30 + alias = { 31 + co = "checkout"; 32 + ci = "commit"; 33 + st = "status"; 34 + br = "branch"; 35 + hist = "log --pretty=format:'%h %ad | %s%d [%an]' --graph --date=short"; 36 + type = "cat-file -t"; 37 + dump = "cat-file -p"; 38 + dft = "difftool"; 39 + }; 40 + 41 + init.defaultBranch = "main"; 42 + merge.stat = true; 43 + pull.rebase = true; 44 + 45 + push = { 46 + autoSetupRemote = true; 47 + default = "current"; 48 + }; 49 + 50 + url."ssh://git@github.com/".insteadOf = "https://github.com/"; 51 + 52 + gpg = { 53 + format = "ssh"; 54 + ssh.defaultKeyCommand = "ssh-add -L"; 55 + }; 56 + 57 + core = { 58 + editor = config.home.sessionVariables.EDITOR; 59 + whitespace = "fix,-indent-with-non-tab,trailing-space,cr-at-eol"; 60 + }; 61 + 62 + pager.difftool = true; 63 + diff.tool = "difftastic"; 64 + difftool = { 65 + prompt = false; 66 + difftastic.cmd = "${pkgs.difftastic}/bin/difft --color auto --background light --display side-by-side \"$LOCAL\" \"$REMOTE\""; 67 + }; 68 + 69 + rebase = { 70 + autoSquash = true; 71 + autoStash = true; 72 + updateRefs = true; 73 + }; 74 + 75 + rerere = { 76 + enabled = true; 77 + autoUpdate = true; 78 + }; 79 + }; 80 + }; 81 + }; 82 + }
+52
modules/dev/vcs/jj.nix
··· 1 + { config, lib, ... }: 2 + { 3 + config = lib.mkIf config.dev.vcs.enable { 4 + programs.jujutsu = { 5 + enable = true; 6 + 7 + settings = { 8 + user = { 9 + email = "kar@karitham.dev"; 10 + name = "karitham"; 11 + }; 12 + signing = { 13 + behavior = "own"; 14 + backend = "ssh"; 15 + key = "~/.ssh/id_ed25519.pub"; 16 + }; 17 + git = { 18 + write-change-id-header = true; 19 + track-default-bookmark-on-clone = true; 20 + }; 21 + remotes."origin".auto-track-bookmarks = "glob:*"; 22 + revsets = { 23 + log = "..@ | branches | curbranch::@ | @::nextbranch | downstream(@, branchesandheads)"; 24 + }; 25 + revset-aliases = { 26 + "immutable_heads()" = "builtin_immutable_heads() | (trunk().. & ~mine())"; 27 + "downstream(x,y)" = "(x::y) & y"; 28 + "branches" = "downstream(trunk(), bookmarks()) & mine()"; 29 + "branchesandheads" = "branches | (heads(trunk()::) & mine())"; 30 + "curbranch" = "latest(branches::@- & branches)"; 31 + "nextbranch" = "roots(@:: & branchesandheads)"; 32 + }; 33 + ui = { 34 + default-command = [ 35 + "log" 36 + "--no-pager" 37 + "-n" 38 + "10" 39 + ]; 40 + movement.edit = true; 41 + editor = "hx"; 42 + }; 43 + }; 44 + }; 45 + 46 + programs.delta = { 47 + enable = true; 48 + enableJujutsuIntegration = true; 49 + enableGitIntegration = true; 50 + }; 51 + }; 52 + }
+6
modules/hardware/peripherals.nix
··· 1 + { pkgs, ... }: 2 + { 3 + hardware.bluetooth.enable = true; 4 + hardware.keyboard.qmk.enable = true; 5 + services.udev.packages = with pkgs; [ via ]; 6 + }
+17 -25
modules/home/default.nix
··· 5 5 self, 6 6 self', 7 7 ... 8 - }: { 9 - imports = [inputs.home-manager.nixosModules.default]; 10 - users.users.${config.my.username} = 11 - if config.my.username != "root" 12 - then { 13 - home = "/home/${config.my.username}"; 14 - isNormalUser = true; 15 - extraGroups = [ 16 - "networkmanager" 17 - "docker" 18 - "wheel" 19 - ]; 20 - } 21 - else {}; 8 + }: 9 + { 10 + imports = [ 11 + inputs.home-manager.nixosModules.default 12 + inputs.catppuccin.nixosModules.catppuccin 13 + ]; 14 + 15 + catppuccin = { 16 + enable = true; 17 + flavor = "macchiato"; 18 + }; 22 19 23 20 home-manager = { 24 21 extraSpecialArgs = { ··· 31 28 }; 32 29 backupFileExtension = "bak"; 33 30 users.${config.my.username} = { 34 - home.username = config.my.username; 35 - home.stateVersion = "25.11"; 31 + imports = [ inputs.catppuccin.homeModules.default ]; 36 32 37 - catppuccin = { 38 - inherit (config.catppuccin) enable; 39 - inherit (config.catppuccin) flavor; 33 + home = { 34 + inherit (config.my) username; 35 + stateVersion = "25.11"; 40 36 }; 37 + 38 + catppuccin = { inherit (config.catppuccin) flavor enable; }; 41 39 42 40 nixpkgs.overlays = [ 43 41 inputs.self.overlays.default 44 42 inputs.niri.overlays.niri 45 43 inputs.ghostty.overlays.default 46 44 inputs.knixpkgs.overlays.default 47 - ]; 48 - 49 - imports = [ 50 - inputs.catppuccin.homeModules.default 51 - ./desktop 52 - ./dev 53 45 ]; 54 46 }; 55 47 };
-18
modules/home/desktop/browser.nix
··· 1 - { 2 - lib, 3 - osConfig, 4 - pkgs, 5 - ... 6 - }: { 7 - options.browser.default = lib.mkOption { 8 - description = "default browser xdg file"; 9 - default = "firefox-devedition.desktop"; 10 - type = lib.types.str; 11 - }; 12 - 13 - config = lib.mkIf osConfig.desktop.enable { 14 - home = { 15 - packages = [pkgs.firefox-devedition]; 16 - }; 17 - }; 18 - }
+2 -5
modules/home/desktop/cursor.nix modules/desktop/wm/cursor.nix
··· 1 + { lib, config, ... }: 1 2 { 2 - lib, 3 - osConfig, 4 - ... 5 - }: { 6 - config = lib.mkIf osConfig.desktop.enable { 3 + config = lib.mkIf config.desktop.wm.enable { 7 4 catppuccin.cursors.enable = true; 8 5 home.pointerCursor = { 9 6 gtk.enable = true;
+1 -6
modules/home/desktop/default.nix modules/desktop/wm/default.nix
··· 1 - _: { 1 + { 2 2 imports = [ 3 - ./browser.nix 4 3 ./cursor.nix 5 - ./discord.nix 6 4 ./dunst.nix 7 - ./easyeffects.nix 8 5 ./fuzzel.nix 9 - ./ghostty.nix 10 6 ./hyprlock.nix 11 7 ./hyprpaper.nix 12 8 ./niri.nix 13 - ./rnnoise.nix 14 9 ./waybar.nix 15 10 ./xdg.nix 16 11 ];
-9
modules/home/desktop/discord.nix
··· 1 - { 2 - lib, 3 - osConfig, 4 - ... 5 - }: { 6 - config = lib.mkIf osConfig.desktop.enable { 7 - programs.vesktop.enable = true; 8 - }; 9 - }
-9
modules/home/desktop/dunst.nix
··· 1 - { 2 - osConfig, 3 - lib, 4 - ... 5 - }: { 6 - services.dunst = lib.mkIf osConfig.desktop.enable { 7 - enable = true; 8 - }; 9 - }
-6
modules/home/desktop/easyeffects.nix
··· 1 - _: { 2 - xdg.configFile."easyeffects/output".source = ./easyeffects; 3 - services.easyeffects = { 4 - enable = true; 5 - }; 6 - }
modules/home/desktop/easyeffects/EarFun Pro Air 4 ANC ON.json modules/desktop/audio/easyeffects/EarFun Pro Air 4 ANC ON.json
modules/home/desktop/easyeffects/Logitech G Pro X.json modules/desktop/audio/easyeffects/Logitech G Pro X.json
-12
modules/home/desktop/fuzzel.nix
··· 1 - { 2 - osConfig, 3 - lib, 4 - ... 5 - }: { 6 - programs.fuzzel = lib.mkIf osConfig.desktop.enable { 7 - enable = true; 8 - settings.main = { 9 - terminal = "ghostty"; 10 - }; 11 - }; 12 - }
modules/home/desktop/ghostty-shader.glsl modules/desktop/terminal/ghostty-shader.glsl
+4 -2
modules/home/desktop/ghostty.nix modules/desktop/terminal/ghostty.nix
··· 1 1 { 2 + config, 2 3 osConfig, 3 4 lib, 4 5 inputs', 5 6 ... 6 - }: { 7 - config = lib.mkIf osConfig.desktop.enable { 7 + }: 8 + { 9 + config = lib.mkIf config.desktop.terminal.enable { 8 10 programs.ghostty = { 9 11 enable = true; 10 12 package = inputs'.ghostty.packages.default;
+5 -3
modules/home/desktop/hyprlock.nix modules/desktop/wm/hyprlock.nix
··· 1 1 { 2 2 lib, 3 3 osConfig, 4 + config, 4 5 ... 5 - }: { 6 - config = lib.mkIf osConfig.desktop.enable { 6 + }: 7 + { 8 + config = lib.mkIf config.desktop.wm.enable { 7 9 services.hypridle = { 8 10 enable = true; 9 11 settings = { ··· 43 45 44 46 background = { 45 47 monitor = ""; 46 - path = "${osConfig.desktop.wallpaper}"; 48 + path = "${config.desktop.wallpaper}"; 47 49 blur_passes = 0; 48 50 color = "$base"; 49 51 };
-15
modules/home/desktop/hyprpaper.nix
··· 1 - { 2 - osConfig, 3 - lib, 4 - ... 5 - }: { 6 - config = lib.mkIf osConfig.desktop.enable { 7 - services.hyprpaper = { 8 - enable = true; 9 - settings = { 10 - preload = ["${osConfig.desktop.wallpaper}"]; 11 - wallpaper = [", ${osConfig.desktop.wallpaper}"]; 12 - }; 13 - }; 14 - }; 15 - }
-270
modules/home/desktop/niri.nix
··· 1 - { 2 - config, 3 - osConfig, 4 - lib, 5 - pkgs, 6 - ... 7 - }: { 8 - config = lib.mkIf (osConfig.desktop.enable && osConfig.desktop.enable) { 9 - home.packages = [pkgs.nautilus]; # xdg-desktop-portal-gnome wants it 10 - programs.niri = { 11 - settings = { 12 - environment = { 13 - NIXOS_OZONE_WL = "1"; 14 - ELECTRON_OZONE_PLATFORM_HINT = "auto"; 15 - QT_QPA_PLATFORMTHEME = "qt5ct"; 16 - QT_QPA_PLATFORM = "wayland"; 17 - DISPLAY = ":0"; 18 - GTK_IM_MODULE = "simple"; 19 - }; 20 - 21 - screenshot-path = null; 22 - prefer-no-csd = true; 23 - 24 - input = { 25 - focus-follows-mouse = { 26 - enable = true; 27 - max-scroll-amount = "80%"; 28 - }; 29 - keyboard = { 30 - repeat-delay = 300; 31 - repeat-rate = 5; 32 - xkb = { 33 - layout = "us"; 34 - variant = "intl"; 35 - }; 36 - }; 37 - 38 - mouse = { 39 - accel-profile = "flat"; 40 - accel-speed = 0.5; 41 - }; 42 - 43 - touchpad = { 44 - tap = true; 45 - dwt = true; 46 - natural-scroll = true; 47 - click-method = "clickfinger"; 48 - }; 49 - }; 50 - 51 - spawn-at-startup = [ 52 - { 53 - command = [ 54 - "systemctl --user restart waybar.service" 55 - ]; 56 - } 57 - ]; 58 - 59 - layout = { 60 - gaps = 16; 61 - always-center-single-column = true; 62 - empty-workspace-above-first = true; 63 - default-column-width = { 64 - proportion = 0.5; 65 - }; 66 - }; 67 - 68 - window-rules = [ 69 - { 70 - geometry-corner-radius = let 71 - radius = 8.0; 72 - in { 73 - bottom-left = radius; 74 - bottom-right = radius; 75 - top-left = radius; 76 - top-right = radius; 77 - }; 78 - clip-to-geometry = true; 79 - } 80 - { 81 - matches = [ 82 - { 83 - title = "Picture-in-Picture"; 84 - } 85 - ]; 86 - open-floating = true; 87 - default-floating-position = { 88 - x = 16; 89 - y = 16; 90 - relative-to = "bottom-right"; 91 - }; 92 - } 93 - ]; 94 - 95 - outputs = rec { 96 - eDP-1 = { 97 - mode = null; 98 - position = { 99 - x = HDMI-A-1.mode.width; 100 - y = 0; 101 - }; 102 - }; 103 - HDMI-A-1 = { 104 - mode = { 105 - width = 2560; 106 - height = 1440; 107 - }; 108 - position = { 109 - x = 0; 110 - y = 0; 111 - }; 112 - }; 113 - }; 114 - 115 - binds = with config.lib.niri.actions; let 116 - # programs.niri.settings.binds."Mod+Q".action.close-window = [] 117 - toAction = act: dir: (lib.mapAttrs' ( 118 - argName: argValue: 119 - lib.nameValuePair "${argName}+${dir.name}" { 120 - action = { 121 - "${argValue}-${dir.value}" = []; 122 - }; 123 - } 124 - ) 125 - act); 126 - windowMoves = lib.mergeAttrsList ( 127 - ( 128 - map 129 - (toAction { 130 - "Mod" = "focus"; 131 - "Mod+Ctrl" = "move"; 132 - }) 133 - ( 134 - lib.attrsToList { 135 - "Up" = "window-up"; 136 - "k" = "window-up"; 137 - "Down" = "window-down"; 138 - "j" = "window-down"; 139 - "Left" = "column-left"; 140 - "h" = "column-left"; 141 - "Right" = "column-right"; 142 - "l" = "column-right"; 143 - "I" = "workspace-down"; 144 - "U" = "workspace-up"; 145 - } 146 - ) 147 - ) 148 - ++ ( 149 - map 150 - (toAction { 151 - "Mod+Shift" = "focus"; 152 - "Mod+Ctrl+Shift" = "move-window-to"; 153 - }) 154 - ( 155 - lib.attrsToList { 156 - "Up" = "monitor-up"; 157 - "K" = "monitor-up"; 158 - "Down" = "monitor-down"; 159 - "J" = "monitor-down"; 160 - "Left" = "monitor-left"; 161 - "H" = "monitor-left"; 162 - "Right" = "monitor-right"; 163 - "L" = "monitor-right"; 164 - "I" = "workspace-down"; 165 - "U" = "workspace-up"; 166 - } 167 - ) 168 - ) 169 - ); 170 - in 171 - { 172 - "Mod+O".action = show-hotkey-overlay; 173 - "Mod+Q".action.spawn = "${lib.getExe pkgs.ghostty}"; 174 - "Mod+R".action.spawn = "${lib.getExe pkgs.fuzzel}"; 175 - "Mod+C".action.close-window = []; 176 - 177 - "Mod+Comma".action = consume-window-into-column; 178 - "Mod+Period".action = expel-window-from-column; 179 - 180 - "Mod+T".action = switch-preset-column-width; 181 - "Mod+F".action = maximize-column; 182 - "Mod+Shift+F".action = fullscreen-window; 183 - "Mod+D".action = center-column; 184 - "Mod+B".action = toggle-window-floating; 185 - 186 - "Mod+Minus".action = set-column-width "-10%"; 187 - "Mod+Equal".action = set-column-width "+10%"; 188 - "Mod+Shift+Minus".action = set-window-height "-10%"; 189 - "Mod+Shift+Equal".action = set-window-height "+10%"; 190 - 191 - "Mod+Shift+Escape".action = toggle-keyboard-shortcuts-inhibit; 192 - "Mod+Shift+E".action = quit; 193 - "Mod+Shift+P".action = power-off-monitors; 194 - "Mod+Shift+Ctrl+T".action = toggle-debug-tint; 195 - 196 - "Mod+Shift+WheelScrollDown".action = focus-workspace-down; 197 - "Mod+Shift+WheelScrollUp".action = focus-workspace-up; 198 - "Mod+WheelScrollDown".action = focus-column-right; 199 - "Mod+WheelScrollUp".action = focus-column-left; 200 - 201 - "Mod+Shift+S".action.spawn = [ 202 - (lib.getExe pkgs.bash) 203 - "-c" 204 - ''${lib.getExe pkgs.slurp} -d | ${lib.getExe pkgs.grim} -t ppm -g - - | ${lib.getExe pkgs.satty} -f - --copy-command=${lib.getExe' pkgs.wl-clipboard "wl-copy"} --actions-on-escape="save-to-clipboard,exit"'' 205 - ]; 206 - "Mod+S".action.screenshot = {}; 207 - 208 - "XF86MonBrightnessDown".action.spawn = [ 209 - (lib.getExe pkgs.brightnessctl) 210 - "set" 211 - "5%-" 212 - ]; 213 - "XF86MonBrightnessUp".action.spawn = [ 214 - (lib.getExe pkgs.brightnessctl) 215 - "set" 216 - "+5%" 217 - ]; 218 - "XF86AudioLowerVolume".action.spawn = [ 219 - (lib.getExe' pkgs.wireplumber "wpctl") 220 - "set-volume" 221 - "@DEFAULT_AUDIO_SINK@" 222 - "2%-" 223 - ]; 224 - "XF86AudioRaiseVolume".action.spawn = [ 225 - (lib.getExe' pkgs.wireplumber "wpctl") 226 - "set-volume" 227 - "@DEFAULT_AUDIO_SINK@" 228 - "2%+" 229 - ]; 230 - } 231 - // windowMoves; 232 - 233 - animations = let 234 - vm = { 235 - kind.spring = { 236 - damping-ratio = 0.75; 237 - stiffness = 200; 238 - epsilon = 0.0001; 239 - }; 240 - }; 241 - in { 242 - horizontal-view-movement = vm; 243 - workspace-switch = vm; 244 - window-resize = vm; 245 - 246 - window-open = { 247 - kind.easing = { 248 - duration-ms = 200; 249 - curve = "linear"; 250 - }; 251 - custom-shader = '' 252 - vec4 open_color(vec3 coords_geo, vec3 size_geo) { 253 - vec3 coords_tex = niri_geo_to_tex * coords_geo; 254 - vec4 color = texture2D(niri_tex, coords_tex.st); 255 - 256 - vec2 coords = (coords_geo.xy - vec2(0.5, 0.5)) * size_geo.xy * 2.0; 257 - coords = coords / length(size_geo.xy); 258 - float p = niri_clamped_progress; 259 - if (p * p <= dot(coords, coords)) 260 - color = vec4(0.0); 261 - 262 - return color; 263 - } 264 - ''; 265 - }; 266 - }; 267 - }; 268 - }; 269 - }; 270 - }
+4 -3
modules/home/desktop/rnnoise.nix modules/desktop/audio/rnnoise.nix
··· 1 1 { 2 - osConfig, 2 + config, 3 3 lib, 4 4 pkgs, 5 5 ... 6 - }: { 7 - config = lib.mkIf osConfig.desktop.enable { 6 + }: 7 + { 8 + config = lib.mkIf config.desktop.audio.enable { 8 9 xdg.configFile."pipewire/pipewire.conf.d/99-input-denoising.conf".text = builtins.toJSON { 9 10 "context.modules" = [ 10 11 {
+39 -35
modules/home/desktop/waybar.nix modules/desktop/wm/waybar.nix
··· 2 2 osConfig, 3 3 lib, 4 4 pkgs, 5 + config, 5 6 ... 6 - }: { 7 - config = lib.mkIf osConfig.desktop.enable { 7 + }: 8 + { 9 + config = lib.mkIf config.desktop.wm.enable { 8 10 programs.waybar = { 9 11 enable = true; 10 12 systemd.enable = true; ··· 21 23 "backlight" 22 24 ]; 23 25 24 - modules-center = lib.optional osConfig.desktop.enable "niri/workspaces"; 26 + modules-center = lib.optional config.desktop.wm.enable "niri/workspaces"; 25 27 26 28 modules-right = [ 27 29 "pulseaudio" ··· 60 62 critical-threshold = 80; 61 63 }; 62 64 63 - backlight = let 64 - bctl = lib.meta.getExe pkgs.brightnessctl; 65 - in { 66 - device = "eDP-1"; 67 - max-length = "4"; 68 - format = "{icon} {percent}%"; 69 - format-icons = [ 70 - "" 71 - "" 72 - "" 73 - "" 74 - "" 75 - "" 76 - "" 77 - "" 78 - "" 79 - ]; 80 - on-scroll-up = pkgs.writeShellScript "brightness.sh" '' 81 - MIN_BRIGHTNESS=5 82 - current_brightness=$(${bctl} g) 83 - max_brightness=$(${bctl} m) 84 - min_brightness_raw=$((max_brightness * MIN_BRIGHTNESS / 100)) 85 - scaling_factor=30 86 - decrement=$((max_brightness / scaling_factor)) 87 - new_brightness_raw=$((current_brightness - decrement)) 88 - if [ "$new_brightness_raw" -lt "$min_brightness_raw" ]; then 89 - new_brightness_raw=$min_brightness_raw 90 - fi 91 - ${bctl} set "$new_brightness_raw" 92 - ''; 93 - on-scroll-down = "${bctl} set +5%"; 94 - }; 65 + backlight = 66 + let 67 + bctl = lib.meta.getExe pkgs.brightnessctl; 68 + in 69 + { 70 + device = "eDP-1"; 71 + max-length = "4"; 72 + format = "{icon} {percent}%"; 73 + format-icons = [ 74 + "" 75 + "" 76 + "" 77 + "" 78 + "" 79 + "" 80 + "" 81 + "" 82 + "" 83 + ]; 84 + on-scroll-up = pkgs.writeShellScript "brightness.sh" '' 85 + MIN_BRIGHTNESS=5 86 + current_brightness=$(${bctl} g) 87 + max_brightness=$(${bctl} m) 88 + min_brightness_raw=$((max_brightness * MIN_BRIGHTNESS / 100)) 89 + scaling_factor=30 90 + decrement=$((max_brightness / scaling_factor)) 91 + new_brightness_raw=$((current_brightness - decrement)) 92 + if [ "$new_brightness_raw" -lt "$min_brightness_raw" ]; then 93 + new_brightness_raw=$min_brightness_raw 94 + fi 95 + ${bctl} set "$new_brightness_raw" 96 + ''; 97 + on-scroll-down = "${bctl} set +5%"; 98 + }; 95 99 96 100 pulseaudio = { 97 101 format = "{icon} {volume}%";
-55
modules/home/desktop/xdg.nix
··· 1 - { 2 - config, 3 - lib, 4 - ... 5 - }: { 6 - xdg.mimeApps = let 7 - editor = "Helix.desktop"; 8 - browser = config.browser.default; 9 - in { 10 - enable = true; 11 - defaultApplications = { 12 - "x-scheme-handler/http " = browser; 13 - "x-scheme-handler/https" = browser; 14 - "x-scheme-handler/chrome" = browser; 15 - "text/html" = browser; 16 - "binary/octet-stream" = browser; 17 - "image/jpeg" = browser; 18 - "application/x-extension-htm" = browser; 19 - "application/x-extension-html" = browser; 20 - "application/x-extension-shtml" = browser; 21 - "application/xhtml+xml" = browser; 22 - "application/x-extension-xhtml" = browser; 23 - "application/x-extension-xht" = browser; 24 - "x-scheme-handler/about" = browser; 25 - "x-scheme-handler/unknown" = browser; 26 - "x-scheme-handler/discord" = "legcord.desktop"; 27 - "text/markdown" = editor; 28 - "text/plain" = editor; 29 - }; 30 - associations = { 31 - added = 32 - { 33 - "x-scheme-handler/http" = browser; 34 - "x-scheme-handler/https" = browser; 35 - "text/html" = browser; 36 - "binary/octet-stream" = browser; 37 - "image/jpeg" = browser; 38 - } 39 - // lib.mergeAttrsList ( 40 - map 41 - (lang: { 42 - "text/x-${lang}" = editor; 43 - "application/x-${lang}" = editor; 44 - }) 45 - [ 46 - "python" 47 - "go" 48 - "mod" 49 - "ruby" 50 - "yaml" 51 - ] 52 - ); 53 - }; 54 - }; 55 - }
-13
modules/home/dev/atuin.nix
··· 1 - _: { 2 - programs.atuin = { 3 - enable = true; 4 - flags = [ 5 - "--disable-up-arrow" 6 - ]; 7 - settings = { 8 - enter_accept = false; 9 - style = "compact"; 10 - sync_address = "http://reg.dolly-ruffe.ts.net:8888"; 11 - }; 12 - }; 13 - }
-16
modules/home/dev/default.nix
··· 1 - _: { 2 - imports = [ 3 - ./atuin.nix 4 - ./direnv.nix 5 - ./git.nix 6 - ./helix.nix 7 - ./jj.nix 8 - ./mise.nix 9 - ./nushell.nix 10 - ./opencode.nix 11 - ./starship.nix 12 - ./utils.nix 13 - ./yazi.nix 14 - ./zellij.nix 15 - ]; 16 - }
-22
modules/home/dev/direnv.nix
··· 1 - _: { 2 - programs.direnv = { 3 - enable = true; 4 - nix-direnv.enable = true; 5 - silent = true; 6 - stdlib = '' 7 - alias() { 8 - if [ ! $PWD/.direnv/bin ]; then 9 - mkdir $PWD/.direnv/bin 10 - fi 11 - 12 - echo "#!/usr/bin/env sh 13 - $2 \$@" > "$PWD/.direnv/bin/$1" 14 - chmod +x "$PWD/.direnv/bin/$1" 15 - } 16 - ''; 17 - }; 18 - 19 - programs.nushell.extraConfig = '' 20 - $env.DIRENV_LOG_FORMAT = "" 21 - ''; 22 - }
-78
modules/home/dev/git.nix
··· 1 - { 2 - config, 3 - pkgs, 4 - ... 5 - }: { 6 - home.packages = [pkgs.gh]; 7 - programs.git = { 8 - enable = true; 9 - ignores = [ 10 - "/notes" 11 - "/tmp" 12 - ".direnv" 13 - ".envrc" 14 - ]; 15 - 16 - signing = { 17 - key = "~/.ssh/id_ed25519.pub"; 18 - signByDefault = true; 19 - }; 20 - 21 - settings = { 22 - user = { 23 - name = "karitham"; 24 - email = "kar@karitham.dev"; 25 - }; 26 - 27 - alias = { 28 - co = "checkout"; 29 - ci = "commit"; 30 - st = "status"; 31 - br = "branch"; 32 - hist = "log --pretty=format:'%h %ad | %s%d [%an]' --graph --date=short"; 33 - type = "cat-file -t"; 34 - dump = "cat-file -p"; 35 - dft = "difftool"; 36 - }; 37 - 38 - init.defaultBranch = "main"; 39 - merge.stat = true; 40 - pull.rebase = true; 41 - 42 - push = { 43 - autoSetupRemote = true; 44 - default = "current"; 45 - }; 46 - 47 - url."ssh://git@github.com/".insteadOf = "https://github.com/"; 48 - 49 - gpg = { 50 - format = "ssh"; 51 - ssh.defaultKeyCommand = "ssh-add -L"; 52 - }; 53 - 54 - core = { 55 - editor = config.home.sessionVariables.EDITOR; 56 - whitespace = "fix,-indent-with-non-tab,trailing-space,cr-at-eol"; 57 - }; 58 - 59 - pager.difftool = true; 60 - diff.tool = "difftastic"; 61 - difftool = { 62 - prompt = false; 63 - difftastic.cmd = "${pkgs.difftastic}/bin/difft --color auto --background light --display side-by-side \"$LOCAL\" \"$REMOTE\""; 64 - }; 65 - 66 - rebase = { 67 - autoSquash = true; 68 - autoStash = true; 69 - updateRefs = true; 70 - }; 71 - 72 - rerere = { 73 - enabled = true; 74 - autoUpdate = true; 75 - }; 76 - }; 77 - }; 78 - }
-551
modules/home/dev/helix.nix
··· 1 - { 2 - lib, 3 - pkgs, 4 - inputs', 5 - self', 6 - ... 7 - }: let 8 - jj-patch = pkgs.fetchurl { 9 - url = "https://patch-diff.githubusercontent.com/raw/helix-editor/helix/pull/14519.patch"; 10 - hash = "sha256-e4xaKcOhAKKYbJXhYHbjdFk6CwLubmCp+m7y//MmQFw="; 11 - }; 12 - helix = inputs'.helix.packages.default.overrideAttrs (_: { 13 - patches = jj-patch; 14 - }); 15 - global-tools = with pkgs; [ 16 - alejandra 17 - biome 18 - golangci-lint 19 - gotools 20 - gopls 21 - sql-formatter 22 - nodePackages.prettier 23 - ]; 24 - in { 25 - home.packages = global-tools; 26 - programs.helix = { 27 - enable = true; 28 - defaultEditor = true; 29 - package = helix; 30 - extraPackages = with pkgs; 31 - [ 32 - golangci-lint-langserver 33 - nixd 34 - marksman 35 - nodePackages.typescript-language-server 36 - vscode-langservers-extracted 37 - yaml-language-server 38 - typos-lsp 39 - nil 40 - ] 41 - ++ global-tools; 42 - 43 - ignores = [ 44 - ".zig-cache" 45 - "node_modules" 46 - ".direnv" 47 - "!/notes" 48 - ]; 49 - 50 - settings = { 51 - keys = let 52 - plusMenu = { 53 - g = '' 54 - :sh ${pkgs.nushell}/bin/nu -c ' 55 - let line = ("%{selection_line_start}" | default "%{cursor_line}") 56 - let line_end = (if ("%{selection_line_end}" | is-not-empty) {$"-L%{selection_line_end}"} else "") 57 - let root = (${pkgs.jujutsu}/bin/jj workspace root | str trim) 58 - let rel_path = ("%{file_path_absolute}" | path relative-to $root) 59 - let ref = (${pkgs.jujutsu}/bin/jj log -r `heads(::@ & bookmarks())` -T `remote_bookmarks` | parse -r `(?<branch>[^\s]+)@(?<remote>[^\s]+)` | sort-by remote -r | get branch.0) 60 - let remote_url = (${pkgs.jujutsu}/bin/jj git remote list | parse "{remote} {url}" | where remote == origin | get url.0 | if ($in | str contains '://') {$in} else $"https://($in | str replace ':' '/')" | url parse) 61 - let url = $"https://($remote_url.host)($remote_url.path | str replace ".git" "")/blob/($ref)/($rel_path)#L($line)($line_end)" 62 - $url | ${pkgs.wl-clipboard}/bin/wl-copy 63 - ' 64 - ''; 65 - b = ":echo %sh{git blame -L %{cursor_line},+1 %{buffer_name}}"; 66 - p = ":sh echo %{buffer_name} | ${pkgs.wl-clipboard}/bin/wl-copy"; 67 - }; 68 - goMenu = { 69 - "8" = [ 70 - "move_prev_word_start" 71 - "move_next_word_end" 72 - ]; 73 - "c" = caseMenu; 74 - }; 75 - caseMenu = { 76 - p = ":pipe ${lib.getExe pkgs.sttr} pascal"; 77 - c = ":pipe ${lib.getExe pkgs.sttr} camel"; 78 - k = ":pipe ${lib.getExe pkgs.sttr} kebab"; 79 - K = ":pipe ${lib.getExe pkgs.sttr} kebab | ${lib.getExe pkgs.sttr} upper"; 80 - s = ":pipe ${lib.getExe pkgs.sttr} snake"; 81 - S = ":pipe ${lib.getExe pkgs.sttr} snake | ${lib.getExe pkgs.sttr} upper"; 82 - t = ":pipe ${lib.getExe pkgs.sttr} title"; 83 - }; 84 - runMenu = { 85 - f = [ 86 - ":sh golangci-lint run --issues-exit-code=0 --fix %{buffer_name}" 87 - ":reload" 88 - ]; 89 - }; 90 - scrollFast = { 91 - "C-j" = lib.replicate 5 "move_visual_line_down"; 92 - "C-k" = lib.replicate 5 "move_visual_line_up"; 93 - }; 94 - in { 95 - normal = 96 - { 97 - "+" = plusMenu; 98 - "-" = runMenu; 99 - "g" = goMenu; 100 - } 101 - // scrollFast; 102 - select = 103 - { 104 - "+" = plusMenu; 105 - "-" = runMenu; 106 - "." = goMenu; 107 - } 108 - // scrollFast; 109 - }; 110 - 111 - editor = { 112 - scrolloff = 10; 113 - text-width = 120; 114 - rulers = [120]; 115 - bufferline = "multiple"; 116 - color-modes = true; 117 - auto-format = true; 118 - auto-save = true; 119 - lsp = { 120 - snippets = true; 121 - display-color-swatches = true; 122 - display-messages = true; 123 - }; 124 - soft-wrap = { 125 - enable = true; 126 - }; 127 - statusline = { 128 - left = [ 129 - "mode" 130 - "spacer" 131 - "diagnostics" 132 - "version-control" 133 - "file-name" 134 - "read-only-indicator" 135 - "file-modification-indicator" 136 - "spinner" 137 - ]; 138 - right = [ 139 - "file-encoding" 140 - "file-type" 141 - "selections" 142 - "position" 143 - ]; 144 - }; 145 - gutters = [ 146 - "line-numbers" 147 - "diagnostics" 148 - "diff" 149 - ]; 150 - end-of-line-diagnostics = "hint"; 151 - inline-diagnostics = { 152 - cursor-line = "warning"; # show warnings and errors on the cursorline inline 153 - }; 154 - cursor-shape = { 155 - insert = "bar"; 156 - normal = "block"; 157 - select = "underline"; 158 - }; 159 - whitespace.render.tab = "all"; 160 - indent-guides = { 161 - render = true; 162 - character = "┊"; 163 - skip-levels = 1; 164 - }; 165 - }; 166 - }; 167 - 168 - languages = { 169 - language-server = { 170 - biome = { 171 - command = "biome"; 172 - args = ["lsp-proxy"]; 173 - }; 174 - nu-lsp = { 175 - command = "nu"; 176 - args = [ 177 - "--lsp" 178 - "--no-config-file" 179 - ]; 180 - }; 181 - typos = { 182 - command = "typos-lsp"; 183 - config = { 184 - diagnosticSeverity = "Warning"; 185 - }; 186 - }; 187 - yaml-language-server = { 188 - config = { 189 - enabled = true; 190 - enabledForFilesGlob = "*.{yaml,yml}"; 191 - diagnosticsLimit = 50; 192 - showDiagnosticsDirectly = false; 193 - config = { 194 - schemas = { 195 - kubernetes = "templates/**"; 196 - }; 197 - completion = true; 198 - hover = true; 199 - }; 200 - }; 201 - }; 202 - golangci-lint-lsp = { 203 - command = "golangci-lint-langserver"; 204 - config = { 205 - command = [ 206 - "nu" 207 - "-c" 208 - '' 209 - let args = [ 210 - --output.json.path=stdout 211 - --path-mode=abs 212 - --issues-exit-code=1 213 - --show-stats=false 214 - ] 215 - 216 - if ($env.GOLANGCI_LINT_CONFIG? | is-not-empty) { 217 - golangci-lint run --config $env.GOLANGCI_LINT_CONFIG ...$args 218 - } else { 219 - golangci-lint run ...$args 220 - } 221 - '' 222 - ]; 223 - }; 224 - }; 225 - rubocop = { 226 - command = "rubocop"; 227 - args = ["--lsp"]; 228 - }; 229 - ruby-lsp = { 230 - command = "ruby-lsp"; 231 - config = { 232 - diagnostics = true; 233 - formatting = true; 234 - config = { 235 - initializationOptions = { 236 - enabledFeatures = { 237 - codeActions = true; 238 - codeLens = true; 239 - completion = true; 240 - definition = true; 241 - diagnostics = true; 242 - documentHighlights = true; 243 - documentLink = true; 244 - documentSymbols = true; 245 - foldingRanges = true; 246 - formatting = true; 247 - hover = true; 248 - inlayHint = true; 249 - onTypeFormatting = true; 250 - selectionRanges = true; 251 - semanticHighlighting = true; 252 - signatureHelp = true; 253 - typeHierarchy = true; 254 - workspaceSymbol = true; 255 - }; 256 - featuresConfiguration = { 257 - inlayHint = { 258 - implicitHashValue = true; 259 - implicitRescue = true; 260 - }; 261 - }; 262 - }; 263 - }; 264 - }; 265 - }; 266 - thriftls = { 267 - command = "thriftls"; 268 - except-features = ["format"]; 269 - }; 270 - }; 271 - 272 - language = let 273 - defaults = [ 274 - "typos" 275 - ]; 276 - in 277 - map 278 - ( 279 - lang: 280 - lang 281 - // { 282 - language-servers = 283 - if lang ? language-servers 284 - then lang.language-servers ++ defaults 285 - else defaults; 286 - } 287 - ) 288 - ( 289 - [ 290 - { 291 - name = "nix"; 292 - language-servers = [ 293 - "nixd" 294 - "nil" 295 - ]; 296 - formatter = { 297 - command = "alejandra"; 298 - }; 299 - auto-format = true; 300 - } 301 - { 302 - name = "go"; 303 - language-servers = [ 304 - "gopls" 305 - "golangci-lint-lsp" 306 - ]; 307 - formatter = { 308 - command = "goimports"; 309 - }; 310 - auto-format = true; 311 - } 312 - { 313 - name = "ruby"; 314 - language-servers = [ 315 - "ruby-lsp" 316 - "rubocop" 317 - ]; 318 - auto-format = true; 319 - } 320 - { 321 - name = "html"; 322 - language-servers = ["vscode-html-language-server"]; 323 - formatter = { 324 - command = "prettier"; 325 - args = [ 326 - "--stdin-filepath" 327 - "file.html" 328 - ]; 329 - }; 330 - auto-format = true; 331 - } 332 - { 333 - name = "javascript"; 334 - language-servers = [ 335 - { 336 - name = "typescript-language-server"; 337 - except-features = ["format"]; 338 - } 339 - "biome" 340 - ]; 341 - auto-format = true; 342 - } 343 - { 344 - name = "json"; 345 - language-servers = [ 346 - { 347 - name = "vscode-json-language-server"; 348 - except-features = ["format"]; 349 - } 350 - "biome" 351 - ]; 352 - formatter = { 353 - command = "biome"; 354 - args = [ 355 - "format" 356 - "--stdin-file-path" 357 - "file.json" 358 - ]; 359 - }; 360 - auto-format = true; 361 - } 362 - { 363 - name = "graphql"; 364 - formatter = { 365 - command = "biome"; 366 - args = [ 367 - "format" 368 - "--stdin-file-path" 369 - "file.gql" 370 - ]; 371 - }; 372 - auto-format = true; 373 - } 374 - { 375 - name = "jsonc"; 376 - language-servers = [ 377 - { 378 - name = "vscode-json-language-server"; 379 - except-features = ["format"]; 380 - } 381 - "biome" 382 - ]; 383 - formatter = { 384 - command = "biome"; 385 - args = [ 386 - "format" 387 - "--stdin-file-path" 388 - "file.jsonc" 389 - ]; 390 - }; 391 - file-types = [ 392 - "jsonc" 393 - "hujson" 394 - ]; 395 - auto-format = true; 396 - } 397 - { 398 - name = "jsx"; 399 - language-servers = [ 400 - { 401 - name = "typescript-language-server"; 402 - except-features = ["format"]; 403 - } 404 - "biome" 405 - ]; 406 - formatter = { 407 - command = "biome"; 408 - args = [ 409 - "format" 410 - "--stdin-file-path" 411 - "file.jsx" 412 - ]; 413 - }; 414 - auto-format = true; 415 - } 416 - { 417 - name = "tsx"; 418 - language-servers = [ 419 - { 420 - name = "typescript-language-server"; 421 - except-features = ["format"]; 422 - } 423 - "biome" 424 - ]; 425 - formatter = { 426 - command = "biome"; 427 - args = [ 428 - "format" 429 - "--stdin-file-path" 430 - "file.tsx" 431 - ]; 432 - }; 433 - auto-format = true; 434 - } 435 - { 436 - name = "typescript"; 437 - language-servers = [ 438 - { 439 - name = "typescript-language-server"; 440 - except-features = ["format"]; 441 - } 442 - "biome" 443 - ]; 444 - formatter = { 445 - command = "biome"; 446 - args = [ 447 - "format" 448 - "--stdin-file-path" 449 - "file.ts" 450 - ]; 451 - }; 452 - auto-format = true; 453 - } 454 - { 455 - name = "yaml"; 456 - language-servers = ["yaml-language-server"]; 457 - formatter = { 458 - command = "prettier"; 459 - args = [ 460 - "--stdin-filepath" 461 - "file.yaml" 462 - ]; 463 - }; 464 - auto-format = true; 465 - } 466 - { 467 - name = "helm"; 468 - language-servers = ["helm_ls"]; 469 - } 470 - { 471 - name = "typst"; 472 - language-servers = ["tinymist"]; 473 - } 474 - { 475 - name = "markdown"; 476 - language-servers = [ 477 - "marksman" 478 - # "vale-ls" 479 - ]; 480 - text-width = 100; 481 - rulers = [100]; 482 - soft-wrap = { 483 - enable = true; 484 - wrap-at-text-width = true; 485 - }; 486 - formatter = { 487 - command = "prettier"; 488 - args = [ 489 - "--stdin-filepath" 490 - "file.md" 491 - ]; 492 - }; 493 - auto-format = true; 494 - } 495 - { 496 - name = "sql"; 497 - formatter = { 498 - command = "sql-formatter"; 499 - args = [ 500 - "-c" 501 - (builtins.toJSON { 502 - keywordCase = "upper"; 503 - functionCase = "upper"; 504 - dataTypeCase = "upper"; 505 - identifierCase = "lower"; 506 - language = "postgresql"; 507 - expressionWidth = 80; 508 - tabWidth = 2; 509 - }) 510 - ]; 511 - }; 512 - auto-format = false; 513 - } 514 - { 515 - name = "nu"; 516 - language-servers = ["nu-lsp"]; 517 - formatter = { 518 - command = "${lib.getExe self'.packages.topiary-nu}"; 519 - args = [ 520 - "format" 521 - "--language" 522 - "nu" 523 - ]; 524 - }; 525 - auto-format = true; 526 - } 527 - { 528 - name = "thrift"; 529 - language-servers = ["thriftls"]; 530 - formatter = { 531 - command = "thriftls"; 532 - args = [ 533 - "format" 534 - "-indent" 535 - "2space" 536 - ]; 537 - }; 538 - auto-format = true; 539 - } 540 - ] 541 - ++ map (lang: {name = lang;}) [ 542 - "git-attributes" 543 - "git-commit" 544 - "git-config" 545 - "git-ignore" 546 - "git-rebase" 547 - ] 548 - ); 549 - }; 550 - }; 551 - }
-49
modules/home/dev/jj.nix
··· 1 - _: { 2 - programs.jujutsu = { 3 - enable = true; 4 - 5 - settings = { 6 - user = { 7 - email = "kar@karitham.dev"; 8 - name = "karitham"; 9 - }; 10 - signing = { 11 - behavior = "own"; 12 - backend = "ssh"; 13 - key = "~/.ssh/id_ed25519.pub"; 14 - }; 15 - git = { 16 - write-change-id-header = true; 17 - track-default-bookmark-on-clone = true; 18 - }; 19 - remotes."origin".auto-track-bookmarks = "glob:*"; 20 - revsets = { 21 - log = "..@ | branches | curbranch::@ | @::nextbranch | downstream(@, branchesandheads)"; 22 - }; 23 - revset-aliases = { 24 - "immutable_heads()" = "builtin_immutable_heads() | (trunk().. & ~mine())"; 25 - "downstream(x,y)" = "(x::y) & y"; 26 - "branches" = "downstream(trunk(), bookmarks()) & mine()"; 27 - "branchesandheads" = "branches | (heads(trunk()::) & mine())"; 28 - "curbranch" = "latest(branches::@- & branches)"; 29 - "nextbranch" = "roots(@:: & branchesandheads)"; 30 - }; 31 - ui = { 32 - default-command = [ 33 - "log" 34 - "--no-pager" 35 - "-n" 36 - "10" 37 - ]; 38 - movement.edit = true; 39 - editor = "hx"; 40 - }; 41 - }; 42 - }; 43 - 44 - programs.delta = { 45 - enable = true; 46 - enableJujutsuIntegration = true; 47 - enableGitIntegration = true; 48 - }; 49 - }
-17
modules/home/dev/mise.nix
··· 1 - { 2 - lib, 3 - config, 4 - ... 5 - }: { 6 - config = lib.mkIf config.programs.mise.enable { 7 - programs.nushell = { 8 - envFile.text = '' 9 - let mise_path = $nu.default-config-dir | path join mise.nu 10 - ^mise activate nu | save $mise_path --force 11 - ''; 12 - configFile.text = '' 13 - use ($nu.default-config-dir | path join mise.nu) 14 - ''; 15 - }; 16 - }; 17 - }
-35
modules/home/dev/nushell.nix
··· 1 - { 2 - lib, 3 - pkgs, 4 - ... 5 - }: { 6 - programs.nushell = { 7 - enable = true; 8 - shellAliases = { 9 - k = "kubectl"; 10 - fg = "job unfreeze"; 11 - nn = "exec $env.EDITOR ~/notes"; 12 - }; 13 - configFile.text = '' 14 - $env.config = { 15 - show_banner: false, 16 - } 17 - 18 - if ("~/.profile.nu" | path exists) { 19 - source-env "~/.profile.nu" 20 - } 21 - 22 - ${lib.meta.getExe pkgs.pokego} -l french 23 - ''; 24 - 25 - extraLogin = '' 26 - bash -c ". /etc/profile && env" 27 - | parse "{n}={v}" 28 - | where n not-in $env or v != ($env | get $it.n) 29 - | where n not-in ["_", "LAST_EXIT_CODE", "DIRS_POSITION"] 30 - | transpose --header-row 31 - | into record 32 - | load-env 33 - ''; 34 - }; 35 - }
-62
modules/home/dev/opencode.nix
··· 1 - {pkgs, ...}: { 2 - programs.opencode = let 3 - opencodePkg = pkgs.symlinkJoin { 4 - name = "opencode-wrapped"; 5 - paths = [ 6 - pkgs.opencode 7 - pkgs.nixd 8 - pkgs.alejandra 9 - ]; 10 - buildInputs = [pkgs.makeWrapper]; 11 - postBuild = '' 12 - wrapProgram $out/bin/opencode \ 13 - --set SHELL ${pkgs.bash}/bin/bash 14 - ''; 15 - }; 16 - in { 17 - enable = true; 18 - package = opencodePkg; 19 - enableMcpIntegration = true; 20 - settings = { 21 - theme = "catppuccin-macchiato"; 22 - formatter = { 23 - alejandra = { 24 - command = ["alejandra"]; 25 - extensions = [".nix"]; 26 - }; 27 - }; 28 - agent = { 29 - stack-analyst = { 30 - description = "Analyzes stack traces to map errors to code paths and identify root causes"; 31 - prompt = builtins.readFile ./opencode/stack-analyst.md; 32 - mode = "primary"; 33 - tools = { 34 - read = true; 35 - glob = true; 36 - grep = true; 37 - write = true; 38 - edit = false; 39 - bash = true; 40 - }; 41 - permissions = { 42 - bash = { 43 - "git status" = "allow"; 44 - "git log" = "allow"; 45 - "*" = "ask"; 46 - }; 47 - }; 48 - }; 49 - }; 50 - mcp = { 51 - gopls = { 52 - type = "local"; 53 - enabled = true; 54 - command = [ 55 - "gopls" 56 - "mcp" 57 - ]; 58 - }; 59 - }; 60 - }; 61 - }; 62 - }
-48
modules/home/dev/opencode/stack-analyst.md
··· 1 - You are the **Stack Trace & Debugging Specialist**, an advanced engineering agent dedicated to performing root cause analysis on software crashes, errors, and panics. 2 - 3 - ### Core Objective 4 - Your goal is to take a stack trace (from text, a file, a URL, or an issue tracker) and provide a deterministic explanation of *why* the code failed, along with the specific inputs or state required to reproduce it. 5 - 6 - ### Capabilities & Tooling Strategy 7 - 1. **Code Intelligence (LSP) [Best Effort]:** 8 - * **Primary Tool:** Attempt to use `gopls` (for Go) or `ruby-lsp` (for Ruby) to read and understand code. 9 - * **Fallback:** If LSP tools fail to launch (e.g., due to missing gems/dependencies) or return errors, **immediately** switch to standard `grep`, `glob`, and `read` tools. Do not waste turns debugging the LSP setup itself. 10 - * **Usage:** Use these tools to jump to definitions, view struct/class hierarchies, and inspect function signatures. 11 - * **Why:** To accurately interpret types, interfaces, and shared logic that simple text searching might miss. 12 - 13 - 2. **Context Retrieval:** 14 - * **Inputs:** You may receive stack traces as raw text, file paths, or URLs (e.g., Linear issues, GitHub issues, Pastebin). 15 - * **Linear:** If provided a Linear link, use the `linear` tool to extract the crash report and context. 16 - * **File System:** Use `read` and `glob` to ingest logs, config files, or local repro cases. 17 - 18 - 3. **Codebase Navigation:** 19 - * Use `glob` to fuzzy-find files when stack trace paths are relative or truncated. 20 - * Use `grep` to find where specific error messages or constants are generated. 21 - 22 - ### Analysis Protocol 23 - 24 - **Phase 1: Ingestion & Parsing** 25 - * Identify the panic message, error code, or exception type. 26 - * Extract the stack trace frames. Distinguish between library/framework code (noise) and application code (signal). 27 - 28 - **Phase 2: Mapping & Inspection** 29 - * Locate the exact file and line number of the crash. 30 - * **Crucial:** Use LSP tools to inspect the definitions of variables involved at the crash site. 31 - * *Example:* If `user.Process()` panicked, check the definition of `user`. Is it a pointer? interface? nullable? 32 - 33 - **Phase 3: Backward Execution Trace** 34 - * Analyze the calling frames. How did execution reach the failure point? 35 - * Identify "source" data. Where did the variables causing the crash originate? (e.g., HTTP request body, database row, config file). 36 - 37 - **Phase 4: Root Cause & Reproduction** 38 - * **Hypothesize:** Formulate a strict logical theory (e.g., "The `Context` object was canceled before the database transaction completed, but error checking was skipped"). 39 - * **Payload Reconstruction:** Define the specific JSON payload, environment variable, or sequence of events needed to trigger this path. 40 - 41 - ### Output Style 42 - * **Direct & Analytical:** Start with the root cause. 43 - * **Evidence-Based:** Cite specific file names, line numbers, and variable types. 44 - * **Actionable:** Conclude with a specific code path fix or a reproduction payload. 45 - 46 - ### Constraints 47 - * **Read-Only Analysis:** Your primary role is analysis and diagnosis. Do not run commands that modify the codebase (like `rails generate`, `npm install`, or writing files) unless explicitly asked to "fix" or "apply" the solution. 48 - * **Safe Exploration:** You may run read-only commands (e.g., `grep`, `ls`, `cat`) freely.
-104
modules/home/dev/starship.nix
··· 1 - { 2 - inputs', 3 - lib, 4 - ... 5 - }: { 6 - xdg.configFile."starship-jj/starship-jj.toml".text = '' 7 - "$schema"="https://gitlab.com/Lanastara/lanastara_foss/-/raw/v0.3.0/schema.json?ref_type=tags" 8 - module_separator = " " 9 - timeout = 1000 10 - [bookmarks] 11 - search_depth = 100 12 - exclude = [] 13 - 14 - [[module]] 15 - type = "Commit" 16 - empty_text = "" 17 - [module.change] 18 - fg = "magenta" 19 - 20 - [[module]] 21 - type = "Bookmarks" 22 - separator = " " 23 - color = "Magenta" 24 - behind_symbol = "⇡" 25 - 26 - [[module]] 27 - type = "State" 28 - separator = " " 29 - 30 - [module.conflict] 31 - disabled = true 32 - text = "(CONFLICT)" 33 - color = "Red" 34 - 35 - [module.divergent] 36 - disabled = true 37 - text = "(DIVERGENT)" 38 - color = "Cyan" 39 - 40 - [module.empty] 41 - disabled = false 42 - text = "(EMPTY)" 43 - color = "Yellow" 44 - 45 - [module.immutable] 46 - disabled = false 47 - text = "(IMMUTABLE)" 48 - color = "Yellow" 49 - 50 - [module.hidden] 51 - disabled = false 52 - text = "(HIDDEN)" 53 - color = "Yellow" 54 - 55 - [[module]] 56 - type = "Metrics" 57 - template = "[{changed} {added}{removed}]" 58 - color = "Magenta" 59 - 60 - [module.changed_files] 61 - prefix = "" 62 - suffix = "" 63 - color = "Cyan" 64 - 65 - [module.added_lines] 66 - prefix = "+" 67 - suffix = "" 68 - color = "Green" 69 - 70 - [module.removed_lines] 71 - prefix = "-" 72 - suffix = "" 73 - color = "Red" 74 - ''; 75 - programs.starship = { 76 - enable = true; 77 - settings = { 78 - format = lib.concatMapStrings (s: s) [ 79 - "$directory" 80 - "$nix_shell" 81 - "$custom" 82 - "$cmd_duration" 83 - "$line_break" 84 - "$character" 85 - ]; 86 - nix_shell = { 87 - format = "[$symbol]($style)"; 88 - }; 89 - custom = { 90 - jj = { 91 - command = ''${lib.getExe' inputs'.starship-jj.packages.default "starship-jj"} --ignore-working-copy starship prompt''; 92 - format = "[$symbol](blue bold) $output"; 93 - symbol = "󱗆"; 94 - when = "jj root --ignore-working-copy"; 95 - }; 96 - git_branch = { 97 - when = true; 98 - command = "jj root >/dev/null 2>&1 || starship module git_branch"; 99 - description = "Only show git_branch if we're not in a jj repo"; 100 - }; 101 - }; 102 - }; 103 - }; 104 - }
-21
modules/home/dev/utils.nix
··· 1 - {pkgs, ...}: { 2 - home.packages = [ 3 - pkgs.sd 4 - pkgs.fd 5 - pkgs.uutils-coreutils-noprefix 6 - ]; 7 - programs = { 8 - zoxide.enable = true; 9 - carapace.enable = true; 10 - 11 - ripgrep.enable = true; 12 - bat.enable = true; 13 - less = { 14 - enable = true; 15 - config = '' 16 - #env 17 - LESS = -S -R -i 18 - ''; 19 - }; 20 - }; 21 - }
-5
modules/home/dev/yazi.nix
··· 1 - _: { 2 - programs.yazi = { 3 - enable = true; 4 - }; 5 - }
+9 -3
modules/home/dev/zellij.nix modules/dev/shell/zellij.nix
··· 1 - {inputs', ...}: { 1 + { 2 + inputs', 3 + lib, 4 + config, 5 + ... 6 + }: 7 + lib.mkIf config.dev.shell.enable { 2 8 programs.zellij = { 3 9 enable = true; 4 10 settings = { ··· 13 19 shared._children = [ 14 20 { 15 21 bind = { 16 - _args = ["Alt f"]; 17 - ToggleFloatingPanes = {}; 22 + _args = [ "Alt f" ]; 23 + ToggleFloatingPanes = { }; 18 24 }; 19 25 } 20 26 ];
+24
modules/locale.nix
··· 1 + { pkgs, ... }: 2 + { 3 + time.timeZone = "Europe/Paris"; 4 + 5 + console = { 6 + keyMap = "us-acentos"; 7 + packages = [ pkgs.kbd ]; 8 + }; 9 + 10 + i18n = { 11 + defaultLocale = "en_US.UTF-8"; 12 + extraLocaleSettings = { 13 + LC_ADDRESS = "fr_FR.UTF-8"; 14 + LC_IDENTIFICATION = "fr_FR.UTF-8"; 15 + LC_MEASUREMENT = "fr_FR.UTF-8"; 16 + LC_MONETARY = "fr_FR.UTF-8"; 17 + LC_NAME = "fr_FR.UTF-8"; 18 + LC_NUMERIC = "fr_FR.UTF-8"; 19 + LC_PAPER = "fr_FR.UTF-8"; 20 + LC_TELEPHONE = "fr_FR.UTF-8"; 21 + LC_TIME = "fr_FR.UTF-8"; 22 + }; 23 + }; 24 + }
+4 -3
modules/nixos/cachix.nix
··· 3 3 lib, 4 4 config, 5 5 ... 6 - }: { 6 + }: 7 + { 7 8 config = lib.mkIf (!config.server) { 8 9 nix.settings = { 9 - substituters = lib.mkAfter ["https://karitham.cachix.org"]; 10 + substituters = lib.mkAfter [ "https://karitham.cachix.org" ]; 10 11 trusted-public-keys = lib.mkAfter [ 11 12 "karitham.cachix.org-1:Q0wdHZsCssuepIrtx83gHibE0LTDYLVNnvaV3Nms9U0=" 12 13 ]; 13 14 }; 14 15 15 - environment.systemPackages = [pkgs.cachix]; 16 + environment.systemPackages = [ pkgs.cachix ]; 16 17 }; 17 18 }
+2 -8
modules/nixos/default.nix
··· 1 - {...}: { 1 + { ... }: 2 + { 2 3 imports = [ 3 - ./shell.nix 4 - ./ipcam.nix 5 - ./desktop.nix 6 - ./sound.nix 7 4 ./nix.nix 8 5 ./cachix.nix 9 - ./locale.nix 10 6 ./docker.nix 11 - ./fonts.nix 12 - ./yubikey.nix 13 7 ./server.nix 14 8 ]; 15 9 }
+22
modules/nixos/desktop-common.nix
··· 1 + _: { 2 + imports = [ ../../modules/home ]; 3 + 4 + networking.networkmanager.enable = true; 5 + 6 + services = { 7 + tailscale = { 8 + enable = true; 9 + useRoutingFeatures = "client"; 10 + }; 11 + touchegg.enable = true; 12 + blueman.enable = true; 13 + auto-cpufreq.enable = true; 14 + }; 15 + 16 + security = { 17 + sudo.wheelNeedsPassword = false; 18 + rtkit.enable = true; 19 + }; 20 + 21 + virtualisation.docker.enable = true; 22 + }
+5 -20
modules/nixos/desktop.nix modules/desktop/desktop.nix
··· 4 4 pkgs, 5 5 inputs, 6 6 ... 7 - }: let 7 + }: 8 + let 8 9 cfg = config.desktop; 9 - in { 10 - options.desktop = { 11 - enable = lib.mkEnableOption "desktop usage"; 12 - wallpaper = lib.mkOption { 13 - default = pkgs.fetchurl { 14 - url = "https://raw.githubusercontent.com/HoulFloof/wallpapers/f23c1010b93cb97baa7ad7c94fd552f7601496d2/misc/waves_right_colored.png"; 15 - hash = "sha256-NqqE+pGnCIWAitH86sxu1EudVEEaSO82y3NqbhtDh9k="; 16 - }; 17 - type = lib.types.path; 18 - description = "the wallpaper to use"; 19 - }; 20 - }; 21 - 22 - imports = [inputs.niri.nixosModules.niri]; 23 - 10 + in 11 + { 12 + imports = [ inputs.niri.nixosModules.niri ]; 24 13 config = lib.mkIf cfg.enable { 25 - hardware = { 26 - bluetooth.enable = true; 27 - }; 28 - 29 14 environment = { 30 15 systemPackages = with pkgs; [ 31 16 wl-clipboard
+3 -2
modules/nixos/fonts.nix modules/desktop/fonts.nix
··· 3 3 lib, 4 4 pkgs, 5 5 ... 6 - }: { 6 + }: 7 + { 7 8 options.fonts = { 8 9 mono = lib.mkOption { 9 10 type = lib.types.str; ··· 39 40 "Noto Serif" 40 41 "Noto Color Emoji" 41 42 ]; 42 - emoji = ["Noto Color Emoji"]; 43 + emoji = [ "Noto Color Emoji" ]; 43 44 }; 44 45 }; 45 46 };
-32
modules/nixos/ipcam.nix
··· 1 - { 2 - config, 3 - lib, 4 - pkgs, 5 - ... 6 - }: { 7 - options.ipcam.enable = lib.mkEnableOption "enable ipcam module"; 8 - 9 - config = lib.mkIf (config.desktop.enable && config.ipcam.enable) { 10 - boot = { 11 - extraModulePackages = with config.boot.kernelPackages; [v4l2loopback]; 12 - kernelModules = ["v4l2loopback"]; 13 - extraModprobeConfig = '' 14 - options v4l2loopback video_nr=9 card_label=IP-Webcam exclusive_caps=1 15 - ''; 16 - }; 17 - 18 - environment.systemPackages = let 19 - port = 9696; 20 - ipcam = pkgs.writeShellScriptBin "ipcam" '' 21 - ${lib.getExe' pkgs.android-tools "adb"} wait-for-usb-device 22 - ${lib.getExe' pkgs.android-tools "adb"} forward tcp:${toString port} tcp:8080 23 - ${lib.getExe pkgs.ffmpeg} -i http://localhost:${toString port}/video -vf format=yuv420p -f v4l2 /dev/video9 24 - ${lib.getExe' pkgs.android-tools "adb"} forward --remove tcp:${toString port} 25 - ''; 26 - in [ 27 - pkgs.ffmpeg 28 - pkgs.android-tools 29 - ipcam 30 - ]; 31 - }; 32 - }
+6 -3
modules/nixos/locale.nix modules/desktop/locale.nix
··· 3 3 lib, 4 4 pkgs, 5 5 ... 6 - }: { 7 - config = lib.mkIf (!config.server) { 6 + }: 7 + { 8 + config = lib.mkIf config.desktop.locale.enable { 9 + time.timeZone = "Europe/Paris"; 10 + 8 11 console = { 9 12 keyMap = "us-acentos"; 10 - packages = [pkgs.kbd]; 13 + packages = [ pkgs.kbd ]; 11 14 }; 12 15 13 16 i18n = {
+6 -3
modules/nixos/nix.nix
··· 4 4 config, 5 5 pkgs, 6 6 ... 7 - }: { 7 + }: 8 + { 8 9 config = lib.mkIf (!config.server) { 9 10 nix = { 10 11 package = pkgs.lix; ··· 16 17 settings = { 17 18 auto-optimise-store = true; 18 19 builders-use-substitutes = true; 19 - allowed-users = ["@wheel"]; 20 - trusted-users = ["@wheel"]; 20 + allowed-users = [ "@wheel" ]; 21 + trusted-users = [ "@wheel" ]; 21 22 commit-lockfile-summary = "chore: Update flake.lock"; 22 23 accept-flake-config = true; 23 24 keep-derivations = true; ··· 45 46 overlays = [ 46 47 inputs.self.overlays.default 47 48 inputs.niri.overlays.niri 49 + inputs.ghostty.overlays.default 50 + inputs.knixpkgs.overlays.default 48 51 ]; 49 52 }; 50 53
+9
modules/nixos/server-common.nix
··· 1 + _: { 2 + services = { 3 + tailscale = { 4 + enable = true; 5 + useRoutingFeatures = "server"; 6 + }; 7 + openssh.enable = true; 8 + }; 9 + }
+2 -1
modules/nixos/server.nix
··· 1 - {lib, ...}: { 1 + { lib, ... }: 2 + { 2 3 options.server = lib.mkEnableOption "enable server mode"; 3 4 }
+93
modules/nixos/services/acme-nginx.nix
··· 1 + { config, lib, ... }: 2 + let 3 + cfg = config.services.acme-nginx; 4 + hostType = lib.types.submodule { 5 + options = { 6 + domain = lib.mkOption { 7 + type = lib.types.str; 8 + description = "The main domain for this host."; 9 + }; 10 + extraDomainNames = lib.mkOption { 11 + type = lib.types.listOf lib.types.str; 12 + default = [ ]; 13 + description = "Extra domain names for this host."; 14 + }; 15 + proxyPort = lib.mkOption { 16 + type = lib.types.int; 17 + description = "The port to proxy to locally for this host."; 18 + }; 19 + }; 20 + }; 21 + in 22 + { 23 + options.services.acme-nginx = { 24 + enable = lib.mkEnableOption "ACME and Nginx reverse proxy"; 25 + 26 + email = lib.mkOption { 27 + type = lib.types.str; 28 + description = "Email for ACME."; 29 + }; 30 + 31 + credentialsFile = lib.mkOption { 32 + type = lib.types.path; 33 + description = "Path to the credentials file for DNS provider."; 34 + }; 35 + 36 + hosts = lib.mkOption { 37 + type = lib.types.listOf hostType; 38 + default = [ ]; 39 + description = "List of hosts to configure."; 40 + example = [ 41 + { 42 + domain = "example.com"; 43 + extraDomainNames = [ "*.example.com" ]; 44 + proxyPort = 3000; 45 + } 46 + ]; 47 + }; 48 + }; 49 + 50 + config = lib.mkIf cfg.enable { 51 + networking.firewall.allowedTCPPorts = [ 52 + 80 53 + 443 54 + ]; 55 + 56 + security.acme = { 57 + defaults.email = cfg.email; 58 + acceptTerms = true; 59 + certs = lib.listToAttrs ( 60 + map (host: { 61 + name = host.domain; 62 + value = { 63 + dnsProvider = "cloudflare"; 64 + inherit (cfg) credentialsFile; 65 + inherit (config.services.nginx) group; 66 + inherit (host) domain; 67 + extraDomainNames = host.extraDomainNames or [ ]; 68 + reloadServices = [ "nginx" ]; 69 + }; 70 + }) cfg.hosts 71 + ); 72 + }; 73 + 74 + services.nginx = { 75 + enable = true; 76 + recommendedProxySettings = true; 77 + recommendedTlsSettings = true; 78 + virtualHosts = lib.listToAttrs ( 79 + map (host: { 80 + name = "~(.*)\\.${lib.escapeRegex host.domain}$"; 81 + value = { 82 + useACMEHost = host.domain; 83 + forceSSL = true; 84 + locations."/" = { 85 + proxyPass = "http://127.0.0.1:${toString host.proxyPort}"; 86 + proxyWebsockets = true; 87 + }; 88 + }; 89 + }) cfg.hosts 90 + ); 91 + }; 92 + }; 93 + }
-33
modules/nixos/shell.nix
··· 1 - { 2 - config, 3 - lib, 4 - pkgs, 5 - ... 6 - }: { 7 - config = lib.mkIf (!config.server) { 8 - users.defaultUserShell = pkgs.nushell; 9 - environment.shells = [pkgs.nushell]; 10 - 11 - environment.sessionVariables.EDITOR = 12 - lib.attrByPath [ 13 - "home-manager" 14 - "users" 15 - config.my.username 16 - "home" 17 - "sessionVariables" 18 - "EDITOR" 19 - ] "nano" 20 - config; 21 - programs.nano.enable = 22 - !(lib.attrByPath [ 23 - "home-manager" 24 - "users" 25 - config.my.username 26 - "programs" 27 - "helix" 28 - "enable" 29 - ] 30 - false 31 - config); 32 - }; 33 - }
+1 -4
modules/nixos/sound.nix modules/desktop/sound.nix
··· 1 + { config, lib, ... }: 1 2 { 2 - config, 3 - lib, 4 - ... 5 - }: { 6 3 config = lib.mkIf config.desktop.enable { 7 4 services = { 8 5 pulseaudio.enable = false;
+5 -6
modules/nixos/yubikey.nix modules/desktop/yubikey.nix
··· 3 3 lib, 4 4 pkgs, 5 5 ... 6 - }: { 7 - options.yubikey.enable = lib.mkEnableOption "enable yubikey"; 8 - 9 - config = lib.mkIf (config.desktop.enable && config.yubikey.enable) { 10 - services.udev.packages = [pkgs.yubikey-personalization]; 6 + }: 7 + { 8 + config = lib.mkIf (config.desktop.enable && config.desktop.yubikey.enable) { 9 + services.udev.packages = [ pkgs.yubikey-personalization ]; 11 10 12 11 programs.gnupg.agent = { 13 12 enable = true; ··· 21 20 security.pam.yubico = { 22 21 enable = true; 23 22 mode = "challenge-response"; 24 - id = ["32235281"]; 23 + id = [ "32235281" ]; 25 24 }; 26 25 27 26 services.udev.extraRules = ''
+1
modules/server/default.nix
··· 1 + { imports = [ ../nixos/server-common.nix ]; }
+10
modules/tags/secureboot.nix
··· 1 + { inputs, pkgs, ... }: 2 + { 3 + imports = [ inputs.lanzaboote.nixosModules.lanzaboote ]; 4 + environment.systemPackages = [ pkgs.sbctl ]; 5 + boot.lanzaboote = { 6 + enable = true; 7 + pkiBundle = "/etc/secureboot"; 8 + configurationLimit = 5; 9 + }; 10 + }
+35
modules/tags/work.nix
··· 1 + { config, pkgs, ... }: 2 + { 3 + desktop.yubikey.enable = true; 4 + programs._1password.enable = true; 5 + 6 + home-manager.users.${config.my.username} = { 7 + xdg.configFile."git/config".text = '' 8 + [includeIf "hasconfig:remote.*.url:git+ssh://git@github.com/upfluence/**"] 9 + path = "~/upf/.gitconfig" 10 + [includeIf "hasconfig:remote.*.url:git@github.com:upfluence/**"] 11 + path = "~/upf/.gitconfig" 12 + ''; 13 + 14 + programs.opencode.settings.mcp = { 15 + linear = { 16 + type = "remote"; 17 + url = "https://mcp.linear.app/mcp"; 18 + enabled = true; 19 + headers = { 20 + Authorization = "Bearer {env:LINEAR_API_KEY}"; 21 + }; 22 + }; 23 + sentry = { 24 + type = "local"; 25 + enabled = true; 26 + command = [ 27 + "${pkgs.bun}/bin/bun" 28 + "x" 29 + "mcp-remote@latest" 30 + "https://mcp.sentry.dev/mcp" 31 + ]; 32 + }; 33 + }; 34 + }; 35 + }
+18
modules/wsl/default.nix
··· 1 + { 2 + inputs, 3 + self, 4 + config, 5 + ... 6 + }: 7 + { 8 + imports = [ 9 + self.nixosModules.dev 10 + inputs.nixos-wsl.nixosModules.default 11 + ../locale.nix 12 + ../home 13 + ]; 14 + 15 + dev.enable = true; 16 + 17 + home-manager.users.${config.my.username}.imports = [ self.homeModules.dev ]; 18 + }
+1 -1
overlays/default.nix
··· 1 1 _: prev: { 2 - pokego = prev.callPackage ../pkgs/pokego.nix {}; 2 + pokego = prev.callPackage ../pkgs/pokego.nix { }; 3 3 golangci-lint-langserver = prev.golangci-lint-langserver.overrideAttrs (_: { 4 4 patches = prev.fetchurl { 5 5 url = "https://github.com/karitham/golangci-lint-langserver/commit/31e6806187d431a8865261b5441ef5a65b589ae5.patch";
+1 -3
pkgs/http-nu.nix
··· 25 25 26 26 doCheck = false; 27 27 28 - buildInputs = [ 29 - sqlite 30 - ]; 28 + buildInputs = [ sqlite ]; 31 29 32 30 meta = { 33 31 description = "The surprisingly performant, Nushell-scriptable HTTP server that fits in your back pocket";
+3 -3
pkgs/pokego.nix
··· 1 - {pkgs, ...}: 1 + { pkgs, ... }: 2 2 pkgs.buildGoModule { 3 3 pname = "pokego"; 4 4 version = "devel"; ··· 11 11 12 12 vendorHash = "sha256-Eykg/qGqWA+qxeFPAhd0BERHtLj5X7kMQo/IPp1yRU4="; 13 13 env.CGO_ENABLED = 0; 14 - flags = ["-trimpath"]; 14 + flags = [ "-trimpath" ]; 15 15 ldflags = [ 16 16 "-s" 17 17 "-w" ··· 23 23 homepage = "https://github.com/karitham/pokego"; 24 24 mainProgram = "pokego"; 25 25 license = licenses.gpl3; 26 - maintainers = with maintainers; [karitham]; 26 + maintainers = with maintainers; [ karitham ]; 27 27 }; 28 28 }
+4 -3
pkgs/topiary-nu.nix
··· 8 8 nodejs, 9 9 tree-sitter-nu, 10 10 topiary-nushell, 11 - }: let 11 + }: 12 + let 12 13 treeSitterNu = stdenv.mkDerivation { 13 14 name = "tree-sitter-nu"; 14 15 src = tree-sitter-nu; ··· 49 50 ''; 50 51 }; 51 52 in 52 - runCommand "topiary-nu" 53 + runCommand "topiary-nu" 53 54 { 54 - buildInputs = [makeWrapper]; 55 + buildInputs = [ makeWrapper ]; 55 56 meta = { 56 57 mainProgram = "topiary-nu"; 57 58 };
+50
systems/default.nix
··· 1 + { self, inputs, ... }: 2 + { 3 + imports = [ inputs.easy-hosts.flakeModule ]; 4 + 5 + config.easy-hosts = { 6 + shared = { 7 + modules = [ 8 + ../modules/core.nix 9 + ../modules/nixos 10 + ]; 11 + 12 + specialArgs = { inherit inputs self; }; 13 + }; 14 + 15 + additionalClasses = { 16 + desktop = "nixos"; 17 + server = "nixos"; 18 + wsl = "nixos"; 19 + }; 20 + 21 + perClass = class: { modules = [ ../modules/${class}/default.nix ]; }; 22 + 23 + perTag = tag: { modules = [ ../modules/tags/${tag}.nix ]; }; 24 + 25 + hosts = { 26 + kiwi = { 27 + class = "desktop"; 28 + tags = [ "work" ]; 29 + }; 30 + 31 + ozen = { 32 + class = "wsl"; 33 + }; 34 + 35 + reg = { 36 + class = "server"; 37 + }; 38 + 39 + belaf = { 40 + class = "desktop"; 41 + tags = [ "secureboot" ]; 42 + }; 43 + 44 + wakuna = { 45 + arch = "aarch64"; 46 + class = "server"; 47 + }; 48 + }; 49 + }; 50 + }