diff --git a/nixos/tests/terminal-emulators.nix b/nixos/tests/terminal-emulators.nix index 1affcbf3c8f79..3fc820d3ac8ba 100644 --- a/nixos/tests/terminal-emulators.nix +++ b/nixos/tests/terminal-emulators.nix @@ -44,6 +44,8 @@ let germinal.pkg = p: p.germinal; + ghostty.pkg = p: p.ghostty; + gnome-terminal.pkg = p: p.gnome-terminal; guake.pkg = p: p.guake; diff --git a/pkgs/by-name/gh/ghostty/package.nix b/pkgs/by-name/gh/ghostty/package.nix index cbafd16ba3623..dc5e936d2e141 100644 --- a/pkgs/by-name/gh/ghostty/package.nix +++ b/pkgs/by-name/gh/ghostty/package.nix @@ -1,44 +1,59 @@ { + lib, + stdenv, bzip2, callPackage, - expat, fetchFromGitHub, fontconfig, freetype, glib, glslang, harfbuzz, - lib, - libadwaita, libGL, - libpng, libX11, - libXcursor, - libXi, - libXrandr, + libadwaita, ncurses, nixosTests, oniguruma, pandoc, pkg-config, removeReferencesTo, - stdenv, versionCheckHook, wrapGAppsHook4, zig_0_13, - zlib, + # Usually you would override `zig.hook` with this, but we do that internally + # since upstream recommends a non-default level + # https://github.com/ghostty-org/ghostty/blob/4b4d4062dfed7b37424c7210d1230242c709e990/PACKAGING.md#build-options + optimizeLevel ? "ReleaseFast", + # https://github.com/ghostty-org/ghostty/blob/4b4d4062dfed7b37424c7210d1230242c709e990/build.zig#L106 + withAdwaita ? true, }: + let - # Ghostty needs to be built with --release=fast, --release=debug and - # --release=safe enable too many runtime safety checks. zig_hook = zig_0_13.hook.overrideAttrs { - zig_default_flags = "-Dcpu=baseline -Doptimize=ReleaseFast --color off"; + zig_default_flags = "-Dcpu=baseline -Doptimize=${optimizeLevel} --color off"; }; + + # https://github.com/ghostty-org/ghostty/blob/4b4d4062dfed7b37424c7210d1230242c709e990/src/apprt.zig#L72-L76 + appRuntime = if stdenv.hostPlatform.isLinux then "gtk" else "none"; + # https://github.com/ghostty-org/ghostty/blob/4b4d4062dfed7b37424c7210d1230242c709e990/src/font/main.zig#L94 + fontBackend = if stdenv.hostPlatform.isDarwin then "coretext" else "fontconfig_freetype"; + # https://github.com/ghostty-org/ghostty/blob/4b4d4062dfed7b37424c7210d1230242c709e990/src/renderer.zig#L51-L52 + renderer = if stdenv.hostPlatform.isDarwin then "metal" else "opengl"; in + stdenv.mkDerivation (finalAttrs: { pname = "ghostty"; version = "1.0.0"; + outputs = [ + "out" + "man" + "shell_integration" + "terminfo" + "vim" + ]; + src = fetchFromGitHub { owner = "ghostty-org"; repo = "ghostty"; @@ -46,50 +61,56 @@ stdenv.mkDerivation (finalAttrs: { hash = "sha256-AHI1Z4mfgXkNwQA8xYq4tS0/BARbHL7gQUT41vCxQTM="; }; - strictDeps = true; - - nativeBuildInputs = [ - glib # Required for `glib-compile-schemas` - ncurses - pandoc - pkg-config - removeReferencesTo - wrapGAppsHook4 - zig_hook - ]; - - buildInputs = [ - bzip2 - expat - fontconfig - freetype - glslang - harfbuzz - libadwaita - libGL - libpng - libX11 - libXcursor - libXi - libXrandr - oniguruma - zlib - ]; - - dontConfigure = true; - # doCheck is set to false because unit tests currently fail inside the Nix sandbox. - doCheck = false; - doInstallCheck = true; + # Avoid using runtime hacks to help find X11 + postPatch = lib.optionalString (appRuntime == "gtk") '' + substituteInPlace src/apprt/gtk/x11.zig \ + --replace-warn 'std.DynLib.open("libX11.so");' 'std.DynLib.open("${lib.getLib libX11}/lib/libX11.so");' + ''; deps = callPackage ./deps.nix { name = "${finalAttrs.pname}-cache-${finalAttrs.version}"; }; + strictDeps = true; + + nativeBuildInputs = + [ + ncurses + pandoc + pkg-config + removeReferencesTo + zig_hook + ] + ++ lib.optionals (appRuntime == "gtk") [ + glib # Required for `glib-compile-schemas` + wrapGAppsHook4 + ]; + + buildInputs = + [ + glslang + oniguruma + ] + ++ lib.optional (appRuntime == "gtk" && withAdwaita) libadwaita + ++ lib.optional (appRuntime == "gtk") libX11 + ++ lib.optional (renderer == "opengl") libGL + ++ lib.optionals (fontBackend == "fontconfig_freetype") [ + bzip2 + fontconfig + freetype + harfbuzz + ]; + zigBuildFlags = [ "--system" "${finalAttrs.deps}" "-Dversion-string=${finalAttrs.version}" + + "-Dapp-runtime=${appRuntime}" + "-Dfont-backend=${fontBackend}" + "-Dgtk-adwaita=${lib.boolToString withAdwaita}" + "-Drenderer=${renderer}" ] ++ lib.mapAttrsToList (name: package: "-fsys=${name} --search-prefix ${lib.getLib package}") { inherit glslang; @@ -97,40 +118,65 @@ stdenv.mkDerivation (finalAttrs: { zigCheckFlags = finalAttrs.zigBuildFlags; - outputs = [ - "out" - "terminfo" - "shell_integration" - "vim" - ]; + # Unit tests currently fail inside the sandbox + doCheck = false; - postInstall = '' - mkdir -p "$terminfo/share" - mv "$out/share/terminfo" "$terminfo/share/terminfo" - ln -sf "$terminfo/share/terminfo" "$out/share/terminfo" + /** + Ghostty really likes all of it's resources to be in the same directory, so link them back after we split them - mkdir -p "$shell_integration" - mv "$out/share/ghostty/shell-integration" "$shell_integration/shell-integration" - ln -sf "$shell_integration/shell-integration" "$out/share/ghostty/shell-integration" + - https://github.com/ghostty-org/ghostty/blob/4b4d4062dfed7b37424c7210d1230242c709e990/src/os/resourcesdir.zig#L11-L52 + - https://github.com/ghostty-org/ghostty/blob/4b4d4062dfed7b37424c7210d1230242c709e990/src/termio/Exec.zig#L745-L750 + - https://github.com/ghostty-org/ghostty/blob/4b4d4062dfed7b37424c7210d1230242c709e990/src/termio/Exec.zig#L818-L834 + + terminfo and shell integration should also be installable on remote machines + + ```nix + { pkgs, ... }: { + environment.systemPackages = [ pkgs.ghostty.terminfo ]; + + programs.bash = { + interactiveShellInit = '' + if [[ "$TERM" == "xterm-ghostty" ]]; then + builtin source ${pkgs.ghostty.shell_integration}/bash/ghostty.bash + fi + ''; + }; + } + ``` + */ + postFixup = '' + ln -s $man/share/man $out/share/man + + moveToOutput share/terminfo $terminfo + ln -s $terminfo/share/terminfo $out/share/terminfo + + mv $out/share/ghostty/shell-integration $shell_integration + ln -s $shell_integration $out/share/ghostty/shell-integration + + mv $out/share/vim/vimfiles $vim + rmdir $out/share/vim + ln -s $vim $out/share/vim-plugins - mv "$out/share/vim/vimfiles" "$vim" - ln -sf "$vim" "$out/share/vim/vimfiles" - ''; - preFixup = '' remove-references-to -t ${finalAttrs.deps} $out/bin/ghostty ''; - NIX_LDFLAGS = [ "-lX11" ]; - nativeInstallCheckInputs = [ versionCheckHook ]; + doInstallCheck = true; + versionCheckProgramArg = [ "--version" ]; + passthru = { + tests = lib.optionalAttrs stdenv.hostPlatform.isLinux { + inherit (nixosTests) allTerminfo; + nixos = nixosTests.terminal-emulators.ghostty; + }; + }; + meta = { - homepage = "https://ghostty.org/"; description = "Fast, native, feature-rich terminal emulator pushing modern features"; longDescription = '' Ghostty is a terminal emulator that differentiates itself by being @@ -138,16 +184,24 @@ stdenv.mkDerivation (finalAttrs: { emulators available, they all force you to choose between speed, features, or native UIs. Ghostty provides all three. ''; + homepage = "https://ghostty.org/"; downloadPage = "https://ghostty.org/download"; license = lib.licenses.mit; - platforms = lib.platforms.linux; mainProgram = "ghostty"; - outputsToInstall = finalAttrs.outputs; maintainers = with lib.maintainers; [ jcollie pluiedev getchoo ]; + outputsToInstall = [ + "out" + "man" + "shell_integration" + "terminfo" + ]; + platforms = lib.platforms.linux ++ lib.platforms.darwin; + # Issues finding the SDK in the sandbox + broken = stdenv.hostPlatform.isDarwin; }; })