dotfiles/flakes/emacs/package.nix
2026-07-22 15:03:09 +07:00

160 lines
3.7 KiB
Nix

{ pkgs }:
let
inherit (pkgs) lib;
treeSitterLibraryExtension =
if pkgs.stdenv.hostPlatform.isDarwin then "dylib" else "so";
treeSitterGrammars = {
swift = pkgs.tree-sitter-grammars.tree-sitter-swift;
python = pkgs.tree-sitter-grammars.tree-sitter-python;
typescript = pkgs.tree-sitter-grammars.tree-sitter-typescript;
tsx = pkgs.tree-sitter-grammars.tree-sitter-tsx.override {
location = "tsx";
};
javascript = pkgs.tree-sitter-grammars.tree-sitter-javascript;
json = pkgs.tree-sitter-grammars.tree-sitter-json;
};
treeSitterBundle = pkgs.runCommand "tobmacs-tree-sitter-grammars" { } (
''
mkdir -p "$out/lib"
''
+ lib.concatStringsSep "\n" (lib.mapAttrsToList
(language: grammar: ''
ln -s "${grammar}/parser" \
"$out/lib/libtree-sitter-${language}.${treeSitterLibraryExtension}"
'')
treeSitterGrammars)
);
epkgs = (pkgs.emacsPackagesFor pkgs.emacs).overrideScope (
import ./pkgs { inherit pkgs; }
);
emacsPackages = with epkgs; [
agent-shell
apheleia
avy
cape
catppuccin-theme
cider
clojure-mode
consult
consult-denote
copilot
corfu
denote
diff-hl
dockerfile-mode
ef-themes
eglot
envrc
exec-path-from-shell
flycheck
flycheck-clj-kondo
flycheck-swiftlint
flymake-collection
fontaine
git-timemachine
graphql-mode
helpful
htmlize
jinx
js2-mode
json-mode
ledger-mode
ligature
magit
magit-todos
marginalia
markdown-mode
minions
modus-themes
multiple-cursors
nerd-icons
nerd-icons-completion
nerd-icons-corfu
nerd-icons-dired
nerd-icons-ibuffer
nix-mode
ob-restclient
ob-swift
ob-typescript
olivetti
orderless
org
org-modern
ox-gfm
ox-reveal
pulsar
rainbow-delimiters
rainbow-mode
restclient
smartparens
super-save
swift-mode
swift-ts-mode
terraform-mode
treesit-auto
vertico
vterm
web-mode
winpulse
yaml-mode
yasnippet
];
configDirectory = pkgs.runCommand "tobmacs-config" { } ''
mkdir -p "$out"
cp ${./config/early-init.el} "$out/early-init.el"
cat > "$out/init.el" <<'EOF'
;; -*- lexical-binding: t; -*-
;; --init-directory points at the immutable Nix store. Reset this after
;; startup has found init.el so mutable state remains in the user's home.
(setq user-emacs-directory (expand-file-name "~/.emacs.d/"))
(make-directory user-emacs-directory t)
(setq yas-snippet-dirs '("${./config/snippets}"))
${builtins.readFile ./config/init.el}
${builtins.readFile ./config/lisp/utils.el}
EOF
'';
emacsWithPackages = epkgs.emacsWithPackages (
_: emacsPackages ++ [ treeSitterBundle ]
);
# Make this package own its init directory, including a real early-init.el.
# The inner emacsWithPackages wrapper still supplies all package load paths.
emacs = pkgs.symlinkJoin {
name = "tobmacs-emacs";
paths = [ emacsWithPackages ];
nativeBuildInputs = [ pkgs.makeBinaryWrapper ];
postBuild = ''
wrapProgramBinary "$out/bin/emacs" \
--add-flags "--init-directory=${configDirectory}"
if [ -x "$out/Applications/Emacs.app/Contents/MacOS/Emacs" ]; then
wrapProgramBinary "$out/Applications/Emacs.app/Contents/MacOS/Emacs" \
--add-flags "--init-directory=${configDirectory}"
fi
'';
meta = emacsWithPackages.meta;
};
in
pkgs.buildEnv {
name = "tobmacs";
paths = [
emacs
pkgs.enchant
pkgs.hunspell
pkgs.hunspellDicts.de_DE
pkgs.hunspellDicts.en_US
];
meta = emacs.meta // {
description = "Emacs with Tobias Ostner's configuration and packages";
mainProgram = "emacs";
};
}