{ description = "Handy - A free, open source, and extensible speech-to-text application that works completely offline"; inputs = { nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; }; outputs = { self, nixpkgs, }: let supportedSystems = [ "x86_64-linux" "aarch64-linux" ]; forAllSystems = nixpkgs.lib.genAttrs supportedSystems; # Read version from Cargo.toml cargoToml = builtins.fromTOML (builtins.readFile ./src-tauri/Cargo.toml); version = cargoToml.package.version; in { packages = forAllSystems ( system: let pkgs = nixpkgs.legacyPackages.${system}; lib = pkgs.lib; bunDeps = pkgs.stdenv.mkDerivation { pname = "handy-bun-deps"; inherit version; src = self; nativeBuildInputs = [ pkgs.bun pkgs.cacert ]; dontFixup = true; buildPhase = '' export HOME=$TMPDIR bun install --frozen-lockfile --no-progress ''; installPhase = '' mkdir -p $out cp -r node_modules $out/ ''; outputHashAlgo = "sha256"; outputHashMode = "recursive"; outputHash = "sha256-+hUANv0w3qnK5d2+4JW3XMazLRDhWCbOxUXQyTGta/0="; }; in { handy = pkgs.rustPlatform.buildRustPackage { pname = "handy"; inherit version; src = self; cargoRoot = "src-tauri"; cargoLock = { lockFile = ./src-tauri/Cargo.lock; outputHashes = { "rdev-0.5.0-2" = "sha256-0F7EaPF8Oa1nnSCAjzEAkitWVpMldL3nCp3c5DVFMe0="; "rodio-0.20.1" = "sha256-wq72awTvN4fXZ9qZc5KLYS9oMxtNDZ4YGxfqz8msofs="; "tauri-nspanel-2.1.0" = "sha256-gotQQ1DOhavdXU8lTEux0vdY880LLetk7VLvSm6/8TI="; "tauri-runtime-2.9.1" = "sha256-sdneSI2kfRMgTkuqQoFPgtYvkqMPSuoyrffFwOph+ZM="; "vad-rs-0.1.5" = "sha256-Q9Dxq31npyUPY9wwi6OxqSJrEvFvG8/n0dbyT7XNcyI="; }; }; postPatch = '' ${pkgs.jq}/bin/jq 'del(.build.beforeBuildCommand) | .bundle.createUpdaterArtifacts = false' \ src-tauri/tauri.conf.json > $TMPDIR/tauri.conf.json cp $TMPDIR/tauri.conf.json src-tauri/tauri.conf.json # Point libappindicator-sys to the Nix store path substituteInPlace \ $cargoDepsCopy/libappindicator-sys-*/src/lib.rs \ --replace-fail \ "libayatana-appindicator3.so.1" \ "${pkgs.libayatana-appindicator}/lib/libayatana-appindicator3.so.1" # Disable cbindgen in ferrous-opencc (calls cargo metadata which fails in sandbox) # Upstream removed this call in v0.3.1+ substituteInPlace $cargoDepsCopy/ferrous-opencc-0.2.3/build.rs \ --replace-fail '.expect("Unable to generate bindings")' '.ok();' substituteInPlace $cargoDepsCopy/ferrous-opencc-0.2.3/build.rs \ --replace-fail '.write_to_file("opencc.h");' '// skipped' ''; preBuild = '' cp -r ${bunDeps}/node_modules node_modules chmod -R +w node_modules patchShebangs node_modules export HOME=$TMPDIR ${pkgs.bun}/bin/bun run build ''; doCheck = false; # The tauri hook's installPhase expects target/ in cwd, but our # cargoRoot puts it under src-tauri/. Override to extract the DEB. installPhase = '' runHook preInstall mkdir -p $out cd src-tauri mv target/${pkgs.stdenv.hostPlatform.rust.rustcTarget}/release/bundle/deb/*/data/usr/* $out/ runHook postInstall ''; nativeBuildInputs = with pkgs; [ cargo-tauri.hook pkg-config wrapGAppsHook4 bun nodejs jq cmake llvmPackages.libclang shaderc ]; buildInputs = with pkgs; [ webkitgtk_4_1 gtk3 glib glib-networking libsoup_3 alsa-lib onnxruntime libayatana-appindicator libevdev xorg.libX11 xorg.libXtst gtk-layer-shell openssl vulkan-loader vulkan-headers shaderc ]; env = { LIBCLANG_PATH = "${pkgs.llvmPackages.libclang.lib}/lib"; BINDGEN_EXTRA_CLANG_ARGS = "-isystem ${pkgs.llvmPackages.libclang.lib}/lib/clang/${lib.getVersion pkgs.llvmPackages.libclang}/include -isystem ${pkgs.glibc.dev}/include"; ORT_LIB_LOCATION = "${pkgs.onnxruntime}/lib"; OPENSSL_NO_VENDOR = "1"; }; preFixup = '' gappsWrapperArgs+=( --set WEBKIT_DISABLE_DMABUF_RENDERER 1 --prefix LD_LIBRARY_PATH : "${lib.makeLibraryPath [ pkgs.vulkan-loader pkgs.onnxruntime ]}" ) ''; meta = { description = "A free, open source, and extensible speech-to-text application that works completely offline"; homepage = "https://github.com/cjpais/Handy"; license = lib.licenses.mit; mainProgram = "handy"; platforms = [ "x86_64-linux" ]; }; }; default = self.packages.${system}.handy; } ); # Development shell for building from source devShells = forAllSystems ( system: let pkgs = nixpkgs.legacyPackages.${system}; in { default = pkgs.mkShell { buildInputs = with pkgs; [ # Rust rustc cargo rust-analyzer clippy # Frontend nodejs bun # Tauri CLI cargo-tauri # Native deps pkg-config openssl alsa-lib libsoup_3 webkitgtk_4_1 gtk3 gtk-layer-shell glib libxtst libevdev llvmPackages.libclang cmake vulkan-headers vulkan-loader shaderc libappindicator ]; LIBCLANG_PATH = "${pkgs.llvmPackages.libclang.lib}/lib"; LD_LIBRARY_PATH = "${pkgs.lib.makeLibraryPath [ pkgs.libappindicator ]}"; shellHook = '' echo "Handy development environment" bun install echo "Run 'bun run tauri dev' to start" ''; }; } ); }; }