{ description = "fff.nvim"; inputs = { nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable"; crane.url = "github:ipetkov/crane"; flake-utils.url = "github:numtide/flake-utils"; rust-overlay = { url = "github:oxalica/rust-overlay"; inputs.nixpkgs.follows = "nixpkgs"; }; zig-overlay = { url = "github:mitchellh/zig-overlay"; inputs.nixpkgs.follows = "nixpkgs"; }; }; outputs = { self, nixpkgs, crane, flake-utils, rust-overlay, zig-overlay, ... }: flake-utils.lib.eachDefaultSystem ( system: let pkgs = import nixpkgs { inherit system; overlays = [ (import rust-overlay) ]; }; # zlob requires Zig >= 0.16, but nixpkgs tops out at 0.15. Pull from # mitchellh/zig-overlay which ships every released version. zig = zig-overlay.packages.${system}."0.16.0"; rustToolchain = pkgs.rust-bin.fromRustupToolchainFile ./rust-toolchain.toml; craneLib = (crane.mkLib pkgs).overrideToolchain rustToolchain; cargoToml = builtins.fromTOML (builtins.readFile ./crates/fff-nvim/Cargo.toml); fffMcpCargoToml = builtins.fromTOML (builtins.readFile ./crates/fff-mcp/Cargo.toml); # Common arguments can be set here to avoid repeating them later # Note: changes here will rebuild all dependency crates commonArgs = { pname = cargoToml.package.name; version = cargoToml.package.version; src = craneLib.cleanCargoSource ./.; strictDeps = true; nativeBuildInputs = [ pkgs.pkg-config pkgs.perl zig pkgs.llvmPackages.libclang.lib ]; buildInputs = with pkgs; [ # Add additional build inputs here openssl ]; LIBCLANG_PATH = "${pkgs.llvmPackages.libclang.lib}/lib"; # Zig 0.16 insists on writing to its global cache even when the # zlob build.rs passes --global-cache-dir. In the nix sandbox $HOME # is /homeless-shelter (unwritable), so redirect to $TMPDIR before # the build phase runs. preBuild = '' export ZIG_GLOBAL_CACHE_DIR="$TMPDIR/zig-global-cache" export ZIG_LOCAL_CACHE_DIR="$TMPDIR/zig-local-cache" export XDG_CACHE_HOME="$TMPDIR/cache" mkdir -p "$ZIG_GLOBAL_CACHE_DIR" "$ZIG_LOCAL_CACHE_DIR" "$XDG_CACHE_HOME" ''; }; my-crate = craneLib.buildPackage ( commonArgs // { cargoArtifacts = craneLib.buildDepsOnly commonArgs; doCheck = false; } ); fff-mcp-args = commonArgs // { pname = fffMcpCargoToml.package.name; version = fffMcpCargoToml.package.version; cargoExtraArgs = "-p fff-mcp --bin fff-mcp"; }; fff-mcp = craneLib.buildPackage ( fff-mcp-args // { cargoArtifacts = craneLib.buildDepsOnly fff-mcp-args; doCheck = false; } ); # Copies the dynamic library into the target/release folder copy-dynamic-library = /* bash */ '' set -eo pipefail mkdir -p target/release if [ "$(uname)" = "Darwin" ]; then cp -vf ${my-crate}/lib/libfff_nvim.dylib target/release/libfff_nvim.dylib else cp -vf ${my-crate}/lib/libfff_nvim.so target/release/libfff_nvim.so fi echo "Library copied to target/release/" ''; in { checks = { inherit my-crate fff-mcp; }; packages = { default = my-crate; inherit fff-mcp; # Neovim plugin fff-nvim = pkgs.vimUtils.buildVimPlugin { pname = "fff.nvim"; version = "main"; src = pkgs.lib.cleanSource ./.; postPatch = copy-dynamic-library; doCheck = false; # Skip require check since we have a Rust FFI component }; }; apps.default = flake-utils.lib.mkApp { drv = my-crate; }; apps.fff-mcp = flake-utils.lib.mkApp { drv = fff-mcp; }; # Add the release command apps.release = flake-utils.lib.mkApp { drv = pkgs.writeShellScriptBin "release" copy-dynamic-library; }; devShells.default = craneLib.devShell { # Inherit inputs from checks. checks = self.checks.${system}; # Extra inputs can be added here; cargo and rustc are provided by default. packages = [ # pkgs.ripgrep ]; }; } ); }