Files
dotfiles/nixos/emacs-overlay.nix

133 lines
3.7 KiB
Nix
Raw Normal View History

final: prev:
{
# Keep pkgs.emacs as a real Emacs package (used by other derivations / emacsPackages),
# but provide an "auto" wrapper for interactive use that selects the right GUI backend.
emacs = prev."emacs30-pgtk".override {
withNativeCompilation = true;
withTreeSitter = true;
};
emacs-wayland = final.emacs;
emacs-x11 = prev.emacs30.override {
withNativeCompilation = true;
withTreeSitter = true;
};
# Runtime launcher that chooses:
# - Wayland session: pgtk build with GDK_BACKEND=wayland (avoids XWayland)
# - X11 session: X11 build with GDK_BACKEND=x11
# - No display: falls back to -nw
#
# Override with EMACS_AUTO_BACKEND=wayland|x11|tty.
emacs-auto = final.stdenvNoCC.mkDerivation {
pname = "emacs-auto";
version = final.emacs.version or "unknown";
dontUnpack = true;
nativeBuildInputs = [ final.makeWrapper ];
installPhase =
let
emacsWayland = final.emacs-wayland;
emacsX11 = final.emacs-x11;
in
''
mkdir -p "$out/bin" "$out/share/applications" "$out/share/icons" "$out/share/pixmaps"
# Ensure desktop integrations (icons) exist even though we don't install the raw emacs packages.
if [ -d "${emacsWayland}/share/icons" ]; then
ln -s "${emacsWayland}/share/icons/hicolor" "$out/share/icons/hicolor"
fi
if [ -d "${emacsWayland}/share/pixmaps" ]; then
ln -s "${emacsWayland}/share/pixmaps/"* "$out/share/pixmaps/" || true
fi
# Convenience explicit launchers.
makeWrapper ${emacsWayland}/bin/emacs "$out/bin/emacs-wayland" \
--set GDK_BACKEND wayland
makeWrapper ${emacsX11}/bin/emacs "$out/bin/emacs-x11" \
--set GDK_BACKEND x11
# Main launcher.
cat > "$out/bin/emacs" <<'EOF_EMACS_WRAPPER'
#!${final.runtimeShell}
set -eu
backend="''${EMACS_AUTO_BACKEND:-}"
tty=0
for a in "$@"; do
case "$a" in
-nw|--nw|--tty|--terminal|--no-window-system) tty=1 ;;
esac
done
if [ "$backend" = "wayland" ] || [ "$backend" = "pgtk" ]; then
exec "@out@/bin/emacs-wayland" "$@"
fi
if [ "$backend" = "x11" ]; then
exec "@out@/bin/emacs-x11" "$@"
fi
if [ "$backend" = "tty" ]; then
exec "@emacsX11@/bin/emacs" -nw "$@"
fi
if [ "$tty" -eq 1 ]; then
# Respect the user's explicit -nw, but still run a consistent binary.
exec "@emacsX11@/bin/emacs" "$@"
fi
# Prefer Wayland if it looks like a Wayland session.
if [ -n "''${WAYLAND_DISPLAY:-}" ] || [ "''${XDG_SESSION_TYPE:-}" = "wayland" ] || [ -n "''${HYPRLAND_INSTANCE_SIGNATURE:-}" ]; then
exec "@out@/bin/emacs-wayland" "$@"
fi
# Otherwise, if X is available, use the X11 build.
if [ -n "''${DISPLAY:-}" ] || [ "''${XDG_SESSION_TYPE:-}" = "x11" ]; then
exec "@out@/bin/emacs-x11" "$@"
fi
# Headless fallback.
exec "@emacsX11@/bin/emacs" -nw "$@"
EOF_EMACS_WRAPPER
substituteInPlace "$out/bin/emacs" \
--subst-var out \
--replace-fail "@emacsX11@" "${emacsX11}"
chmod +x "$out/bin/emacs"
# emacsclient is compatible across builds as long as versions match; use one.
ln -s ${emacsX11}/bin/emacsclient "$out/bin/emacsclient"
cat > "$out/share/applications/emacs.desktop" <<'EOF'
[Desktop Entry]
Name=Emacs
GenericName=Text Editor
Comment=Edit text
Exec=emacs %F
TryExec=emacs
Icon=emacs
Type=Application
Terminal=false
Categories=Development;TextEditor;
MimeType=text/plain;
StartupWMClass=Emacs
EOF
cat > "$out/share/applications/emacsclient.desktop" <<'EOF'
[Desktop Entry]
Name=Emacs (Client)
GenericName=Text Editor
Comment=Edit text using a running Emacs server
Exec=emacsclient -c -a emacs %F
TryExec=emacsclient
Icon=emacs
Type=Application
Terminal=false
Categories=Development;TextEditor;
MimeType=text/plain;
StartupWMClass=Emacs
EOF
'';
};
}