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
-}