diff --git a/.envrc b/.envrc index 49bacf7..e483044 100644 --- a/.envrc +++ b/.envrc @@ -1,10 +1,11 @@ # 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 8d44b1d..3199e04 100644 --- a/.forgejo/workflows/check.yml +++ b/.forgejo/workflows/check.yml @@ -1,52 +1,92 @@ on: push: jobs: - check: + check-fmt: runs-on: nixos steps: - - uses: "https://git.salame.cl/actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683" # v4 - - name: Run checks + - uses: https://git.salame.cl/actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 + - run: nix --version + - name: Run treefmt run: | - nix --version - nix-fast-build --max-jobs 2 --no-nom --skip-cached --no-link \ - --flake ".#checks.$(nix eval --raw --impure --expr builtins.currentSystem)" - check-renovaterc: + 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: + - audiomenu + - docs + - docs-home-markdown + - docs-nixos-markdown + - docs-nvim-markdown + - jpassmenu + - nvim + - nvim-headless + - nvim-no-lsps + - nvim-no-ts + - nvim-small + - search 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-packages: - runs-on: nixos - needs: check - steps: - - uses: "https://git.salame.cl/actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683" # v4 + - run: nix --version - name: Build target + env: + PACKAGE: ${{ matrix.package }} run: | - nix --version - nix-fast-build --max-jobs 2 --no-nom --skip-cached --no-link \ - --flake ".#packages.$(nix eval --raw --impure --expr builtins.currentSystem)" + # 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-packages + needs: + - build-package + - check-nvim steps: - uses: "https://git.salame.cl/actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683" # v4 + - run: nix --version - name: Build VM configuration run: | - nix --version 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' report-size: runs-on: nixos needs: - - build-packages - build-vm + - build-hm 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@5c40a31e3e2ed0ea28f8ba68deca41d05fdf2e71" # main + uses: "https://git.salame.cl/jalil/nix-flake-outputs-size@838f2050208b41c339803a1111608d7182bbda3e" # 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 new file mode 100644 index 0000000..ab1aac5 --- /dev/null +++ b/.forgejo/workflows/renovate.yml @@ -0,0 +1,14 @@ +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/docs/book.toml b/docs/book.toml index 77ec9d4..aa7e72e 100644 --- a/docs/book.toml +++ b/docs/book.toml @@ -5,6 +5,12 @@ multilingual = false src = "src" title = "Jalil's NixOS configuration modules" +[build] +create-missing = false + [preprocessor.toc] command = "mdbook-toc" renderer = ["html"] + +[output.html] +git-repository-url = "https://github.com/jalil-salame/configuration.nix" diff --git a/example-hm/home.nix b/example-hm/home.nix new file mode 100644 index 0000000..4e86064 --- /dev/null +++ b/example-hm/home.nix @@ -0,0 +1,70 @@ +{ + 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/vm-config.nix b/example-vm/vm-config.nix index 1b2b4d0..67e38a7 100644 --- a/example-vm/vm-config.nix +++ b/example-vm/vm-config.nix @@ -31,4 +31,6 @@ # 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 ce3e3c5..1b806a6 100644 --- a/flake-modules/default.nix +++ b/flake-modules/default.nix @@ -1,26 +1,21 @@ { inputs, ... }: -let - overlays = builtins.attrValues inputs.self.overlays; -in { imports = [ inputs.treefmt-nix.flakeModule ./devshells.nix ./docs.nix - ./example-vm.nix + ./example-configs.nix ./nixos-modules.nix ./home-modules.nix ./nixvim-modules.nix ./overlays.nix - ./scripts.nix + ../scripts ]; 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 962c4bf..c387269 100644 --- a/flake-modules/devshells.nix +++ b/flake-modules/devshells.nix @@ -6,6 +6,7 @@ _: { buildInputs = [ pkgs.just self'.packages.nvim + pkgs.uv ]; 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 d296e38..594d592 100644 --- a/flake-modules/docs.nix +++ b/flake-modules/docs.nix @@ -62,7 +62,7 @@ ''; # FIXME: only add the `/configuration.nix/` part for GH CI nativeBuildInputs = [ pkgs.mdbook-toc ]; - buildPhase = "${pkgs.mdbook}/bin/mdbook build --dest-dir \"$out\""; + buildPhase = "${pkgs.mdbook}/bin/mdbook build --dest-dir $out"; }; }; }; diff --git a/flake-modules/example-configs.nix b/flake-modules/example-configs.nix new file mode 100644 index 0000000..362e36a --- /dev/null +++ b/flake-modules/example-configs.nix @@ -0,0 +1,33 @@ +{ 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 deleted file mode 100644 index b21085d..0000000 --- a/flake-modules/example-vm.nix +++ /dev/null @@ -1,19 +0,0 @@ -{ 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 pkgs; - modules = [ - inputs.self.nixosModules.default - ../example-vm # import vm configuration - { nix.registry.nixpkgs.flake = inputs.nixpkgs; } # pin nixpkgs to the one used by the system - ]; - }; - -} diff --git a/flake-modules/home-modules.nix b/flake-modules/home-modules.nix index 09c500d..6c9ae51 100644 --- a/flake-modules/home-modules.nix +++ b/flake-modules/home-modules.nix @@ -1,12 +1,11 @@ { self, inputs, ... }: { - # FIXME(25.05): this version of HM should have the flake module - # imports = [ inputs.home-manager.flakeModules.home-manager ]; + imports = [ inputs.home-manager.flakeModules.home-manager ]; flake.homeModules = let defaultModules = [ - inputs.nixvim.homeManagerModules.nixvim + inputs.nixvim.homeModules.nixvim self.nixvimModules.homeManager ../modules/hm ]; @@ -15,11 +14,11 @@ }; standalone = { imports = defaultModules ++ [ - inputs.stylix.homeManagerModules.stilyx + inputs.stylix.homeModules.stylix ( - { config, ... }: - { - stylix.image = config.jhome.sway.background; + { lib, config, ... }: + lib.mkIf config.jhome.gui.enable { + stylix.image = config.jhome.gui.sway.background; } ) ]; diff --git a/flake-modules/nixos-modules.nix b/flake-modules/nixos-modules.nix index 44ec630..ef8355e 100644 --- a/flake-modules/nixos-modules.nix +++ b/flake-modules/nixos-modules.nix @@ -9,7 +9,6 @@ let nixosModule = { imports = [ - inputs.niri.nixosModules.niri inputs.stylix.nixosModules.stylix inputs.home-manager.nixosModules.home-manager ../modules/nixos diff --git a/flake-modules/scripts.nix b/flake-modules/scripts.nix deleted file mode 100644 index 590f6a1..0000000 --- a/flake-modules/scripts.nix +++ /dev/null @@ -1,14 +0,0 @@ -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 5803f77..404f043 100644 --- a/flake.lock +++ b/flake.lock @@ -5,11 +5,11 @@ "fromYaml": "fromYaml" }, "locked": { - "lastModified": 1732200724, - "narHash": "sha256-+R1BH5wHhfnycySb7Sy5KbYEaTJZWm1h+LW1OtyhiTs=", + "lastModified": 1746562888, + "narHash": "sha256-YgNJQyB5dQiwavdDFBMNKk1wyS77AtdgDk/VtU6wEaI=", "owner": "SenchoPens", "repo": "base16.nix", - "rev": "153d52373b0fb2d343592871009a286ec8837aec", + "rev": "806a1777a5db2a1ef9d5d6f493ef2381047f2b89", "type": "github" }, "original": { @@ -70,11 +70,11 @@ "firefox-gnome-theme": { "flake": false, "locked": { - "lastModified": 1743774811, - "narHash": "sha256-oiHLDHXq7ymsMVYSg92dD1OLnKLQoU/Gf2F1GoONLCE=", + "lastModified": 1744642301, + "narHash": "sha256-5A6LL7T0lttn1vrKsNOKUk9V0ittdW0VEqh6AtefxJ4=", "owner": "rafaelmardojai", "repo": "firefox-gnome-theme", - "rev": "df53a7a31872faf5ca53dd0730038a62ec63ca9e", + "rev": "59e3de00f01e5adb851d824cf7911bd90c31083a", "type": "github" }, "original": { @@ -90,11 +90,11 @@ ] }, "locked": { - "lastModified": 1743550720, - "narHash": "sha256-hIshGgKZCgWh6AYJpJmRgFdR3WUbkY04o82X05xqQiY=", + "lastModified": 1749398372, + "narHash": "sha256-tYBdgS56eXYaWVW3fsnPQ/nFlgWi/Z2Ymhyu21zVM98=", "owner": "hercules-ci", "repo": "flake-parts", - "rev": "c621e8422220273271f52058f618c94e405bb0f5", + "rev": "9305fe4e5c2a6fcf5ba6a3ff155720fbe4076569", "type": "github" }, "original": { @@ -205,16 +205,16 @@ "gnome-shell": { "flake": false, "locked": { - "lastModified": 1732369855, - "narHash": "sha256-JhUWbcYPjHO3Xs3x9/Z9RuqXbcp5yhPluGjwsdE2GMg=", + "lastModified": 1744584021, + "narHash": "sha256-0RJ4mJzf+klKF4Fuoc8VN8dpQQtZnKksFmR2jhWE1Ew=", "owner": "GNOME", "repo": "gnome-shell", - "rev": "dadd58f630eeea41d645ee225a63f719390829dc", + "rev": "52c517c8f6c199a1d6f5118fae500ef69ea845ae", "type": "github" }, "original": { "owner": "GNOME", - "ref": "47.2", + "ref": "48.1", "repo": "gnome-shell", "type": "github" } @@ -226,16 +226,16 @@ ] }, "locked": { - "lastModified": 1744743431, - "narHash": "sha256-iyn/WBYDc7OtjSawbegINDe/gIkok888kQxk3aVnkgg=", + "lastModified": 1750792728, + "narHash": "sha256-Lh3dopA8DdY+ZoaAJPrtkZOZaFEJGSYjOdAYYgOPgE4=", "owner": "nix-community", "repo": "home-manager", - "rev": "c61bfe3ae692f42ce688b5865fac9e0de58e1387", + "rev": "366f00797b1efb70f2882d3da485e3c10fd3d557", "type": "github" }, "original": { "owner": "nix-community", - "ref": "release-24.11", + "ref": "release-25.05", "repo": "home-manager", "type": "github" } @@ -252,16 +252,16 @@ ] }, "locked": { - "lastModified": 1729958008, - "narHash": "sha256-EiOq8jF4Z/zQe0QYVc3+qSKxRK//CFHMB84aYrYGwEs=", + "lastModified": 1748294338, + "narHash": "sha256-FVO01jdmUNArzBS7NmaktLdGA5qA3lUMJ4B7a05Iynw=", "owner": "NuschtOS", "repo": "ixx", - "rev": "9fd01aad037f345350eab2cd45e1946cc66da4eb", + "rev": "cc5f390f7caf265461d4aab37e98d2292ebbdb85", "type": "github" }, "original": { "owner": "NuschtOS", - "ref": "v0.0.6", + "ref": "v0.0.8", "repo": "ixx", "type": "github" } @@ -269,15 +269,15 @@ "lix": { "flake": false, "locked": { - "lastModified": 1737234286, - "narHash": "sha256-pgDJZjj4jpzkFxsqBTI/9Yb0n3gW+DvDtuv9SwQZZcs=", - "rev": "079528098f5998ba13c88821a2eca1005c1695de", + "lastModified": 1751235704, + "narHash": "sha256-J4ycLoXHPsoBoQtEXFCelL4xlq5pT8U9tNWNKm43+YI=", + "rev": "1d7368585eebaa2c4bdbcb88fe600cfb2239b2c6", "type": "tarball", - "url": "https://git.lix.systems/api/v1/repos/lix-project/lix/archive/079528098f5998ba13c88821a2eca1005c1695de.tar.gz?rev=079528098f5998ba13c88821a2eca1005c1695de" + "url": "https://git.lix.systems/api/v1/repos/lix-project/lix/archive/1d7368585eebaa2c4bdbcb88fe600cfb2239b2c6.tar.gz?rev=1d7368585eebaa2c4bdbcb88fe600cfb2239b2c6" }, "original": { "type": "tarball", - "url": "https://git.lix.systems/lix-project/lix/archive/release-2.92.tar.gz" + "url": "https://git.lix.systems/lix-project/lix/archive/release-2.93.tar.gz" } }, "lix-module": { @@ -290,91 +290,28 @@ ] }, "locked": { - "lastModified": 1742943028, - "narHash": "sha256-fprwZKE1uMzO9tiWWOrmLWBW3GPkMayQfb0xOvVFIno=", - "rev": "3fae818597ca2f1474de62022f850c23be50528d", + "lastModified": 1751240025, + "narHash": "sha256-SXUAlxpjPRkArRMHy5+Hdi+PiC+ND9yzzIjiaHmTvQU=", + "rev": "8b1094356f4723d6e89d3f8a95b333ee16d9ab02", "type": "tarball", - "url": "https://git.lix.systems/api/v1/repos/lix-project/nixos-module/archive/3fae818597ca2f1474de62022f850c23be50528d.tar.gz?rev=3fae818597ca2f1474de62022f850c23be50528d" + "url": "https://git.lix.systems/api/v1/repos/lix-project/nixos-module/archive/8b1094356f4723d6e89d3f8a95b333ee16d9ab02.tar.gz?rev=8b1094356f4723d6e89d3f8a95b333ee16d9ab02" }, "original": { "type": "tarball", - "url": "https://git.lix.systems/lix-project/nixos-module/archive/release-2.92.tar.gz" - } - }, - "niri": { - "inputs": { - "niri-stable": "niri-stable", - "niri-unstable": [], - "nixpkgs": [ - "unstable" - ], - "nixpkgs-stable": [ - "nixpkgs" - ], - "xwayland-satellite-stable": "xwayland-satellite-stable", - "xwayland-satellite-unstable": [] - }, - "locked": { - "lastModified": 1742108116, - "narHash": "sha256-NrV9ysEfSbeRUPo0jdCBeesuNLTVrpHGXg40snH1YGE=", - "owner": "sodiboo", - "repo": "niri-flake", - "rev": "824f10012de455a1d0ef795a605f28948ee10467", - "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" + "url": "https://git.lix.systems/lix-project/nixos-module/archive/release-2.93.tar.gz" } }, "nixpkgs": { "locked": { - "lastModified": 1744440957, - "narHash": "sha256-FHlSkNqFmPxPJvy+6fNLaNeWnF1lZSgqVCl/eWaJRc4=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "26d499fc9f1d567283d5d56fcf367edd815dba1d", - "type": "github" + "lastModified": 1751272999, + "narHash": "sha256-iAmjAfHulye0CGJuiVWKQhVlKx0szRYJb7KrnmMsx58=", + "rev": "b43c397f6c213918d6cfe6e3550abfe79b5d1c51", + "type": "tarball", + "url": "https://releases.nixos.org/nixos/25.05/nixos-25.05.805252.b43c397f6c21/nixexprs.tar.xz?rev=b43c397f6c213918d6cfe6e3550abfe79b5d1c51" }, "original": { - "owner": "NixOS", - "ref": "nixos-24.11", - "repo": "nixpkgs", - "type": "github" - } - }, - "nixpkgs_2": { - "locked": { - "lastModified": 1744157173, - "narHash": "sha256-bWSjxDwq7iVePrhmA7tY2dyMWHuNJo8knkO4y+q4ZkY=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "6a39c6e495eefabc935d8ddf66aa45d85b85fa3f", - "type": "github" - }, - "original": { - "owner": "NixOS", - "ref": "nixpkgs-unstable", - "repo": "nixpkgs", - "type": "github" + "type": "tarball", + "url": "https://channels.nixos.org/nixos-25.05/nixexprs.tar.xz" } }, "nixvim": { @@ -382,15 +319,20 @@ "flake-parts": [ "flake-parts" ], - "nixpkgs": "nixpkgs_2", - "nuschtosSearch": [] + "nixpkgs": [ + "unstable" + ], + "nuschtosSearch": [], + "systems": [ + "systems" + ] }, "locked": { - "lastModified": 1744874965, - "narHash": "sha256-eOnMgAWsjqOhGRoY9smkKlNQcCz9R89mgiKwLrCIYBE=", + "lastModified": 1751144320, + "narHash": "sha256-KJsKiGfkfXFB23V26NQ1p+UPsexI6NKtivnrwSlWWdQ=", "owner": "nix-community", "repo": "nixvim", - "rev": "500b56f023e0f095ffee2d4f79e58aa09e6b0719", + "rev": "ceb52aece5d571b37096945c2815604195a04eb4", "type": "github" }, "original": { @@ -411,11 +353,11 @@ ] }, "locked": { - "lastModified": 1744375525, - "narHash": "sha256-/Wf5Ca0DmV+y+qVBDXX8HAfAvSQI6y5oE27dv6t1jXk=", + "lastModified": 1749730855, + "narHash": "sha256-L3x2nSlFkXkM6tQPLJP3oCBMIsRifhIDPMQQdHO5xWo=", "owner": "NuschtOS", "repo": "search", - "rev": "c0e7d3bda11e2cfad692d205d82757078475957a", + "rev": "8dfe5879dd009ff4742b668d9c699bc4b9761742", "type": "github" }, "original": { @@ -429,17 +371,13 @@ "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": [ - "nixvim", - "nixpkgs" - ] + "unstable": "unstable" } }, "stylix": { @@ -450,9 +388,8 @@ "base16-vim": "base16-vim", "firefox-gnome-theme": "firefox-gnome-theme", "flake-compat": [], - "flake-utils": [ - "lix-module", - "flake-utils" + "flake-parts": [ + "flake-parts" ], "git-hooks": "git-hooks", "gnome-shell": "gnome-shell", @@ -462,24 +399,27 @@ "nixpkgs": [ "nixpkgs" ], + "nur": [], "systems": [ "systems" ], "tinted-foot": "tinted-foot", "tinted-kitty": "tinted-kitty", - "tinted-tmux": "tinted-tmux" + "tinted-schemes": "tinted-schemes", + "tinted-tmux": "tinted-tmux", + "tinted-zed": "tinted-zed" }, "locked": { - "lastModified": 1744152965, - "narHash": "sha256-LWUeN1+bH3k46fwtIv0bNgtmkqB0UduyX7T2i+230n0=", - "owner": "danth", + "lastModified": 1751297908, + "narHash": "sha256-aoXASRGxR8mdXs9SU88x8yVDLs9cEou49ulWEHyn1s4=", + "owner": "nix-community", "repo": "stylix", - "rev": "8748db082ca15d32243c86e5d785d5dfc8a65719", + "rev": "d859a4a6e079ffdae115bfe7b11cd69668b7f356", "type": "github" }, "original": { - "owner": "danth", - "ref": "release-24.11", + "owner": "nix-community", + "ref": "release-25.05", "repo": "stylix", "type": "github" } @@ -519,28 +459,43 @@ "tinted-kitty": { "flake": false, "locked": { - "lastModified": 1716423189, - "narHash": "sha256-2xF3sH7UIwegn+2gKzMpFi3pk5DlIlM18+vj17Uf82U=", + "lastModified": 1735730497, + "narHash": "sha256-4KtB+FiUzIeK/4aHCKce3V9HwRvYaxX+F1edUrfgzb8=", "owner": "tinted-theming", "repo": "tinted-kitty", - "rev": "eb39e141db14baef052893285df9f266df041ff8", + "rev": "de6f888497f2c6b2279361bfc790f164bfd0f3fa", "type": "github" }, "original": { "owner": "tinted-theming", "repo": "tinted-kitty", - "rev": "eb39e141db14baef052893285df9f266df041ff8", + "type": "github" + } + }, + "tinted-schemes": { + "flake": false, + "locked": { + "lastModified": 1744974599, + "narHash": "sha256-Fg+rdGs5FAgfkYNCs74lnl8vkQmiZVdBsziyPhVqrlY=", + "owner": "tinted-theming", + "repo": "schemes", + "rev": "28c26a621123ad4ebd5bbfb34ab39421c0144bdd", + "type": "github" + }, + "original": { + "owner": "tinted-theming", + "repo": "schemes", "type": "github" } }, "tinted-tmux": { "flake": false, "locked": { - "lastModified": 1743296873, - "narHash": "sha256-8IQulrb1OBSxMwdKijO9fB70ON//V32dpK9Uioy7FzY=", + "lastModified": 1745111349, + "narHash": "sha256-udV+nHdpqgkJI9D0mtvvAzbqubt9jdifS/KhTTbJ45w=", "owner": "tinted-theming", "repo": "tinted-tmux", - "rev": "af5152c8d7546dfb4ff6df94080bf5ff54f64e3a", + "rev": "e009f18a01182b63559fb28f1c786eb027c3dee9", "type": "github" }, "original": { @@ -549,6 +504,22 @@ "type": "github" } }, + "tinted-zed": { + "flake": false, + "locked": { + "lastModified": 1725758778, + "narHash": "sha256-8P1b6mJWyYcu36WRlSVbuj575QWIFZALZMTg5ID/sM4=", + "owner": "tinted-theming", + "repo": "base16-zed", + "rev": "122c9e5c0e6f27211361a04fae92df97940eccf9", + "type": "github" + }, + "original": { + "owner": "tinted-theming", + "repo": "base16-zed", + "type": "github" + } + }, "treefmt-nix": { "inputs": { "nixpkgs": [ @@ -556,11 +527,11 @@ ] }, "locked": { - "lastModified": 1744961264, - "narHash": "sha256-aRmUh0AMwcbdjJHnytg1e5h5ECcaWtIFQa6d9gI85AI=", + "lastModified": 1750931469, + "narHash": "sha256-0IEdQB1nS+uViQw4k3VGUXntjkDp7aAlqcxdewb/hAc=", "owner": "numtide", "repo": "treefmt-nix", - "rev": "8d404a69efe76146368885110f29a2ca3700bee6", + "rev": "ac8e6f32e11e9c7f153823abc3ab007f2a65d3e1", "type": "github" }, "original": { @@ -569,21 +540,17 @@ "type": "github" } }, - "xwayland-satellite-stable": { - "flake": false, + "unstable": { "locked": { - "lastModified": 1739246919, - "narHash": "sha256-/hBM43/Gd0/tW+egrhlWgOIISeJxEs2uAOIYVpfDKeU=", - "owner": "Supreeeme", - "repo": "xwayland-satellite", - "rev": "44590a416d4a3e8220e19e29e0b6efe64a80315d", - "type": "github" + "lastModified": 1751104079, + "narHash": "sha256-6RZXUJorxswQLvrBbD2yhgh3BrgdUAvg9t5qfkuzI/g=", + "rev": "30e2e2857ba47844aa71991daa6ed1fc678bcbb7", + "type": "tarball", + "url": "https://releases.nixos.org/nixos/unstable/nixos-25.11pre822156.30e2e2857ba4/nixexprs.tar.xz?rev=30e2e2857ba47844aa71991daa6ed1fc678bcbb7" }, "original": { - "owner": "Supreeeme", - "ref": "v0.5.1", - "repo": "xwayland-satellite", - "type": "github" + "type": "tarball", + "url": "https://channels.nixos.org/nixos-unstable/nixexprs.tar.xz" } } }, diff --git a/flake.nix b/flake.nix index 5f68856..795adef 100644 --- a/flake.nix +++ b/flake.nix @@ -8,11 +8,11 @@ # Flake inputs inputs = { - nixpkgs.url = "github:NixOS/nixpkgs/nixos-24.11"; - unstable.follows = "nixvim/nixpkgs"; + nixpkgs.url = "https://channels.nixos.org/nixos-25.05/nixexprs.tar.xz"; + unstable.url = "https://channels.nixos.org/nixos-unstable/nixexprs.tar.xz"; # Lix lix-module = { - url = "https://git.lix.systems/lix-project/nixos-module/archive/release-2.92.tar.gz"; + url = "https://git.lix.systems/lix-project/nixos-module/archive/release-2.93.tar.gz"; inputs = { nixpkgs.follows = "nixpkgs"; flake-utils.inputs.systems.follows = "systems"; @@ -20,15 +20,16 @@ }; # Modules home-manager = { - url = "github:nix-community/home-manager/release-24.11"; + url = "github:nix-community/home-manager/release-25.05"; inputs.nixpkgs.follows = "nixpkgs"; }; stylix = { - url = "github:danth/stylix/release-24.11"; + url = "github:nix-community/stylix/release-25.05"; inputs = { nixpkgs.follows = "nixpkgs"; - flake-utils.follows = "lix-module/flake-utils"; + flake-parts.follows = "flake-parts"; systems.follows = "systems"; + nur.follows = ""; home-manager.follows = "home-manager"; # disable optional inputs @@ -39,21 +40,12 @@ url = "github:nix-community/nixvim"; inputs = { flake-parts.follows = "flake-parts"; + systems.follows = "systems"; + nixpkgs.follows = "unstable"; # disable optional inputs nuschtosSearch.follows = ""; }; }; - niri = { - url = "github:sodiboo/niri-flake"; - inputs = { - # Deduplicate - nixpkgs.follows = "unstable"; - nixpkgs-stable.follows = "nixpkgs"; - # Unused - niri-unstable.follows = ""; - xwayland-satellite-unstable.follows = ""; - }; - }; flake-parts = { url = "github:hercules-ci/flake-parts"; inputs.nixpkgs-lib.follows = "nixpkgs"; diff --git a/justfile b/justfile index 4021089..483e46c 100644 --- a/justfile +++ b/justfile @@ -3,10 +3,10 @@ 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 --flake .#vm --print-build-logs + nixos-rebuild build-vm --fallback --flake .#vm --print-build-logs run-vm: build-vm QEMU_OPTS="$QEMU_OPTS_WL" result/bin/run-nixos-vm diff --git a/modules/hm/default.nix b/modules/hm/default.nix index 98de725..98cb89a 100644 --- a/modules/hm/default.nix +++ b/modules/hm/default.nix @@ -31,13 +31,33 @@ in # 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; + 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; @@ -88,9 +108,11 @@ in gpg-agent = { enable = true; maxCacheTtl = 86400; - pinentryPackage = if config.jhome.gui.enable then pkgs.pinentry-qt else pkgs.pinentry-curses; + 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; diff --git a/modules/hm/dev.nix b/modules/hm/dev.nix index 2c2d898..afa3899 100644 --- a/modules/hm/dev.nix +++ b/modules/hm/dev.nix @@ -6,6 +6,80 @@ }: 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 = @@ -65,9 +139,22 @@ in # Jujutsu (alternative DVCS (git-compatible)) jujutsu = { enable = true; + # Use the more up to date version of jj package = pkgs.unstable.jujutsu; settings = { - ui.pager = "bat"; + 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( diff --git a/modules/hm/gui/default.nix b/modules/hm/gui/default.nix index bc12a65..0e0bdf2 100644 --- a/modules/hm/gui/default.nix +++ b/modules/hm/gui/default.nix @@ -13,6 +13,7 @@ let cfg = jhome.gui; cursor = { package = pkgs.nordzy-cursor-theme; + size = 48; name = "Nordzy-cursors"; }; iconTheme = { @@ -21,21 +22,24 @@ let }; in { + imports = [ + ./sway.nix + ./waybar.nix + ]; + 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; + 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 { @@ -56,7 +60,76 @@ in }; # Browser programs = { - firefox.enable = true; + 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; @@ -73,30 +146,6 @@ in }; # 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 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 - ]; - }; # Terminal wezterm = { enable = cfg.terminal == "wezterm"; @@ -128,13 +177,16 @@ in zellij = { enable = cfg.terminal == "alacritty"; # alacritty has no terminal multiplexer built-in # Set default shell - settings.default_shell = - if config.programs.fish.enable then - "fish" - else if config.programs.zsh.enable then - "zsh" - else - "bash"; + 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; @@ -167,25 +219,19 @@ in # Notifications mako = { enable = true; - layer = "overlay"; - borderRadius = 8; - defaultTimeout = 15000; + settings = { + layer = "overlay"; + border-radius = 8; + default-timeout = 15000; + }; }; }; - # Window Manager - wayland.windowManager.sway = { - inherit (cfg.sway) enable; - package = swayPkg; # no sway package if it comes from the OS - config = import ./sway-config.nix { inherit config pkgs; }; - systemd = { - enable = true; - xdgAutostart = true; - }; + stylix = lib.mkIf config.jhome.styling.enable { + # Set cursor style + inherit cursor; + targets.firefox.profileNames = [ config.home.username ]; }; - - # 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; @@ -200,10 +246,7 @@ in gtk4.extraConfig.gtk-application-prefer-dark-theme = 1; }; # Set Qt theme - qt = lib.mkIf config.jhome.styling.enable { - enable = true; - platformTheme.name = "gtk"; - }; + qt = lib.mkIf config.jhome.styling.enable { enable = true; }; xdg.systemDirs.data = [ "/usr/share" diff --git a/modules/hm/gui/keybindings.nix b/modules/hm/gui/keybindings.nix deleted file mode 100644 index cfc8788..0000000 --- a/modules/hm/gui/keybindings.nix +++ /dev/null @@ -1,118 +0,0 @@ -{ 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 ${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 - ) diff --git a/modules/hm/gui/sway-config.nix b/modules/hm/gui/sway-config.nix deleted file mode 100644 index e20e8aa..0000000 --- a/modules/hm/gui/sway-config.nix +++ /dev/null @@ -1,101 +0,0 @@ -{ config, pkgs }: -let - cfg = config.jhome.gui.sway; - modifier = "Mod4"; - 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}'"; - # 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 modifier terminal 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/modules/hm/gui/sway.nix b/modules/hm/gui/sway.nix new file mode 100644 index 0000000..9c7a312 --- /dev/null +++ b/modules/hm/gui/sway.nix @@ -0,0 +1,224 @@ +{ + 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-settings.nix b/modules/hm/gui/waybar-settings.nix deleted file mode 100644 index 3fcf58c..0000000 --- a/modules/hm/gui/waybar-settings.nix +++ /dev/null @@ -1,127 +0,0 @@ -{ 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/gui/waybar.nix b/modules/hm/gui/waybar.nix new file mode 100644 index 0000000..eefdab4 --- /dev/null +++ b/modules/hm/gui/waybar.nix @@ -0,0 +1,159 @@ +{ + 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/nixos/default.nix b/modules/nixos/default.nix index da8f8b4..e2e4370 100644 --- a/modules/nixos/default.nix +++ b/modules/nixos/default.nix @@ -17,6 +17,7 @@ in ./options.nix ./dev.nix ./gui.nix + ./starship.nix ./styling.nix ]; @@ -34,33 +35,7 @@ in pkgs.unzip ]; - programs = { - # Default shell - fish.enable = true; - # 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 - (import ./starship-shorter-text.nix) - ]; - }; - }; + programs.fish.enable = true; environment.etc = keysFromGithub; services = { diff --git a/modules/nixos/starship-nerdfont-symbols.nix b/modules/nixos/starship-nerdfont-symbols.nix deleted file mode 100644 index 2032150..0000000 --- a/modules/nixos/starship-nerdfont-symbols.nix +++ /dev/null @@ -1,89 +0,0 @@ -{ - 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/modules/nixos/starship-shorter-text.nix b/modules/nixos/starship-shorter-text.nix deleted file mode 100644 index 605a53a..0000000 --- a/modules/nixos/starship-shorter-text.nix +++ /dev/null @@ -1,66 +0,0 @@ -{ - 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/starship.nix b/modules/nixos/starship.nix new file mode 100644 index 0000000..3ab8d8b --- /dev/null +++ b/modules/nixos/starship.nix @@ -0,0 +1,183 @@ +{ 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/nixvim/default.nix b/modules/nixvim/default.nix index 9a9b212..6152af6 100644 --- a/modules/nixvim/default.nix +++ b/modules/nixvim/default.nix @@ -6,7 +6,7 @@ in imports = [ ./options.nix ]; config.programs.nixvim = lib.mkMerge [ - (import ./standalone.nix) + ./standalone.nix (lib.mkIf cfg.enable { enable = true; defaultEditor = lib.mkDefault true; diff --git a/modules/nixvim/dev-plugins.nix b/modules/nixvim/dev-plugins.nix index fdfaff1..d7c0a21 100644 --- a/modules/nixvim/dev-plugins.nix +++ b/modules/nixvim/dev-plugins.nix @@ -13,6 +13,7 @@ let "basedpyright" "bashls" "clangd" + "gopls" # "html" # Not writing html "jsonls" "marksman" @@ -44,17 +45,19 @@ in enable = true; servers = { # Pyright needs to have the project root set? - basedpyright.rootDir = # lua - '' - function() - return vim.fs.root(0, {'flake.nix', '.git', '.jj', 'pyproject.toml', 'setup.py'}) - end - ''; + 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; }; }; @@ -89,18 +92,18 @@ in }) # Configure Formatters { - extraPackages = [ - pkgs.luajitPackages.jsregexp - pkgs.shfmt - pkgs.stylua - pkgs.taplo - pkgs.yamlfmt - pkgs.fish - ]; + extraPackages = [ pkgs.luajitPackages.jsregexp ]; plugins.conform-nvim = { enable = true; settings = { - formatters.nixfmt.command = "${lib.getExe pkgs.nixfmt-rfc-style}"; + 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_by_ft = { "_" = [ "trim_whitespace" ]; c = [ "clang_format" ]; @@ -119,12 +122,13 @@ in } # 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" ]; @@ -172,6 +176,7 @@ in mode = "virtualtext"; }; }; + hunk.enable = true; otter.enable = true; }; } diff --git a/modules/nixvim/extraPlugins/default.nix b/modules/nixvim/extraPlugins/default.nix deleted file mode 100644 index 87e972c..0000000 --- a/modules/nixvim/extraPlugins/default.nix +++ /dev/null @@ -1,11 +0,0 @@ -{ 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/standalone.nix b/modules/nixvim/standalone.nix index 8f4f63f..f66d239 100644 --- a/modules/nixvim/standalone.nix +++ b/modules/nixvim/standalone.nix @@ -7,7 +7,12 @@ let cfg = config.jhome.nvim; plugins = pkgs.vimPlugins; - extraPlugins = import ./extraPlugins { inherit pkgs; }; + jExtraVimPlugins = pkgs.vimPlugins.extend ( + pkgs.callPackage ./extraPlugins/generated.nix { + inherit (pkgs.vimUtils) buildVimPlugin; + inherit (pkgs.neovimUtils) buildNeovimPlugin; + } + ); in { imports = [ @@ -78,7 +83,7 @@ in } # Big packages that are kinda unnecessary (lib.mkIf (!cfg.reduceSize) { - extraPlugins = [ extraPlugins.nvim-silicon ]; + extraPlugins = [ jExtraVimPlugins.nvim-silicon ]; extraPackages = [ pkgs.silicon ]; extraConfigLua = # lua diff --git a/.renovaterc.json b/renovate.json similarity index 83% rename from .renovaterc.json rename to renovate.json index feb16d3..86737e0 100644 --- a/.renovaterc.json +++ b/renovate.json @@ -13,11 +13,6 @@ "config:best-practices" ], "nix": { - "fileMatch": [ - "(^|/)flake\\.nix$" - ], - "commitMessageTopic": "nixpkgs", - "commitMessageExtra": "to {{newValue}}", "enabled": true }, "lockFileMaintenance": { diff --git a/scripts/audiomenu/.envrc b/scripts/audiomenu/.envrc new file mode 100644 index 0000000..729d54f --- /dev/null +++ b/scripts/audiomenu/.envrc @@ -0,0 +1,2 @@ +source_up +source .venv/bin/activate diff --git a/scripts/audiomenu/.gitignore b/scripts/audiomenu/.gitignore index ea8c4bf..1d17dae 100644 --- a/scripts/audiomenu/.gitignore +++ b/scripts/audiomenu/.gitignore @@ -1 +1 @@ -/target +.venv diff --git a/scripts/audiomenu/.python-version b/scripts/audiomenu/.python-version new file mode 100644 index 0000000..24ee5b1 --- /dev/null +++ b/scripts/audiomenu/.python-version @@ -0,0 +1 @@ +3.13 diff --git a/scripts/audiomenu/Cargo.lock b/scripts/audiomenu/Cargo.lock deleted file mode 100644 index 8974818..0000000 --- a/scripts/audiomenu/Cargo.lock +++ /dev/null @@ -1,568 +0,0 @@ -# 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.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eccb054f56cbd38340b380d4a8e69ef1f02f1af43db2f0cc817a4774d80ae071" -dependencies = [ - "clap_builder", - "clap_derive", -] - -[[package]] -name = "clap_builder" -version = "4.5.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efd9466fac8543255d3b1fcad4762c5e116ffe808c8a3043d4263cd4fd4862a2" -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.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "976dd42dc7e85965fe702eb8164f21f450704bdde31faefd6471dba214cb594e" -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.172" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" - -[[package]] -name = "linux-raw-sys" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" - -[[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.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a" -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.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" - -[[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.95" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" -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.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d97817398dd4bb2e6da002002db259209759911da105da92bec29ccb12cf58bf" -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 deleted file mode 100644 index b469215..0000000 --- a/scripts/audiomenu/Cargo.toml +++ /dev/null @@ -1,18 +0,0 @@ -[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 new file mode 100644 index 0000000..e69de29 diff --git a/scripts/audiomenu/audiomenu.py b/scripts/audiomenu/audiomenu.py new file mode 100644 index 0000000..88fe671 --- /dev/null +++ b/scripts/audiomenu/audiomenu.py @@ -0,0 +1,238 @@ +# 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 88636da..45a5a3b 100644 --- a/scripts/audiomenu/package.nix +++ b/scripts/audiomenu/package.nix @@ -1,40 +1,9 @@ -{ 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; - }; -} +{ 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 diff --git a/scripts/audiomenu/pyproject.toml b/scripts/audiomenu/pyproject.toml new file mode 100644 index 0000000..6d992a3 --- /dev/null +++ b/scripts/audiomenu/pyproject.toml @@ -0,0 +1,9 @@ +[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 deleted file mode 100644 index a542fd4..0000000 --- a/scripts/audiomenu/src/main.rs +++ /dev/null @@ -1,231 +0,0 @@ -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 23ec010..5cde95c 100644 --- a/scripts/default.nix +++ b/scripts/default.nix @@ -1,23 +1,17 @@ -# 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 - files = builtins.readDir ./.; - isPackage = path: type: (type == "directory") && (builtins.readDir path) ? "package.nix"; - toPackage = name: pkgs: { - inherit name; - value = pkgs.callPackage (./. + "/${name}/package.nix") { }; + packages = pkgs: { + jpassmenu = pkgs.callPackage ./jpassmenu/package.nix { }; + audiomenu = pkgs.callPackage ./audiomenu/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 -# we have lib.filterMapAttrs at home -pkgs: builtins.listToAttrs (builtins.concatMap (makePackage pkgs) (builtins.attrNames files)) +{ + # Add scripts to overlay + flake.overlays.scripts = _final: packages; + + # Add scripts to packages + perSystem = + { pkgs, ... }: + { + packages = packages pkgs; + }; +} diff --git a/scripts/jpassmenu/.envrc b/scripts/jpassmenu/.envrc new file mode 100644 index 0000000..729d54f --- /dev/null +++ b/scripts/jpassmenu/.envrc @@ -0,0 +1,2 @@ +source_up +source .venv/bin/activate diff --git a/scripts/jpassmenu/.gitignore b/scripts/jpassmenu/.gitignore deleted file mode 100644 index ea8c4bf..0000000 --- a/scripts/jpassmenu/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/target diff --git a/scripts/jpassmenu/.python-version b/scripts/jpassmenu/.python-version new file mode 100644 index 0000000..24ee5b1 --- /dev/null +++ b/scripts/jpassmenu/.python-version @@ -0,0 +1 @@ +3.13 diff --git a/scripts/jpassmenu/Cargo.lock b/scripts/jpassmenu/Cargo.lock deleted file mode 100644 index 73ad397..0000000 --- a/scripts/jpassmenu/Cargo.lock +++ /dev/null @@ -1,743 +0,0 @@ -# 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.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "234113d19d0d7d613b40e86fb654acf958910802bcceab913a4f9e7cda03b1a4" -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.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eccb054f56cbd38340b380d4a8e69ef1f02f1af43db2f0cc817a4774d80ae071" -dependencies = [ - "clap_builder", - "clap_derive", -] - -[[package]] -name = "clap_builder" -version = "4.5.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efd9466fac8543255d3b1fcad4762c5e116ffe808c8a3043d4263cd4fd4862a2" -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.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13c863f0904021b108aa8b2f55046443e6b1ebde8fd4a15c399893aae4fa069f" -dependencies = [ - "anstream", - "anstyle", - "env_filter", - "jiff", - "log", -] - -[[package]] -name = "errno" -version = "0.3.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "976dd42dc7e85965fe702eb8164f21f450704bdde31faefd6471dba214cb594e" -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.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5ad87c89110f55e4cd4dc2893a9790820206729eaf221555f742d540b0724a0" -dependencies = [ - "jiff-static", - "log", - "portable-atomic", - "portable-atomic-util", - "serde", -] - -[[package]] -name = "jiff-static" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d076d5b64a7e2fe6f0743f02c43ca4a6725c0f904203bfe276a5b3e793103605" -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.172" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" - -[[package]] -name = "linux-raw-sys" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" - -[[package]] -name = "log" -version = "0.4.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" - -[[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.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a" -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.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" - -[[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.95" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" -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.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d97817398dd4bb2e6da002002db259209759911da105da92bec29ccb12cf58bf" -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 deleted file mode 100644 index 7ffa4ba..0000000 --- a/scripts/jpassmenu/Cargo.toml +++ /dev/null @@ -1,19 +0,0 @@ -[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 new file mode 100644 index 0000000..2c28fb8 --- /dev/null +++ b/scripts/jpassmenu/README.md @@ -0,0 +1,3 @@ +# 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 new file mode 100644 index 0000000..f446412 --- /dev/null +++ b/scripts/jpassmenu/jpassmenu.py @@ -0,0 +1,111 @@ +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 88636da..6fbfbbd 100644 --- a/scripts/jpassmenu/package.nix +++ b/scripts/jpassmenu/package.nix @@ -1,40 +1,6 @@ -{ 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; - }; -} +{ writers, python3Packages }: +writers.writePython3Bin "jpassmenu" { + libraries = [ python3Packages.click ]; + # line too long, but I like my code well documented + flakeIgnore = [ "E501" ]; +} ./jpassmenu.py diff --git a/scripts/jpassmenu/pyproject.toml b/scripts/jpassmenu/pyproject.toml new file mode 100644 index 0000000..5cfa6aa --- /dev/null +++ b/scripts/jpassmenu/pyproject.toml @@ -0,0 +1,9 @@ +[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 deleted file mode 100644 index 279dbdc..0000000 --- a/scripts/jpassmenu/src/main.rs +++ /dev/null @@ -1,156 +0,0 @@ -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 -}