Add `zed-editor` package and overlay to flake (#16783)

jvmncs created

Adds a `zed-editor` package to the flake, along with exported overlay.
Uses [`crane`](https://crane.dev) to avoid issues with updating
git-sourced dependencies' hashes. Crane will also be useful if we want
to export separate packages for `stable`, `preview`, and `nightly` in
the future.

Release Notes:

- Added a default package + overlay to Zed's Nix flake. This is useful
for users wanting to pilot nightly builds of Zed on NixOS.

Change summary

default.nix   |  14 +++++
flake.lock    |  81 +++++++++++++++++++++++++++++-
flake.nix     |  66 +++++++++++++++++--------
nix/build.nix | 138 +++++++++++++++++++++++++++++++++++++++++++++++++++++
nix/shell.nix |  52 +++++++++++++++++++
shell.nix     |  71 +++++---------------------
6 files changed, 341 insertions(+), 81 deletions(-)

Detailed changes

default.nix 🔗

@@ -0,0 +1,14 @@
+(
+  import
+  (
+    let
+      lock = builtins.fromJSON (builtins.readFile ./flake.lock);
+    in
+      fetchTarball {
+        url = lock.nodes.flake-compat.locked.url or "https://github.com/edolstra/flake-compat/archive/${lock.nodes.flake-compat.locked.rev}.tar.gz";
+        sha256 = lock.nodes.flake-compat.locked.narHash;
+      }
+  )
+  {src = ./.;}
+)
+.defaultNix

flake.lock 🔗

@@ -1,12 +1,67 @@
 {
   "nodes": {
+    "crane": {
+      "inputs": {
+        "nixpkgs": [
+          "nixpkgs"
+        ]
+      },
+      "locked": {
+        "lastModified": 1724537630,
+        "narHash": "sha256-gpqINM71zp3kw5XYwUXa84ZtPnCmLLnByuFoYesT1bY=",
+        "owner": "ipetkov",
+        "repo": "crane",
+        "rev": "3e08f4b1fc9aaede5dd511d8f5f4ef27501e49b0",
+        "type": "github"
+      },
+      "original": {
+        "owner": "ipetkov",
+        "repo": "crane",
+        "type": "github"
+      }
+    },
+    "fenix": {
+      "inputs": {
+        "nixpkgs": [
+          "nixpkgs"
+        ],
+        "rust-analyzer-src": "rust-analyzer-src"
+      },
+      "locked": {
+        "lastModified": 1724480904,
+        "narHash": "sha256-puBjYiWZMu/VhDk5ZQW88o/IlwsYuoqvCglOESolyBc=",
+        "owner": "nix-community",
+        "repo": "fenix",
+        "rev": "dba5ef499c684acae11a2661d0ed45017fe75b71",
+        "type": "github"
+      },
+      "original": {
+        "owner": "nix-community",
+        "repo": "fenix",
+        "type": "github"
+      }
+    },
+    "flake-compat": {
+      "locked": {
+        "lastModified": 1696426674,
+        "narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=",
+        "rev": "0f9255e01c2351cc7d116c072cb317785dd33b33",
+        "revCount": 57,
+        "type": "tarball",
+        "url": "https://api.flakehub.com/f/pinned/edolstra/flake-compat/1.0.1/018afb31-abd1-7bff-a5e4-cff7e18efb7a/source.tar.gz"
+      },
+      "original": {
+        "type": "tarball",
+        "url": "https://flakehub.com/f/edolstra/flake-compat/1.tar.gz"
+      }
+    },
     "nixpkgs": {
       "locked": {
-        "lastModified": 1719690277,
-        "narHash": "sha256-0xSej1g7eP2kaUF+JQp8jdyNmpmCJKRpO12mKl/36Kc=",
+        "lastModified": 1724224976,
+        "narHash": "sha256-Z/ELQhrSd7bMzTO8r7NZgi9g5emh+aRKoCdaAv5fiO0=",
         "owner": "NixOS",
         "repo": "nixpkgs",
-        "rev": "2741b4b489b55df32afac57bc4bfd220e8bf617e",
+        "rev": "c374d94f1536013ca8e92341b540eba4c22f9c62",
         "type": "github"
       },
       "original": {
@@ -18,8 +73,28 @@
     },
     "root": {
       "inputs": {
+        "crane": "crane",
+        "fenix": "fenix",
+        "flake-compat": "flake-compat",
         "nixpkgs": "nixpkgs"
       }
+    },
+    "rust-analyzer-src": {
+      "flake": false,
+      "locked": {
+        "lastModified": 1724436261,
+        "narHash": "sha256-N6p1Qd7qgIATJz61JXAqV/rd8umeg0Uj1IawJCTdDlU=",
+        "owner": "rust-lang",
+        "repo": "rust-analyzer",
+        "rev": "ab34fdd9f3367d1761991f78e3a7006a4d8d2b34",
+        "type": "github"
+      },
+      "original": {
+        "owner": "rust-lang",
+        "ref": "nightly",
+        "repo": "rust-analyzer",
+        "type": "github"
+      }
     }
   },
   "root": "root",

flake.nix 🔗

@@ -3,29 +3,53 @@
 
   inputs = {
     nixpkgs.url = "github:NixOS/nixpkgs?ref=nixos-unstable";
+    fenix = {
+      url = "github:nix-community/fenix";
+      inputs.nixpkgs.follows = "nixpkgs";
+    };
+    crane = {
+      url = "github:ipetkov/crane";
+      inputs.nixpkgs.follows = "nixpkgs";
+    };
+
   };
 
-  outputs =
-    { self, nixpkgs }:
-    let
-      inherit (self) outputs;
-      systems = [
-        "aarch64-linux"
+  outputs = {
+    nixpkgs,
+    crane,
+    fenix,
+    ...
+  }: let
+    forAllSystems = function:
+      nixpkgs.lib.genAttrs [
         "x86_64-linux"
-        "aarch64-darwin"
-        "x86_64-darwin"
-      ];
-      forAllSystems = nixpkgs.lib.genAttrs systems;
-    in
-    {
-      devShells = forAllSystems (
-        system:
-        let
-          pkgs = import nixpkgs { inherit system; };
-        in
-        {
-          default = import ./shell.nix { inherit pkgs; };
-        }
-      );
+        "aarch64-linux"
+      ] (system:
+        function (import nixpkgs {
+          inherit system;
+          overlays = [fenix.overlays.default];
+        }));
+  in {
+    packages = forAllSystems (pkgs: let
+      craneLib = (crane.mkLib pkgs).overrideToolchain (p: p.fenix.stable.toolchain);
+      nightlyBuild = pkgs.callPackage ./nix/build.nix {
+        inherit craneLib;
+      };
+    in {
+      zed-editor = nightlyBuild;
+      default = nightlyBuild;
+    });
+
+    devShells = forAllSystems (pkgs: {
+      default = import ./nix/shell.nix {inherit pkgs;};
+    });
+
+    formatter = forAllSystems (pkgs: pkgs.alejandra);
+
+    overlays.default = final: _prev: {
+      zed-editor = final.callPackage ./nix/build.nix {
+        craneLib = (crane.mkLib final).overrideToolchain (p: p.fenix.stable.toolchain);
+      };
     };
+  };
 }

nix/build.nix 🔗

@@ -0,0 +1,138 @@
+{
+  lib,
+  craneLib,
+  clang,
+  llvmPackages_18,
+  mold-wrapped,
+  copyDesktopItems,
+  curl,
+  perl,
+  pkg-config,
+  protobuf,
+  fontconfig,
+  freetype,
+  libgit2,
+  openssl,
+  sqlite,
+  zlib,
+  zstd,
+  alsa-lib,
+  libxkbcommon,
+  wayland,
+  libglvnd,
+  xorg,
+  makeFontsConf,
+  vulkan-loader,
+  envsubst,
+  stdenvAdapters,
+  nix-gitignore,
+  withGLES ? false,
+}: let
+  includeFilter = path: type: let
+    baseName = baseNameOf (toString path);
+    parentDir = dirOf path;
+    inRootDir = type == "directory" && parentDir == ../.;
+  in
+    !(inRootDir && (baseName == "docs" || baseName == ".github" || baseName == "script" || baseName == ".git" || baseName == "target"));
+
+  src = lib.cleanSourceWith {
+    src = nix-gitignore.gitignoreSource [] ../.;
+    filter = includeFilter;
+    name = "source";
+  };
+
+  stdenv = stdenvAdapters.useMoldLinker llvmPackages_18.stdenv;
+
+  commonArgs =
+    craneLib.crateNameFromCargoToml {cargoToml = ../crates/zed/Cargo.toml;}
+    // {
+      inherit src stdenv;
+
+      buildInputs = [
+        curl
+        fontconfig
+        freetype
+        libgit2
+        openssl
+        sqlite
+        zlib
+        zstd
+        alsa-lib
+        libxkbcommon
+        wayland
+        xorg.libxcb
+      ];
+
+      nativeBuildInputs = [
+        clang
+        copyDesktopItems
+        curl
+        mold-wrapped
+        perl
+        pkg-config
+        protobuf
+      ];
+
+      ZSTD_SYS_USE_PKG_CONFIG = true;
+      FONTCONFIG_FILE = makeFontsConf {
+        fontDirectories = [
+          "../assets/fonts/zed-mono"
+          "../assets/fonts/zed-sans"
+        ];
+      };
+      ZED_UPDATE_EXPLANATION = "zed has been installed using nix. Auto-updates have thus been disabled.";
+    };
+
+  cargoArtifacts = craneLib.buildDepsOnly commonArgs;
+
+  gpu-lib =
+    if withGLES
+    then libglvnd
+    else vulkan-loader;
+
+  zed = craneLib.buildPackage (commonArgs
+    // {
+      inherit cargoArtifacts;
+      cargoExtraArgs = "--package=zed --package=cli";
+      buildFeatures = ["gpui/runtime_shaders"];
+      doCheck = false;
+
+      RUSTFLAGS =
+        if withGLES
+        then "--cfg gles"
+        else "";
+
+      postFixup = ''
+        patchelf --add-rpath ${gpu-lib}/lib $out/bin/*
+        patchelf --add-rpath ${wayland}/lib $out/bin/*
+      '';
+
+      postInstall = ''
+        mkdir -p $out/bin $out/libexec
+        mv $out/bin/zed $out/libexec/zed-editor
+        mv $out/bin/cli $out/bin/zed
+
+        install -D crates/zed/resources/app-icon@2x.png $out/share/icons/hicolor/1024x1024@2x/apps/zed.png
+        install -D crates/zed/resources/app-icon.png $out/share/icons/hicolor/512x512/apps/zed.png
+
+        export DO_STARTUP_NOTIFY="true"
+        export APP_CLI="zed"
+        export APP_ICON="zed"
+        export APP_NAME="Zed"
+        export APP_ARGS="%U"
+        mkdir -p "$out/share/applications"
+        ${lib.getExe envsubst} < "crates/zed/resources/zed.desktop.in" > "$out/share/applications/dev.zed.Zed.desktop"
+      '';
+    });
+in
+  zed
+  // {
+    meta = with lib; {
+      description = "High-performance, multiplayer code editor from the creators of Atom and Tree-sitter";
+      homepage = "https://zed.dev";
+      changelog = "https://zed.dev/releases/preview";
+      license = licenses.gpl3Only;
+      mainProgram = "zed";
+      platforms = platforms.linux;
+    };
+  }

nix/shell.nix 🔗

@@ -0,0 +1,52 @@
+{pkgs ? import <nixpkgs> {}}: let
+  stdenv = pkgs.stdenvAdapters.useMoldLinker pkgs.llvmPackages_18.stdenv;
+in
+  if pkgs.stdenv.isDarwin
+  then
+    # See https://github.com/NixOS/nixpkgs/issues/320084
+    throw "zed: nix dev-shell isn't supported on darwin yet."
+  else let
+    buildInputs = with pkgs; [
+      curl
+      fontconfig
+      freetype
+      libgit2
+      openssl
+      sqlite
+      zlib
+      zstd
+      alsa-lib
+      libxkbcommon
+      wayland
+      xorg.libxcb
+      vulkan-loader
+    ];
+  in
+    pkgs.mkShell.override {inherit stdenv;} {
+      nativeBuildInputs = with pkgs; [
+        clang
+        curl
+        perl
+        pkg-config
+        protobuf
+        rustPlatform.bindgenHook
+      ];
+
+      inherit buildInputs;
+
+      shellHook = ''
+        export LD_LIBRARY_PATH="${pkgs.lib.makeLibraryPath ([
+            pkgs.vulkan-loader
+          ]
+          ++ buildInputs)}:$LD_LIBRARY_PATH"
+        export PROTOC="${pkgs.protobuf}/bin/protoc"
+      '';
+
+      FONTCONFIG_FILE = pkgs.makeFontsConf {
+        fontDirectories = [
+          "./assets/fonts/zed-mono"
+          "./assets/fonts/zed-sans"
+        ];
+      };
+      ZSTD_SYS_USE_PKG_CONFIG = true;
+    }

shell.nix 🔗

@@ -1,57 +1,14 @@
-{
-  pkgs ? import <nixpkgs> { },
-}:
-
-let
-  stdenv = pkgs.stdenvAdapters.useMoldLinker pkgs.llvmPackages_18.stdenv;
-in
-if pkgs.stdenv.isDarwin then
-  # See https://github.com/NixOS/nixpkgs/issues/320084
-  throw "zed: nix dev-shell isn't supported on darwin yet."
-else
-  (pkgs.mkShell.override { inherit stdenv; }) rec {
-    nativeBuildInputs = with pkgs; [
-      copyDesktopItems
-      curl
-      perl
-      pkg-config
-      protobuf
-      rustPlatform.bindgenHook
-    ];
-
-    buildInputs = with pkgs; [
-      curl
-      fontconfig
-      freetype
-      libgit2
-      openssl
-      sqlite
-      zlib
-      zstd
-
-      alsa-lib
-      libxkbcommon
-      wayland
-      xorg.libxcb
-    ];
-
-    env = {
-      LD_LIBRARY_PATH =
-        with pkgs;
-        lib.makeLibraryPath (
-          buildInputs
-          ++ [
-            stdenv.cc.cc.lib
-            vulkan-loader
-          ]
-        );
-      ZSTD_SYS_USE_PKG_CONFIG = true;
-      FONTCONFIG_FILE = pkgs.makeFontsConf {
-        fontDirectories = [
-          "assets/fonts/zed-mono"
-          "assets/fonts/zed-sans"
-        ];
-      };
-      PROTOC = "${pkgs.protobuf}/bin/protoc";
-    };
-  }
+(
+  import
+  (
+    let
+      lock = builtins.fromJSON (builtins.readFile ./flake.lock);
+    in
+      fetchTarball {
+        url = lock.nodes.flake-compat.locked.url or "https://github.com/edolstra/flake-compat/archive/${lock.nodes.flake-compat.locked.rev}.tar.gz";
+        sha256 = lock.nodes.flake-compat.locked.narHash;
+      }
+  )
+  {src = ./.;}
+)
+.shellNix