···1+{ lib
2+, stdenv
3+, fetchFromGitHub
4+, fetchzip
5+, writeShellScript
6+, installShellFiles
7+, testers
8+, yabai
9+, xxd
10+, xcodebuild
11+, Carbon
12+, Cocoa
13+, ScriptingBridge
14+ # This needs to be from SDK 10.13 or higher, SLS APIs introduced in that version get used
15+, SkyLight
16+}:
1718+let
19 pname = "yabai";
20+ version = "4.0.2";
2122+ test-version = testers.testVersion {
23+ package = yabai;
24+ version = "yabai-v${version}";
0025 };
2627+ _meta = with lib; {
28+ description = "A tiling window manager for macOS based on binary space partitioning";
29+ longDescription = ''
30+ yabai is a window management utility that is designed to work as an extension to the built-in
31+ window manager of macOS. yabai allows you to control your windows, spaces and displays freely
32+ using an intuitive command line interface and optionally set user-defined keyboard shortcuts
33+ using skhd and other third-party software.
34+ '';
35+ homepage = "https://github.com/koekeishiya/yabai";
36+ changelog = "https://github.com/koekeishiya/yabai/blob/v${version}/CHANGELOG.md";
37+ license = licenses.mit;
38+ platforms = platforms.darwin;
39+ maintainers = with maintainers; [
40+ cmacrae
41+ shardy
42+ ivar
43+ ];
44+ };
45+in
46+{
47+ # Unfortunately compiling yabai from source on aarch64-darwin is a bit complicated. We use the precompiled binary instead for now.
48+ # See the comments on https://github.com/NixOS/nixpkgs/pull/188322 for more information.
49+ aarch64-darwin = stdenv.mkDerivation {
50+ inherit pname version;
51+52+ src = fetchzip {
53+ url = "https://github.com/koekeishiya/yabai/releases/download/v${version}/yabai-v${version}.tar.gz";
54+ sha256 = "sha256-RwARzK3e0e2N3ndFNikfo8srDjeo6jsWN2xQ18bXt/I=";
55+ };
56+57+ nativeBuildInputs = [
58+ installShellFiles
59+ ];
60+61+ dontConfigure = true;
62+ dontBuild = true;
6364+ installPhase = ''
65+ runHook preInstall
00006667+ mkdir -p $out
68+ cp -r ./bin $out
69+ installManPage ./doc/yabai.1
0007071+ runHook postInstall
0072 '';
73+74+ passthru.tests.version = test-version;
75+76+ meta = _meta // {
77+ sourceProvenance = with lib.sourceTypes; [
78+ binaryNativeCode
79+ ];
80+ };
81 };
82+83+ x86_64-darwin = stdenv.mkDerivation rec {
84+ inherit pname version;
85+86+ src = fetchFromGitHub {
87+ owner = "koekeishiya";
88+ repo = "yabai";
89+ rev = "v${version}";
90+ sha256 = "sha256-DXDdjI4kkLcRUNtMoSu7fJ0f3fUty88o5ZS6lJz0cGU=";
91+ };
92+93+ nativeBuildInputs = [
94+ installShellFiles
95+ xcodebuild
96+ xxd
97+ ];
98+99+ buildInputs = [
100+ Carbon
101+ Cocoa
102+ ScriptingBridge
103+ SkyLight
104+ ];
105+106+ dontConfigure = true;
107+ enableParallelBuilding = true;
108+109+ postPatch = ''
110+ # aarch64 code is compiled on all targets, which causes our Apple SDK headers to error out.
111+ # Since multilib doesnt work on darwin i dont know of a better way of handling this.
112+ substituteInPlace makefile \
113+ --replace "-arch arm64e" "" \
114+ --replace "-arch arm64" "" \
115+ --replace "clang" "${stdenv.cc.targetPrefix}clang"
116+117+ # `NSScreen::safeAreaInsets` is only available on macOS 12.0 and above, which frameworks arent packaged.
118+ # When a lower OS version is detected upstream just returns 0, so we can hardcode that at compiletime.
119+ # https://github.com/koekeishiya/yabai/blob/v4.0.2/src/workspace.m#L109
120+ substituteInPlace src/workspace.m \
121+ --replace 'return screen.safeAreaInsets.top;' 'return 0;'
122+ '';
123+124+ installPhase = ''
125+ runHook preInstall
126+127+ mkdir -p $out/{bin,share/icons/hicolor/scalable/apps}
128+129+ cp ./bin/yabai $out/bin/yabai
130+ ln -s ${loadScriptingAddition} $out/bin/yabai-load-sa
131+ cp ./assets/icon/icon.svg $out/share/icons/hicolor/scalable/apps/yabai.svg
132+ installManPage ./doc/yabai.1
133+134+ runHook postInstall
135+ '';
136+137+ # Defining this here exposes it as a passthru attribute, which is useful because it allows us to run `builtins.hashFile` on it in pure-eval mode.
138+ # With that we can programatically generate an `/etc/sudoers.d` entry which disables the password requirement, so that a user-agent can run it at login.
139+ loadScriptingAddition = writeShellScript "yabai-load-sa" ''
140+ # For whatever reason the regular commands to load the scripting addition do not work, yabai will throw an error.
141+ # The installation command mutably installs binaries to '/System', but then fails to start them. Manually running
142+ # the bins as root does start the scripting addition, so this serves as a more user-friendly way to do that.
143+144+ set -euo pipefail
145+146+ if [[ "$EUID" != 0 ]]; then
147+ echo "error: the scripting-addition loader must ran as root. try 'sudo $0'"
148+ exit 1
149+ fi
150+151+ loaderPath="/Library/ScriptingAdditions/yabai.osax/Contents/MacOS/mach_loader";
152+153+ if ! test -x "$loaderPath"; then
154+ echo "could not locate the scripting-addition loader at '$loaderPath', installing it..."
155+ echo "note: this may display an error"
156+157+ eval "$(dirname "''${BASH_SOURCE[0]}")/yabai --install-sa" || true
158+ sleep 1
159+ fi
160+161+ echo "executing loader..."
162+ eval "$loaderPath"
163+ echo "scripting-addition started"
164+ '';
165+166+ passthru.tests.version = test-version;
167+168+ meta = _meta // {
169+ longDescription = _meta.longDescription + ''
170+ Note that due to a nix-only bug the scripting addition cannot be launched using the regular
171+ procedure. Instead, you can use the provided `yabai-load-sa` script.
172+ '';
173+174+ sourceProvenance = with lib.sourceTypes; [
175+ fromSource
176+ ];
177+ };
178+ };
179+}.${stdenv.hostPlatform.system} or (throw "Unsupported platform ${stdenv.hostPlatform.system}")