diff --git a/.envrc b/.envrc index e483044..49bacf7 100644 --- a/.envrc +++ b/.envrc @@ -1,11 +1,10 @@ # update repo if has jj; then - jj git fetch --all-remotes + jj git fetch --all-remotes elif has gix; then - gix fetch + gix fetch elif has git; then - git fetch + git fetch fi -watch_file ./flake.{nix,lock} ./flake-modules/{default,devshells,overlays,nixvim-modules}.nix use flake diff --git a/.forgejo/workflows/check.yml b/.forgejo/workflows/check.yml index 3199e04..adddf31 100644 --- a/.forgejo/workflows/check.yml +++ b/.forgejo/workflows/check.yml @@ -1,92 +1,58 @@ on: push: jobs: - check-fmt: + check: runs-on: nixos - steps: - - uses: https://git.salame.cl/actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 - - run: nix --version - - name: Run treefmt - run: | - nix build --print-build-logs ".#checks.$(nix eval --raw --impure --expr builtins.currentSystem).treefmt" - build-package: - runs-on: nixos - needs: check-fmt strategy: matrix: - package: + check: + - nvimDev + - nvimHeadless + - nvimNoBundledBins + - nvimNoLsp + - nvimNoTSGrammars + - treefmt + steps: + - uses: "https://git.salame.cl/actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683" # v4 + - name: Run checks + run: | + nix --version + # shellcheck disable=SC2016 + nix build --print-build-logs '.#checks.x86_64-linux.${{ matrix.check }}' + check-renovaterc: + runs-on: nixos + steps: + - uses: "https://git.salame.cl/actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683" # v4 + - name: Validate renovaterc.json + run: | + nix --version + nix shell nixpkgs#renovate --command renovate-config-validator + build: + runs-on: nixos + needs: check + strategy: + matrix: + target: - audiomenu - docs - - docs-home-markdown - - docs-nixos-markdown - - docs-nvim-markdown - jpassmenu + - nixosConfigurations.vm.config.system.build.toplevel - nvim - - nvim-headless - - nvim-no-lsps - - nvim-no-ts - - nvim-small - - search steps: - uses: "https://git.salame.cl/actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683" # v4 - - run: nix --version - name: Build target - env: - PACKAGE: ${{ matrix.package }} run: | + nix --version # shellcheck disable=SC2016 - nix build --print-build-logs ".#$PACKAGE" - check-nvim: - runs-on: nixos - needs: build-package - strategy: - matrix: - nvim: - - nvim - - nvim-headless - - nvim-no-lsps - - nvim-no-ts - - nvim-small - steps: - - uses: "https://git.salame.cl/actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683" # v4 - - run: nix --version - - name: Build target - env: - NVIM: ${{ matrix.nvim }} - run: | - nix build --print-build-logs ".#checks.$(nix eval --raw --impure --expr builtins.currentSystem).$NVIM" - build-vm: - runs-on: nixos - needs: - - build-package - - check-nvim - steps: - - uses: "https://git.salame.cl/actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683" # v4 - - run: nix --version - - name: Build VM configuration - run: | - nix build --print-build-logs '.#nixosConfigurations.vm.config.system.build.toplevel' - build-hm: - runs-on: nixos - needs: - - build-package - - check-nvim - steps: - - uses: "https://git.salame.cl/actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683" # v4 - - run: nix --version - - name: Build Home Manager configuration - run: | - nix build --print-build-logs '.#homeConfigurations.example.activationPackage' + nix build --print-build-logs '.#${{ matrix.target }}' report-size: runs-on: nixos - needs: - - build-vm - - build-hm + needs: build steps: - uses: "https://git.salame.cl/actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683" # v4 - run: nix --version - name: Create Size Report - uses: "https://git.salame.cl/jalil/nix-flake-outputs-size@838f2050208b41c339803a1111608d7182bbda3e" # main + uses: "https://git.salame.cl/jalil/nix-flake-outputs-size@5c40a31e3e2ed0ea28f8ba68deca41d05fdf2e71" # main with: # Create a comment on the associated PR comment-on-pr: ${{ github.ref_name != 'main' }} diff --git a/.forgejo/workflows/renovate.yml b/.forgejo/workflows/renovate.yml deleted file mode 100644 index ab1aac5..0000000 --- a/.forgejo/workflows/renovate.yml +++ /dev/null @@ -1,14 +0,0 @@ -on: - push: - paths: - # only run if the renovate config changed - - renovate.json -jobs: - check-renovaterc: - runs-on: nixos - steps: - - uses: https://git.salame.cl/actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 - - run: nix --version - - name: Validate renovaterc.json - run: | - nix shell nixpkgs#renovate --command renovate-config-validator diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index 1f8ead4..dd7df12 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -16,6 +16,7 @@ jobs: with: source-url: "https://install.lix.systems/lix/lix-installer-x86_64-linux" diagnostic-endpoint: "" + - uses: DeterminateSystems/magic-nix-cache-action@6221693898146dc97e38ad0e013488a16477a4c4 # v9 - name: Run `nix flake check` run: | nix flake check --verbose --keep-going @@ -24,6 +25,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 + - uses: DeterminateSystems/magic-nix-cache-action@6221693898146dc97e38ad0e013488a16477a4c4 # v9 - uses: DeterminateSystems/nix-installer-action@v13 with: source-url: "https://install.lix.systems/lix/lix-installer-x86_64-linux" diff --git a/renovate.json b/.renovaterc.json similarity index 83% rename from renovate.json rename to .renovaterc.json index 86737e0..feb16d3 100644 --- a/renovate.json +++ b/.renovaterc.json @@ -13,6 +13,11 @@ "config:best-practices" ], "nix": { + "fileMatch": [ + "(^|/)flake\\.nix$" + ], + "commitMessageTopic": "nixpkgs", + "commitMessageExtra": "to {{newValue}}", "enabled": true }, "lockFileMaintenance": { diff --git a/docs/book.toml b/docs/book.toml index aa7e72e..d31b799 100644 --- a/docs/book.toml +++ b/docs/book.toml @@ -3,14 +3,8 @@ authors = ["Jalil David Salamé Messina"] language = "en" multilingual = false src = "src" -title = "Jalil's NixOS configuration modules" - -[build] -create-missing = false +title = "Jalil's NixOS configuration module" [preprocessor.toc] command = "mdbook-toc" renderer = ["html"] - -[output.html] -git-repository-url = "https://github.com/jalil-salame/configuration.nix" diff --git a/docs/src/SUMMARY.md b/docs/src/SUMMARY.md index 48707f4..16ff37a 100644 --- a/docs/src/SUMMARY.md +++ b/docs/src/SUMMARY.md @@ -1,9 +1,6 @@ # Summary -[Nix Based Configuration](./configuration-overview.md) - -- [NixOS Module Options](./nixos-options.md) -- [Neovim Module Options](./nvim-options.md) -- [Home Manager Module Options](./home-options.md) - -[Search](./search/index.html) +- [Nix Based Configuration](./configuration-overview.md) + - [NixOS Module Options](./nixos-options.md) + - [Neovim Module Options](./nvim-options.md) + - [Home Manager Module Options](./home-options.md) diff --git a/example-hm/home.nix b/example-hm/home.nix deleted file mode 100644 index 4e86064..0000000 --- a/example-hm/home.nix +++ /dev/null @@ -1,70 +0,0 @@ -{ - lib, - pkgs, - config, - ... -}: -{ - home = { - homeDirectory = "/home/jdoe"; - stateVersion = "25.05"; - username = "jdoe"; - }; - - jhome = { - enable = true; - dev = { - enable = true; - neovimAsManPager = true; - rust.enable = true; - }; - gui.enable = false; - hostName = "example"; - user = { - enable = true; - defaultIdentity = { - email = "jdoe@example.org"; - name = "John Doe"; - }; - }; - }; - - programs = { - # Switch to fish if bash is started interactively - bash.initExtra = '' - if [[ $(${pkgs.procps}/bin/ps --no-header --pid=$PPID --format=comm) != "fish" && -z ''${BASH_EXECUTION_STRING} ]] - then - shopt -q login_shell && LOGIN_OPTION='--login' || LOGIN_OPTION="" - exec ${pkgs.fish}/bin/fish $LOGIN_OPTION - fi - ''; - - # Enable zellij (tmux like terminal session manager) - zellij.enable = lib.mkForce true; - }; - - nix = { - package = pkgs.lix; - gc = { - automatic = true; - frequency = "weekly"; - options = "--delete-older-than 30d"; - # run between 0 and 45min after boot if run was missed - randomizedDelaySec = "45min"; - }; - settings = { - # Add my personal binary cache to the mix (only for personal computers) - extra-substituters = [ "https://cache.salame.cl" ]; - extra-trusted-public-keys = [ "cache.salame.cl:D+pBaoutwxja7qKGpju+CmM1LRbVmf2gqEQ/9c7qHrw=" ]; - auto-optimise-store = true; - }; - }; - - stylix = { - image = config.jhome.gui.sway.background; - base16Scheme = "${pkgs.base16-schemes}/share/themes/gruvbox-dark-hard.yaml"; - }; - - # Let Home Manager install and manage itself. - programs.home-manager.enable = true; -} diff --git a/example-vm/default.nix b/example-vm/default.nix deleted file mode 100644 index ab7a40b..0000000 --- a/example-vm/default.nix +++ /dev/null @@ -1,41 +0,0 @@ -{ - imports = [ ./vm-config.nix ]; - - time.timeZone = "Europe/Berlin"; - i18n.defaultLocale = "en_US.UTF-8"; - users.users.jdoe = { - password = "example"; - isNormalUser = true; - extraGroups = [ - "wheel" - "video" - "networkmanager" - ]; - }; - home-manager.users.jdoe = { - home = { - username = "jdoe"; - homeDirectory = "/home/jdoe"; - stateVersion = "24.11"; - }; - jhome = { - enable = true; - gui.enable = true; - dev = { - enable = true; - rust.enable = true; - }; - }; - }; - - # password is 'test' see module documentation for more options - services.jupyter.password = "'sha1:1b961dc713fb:88483270a63e57d18d43cf337e629539de1436ba'"; - jconfig = { - enable = true; - dev = { - enable = true; - jupyter.enable = true; - }; - gui.enable = true; - }; -} diff --git a/example-vm/vm-config.nix b/example-vm/vm-config.nix deleted file mode 100644 index 67e38a7..0000000 --- a/example-vm/vm-config.nix +++ /dev/null @@ -1,36 +0,0 @@ -## Default QEMU guest config -{ - services = { - qemuGuest.enable = true; - openssh.enable = true; - }; - - boot = { - loader.systemd-boot.enable = true; - initrd.availableKernelModules = [ - "xhci_pci" - "ehci_pci" - "ahci" - "usbhid" - "usb_storage" - "sd_mod" - "virtio_balloon" - "virtio_blk" - "virtio_pci" - "virtio_ring" - # "virtio_vga" - "virtio_gpu" - ]; - }; - fileSystems."/".device = "/dev/disk/by-label/nixos"; - - # This value determines the NixOS release from which the default - # settings for stateful data, like file locations and database versions - # on your system were taken. It‘s perfectly fine and recommended to leave - # this value at the release version of the first install of this system. - # Before changing this value read the documentation for this option - # (e.g. man configuration.nix or on https://nixos.org/nixos/options.html). - system.stateVersion = "24.11"; # Did you read the comment? - - nixpkgs.hostPlatform = "x86_64-linux"; -} diff --git a/flake-modules/default.nix b/flake-modules/default.nix index 1b806a6..050721e 100644 --- a/flake-modules/default.nix +++ b/flake-modules/default.nix @@ -1,21 +1,25 @@ { inputs, ... }: +let + overlays = builtins.attrValues inputs.self.overlays; +in { imports = [ inputs.treefmt-nix.flakeModule ./devshells.nix ./docs.nix - ./example-configs.nix + ./example-vm.nix ./nixos-modules.nix - ./home-modules.nix - ./nixvim-modules.nix + ./nvim.nix ./overlays.nix - ../scripts + ./scripts.nix ]; perSystem = { system, ... }: { + _module.args.pkgs = import inputs.nixpkgs { inherit system overlays; }; + # Setup formatters treefmt = { projectRootFile = "flake.nix"; diff --git a/flake-modules/devshells.nix b/flake-modules/devshells.nix index f9eeaa4..962c4bf 100644 --- a/flake-modules/devshells.nix +++ b/flake-modules/devshells.nix @@ -4,12 +4,8 @@ _: { { devShells.default = pkgs.mkShellNoCC { buildInputs = [ - self'.packages.nvim - pkgs.just - pkgs.nix-diff - pkgs.nvd - pkgs.uv + self'.packages.nvim ]; QEMU_OPTS_WL = "-enable-kvm -nodefaults -m 4G -cpu host -smp 4 -device virtio-gpu"; }; diff --git a/flake-modules/docs.nix b/flake-modules/docs.nix index 594d592..cc85766 100644 --- a/flake-modules/docs.nix +++ b/flake-modules/docs.nix @@ -1,50 +1,45 @@ -{ lib, ... }: +{ lib, inputs, ... }: { perSystem = - { inputs', pkgs, ... }: + { pkgs, ... }: { packages = let filterVisible = toplevelOption: option: option // { visible = option.visible && builtins.elemAt option.loc 0 == toplevelOption; }; - genOptionsDoc = - toplevelOption: module: - pkgs.nixosOptionsDoc { - inherit (lib.evalModules { modules = [ module ]; }) options; - transformOptions = filterVisible toplevelOption; + home-eval = lib.evalModules { + modules = [ ../home/options.nix ]; + specialArgs = { + inherit pkgs; }; - mkScope = name: options: { - inherit name; - optionsJSON = "${options.optionsJSON}/share/doc/nixos/options.json"; - urlPrefix = "https://github.com/jalil-salame/configuration.nix/blob/main/"; }; - search = inputs'.nuschtosSearch.packages.mkMultiSearch { - title = "Search Jalil's configuration.nix"; - baseHref = "/"; - - scopes = [ - (mkScope "NixOS" nixos) - (mkScope "Home-Manager" home) - (mkScope "NixVIM" nvim) - ]; - }; - home = genOptionsDoc "jhome" ../modules/hm/options.nix; - nvim = genOptionsDoc "jhome" ../modules/nixvim/options.nix; - nixos = genOptionsDoc "jconfig" ../modules/nixos/options.nix; - nixos-markdown = nixos.optionsCommonMark; - home-markdown = home.optionsCommonMark; - nvim-markdown = nvim.optionsCommonMark; + nvim-eval = lib.evalModules { modules = [ ../nvim/options.nix ]; }; + nixos-eval = lib.evalModules { modules = [ ../system/options.nix ]; }; + home-markdown = + (pkgs.nixosOptionsDoc { + inherit (home-eval) options; + transformOptions = filterVisible "jhome"; + }).optionsCommonMark; + nvim-markdown = + (pkgs.nixosOptionsDoc { + inherit (nvim-eval) options; + transformOptions = filterVisible "jhome"; + }).optionsCommonMark; + nixos-markdown = + (pkgs.nixosOptionsDoc { + inherit (nixos-eval) options; + transformOptions = filterVisible "jconfig"; + }).optionsCommonMark; in { - inherit search; docs-home-markdown = home-markdown; docs-nixos-markdown = nixos-markdown; docs-nvim-markdown = nvim-markdown; # Documentation docs = pkgs.stdenvNoCC.mkDerivation { name = "nixos-configuration-book"; - src = ../docs; + src = inputs.self + "/docs"; patchPhase = '' cleanup_md() { @@ -57,9 +52,7 @@ cleanup_md ${home-markdown} >> ./src/home-options.md cleanup_md ${nvim-markdown} >> ./src/nvim-options.md cleanup_md ${nixos-markdown} >> ./src/nixos-options.md - # link search site - ln -s "${search.override { baseHref = "/configuration.nix/search/"; }}" ./src/search - ''; # FIXME: only add the `/configuration.nix/` part for GH CI + ''; nativeBuildInputs = [ pkgs.mdbook-toc ]; buildPhase = "${pkgs.mdbook}/bin/mdbook build --dest-dir $out"; diff --git a/flake-modules/example-configs.nix b/flake-modules/example-configs.nix deleted file mode 100644 index 362e36a..0000000 --- a/flake-modules/example-configs.nix +++ /dev/null @@ -1,33 +0,0 @@ -{ inputs, lib, ... }: -{ - flake = { - # Example vm configuration - nixosConfigurations.vm = lib.nixosSystem { - modules = [ - inputs.self.nixosModules.default - ../example-vm # import vm configuration - { - nixpkgs = { - overlays = builtins.attrValues inputs.self.overlays; - config.allowUnfreePredicate = pkg: builtins.elem (lib.getName pkg) [ "steam-unwrapped" ]; - }; - # pin nixpkgs to the one used by the system - nix.registry.nixpkgs.flake = inputs.nixpkgs; - } - ]; - }; - homeConfigurations.example = inputs.home-manager.lib.homeManagerConfiguration { - pkgs = inputs.nixpkgs.legacyPackages.x86_64-linux; - modules = [ - inputs.self.homeModules.standalone - ../example-hm/home.nix # import home-manager configuration - { - nixpkgs.overlays = [ - inputs.self.overlays.unstable - inputs.lix-module.overlays.default - ]; - } - ]; - }; - }; -} diff --git a/flake-modules/example-vm.nix b/flake-modules/example-vm.nix new file mode 100644 index 0000000..a8ce4b3 --- /dev/null +++ b/flake-modules/example-vm.nix @@ -0,0 +1,55 @@ +{ inputs, lib, ... }: +let + system = "x86_64-linux"; + overlays = builtins.attrValues inputs.self.overlays; + config.allowUnfreePredicate = pkg: builtins.elem (lib.getName pkg) [ "steam-unwrapped" ]; + pkgs = import inputs.nixpkgs { inherit system overlays config; }; +in +{ + # Example vm configuration + flake.nixosConfigurations.vm = lib.nixosSystem { + inherit system pkgs; + modules = [ + inputs.self.nixosModules.vm # import vm module + { + time.timeZone = "Europe/Berlin"; + i18n.defaultLocale = "en_US.UTF-8"; + users.users.jdoe = { + password = "example"; + isNormalUser = true; + extraGroups = [ + "wheel" + "video" + "networkmanager" + ]; + }; + home-manager.users.jdoe = { + home = { + username = "jdoe"; + homeDirectory = "/home/jdoe"; + }; + jhome = { + enable = true; + gui.enable = true; + dev = { + enable = true; + rust.enable = true; + }; + }; + }; + nix.registry.nixpkgs.flake = inputs.nixpkgs; + # password is 'test' see module documentation for more options + services.jupyter.password = "'sha1:1b961dc713fb:88483270a63e57d18d43cf337e629539de1436ba'"; + jconfig = { + enable = true; + dev = { + enable = true; + jupyter.enable = true; + }; + gui.enable = true; + }; + } + ]; + }; + +} diff --git a/flake-modules/home-modules.nix b/flake-modules/home-modules.nix deleted file mode 100644 index 6c9ae51..0000000 --- a/flake-modules/home-modules.nix +++ /dev/null @@ -1,30 +0,0 @@ -{ self, inputs, ... }: -{ - imports = [ inputs.home-manager.flakeModules.home-manager ]; - - flake.homeModules = - let - defaultModules = [ - inputs.nixvim.homeModules.nixvim - self.nixvimModules.homeManager - ../modules/hm - ]; - nixos = { - imports = defaultModules; - }; - standalone = { - imports = defaultModules ++ [ - inputs.stylix.homeModules.stylix - ( - { lib, config, ... }: - lib.mkIf config.jhome.gui.enable { - stylix.image = config.jhome.gui.sway.background; - } - ) - ]; - }; - in - { - inherit standalone nixos; - }; -} diff --git a/flake-modules/nixos-modules.nix b/flake-modules/nixos-modules.nix index ef8355e..70fb0fb 100644 --- a/flake-modules/nixos-modules.nix +++ b/flake-modules/nixos-modules.nix @@ -1,29 +1,46 @@ -{ - self, - inputs, - lib, - ... -}: +{ inputs, lib, ... }: { flake.nixosModules = let + nvim-config = { + imports = [ + inputs.nixvim.homeManagerModules.nixvim + ../nvim + ]; + }; + homeManagerModuleSandalone = import ../home { + inherit nvim-config; + inherit (inputs) stylix; + }; + homeManagerModuleNixOS = import ../home { inherit nvim-config; }; nixosModule = { imports = [ - inputs.stylix.nixosModules.stylix + (import ../system { inherit (inputs) stylix; }) + inputs.niri.nixosModules.niri inputs.home-manager.nixosModules.home-manager - ../modules/nixos ] ++ lib.optional (inputs.lix-module != null) inputs.lix-module.nixosModules.default; home-manager = { useGlobalPkgs = true; useUserPackages = true; - sharedModules = [ self.homeModules.nixos ]; + sharedModules = [ homeManagerModuleNixOS ]; }; # Pin nixpkgs nix.registry.nixpkgs.flake = inputs.nixpkgs; }; + + machines = [ "vm" ]; + mkMachine = hostname: { + imports = [ + nixosModule + (import (../machines + "/${hostname}")) + ]; + home-manager.sharedModules = [ { jhome.hostName = hostname; } ]; + }; + machineModules = lib.genAttrs machines mkMachine; in { default = nixosModule; - inherit nixosModule; - }; + inherit nixosModule homeManagerModuleNixOS homeManagerModuleSandalone; + } + // machineModules; } diff --git a/flake-modules/nixvim-modules.nix b/flake-modules/nixvim-modules.nix deleted file mode 100644 index b40b0dd..0000000 --- a/flake-modules/nixvim-modules.nix +++ /dev/null @@ -1,62 +0,0 @@ -{ self, inputs, ... }: -{ - imports = [ inputs.nixvim.flakeModules.default ]; - - nixvim = { - packages.enable = true; - checks.enable = false; # FIXME: borked due to nix-community/nixvim#3074 - }; - - flake.nixvimModules = - let - module = ../modules/nixvim; - in - { - standalone = "${module}/standalone.nix"; - homeManager = module; - }; - - perSystem = - { system, ... }: - let - nvimModule = extraConfig: { - inherit system; - modules = [ - self.nixvimModules.standalone - # FIXME: borked due to https://github.com/nix-community/nixvim/issues/3140 - # { performance.combinePlugins.enable = true; } - extraConfig - ]; - }; - modules = { - nvim = nvimModule { }; - # Smaller derivations - nvim-headless = nvimModule { - jhome.nvim.dev.enable = false; - jhome.nvim.reduceSize = true; - }; - nvim-small = nvimModule { - jhome.nvim.dev.bundleLSPs = false; - }; - nvim-no-ts = nvimModule { - jhome.nvim.dev.bundleGrammars = false; - }; - nvim-no-lsps = nvimModule { - jhome.nvim.dev = { - bundleLSPs = false; - bundleGrammars = false; - }; - }; - }; - in - { - checks = builtins.mapAttrs ( - _name: module: - inputs.nixvim.lib.${system}.check.mkTestDerivationFromNixvimModule { - module.imports = module.modules; - } - ) modules; - - nixvimConfigurations = builtins.mapAttrs (_name: inputs.nixvim.lib.evalNixvim) modules; - }; -} diff --git a/flake-modules/nvim.nix b/flake-modules/nvim.nix new file mode 100644 index 0000000..89832f3 --- /dev/null +++ b/flake-modules/nvim.nix @@ -0,0 +1,53 @@ +{ inputs, ... }: +{ + perSystem = + { lib, system, ... }: + let + nixvimLib = inputs.nixvim.lib.${system}; + nixvim = inputs.nixvim.legacyPackages.${system}; + testNvimModule = nixvimLib.check.mkTestDerivationFromNixvimModule; + nvimModule = extraConfig: { + pkgs = inputs.unstable.legacyPackages.${system}; + module = { + imports = [ ../nvim/standalone.nix ]; + config = lib.mkMerge [ + { performance.combinePlugins.enable = true; } + extraConfig + ]; + }; + }; + moduleDev = nvimModule { }; + moduleHeadless = nvimModule { + jhome.nvim.dev.enable = false; + jhome.nvim.reduceSize = true; + }; + moduleNoLsp = nvimModule { jhome.nvim.dev.bundleLSPs = false; }; + moduleNoTSGrammars = nvimModule { jhome.nvim.dev.bundleGrammars = false; }; + moduleNoBundledBins = nvimModule { + jhome.nvim.dev = { + bundleLSPs = false; + bundleGrammars = false; + }; + }; + in + { + # Check standalone nvim build + checks = { + nvimDev = testNvimModule moduleDev; + nvimHeadless = testNvimModule moduleHeadless; + nvimNoLsp = testNvimModule moduleNoLsp; + nvimNoTSGrammars = testNvimModule moduleNoTSGrammars; + nvimNoBundledBins = testNvimModule moduleNoBundledBins; + }; + + # Nvim standalone module + packages = { + nvim = nixvim.makeNixvimWithModule moduleDev; + # Smaller derivations + nvim-headless = nixvim.makeNixvimWithModule moduleHeadless; + nvim-small = nixvim.makeNixvimWithModule moduleNoBundledBins; + nvim-no-ts = nixvim.makeNixvimWithModule moduleNoTSGrammars; + nvim-no-lsps = nixvim.makeNixvimWithModule moduleNoLsp; + }; + }; +} diff --git a/flake-modules/scripts.nix b/flake-modules/scripts.nix new file mode 100644 index 0000000..590f6a1 --- /dev/null +++ b/flake-modules/scripts.nix @@ -0,0 +1,14 @@ +let + scripts = import ../scripts; +in +{ + # Add scripts to overlay + flake.overlays.scripts = final: prev: scripts final; + + # Add scripts to packages + perSystem = + { pkgs, ... }: + { + packages = scripts pkgs; + }; +} diff --git a/flake.lock b/flake.lock index 1d6c7f2..5f95dd5 100644 --- a/flake.lock +++ b/flake.lock @@ -5,11 +5,11 @@ "fromYaml": "fromYaml" }, "locked": { - "lastModified": 1746562888, - "narHash": "sha256-YgNJQyB5dQiwavdDFBMNKk1wyS77AtdgDk/VtU6wEaI=", + "lastModified": 1732200724, + "narHash": "sha256-+R1BH5wHhfnycySb7Sy5KbYEaTJZWm1h+LW1OtyhiTs=", "owner": "SenchoPens", "repo": "base16.nix", - "rev": "806a1777a5db2a1ef9d5d6f493ef2381047f2b89", + "rev": "153d52373b0fb2d343592871009a286ec8837aec", "type": "github" }, "original": { @@ -37,11 +37,11 @@ "base16-helix": { "flake": false, "locked": { - "lastModified": 1748408240, - "narHash": "sha256-9M2b1rMyMzJK0eusea0x3lyh3mu5nMeEDSc4RZkGm+g=", + "lastModified": 1736852337, + "narHash": "sha256-esD42YdgLlEh7koBrSqcT7p2fsMctPAcGl/+2sYJa2o=", "owner": "tinted-theming", "repo": "base16-helix", - "rev": "6c711ab1a9db6f51e2f6887cc3345530b33e152e", + "rev": "03860521c40b0b9c04818f2218d9cc9efc21e7a5", "type": "github" }, "original": { @@ -70,11 +70,11 @@ "firefox-gnome-theme": { "flake": false, "locked": { - "lastModified": 1748383148, - "narHash": "sha256-pGvD/RGuuPf/4oogsfeRaeMm6ipUIznI2QSILKjKzeA=", + "lastModified": 1739223196, + "narHash": "sha256-vAxN2f3rvl5q62gQQjZGVSvF93nAsOxntuFz+e/655w=", "owner": "rafaelmardojai", "repo": "firefox-gnome-theme", - "rev": "4eb2714fbed2b80e234312611a947d6cb7d70caf", + "rev": "a89108e6272426f4eddd93ba17d0ea101c34fb21", "type": "github" }, "original": { @@ -90,11 +90,11 @@ ] }, "locked": { - "lastModified": 1751413152, - "narHash": "sha256-Tyw1RjYEsp5scoigs1384gIg6e0GoBVjms4aXFfRssQ=", + "lastModified": 1741352980, + "narHash": "sha256-+u2UunDA4Cl5Fci3m7S643HzKmIDAe+fiXrLqYsR2fs=", "owner": "hercules-ci", "repo": "flake-parts", - "rev": "77826244401ea9de6e3bac47c2db46005e1f30b5", + "rev": "f4330d22f1c5d2ba72d3d22df5597d123fdb60a9", "type": "github" }, "original": { @@ -167,11 +167,11 @@ ] }, "locked": { - "lastModified": 1750779888, - "narHash": "sha256-wibppH3g/E2lxU43ZQHC5yA/7kIKLGxVEnsnVK1BtRg=", + "lastModified": 1737465171, + "narHash": "sha256-R10v2hoJRLq8jcL4syVFag7nIGE7m13qO48wRIukWNg=", "owner": "cachix", "repo": "git-hooks.nix", - "rev": "16ec914f6fb6f599ce988427d9d94efddf25fe6d", + "rev": "9364dc02281ce2d37a1f55b6e51f7c0f65a75f17", "type": "github" }, "original": { @@ -205,16 +205,16 @@ "gnome-shell": { "flake": false, "locked": { - "lastModified": 1744584021, - "narHash": "sha256-0RJ4mJzf+klKF4Fuoc8VN8dpQQtZnKksFmR2jhWE1Ew=", + "lastModified": 1732369855, + "narHash": "sha256-JhUWbcYPjHO3Xs3x9/Z9RuqXbcp5yhPluGjwsdE2GMg=", "owner": "GNOME", "repo": "gnome-shell", - "rev": "52c517c8f6c199a1d6f5118fae500ef69ea845ae", + "rev": "dadd58f630eeea41d645ee225a63f719390829dc", "type": "github" }, "original": { "owner": "GNOME", - "ref": "48.1", + "ref": "47.2", "repo": "gnome-shell", "type": "github" } @@ -226,58 +226,32 @@ ] }, "locked": { - "lastModified": 1751468302, - "narHash": "sha256-tWosziZTT039x6PgEZUhzGlV8oLvdDmIgKTE8ESMaEA=", + "lastModified": 1739757849, + "narHash": "sha256-Gs076ot1YuAAsYVcyidLKUMIc4ooOaRGO0PqTY7sBzA=", "owner": "nix-community", "repo": "home-manager", - "rev": "501cfec8277f931a9c9af9f23d3105c537faeafe", + "rev": "9d3d080aec2a35e05a15cedd281c2384767c2cfe", "type": "github" }, "original": { "owner": "nix-community", - "ref": "release-25.05", + "ref": "release-24.11", "repo": "home-manager", "type": "github" } }, - "ixx": { - "inputs": { - "flake-utils": [ - "nuschtosSearch", - "flake-utils" - ], - "nixpkgs": [ - "nuschtosSearch", - "nixpkgs" - ] - }, - "locked": { - "lastModified": 1748294338, - "narHash": "sha256-FVO01jdmUNArzBS7NmaktLdGA5qA3lUMJ4B7a05Iynw=", - "owner": "NuschtOS", - "repo": "ixx", - "rev": "cc5f390f7caf265461d4aab37e98d2292ebbdb85", - "type": "github" - }, - "original": { - "owner": "NuschtOS", - "ref": "v0.0.8", - "repo": "ixx", - "type": "github" - } - }, "lix": { "flake": false, "locked": { - "lastModified": 1751235704, - "narHash": "sha256-J4ycLoXHPsoBoQtEXFCelL4xlq5pT8U9tNWNKm43+YI=", - "rev": "1d7368585eebaa2c4bdbcb88fe600cfb2239b2c6", + "lastModified": 1737234286, + "narHash": "sha256-CCKIAE84dzkrnlxJCKFyffAxP3yfsOAbdvydUGqq24g=", + "rev": "2837da71ec1588c1187d2e554719b15904a46c8b", "type": "tarball", - "url": "https://git.lix.systems/api/v1/repos/lix-project/lix/archive/1d7368585eebaa2c4bdbcb88fe600cfb2239b2c6.tar.gz?rev=1d7368585eebaa2c4bdbcb88fe600cfb2239b2c6" + "url": "https://git.lix.systems/api/v1/repos/lix-project/lix/archive/2837da71ec1588c1187d2e554719b15904a46c8b.tar.gz?rev=2837da71ec1588c1187d2e554719b15904a46c8b" }, "original": { "type": "tarball", - "url": "https://git.lix.systems/lix-project/lix/archive/release-2.93.tar.gz" + "url": "https://git.lix.systems/lix-project/lix/archive/2.92.0.tar.gz" } }, "lix-module": { @@ -290,28 +264,91 @@ ] }, "locked": { - "lastModified": 1751240025, - "narHash": "sha256-SXUAlxpjPRkArRMHy5+Hdi+PiC+ND9yzzIjiaHmTvQU=", - "rev": "8b1094356f4723d6e89d3f8a95b333ee16d9ab02", + "lastModified": 1737237494, + "narHash": "sha256-YMLrcBpf0TR5r/eaqm8lxzFPap2TxCor0ZGcK3a7+b8=", + "rev": "b90bf629bbd835e61f1317b99e12f8c831017006", "type": "tarball", - "url": "https://git.lix.systems/api/v1/repos/lix-project/nixos-module/archive/8b1094356f4723d6e89d3f8a95b333ee16d9ab02.tar.gz?rev=8b1094356f4723d6e89d3f8a95b333ee16d9ab02" + "url": "https://git.lix.systems/api/v1/repos/lix-project/nixos-module/archive/b90bf629bbd835e61f1317b99e12f8c831017006.tar.gz?rev=b90bf629bbd835e61f1317b99e12f8c831017006" }, "original": { "type": "tarball", - "url": "https://git.lix.systems/lix-project/nixos-module/archive/release-2.93.tar.gz" + "url": "https://git.lix.systems/lix-project/nixos-module/archive/2.92.0.tar.gz" + } + }, + "niri": { + "inputs": { + "niri-stable": "niri-stable", + "niri-unstable": [], + "nixpkgs": [ + "nixpkgs" + ], + "nixpkgs-stable": [ + "nixpkgs" + ], + "xwayland-satellite-stable": "xwayland-satellite-stable", + "xwayland-satellite-unstable": [] + }, + "locked": { + "lastModified": 1741686876, + "narHash": "sha256-Kt37Zm9YcQoe/aRVbPFydZcfwIrEAg/U+iz3FcxsOZs=", + "owner": "sodiboo", + "repo": "niri-flake", + "rev": "fa230971ab63885ba5666588a7b78f75f73d5a85", + "type": "github" + }, + "original": { + "owner": "sodiboo", + "repo": "niri-flake", + "type": "github" + } + }, + "niri-stable": { + "flake": false, + "locked": { + "lastModified": 1740117926, + "narHash": "sha256-mTTHA0RAaQcdYe+9A3Jx77cmmyLFHmRoZdd8RpWa+m8=", + "owner": "YaLTeR", + "repo": "niri", + "rev": "b94a5db8790339cf9134873d8b490be69e02ac71", + "type": "github" + }, + "original": { + "owner": "YaLTeR", + "ref": "v25.02", + "repo": "niri", + "type": "github" } }, "nixpkgs": { "locked": { - "lastModified": 1751652329, - "narHash": "sha256-QFeGjfEn4dxrsAKvDBBzJkdDzw360BC5lp9SUs3BNbY=", - "rev": "7a732ed41ca0dd64b4b71b563ab9805a80a7d693", - "type": "tarball", - "url": "https://releases.nixos.org/nixos/25.05/nixos-25.05.805766.7a732ed41ca0/nixexprs.tar.xz?rev=7a732ed41ca0dd64b4b71b563ab9805a80a7d693" + "lastModified": 1741445498, + "narHash": "sha256-F5Em0iv/CxkN5mZ9hRn3vPknpoWdcdCyR0e4WklHwiE=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "52e3095f6d812b91b22fb7ad0bfc1ab416453634", + "type": "github" }, "original": { - "type": "tarball", - "url": "https://channels.nixos.org/nixos-25.05/nixexprs.tar.xz" + "owner": "NixOS", + "ref": "nixos-24.11", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_2": { + "locked": { + "lastModified": 1738797219, + "narHash": "sha256-KRwX9Z1XavpgeSDVM/THdFd6uH8rNm/6R+7kIbGa+2s=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "1da52dd49a127ad74486b135898da2cef8c62665", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" } }, "nixvim": { @@ -319,20 +356,15 @@ "flake-parts": [ "flake-parts" ], - "nixpkgs": [ - "unstable" - ], - "nuschtosSearch": [], - "systems": [ - "systems" - ] + "nixpkgs": "nixpkgs_2", + "nuschtosSearch": [] }, "locked": { - "lastModified": 1751746175, - "narHash": "sha256-6JABU+UMkaL4c+ZJRQYyFyIkm9ry1fOkhNQgSSjK5OM=", + "lastModified": 1741098523, + "narHash": "sha256-gXDSXDr6tAb+JgxGMvcEjKC9YO8tVOd8hMMZHJLyQ6Q=", "owner": "nix-community", "repo": "nixvim", - "rev": "ef0fa015a8236241bdcc27f32e6a4aa537d96cf8", + "rev": "03065fd4708bfdf47dd541d655392a60daa25ded", "type": "github" }, "original": { @@ -341,43 +373,21 @@ "type": "github" } }, - "nuschtosSearch": { - "inputs": { - "flake-utils": [ - "lix-module", - "flake-utils" - ], - "ixx": "ixx", - "nixpkgs": [ - "nixpkgs" - ] - }, - "locked": { - "lastModified": 1749730855, - "narHash": "sha256-L3x2nSlFkXkM6tQPLJP3oCBMIsRifhIDPMQQdHO5xWo=", - "owner": "NuschtOS", - "repo": "search", - "rev": "8dfe5879dd009ff4742b668d9c699bc4b9761742", - "type": "github" - }, - "original": { - "owner": "NuschtOS", - "repo": "search", - "type": "github" - } - }, "root": { "inputs": { "flake-parts": "flake-parts", "home-manager": "home-manager", "lix-module": "lix-module", + "niri": "niri", "nixpkgs": "nixpkgs", "nixvim": "nixvim", - "nuschtosSearch": "nuschtosSearch", "stylix": "stylix", "systems": "systems", "treefmt-nix": "treefmt-nix", - "unstable": "unstable" + "unstable": [ + "nixvim", + "nixpkgs" + ] } }, "stylix": { @@ -388,8 +398,9 @@ "base16-vim": "base16-vim", "firefox-gnome-theme": "firefox-gnome-theme", "flake-compat": [], - "flake-parts": [ - "flake-parts" + "flake-utils": [ + "lix-module", + "flake-utils" ], "git-hooks": "git-hooks", "gnome-shell": "gnome-shell", @@ -399,27 +410,24 @@ "nixpkgs": [ "nixpkgs" ], - "nur": [], "systems": [ "systems" ], "tinted-foot": "tinted-foot", "tinted-kitty": "tinted-kitty", - "tinted-schemes": "tinted-schemes", - "tinted-tmux": "tinted-tmux", - "tinted-zed": "tinted-zed" + "tinted-tmux": "tinted-tmux" }, "locked": { - "lastModified": 1751658706, - "narHash": "sha256-jqRbWjB8aH2qzq6nMQpwkzVBR4o9lNxAHFmRgGwnJ94=", - "owner": "nix-community", + "lastModified": 1740520580, + "narHash": "sha256-QRlcA8rtfNdyKpBE+ptjiB9717Tzum4/sKBSbsyqL6k=", + "owner": "danth", "repo": "stylix", - "rev": "5dd301b72207d4fd8d8b929abd88ba1c486d1744", + "rev": "aaa2eb8956770c096f9c46fb163bb26602e20e56", "type": "github" }, "original": { - "owner": "nix-community", - "ref": "release-25.05", + "owner": "danth", + "ref": "release-24.11", "repo": "stylix", "type": "github" } @@ -459,43 +467,28 @@ "tinted-kitty": { "flake": false, "locked": { - "lastModified": 1735730497, - "narHash": "sha256-4KtB+FiUzIeK/4aHCKce3V9HwRvYaxX+F1edUrfgzb8=", + "lastModified": 1716423189, + "narHash": "sha256-2xF3sH7UIwegn+2gKzMpFi3pk5DlIlM18+vj17Uf82U=", "owner": "tinted-theming", "repo": "tinted-kitty", - "rev": "de6f888497f2c6b2279361bfc790f164bfd0f3fa", + "rev": "eb39e141db14baef052893285df9f266df041ff8", "type": "github" }, "original": { "owner": "tinted-theming", "repo": "tinted-kitty", - "type": "github" - } - }, - "tinted-schemes": { - "flake": false, - "locked": { - "lastModified": 1750770351, - "narHash": "sha256-LI+BnRoFNRa2ffbe3dcuIRYAUcGklBx0+EcFxlHj0SY=", - "owner": "tinted-theming", - "repo": "schemes", - "rev": "5a775c6ffd6e6125947b393872cde95867d85a2a", - "type": "github" - }, - "original": { - "owner": "tinted-theming", - "repo": "schemes", + "rev": "eb39e141db14baef052893285df9f266df041ff8", "type": "github" } }, "tinted-tmux": { "flake": false, "locked": { - "lastModified": 1751159871, - "narHash": "sha256-UOHBN1fgHIEzvPmdNMHaDvdRMgLmEJh2hNmDrp3d3LE=", + "lastModified": 1740272597, + "narHash": "sha256-/etfUV3HzAaLW3RSJVwUaW8ULbMn3v6wbTlXSKbcoWQ=", "owner": "tinted-theming", "repo": "tinted-tmux", - "rev": "bded5e24407cec9d01bd47a317d15b9223a1546c", + "rev": "b6c7f46c8718cc484f2db8b485b06e2a98304cd0", "type": "github" }, "original": { @@ -504,22 +497,6 @@ "type": "github" } }, - "tinted-zed": { - "flake": false, - "locked": { - "lastModified": 1751158968, - "narHash": "sha256-ksOyv7D3SRRtebpXxgpG4TK8gZSKFc4TIZpR+C98jX8=", - "owner": "tinted-theming", - "repo": "base16-zed", - "rev": "86a470d94204f7652b906ab0d378e4231a5b3384", - "type": "github" - }, - "original": { - "owner": "tinted-theming", - "repo": "base16-zed", - "type": "github" - } - }, "treefmt-nix": { "inputs": { "nixpkgs": [ @@ -527,11 +504,11 @@ ] }, "locked": { - "lastModified": 1750931469, - "narHash": "sha256-0IEdQB1nS+uViQw4k3VGUXntjkDp7aAlqcxdewb/hAc=", + "lastModified": 1739829690, + "narHash": "sha256-mL1szCeIsjh6Khn3nH2cYtwO5YXG6gBiTw1A30iGeDU=", "owner": "numtide", "repo": "treefmt-nix", - "rev": "ac8e6f32e11e9c7f153823abc3ab007f2a65d3e1", + "rev": "3d0579f5cc93436052d94b73925b48973a104204", "type": "github" }, "original": { @@ -540,17 +517,21 @@ "type": "github" } }, - "unstable": { + "xwayland-satellite-stable": { + "flake": false, "locked": { - "lastModified": 1751734347, - "narHash": "sha256-EzgiAGp3yKKlpkjPRXL+sVhVNmp46lyq3BadLEqMeQM=", - "rev": "5c724ed1388e53cc231ed98330a60eb2f7be4be3", - "type": "tarball", - "url": "https://releases.nixos.org/nixos/unstable/nixos-25.11pre824861.5c724ed1388e/nixexprs.tar.xz?rev=5c724ed1388e53cc231ed98330a60eb2f7be4be3" + "lastModified": 1739246919, + "narHash": "sha256-/hBM43/Gd0/tW+egrhlWgOIISeJxEs2uAOIYVpfDKeU=", + "owner": "Supreeeme", + "repo": "xwayland-satellite", + "rev": "44590a416d4a3e8220e19e29e0b6efe64a80315d", + "type": "github" }, "original": { - "type": "tarball", - "url": "https://channels.nixos.org/nixos-unstable/nixexprs.tar.xz" + "owner": "Supreeeme", + "ref": "v0.5.1", + "repo": "xwayland-satellite", + "type": "github" } } }, diff --git a/flake.nix b/flake.nix index 795adef..1ad8772 100644 --- a/flake.nix +++ b/flake.nix @@ -8,11 +8,11 @@ # Flake inputs inputs = { - nixpkgs.url = "https://channels.nixos.org/nixos-25.05/nixexprs.tar.xz"; - unstable.url = "https://channels.nixos.org/nixos-unstable/nixexprs.tar.xz"; + nixpkgs.url = "github:NixOS/nixpkgs/nixos-24.11"; + unstable.follows = "nixvim/nixpkgs"; # Lix lix-module = { - url = "https://git.lix.systems/lix-project/nixos-module/archive/release-2.93.tar.gz"; + url = "https://git.lix.systems/lix-project/nixos-module/archive/2.92.0.tar.gz"; inputs = { nixpkgs.follows = "nixpkgs"; flake-utils.inputs.systems.follows = "systems"; @@ -20,16 +20,24 @@ }; # Modules home-manager = { - url = "github:nix-community/home-manager/release-25.05"; + url = "github:nix-community/home-manager/release-24.11"; inputs.nixpkgs.follows = "nixpkgs"; }; - stylix = { - url = "github:nix-community/stylix/release-25.05"; + niri = { + url = "github:sodiboo/niri-flake"; inputs = { nixpkgs.follows = "nixpkgs"; - flake-parts.follows = "flake-parts"; + nixpkgs-stable.follows = "nixpkgs"; + niri-unstable.follows = ""; + xwayland-satellite-unstable.follows = ""; + }; + }; + stylix = { + url = "github:danth/stylix/release-24.11"; + inputs = { + nixpkgs.follows = "nixpkgs"; + flake-utils.follows = "lix-module/flake-utils"; systems.follows = "systems"; - nur.follows = ""; home-manager.follows = "home-manager"; # disable optional inputs @@ -40,8 +48,6 @@ url = "github:nix-community/nixvim"; inputs = { flake-parts.follows = "flake-parts"; - systems.follows = "systems"; - nixpkgs.follows = "unstable"; # disable optional inputs nuschtosSearch.follows = ""; }; @@ -50,19 +56,10 @@ url = "github:hercules-ci/flake-parts"; inputs.nixpkgs-lib.follows = "nixpkgs"; }; - # For the formatter (can be set to null) treefmt-nix = { url = "github:numtide/treefmt-nix"; inputs.nixpkgs.follows = "nixpkgs"; }; - # For generating the docs (can be set to null) - nuschtosSearch = { - url = "github:NuschtOS/search"; - inputs = { - nixpkgs.follows = "nixpkgs"; - flake-utils.follows = "lix-module/flake-utils"; - }; - }; # For deduplication systems.url = "github:nix-systems/default"; }; diff --git a/home/default.nix b/home/default.nix new file mode 100644 index 0000000..2a8e6a5 --- /dev/null +++ b/home/default.nix @@ -0,0 +1,231 @@ +{ + nvim-config, + stylix ? null, +}: +{ + config, + pkgs, + lib, + osConfig ? null, + ... +}: +let + cfg = config.jhome; + devcfg = cfg.dev; + # Query the osConfig for a setting. Return the default value if missing or in standalone mode + fromOs = + path: default: if osConfig == null then default else lib.attrsets.attrByPath path default osConfig; +in +{ + imports = + [ + nvim-config + ./options.nix + ./gui + ./users.nix + ] + ++ lib.optionals (stylix != null) [ + stylix.homeManagerModules.stylix + { stylix.image = cfg.sway.background; } + ]; + + config = lib.mkMerge [ + (lib.mkIf (cfg.enable && cfg.styling.enable) { + stylix = { + enable = true; + targets.nixvim.enable = false; # I prefer doing it myself + }; + }) + (lib.mkIf cfg.enable { + # Add gopass if pass is enabled + home.packages = lib.optional config.programs.password-store.enable pkgs.gopass; + + nix.settings.use-xdg-base-directories = fromOs [ + "nix" + "settings" + "use-xdg-base-directories" + ] true; + programs = { + # Better cat (bat) + bat = { + enable = true; + config = { + # Disable headers and numbers + style = "plain"; + theme = lib.mkForce "gruvbox-dark"; + }; + }; + # Direnv + direnv = { + enable = true; + nix-direnv.enable = true; + }; + # ls replacement + eza = { + enable = true; + git = true; + icons = "auto"; + }; + # GnuPG + gpg = { + enable = true; + homedir = "${config.xdg.dataHome}/gnupg"; + }; + # Mail client + himalaya.enable = lib.mkDefault true; + # Password manager + password-store = { + enable = lib.mkDefault true; + package = pkgs.pass-nodmenu; + settings.PASSWORD_STORE_DIR = "${config.xdg.dataHome}/pass"; + }; + # SSH + ssh.enable = true; + # cd replacement + zoxide.enable = true; + # Shell + zsh = { + enable = true; + autosuggestion.enable = true; + enableCompletion = true; + autocd = true; + dotDir = ".config/zsh"; + history.path = "${config.xdg.dataHome}/zsh/zsh_history"; + syntaxHighlighting.enable = true; + }; + }; + services = { + # GPG Agent + gpg-agent = { + enable = true; + maxCacheTtl = 86400; + pinentryPackage = if config.jhome.gui.enable then pkgs.pinentry-qt else pkgs.pinentry-curses; + extraConfig = "allow-preset-passphrase"; + }; + # Spotifyd + spotifyd = { + inherit (config.jhome.gui) enable; + settings.global = { + device_name = config.jhome.hostName; + device_type = "computer"; + backend = "pulseaudio"; + zeroconf_port = 2020; + }; + }; + }; + home = { + stateVersion = "22.11"; + # Extra packages + # Extra variables + sessionVariables = { + CARGO_HOME = "${config.xdg.dataHome}/cargo"; + RUSTUP_HOME = "${config.xdg.dataHome}/rustup"; + GOPATH = "${config.xdg.dataHome}/go"; + }; + shellAliases = { + # Verbose Commands + cp = "cp --verbose"; + ln = "ln --verbose"; + mv = "mv --verbose"; + mkdir = "mkdir --verbose"; + rename = "rename --verbose"; + rm = "rm --verbose"; + # Add Color + grep = "grep --color=auto"; + ip = "ip --color=auto"; + # Use exa/eza + tree = "eza --tree"; + }; + }; + # XDG directories + xdg = { + enable = true; + userDirs = { + enable = true; + createDirectories = true; + }; + }; + }) + (lib.mkIf (cfg.enable && devcfg.enable) { + home = { + sessionVariables.MANPAGER = lib.optionalString devcfg.neovimAsManPager "nvim -c 'Man!' -o -"; + packages = devcfg.extraPackages; + }; + # Github CLI + programs = { + gh.enable = true; + gh-dash.enable = true; + # Git + git = { + enable = true; + difftastic = { + enable = true; + background = "dark"; + }; + lfs.enable = true; + extraConfig = { + # Add diff to the commit message editor + commit.verbose = true; + # Improve submodule diff + diff.submodule = "log"; + # Set the default branch name for new branches + init.defaultBranch = "main"; + # Better conflicts (also shows parent commit state) + merge.conflictStyle = "zdiff3"; + # Do not create merge commits when pulling (rebase but abort on conflict) + pull.ff = "only"; + # Use `--set-upstream` if the remote does not have the branch + push.autoSetupRemote = true; + rebase = { + # If there are uncommitted changes, stash them before rebasing + autoStash = true; + # If there are fixup! commits, squash them while rebasing + autoSquash = true; + }; + # Enable ReReRe (Reuse Recovered Resolution) auto resolve previously resolved conflicts + rerere.enabled = true; + # Improve submodule status + status.submoduleSummary = true; + }; + }; + lazygit.enable = true; + # Jujutsu (alternative DVCS (git-compatible)) + jujutsu = { + enable = true; + package = pkgs.unstable.jujutsu; + settings = { + ui.pager = "bat"; + # mimic git commit --verbose by adding a diff + templates.draft_commit_description = '' + concat( + description, + surround( + "\nJJ: This commit contains the following changes:\n", "", + indent("JJ: ", diff.stat(72)), + ), + surround( + "\nJJ: Diff:\n", "", + indent("JJ: ", diff.git()), + ), + ) + ''; + }; + }; + }; + }) + (lib.mkIf (cfg.enable && devcfg.enable && devcfg.rust.enable) { + home.packages = [ pkgs.rustup ] ++ devcfg.rust.extraPackages; + # Background code checker (for Rust) + programs.bacon = { + enable = true; + settings = { + export = { + enabled = true; + path = ".bacon-locations"; + line_format = "{kind} {path}:{line}:{column} {message}"; + }; + }; + }; + }) + ]; +} diff --git a/home/gui/default.nix b/home/gui/default.nix new file mode 100644 index 0000000..07aa7d6 --- /dev/null +++ b/home/gui/default.nix @@ -0,0 +1,244 @@ +{ + config, + lib, + pkgs, + osConfig ? null, + ... +}: +let + inherit (config) jhome; + flatpakEnabled = if osConfig != null then osConfig.services.flatpak.enable else false; + osSway = osConfig == null && !osConfig.programs.sway.enable; + swayPkg = if osSway then pkgs.sway else null; + cfg = jhome.gui; + cursor = { + package = pkgs.nordzy-cursor-theme; + name = "Nordzy-cursors"; + }; + iconTheme = { + name = "Papirus-Dark"; + package = pkgs.papirus-icon-theme; + }; +in +{ + config = lib.mkIf (jhome.enable && cfg.enable) { + home.packages = + (with pkgs; [ + webcord + ferdium + xournalpp + signal-desktop + pcmanfm + wl-clipboard + # Extra fonts + noto-fonts-cjk-sans # Chinese, Japanese and Korean characters + noto-fonts-cjk-serif # Chinese, Japanese and Korean characters + (nerdfonts.override { fonts = [ "NerdFontsSymbolsOnly" ]; }) + ]) + ++ lib.optional flatpakEnabled pkgs.flatpak; + fonts.fontconfig = { + enable = true; + defaultFonts = lib.mkIf config.jhome.styling.enable { + emoji = [ "Noto Color Emoji" ]; + monospace = [ + "JetBrains Mono" + "Symbols Nerd Font" + ]; + serif = [ + "Noto Serif" + "Symbols Nerd Font" + ]; + sansSerif = [ + "Noto Sans" + "Symbols Nerd Font" + ]; + }; + }; + # Browser + programs = { + firefox.enable = true; + # Dynamic Menu + fuzzel = { + enable = true; + settings.main = lib.mkIf config.jhome.styling.enable { + icon-theme = "Papirus-Dark"; + inherit (cfg) terminal; + layer = "overlay"; + }; + }; + # Video player + mpv = { + enable = true; + scripts = builtins.attrValues { inherit (pkgs.mpvScripts) uosc thumbfast; }; + }; + # Text editor + nixvim.clipboard.providers.wl-copy.enable = lib.mkDefault true; + # Status bar + waybar = { + enable = true; + systemd.enable = true; + settings = lib.mkIf config.jhome.styling.enable ( + import ./waybar-settings.nix { inherit config lib; } + ); + style = + lib.optionalString config.jhome.styling.enable # css + '' + .modules-left #workspaces button { + border-bottom: 3px solid @base01; + } + .modules-left #workspaces button.persistent { + border-bottom: 3px solid transparent; + } + ''; + }; + # Terminal + wezterm = { + enable = cfg.terminal == "wezterm"; + extraConfig = + lib.optionalString config.jhome.styling.enable # lua + '' + local wezterm = require("wezterm") + + local config = wezterm.config_builder() + + config.front_end = "WebGpu" + config.hide_tab_bar_if_only_one_tab = true + config.window_padding = { left = 1, right = 1, top = 1, bottom = 1 } + + return config + ''; + }; + alacritty = { + enable = cfg.terminal == "alacritty"; + settings = { + # hide mouse when typing, this ensures I don't have to move the mouse when it hides text + mouse.hide_when_typing = true; + # Start zellij when it is enabled + terminal.shell = lib.mkIf (config.jhome.dev.enable && config.programs.zellij.enable) { + program = "${lib.getExe config.programs.zellij.package}"; + }; + }; + }; + zellij.enable = cfg.terminal == "alacritty"; # alacritty has no terminal multiplexer built-in + # PDF reader + zathura.enable = true; + # Auto start sway + zsh.loginExtra = + lib.optionalString cfg.sway.autostart # sh + '' + # Start Sway on login to TTY 1 + if [ "$TTY" = /dev/tty1 ]; then + exec sway + fi + ''; + }; + services = { + # Volume/Backlight control and notifications + avizo = { + enable = true; + settings.default = { + time = 0.8; + border-width = 0; + height = 176; + y-offset = 0.1; + block-spacing = 1; + }; + }; + # Sound tuning + easyeffects.enable = true; + # Auto configure displays + kanshi.enable = lib.mkDefault true; + # Notifications + mako = { + enable = true; + layer = "overlay"; + borderRadius = 8; + defaultTimeout = 15000; + }; + }; + + # Window Manager + programs.niri = { + package = pkgs.niri; # use nixpkgs' package instead of the flake's + settings = { + binds = + let + # Modifier key + mod = "Mod"; + # Available workspaces (1..=9) + workspaces = lib.range 1 9; + # Run function for each workspace + perWorkspace = f: lib.mergeAttrsList (builtins.map f workspaces); + # alias for concatStringsSep + joinWith = lib.strings.concatStringsSep; + in + with config.lib.niri.actions; + { + # Open Terminal + "${mod}+Return".action.spawn = + if config.jhome.gui.terminal == "alacritty" then "alacritty" else config.jhome.gui.terminalCommand; + # Open menu + "${mod}+D".action = + spawn "${lib.getExe pkgs.fuzzel}" "--terminal" + "${joinWith " " config.jhome.gui.terminalCommand}"; + # Close Window + "${mod}+Q".action = close-window; + # Fullscreen + "${mod}+F".action = fullscreen-window; + # Hotkey help menu + "${mod}+Shift+Slash".action = show-hotkey-overlay; + # Media Keys + "XF86AudioRaiseVolume" = { + action = spawn "${pkgs.avizo}/bin/volumectl" "up"; + allow-when-locked = true; + }; + "XF86AudioLowerVolume" = { + action = spawn "${pkgs.avizo}/bin/volumectl" "down"; + allow-when-locked = true; + }; + "XF86AudioMute" = { + action = spawn "${pkgs.avizo}/bin/volumectl" "toggle-mute"; + allow-when-locked = true; + }; + # FIXME: swaylock is missing so this doesn't work anyways + # Lock screen + # "XF86ScreenSaver".action = spawn "swaylock" "--image" "${cfg.background}"; + # Screen brightness + "XF86MonBrightnessUp".action = spawn "${pkgs.avizo}/bin/lightctl" "up"; + "XF86MonBrightnessDown".action = spawn "${pkgs.avizo}/bin/lightctl" "down"; + } + // perWorkspace (workspace: { + # Focus workspace N + "${mod}+${builtins.toString workspace}".action = focus-workspace workspace; + }); + }; + }; + + # Set cursor style + stylix = lib.mkIf config.jhome.styling.enable { inherit cursor; }; + home.pointerCursor = lib.mkIf config.jhome.styling.enable ( + lib.mkDefault { + gtk.enable = true; + inherit (cursor) name package; + } + ); + # Set Gtk theme + gtk = lib.mkIf config.jhome.styling.enable { + enable = true; + inherit iconTheme; + gtk3.extraConfig.gtk-application-prefer-dark-theme = 1; + gtk4.extraConfig.gtk-application-prefer-dark-theme = 1; + }; + # Set Qt theme + qt = lib.mkIf config.jhome.styling.enable { + enable = true; + platformTheme.name = "gtk"; + }; + + xdg.systemDirs.data = [ + "/usr/share" + "/var/lib/flatpak/exports/share" + "${config.xdg.dataHome}/flatpak/exports/share" + ]; + }; +} diff --git a/home/gui/keybindings.nix b/home/gui/keybindings.nix new file mode 100644 index 0000000..867be55 --- /dev/null +++ b/home/gui/keybindings.nix @@ -0,0 +1,118 @@ +{ pkgs, config }: +let + cfg = config.jhome.gui.sway; + passmenu = "${pkgs.jpassmenu}/bin/jpassmenu"; + selectAudio = "${pkgs.audiomenu}/bin/audiomenu"; + swayconf = config.wayland.windowManager.sway.config; + mod = swayconf.modifier; + workspaces = map toString [ + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + ]; + dirs = + map + (dir: { + key = swayconf.${dir}; + arrow = dir; + direction = dir; + }) + [ + "up" + "down" + "left" + "right" + ]; + joinKeys = builtins.concatStringsSep "+"; + # Generate a keybind from a modifier prefix and a key + keycombo = prefix: key: joinKeys (prefix ++ [ key ]); + modKeybind = keycombo [ mod ]; + modCtrlKeybind = keycombo [ + mod + "Ctrl" + ]; + modShiftKeybind = keycombo [ + mod + "Shift" + ]; + modCtrlShiftKeybind = keycombo [ + mod + "Ctrl" + "Shift" + ]; + dir2resize.up = "resize grow height"; + dir2resize.down = "resize shrink height"; + dir2resize.right = "resize grow width"; + dir2resize.left = "resize shrink width"; + # Bind a key combo to an action + genKeybind = prefix: action: key: { "${prefix key}" = "${action key}"; }; + genKey = + prefix: action: genKeybind ({ key, ... }: prefix key) ({ direction, ... }: action direction); + genArrow = + prefix: action: genKeybind ({ arrow, ... }: prefix arrow) ({ direction, ... }: action direction); + genArrowAndKey = + prefix: action: key: + (genKey prefix action key) // (genArrow prefix action key); + # Move window + moveWindowKeybinds = map (genArrowAndKey modShiftKeybind (dir: "move ${dir}")) dirs; + # Focus window + focusWindowKeybinds = map (genArrowAndKey modKeybind (dir: "focus ${dir}")) dirs; + # Resize window + resizeWindowKeybinds = map (genArrowAndKey modCtrlKeybind (dir: dir2resize.${dir})) dirs; + # Move container to workspace + moveWorkspaceKeybindings = map (genKeybind modShiftKeybind ( + number: "move container to workspace number ${number}" + )) workspaces; + # Focus workspace + focusWorkspaceKeybindings = map (genKeybind modKeybind ( + number: "workspace number ${number}" + )) workspaces; + # Move container to Workspace and focus on it + moveFocusWorkspaceKeybindings = map (genKeybind modCtrlShiftKeybind ( + number: "move container to workspace number ${number}; workspace number ${number}" + )) workspaces; +in +builtins.foldl' (l: r: l // r) + { + "${mod}+Return" = "exec ${swayconf.terminal}"; + "${mod}+D" = "exec ${swayconf.menu}"; + "${mod}+P" = "exec ${passmenu}"; + "${mod}+Shift+P" = "exec ${passmenu} --type"; + "${mod}+F2" = "exec qutebrowser"; + "${mod}+Shift+Q" = "kill"; + "${mod}+F" = "fullscreen toggle"; + # Media Controls + "${mod}+F10" = "exec ${selectAudio} select-sink"; + "${mod}+Shift+F10" = "exec ${selectAudio} select-source"; + "XF86AudioRaiseVolume" = "exec ${pkgs.avizo}/bin/volumectl up"; + "XF86AudioLowerVolume" = "exec ${pkgs.avizo}/bin/volumectl down"; + "XF86AudioMute" = "exec ${pkgs.avizo}/bin/volumectl toggle-mute"; + "XF86ScreenSaver" = "exec swaylock --image ${cfg.background}"; + "XF86MonBrightnessUp" = "exec ${pkgs.avizo}/bin/lightctl up"; + "XF86MonBrightnessDown" = "exec ${pkgs.avizo}/bin/lightctl down"; + # Floating + "${mod}+Space" = "floating toggle"; + "${mod}+Shift+Space" = "focus mode_toggle"; + # Scratchpad + "${mod}+Minus" = "scratchpad show"; + "${mod}+Shift+Minus" = "move scratchpad"; + # Layout + "${mod}+e" = "layout toggle split"; + # Session control + "${mod}+r" = "reload"; + "${mod}+Shift+m" = "exit"; + } + ( + focusWindowKeybinds + ++ moveWindowKeybinds + ++ resizeWindowKeybinds + ++ focusWorkspaceKeybindings + ++ moveWorkspaceKeybindings + ++ moveFocusWorkspaceKeybindings + ) diff --git a/home/gui/sway-config.nix b/home/gui/sway-config.nix new file mode 100644 index 0000000..f499f71 --- /dev/null +++ b/home/gui/sway-config.nix @@ -0,0 +1,95 @@ +{ config, pkgs }: +let + cfg = config.jhome.gui.sway; + modifier = "Mod4"; + termCmd = builtins.concatStringsSep " " config.jhome.gui.terminalCommand; + menu = "${pkgs.fuzzel}/bin/fuzzel --terminal '${termCmd}'"; + # currently, there is some friction between sway and gtk: + # https://github.com/swaywm/sway/wiki/GTK-3-settings-on-Wayland + # the suggested way to set gtk settings is with gsettings + # for gsettings to work, we need to tell it where the schemas are + # using the XDG_DATA_DIR environment variable + # run at the end of sway config + configure-gtk = + let + schema = pkgs.gsettings-desktop-schemas; + datadir = "${schema}/share/gsettings-schemas/${schema.name}"; + in + pkgs.writers.writeDashBin "configure-gtk" '' + export XDG_DATA_DIRS="${datadir}:$XDG_DATA_DIRS" + + gnome_schema=org.gnome.desktop.interface + config="${config.xdg.configHome}/gtk-3.0/settings.ini" + if [ ! -f "$config" ]; then exit 1; fi + # Read settings from gtk3 + gtk_theme="$(${pkgs.gnugrep}/bin/grep 'gtk-theme-name' "$config" | ${pkgs.gnused}/bin/sed 's/.*\s*=\s*//')" + icon_theme="$(${pkgs.gnugrep}/bin/grep 'gtk-icon-theme-name' "$config" | ${pkgs.gnused}/bin/sed 's/.*\s*=\s*//')" + cursor_theme="$(${pkgs.gnugrep}/bin/grep 'gtk-cursor-theme-name' "$config" | ${pkgs.gnused}/bin/sed 's/.*\s*=\s*//')" + font_name="$(grep 'gtk-font-name' "$config" | sed 's/.*\s*=\s*//')" + ${pkgs.glib}/bin/gsettings set "$gnome_schema" gtk-theme "$gtk_theme" + ${pkgs.glib}/bin/gsettings set "$gnome_schema" icon-theme "$icon_theme" + ${pkgs.glib}/bin/gsettings set "$gnome_schema" cursor-theme "$cursor_theme" + ${pkgs.glib}/bin/gsettings set "$gnome_schema" font-name "$font_name" + ${pkgs.glib}/bin/gsettings set "$gnome_schema" color-scheme prefer-dark + ''; + cmdOnce = command: { inherit command; }; + cmdAlways = command: { + inherit command; + always = true; + }; +in +{ + inherit (config.jhome.gui) terminal; + inherit modifier menu; + keybindings = import ./keybindings.nix { inherit config pkgs; }; + # Appearance + bars = [ ]; # Waybar is started as a systemd service + gaps = { + smartGaps = true; + smartBorders = "on"; + inner = 4; + }; + output."*".bg = "${cfg.background} fill"; + # Window Appearance + window = { + border = 2; + titlebar = false; + # Make certain windows floating + commands = [ + { + command = "floating enable"; + criteria.title = "zoom"; + } + { + command = "floating enable"; + criteria.class = "floating"; + } + { + command = "floating enable"; + criteria.app_id = "floating"; + } + ]; + }; + # Startup scripts + startup = + [ + (cmdAlways "${configure-gtk}/bin/configure-gtk") + ] + ++ (builtins.map cmdAlways cfg.exec.always) + ++ (builtins.map cmdOnce cfg.exec.once); + # Keyboard configuration + input."type:keyboard" = { + repeat_delay = "300"; + repeat_rate = "50"; + xkb_options = "caps:swapescape,compose:ralt"; + xkb_numlock = "enabled"; + }; + # Touchpad + input."type:touchpad" = { + click_method = "clickfinger"; + natural_scroll = "enabled"; + scroll_method = "two_finger"; + tap = "enabled"; + tap_button_map = "lrm"; + }; +} diff --git a/home/gui/waybar-settings.nix b/home/gui/waybar-settings.nix new file mode 100644 index 0000000..3fcf58c --- /dev/null +++ b/home/gui/waybar-settings.nix @@ -0,0 +1,127 @@ +{ config, lib }: +let + cfg = config.jhome.gui; +in +{ + mainBar = { + layer = "top"; + position = "top"; + margin = "2 2 2 2"; + # Choose the order of the modules + modules-left = [ "sway/workspaces" ]; + modules-center = [ "clock" ]; + modules-right = + [ + "pulseaudio" + "backlight" + "battery" + "sway/language" + "memory" + ] + ++ lib.optional (cfg.tempInfo != null) "temperature" + ++ [ "tray" ]; + "sway/workspaces" = { + disable-scroll = true; + persistent-workspaces = { + "1" = [ ]; + "2" = [ ]; + "3" = [ ]; + "4" = [ ]; + "5" = [ ]; + "6" = [ ]; + "7" = [ ]; + "8" = [ ]; + "9" = [ ]; + }; + }; + "sway/language" = { + format = "{} "; + min-length = 5; + tooltip = false; + }; + memory = { + format = "{used:0.1f}/{total:0.1f}GiB "; + interval = 3; + }; + clock = { + timezone = "Europe/Berlin"; + tooltip-format = "{:%Y %B}\n{calendar}"; + format = "{:%a, %d %b, %H:%M}"; + }; + pulseaudio = { + reverse-scrolling = 1; + format = "{volume}% {icon} {format_source}"; + format-bluetooth = "{volume}% {icon} {format_source}"; + format-bluetooth-muted = "{volume}% 󰖁 {icon} {format_source}"; + format-muted = "{volume}% 󰖁 {format_source}"; + format-source = "{volume}% "; + format-source-muted = "{volume}% 󰍭"; + format-icons = { + headphone = "󰋋"; + hands-free = ""; + headset = "󰋎"; + phone = "󰘂"; + portable = ""; + car = ""; + default = [ + "󰕿" + "󰖀" + "󰕾" + ]; + }; + on-click = "pavucontrol"; + min-length = 13; + }; + temperature = lib.optionalAttrs (cfg.tempInfo != null) { + inherit (cfg.tempInfo) hwmon-path; + critical-threshold = 80; + format = "{temperatureC}°C {icon}"; + format-icons = [ + "" + "" + "" + "" + "" + ]; + tooltip = false; + }; + backlight = { + device = "intel_backlight"; + format = "{percent}% {icon}"; + format-icons = [ + "󰃚" + "󰃛" + "󰃜" + "󰃝" + "󰃞" + "󰃟" + "󰃠" + ]; + min-length = 7; + }; + battery = { + states.warning = 30; + states.critical = 15; + format = "{capacity}% {icon}"; + format-charging = "{capacity}% 󰂄"; + format-plugged = "{capacity}% 󰚥"; + format-alt = "{time} {icon}"; + format-icons = [ + "󰁺" + "󰁻" + "󰁼" + "󰁽" + "󰁾" + "󰁿" + "󰂀" + "󰂁" + "󰂂" + "󰁹" + ]; + }; + tray = { + icon-size = 16; + spacing = 0; + }; + }; +} diff --git a/modules/hm/options.nix b/home/options.nix similarity index 76% rename from modules/hm/options.nix rename to home/options.nix index 811384a..24b09cc 100644 --- a/modules/hm/options.nix +++ b/home/options.nix @@ -78,13 +78,23 @@ let example = "/sys/class/hwmon/hwmon2/temp1_input"; }; - sway.options = { - enable = lib.mkEnableOption "sway" // { + windowManager.options = { + enable = lib.mkEnableOption "window manager" // { default = fromConfig [ "gui" - "sway" + "windowManager" + "enable" ] true; }; + windowManager = lib.mkOption { + description = "Which window manager to enable"; + type = types.enum [ "niri" ]; + default = fromConfig [ + "gui" + "windowManager" + "windowManager" + ] "niri"; + }; background = lib.mkOption { description = "The wallpaper to use."; type = types.path; @@ -114,55 +124,60 @@ let default = true; example = false; }; - exec = lib.mkOption { - description = "Run commands when starting sway."; - default = { }; - type = types.submodule { - options = { - once = lib.mkOption { - description = "Programs to start only once (`exec`)."; - type = types.listOf types.str; - default = [ ]; - example = [ "signal-desktop --start-in-tray" ]; - }; - always = lib.mkOption { - description = "Programs to start whenever the config is sourced (`exec_always`)."; - type = types.listOf types.str; - default = [ ]; - example = [ "signal-desktop --start-in-tray" ]; - }; - }; - }; - }; }; - gui.options = { - enable = lib.mkEnableOption "GUI applications" // { - default = fromConfig [ - "gui" - "enable" - ] false; + gui.options = + let + cfg = attrs.config.jhome.gui; + in + { + enable = lib.mkEnableOption "GUI applications" // { + default = fromConfig [ + "gui" + "enable" + ] false; + }; + tempInfo = lib.mkOption { + description = "Temperature info to display in the statusbar."; + default = null; + type = types.nullOr (types.submodule tempInfo); + }; + windowManager = lib.mkOption { + description = "Window manager configuration."; + default = { }; + type = types.submodule windowManager; + }; + terminal = lib.mkOption { + description = "The terminal emulator to use."; + default = "alacritty"; + example = "wezterm"; + type = types.enum [ + "wezterm" + "alacritty" + ]; + }; + terminalCommand = lib.mkOption { + description = "The command to run in order to start the terminal."; + default = + if cfg.terminal == "wezterm" then + [ + "wezterm" + "start" + ] + else if cfg.terminal == "alacritty" then + [ + "alacritty" + "-e" + ] + else + builtins.abort "no command configured for ${cfg.terminal}"; + example = [ + "wezterm" + "start" + ]; + type = types.listOf types.str; + }; }; - tempInfo = lib.mkOption { - description = "Temperature info to display in the statusbar."; - default = null; - type = types.nullOr (types.submodule tempInfo); - }; - sway = lib.mkOption { - description = "Sway window manager configuration."; - default = { }; - type = types.submodule sway; - }; - terminal = lib.mkOption { - description = "The terminal emulator to use."; - default = "alacritty"; - example = "wezterm"; - type = types.enum [ - "wezterm" - "alacritty" - ]; - }; - }; in { options.jhome = lib.mkOption { @@ -198,6 +213,8 @@ in [ "just" ] # just a command runner [ "typos" ] # low false positive rate typo checker [ "gcc" ] # GNU Compiler Collection + [ "git-absorb" ] # fixup! but automatic + [ "gitoxide" ] # git but RiiR [ "man-pages" ] # gimme the man pages [ "man-pages-posix" ] # I said gimme the man pages!!! ]; @@ -209,6 +226,8 @@ in options.extraPackages = mkExtraPackagesOption "Rust" [ [ "cargo-insta" ] # snapshot testing [ "cargo-nextest" ] # better testing harness + [ "cargo-udeps" ] # check for unused dependencies (requires nightly) + [ "cargo-watch" ] # watch for file changes and run commands ]; }; }; diff --git a/modules/hm/users.nix b/home/users.nix similarity index 55% rename from modules/hm/users.nix rename to home/users.nix index 702e60c..dc36346 100644 --- a/modules/hm/users.nix +++ b/home/users.nix @@ -4,12 +4,15 @@ let inherit (cfg.defaultIdentity) signingKey; cfg = jhome.user; + hasConfig = jhome.enable && cfg != null; hasKey = signingKey != null; + gpgHome = config.programs.gpg.homedir; + unlockKey = hasConfig && cfg.gpg.unlockKeys != [ ]; in { - config = lib.mkIf (jhome.enable && cfg != null) { - programs = { - git = { + config = lib.mkMerge [ + (lib.mkIf hasConfig { + programs.git = { userName = cfg.defaultIdentity.name; userEmail = cfg.defaultIdentity.email; signing = lib.mkIf hasKey { @@ -17,24 +20,22 @@ in key = signingKey; }; }; - - jujutsu.settings = { + programs.jujutsu.settings = { user = lib.mkIf (cfg.defaultIdentity != null) { inherit (cfg.defaultIdentity) name email; }; - git.sign-on-push = lib.mkDefault hasKey; signing = lib.mkIf hasKey { - behaviour = "own"; + sign-all = true; backend = "gpg"; key = signingKey; }; }; - }; + }) + (lib.mkIf unlockKey { + xdg.configFile.pam-gnupg.text = + '' + ${gpgHome} - xdg.configFile.pam-gnupg = lib.mkIf (cfg.gpg.unlockKeys != [ ]) { - text = '' - ${config.programs.gpg.homedir} - - ${lib.strings.concatLines cfg.gpg.unlockKeys} - ''; - }; - }; + '' + + (lib.strings.concatLines cfg.gpg.unlockKeys); + }) + ]; } diff --git a/justfile b/justfile index 483e46c..a88bd00 100644 --- a/justfile +++ b/justfile @@ -3,29 +3,32 @@ default: # Update a specific flake input update input: - nix flake lock --update-input "{{input}}" --commit-lock-file + nix flake lock --update-input {{input}} --commit-lock-file build-vm: - nixos-rebuild build-vm --fallback --flake .#vm --print-build-logs + nixos-rebuild build-vm --flake .#vm --print-build-logs run-vm: build-vm QEMU_OPTS="$QEMU_OPTS_WL" result/bin/run-nixos-vm update-vim-plugins: #!/bin/sh - plugindir=./modules/nixvim/extraPlugins + # Use local nixpkgs if available + nixpkgs="$HOME/Dev/nixpkgs" # copy nixpkgs from local checkout - nixpkgs="$(mktemp -d)" - cp -r /nix/var/nix/profiles/per-user/root/channels/nixos/nixpkgs/. "$nixpkgs" - cd "$nixpkgs" - git init . - git add . - git commit -m 'dummy commit' - cd - + if [ ! -d "$nixpkgs" ]; then + nixpkgs="$(mktemp -d)" + cp -r /nix/var/nix/profiles/per-user/root/channels/nixos/nixpkgs/. "$nixpkgs" + cd "$nixpkgs" + git init . + git add . + git commit -m 'dummy commit' + cd - + fi # update vim plugins - nix run nixpkgs#vimPluginsUpdater -- --proc=1 --nixpkgs "$nixpkgs" --no-commit -i "$plugindir/plugins" -o "$plugindir/generated.nix" update + nix run nixpkgs#vimPluginsUpdater -- --proc=1 --nixpkgs "$nixpkgs" --no-commit -i ./nvim/extraPlugins/plugins -o ./nvim/extraPlugins/generated.nix update # format the generated output - nix fmt "$plugindir/generated.nix" + nix fmt ./nvim/extraPlugins/generated.nix # Amend Update flake.lock PR flake-pr: diff --git a/machines/vm/default.nix b/machines/vm/default.nix new file mode 100644 index 0000000..ced0faa --- /dev/null +++ b/machines/vm/default.nix @@ -0,0 +1,31 @@ +{ + services.qemuGuest.enable = true; + + boot.initrd.availableKernelModules = [ + "xhci_pci" + "ehci_pci" + "ahci" + "usbhid" + "usb_storage" + "sd_mod" + "virtio_balloon" + "virtio_blk" + "virtio_pci" + "virtio_ring" + # "virtio_vga" + "virtio_gpu" + ]; + fileSystems."/".device = "/dev/disk/by-label/nixos"; + + boot.loader.systemd-boot.enable = true; + + services.openssh.enable = true; + + # This value determines the NixOS release from which the default + # settings for stateful data, like file locations and database versions + # on your system were taken. It‘s perfectly fine and recommended to leave + # this value at the release version of the first install of this system. + # Before changing this value read the documentation for this option + # (e.g. man configuration.nix or on https://nixos.org/nixos/options.html). + system.stateVersion = "22.11"; # Did you read the comment? +} diff --git a/modules/hm/default.nix b/modules/hm/default.nix deleted file mode 100644 index 2e5a8db..0000000 --- a/modules/hm/default.nix +++ /dev/null @@ -1,171 +0,0 @@ -{ - config, - pkgs, - lib, - osConfig ? null, - ... -}: -let - cfg = config.jhome; - devcfg = cfg.dev; - # Query the osConfig for a setting. Return the default value if missing or in standalone mode - fromOs = - path: default: if osConfig == null then default else lib.attrsets.attrByPath path default osConfig; -in -{ - imports = [ - ./options.nix - ./gui - ./dev.nix - ./users.nix - ]; - - config = lib.mkMerge [ - (lib.mkIf (cfg.enable && cfg.styling.enable) { - stylix = { - enable = true; - targets.nixvim.enable = false; # I prefer styling it myself - }; - }) - (lib.mkIf (cfg.enable && cfg.styling.enable && !cfg.gui.enable) { - # Stylix disable graphical targets when no GUI is requested - stylix.targets = { - gtk.enable = false; - qt.enable = false; - gnome.enable = false; - kde.enable = false; - xresources.enable = false; - }; - }) - (lib.mkIf cfg.enable { - # Add gopass if pass is enabled - home.packages = lib.optional config.programs.password-store.enable pkgs.gopass; - - nix = { - # Run GC for Home Manager generations - gc = { - automatic = true; - frequency = "weekly"; - options = "--delete-older-than 30d"; - # run between 0 and 45min after boot if run was missed - randomizedDelaySec = "45min"; - }; - - # Use XDG directories - settings.use-xdg-base-directories = fromOs [ - "nix" - "settings" - "use-xdg-base-directories" - ] true; - }; - - programs = { - # Switch to fish if bash is started interactively - bash.initExtra = '' - if [[ $(${pkgs.procps}/bin/ps --no-header --pid=$PPID --format=comm) != "fish" && -z ''${BASH_EXECUTION_STRING} ]] - then - shopt -q login_shell && LOGIN_OPTION='--login' || LOGIN_OPTION="" - exec ${pkgs.fish}/bin/fish $LOGIN_OPTION - fi - ''; - # Better cat (bat) - bat = { - enable = true; - config = { - # Disable headers and numbers - style = "plain"; - theme = lib.mkForce "gruvbox-dark"; - }; - }; - # Direnv - direnv = { - enable = true; - nix-direnv.enable = true; - }; - # ls replacement - eza = { - enable = true; - git = true; - icons = "auto"; - }; - # Shell - bash.enable = true; # ensure HM variables are passed to `bash` too (otherwise `jpassmenu` doesn't work) - fish = { - enable = true; - preferAbbrs = true; # when defining an alias, prefer instead to define an abbreviation - }; - # GnuPG - gpg = { - enable = true; - homedir = "${config.xdg.dataHome}/gnupg"; - }; - # Mail client - himalaya.enable = lib.mkDefault true; - # Password manager - password-store = { - enable = lib.mkDefault true; - package = pkgs.pass-nodmenu; - settings.PASSWORD_STORE_DIR = "${config.xdg.dataHome}/pass"; - }; - # SSH - ssh.enable = true; - # cd replacement - zoxide.enable = true; - }; - - services = { - # GPG Agent - gpg-agent = { - enable = true; - maxCacheTtl = 86400; - pinentry.package = if config.jhome.gui.enable then pkgs.pinentry-qt else pkgs.pinentry-curses; - extraConfig = "allow-preset-passphrase"; - }; - # Delete old generations (>month) - home-manager.autoExpire.enable = true; - # Spotifyd - spotifyd = { - inherit (config.jhome.gui) enable; - settings.global = { - device_name = config.jhome.hostName; - device_type = "computer"; - backend = "pulseaudio"; - zeroconf_port = 2020; - }; - }; - }; - - home = { - # Extra variables - sessionVariables = { - CARGO_HOME = "${config.xdg.dataHome}/cargo"; - RUSTUP_HOME = "${config.xdg.dataHome}/rustup"; - GOPATH = "${config.xdg.dataHome}/go"; - }; - shellAliases = { - # Verbose Commands - cp = "cp --verbose"; - ln = "ln --verbose"; - mv = "mv --verbose"; - mkdir = "mkdir --verbose"; - rename = "rename --verbose"; - rm = "rm --verbose"; - # Add Color - grep = "grep --color=auto"; - ip = "ip --color=auto"; - # Use exa/eza - tree = "eza --tree"; - }; - }; - - # XDG directories - xdg = { - enable = true; - userDirs = { - enable = true; - createDirectories = true; - }; - }; - }) - ]; -} diff --git a/modules/hm/dev.nix b/modules/hm/dev.nix deleted file mode 100644 index afa3899..0000000 --- a/modules/hm/dev.nix +++ /dev/null @@ -1,178 +0,0 @@ -{ - pkgs, - lib, - config, - ... -}: -let - cfg = config.jhome.dev; - nvimFormatters = builtins.mapAttrs ( - name: value: value.command - ) config.programs.nixvim.plugins.conform-nvim.settings.formatters; - jjFormatters = - let - ext_to_glob = ext: "glob:'**/*.${ext}'"; - exts = builtins.map ext_to_glob; - in - { - fish = cmd: { - command = [ cmd ]; - patterns = exts [ "fish" ]; - }; - clang_format = cmd: { - command = [ - cmd - "--assume-filename=$path" - ]; - patterns = exts [ - "c" - "cc" - "cpp" - "h" - "hh" - "hpp" - ]; - }; - nixfmt = cmd: { - command = [ - cmd - "--filename=$path" - ]; - patterns = exts [ "nix" ]; - }; - shfmt = cmd: { - command = [ - cmd - "--filename" - "$path" - "-" - ]; - patterns = exts [ - "sh" - "bash" - ]; - }; - stylua = cmd: { - command = [ - cmd - "--stdin-filepath=$path" - "-" - ]; - patterns = exts [ "lua" ]; - }; - taplo = cmd: { - command = [ - cmd - "format" - "--stdin-filepath=$path" - "-" - ]; - patterns = exts [ "toml" ]; - }; - yamlfmt = cmd: { - command = [ - cmd - "-in" - ]; - patterns = exts [ - "yaml" - "yml" - ]; - }; - }; -in -{ - config = - lib.flip lib.pipe - [ - lib.mkMerge - (lib.mkIf (config.jhome.enable && cfg.enable)) - ] - [ - (lib.mkIf cfg.rust.enable { - home.packages = [ pkgs.rustup ] ++ cfg.rust.extraPackages; - }) - { - home = { - sessionVariables.MANPAGER = lib.optionalString cfg.neovimAsManPager "nvim -c 'Man!' -o -"; - packages = cfg.extraPackages; - }; - - # Github CLI - programs = { - gh.enable = true; - gh-dash.enable = true; - # Git - git = { - enable = true; - difftastic = { - enable = true; - background = "dark"; - }; - lfs.enable = true; - extraConfig = { - # Add diff to the commit message editor - commit.verbose = true; - # Improve submodule diff - diff.submodule = "log"; - # Set the default branch name for new branches - init.defaultBranch = "main"; - # Better conflicts (also shows parent commit state) - merge.conflictStyle = "zdiff3"; - # Do not create merge commits when pulling (rebase but abort on conflict) - pull.ff = "only"; - # Use `--set-upstream` if the remote does not have the branch - push.autoSetupRemote = true; - rebase = { - # If there are uncommitted changes, stash them before rebasing - autoStash = true; - # If there are fixup! commits, squash them while rebasing - autoSquash = true; - }; - # Enable ReReRe (Reuse Recovered Resolution) auto resolve previously resolved conflicts - rerere.enabled = true; - # Improve submodule status - status.submoduleSummary = true; - }; - }; - lazygit.enable = true; - # Jujutsu (alternative DVCS (git-compatible)) - jujutsu = { - enable = true; - # Use the more up to date version of jj - package = pkgs.unstable.jujutsu; - settings = { - ui = lib.mkMerge [ - # If `bat` is available use it as the pager - (lib.mkIf config.programs.bat.enable { pager = "bat"; }) - # if hunk.nvim is enabled use it as a diff editor - (lib.mkIf config.programs.nixvim.plugins.hunk.enable { - diff-editor = [ - "nvim" - "-c" - "DiffEditor $left $right $output" - ]; - }) - ]; - fix.tools = builtins.mapAttrs (tool: cmd: jjFormatters.${tool} cmd) nvimFormatters; - # mimic git commit --verbose by adding a diff - templates.draft_commit_description = '' - concat( - description, - "\n", - surround( - "\nJJ: This commit contains the following changes:\n", "", - indent("JJ: ", diff.summary()), - ), - surround( - "JJ: ignore-rest\n", "", - diff.git(), - ), - ) - ''; - }; - }; - }; - } - ]; -} diff --git a/modules/hm/gui/default.nix b/modules/hm/gui/default.nix deleted file mode 100644 index 8c40e5a..0000000 --- a/modules/hm/gui/default.nix +++ /dev/null @@ -1,257 +0,0 @@ -{ - config, - lib, - pkgs, - osConfig ? null, - ... -}: -let - inherit (config) jhome; - flatpakEnabled = if osConfig != null then osConfig.services.flatpak.enable else false; - osSway = osConfig == null && !osConfig.programs.sway.enable; - swayPkg = if osSway then pkgs.sway else null; - cfg = jhome.gui; - cursor = { - package = pkgs.nordzy-cursor-theme; - size = 48; - name = "Nordzy-cursors"; - }; -in -{ - imports = [ - ./sway.nix - ./waybar.nix - ]; - - config = lib.mkIf (jhome.enable && cfg.enable) { - home.packages = [ - pkgs.webcord - pkgs.ferdium - pkgs.xournalpp - pkgs.signal-desktop - pkgs.pcmanfm - pkgs.wl-clipboard - # Extra fonts - pkgs.noto-fonts-cjk-sans # Chinese, Japanese and Korean characters - pkgs.noto-fonts-cjk-serif # Chinese, Japanese and Korean characters - pkgs.nerd-fonts.symbols-only - ] ++ lib.optional flatpakEnabled pkgs.flatpak; - fonts.fontconfig = { - enable = true; - defaultFonts = lib.mkIf config.jhome.styling.enable { - emoji = [ "Noto Color Emoji" ]; - monospace = [ - "JetBrains Mono" - "Symbols Nerd Font" - ]; - serif = [ - "Noto Serif" - "Symbols Nerd Font" - ]; - sansSerif = [ - "Noto Sans" - "Symbols Nerd Font" - ]; - }; - }; - # Browser - programs = { - firefox = { - enable = true; - profiles."${config.home.username}" = { - search = { - force = true; # firefox replaces the search settings, force replace them back - engines = - let - queryParam = name: value: { inherit name value; }; - in - { - # Add search.nixos.org as search engines - nix-packages = { - name = "Nix Packages"; - urls = [ - { - template = "https://search.nixos.org/packages"; - params = [ - (queryParam "type" "packages") - (queryParam "query" "{searchTerms}") - ]; - } - ]; - - icon = "${pkgs.nixos-icons}/share/icons/hicolor/scalable/apps/nix-snowflake.svg"; - definedAliases = [ - "@np" - "@nixpackages" - ]; - }; - - nixos-options = { - name = "NixOS Options"; - urls = [ - { - template = "https://search.nixos.org/options"; - params = [ - (queryParam "type" "packages") - (queryParam "query" "{searchTerms}") - ]; - } - ]; - - icon = "${pkgs.nixos-icons}/share/icons/hicolor/scalable/apps/nix-snowflake.svg"; - definedAliases = [ - "@no" - "@nixopts" - ]; - }; - - nixos-wiki = { - name = "NixOS Wiki"; - urls = [ - { - template = "https://wiki.nixos.org/w/index.php"; - params = [ (queryParam "search" "{searchTerms}") ]; - } - ]; - iconMapObj."16" = "https://wiki.nixos.org/favicon.ico"; - definedAliases = [ - "@nw" - "@nixwiki" - ]; - }; - - # hide bing - bing.metaData.hidden = true; - }; - }; - }; - }; - # Dynamic Menu - fuzzel = { - enable = true; - settings.main = lib.mkIf config.jhome.styling.enable { - inherit (cfg) terminal; - layer = "overlay"; - }; - }; - # Video player - mpv = { - enable = true; - scripts = builtins.attrValues { inherit (pkgs.mpvScripts) uosc thumbfast; }; - }; - # Text editor - nixvim.clipboard.providers.wl-copy.enable = lib.mkDefault true; - # Terminal - wezterm = { - enable = cfg.terminal == "wezterm"; - extraConfig = - lib.optionalString config.jhome.styling.enable # lua - '' - local wezterm = require("wezterm") - - local config = wezterm.config_builder() - - config.front_end = "WebGpu" - config.hide_tab_bar_if_only_one_tab = true - config.window_padding = { left = 1, right = 1, top = 1, bottom = 1 } - - return config - ''; - }; - alacritty = { - enable = cfg.terminal == "alacritty"; - settings = { - # hide mouse when typing, this ensures I don't have to move the mouse when it hides text - mouse.hide_when_typing = true; - # Start zellij when it is enabled - terminal.shell = lib.mkIf (config.jhome.dev.enable && config.programs.zellij.enable) { - program = "${lib.getExe config.programs.zellij.package}"; - }; - }; - }; - zellij = { - enable = cfg.terminal == "alacritty"; # alacritty has no terminal multiplexer built-in - # Set default shell - settings = { - show_startup_tips = false; # disable the startup tips dialogue - default_shell = - if config.programs.fish.enable then - "fish" - else if config.programs.zsh.enable then - "zsh" - else - "bash"; - }; - }; - # PDF reader - zathura.enable = true; - # Auto start sway - fish.loginShellInit = - lib.optionalString cfg.sway.autostart # fish - '' - # Start Sway on login to TTY 1 - if test "$(tty)" = /dev/tty1 - exec sway - end - ''; - }; - services = { - # Volume/Backlight control and notifications - avizo = { - enable = true; - settings.default = { - time = 0.8; - border-width = 0; - height = 176; - y-offset = 0.1; - block-spacing = 1; - }; - }; - # Sound tuning - easyeffects.enable = true; - # Auto configure displays - kanshi.enable = lib.mkDefault true; - # Notifications - mako = { - enable = true; - settings = { - layer = "overlay"; - border-radius = 8; - default-timeout = 15000; - }; - }; - }; - - stylix = lib.mkIf config.jhome.styling.enable { - # Set cursor style - inherit cursor; - targets.firefox.profileNames = [ config.home.username ]; - iconTheme = { - enable = true; - light = "Papirus-Light"; - dark = "Papirus-Dark"; - package = pkgs.papirus-icon-theme; - }; - }; - home.pointerCursor = lib.mkIf config.jhome.styling.enable ( - lib.mkDefault { - gtk.enable = true; - inherit (cursor) name package; - } - ); - # Set Gtk theme - gtk = lib.mkIf config.jhome.styling.enable { - enable = true; - gtk3.extraConfig.gtk-application-prefer-dark-theme = 1; - gtk4.extraConfig.gtk-application-prefer-dark-theme = 1; - }; - # Set Qt theme - qt = lib.mkIf config.jhome.styling.enable { enable = true; }; - - xdg.systemDirs.data = [ - "/usr/share" - "/var/lib/flatpak/exports/share" - "${config.xdg.dataHome}/flatpak/exports/share" - ]; - }; -} diff --git a/modules/hm/gui/sway.nix b/modules/hm/gui/sway.nix deleted file mode 100644 index 9c7a312..0000000 --- a/modules/hm/gui/sway.nix +++ /dev/null @@ -1,224 +0,0 @@ -{ - config, - pkgs, - lib, - ... -}: -let - cfg = config.jhome.gui.sway; -in -{ - config = lib.mkIf (config.jhome.enable && config.jhome.gui.enable && cfg.enable) { - # Window Manager - wayland.windowManager.sway = { - inherit (cfg) enable; - config = - let - inherit (config.jhome.gui) terminal; - termCmd = - if terminal == "wezterm" then - "wezterm start" - else if terminal == "alacritty" then - "alacritty -e" - else - builtins.abort "no command configured for ${terminal}"; - menu = "${pkgs.fuzzel}/bin/fuzzel --terminal '${termCmd}'"; - cmdOnce = command: { inherit command; }; - cmdAlways = command: { - inherit command; - always = true; - }; - in - { - modifier = "Mod4"; - inherit terminal menu; - # Appearance - bars = [ ]; # Waybar is started as a systemd service - gaps = { - smartGaps = true; - smartBorders = "on"; - inner = 4; - }; - output."*".bg = "${cfg.background} fill"; - # Window Appearance - window = { - border = 2; - titlebar = false; - # Make certain windows floating - commands = [ - { - command = "floating enable"; - criteria.title = "zoom"; - } - { - command = "floating enable"; - criteria.class = "floating"; - } - { - command = "floating enable"; - criteria.app_id = "floating"; - } - ]; - }; - # Startup scripts - startup = - let - # currently, there is some friction between sway and gtk: - # https://github.com/swaywm/sway/wiki/GTK-3-settings-on-Wayland - # the suggested way to set gtk settings is with gsettings - # for gsettings to work, we need to tell it where the schemas are - # using the XDG_DATA_DIR environment variable - # run at the end of sway config - schema = pkgs.gsettings-desktop-schemas; - datadir = "${schema}/share/gsettings-schemas/${schema.name}"; - in - [ - (cmdAlways "${pkgs.writers.writeDash "configure-gtk" '' - export XDG_DATA_DIRS="${datadir}:$XDG_DATA_DIRS" - - gnome_schema=org.gnome.desktop.interface - config="${config.xdg.configHome}/gtk-3.0/settings.ini" - if [ ! -f "$config" ]; then exit 1; fi - # Read settings from gtk3 - gtk_theme="$(${pkgs.gnugrep}/bin/grep 'gtk-theme-name' "$config" | ${pkgs.gnused}/bin/sed 's/.*\s*=\s*//')" - icon_theme="$(${pkgs.gnugrep}/bin/grep 'gtk-icon-theme-name' "$config" | ${pkgs.gnused}/bin/sed 's/.*\s*=\s*//')" - cursor_theme="$(${pkgs.gnugrep}/bin/grep 'gtk-cursor-theme-name' "$config" | ${pkgs.gnused}/bin/sed 's/.*\s*=\s*//')" - font_name="$(grep 'gtk-font-name' "$config" | sed 's/.*\s*=\s*//')" - ${pkgs.glib}/bin/gsettings set "$gnome_schema" gtk-theme "$gtk_theme" - ${pkgs.glib}/bin/gsettings set "$gnome_schema" icon-theme "$icon_theme" - ${pkgs.glib}/bin/gsettings set "$gnome_schema" cursor-theme "$cursor_theme" - ${pkgs.glib}/bin/gsettings set "$gnome_schema" font-name "$font_name" - ${pkgs.glib}/bin/gsettings set "$gnome_schema" color-scheme prefer-dark - ''}") - ] - ++ (builtins.map cmdAlways cfg.exec.always) - ++ (builtins.map cmdOnce cfg.exec.once); - # Keyboard configuration - input."type:keyboard" = { - repeat_delay = "300"; - repeat_rate = "50"; - }; - # Touchpad - input."type:touchpad" = { - click_method = "clickfinger"; - natural_scroll = "enabled"; - scroll_method = "two_finger"; - tap = "enabled"; - tap_button_map = "lrm"; - }; - # Keybinds - keybindings = - let - passmenu = "${pkgs.jpassmenu}/bin/jpassmenu"; - selectAudio = "${pkgs.audiomenu}/bin/audiomenu"; - swayconf = config.wayland.windowManager.sway.config; - mod = swayconf.modifier; - workspaces = map toString (lib.lists.range 1 9); - dirs = - map - (dir: { - key = swayconf.${dir}; - arrow = dir; - direction = dir; - }) - [ - "up" - "down" - "left" - "right" - ]; - joinKeys = builtins.concatStringsSep "+"; - # Generate a keybind from a modifier prefix and a key - keycombo = prefix: key: joinKeys (prefix ++ [ key ]); - modKeybind = keycombo [ mod ]; - modCtrlKeybind = keycombo [ - mod - "Ctrl" - ]; - modShiftKeybind = keycombo [ - mod - "Shift" - ]; - modCtrlShiftKeybind = keycombo [ - mod - "Ctrl" - "Shift" - ]; - dir2resize.up = "resize grow height"; - dir2resize.down = "resize shrink height"; - dir2resize.right = "resize grow width"; - dir2resize.left = "resize shrink width"; - # Bind a key combo to an action - genKeybind = prefix: action: key: { "${prefix key}" = "${action key}"; }; - genKey = - prefix: action: genKeybind ({ key, ... }: prefix key) ({ direction, ... }: action direction); - genArrow = - prefix: action: genKeybind ({ arrow, ... }: prefix arrow) ({ direction, ... }: action direction); - genArrowAndKey = - prefix: action: key: - (genKey prefix action key) // (genArrow prefix action key); - # Move window - moveWindowKeybinds = map (genArrowAndKey modShiftKeybind (dir: "move ${dir}")) dirs; - # Focus window - focusWindowKeybinds = map (genArrowAndKey modKeybind (dir: "focus ${dir}")) dirs; - # Resize window - resizeWindowKeybinds = map (genArrowAndKey modCtrlKeybind (dir: dir2resize.${dir})) dirs; - # Move container to workspace - moveWorkspaceKeybindings = map (genKeybind modShiftKeybind ( - number: "move container to workspace number ${number}" - )) workspaces; - # Focus workspace - focusWorkspaceKeybindings = map (genKeybind modKeybind ( - number: "workspace number ${number}" - )) workspaces; - # Move container to Workspace and focus on it - moveFocusWorkspaceKeybindings = map (genKeybind modCtrlShiftKeybind ( - number: "move container to workspace number ${number}; workspace number ${number}" - )) workspaces; - in - builtins.foldl' (l: r: l // r) - { - "${mod}+Return" = "exec ${swayconf.terminal}"; - "${mod}+D" = "exec ${swayconf.menu}"; - "${mod}+P" = "exec ${passmenu}"; - "${mod}+Shift+P" = "exec ${passmenu} --type"; - "${mod}+F2" = "exec qutebrowser"; - "${mod}+Shift+Q" = "kill"; - "${mod}+F" = "fullscreen toggle"; - # Media Controls - "${mod}+F10" = "exec ${selectAudio} select-sink"; - "${mod}+Shift+F10" = "exec ${selectAudio} select-source"; - "XF86AudioRaiseVolume" = "exec ${pkgs.avizo}/bin/volumectl up"; - "XF86AudioLowerVolume" = "exec ${pkgs.avizo}/bin/volumectl down"; - "XF86AudioMute" = "exec ${pkgs.avizo}/bin/volumectl toggle-mute"; - "XF86ScreenSaver" = "exec ${pkgs.swaylock}/bin/swaylock --image ${cfg.background}"; - "XF86MonBrightnessUp" = "exec ${pkgs.avizo}/bin/lightctl up"; - "XF86MonBrightnessDown" = "exec ${pkgs.avizo}/bin/lightctl down"; - # Floating - "${mod}+Space" = "floating toggle"; - "${mod}+Shift+Space" = "focus mode_toggle"; - # Scratchpad - "${mod}+Minus" = "scratchpad show"; - "${mod}+Shift+Minus" = "move scratchpad"; - # Layout - "${mod}+e" = "layout toggle split"; - # Session control - "${mod}+r" = "reload"; - "${mod}+Shift+m" = "exit"; - } - ( - focusWindowKeybinds - ++ moveWindowKeybinds - ++ resizeWindowKeybinds - ++ focusWorkspaceKeybindings - ++ moveWorkspaceKeybindings - ++ moveFocusWorkspaceKeybindings - ); - }; - systemd = { - enable = true; - xdgAutostart = true; - }; - }; - }; -} diff --git a/modules/hm/gui/waybar.nix b/modules/hm/gui/waybar.nix deleted file mode 100644 index eefdab4..0000000 --- a/modules/hm/gui/waybar.nix +++ /dev/null @@ -1,159 +0,0 @@ -{ - config, - pkgs, - lib, - ... -}: -let - inherit (config) jhome; - cfg = jhome.gui; - swayconf = config.wayland.windowManager.sway; -in -{ - config = lib.mkIf (config.jhome.enable && cfg.enable) { - # Status bar - programs.waybar = { - enable = true; - systemd.enable = true; - settings = lib.mkIf config.jhome.styling.enable { - mainBar = { - layer = "top"; - position = "top"; - margin = "2 2 2 2"; - # Choose the order of the modules - modules-left = [ "sway/workspaces" ]; - modules-center = [ "clock" ]; - modules-right = - [ - "pulseaudio" - "backlight" - "battery" - "sway/language" - "memory" - ] - ++ lib.optional (cfg.tempInfo != null) "temperature" - ++ [ "tray" ]; - "sway/workspaces" = lib.mkIf swayconf.enable { - disable-scroll = true; - persistent-workspaces = { - "1" = [ ]; - "2" = [ ]; - "3" = [ ]; - "4" = [ ]; - "5" = [ ]; - "6" = [ ]; - "7" = [ ]; - "8" = [ ]; - "9" = [ ]; - }; - }; - "sway/language" = lib.mkIf swayconf.enable { - format = "{} "; - min-length = 5; - tooltip = false; - }; - memory = { - format = "{used:0.1f}/{total:0.1f}GiB "; - interval = 3; - }; - clock = { - timezone = "Europe/Berlin"; - tooltip-format = "{:%Y %B}\n{calendar}"; - format = "{:%a, %d %b, %H:%M}"; - }; - wireplumber = { - reverse-scrolling = 1; - format = "{volume}% {icon} {format_source}"; - format-bluetooth = "{volume}% {icon} {format_source}"; - format-bluetooth-muted = "{volume}% 󰖁 {icon} {format_source}"; - format-muted = "{volume}% 󰖁 {format_source}"; - format-source = "{volume}% "; - format-source-muted = "{volume}% 󰍭"; - format-icons = { - headphone = "󰋋"; - hands-free = ""; - headset = "󰋎"; - phone = "󰘂"; - portable = ""; - car = ""; - default = [ - "󰕿" - "󰖀" - "󰕾" - ]; - }; - on-click = lib.getExe pkgs.helvum; - min-length = 13; - }; - temperature = lib.optionalAttrs (cfg.tempInfo != null) { - inherit (cfg.tempInfo) hwmon-path; - critical-threshold = 80; - format = "{temperatureC}°C {icon}"; - format-icons = [ - "" - "" - "" - "" - "" - ]; - tooltip = false; - }; - backlight = { - device = "intel_backlight"; - format = "{percent}% {icon}"; - format-icons = [ - "󰃚" - "󰃛" - "󰃜" - "󰃝" - "󰃞" - "󰃟" - "󰃠" - ]; - min-length = 7; - }; - battery = { - states.warning = 30; - states.critical = 15; - format = "{capacity}% {icon}"; - format-charging = "{capacity}% 󰂄"; - format-plugged = "{capacity}% 󰚥"; - format-alt = "{time} {icon}"; - format-icons = [ - "󰁺" - "󰁻" - "󰁼" - "󰁽" - "󰁾" - "󰁿" - "󰂀" - "󰂁" - "󰂂" - "󰁹" - ]; - }; - tray = { - icon-size = 16; - spacing = 0; - }; - }; - }; - # Style overrides to highlight workspaces with windows - style = - lib.pipe - # css - '' - .modules-left #workspaces button { - border-bottom: 3px solid @base01; - } - .modules-left #workspaces button.persistent { - border-bottom: 3px solid transparent; - } - '' - [ - (lib.optionalString config.jhome.styling.enable) - lib.mkAfter - ]; - }; - }; -} diff --git a/modules/lib.nix b/modules/lib.nix deleted file mode 100644 index 3e3a288..0000000 --- a/modules/lib.nix +++ /dev/null @@ -1,27 +0,0 @@ -{ lib }: -let - inherit (lib) types; -in -{ - # Like mkEnableOption but defaults to true - mkDisableOption = - option: - (lib.mkEnableOption option) - // { - default = true; - example = false; - }; - # A option that accepts an image (and shows it in the docs) - mkImageOption = - { - description, - url, - sha256 ? "", - }: - lib.mkOption { - inherit description; - type = types.path; - default = builtins.fetchurl { inherit url sha256; }; - defaultText = lib.literalMD "![${description}](${url})"; - }; -} diff --git a/modules/nixos/default.nix b/modules/nixos/default.nix deleted file mode 100644 index e2e4370..0000000 --- a/modules/nixos/default.nix +++ /dev/null @@ -1,76 +0,0 @@ -{ pkgs, lib, ... }@args: -let - cfg = args.config.jconfig; - keysFromGithub = lib.attrsets.mapAttrs' (username: sha256: { - name = "pubkeys/${username}"; - value = { - mode = "0755"; - source = builtins.fetchurl { - inherit sha256; - url = "https://github.com/${username}.keys"; - }; - }; - }) cfg.importSSHKeysFromGithub; -in -{ - imports = [ - ./options.nix - ./dev.nix - ./gui.nix - ./starship.nix - ./styling.nix - ]; - - config = lib.mkIf cfg.enable { - # Enable unlocking the gpg-agent at boot (configured through home.nix) - security.pam.services.login.gnupg.enable = true; - - environment.systemPackages = [ - # CLI tools - pkgs.fd - pkgs.ripgrep - pkgs.du-dust - pkgs.curl - pkgs.zip - pkgs.unzip - ]; - - programs.fish.enable = true; - - environment.etc = keysFromGithub; - services = { - # Enable printer autodiscovery if printing is enabled - avahi = { - inherit (args.config.services.printing) enable; - nssmdns4 = true; - openFirewall = true; - }; - openssh.authorizedKeysFiles = builtins.map (keys: "/etc/${keys}") ( - builtins.attrNames keysFromGithub - ); - }; - # Open ports for spotifyd - networking.firewall = { - allowedUDPPorts = [ 5353 ]; - allowedTCPPorts = [ 2020 ]; - }; - # Nix Settings - nix = { - gc = { - automatic = true; - dates = "weekly"; - options = "--delete-older-than 30d"; - # run between 0 and 45min after boot if run was missed - randomizedDelaySec = "45min"; - }; - settings = { - use-xdg-base-directories = true; - auto-optimise-store = true; - experimental-features = [ - "nix-command" - "flakes" - ]; - }; - }; - }; -} diff --git a/modules/nixos/dev.nix b/modules/nixos/dev.nix deleted file mode 100644 index b4aee84..0000000 --- a/modules/nixos/dev.nix +++ /dev/null @@ -1,18 +0,0 @@ -{ lib, config, ... }: -let - cfg = config.jconfig.dev; -in -{ - config = lib.mkIf (config.jconfig.enable && cfg.enable) { - # Enable dev documentation - documentation.dev = { inherit (cfg) enable; }; - - users.extraUsers = lib.mkIf cfg.jupyter.enable { jupyter.group = "jupyter"; }; - - services.jupyter = { - inherit (cfg.jupyter) enable; - group = "jupyter"; - user = "jupyter"; - }; - }; -} diff --git a/modules/nixos/gui.nix b/modules/nixos/gui.nix deleted file mode 100644 index d07f706..0000000 --- a/modules/nixos/gui.nix +++ /dev/null @@ -1,117 +0,0 @@ -{ lib, pkgs, ... }@args: -let - cfg = args.config.jconfig.gui; - enable = args.config.jconfig.enable && cfg.enable; - linuxOlderThan6_3 = lib.versionOlder args.config.boot.kernelPackages.kernel.version "6.3"; -in -{ - config = - lib.flip lib.pipe - [ lib.mkMerge (lib.mkIf enable) ] - [ - { - environment.systemPackages = [ - pkgs.adwaita-icon-theme - pkgs.adwaita-qt - pkgs.nordzy-cursor-theme - pkgs.pinentry-qt - ]; - # Fix xdg-portals issue issue: https://github.com/NixOS/nixpkgs/issues/189851 - systemd.user.extraConfig = '' - DefaultEnvironment="PATH=/run/wrappers/bin:/etc/profiles/per-user/%u/bin:/nix/var/nix/profiles/default/bin:/run/current-system/sw/bin" - ''; - - fonts.fontDir.enable = true; - programs = { - dconf.enable = true; - sway = { - enable = cfg.sway; - # No extra packages (by default it adds foot, dmenu, and other stuff) - extraPackages = [ ]; - wrapperFeatures = { - base = true; - gtk = true; - }; - }; - }; - security = { - polkit.enable = true; - rtkit.enable = true; # Recommended for pipewire - }; - services = { - flatpak.enable = true; - # Audio - pipewire = { - enable = true; - alsa = { - enable = true; - support32Bit = true; - }; - pulse.enable = true; - wireplumber.enable = true; - }; - # Dbus - dbus.enable = true; - # Virtual Filesystem (for PCManFM) - gvfs.enable = true; - }; - xdg.portal = { - # XDG portals - enable = true; - wlr.enable = true; - extraPortals = [ pkgs.xdg-desktop-portal-gtk ]; - config.preferred = { - # Default to the gtk portal - default = "gtk"; - # Use wlr for screenshots and screen recording - "org.freedesktop.impl.portal.Screenshot" = "wlr"; - }; - # Consider using darkman like upstream - }; - hardware = { - graphics.enable = true; - uinput.enable = true; - steam-hardware.enable = cfg.steamHardwareSupport; - }; - } - (lib.mkIf cfg.ydotool.enable { - environment.systemPackages = [ pkgs.ydotool ]; - systemd.user.services.ydotool = { - enable = cfg.ydotool.autoStart; - wantedBy = [ "default.target" ]; - description = "Generic command-line automation tool"; - documentation = [ - "man:ydotool(1)" - "man:ydotoold(8)" - ]; - serviceConfig = { - Type = "simple"; - Restart = "always"; - ExecStart = "${pkgs.ydotool}/bin/ydotoold"; - ExecReload = "${pkgs.util-linux}/bin/kill -HUP $MAINPID"; - KillMode = "process"; - TimeoutSec = 180; - }; - }; - }) - (lib.mkIf (linuxOlderThan6_3 && cfg."8bitdoFix") { - # Udev rules to start or stop systemd service when controller is connected or disconnected - services.udev.extraRules = # udev - '' - # May vary depending on your controller model, find product id using 'lsusb' - SUBSYSTEM=="usb", ATTR{idVendor}=="2dc8", ATTR{idProduct}=="3106", ATTR{manufacturer}=="8BitDo", RUN+="${pkgs.systemd}/bin/systemctl start 8bitdo-ultimate-xinput@2dc8:3106" - # This device (2dc8:3016) is "connected" when the above device disconnects - SUBSYSTEM=="usb", ATTR{idVendor}=="2dc8", ATTR{idProduct}=="3016", ATTR{manufacturer}=="8BitDo", RUN+="${pkgs.systemd}/bin/systemctl stop 8bitdo-ultimate-xinput@2dc8:3106" - ''; - - # Systemd service which starts xboxdrv in xbox360 mode - systemd.services."8bitdo-ultimate-xinput@" = { - unitConfig.Description = "8BitDo Ultimate Controller XInput mode xboxdrv daemon"; - serviceConfig = { - Type = "simple"; - ExecStart = "${pkgs.xboxdrv}/bin/xboxdrv --mimic-xpad --silent --type xbox360 --device-by-id %I --force-feedback"; - }; - }; - }) - ]; -} diff --git a/modules/nixos/options.nix b/modules/nixos/options.nix deleted file mode 100644 index d8b4e64..0000000 --- a/modules/nixos/options.nix +++ /dev/null @@ -1,95 +0,0 @@ -{ lib, ... }: -let - inherit (lib) types; - inherit (import ../lib.nix { inherit lib; }) - mkDisableOption - mkImageOption - ; -in -{ - options.jconfig = lib.mkOption { - description = "Jalil's default NixOS configuration."; - default = { }; - type = types.submodule { - options = { - enable = lib.mkEnableOption "jalil's default configuration."; - importSSHKeysFromGithub = lib.mkOption { - description = '' - Import public ssh keys from a github username. - - This will fetch the keys from https://github.com/$${username}.keys. - - The format is `"$${github-username}" = $${sha256-hash}`. The example - will try to fetch the keys from . - - **Warning**: this will interfere with services like gitea that override - the default ssh behaviour. In that case you want to use - `users.users..openssh.authorizedKeys.keyFiles` on the users you - want to allow ssh logins. - ''; - default = { }; - example = { - "jalil-salame" = "sha256:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; - }; - type = types.attrsOf types.str; - }; - - dev = lib.mkOption { - description = "Options for setting up a dev environment"; - default = { }; - type = types.submodule { - options = { - enable = lib.mkEnableOption "dev configuration"; - jupyter.enable = lib.mkEnableOption "jupyter configuration"; - }; - }; - }; - - gui = lib.mkOption { - description = "Jalil's default configuration for a NixOS gui."; - default = { }; - type = types.submodule { - options = { - enable = lib.mkEnableOption "jalil's default gui configuration."; - # Fix for using Xinput mode on 8bitdo Ultimate C controller - # Inspired by https://aur.archlinux.org/packages/8bitdo-ultimate-controller-udev - # Adapted from: https://gist.github.com/interdependence/28452fbfbe692986934fbe1e54c920d4 - "8bitdoFix" = mkDisableOption "a fix for 8bitdo controllers"; - steamHardwareSupport = mkDisableOption "steam hardware support"; - ydotool = lib.mkOption { - description = "Jalil's default ydotool configuration."; - default = { }; - type = types.submodule { - options.enable = mkDisableOption "ydotool"; - options.autoStart = mkDisableOption "autostarting ydotool at login"; - }; - }; - sway = mkDisableOption "sway"; - }; - }; - }; - - styling = lib.mkOption { - description = "Jalil's styling options"; - default = { }; - type = types.submodule { - options = { - enable = mkDisableOption "jalil's default styling (disables stylix)"; - wallpaper = mkImageOption { - description = "The wallpaper to use."; - url = "https://raw.githubusercontent.com/lunik1/nixos-logo-gruvbox-wallpaper/d4937c424fad79c1136a904599ba689fcf8d0fad/png/gruvbox-dark-rainbow.png"; - sha256 = "036gqhbf6s5ddgvfbgn6iqbzgizssyf7820m5815b2gd748jw8zc"; - }; - bootLogo = mkImageOption { - description = "The logo used by plymouth at boot."; - # http://xenia-linux-site.glitch.me/images/cathodegaytube-splash.png - url = "https://efimero.github.io/xenia-images/cathodegaytube-splash.png"; - sha256 = "qKugUfdRNvMwSNah+YmMepY3Nj6mWlKFh7jlGlAQDo8="; - }; - }; - }; - }; - }; - }; - }; -} diff --git a/modules/nixos/starship.nix b/modules/nixos/starship.nix deleted file mode 100644 index 3ab8d8b..0000000 --- a/modules/nixos/starship.nix +++ /dev/null @@ -1,183 +0,0 @@ -{ pkgs, lib, ... }@args: -let - cfg = args.config.jconfig; -in -{ - config = lib.mkIf cfg.enable { - programs.starship = { - enable = true; - settings = lib.mkMerge [ - { - format = "$time$all"; - add_newline = false; - cmd_duration.min_time = 500; - cmd_duration.show_milliseconds = true; - time.disabled = false; - status = { - format = "[$signal_name$common_meaning$maybe_int](red)"; - symbol = "[✗](bold red)"; - disabled = false; - }; - sudo.disabled = false; - } - # Add nerdfont symbols - (lib.mkIf cfg.styling.enable { - aws.symbol = " "; - buf.symbol = " "; - c.symbol = " "; - conda.symbol = " "; - crystal.symbol = " "; - dart.symbol = " "; - directory.read_only = " 󰌾"; - docker_context.symbol = " "; - elixir.symbol = " "; - elm.symbol = " "; - fennel.symbol = " "; - fossil_branch.symbol = " "; - git_branch.symbol = " "; - git_commit.tag_symbol = "  "; - golang.symbol = " "; - gradle.symbol = " "; - guix_shell.symbol = " "; - haskell.symbol = " "; - haxe.symbol = " "; - hg_branch.symbol = " "; - hostname.ssh_symbol = " "; - java.symbol = " "; - julia.symbol = " "; - kotlin.symbol = " "; - lua.symbol = " "; - memory_usage.symbol = "󰍛 "; - meson.symbol = "󰔷 "; - nim.symbol = "󰆥 "; - nix_shell.symbol = " "; - nodejs.symbol = " "; - ocaml.symbol = " "; - package.symbol = "󰏗 "; - perl.symbol = " "; - php.symbol = " "; - pijul_channel.symbol = " "; - python.symbol = " "; - rlang.symbol = "󰟔 "; - ruby.symbol = " "; - rust.symbol = "󱘗 "; - scala.symbol = " "; - swift.symbol = " "; - zig.symbol = " "; - os.symbols = { - Alpaquita = " "; - Alpine = " "; - AlmaLinux = " "; - Amazon = " "; - Android = " "; - Arch = " "; - Artix = " "; - CentOS = " "; - Debian = " "; - DragonFly = " "; - Emscripten = " "; - EndeavourOS = " "; - Fedora = " "; - FreeBSD = " "; - Garuda = "󰛓 "; - Gentoo = " "; - HardenedBSD = "󰞌 "; - Illumos = "󰈸 "; - Kali = " "; - Linux = " "; - Mabox = " "; - Macos = " "; - Manjaro = " "; - Mariner = " "; - MidnightBSD = " "; - Mint = " "; - NetBSD = " "; - NixOS = " "; - OpenBSD = "󰈺 "; - openSUSE = " "; - OracleLinux = "󰌷 "; - Pop = " "; - Raspbian = " "; - Redhat = " "; - RedHatEnterprise = " "; - RockyLinux = " "; - Redox = "󰀘 "; - Solus = "󰠳 "; - SUSE = " "; - Ubuntu = " "; - Unknown = " "; - Void = " "; - Windows = "󰍲 "; - }; - }) - # Remove the `in`s and `on`s from the prompt - { - aws.format = "[$symbol($profile)(\\($region\\))(\\[$duration\\])]($style) "; - bun.format = "[$symbol($version)]($style) "; - c.format = "[$symbol($version(-$name))]($style) "; - cmake.format = "[$symbol($version)]($style) "; - cmd_duration.format = "[⏱ $duration]($style) "; - cobol.format = "[$symbol($version)]($style) "; - conda.format = "[$symbol$environment]($style) "; - crystal.format = "[$symbol($version)]($style) "; - daml.format = "[$symbol($version)]($style) "; - dart.format = "[$symbol($version)]($style) "; - deno.format = "[$symbol($version)]($style) "; - docker_context.format = "[$symbol$context]($style) "; - dotnet.format = "[$symbol($version)(🎯 $tfm)]($style) "; - elixir.format = "[$symbol($version \\(OTP $otp_version\\))]($style) "; - elm.format = "[$symbol($version)]($style) "; - erlang.format = "[$symbol($version)]($style) "; - fennel.format = "[$symbol($version)]($style) "; - fossil_branch.format = "[$symbol$branch]($style) "; - gcloud.format = "[$symbol$account(@$domain)(\\($region\\))]($style) "; - git_branch.format = "[$symbol$branch]($style) "; - git_status.format = "[$all_status$ahead_behind]($style) "; - golang.format = "[$symbol($version)]($style) "; - gradle.format = "[$symbol($version)]($style) "; - guix_shell.format = "[$symbol]($style) "; - haskell.format = "[$symbol($version)]($style) "; - haxe.format = "[$symbol($version)]($style) "; - helm.format = "[$symbol($version)]($style) "; - hg_branch.format = "[$symbol$branch]($style) "; - java.format = "[$symbol($version)]($style) "; - julia.format = "[$symbol($version)]($style) "; - kotlin.format = "[$symbol($version)]($style) "; - kubernetes.format = "[$symbol$context( \\($namespace\\))]($style) "; - lua.format = "[$symbol($version)]($style) "; - memory_usage.format = "$symbol[$ram( | $swap)]($style) "; - meson.format = "[$symbol$project]($style) "; - nim.format = "[$symbol($version)]($style) "; - nix_shell.format = "[$symbol$state( \\($name\\))]($style) "; - nodejs.format = "[$symbol($version)]($style) "; - ocaml.format = "[$symbol($version)(\\($switch_indicator$switch_name\\))]($style) "; - opa.format = "[$symbol($version)]($style) "; - openstack.format = "[$symbol$cloud(\\($project\\))]($style) "; - os.format = "[$symbol]($style) "; - package.format = "[$symbol$version]($style) "; - perl.format = "[$symbol($version)]($style) "; - php.format = "[$symbol($version)]($style) "; - pijul_channel.format = "[$symbol$channel]($style) "; - pulumi.format = "[$symbol$stack]($style) "; - purescript.format = "[$symbol($version)]($style) "; - python.format = "[\${symbol}\${pyenv_prefix}(\${version})(\\($virtualenv\\))]($style) "; - raku.format = "[$symbol($version-$vm_version)]($style) "; - red.format = "[$symbol($version)]($style) "; - ruby.format = "[$symbol($version)]($style) "; - rust.format = "[$symbol($version)]($style) "; - scala.format = "[$symbol($version)]($style) "; - spack.format = "[$symbol$environment]($style) "; - sudo.format = "[as $symbol]($style) "; - swift.format = "[$symbol($version)]($style) "; - terraform.format = "[$symbol$workspace]($style) "; - time.format = "[$time]($style) "; - username.format = "[$user]($style) "; - vagrant.format = "[$symbol($version)]($style) "; - vlang.format = "[$symbol($version)]($style) "; - zig.format = "[$symbol($version)]($style) "; - solidity.format = "[$symbol($version)]($style) "; - } - ]; - }; - }; -} diff --git a/modules/nixos/styling.nix b/modules/nixos/styling.nix deleted file mode 100644 index b20a2d7..0000000 --- a/modules/nixos/styling.nix +++ /dev/null @@ -1,43 +0,0 @@ -{ lib, pkgs, ... }@args: -let - cfg = args.config.jconfig.styling; - enable = args.config.jconfig.enable && cfg.enable; -in -{ - config = lib.mkIf enable { - boot.plymouth = { inherit (cfg) enable; }; - - stylix = { - inherit (cfg) enable; - image = cfg.wallpaper; - base16Scheme = "${pkgs.base16-schemes}/share/themes/gruvbox-dark-hard.yaml"; - polarity = "dark"; - fonts = { - monospace = { - name = "JetBrains Mono"; - package = pkgs.jetbrains-mono; - }; - sansSerif = { - name = "Noto Sans"; - package = pkgs.noto-fonts; - }; - serif = { - name = "Noto Serif"; - package = pkgs.noto-fonts; - }; - emoji = { - package = pkgs.noto-fonts-emoji; - name = "Noto Color Emoji"; - }; - sizes.popups = 12; - }; - targets = { - plymouth = { - logoAnimated = false; - logo = cfg.bootLogo; - }; - nixvim.enable = false; - }; - }; - }; -} diff --git a/modules/nixvim/plugins.nix b/modules/nixvim/plugins.nix deleted file mode 100644 index 8943c56..0000000 --- a/modules/nixvim/plugins.nix +++ /dev/null @@ -1,151 +0,0 @@ -{ lib, helpers, ... }: -let - inherit (helpers) mkRaw; -in -{ - config.plugins = { - cmp = - let - srcWithIndex = groupIndex: name: { inherit name groupIndex; }; - in - { - enable = true; - cmdline = { - "/" = { - mapping = - mkRaw - # lua - '' - cmp.mapping.preset.cmdline() - ''; - sources = [ - { name = "rg"; } - { name = "buffer"; } - ]; - }; - ":" = { - mapping = - mkRaw - # lua - "cmp.mapping.preset.cmdline()"; - sources = [ - { name = "path"; } - { name = "cmdline"; } - ]; - }; - }; - settings = { - # Snippets - snippet.expand = - # lua - "function(args) require('luasnip').lsp_expand(args.body) end"; - # Completion Sources - sources = [ - # very specific (not noisy) - (srcWithIndex 1 "calc") - (srcWithIndex 1 "crates") - (srcWithIndex 1 "fish") - (srcWithIndex 1 "luasnip") - (srcWithIndex 1 "nvim_lsp") - # Generally ok - (srcWithIndex 2 "conventionalcommits") - (srcWithIndex 2 "nvim_lsp_document_symbol") - (srcWithIndex 2 "nvim_lsp_signature_help") - # Noisy - (srcWithIndex 2 "path") - (srcWithIndex 3 "spell") - (srcWithIndex 3 "treesitter") - # Very noisy - (srcWithIndex 4 "buffer") - ]; - mapping = - mkRaw - # lua - '' - cmp.mapping.preset.insert({ - [""] = function(fallback) - if cmp.visible() then - cmp.select_next_item() - elseif require("luasnip").expand_or_jumpable() then - require("luasnip").expand_or_jump() - elseif has_words_before() then - cmp.complete() - else - fallback() - end - end, - [""] = function(fallback) - if cmp.visible() then - cmp.select_prev_item() - elseif require("luasnip").jumpable(-1) then - require("luasnip").jump(-1) - else - fallback() - end - end, - [""] = cmp.mapping(function(fallback) - if require("luasnip").choice_active() then - require("luasnip").next_choice() - else - fallback() - end - end), - [""] = cmp.mapping.scroll_docs(-4), - [""] = cmp.mapping.scroll_docs(4), - [""] = cmp.mapping.complete { }, - [""] = cmp.mapping.close(), - [""] = cmp.mapping.confirm { select = true }, - }) - ''; - }; - }; - cmp-fish.enable = true; - gitsigns.enable = true; - lualine = { - enable = true; - settings.options.theme = lib.mkForce "gruvbox"; - }; - luasnip = { - enable = true; - settings.update_events = "TextChanged,TextChangedI"; - }; - noice = { - enable = true; - settings = { - lsp.override = { - "vim.lsp.util.convert_input_to_markdown_lines" = true; - "vim.lsp.util.stylize_markdown" = true; - "cmp.entry.get_documentation" = true; - }; - presets = { - # use a classic bottom cmdline for search - bottom_search = true; - # position the cmdline and popupmenu together - command_palette = false; - # long messages will be sent to a split - long_message_to_split = true; - # enables an input dialog for inc-rename.nvim - inc_rename = false; - # add a border to hover docs and signature help - lsp_doc_border = true; - }; - }; - }; - notify = { - enable = true; - settings.background_colour = "#000000"; - }; - telescope = { - enable = true; - extensions = { - ui-select.enable = true; - fzy-native.enable = true; - }; - }; - trouble = { - enable = true; - settings.auto_close = true; - }; - web-devicons.enable = true; - }; -} diff --git a/modules/nixvim/augroups.nix b/nvim/augroups.nix similarity index 100% rename from modules/nixvim/augroups.nix rename to nvim/augroups.nix diff --git a/modules/nixvim/default.nix b/nvim/default.nix similarity index 78% rename from modules/nixvim/default.nix rename to nvim/default.nix index 6152af6..afe1a05 100644 --- a/modules/nixvim/default.nix +++ b/nvim/default.nix @@ -6,9 +6,10 @@ in imports = [ ./options.nix ]; config.programs.nixvim = lib.mkMerge [ - ./standalone.nix + (import ./standalone.nix) (lib.mkIf cfg.enable { enable = true; + nixpkgs.useGlobalPackages = true; defaultEditor = lib.mkDefault true; jhome.nvim = cfg; }) diff --git a/modules/nixvim/dev-plugins.nix b/nvim/dev-plugins.nix similarity index 65% rename from modules/nixvim/dev-plugins.nix rename to nvim/dev-plugins.nix index d7c0a21..7659912 100644 --- a/modules/nixvim/dev-plugins.nix +++ b/nvim/dev-plugins.nix @@ -7,13 +7,11 @@ }: let inherit (helpers) enableExceptInTests; - inherit (lib.trivial) const; cfg = config.jhome.nvim; enabledLSPs = [ "basedpyright" "bashls" "clangd" - "gopls" # "html" # Not writing html "jsonls" "marksman" @@ -23,20 +21,22 @@ let "typos_lsp" # "typst_lsp" # Not using it "zls" - "fish_lsp" ]; - - enableOpt.enable = true; - noPackage.package = null; in { config = lib.mkIf cfg.dev.enable ( lib.mkMerge [ # Enable LSPs - { plugins.lsp.servers = lib.genAttrs enabledLSPs (const enableOpt); } + { + plugins.lsp.servers = lib.genAttrs enabledLSPs (_: { + enable = true; + }); + } # Remove bundled LSPs (lib.mkIf (!cfg.dev.bundleLSPs) { - plugins.lsp.servers = lib.genAttrs enabledLSPs (const noPackage); + plugins.lsp.servers = lib.genAttrs enabledLSPs (_: { + package = null; + }); }) # Configure LSPs { @@ -45,20 +45,17 @@ in enable = true; servers = { # Pyright needs to have the project root set? - basedpyright.rootMarkers = [ - "flake.nix" - ".git" - ".jj" - "pyproject.toml" - "setup.py" - ]; - # Big but infrequently used dependencies. - # - # Configure the LSPs, but don't install the packages. - # If you need to use them, add them to your project's devShell - clangd = noPackage; - gopls = noPackage; - zls = noPackage; + basedpyright.rootDir = # lua + '' + function() + return vim.fs.root(0, {'flake.nix', '.git', '.jj', 'pyproject.toml', 'setup.py'}) + end + ''; + bashls.package = lib.mkDefault pkgs.bash-language-server; + # Adds ~2 GiB, install in a devShell instead + clangd.package = lib.mkDefault null; + # zls & other zig tools are big, install in a devShell instead + zls.package = lib.mkDefault null; }; }; lspkind = { @@ -84,26 +81,25 @@ in (lib.mkIf (!cfg.dev.bundleGrammars) { plugins.treesitter.grammarPackages = [ ]; }) # Remove tools for building gramars when bundling them (lib.mkIf cfg.dev.bundleGrammars { - dependencies = { - gcc.enable = false; - nodejs.enable = false; - tree-sitter.enable = false; + plugins.treesitter = { + gccPackage = null; + nodejsPackage = null; + treesitterPackage = null; }; }) # Configure Formatters { - extraPackages = [ pkgs.luajitPackages.jsregexp ]; + extraPackages = [ + pkgs.luajitPackages.jsregexp + pkgs.shfmt + pkgs.stylua + pkgs.taplo + pkgs.yamlfmt + ]; plugins.conform-nvim = { enable = true; settings = { - formatters = { - fish.command = lib.getExe' pkgs.fish "fish_indent"; - nixfmt.command = lib.getExe pkgs.nixfmt-rfc-style; - shfmt.command = lib.getExe pkgs.shfmt; - stylua.command = lib.getExe pkgs.stylua; - taplo.command = lib.getExe pkgs.taplo; - yamlfmt.command = lib.getExe pkgs.yamlfmt; - }; + formatters.nixfmt.command = "${lib.getExe pkgs.nixfmt-rfc-style}"; formatters_by_ft = { "_" = [ "trim_whitespace" ]; c = [ "clang_format" ]; @@ -115,24 +111,23 @@ in toml = [ "taplo" ]; yaml = [ "yamlfmt" ]; zig = [ "zigfmt" ]; - fish = [ "fish_indent" ]; }; }; }; } # Configure Linters { + extraPackages = [ + pkgs.dash + pkgs.statix + ]; plugins.lint = { enable = true; - linters = { - dash.command = lib.getExe pkgs.dash; - statix.command = lib.getExe pkgs.statix; - # chktex = lib.getExe pkgs.chktex; # Not in use - }; lintersByFt = { # latex = [ "chktex" ]; # Not in use nix = [ "statix" ]; sh = [ "dash" ]; + zsh = [ "zsh" ]; }; }; } @@ -162,9 +157,17 @@ in } # Rust plugins { - plugins.rustaceanvim.enable = true; - # install through rustup - dependencies.rust-analyzer.enable = false; + plugins = { + bacon = { + enable = true; + settings.quickfix.enabled = true; + }; + rustaceanvim = { + enable = true; + # Install through rustup + rustAnalyzerPackage = null; + }; + }; } # Other plugins { @@ -176,7 +179,6 @@ in mode = "virtualtext"; }; }; - hunk.enable = true; otter.enable = true; }; } diff --git a/nvim/extraPlugins/default.nix b/nvim/extraPlugins/default.nix new file mode 100644 index 0000000..87e972c --- /dev/null +++ b/nvim/extraPlugins/default.nix @@ -0,0 +1,11 @@ +{ pkgs }: +let + overlay = pkgs.callPackage ./generated.nix { + inherit (pkgs.vimUtils) buildVimPlugin buildNeovimPlugin; + }; + plugins = overlay pkgs pkgs; +in +{ + inherit overlay; + inherit (plugins) nvim-silicon; +} diff --git a/modules/nixvim/extraPlugins/generated.nix b/nvim/extraPlugins/generated.nix similarity index 72% rename from modules/nixvim/extraPlugins/generated.nix rename to nvim/extraPlugins/generated.nix index f0a2fcf..e4d204b 100644 --- a/modules/nixvim/extraPlugins/generated.nix +++ b/nvim/extraPlugins/generated.nix @@ -10,12 +10,12 @@ final: prev: { nvim-silicon = buildVimPlugin { pname = "nvim-silicon"; - version = "2025-01-09"; + version = "2024-08-31"; src = fetchFromGitHub { owner = "michaelrommel"; repo = "nvim-silicon"; - rev = "7f66bda8f60c97a5bf4b37e5b8acb0e829ae3c32"; - sha256 = "1zk6lgghvdcys20cqvh2g1kjf661q1w97niq5nx1zz4yppy2f9jy"; + rev = "9fe6001dc8cad4d9c53bcfc8649e3dc76ffa169c"; + sha256 = "1qczi06yndkr2pmwidlkgmk0395x189sznvscn4fnr96jx58j5yl"; }; meta.homepage = "https://github.com/michaelrommel/nvim-silicon/"; }; diff --git a/modules/nixvim/extraPlugins/plugins b/nvim/extraPlugins/plugins similarity index 100% rename from modules/nixvim/extraPlugins/plugins rename to nvim/extraPlugins/plugins diff --git a/modules/nixvim/mappings.nix b/nvim/mappings.nix similarity index 100% rename from modules/nixvim/mappings.nix rename to nvim/mappings.nix diff --git a/modules/nixvim/options.nix b/nvim/options.nix similarity index 100% rename from modules/nixvim/options.nix rename to nvim/options.nix diff --git a/nvim/plugins.nix b/nvim/plugins.nix new file mode 100644 index 0000000..f843db6 --- /dev/null +++ b/nvim/plugins.nix @@ -0,0 +1,178 @@ +{ lib, helpers, ... }: +let + inherit (helpers) mkRaw; +in +{ + config.plugins = { + cmp = { + enable = true; + cmdline = { + "/" = { + mapping = + mkRaw + # lua + '' + cmp.mapping.preset.cmdline() + ''; + sources = [ + { name = "rg"; } + { name = "buffer"; } + ]; + }; + ":" = { + mapping = + mkRaw + # lua + '' + cmp.mapping.preset.cmdline() + ''; + sources = [ + { name = "path"; } + { name = "cmdline"; } + ]; + }; + }; + settings = { + # Snippets + snippet.expand = + # lua + '' + function(args) require('luasnip').lsp_expand(args.body) end + ''; + # Completion Sources + sources = [ + { + name = "buffer"; + groupIndex = 3; + } + { + name = "calc"; + groupIndex = 2; + } + { + name = "conventionalcommits"; + groupIndex = 1; + } + { + name = "crates"; + groupIndex = 1; + } + { + name = "luasnip"; + groupIndex = 1; + } + { + name = "nvim_lsp"; + groupIndex = 1; + } + { + name = "nvim_lsp_document_symbol"; + groupIndex = 1; + } + { + name = "nvim_lsp_signature_help"; + groupIndex = 1; + } + { + name = "path"; + groupIndex = 2; + } + { + name = "spell"; + groupIndex = 2; + } + { + name = "treesitter"; + groupIndex = 2; + } + ]; + mapping = + mkRaw + # lua + '' + cmp.mapping.preset.insert({ + [""] = function(fallback) + if cmp.visible() then + cmp.select_next_item() + elseif require("luasnip").expand_or_jumpable() then + require("luasnip").expand_or_jump() + elseif has_words_before() then + cmp.complete() + else + fallback() + end + end, + [""] = function(fallback) + if cmp.visible() then + cmp.select_prev_item() + elseif require("luasnip").jumpable(-1) then + require("luasnip").jump(-1) + else + fallback() + end + end, + [""] = cmp.mapping(function(fallback) + if require("luasnip").choice_active() then + require("luasnip").next_choice() + else + fallback() + end + end), + [""] = cmp.mapping.scroll_docs(-4), + [""] = cmp.mapping.scroll_docs(4), + [""] = cmp.mapping.complete { }, + [""] = cmp.mapping.close(), + [""] = cmp.mapping.confirm { select = true }, + }) + ''; + }; + }; + gitsigns.enable = true; + lualine = { + enable = true; + settings.options.theme = lib.mkForce "gruvbox"; + }; + luasnip = { + enable = true; + settings.update_events = "TextChanged,TextChangedI"; + }; + noice = { + enable = true; + settings = { + lsp.override = { + "vim.lsp.util.convert_input_to_markdown_lines" = true; + "vim.lsp.util.stylize_markdown" = true; + "cmp.entry.get_documentation" = true; + }; + presets = { + # use a classic bottom cmdline for search + bottom_search = true; + # position the cmdline and popupmenu together + command_palette = false; + # long messages will be sent to a split + long_message_to_split = true; + # enables an input dialog for inc-rename.nvim + inc_rename = false; + # add a border to hover docs and signature help + lsp_doc_border = true; + }; + }; + }; + notify = { + enable = true; + settings.background_colour = "#000000"; + }; + telescope = { + enable = true; + extensions = { + ui-select.enable = true; + fzy-native.enable = true; + }; + }; + trouble = { + enable = true; + settings.auto_close = true; + }; + web-devicons.enable = true; + }; +} diff --git a/modules/nixvim/standalone.nix b/nvim/standalone.nix similarity index 90% rename from modules/nixvim/standalone.nix rename to nvim/standalone.nix index f66d239..cec3117 100644 --- a/modules/nixvim/standalone.nix +++ b/nvim/standalone.nix @@ -7,12 +7,7 @@ let cfg = config.jhome.nvim; plugins = pkgs.vimPlugins; - jExtraVimPlugins = pkgs.vimPlugins.extend ( - pkgs.callPackage ./extraPlugins/generated.nix { - inherit (pkgs.vimUtils) buildVimPlugin; - inherit (pkgs.neovimUtils) buildNeovimPlugin; - } - ); + extraPlugins = import ./extraPlugins { inherit pkgs; }; in { imports = [ @@ -60,6 +55,7 @@ in extraPlugins = [ plugins.nui-nvim plugins.nvim-web-devicons + plugins.vim-jjdescription # FIXME: included since neovim nightly ]; extraPackages = [ pkgs.luajitPackages.jsregexp ]; extraConfigLuaPre = @@ -83,7 +79,7 @@ in } # Big packages that are kinda unnecessary (lib.mkIf (!cfg.reduceSize) { - extraPlugins = [ jExtraVimPlugins.nvim-silicon ]; + extraPlugins = [ extraPlugins.nvim-silicon ]; extraPackages = [ pkgs.silicon ]; extraConfigLua = # lua diff --git a/scripts/audiomenu/.envrc b/scripts/audiomenu/.envrc deleted file mode 100644 index 729d54f..0000000 --- a/scripts/audiomenu/.envrc +++ /dev/null @@ -1,2 +0,0 @@ -source_up -source .venv/bin/activate diff --git a/scripts/audiomenu/.gitignore b/scripts/audiomenu/.gitignore index 1d17dae..ea8c4bf 100644 --- a/scripts/audiomenu/.gitignore +++ b/scripts/audiomenu/.gitignore @@ -1 +1 @@ -.venv +/target diff --git a/scripts/audiomenu/.python-version b/scripts/audiomenu/.python-version deleted file mode 100644 index 24ee5b1..0000000 --- a/scripts/audiomenu/.python-version +++ /dev/null @@ -1 +0,0 @@ -3.13 diff --git a/scripts/audiomenu/Cargo.lock b/scripts/audiomenu/Cargo.lock new file mode 100644 index 0000000..4840d58 --- /dev/null +++ b/scripts/audiomenu/Cargo.lock @@ -0,0 +1,568 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "addr2line" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" + +[[package]] +name = "anstream" +version = "0.6.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" + +[[package]] +name = "anstyle-parse" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e" +dependencies = [ + "anstyle", + "once_cell", + "windows-sys", +] + +[[package]] +name = "audiomenu" +version = "0.1.0" +dependencies = [ + "clap", + "duct", + "miette", + "serde", + "serde_json", +] + +[[package]] +name = "backtrace" +version = "0.3.74" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" +dependencies = [ + "addr2line", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", + "windows-targets", +] + +[[package]] +name = "backtrace-ext" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "537beee3be4a18fb023b570f80e3ae28003db9167a751266b259926e25539d50" +dependencies = [ + "backtrace", +] + +[[package]] +name = "bitflags" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "clap" +version = "4.5.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6088f3ae8c3608d19260cd7445411865a485688711b78b5be70d78cd96136f83" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22a7ef7f676155edfb82daa97f99441f3ebf4a58d5e32f295a56259f1b6facc8" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.5.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09176aae279615badda0765c0c0b3f6ed53f4709118af73cf4655d85d1530cd7" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "clap_lex" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" + +[[package]] +name = "colorchoice" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" + +[[package]] +name = "duct" +version = "0.13.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4ab5718d1224b63252cd0c6f74f6480f9ffeb117438a2e0f5cf6d9a4798929c" +dependencies = [ + "libc", + "once_cell", + "os_pipe", + "shared_child", +] + +[[package]] +name = "errno" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" +dependencies = [ + "libc", + "windows-sys", +] + +[[package]] +name = "gimli" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "is_ci" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7655c9839580ee829dfacba1d1278c2b7883e50a277ff7541299489d6bdfdc45" + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" + +[[package]] +name = "itoa" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" + +[[package]] +name = "libc" +version = "0.2.170" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "875b3680cb2f8f71bdcf9a30f38d48282f5d3c95cbf9b3fa57269bb5d5c06828" + +[[package]] +name = "linux-raw-sys" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db9c683daf087dc577b7506e9695b3d556a9f3849903fa28186283afd6809e9" + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "miette" +version = "7.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a955165f87b37fd1862df2a59547ac542c77ef6d17c666f619d1ad22dd89484" +dependencies = [ + "backtrace", + "backtrace-ext", + "cfg-if", + "miette-derive", + "owo-colors", + "supports-color", + "supports-hyperlinks", + "supports-unicode", + "terminal_size", + "textwrap", + "thiserror", + "unicode-width 0.1.14", +] + +[[package]] +name = "miette-derive" +version = "7.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf45bf44ab49be92fd1227a3be6fc6f617f1a337c06af54981048574d8783147" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "miniz_oxide" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e3e04debbb59698c15bacbb6d93584a8c0ca9cc3213cb423d31f760d8843ce5" +dependencies = [ + "adler2", +] + +[[package]] +name = "object" +version = "0.36.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cde51589ab56b20a6f686b2c68f7a0bd6add753d697abf720d63f8db3ab7b1ad" + +[[package]] +name = "os_pipe" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ffd2b0a5634335b135d5728d84c5e0fd726954b87111f7506a61c502280d982" +dependencies = [ + "libc", + "windows-sys", +] + +[[package]] +name = "owo-colors" +version = "4.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1036865bb9422d3300cf723f657c2851d0e9ab12567854b1f4eba3d77decf564" + +[[package]] +name = "proc-macro2" +version = "1.0.94" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1f1914ce909e1658d9907913b4b91947430c7d9be598b15a1912935b8c04801" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" + +[[package]] +name = "rustix" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7178faa4b75a30e269c71e61c353ce2748cf3d76f0c44c393f4e60abf49b825" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys", +] + +[[package]] +name = "ryu" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" + +[[package]] +name = "serde" +version = "1.0.219" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.219" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.140" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", +] + +[[package]] +name = "shared_child" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09fa9338aed9a1df411814a5b2252f7cd206c55ae9bf2fa763f8de84603aa60c" +dependencies = [ + "libc", + "windows-sys", +] + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "supports-color" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c64fc7232dd8d2e4ac5ce4ef302b1d81e0b80d055b9d77c7c4f51f6aa4c867d6" +dependencies = [ + "is_ci", +] + +[[package]] +name = "supports-hyperlinks" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "804f44ed3c63152de6a9f90acbea1a110441de43006ea51bcce8f436196a288b" + +[[package]] +name = "supports-unicode" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7401a30af6cb5818bb64852270bb722533397edcfc7344954a38f420819ece2" + +[[package]] +name = "syn" +version = "2.0.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "terminal_size" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45c6481c4829e4cc63825e62c49186a34538b7b2750b73b266581ffb612fb5ed" +dependencies = [ + "rustix", + "windows-sys", +] + +[[package]] +name = "textwrap" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c13547615a44dc9c452a8a534638acdf07120d4b6847c8178705da06306a3057" +dependencies = [ + "unicode-linebreak", + "unicode-width 0.2.0", +] + +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "unicode-ident" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" + +[[package]] +name = "unicode-linebreak" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f" + +[[package]] +name = "unicode-width" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" + +[[package]] +name = "unicode-width" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd" + +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" diff --git a/scripts/audiomenu/Cargo.toml b/scripts/audiomenu/Cargo.toml new file mode 100644 index 0000000..b469215 --- /dev/null +++ b/scripts/audiomenu/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "audiomenu" +description = "fuzzel script to select the default audio device for pipewire+wireplumber" +version = "0.1.0" +edition = "2021" + +[dependencies] +clap = { version = "4.5.23", features = ["derive", "env"] } +duct = "0.13.7" +miette = { version = "7.4.0", features = ["fancy"] } +serde = { version = "1.0.215", features = ["derive"] } +serde_json = "1.0.133" + +[profile.release] +lto = true +opt-level = 's' +panic = "abort" +strip = true diff --git a/scripts/audiomenu/README.md b/scripts/audiomenu/README.md deleted file mode 100644 index e69de29..0000000 diff --git a/scripts/audiomenu/audiomenu.py b/scripts/audiomenu/audiomenu.py deleted file mode 100644 index 88fe671..0000000 --- a/scripts/audiomenu/audiomenu.py +++ /dev/null @@ -1,238 +0,0 @@ -# pyright: strict, reportAny=false -from dataclasses import dataclass -import json -import subprocess -from typing import Self -import typing -import click - - -def expect[T](type_: type[T], value: object) -> T: - if not isinstance(value, type_): - raise ValueError( - f"expected value to be of type {type_} but was of type {type(value)}" - ) - return value - - -@dataclass(slots=True) -class PWNodeProps: - object_id: int - node_description: str - node_name: str - media_class: str - - @classmethod - def from_json(cls, data: dict[str, object]) -> Self: - return cls( - object_id=expect(int, data["object.id"]), - node_description=expect(str, data.get("node.description", "(unknown)")), - node_name=expect(str, data["node.name"]), - media_class=expect(str, data.get("media.class", "(unknown)")), - ) - - -@dataclass(slots=True) -class PWNodeInfo: - props: PWNodeProps - - @classmethod - def from_json(cls, data: dict[str, object]) -> Self: - props = typing.cast(dict[str, object], expect(dict, data["props"])) - return cls(PWNodeProps.from_json(props)) - - -@dataclass(slots=True) -class PWNode: - node_type: str - info: PWNodeInfo | None - - @classmethod - def from_json(cls, data: dict[str, object]) -> Self: - info = data.get("info", None) - if info is not None: - info = PWNodeInfo.from_json( - typing.cast(dict[str, object], expect(dict, info)) - ) - return cls(node_type=expect(str, data["type"]), info=info) - - -@dataclass(slots=True) -class AudioDevice: - id: int - name: str - volume: float - muted: bool - default: bool - - @staticmethod - def get_volume(id: int | str) -> tuple[float, bool]: - wpctl_output = subprocess.run( - ["wpctl", "get-volume", str(id)], - encoding="UTF-8", - check=True, - capture_output=True, - ) - match wpctl_output.stdout.strip().split(sep=" "): - case ["Volume:", value]: - return (float(value), False) - case ["Volume:", value, "[MUTED]"]: - return (float(value), True) - case _: - raise ValueError(f"Unexpected wpctl output: {wpctl_output.stdout}") - - @classmethod - def from_pw_node(cls, node: PWNode, default: str) -> Self: - if node.info is None: - raise ValueError(f"Node is not a valid audio device {node}") - - id = node.info.props.object_id - volume, muted = cls.get_volume(id) - - return cls( - id=id, - name=node.info.props.node_description, - volume=volume, - muted=muted, - default=node.info.props.node_name == default, - ) - - def menu_item(self) -> str: - id = f"id={self.id:<3}" - - if self.default: - id = f"[{id}]" - else: - id = f" {id} " - - if self.muted: - return f"{id} {self.volume:>4.0%} [MUTED] {self.name}" - else: - return f"{id} {self.volume:>4.0%} {self.name}" - - -def get_nodes(data: list[dict[str, object]]) -> list[PWNode]: - def is_audio_node(node: object) -> bool: - if not isinstance(node, dict): - return False - - node = typing.cast(dict[str, object], node) - if node["type"] != "PipeWire:Interface:Node": - return False - info = node.get("info", None) - if info is None or not isinstance(info, dict): - return False - info = typing.cast(dict[str, object], info) - props = info.get("props", None) - if props is None or not isinstance(props, dict): - return False - props = typing.cast(dict[str, object], props) - if (media_class := props.get("media.class", None)) is not None: - return isinstance(media_class, str) and media_class.startswith("Audio") - return False - - return [ - PWNode.from_json(typing.cast(dict[str, object], expect(dict, node))) - for node in data - if is_audio_node(node) - ] - - -def pw_dump() -> list[dict[str, object]]: - dump_output = subprocess.run( - ["pw-dump"], encoding="UTF-8", check=True, capture_output=True - ) - data = json.loads(dump_output.stdout) - return typing.cast(list[dict[str, object]], expect(list, data)) - - -def get_defaults_metadata(data: list[dict[str, object]]) -> list[dict[str, object]]: - return typing.cast( - list[dict[str, object]], - expect( - list, - next( - node - for node in data - if node["type"] == "PipeWire:Interface:Metadata" - and expect(dict, node["props"])["metadata.name"] == "default" - )["metadata"], - ), - ) - - -def get_sinks() -> list[AudioDevice]: - data = pw_dump() - default = next( - typing.cast(dict[str, str], expect(dict, data["value"]))["name"] - for data in get_defaults_metadata(data) - if data["key"] == "default.audio.sink" - ) - return [ - AudioDevice.from_pw_node(node, default) - for node in get_nodes(data) - if node.info is not None and node.info.props.media_class == "Audio/Sink" - ] - - -def get_sources() -> list[AudioDevice]: - data = pw_dump() - default = next( - typing.cast(dict[str, str], expect(dict, data["value"]))["name"] - for data in get_defaults_metadata(data) - if data["key"] == "default.audio.source" - ) - return [ - AudioDevice.from_pw_node(node, default) - for node in get_nodes(data) - if node.info is not None and node.info.props.media_class == "Audio/Source" - ] - - -@click.group(name="audiomenu") -def main() -> None: - pass - - -def select(options: list[str], prompt: str) -> int | None: - menu_output = subprocess.run( - ["fuzzel", "--dmenu", f"--prompt={prompt}"], - input="\n".join(options), - encoding="UTF-8", - capture_output=True, - ) - if menu_output.returncode == 2: - return None - menu_output.check_returncode() - selected = menu_output.stdout.rstrip() - return options.index(selected) - - -@main.command() -def select_sink() -> None: - devices = get_sinks() - selected = select([device.menu_item() for device in devices], prompt="Select Sink>") - if selected is None: - click.echo("No sink selected") - return - - device = devices[selected] - _ = subprocess.run(["wpctl", "set-default", str(device.id)], check=True) - - -@main.command() -def select_source() -> None: - devices = get_sources() - selected = select( - [device.menu_item() for device in devices], prompt="Select Source>" - ) - if selected is None: - click.echo("No source selected") - return - - device = devices[selected] - _ = subprocess.run(["wpctl", "set-default", str(device.id)], check=True) - - -if __name__ == "__main__": - main() diff --git a/scripts/audiomenu/package.nix b/scripts/audiomenu/package.nix index 45a5a3b..88636da 100644 --- a/scripts/audiomenu/package.nix +++ b/scripts/audiomenu/package.nix @@ -1,9 +1,40 @@ -{ writers, python3Packages }: -writers.writePython3Bin "audiomenu" { - libraries = [ python3Packages.click ]; - - flakeIgnore = [ - "E501" # line too long, but I like my code well documented - "W503" # line break before binary operator, ruff does this, I trust it - ]; -} ./audiomenu.py +{ lib, rustPlatform }: +let + cargoToml = builtins.fromTOML (builtins.readFile ./Cargo.toml); + inherit (cargoToml.package) name version description; + pname = name; + src = lib.cleanSourceWith { + src = ./.; + name = "${pname}-source"; + # Adapted from + # no need to pull in crane for just this + filter = + orig_path: type: + let + path = toString orig_path; + base = baseNameOf path; + parentDir = baseNameOf (dirOf path); + matchesSuffix = lib.any (suffix: lib.hasSuffix suffix base) [ + # Rust sources + ".rs" + # TOML files are often used to configure cargo based tools (e.g. .cargo/config.toml) + ".toml" + ]; + isCargoLock = base == "Cargo.lock"; + # .cargo/config.toml is captured above + isOldStyleCargoConfig = parentDir == ".cargo" && base == "config"; + in + type == "directory" || matchesSuffix || isCargoLock || isOldStyleCargoConfig; + }; +in +rustPlatform.buildRustPackage { + inherit pname version src; + cargoLock.lockFile = ./Cargo.lock; + useNextest = true; + meta = { + inherit description; + license = lib.licenses.mit; + homepage = "https://github.com/jalil-salame/configuration.nix"; + mainProgram = name; + }; +} diff --git a/scripts/audiomenu/pyproject.toml b/scripts/audiomenu/pyproject.toml deleted file mode 100644 index 6d992a3..0000000 --- a/scripts/audiomenu/pyproject.toml +++ /dev/null @@ -1,9 +0,0 @@ -[project] -name = "audiomenu" -version = "0.1.0" -description = "fuzzel script to select the default audio device for pipewire+wireplumber" -readme = "README.md" -requires-python = ">=3.12" -dependencies = [ - "click>=8.1.7", -] diff --git a/scripts/audiomenu/src/main.rs b/scripts/audiomenu/src/main.rs new file mode 100644 index 0000000..a542fd4 --- /dev/null +++ b/scripts/audiomenu/src/main.rs @@ -0,0 +1,231 @@ +use std::{ + fmt::{Display, Write as _}, + io::{Read, Write as _}, + process::{Command, Stdio}, +}; + +use clap::Parser; +use duct::cmd; +use miette::{bail, Context, IntoDiagnostic, Result}; +use serde::Deserialize; + +fn main() -> Result<()> { + miette::set_panic_hook(); + Opts::parse().run() +} + +/// fuzzel script to select the default audio device for pipewire+wireplumber +#[derive(Debug, Parser)] +struct Opts { + #[clap(subcommand)] + cmd: Cmd, +} + +impl Opts { + fn run(self) -> Result<()> { + self.cmd.run() + } +} + +#[derive(Debug, clap::Subcommand)] +enum Cmd { + /// Select audio sink (speakers/headphones) + SelectSink, + /// Select audio source (microphone) + SelectSource, +} + +impl Cmd { + fn run(self) -> Result<()> { + let id = match self { + Cmd::SelectSink => { + let devices = get_sinks().wrap_err("failed to get sinks")?; + let selected = select( + devices.iter().map(|dev| dev.name.as_ref()), + Some("Select input>"), + ) + .wrap_err("failed to select a default sink")?; + if selected.is_empty() { + eprintln!("did not select a device"); + return Ok(()); + } + let Some(dev) = devices.into_iter().find(|dev| dev.name == selected) else { + bail!("couldn't find a device matching `{selected}`"); + }; + dev.id + } + Cmd::SelectSource => { + let devices = get_sources().wrap_err("failed to get sinks")?; + let selected = select( + devices.iter().map(|dev| dev.name.as_ref()), + Some("Select output>"), + ) + .wrap_err("failed to select a default source")?; + if selected.is_empty() { + eprintln!("did not select a device"); + return Ok(()); + } + let Some(dev) = devices.into_iter().find(|dev| dev.name == selected) else { + bail!("couldn't find a device matching `{selected}`"); + }; + dev.id + } + }; + cmd!("wpctl", "set-default", id.to_string()) + .run() + .map(drop) + .into_diagnostic() + .wrap_err("failed to set default input") + } +} + +#[derive(Debug, Deserialize)] +struct PWNode { + #[serde(rename = "type")] + node_type: Box, + #[serde(default)] + info: PWNodeInfo, + // json ignores the rest of the fields by default +} + +#[derive(Debug, Deserialize, Default)] +struct PWNodeInfo { + props: PWNodeProps, + // json ignores the rest of the fields by default +} + +#[derive(Debug, Deserialize, Default)] +struct PWNodeProps { + #[serde(rename = "object.id")] + object_id: u32, + #[serde(rename = "node.description", default)] + node_description: Box, + #[serde(rename = "media.class", default)] + media_class: Box, + // json ignores the rest of the fields by default +} + +struct AudioDevice { + id: u32, + name: Box, + _side: S, +} + +/// Output (e.g. speakers) +struct AudioSink; + +/// Input (e.g. microphone) +struct AudioSource; + +fn get_sinks() -> Result>> { + get_devices() +} + +fn get_sources() -> Result>> { + get_devices() +} + +fn get_devices() -> Result>> +where + AudioDevice: TryFrom, +{ + Ok(get_nodes()? + .into_iter() + .filter_map(|node| AudioDevice::::try_from(node).ok()) + .collect()) +} + +impl TryFrom for AudioDevice { + type Error = miette::Report; + + fn try_from(value: PWNode) -> std::result::Result { + if value.node_type.as_ref() != "PipeWire:Interface:Node" { + bail!( + "invalid type: `{}`, expected `PipeWire:Interface:Node`", + value.node_type + ) + } + let class = value.info.props.media_class; + match class.as_ref() { + "Audio/Source" => Ok(Self { + id: value.info.props.object_id, + name: value.info.props.node_description, + _side: AudioSource, + }), + _ => bail!("invalid media.class: `{class}`, expected `Audio/Source`"), + } + } +} + +impl TryFrom for AudioDevice { + type Error = miette::Report; + + fn try_from(value: PWNode) -> std::result::Result { + if value.node_type.as_ref() != "PipeWire:Interface:Node" { + bail!( + "invalid type: `{}`, expected `PipeWire:Interface:Node`", + value.node_type + ) + } + let class = value.info.props.media_class; + match class.as_ref() { + "Audio/Sink" => Ok(Self { + id: value.info.props.object_id, + name: value.info.props.node_description, + _side: AudioSink, + }), + _ => bail!("invalid media.class: `{class}`, expected `Audio/Sink`"), + } + } +} + +fn get_nodes() -> Result> { + let dump = cmd!("pw-dump") + .read() + .into_diagnostic() + .wrap_err("failed to get devices with pw-dump")?; + serde_json::from_str(&dump) + .into_diagnostic() + .wrap_err("failed to parse pw-dump output") +} + +fn select(options: It, prompt: Option<&str>) -> Result> +where + T: Display, + It: IntoIterator, +{ + let append_line = |mut s: String, it| { + writeln!(s, "{it}").unwrap(); + s + }; + let options = options.into_iter().fold(String::new(), append_line); + let mut menu = Command::new("fuzzel"); + menu.arg("--dmenu"); + if let Some(prompt) = prompt { + menu.arg(format!("--prompt={prompt}")); + } + Ok(pipe_to_stdin_and_return_stdout(&mut menu, options)? + .trim() + .into()) +} + +fn pipe_to_stdin_and_return_stdout(cmd: &mut Command, data: impl Display) -> Result { + let mut child = cmd + .stdin(Stdio::piped()) + .stdout(Stdio::piped()) + .spawn() + .into_diagnostic() + .wrap_err_with(|| format!("failed to run {cmd:?}"))?; + let mut stdin = child.stdin.take().expect("stdin not piped"); + write!(stdin, "{data}") + .into_diagnostic() + .wrap_err("failed to send data to process' stdin")?; + drop(stdin); + let mut stdout = child.stdout.take().expect("stdout not piped"); + let mut buf = String::new(); + stdout + .read_to_string(&mut buf) + .into_diagnostic() + .wrap_err("failed to retrieve output from process")?; + Ok(buf) +} diff --git a/scripts/default.nix b/scripts/default.nix index 5cde95c..23ec010 100644 --- a/scripts/default.nix +++ b/scripts/default.nix @@ -1,17 +1,23 @@ +# Autodetects files with a package.nix and calls `callPackage` on them. +# +# Will add a package .#dirname to the flake if it finds a ./dirname/package.nix file. let - packages = pkgs: { - jpassmenu = pkgs.callPackage ./jpassmenu/package.nix { }; - audiomenu = pkgs.callPackage ./audiomenu/package.nix { }; + files = builtins.readDir ./.; + isPackage = path: type: (type == "directory") && (builtins.readDir path) ? "package.nix"; + toPackage = name: pkgs: { + inherit name; + value = pkgs.callPackage (./. + "/${name}/package.nix") { }; }; + # call pkgs.callPackage on all ./*/package.nix + makePackage = + pkgs: name: + let + type = files.${name}; + path = ./. + "/${name}"; + package = toPackage name pkgs; + in + # if it is a package then return a package otherwise return no package c: + if isPackage path type then [ package ] else [ ]; in -{ - # Add scripts to overlay - flake.overlays.scripts = _final: packages; - - # Add scripts to packages - perSystem = - { pkgs, ... }: - { - packages = packages pkgs; - }; -} +# we have lib.filterMapAttrs at home +pkgs: builtins.listToAttrs (builtins.concatMap (makePackage pkgs) (builtins.attrNames files)) diff --git a/scripts/jpassmenu/.envrc b/scripts/jpassmenu/.envrc deleted file mode 100644 index 729d54f..0000000 --- a/scripts/jpassmenu/.envrc +++ /dev/null @@ -1,2 +0,0 @@ -source_up -source .venv/bin/activate diff --git a/scripts/jpassmenu/.gitignore b/scripts/jpassmenu/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/scripts/jpassmenu/.gitignore @@ -0,0 +1 @@ +/target diff --git a/scripts/jpassmenu/.python-version b/scripts/jpassmenu/.python-version deleted file mode 100644 index 24ee5b1..0000000 --- a/scripts/jpassmenu/.python-version +++ /dev/null @@ -1 +0,0 @@ -3.13 diff --git a/scripts/jpassmenu/Cargo.lock b/scripts/jpassmenu/Cargo.lock new file mode 100644 index 0000000..9e29ec2 --- /dev/null +++ b/scripts/jpassmenu/Cargo.lock @@ -0,0 +1,743 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "addr2line" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "anstream" +version = "0.6.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" + +[[package]] +name = "anstyle-parse" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e" +dependencies = [ + "anstyle", + "once_cell", + "windows-sys", +] + +[[package]] +name = "backtrace" +version = "0.3.74" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" +dependencies = [ + "addr2line", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", + "windows-targets", +] + +[[package]] +name = "backtrace-ext" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "537beee3be4a18fb023b570f80e3ae28003db9167a751266b259926e25539d50" +dependencies = [ + "backtrace", +] + +[[package]] +name = "bitflags" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" + +[[package]] +name = "bstr" +version = "1.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "531a9155a481e2ee699d4f98f43c0ca4ff8ee1bfd55c31e9e98fb29d2b176fe0" +dependencies = [ + "memchr", + "serde", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "clap" +version = "4.5.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6088f3ae8c3608d19260cd7445411865a485688711b78b5be70d78cd96136f83" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22a7ef7f676155edfb82daa97f99441f3ebf4a58d5e32f295a56259f1b6facc8" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.5.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09176aae279615badda0765c0c0b3f6ed53f4709118af73cf4655d85d1530cd7" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "clap_lex" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" + +[[package]] +name = "colorchoice" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" + +[[package]] +name = "crossbeam-deque" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" + +[[package]] +name = "duct" +version = "0.13.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4ab5718d1224b63252cd0c6f74f6480f9ffeb117438a2e0f5cf6d9a4798929c" +dependencies = [ + "libc", + "once_cell", + "os_pipe", + "shared_child", +] + +[[package]] +name = "env_filter" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "186e05a59d4c50738528153b83b0b0194d3a29507dfec16eccd4b342903397d0" +dependencies = [ + "log", + "regex", +] + +[[package]] +name = "env_logger" +version = "0.11.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3716d7a920fb4fac5d84e9d4bce8ceb321e9414b4409da61b07b75c1e3d0697" +dependencies = [ + "anstream", + "anstyle", + "env_filter", + "jiff", + "log", +] + +[[package]] +name = "errno" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" +dependencies = [ + "libc", + "windows-sys", +] + +[[package]] +name = "gimli" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" + +[[package]] +name = "globset" +version = "0.4.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54a1028dfc5f5df5da8a56a73e6c153c9a9708ec57232470703592a3f18e49f5" +dependencies = [ + "aho-corasick", + "bstr", + "log", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "ignore" +version = "0.4.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d89fd380afde86567dfba715db065673989d6253f42b88179abd3eae47bda4b" +dependencies = [ + "crossbeam-deque", + "globset", + "log", + "memchr", + "regex-automata", + "same-file", + "walkdir", + "winapi-util", +] + +[[package]] +name = "is_ci" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7655c9839580ee829dfacba1d1278c2b7883e50a277ff7541299489d6bdfdc45" + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" + +[[package]] +name = "jiff" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d699bc6dfc879fb1bf9bdff0d4c56f0884fc6f0d0eb0fba397a6d00cd9a6b85e" +dependencies = [ + "jiff-static", + "log", + "portable-atomic", + "portable-atomic-util", + "serde", +] + +[[package]] +name = "jiff-static" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d16e75759ee0aa64c57a56acbf43916987b20c77373cb7e808979e02b93c9f9" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "jpassmenu" +version = "0.1.0" +dependencies = [ + "clap", + "duct", + "env_logger", + "ignore", + "log", + "miette", +] + +[[package]] +name = "libc" +version = "0.2.170" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "875b3680cb2f8f71bdcf9a30f38d48282f5d3c95cbf9b3fa57269bb5d5c06828" + +[[package]] +name = "linux-raw-sys" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db9c683daf087dc577b7506e9695b3d556a9f3849903fa28186283afd6809e9" + +[[package]] +name = "log" +version = "0.4.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30bde2b3dc3671ae49d8e2e9f044c7c005836e7a023ee57cffa25ab82764bb9e" + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "miette" +version = "7.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a955165f87b37fd1862df2a59547ac542c77ef6d17c666f619d1ad22dd89484" +dependencies = [ + "backtrace", + "backtrace-ext", + "cfg-if", + "miette-derive", + "owo-colors", + "supports-color", + "supports-hyperlinks", + "supports-unicode", + "terminal_size", + "textwrap", + "thiserror", + "unicode-width 0.1.14", +] + +[[package]] +name = "miette-derive" +version = "7.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf45bf44ab49be92fd1227a3be6fc6f617f1a337c06af54981048574d8783147" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "miniz_oxide" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e3e04debbb59698c15bacbb6d93584a8c0ca9cc3213cb423d31f760d8843ce5" +dependencies = [ + "adler2", +] + +[[package]] +name = "object" +version = "0.36.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cde51589ab56b20a6f686b2c68f7a0bd6add753d697abf720d63f8db3ab7b1ad" + +[[package]] +name = "os_pipe" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ffd2b0a5634335b135d5728d84c5e0fd726954b87111f7506a61c502280d982" +dependencies = [ + "libc", + "windows-sys", +] + +[[package]] +name = "owo-colors" +version = "4.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1036865bb9422d3300cf723f657c2851d0e9ab12567854b1f4eba3d77decf564" + +[[package]] +name = "portable-atomic" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "350e9b48cbc6b0e028b0473b114454c6316e57336ee184ceab6e53f72c178b3e" + +[[package]] +name = "portable-atomic-util" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507" +dependencies = [ + "portable-atomic", +] + +[[package]] +name = "proc-macro2" +version = "1.0.94" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1f1914ce909e1658d9907913b4b91947430c7d9be598b15a1912935b8c04801" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "regex" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" + +[[package]] +name = "rustc-demangle" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" + +[[package]] +name = "rustix" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7178faa4b75a30e269c71e61c353ce2748cf3d76f0c44c393f4e60abf49b825" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys", +] + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "serde" +version = "1.0.219" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.219" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "shared_child" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09fa9338aed9a1df411814a5b2252f7cd206c55ae9bf2fa763f8de84603aa60c" +dependencies = [ + "libc", + "windows-sys", +] + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "supports-color" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c64fc7232dd8d2e4ac5ce4ef302b1d81e0b80d055b9d77c7c4f51f6aa4c867d6" +dependencies = [ + "is_ci", +] + +[[package]] +name = "supports-hyperlinks" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "804f44ed3c63152de6a9f90acbea1a110441de43006ea51bcce8f436196a288b" + +[[package]] +name = "supports-unicode" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7401a30af6cb5818bb64852270bb722533397edcfc7344954a38f420819ece2" + +[[package]] +name = "syn" +version = "2.0.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "terminal_size" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45c6481c4829e4cc63825e62c49186a34538b7b2750b73b266581ffb612fb5ed" +dependencies = [ + "rustix", + "windows-sys", +] + +[[package]] +name = "textwrap" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c13547615a44dc9c452a8a534638acdf07120d4b6847c8178705da06306a3057" +dependencies = [ + "unicode-linebreak", + "unicode-width 0.2.0", +] + +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "unicode-ident" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" + +[[package]] +name = "unicode-linebreak" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f" + +[[package]] +name = "unicode-width" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" + +[[package]] +name = "unicode-width" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd" + +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "winapi-util" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" diff --git a/scripts/jpassmenu/Cargo.toml b/scripts/jpassmenu/Cargo.toml new file mode 100644 index 0000000..7ffa4ba --- /dev/null +++ b/scripts/jpassmenu/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "jpassmenu" +description = "A simple program that uses dmenu compatible menu to select a password to type/copy" +version = "0.1.0" +edition = "2021" + +[dependencies] +clap = { version = "4.5.23", features = ["derive", "env"] } +duct = "0.13.7" +env_logger = "0.11.5" +ignore = "0.4.23" +log = "0.4.22" +miette = { version = "7.4.0", features = ["fancy"] } + +[profile.release] +lto = true +opt-level = "s" +panic = "abort" +strip = true diff --git a/scripts/jpassmenu/README.md b/scripts/jpassmenu/README.md deleted file mode 100644 index 2c28fb8..0000000 --- a/scripts/jpassmenu/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# jpassmenu - -My own implementation of the `passmenu` `dmenu` script, this one uses `fuzzel` by default and types passwords with `ydotool`. diff --git a/scripts/jpassmenu/jpassmenu.py b/scripts/jpassmenu/jpassmenu.py deleted file mode 100644 index f446412..0000000 --- a/scripts/jpassmenu/jpassmenu.py +++ /dev/null @@ -1,111 +0,0 @@ -from os import environ -from pathlib import Path -import subprocess -import click - - -def select(options: list[str]) -> int | None: - menu_output = subprocess.run( - ["fuzzel", "--dmenu"], - input="\n".join(options), - encoding="UTF-8", - capture_output=True, - ) - if menu_output.returncode == 2: - return None - menu_output.check_returncode() - selected = menu_output.stdout.rstrip() - return options.index(selected) - - -@click.command( - "jpassmenu", context_settings={"show_default": True, "max_content_width": 120} -) -@click.option( - "--type", - "typeit", - help="Type the password using ydotool instead of copying it to the clipboard", -) -@click.option( - "--store-dir", - type=click.Path(exists=True, file_okay=False, path_type=Path), - envvar="PASSWORD_STORE_DIR", - default=Path("~/.password-store"), -) -@click.option( - "--pass-bin", - default="pass", - help="Path to the pass binary\n\nNeeds to support `pass show` and `pass show --clip`", -) -@click.option( - "--menu-bin", default="fuzzel", help="Path to the dmenu compatible menu binary" -) -@click.argument("menu_args", nargs=-1) -def main( - typeit: bool, store_dir: Path, pass_bin: str, menu_bin: str, menu_args: list[str] -) -> None: - menu_args = ( - ["--dmenu"] if not menu_args and menu_bin.endswith("fuzzel") else menu_args - ) - store_dir = store_dir.expanduser().absolute() - # Get all files in store_dir - secrets = ( - dirpath / fname - for dirpath, _dirnames, filenames in store_dir.walk() - for fname in filenames - ) - # Filter for files ending in .gpg and strip the extension - secrets = ( - secret.with_suffix("") - for secret in secrets - if secret.is_file() and secret.suffix == ".gpg" - ) - # Make the paths relative to store_dir and turn to strings - secrets = sorted(str(secret.relative_to(store_dir)) for secret in secrets) - - if not secrets: - click.secho(f"No valid entries found in {store_dir}", err=True, fg="red") - - selected = select(secrets) - if selected is None: - click.echo("No secret selected") - return - selected = secrets[selected] - - # If PASSWORD_STORE_DIR and --store-dir disagree, set PASSWORD_STORE_DIR to --store-dir - env_store = ( - Path(environ.get("PASSWORD_STORE_DIR", default="~/.password-store")) - .expanduser() - .absolute() - ) - if store_dir != env_store: - environ["PASSWORD_STORE_DIR"] = str(store_dir) - - pass_cmd = ( - [pass_bin, "show", selected] - if typeit - else [pass_bin, "show", "--clip", selected] - ) - - pass_output = subprocess.run( - pass_cmd, - encoding="UTF-8", - check=True, - capture_output=typeit, - ) - if not typeit: - return - - pass_entry = pass_output.stdout - secret = pass_entry.splitlines()[0].strip() - - _ = subprocess.run( - ["ydotool", "type", "--file", "-"], - input=secret, - encoding="UTF-8", - check=True, - ) - - -if __name__ == "__main__": - main() diff --git a/scripts/jpassmenu/package.nix b/scripts/jpassmenu/package.nix index 6fbfbbd..88636da 100644 --- a/scripts/jpassmenu/package.nix +++ b/scripts/jpassmenu/package.nix @@ -1,6 +1,40 @@ -{ writers, python3Packages }: -writers.writePython3Bin "jpassmenu" { - libraries = [ python3Packages.click ]; - # line too long, but I like my code well documented - flakeIgnore = [ "E501" ]; -} ./jpassmenu.py +{ lib, rustPlatform }: +let + cargoToml = builtins.fromTOML (builtins.readFile ./Cargo.toml); + inherit (cargoToml.package) name version description; + pname = name; + src = lib.cleanSourceWith { + src = ./.; + name = "${pname}-source"; + # Adapted from + # no need to pull in crane for just this + filter = + orig_path: type: + let + path = toString orig_path; + base = baseNameOf path; + parentDir = baseNameOf (dirOf path); + matchesSuffix = lib.any (suffix: lib.hasSuffix suffix base) [ + # Rust sources + ".rs" + # TOML files are often used to configure cargo based tools (e.g. .cargo/config.toml) + ".toml" + ]; + isCargoLock = base == "Cargo.lock"; + # .cargo/config.toml is captured above + isOldStyleCargoConfig = parentDir == ".cargo" && base == "config"; + in + type == "directory" || matchesSuffix || isCargoLock || isOldStyleCargoConfig; + }; +in +rustPlatform.buildRustPackage { + inherit pname version src; + cargoLock.lockFile = ./Cargo.lock; + useNextest = true; + meta = { + inherit description; + license = lib.licenses.mit; + homepage = "https://github.com/jalil-salame/configuration.nix"; + mainProgram = name; + }; +} diff --git a/scripts/jpassmenu/pyproject.toml b/scripts/jpassmenu/pyproject.toml deleted file mode 100644 index 5cfa6aa..0000000 --- a/scripts/jpassmenu/pyproject.toml +++ /dev/null @@ -1,9 +0,0 @@ -[project] -name = "jpassmenu" -version = "0.1.0" -description = "A simple program that uses dmenu compatible menu to select a password to type/copy" -readme = "README.md" -requires-python = ">=3.12" -dependencies = [ - "click>=8.1.7", -] diff --git a/scripts/jpassmenu/src/main.rs b/scripts/jpassmenu/src/main.rs new file mode 100644 index 0000000..279dbdc --- /dev/null +++ b/scripts/jpassmenu/src/main.rs @@ -0,0 +1,156 @@ +use std::{ + ffi::OsStr, + fmt::Write as _, + path::{Path, PathBuf}, +}; + +use clap::Parser; +use duct::cmd; +use miette::{bail, ensure, Context, IntoDiagnostic, Result}; + +fn main() -> Result<()> { + miette::set_panic_hook(); + env_logger::builder() + .filter_level(log::LevelFilter::Info) + .parse_default_env() + .try_init() + .into_diagnostic()?; + Opts::parse().run() +} + +impl Opts { + fn run(self) -> Result<()> { + log::debug!("parsed opts {self:?}"); + let Self { + typeit, + store_dir, + pass_bin, + menu_bin, + menu_args, + } = self; + let store_dir = resolve_home(store_dir); + // Search paths + log::info!("looking for entries in {}", store_dir.display()); + let mut paths = ignore::Walk::new(&store_dir) + .filter_map(|entry| { + let entry = entry.ok()?; + if entry.file_type()?.is_file() + && entry.path().extension() == Some(OsStr::new("gpg")) + { + let path = entry.path(); + Some( + path.strip_prefix(&store_dir) + .unwrap_or(path) + .with_extension("") + .into_boxed_path(), + ) + } else { + None + } + }) + .collect::>>(); + paths.sort_unstable(); + ensure!( + !paths.is_empty(), + "failed to find entries in {}", + store_dir.display() + ); + log::debug!("found entries: {paths:#?}"); + // Concatenate all paths + let paths = paths + .into_iter() + .try_fold(String::new(), |mut acc, it| { + writeln!(acc, "{}", it.display()).map(|_| acc) + }) + .into_diagnostic() + .wrap_err("preparing paths")?; + // Show dynamic menu + let selected = cmd(menu_bin, menu_args) + .stdin_bytes(paths.as_bytes()) + .read() + .into_diagnostic() + .wrap_err("failed to run menu and retrieve the selected entry")?; + let selected = selected.trim(); + if selected.is_empty() { + bail!("no password entry selected"); + } + // Prepare env dir + let env_store = std::env::var_os("PASSWORD_STORE_DIR"); + let set_env = if let Some(env_store) = env_store { + if store_dir != env_store { + Some(store_dir) + } else { + None + } + } else if store_dir == Path::new("~/.password-store") { + None + } else { + Some(store_dir) + }; + // Prepare pass command + let args = if typeit { + vec!["show", selected] + } else { + vec!["show", "-c", selected] + }; + let pass = cmd(pass_bin, args); + let pass = if let Some(env) = set_env { + pass.env("PASSWORD_STORE_DIR", env) + } else { + pass + }; + // Copy password to clipboard + if !typeit { + pass.run() + .into_diagnostic() + .wrap_err("failed to copy password to clipboard")?; + return Ok(()); + } + // Retrieve password + let pass_entry = pass + .read() + .into_diagnostic() + .wrap_err("failed to retrieve password")?; + let Some(password) = pass_entry.lines().next() else { + bail!("failed to retrieve password or entry was empty"); + }; + // Type password with ydotool + cmd("ydotool", &["type", "--file", "-"]) + .stdin_bytes(password.as_bytes()) + .run() + .into_diagnostic() + .wrap_err("failed to type password with ydotool")?; + Ok(()) + } +} + +#[derive(Debug, Parser)] +struct Opts { + /// Type the password instead of copying it to the clipboard + #[arg(long("type"))] + typeit: bool, + #[arg(long, env("PASSWORD_STORE_DIR"), default_value = "~/.password-store")] + store_dir: PathBuf, + /// Path to the pass binary + /// + /// Needs to support `pass show` and `pass show -c` + #[arg(long, default_value = "pass")] + pass_bin: String, + /// Path to the dynamic menu binary + #[arg(long, default_value = "fuzzel")] + menu_bin: String, + /// Args to the dynamic menu + #[arg(long, default_value = "--dmenu")] + menu_args: Vec, +} + +fn resolve_home(path: PathBuf) -> PathBuf { + if let Ok(path) = path.strip_prefix("~") { + if let Some(home) = std::env::var_os("HOME") { + let mut home = PathBuf::from(home); + home.push(path); + return home; + } + } + path +} diff --git a/system/default.nix b/system/default.nix new file mode 100644 index 0000000..3fdd0cf --- /dev/null +++ b/system/default.nix @@ -0,0 +1,129 @@ +{ stylix }: +{ + config, + pkgs, + lib, + ... +}: +let + cfg = config.jconfig; + keysFromGithub = lib.attrsets.mapAttrs' (username: sha256: { + name = "pubkeys/${username}"; + value = { + mode = "0755"; + source = builtins.fetchurl { + inherit sha256; + url = "https://github.com/${username}.keys"; + }; + }; + }) cfg.importSSHKeysFromGithub; +in +{ + imports = [ + ./options.nix + ./gui + stylix.nixosModules.stylix + { stylix = import ./stylix-config.nix { inherit config pkgs; }; } + ]; + + config = lib.mkIf cfg.enable ( + lib.mkMerge [ + { + boot.plymouth = { + inherit (cfg.styling) enable; + }; + + # Enable unlocking the gpg-agent at boot (configured through home.nix) + security.pam.services.login.gnupg.enable = true; + + environment.systemPackages = [ + # CLI tools + pkgs.fd + pkgs.ripgrep + pkgs.du-dust + pkgs.curl + pkgs.zip + pkgs.unzip + ]; + + # Enable dev documentation + documentation.dev = { + inherit (cfg.dev) enable; + }; + programs = { + # Shell prompt + starship = { + enable = true; + settings = lib.mkMerge [ + { + format = "$time$all"; + add_newline = false; + cmd_duration.min_time = 500; + cmd_duration.show_milliseconds = true; + time.disabled = false; + status = { + format = "[$signal_name$common_meaning$maybe_int](red)"; + symbol = "[✗](bold red)"; + disabled = false; + }; + sudo.disabled = false; + } + # Add nerdfont symbols + (lib.mkIf cfg.styling.enable (import ./starship-nerdfont-symbols.nix)) + # Remove the `in`s and `on`s from the prompt + (lib.mkIf cfg.styling.enable (import ./starship-shorter-text.nix)) + ]; + }; + # Default shell + zsh.enable = true; + }; + + environment.etc = keysFromGithub; + services = { + # Enable printer autodiscovery if printing is enabled + avahi = { + inherit (config.services.printing) enable; + nssmdns4 = true; + openFirewall = true; + }; + openssh.authorizedKeysFiles = builtins.map (path: "/etc/${path}") ( + builtins.attrNames keysFromGithub + ); + }; + users.defaultUserShell = pkgs.zsh; + # Open ports for spotifyd + networking.firewall = { + allowedUDPPorts = [ 5353 ]; + allowedTCPPorts = [ 2020 ]; + }; + # Nix Settings + nix = { + gc = { + automatic = true; + dates = "weekly"; + options = "--delete-older-than 30d"; + # run between 0 and 45min after boot if run was missed + randomizedDelaySec = "45min"; + }; + settings = { + use-xdg-base-directories = true; + auto-optimise-store = true; + experimental-features = [ + "nix-command" + "flakes" + ]; + }; + }; + } + # dev configuration + (lib.mkIf cfg.dev.enable { + users.extraUsers = lib.mkIf cfg.dev.jupyter.enable { jupyter.group = "jupyter"; }; + services.jupyter = { + inherit (cfg.dev.jupyter) enable; + group = "jupyter"; + user = "jupyter"; + }; + }) + ] + ); +} diff --git a/system/gui/default.nix b/system/gui/default.nix new file mode 100644 index 0000000..6be652f --- /dev/null +++ b/system/gui/default.nix @@ -0,0 +1,113 @@ +{ + config, + lib, + pkgs, + ... +}: +let + cfg = config.jconfig.gui; + enable = config.jconfig.enable && cfg.enable; + linuxOlderThan6_3 = lib.versionOlder config.boot.kernelPackages.kernel.version "6.3"; +in +{ + config = lib.mkMerge [ + (lib.mkIf enable { + environment.systemPackages = [ + pkgs.adwaita-icon-theme + pkgs.adwaita-qt + pkgs.nordzy-cursor-theme + pkgs.pinentry-qt + ] ++ lib.optional cfg.ydotool.enable pkgs.ydotool; + systemd = { + user.services.ydotool = lib.mkIf cfg.ydotool.enable { + enable = cfg.ydotool.autoStart; + wantedBy = [ "default.target" ]; + description = "Generic command-line automation tool"; + documentation = [ + "man:ydotool(1)" + "man:ydotoold(8)" + ]; + serviceConfig = { + Type = "simple"; + Restart = "always"; + ExecStart = "${pkgs.ydotool}/bin/ydotoold"; + ExecReload = "${pkgs.util-linux}/bin/kill -HUP $MAINPID"; + KillMode = "process"; + TimeoutSec = 180; + }; + }; + # Fix xdg-portals issue issue: https://github.com/NixOS/nixpkgs/issues/189851 + user.extraConfig = '' + DefaultEnvironment="PATH=/run/wrappers/bin:/etc/profiles/per-user/%u/bin:/nix/var/nix/profiles/default/bin:/run/current-system/sw/bin" + ''; + }; + + fonts.fontDir.enable = true; + programs = { + dconf.enable = true; + niri = { + enable = cfg.windowManager; + package = pkgs.niri; # use nixpkgs' package instead of the flake's + }; + }; + security = { + polkit.enable = true; + rtkit.enable = true; # Recommended for pipewire + }; + services = { + flatpak.enable = true; + # Audio + pipewire = { + enable = true; + alsa = { + enable = true; + support32Bit = true; + }; + pulse.enable = true; + wireplumber.enable = true; + }; + # Dbus + dbus.enable = true; + # Virtual Filesystem (for PCManFM) + gvfs.enable = true; + }; + xdg.portal = { + # XDG portals + enable = true; + wlr.enable = true; + extraPortals = [ pkgs.xdg-desktop-portal-gtk ]; + config.preferred = { + # Default to the gtk portal + default = "gtk"; + # Use wlr for screenshots and screen recording + "org.freedesktop.impl.portal.Screenshot" = "wlr"; + }; + # Consider using darkman like upstream + }; + hardware = { + graphics.enable = true; + uinput.enable = true; + steam-hardware.enable = cfg.steamHardwareSupport; + }; + }) + (lib.mkIf (enable && linuxOlderThan6_3 && cfg."8bitdoFix") { + # Udev rules to start or stop systemd service when controller is connected or disconnected + services.udev.extraRules = # udev + '' + # May vary depending on your controller model, find product id using 'lsusb' + SUBSYSTEM=="usb", ATTR{idVendor}=="2dc8", ATTR{idProduct}=="3106", ATTR{manufacturer}=="8BitDo", RUN+="${pkgs.systemd}/bin/systemctl start 8bitdo-ultimate-xinput@2dc8:3106" + # This device (2dc8:3016) is "connected" when the above device disconnects + SUBSYSTEM=="usb", ATTR{idVendor}=="2dc8", ATTR{idProduct}=="3016", ATTR{manufacturer}=="8BitDo", RUN+="${pkgs.systemd}/bin/systemctl stop 8bitdo-ultimate-xinput@2dc8:3106" + ''; + + # Systemd service which starts xboxdrv in xbox360 mode + systemd.services."8bitdo-ultimate-xinput@" = { + unitConfig.Description = "8BitDo Ultimate Controller XInput mode xboxdrv daemon"; + serviceConfig = { + Type = "simple"; + ExecStart = "${pkgs.xboxdrv}/bin/xboxdrv --mimic-xpad --silent --type xbox360 --device-by-id %I --force-feedback"; + }; + }; + }) + ]; +} diff --git a/system/options.nix b/system/options.nix new file mode 100644 index 0000000..51ac162 --- /dev/null +++ b/system/options.nix @@ -0,0 +1,119 @@ +{ lib, ... }: +let + inherit (lib) types; + # Like mkEnableOption but defaults to true + mkDisableOption = + option: + (lib.mkEnableOption option) + // { + default = true; + example = false; + }; + mkImageOption = + { + description, + url, + sha256 ? "", + }: + lib.mkOption { + inherit description; + type = types.path; + default = builtins.fetchurl { inherit url sha256; }; + defaultText = lib.literalMD "![${description}](${url})"; + }; + + gui.options = { + enable = lib.mkEnableOption "jalil's default gui configuration."; + # Fix for using Xinput mode on 8bitdo Ultimate C controller + # Inspired by https://aur.archlinux.org/packages/8bitdo-ultimate-controller-udev + # Adapted from: https://gist.github.com/interdependence/28452fbfbe692986934fbe1e54c920d4 + "8bitdoFix" = mkDisableOption "a fix for 8bitdo controllers"; + steamHardwareSupport = mkDisableOption "steam hardware support"; + ydotool = lib.mkOption { + description = "Jalil's default ydotool configuration."; + default = { }; + type = types.submodule { + options.enable = mkDisableOption "ydotool"; + options.autoStart = mkDisableOption "autostarting ydotool at login"; + }; + }; + windowManager = lib.mkOption { + description = "Window manager configuration"; + default = { }; + type = types.submodule { + options = { + enable = mkDisableOption "window manager"; + windowManager = lib.mkOption { + description = "Which window manager to enable"; + type = types.enum [ "niri" ]; + default = "niri"; + }; + }; + }; + }; + }; + + styling.options = { + enable = mkDisableOption "jalil's default styling (disables stylix)"; + wallpaper = mkImageOption { + description = "The wallpaper to use."; + url = "https://raw.githubusercontent.com/lunik1/nixos-logo-gruvbox-wallpaper/d4937c424fad79c1136a904599ba689fcf8d0fad/png/gruvbox-dark-rainbow.png"; + sha256 = "036gqhbf6s5ddgvfbgn6iqbzgizssyf7820m5815b2gd748jw8zc"; + }; + bootLogo = mkImageOption { + description = "The logo used by plymouth at boot."; + # http://xenia-linux-site.glitch.me/images/cathodegaytube-splash.png + url = "https://efimero.github.io/xenia-images/cathodegaytube-splash.png"; + sha256 = "qKugUfdRNvMwSNah+YmMepY3Nj6mWlKFh7jlGlAQDo8="; + }; + }; + + config.options = { + enable = lib.mkEnableOption "jalil's default configuration."; + dev = lib.mkOption { + description = "Options for setting up a dev environment"; + default = { }; + type = types.submodule { + options.enable = lib.mkEnableOption "dev configuration"; + options.jupyter.enable = lib.mkEnableOption "jupyter configuration"; + }; + }; + gui = lib.mkOption { + description = "Jalil's default configuration for a NixOS gui."; + default = { }; + type = types.submodule gui; + }; + styling = lib.mkOption { + description = "Jalil's styling options"; + default = { }; + type = types.submodule styling; + }; + importSSHKeysFromGithub = lib.mkOption { + description = '' + Import public ssh keys from a github username. + + This will fetch the keys from https://github.com/$${username}.keys. + + The format is `"$${github-username}" = $${sha256-hash}`. The example + will try to fetch the keys from . + + **Warning**: this will interfere with services like gitea that override + the default ssh behaviour. In that case you want to use + `users.users..openssh.authorizedKeys.keyFiles` on the users you + want to allow ssh logins. + ''; + default = { }; + example = { + "jalil-salame" = "sha256:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; + }; + type = types.attrsOf types.str; + }; + }; +in +{ + options.jconfig = lib.mkOption { + description = "Jalil's default NixOS configuration."; + default = { }; + type = types.submodule config; + }; +} diff --git a/system/starship-nerdfont-symbols.nix b/system/starship-nerdfont-symbols.nix new file mode 100644 index 0000000..2032150 --- /dev/null +++ b/system/starship-nerdfont-symbols.nix @@ -0,0 +1,89 @@ +{ + aws.symbol = " "; + buf.symbol = " "; + c.symbol = " "; + conda.symbol = " "; + crystal.symbol = " "; + dart.symbol = " "; + directory.read_only = " 󰌾"; + docker_context.symbol = " "; + elixir.symbol = " "; + elm.symbol = " "; + fennel.symbol = " "; + fossil_branch.symbol = " "; + git_branch.symbol = " "; + git_commit.tag_symbol = "  "; + golang.symbol = " "; + gradle.symbol = " "; + guix_shell.symbol = " "; + haskell.symbol = " "; + haxe.symbol = " "; + hg_branch.symbol = " "; + hostname.ssh_symbol = " "; + java.symbol = " "; + julia.symbol = " "; + kotlin.symbol = " "; + lua.symbol = " "; + memory_usage.symbol = "󰍛 "; + meson.symbol = "󰔷 "; + nim.symbol = "󰆥 "; + nix_shell.symbol = " "; + nodejs.symbol = " "; + ocaml.symbol = " "; + package.symbol = "󰏗 "; + perl.symbol = " "; + php.symbol = " "; + pijul_channel.symbol = " "; + python.symbol = " "; + rlang.symbol = "󰟔 "; + ruby.symbol = " "; + rust.symbol = "󱘗 "; + scala.symbol = " "; + swift.symbol = " "; + zig.symbol = " "; + os.symbols = { + Alpaquita = " "; + Alpine = " "; + AlmaLinux = " "; + Amazon = " "; + Android = " "; + Arch = " "; + Artix = " "; + CentOS = " "; + Debian = " "; + DragonFly = " "; + Emscripten = " "; + EndeavourOS = " "; + Fedora = " "; + FreeBSD = " "; + Garuda = "󰛓 "; + Gentoo = " "; + HardenedBSD = "󰞌 "; + Illumos = "󰈸 "; + Kali = " "; + Linux = " "; + Mabox = " "; + Macos = " "; + Manjaro = " "; + Mariner = " "; + MidnightBSD = " "; + Mint = " "; + NetBSD = " "; + NixOS = " "; + OpenBSD = "󰈺 "; + openSUSE = " "; + OracleLinux = "󰌷 "; + Pop = " "; + Raspbian = " "; + Redhat = " "; + RedHatEnterprise = " "; + RockyLinux = " "; + Redox = "󰀘 "; + Solus = "󰠳 "; + SUSE = " "; + Ubuntu = " "; + Unknown = " "; + Void = " "; + Windows = "󰍲 "; + }; +} diff --git a/system/starship-shorter-text.nix b/system/starship-shorter-text.nix new file mode 100644 index 0000000..605a53a --- /dev/null +++ b/system/starship-shorter-text.nix @@ -0,0 +1,66 @@ +{ + aws.format = "[$symbol($profile)(\\($region\\))(\\[$duration\\])]($style) "; + bun.format = "[$symbol($version)]($style) "; + c.format = "[$symbol($version(-$name))]($style) "; + cmake.format = "[$symbol($version)]($style) "; + cmd_duration.format = "[⏱ $duration]($style) "; + cobol.format = "[$symbol($version)]($style) "; + conda.format = "[$symbol$environment]($style) "; + crystal.format = "[$symbol($version)]($style) "; + daml.format = "[$symbol($version)]($style) "; + dart.format = "[$symbol($version)]($style) "; + deno.format = "[$symbol($version)]($style) "; + docker_context.format = "[$symbol$context]($style) "; + dotnet.format = "[$symbol($version)(🎯 $tfm)]($style) "; + elixir.format = "[$symbol($version \\(OTP $otp_version\\))]($style) "; + elm.format = "[$symbol($version)]($style) "; + erlang.format = "[$symbol($version)]($style) "; + fennel.format = "[$symbol($version)]($style) "; + fossil_branch.format = "[$symbol$branch]($style) "; + gcloud.format = "[$symbol$account(@$domain)(\\($region\\))]($style) "; + git_branch.format = "[$symbol$branch]($style) "; + git_status.format = "[$all_status$ahead_behind]($style) "; + golang.format = "[$symbol($version)]($style) "; + gradle.format = "[$symbol($version)]($style) "; + guix_shell.format = "[$symbol]($style) "; + haskell.format = "[$symbol($version)]($style) "; + haxe.format = "[$symbol($version)]($style) "; + helm.format = "[$symbol($version)]($style) "; + hg_branch.format = "[$symbol$branch]($style) "; + java.format = "[$symbol($version)]($style) "; + julia.format = "[$symbol($version)]($style) "; + kotlin.format = "[$symbol($version)]($style) "; + kubernetes.format = "[$symbol$context( \\($namespace\\))]($style) "; + lua.format = "[$symbol($version)]($style) "; + memory_usage.format = "$symbol[$ram( | $swap)]($style) "; + meson.format = "[$symbol$project]($style) "; + nim.format = "[$symbol($version)]($style) "; + nix_shell.format = "[$symbol$state( \\($name\\))]($style) "; + nodejs.format = "[$symbol($version)]($style) "; + ocaml.format = "[$symbol($version)(\\($switch_indicator$switch_name\\))]($style) "; + opa.format = "[$symbol($version)]($style) "; + openstack.format = "[$symbol$cloud(\\($project\\))]($style) "; + os.format = "[$symbol]($style) "; + package.format = "[$symbol$version]($style) "; + perl.format = "[$symbol($version)]($style) "; + php.format = "[$symbol($version)]($style) "; + pijul_channel.format = "[$symbol$channel]($style) "; + pulumi.format = "[$symbol$stack]($style) "; + purescript.format = "[$symbol($version)]($style) "; + python.format = "[\${symbol}\${pyenv_prefix}(\${version})(\\($virtualenv\\))]($style) "; + raku.format = "[$symbol($version-$vm_version)]($style) "; + red.format = "[$symbol($version)]($style) "; + ruby.format = "[$symbol($version)]($style) "; + rust.format = "[$symbol($version)]($style) "; + scala.format = "[$symbol($version)]($style) "; + spack.format = "[$symbol$environment]($style) "; + sudo.format = "[as $symbol]($style) "; + swift.format = "[$symbol($version)]($style) "; + terraform.format = "[$symbol$workspace]($style) "; + time.format = "[$time]($style) "; + username.format = "[$user]($style) "; + vagrant.format = "[$symbol($version)]($style) "; + vlang.format = "[$symbol($version)]($style) "; + zig.format = "[$symbol($version)]($style) "; + solidity.format = "[$symbol($version)]($style) "; +} diff --git a/system/stylix-config.nix b/system/stylix-config.nix new file mode 100644 index 0000000..a4e75d8 --- /dev/null +++ b/system/stylix-config.nix @@ -0,0 +1,36 @@ +{ config, pkgs }: +let + cfg = config.jconfig.styling; +in +{ + inherit (cfg) enable; + image = cfg.wallpaper; + base16Scheme = "${pkgs.base16-schemes}/share/themes/gruvbox-dark-hard.yaml"; + polarity = "dark"; + fonts = { + monospace = { + name = "JetBrains Mono"; + package = pkgs.jetbrains-mono; + }; + sansSerif = { + name = "Noto Sans"; + package = pkgs.noto-fonts; + }; + serif = { + name = "Noto Serif"; + package = pkgs.noto-fonts; + }; + emoji = { + package = pkgs.noto-fonts-emoji; + name = "Noto Color Emoji"; + }; + sizes.popups = 12; + }; + targets = { + plymouth = { + logoAnimated = false; + logo = cfg.bootLogo; + }; + nixvim.enable = false; + }; +}