about summary refs log tree commit diff
path: root/users/tazjin/emacs/default.nix
blob: c7c57ba35543c96bd5a18d6538b91c43a7cf6733 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
# This file builds an Emacs pre-configured with the packages I need
# and my personal Emacs configuration.
{ lib, pkgs, ... }:

pkgs.makeOverridable({ emacs ? pkgs.emacsGcc }:
let
  emacsWithPackages = (pkgs.emacsPackagesGen emacs).emacsWithPackages;

  # If switching telega versions, use this variable because it will
  # keep the version check, binary path and so on in sync.
  currentTelega = epkgs: epkgs.melpaPackages.telega;

  # $PATH for binaries that need to be available to Emacs
  emacsBinPath = lib.makeBinPath [
    (currentTelega pkgs.emacsPackages)
    pkgs.libwebp # for dwebp, required by telega
  ];

  identity = x: x;

  tazjinsEmacs = pkgfun: (emacsWithPackages(epkgs: pkgfun(with epkgs; [
    ace-link
    ace-window
    avy
    bazel
    browse-kill-ring
    cargo
    clojure-mode
    cmake-mode
    company
    counsel
    counsel-notmuch
    d-mode
    direnv
    dockerfile-mode
    eglot
    elfeed
    elixir-mode
    elm-mode
    erlang
    exwm
    flymake
    go-mode
    google-c-style
    gruber-darker-theme
    haskell-mode
    ht
    hydra
    idle-highlight-mode
    ivy
    ivy-prescient
    jq-mode
    kotlin-mode
    lsp-mode
    magit
    markdown-toc
    meson-mode
    multi-term
    multiple-cursors
    nginx-mode
    nix-mode
    notmuch
    paredit
    password-store
    pinentry
    polymode
    prescient
    protobuf-mode
    rainbow-delimiters
    rainbow-mode
    refine
    request
    restclient
    rust-mode
    sly
    string-edit
    swiper
    telephone-line
    terraform-mode
    toml-mode
    transient
    undo-tree
    use-package
    uuidgen
    vterm
    web-mode
    websocket
    which-key
    xelb
    yaml-mode
    yasnippet
    zoxide

    # Wonky stuff
    (currentTelega epkgs)

    # Custom depot packages (either ours, or overridden ones)
    tvlPackages.dottime
    tvlPackages.nix-util
    tvlPackages.passively
    tvlPackages.rcirc
    tvlPackages.term-switcher
    tvlPackages.tvl
  ])));

  # Tired of telega.el runtime breakages through tdlib
  # incompatibility. Target to make that a build failure instead.
  tdlibCheck =
    let
      tgEmacs = emacsWithPackages(epkgs: [ (currentTelega epkgs) ]);
      verifyTdlibVersion = builtins.toFile "verify-tdlib-version.el" ''
        (require 'telega)
        (defvar tdlib-version "${pkgs.tdlib.version}")
        (when (or (version< tdlib-version
                            telega-tdlib-min-version)
                  (and telega-tdlib-max-version
                        (version< telega-tdlib-max-version
                                  tdlib-version)))
           (message "Found TDLib version %s, but require %s to %s"
                   tdlib-version telega-tdlib-min-version telega-tdlib-max-version)
          (kill-emacs 1))
       '';
    in pkgs.runCommandNoCC "tdlibCheck" {} ''
      export PATH="${emacsBinPath}:$PATH"
      ${tgEmacs}/bin/emacs --script ${verifyTdlibVersion} && touch $out
    '';
in lib.fix(self: l: f: pkgs.writeShellScriptBin "tazjins-emacs" ''
  export PATH="${emacsBinPath}:$PATH"
  exec ${tazjinsEmacs f}/bin/emacs \
    --debug-init \
    --no-site-file \
    --no-site-lisp \
    --no-init-file \
    --directory ${./config} ${if l != null then "--directory ${l}" else ""} \
    --eval "(require 'init)" $@
  '' // {
    # Call overrideEmacs with a function (pkgs -> pkgs) to modify the
    # packages that should be included in this Emacs distribution.
    overrideEmacs = f': self l f';

    # Call withLocalConfig with the path to a *folder* containing a
    # `local.el` which provides local system configuration.
    withLocalConfig = confDir: self confDir f;

    # Build a derivation that uses the specified local Emacs (i.e.
    # built outside of Nix) instead
    withLocalEmacs = emacsBin: pkgs.writeShellScriptBin "tazjins-emacs" ''
      export PATH="${emacsBinPath}:$PATH"
      export EMACSLOADPATH="${(tazjinsEmacs f).deps}/share/emacs/site-lisp:"
      exec ${emacsBin} \
        --debug-init \
        --no-site-file \
        --no-site-lisp \
        --no-init-file \
        --directory ${./config} \
        ${if l != null then "--directory ${l}" else ""} \
        --eval "(require 'init)" $@
    '';

    # Expose telega/tdlib version check as a target that is built in
    # CI.
    #
    # TODO(tazjin): uncomment when telega works again
    inherit tdlibCheck;
    # meta.targets = [ "tdlibCheck" ];
  }) null identity
) {}