-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathnix-haskell-mode.el
569 lines (494 loc) · 22.8 KB
/
nix-haskell-mode.el
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
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
;;; nix-haskell-mode.el --- haskell-mode integrations for Nix -*- lexical-binding: t -*-
;; Copyright (C) 2019 Matthew Bauer
;; Author: Matthew Bauer <mjbauer95@gmail.com>
;; Homepage: https://github.com/matthewbauer/nix-haskell
;; Keywords: nix, haskell, languages, processes
;; Version: 0.0.3
;; Package-Requires: ((emacs "25") (haskell-mode "16.0") (nix-mode "1.3.0"))
;; This file is NOT part of GNU Emacs.
;; This file is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 3, or (at your option)
;; any later version.
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;; For a full copy of the GNU General Public License
;; see <http://www.gnu.org/licenses/>.
;;; Commentary:
;; Setup for this is fairly straightforward. It aims to automatically
;; configure everything for you. It assumes that you are already using
;; haskell-mode and flycheck.
;; If you have use-package setup, this is enough to get nix-haskell
;; working,
;; (use-package nix-haskell
;; :hook (haskell-mode . nix-haskell-mode))
;; Opening a buffer will start a nix process to get your dependencies.
;; Flycheck and interactive-haskell-mode will start running once they
;; have been downloaded. This is cached so it will only be done once
;; for each buffer.
;; Flycheck will be started automatically. To start a haskell session,
;; press C-c C-l.
;; nix-haskell is designed to build package dbs in Nix and then pass
;; them to GHC. This should avoid some of the security issues in using
;; ‘nix-shell’ automatically in visited directories.
;;; History:
;; This originally lived in https://github.com/matthewbauer/bauer but
;; was moved so it could be included in MELPA.
;;; Code:
(require 'nix)
(require 'nix-instantiate)
(require 'nix-store)
(require 'haskell)
(defgroup nix-haskell nil
"Nix integration with haskell-mode.el"
:group 'nix)
(defcustom nix-haskell-verbose nil
"Whether to print lots of messages when running nix-haskell.el."
:type 'boolean
:group 'nix-haskell)
(defcustom nix-haskell-ttl (* 60 10)
"Time in seconds to keep the cache."
:type 'integer
:group 'nix-haskell)
(defcustom nix-haskell-flycheck nil
"Whether to enable flycheck."
:type 'boolean
:group 'nix-haskell)
(defcustom nix-haskell-interactive t
"Whether to enable variable ‘interactive-haskell-mode’."
:type 'boolean
:group 'nix-haskell)
(defcustom nix-haskell-interactive-auto t
"Whether to start an variable ‘interactive-haskell-mode’ session automatically."
:type 'boolean
:group 'nix-haskell)
;; Prefix to use in the lighters
(defconst nix-haskell-lighter-prefix " NixH")
;; Expression used to build Haskell’s package db
;; We don’t want to just get ghc from the Nix file. This would leave
;; us vulnerable to malicious projects. Instead, we get the compiler
;; name and try to find it in nixpkgs.haskell.compiler. These aren’t
;; left in Nixpkgs for very long so we try to download some channels
;; to see if they are in there.
(defvar nix-haskell-pkg-db-expr "{ pkgs ? import <nixpkgs> {}
, haskellPackages ? pkgs.haskellPackages
, nixFile ? null, packageName, cabalFile
, compilers ? {
ghc6104 = (import (builtins.fetchTarball \"channel:nixos-17.09\") {}).haskell.compiler.ghc6104;
ghc6121 = (import (builtins.fetchTarball \"channel:nixos-14.04\") {}).pkgs.haskell.packages_ghc6121.ghc;
ghc6122 = (import (builtins.fetchTarball \"channel:nixos-14.04\") {}).pkgs.haskell.packages_ghc6122.ghc;
ghc6123 = (import (builtins.fetchTarball \"channel:nixos-17.09\") {}).haskell.compiler.ghc6123;
ghc701 = (import (builtins.fetchTarball \"channel:nixos-14.04\") {}).pkgs.haskell.packages_ghc701.ghc;
ghc702 = (import (builtins.fetchTarball \"channel:nixos-14.04\") {}).pkgs.haskell.packages_ghc702.ghc;
ghc703 = (import (builtins.fetchTarball \"channel:nixos-14.04\") {}).pkgs.haskell.packages_ghc703.ghc;
ghc704 = (import (builtins.fetchTarball \"channel:nixos-18.03\") {}).haskell.compiler.ghc704;
ghc721 = (import (builtins.fetchTarball \"channel:nixos-14.04\") {}).pkgs.haskell.packages_ghc721.ghc;
ghc722 = (import (builtins.fetchTarball \"channel:nixos-17.09\") {}).haskell.compiler.ghc722;
ghc741 = (import (builtins.fetchTarball \"channel:nixos-14.04\") {}).pkgs.haskell.packages_ghc741.ghc;
ghc742 = (import (builtins.fetchTarball \"channel:nixos-18.03\") {}).haskell.compiler.ghc742;
ghc761 = (import (builtins.fetchTarball \"channel:nixos-14.04\") {}).pkgs.haskell.packages_ghc761.ghc;
ghc762 = (import (builtins.fetchTarball \"channel:nixos-14.04\") {}).pkgs.haskell.packages_ghc762.ghc;
ghc763 = (import (builtins.fetchTarball \"channel:nixos-18.03\") {}).haskell.compiler.ghc763;
ghc783 = (import (builtins.fetchTarball \"channel:nixos-17.09\") {}).haskell.compiler.ghc783;
ghc784 = (import (builtins.fetchTarball \"channel:nixos-18.03\") {}).haskell.compiler.ghc784;
ghc7102 = (import (builtins.fetchTarball \"channel:nixos-17.09\") {}).haskell.compiler.ghc7102;
ghc7103 = (import (builtins.fetchTarball \"channel:nixos-18.09\") {}).haskell.compiler.ghc7103;
ghc801 = (import (builtins.fetchTarball \"channel:nixos-17.09\") {}).haskell.compiler.ghc801;
ghc802 = (import (builtins.fetchTarball \"channel:nixos-18.09\") {}).haskell.compiler.ghc802;
ghc821 = (import (builtins.fetchTarball \"channel:nixos-17.09\") {}).haskell.compiler.ghc821;
ghc822 = (import (builtins.fetchTarball \"channel:nixos-19.03\") {}).haskell.compiler.ghc822;
ghc841 = (import (builtins.fetchTarball \"channel:nixos-18.03\") {}).haskell.compiler.ghc841;
ghc843 = (import (builtins.fetchTarball \"channel:nixos-18.09\") {}).haskell.compiler.ghc843;
ghc844 = (import (builtins.fetchTarball \"channel:nixos-19.03\") {}).haskell.compiler.ghc844;
ghc861 = (import (builtins.fetchTarball \"channel:nixos-18.09\") {}).haskell.compiler.ghc861;
ghc862 = (import (builtins.fetchTarball \"channel:nixos-18.09\") {}).haskell.compiler.ghc862;
ghc863 = (import (builtins.fetchTarball \"channel:nixos-18.09\") {}).haskell.compiler.ghc863;
ghc864 = (import (builtins.fetchTarball \"channel:nixos-19.03\") {}).haskell.compiler.ghc864;
} }: let
inherit (pkgs) lib;
getGhc = name: let compilerName = lib.replaceStrings [\".\" \"-\"] [\"\" \"\"] name;
in pkgs.haskell.compiler.${compilerName} or compilers.${compilerName} or (throw \"Can’t find haskell compiler ${compilerName}\");
buildPkgDb = pkg: let
maybeGhc = if pkg.nativeBuildInputs != [] then builtins.head pkg.nativeBuildInputs else null;
compiler = if pkg ? compiler then getGhc pkg.compiler.name
else if maybeGhc != null && builtins.match \"^ghc.*\" maybeGhc.name != null
then getGhc (if maybeGhc ? version then \"ghc-${maybeGhc.version}\" else maybeGhc.name)
else throw \"Can’t find compiler for ${pkg.name}.\";
package-db = pkgs.buildEnv {
name = \"${packageName}-package-db-${compiler.name}\";
paths = [ compiler ] ++ lib.closePropagation
(pkg.getBuildInputs.haskellBuildInputs or
(pkg.buildInputs ++ pkg.propagatedBuildInputs ++ pkg.nativeBuildInputs));
pathsToLink = [ \"/lib/${compiler.name}/package.conf.d\" ];
buildInputs = [ compiler ];
postBuild = ''
ghc-pkg --package-db=$out/lib/${compiler.name}/package.conf.d recache
'';
ignoreCollisions = true;
};
compilerBin = pkgs.buildEnv {
name = \"${compiler.name}-bins\";
paths = [ compiler ];
pathsToLink = [ \"/bin\" ];
};
in pkgs.buildEnv {
name = \"${packageName}-${compiler.name}-wrapped\";
paths = [ package-db pkgs.cabal-install compilerBin ];
};
pkg = if nixFile == null
then haskellPackages.callCabal2nix \"auto-callcabal2nix\" (builtins.toPath cabalFile) {}
else (let nixExpr = import nixFile;
nixExpr' = if builtins.isFunction nixExpr
then (if (builtins.functionArgs nixExpr) ? mkDerivation
then haskellPackages.callPackage nixFile {}
else nixExpr {})
else nixExpr;
in (if lib.isDerivation nixExpr'
then (if nixExpr' ? shells
then nixExpr'.shells.ghc
else nixExpr')
else if builtins.isAttrs nixExpr'
then let nixExpr'' = if nixExpr' ? proj then nixExpr'.proj
else if nixExpr' ? shells then nixExpr'
else if nixExpr' ? haskellPackages then nixExpr'.haskellPackages
else if nixExpr' ? haskellPackageSets then nixExpr'.haskellPackageSets.ghc
else if nixExpr' ? ghc then nixExpr'.ghc
else nixExpr';
in (if nixExpr'' ? shells then nixExpr''.shells.ghc
else if nixExpr'' ? ${packageName} then nixExpr''.${packageName}
else if nixExpr'' ? callCabal2nix
then nixExpr''.callCabal2nix \"auto-callcabal2nix\" (builtins.toPath cabalFile) {}
else haskellPackages.callCabal2nix \"auto-callcabal2nix\" (builtins.toPath cabalFile) {})
else throw \"Can't import ${nixFile} correctly.\"));
in buildPkgDb pkg")
(defvar nix-haskell-running-processes nil
"Store information on running Nix evaluations.")
(defvar nix-haskell-package-db-cache nil
"Cache information on past Nix evaluations.")
(defvar-local nix-haskell-package-name nil
"Stores the package name.")
(defvar-local nix-haskell-status (concat nix-haskell-lighter-prefix "?")
"Get the status of nix-haskell buffer.")
(defun nix-haskell-clear-cache ()
"Clean the nix-haskell cache."
(interactive)
(setq nix-haskell-package-db-cache nil))
(defun nix-haskell-message (str)
"Messaging appropriate in nix-haskell async processes.
STR message to send to minibuffer"
(unless (active-minibuffer-window)
(message "%s" str)))
(defun nix-haskell-store-sentinel (err buf drv-file drv _ event)
"Make a nix-haskell process.
ERR the error buffer.
BUF the main buffer.
DRV-FILE filename of derivation.
DRV parsed derivation file.
PROC the process that has been run.
EVENT the event that was fired."
(pcase event
("finished\n"
(kill-buffer err)
(nix-haskell-interactive buf drv-file drv))
(_
;; (display-buffer err)
(nix-haskell-message "Running nix-haskell failed to realise the store path")
(setq nix-haskell-status (concat nix-haskell-lighter-prefix "!")))))
(defun nix-haskell-instantiate-sentinel (prop err proc event)
"Make a nix-haskell process.
PROP the prop name of ‘nix-haskell-running-processes’.
ERR the error buffer.
PROC the process that has been run.
EVENT the event that was fired."
(pcase event
("finished\n"
(with-current-buffer (process-buffer proc)
(unless (eq (buffer-size) 0)
;; Parse nix-instantiate output
(let* ((drv-file (substring (buffer-string) 0 (- (buffer-size) 1)))
(drv (nix-instantiate--parsed drv-file))
;; Hacky way to get output path without building it.
(out (cdadr (cadar drv))))
(dolist
(callback (lax-plist-get nix-haskell-running-processes prop))
(funcall callback out drv-file))
(setq nix-haskell-package-db-cache
(lax-plist-put nix-haskell-package-db-cache
prop (list (float-time) out drv-file))))))
(setq nix-haskell-running-processes
(lax-plist-put nix-haskell-running-processes prop nil))
(kill-buffer err))
(_
;; (display-buffer err)
(nix-haskell-message "Running nix-haskell failed to instantiate")
(setq nix-haskell-status (concat nix-haskell-lighter-prefix "!"))))
(unless (process-live-p proc)
(kill-buffer (process-buffer proc))))
(defun nix-haskell-root ()
"Get the nix-haskell root."
(let (root)
(or
(setq root (locate-dominating-file default-directory "cabal.project"))
(setq root (locate-dominating-file default-directory "default.nix"))
(setq root (locate-dominating-file default-directory "shell.nix"))
(setq root (file-name-directory (nix-haskell-cabal-file))))
(when root
(setq root (expand-file-name root)))
root))
(defun nix-haskell-package-name ()
"Get the package name of the project."
(unless nix-haskell-package-name
(setq nix-haskell-package-name
(replace-regexp-in-string
".cabal$" ""
(file-name-nondirectory (nix-haskell-cabal-file)))))
nix-haskell-package-name)
(defun nix-haskell-nix-file ()
"Get the nix file based on the current directory."
(let ((root (nix-haskell-root)) nix-file)
;; Look for shell.nix or default.nix
(unless (and nix-file (file-exists-p nix-file))
(setq nix-file (expand-file-name "shell.nix" root)))
(unless (and nix-file (file-exists-p nix-file))
(setq nix-file (expand-file-name "default.nix" root)))
(when (and nix-file (file-exists-p nix-file)) nix-file)))
(defvar-local nix-haskell-instantiate-stderr nil
"Store stderr buffer")
(defvar-local nix-haskell-store-stderr nil
"Store stderr buferr")
(defun nix-haskell-get-pkg-db (callback)
"Get a package-db async.
CALLBACK called once the package-db is determined."
(let* ((cabal-file (nix-haskell-cabal-file))
(cache (lax-plist-get nix-haskell-package-db-cache cabal-file))
(root (nix-haskell-root))
(nix-file (nix-haskell-nix-file))
(package-name (nix-haskell-package-name)))
(when cache (apply callback (cdr cache)))
(when (or (not cache)
(> (float-time) (+ (car cache) nix-haskell-ttl))
(> (time-to-seconds
(nth 5 (file-attributes cabal-file)))
(car cache)))
(setq nix-haskell-instantiate-stderr
(generate-new-buffer
(format "*nix-haskell-instantiate-stderr<%s>*"
package-name)))
(let* ((data (lax-plist-get nix-haskell-running-processes cabal-file))
(stdout (generate-new-buffer
(format "*nix-haskell-instantiate-stdout<%s>*"
package-name)))
(command
(list nix-instantiate-executable
"-E" nix-haskell-pkg-db-expr
"--argstr" "cabalFile" cabal-file
"--argstr" "packageName" package-name)))
(when nix-haskell-verbose
(nix-haskell-message (format "Running nix-instantiate for %s..." cabal-file)))
(when nix-file
(when nix-haskell-verbose
(nix-haskell-message (format "Found Nix file at %s." nix-file)))
(setq command
(append command (list "--argstr" "nixFile" nix-file))))
;; Pick up projects with custom package sets. This is
;; required for some important projects like those based on
;; Obelisk or reflex-platform.
(cond
((file-exists-p (expand-file-name "reflex-platform.nix" root))
(when nix-haskell-verbose
(nix-haskell-message "Detected reflex-platform project."))
(setq command
(append command
(list "--arg" "haskellPackages"
(format "(import %s {}).ghc"
(expand-file-name "reflex-platform.nix"
root))))))
((file-exists-p (expand-file-name ".obelisk/impl/default.nix" root))
(when nix-haskell-verbose
(nix-haskell-message "Detected obelisk project."))
(setq command
(append command
(list "--arg" "haskellPackages"
(format "(import %s {}).haskellPackageSets.ghc"
(expand-file-name
".obelisk/impl/default.nix" root))))))
;; ((and (file-exists-p (expand-file-name "default.nix" root))
;; (not (string= (expand-file-name "default.nix" root)
;; nix-file)))
;; (when nix-haskell-verbose
;; (nix-haskell-message "Detected default.nix."))
;; (setq command
;; (append command
;; (list "--arg" "haskellPackages"
;; (format "(import %s {})"
;; (expand-file-name "default.nix"
;; root))))))
)
(setq nix-haskell-running-processes
(lax-plist-put nix-haskell-running-processes
cabal-file (cons callback data)))
;; (when nix-haskell-verbose
;; (nix-haskell-message (format "Running %s." command)))
(setq nix-haskell-status (concat nix-haskell-lighter-prefix "*"))
(make-process
:name (format "*nix-haskell*<%s>" package-name)
:buffer stdout
:command command
:noquery t
:sentinel (apply-partially 'nix-haskell-instantiate-sentinel
cabal-file nix-haskell-instantiate-stderr)
:stderr nix-haskell-instantiate-stderr)
;; Don’t let hooks wait for make-process.
t))))
(defvar flycheck-haskell-ghc-executable)
(defvar flycheck-haskell-runghc-command)
(defvar flycheck-ghc-package-databases)
(defun nix-haskell-interactive (buf out drv)
"Setup interactive buffers for nix-haskell.
Handles flycheck and haskell-interactive modes currently.
BUF the buffer this was called from.
OUT filename of derivation.
DRV derivation file."
(if (file-exists-p out)
(let ((package-db out))
(when nix-haskell-verbose
(nix-haskell-message "nix-haskell succeeded in buffer."))
(with-current-buffer buf
(setq nix-haskell-status (concat nix-haskell-lighter-prefix
"[" (nix-haskell-package-name) "]"))
;; Find package db directory.
(setq package-db (expand-file-name "lib" package-db))
(setq package-db (expand-file-name
(car (directory-files package-db nil "^ghc"))
package-db))
(setq package-db (expand-file-name "package.conf.d" package-db))
(setq-local haskell-compile-cabal-build-command
(concat "cd %s && " (expand-file-name "bin/cabal" out) " new-build"))
;; Setup haskell-mode args.
(setq-local haskell-process-type 'cabal-new-repl)
(setq-local haskell-process-path-cabal
(expand-file-name "bin/cabal" out))
(make-local-variable 'haskell-process-args-cabal-new-repl)
(add-to-list 'haskell-process-args-cabal-new-repl
(format "--with-ghc-pkg=%s/bin/ghc-pkg" out) t)
(add-to-list 'haskell-process-args-cabal-new-repl
(format "--with-ghc=%s/bin/ghc" out) t)
(add-to-list 'haskell-process-args-cabal-new-repl
(format "--with-hsc2hs=%s/bin/hsc2hs" out) t)
(add-to-list 'haskell-process-args-cabal-new-repl
(format "--ghc-pkg-option=--global-package-db=%s"
package-db) t)
(add-to-list 'haskell-process-args-cabal-new-repl
(format "--ghc-option=-package-db=%s" package-db) t)
(when nix-haskell-interactive
(interactive-haskell-mode 1)
(when nix-haskell-interactive-auto
(let ((haskell-process-load-or-reload-prompt nil))
(haskell-session-new-assume-from-cabal)
(haskell-process-load-file))))
;; Setup flycheck.
(setq-local flycheck-haskell-ghc-executable
(expand-file-name "bin/ghc" out))
(setq-local flycheck-haskell-runghc-command
(list (expand-file-name "bin/runghc" out) "--" "-i"
"-packageCabal" "-packagebase"
"-packagebytestring" "-packagecontainers"
"-packagedirectory" "-packagefilepath"
"-packageprocess"))
(make-local-variable 'flycheck-ghc-package-databases)
(add-to-list 'flycheck-ghc-package-databases package-db)
(when nix-haskell-flycheck
(require 'flycheck)
(require 'flycheck-haskell)
(flycheck-haskell-setup)
(flycheck-mode 1))))
(let ((stderr (generate-new-buffer
(format "*nix-haskell-store<%s>*" (nix-haskell-package-name)))))
(with-current-buffer buf
(setq nix-haskell-status (concat nix-haskell-lighter-prefix "+"))
(setq nix-haskell-store-stderr stderr))
(make-process
:name (format "*nix-haskell-store<%s>*" (nix-haskell-package-name))
:buffer nil
:command (list nix-store-executable "-r" drv)
:noquery t
:sentinel (apply-partially 'nix-haskell-store-sentinel
stderr buf out drv)
:stderr stderr))))
(defun nix-haskell-status ()
"Get the current status of a buffer."
nix-haskell-status)
(defun nix-haskell-cabal-file ()
"Get the current cabal file for the project."
(let ((cabal-file (haskell-cabal-find-file default-directory)))
(when cabal-file (setq cabal-file (expand-file-name cabal-file)))
cabal-file))
(defun nix-haskell-restart ()
"Restart variable ‘nix-haskell-mode’ process."
(interactive)
(setq nix-haskell-package-db-cache
(lax-plist-put nix-haskell-package-db-cache
(nix-haskell-cabal-file) nil))
(nix-haskell-get-pkg-db (apply-partially (lambda (buf &rest args)
(apply 'nix-haskell-interactive buf args)
(with-current-buffer buf
(haskell-process-restart)
(haskell-process-load-file))
;; TODO: restart all haskell buffers!
)
(current-buffer))))
(defun nix-haskell-show-buffer ()
"Show buffer used in nix-haskell."
(interactive)
(cond
(nix-haskell-store-stderr
(display-buffer nix-haskell-store-stderr))
(nix-haskell-instantiate-stderr
(display-buffer nix-haskell-instantiate-stderr))
(t (error "No nix-haskell buffer is active"))))
(defvar nix-haskell-mode-map
(let ((map (make-sparse-keymap)))
map)
"Keymap for nix-haskell minor mode.")
(easy-menu-define nil nix-haskell-mode-map "nix-haskell-mode menu"
'("NixHaskell"
["Clear cache" nix-haskell-clear-cache
:help "Clear the nix-haskell-mode cache."]
["Restart" nix-haskell-restart
:help "Restart the nix-haskell-mode process."]
["Configure..." (lambda () (interactive) (customize-group 'nix-haskell))
:help "Customize nix-haskell-mode settings."]
["Show buffer" nix-haskell-show-buffer
:help "Show the buffer used to download the Nix dependencies."]))
(define-minor-mode nix-haskell-mode
"Minor mode for nix-haskell-mode."
:lighter (:eval (nix-haskell-status))
:group 'nix-haskell
:keymap nix-haskell-mode-map
(if nix-haskell-mode
(progn
(if (nix-haskell-cabal-file)
(progn
;; Disable flycheck and interactive-haskell-mode.
;; They will be reenabled later.
(when (and nix-haskell-flycheck (fboundp 'flycheck-mode))
(flycheck-mode -1))
(when (and nix-haskell-interactive (fboundp 'interactive-haskell-mode))
(interactive-haskell-mode -1))
;; Need to keep the buffer for after the process has run.
(nix-haskell-get-pkg-db (apply-partially 'nix-haskell-interactive
(current-buffer))))
(setq nix-haskell-status "")))
(progn
;; Undo changes made
)))
(defun nix-haskell-mode-message-line (str)
"Echo STR in mini-buffer.
Given string is shrinken to single line, multiple lines just
disturbs the programmer."
(unless (active-minibuffer-window)
(message "%s" (haskell-mode-one-line str (frame-width)))))
(provide 'nix-haskell-mode)
;;; nix-haskell-mode.el ends here