Skip to content

Commit 527a48d

Browse files
Merge pull request #1619 from fommil/haskell-compile-improve
haskell-compile supports stack too
2 parents 5632eef + 42c5c04 commit 527a48d

File tree

1 file changed

+92
-36
lines changed

1 file changed

+92
-36
lines changed

haskell-compile.el

Lines changed: 92 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
(require 'compile)
3030
(require 'haskell-cabal)
3131
(require 'ansi-color)
32+
(eval-when-compile (require 'subr-x))
3233

3334
;;;###autoload
3435
(defgroup haskell-compile nil
@@ -37,16 +38,30 @@
3738
:group 'haskell)
3839

3940
(defcustom haskell-compile-cabal-build-command
40-
"cd %s && cabal build --ghc-option=-ferror-spans"
41+
"cabal build --ghc-option=-ferror-spans"
4142
"Default build command to use for `haskell-cabal-build' when a cabal file is detected.
42-
The `%s' placeholder is replaced by the cabal package top folder."
43+
For legacy compat, `%s' is replaced by the cabal package top folder."
4344
:group 'haskell-compile
4445
:type 'string)
4546

4647
(defcustom haskell-compile-cabal-build-alt-command
47-
"cd %s && cabal clean -s && cabal build --ghc-option=-ferror-spans"
48+
"cabal clean -s && cabal build --ghc-option=-ferror-spans"
4849
"Alternative build command to use when `haskell-cabal-build' is called with a negative prefix argument.
49-
The `%s' placeholder is replaced by the cabal package top folder."
50+
For legacy compat, `%s' is replaced by the cabal package top folder."
51+
:group 'haskell-compile
52+
:type 'string)
53+
54+
(defcustom haskell-compile-stack-build-command
55+
"stack build --fast"
56+
"Default build command to use for `haskell-stack-build' when a stack file is detected.
57+
For legacy compat, `%s' is replaced by the stack package top folder."
58+
:group 'haskell-compile
59+
:type 'string)
60+
61+
(defcustom haskell-compile-stack-build-alt-command
62+
"stack clean && stack build --fast"
63+
"Alternative build command to use when `haskell-stack-build' is called with a negative prefix argument.
64+
For legacy compat, `%s' is replaced by the stack package top folder."
5065
:group 'haskell-compile
5166
:type 'string)
5267

@@ -63,6 +78,13 @@ The `%s' placeholder is replaced by the current buffer's filename."
6378
:group 'haskell-compile
6479
:type 'boolean)
6580

81+
(defcustom haskell-compile-ignore-cabal nil
82+
"Ignore cabal build definitions files for this buffer when detecting the build tool."
83+
:group 'haskell-compile
84+
:type 'boolean)
85+
(make-variable-buffer-local 'haskell-compile-ignore-cabal)
86+
(put 'haskell-compile-ignore-cabal 'safe-local-variable #'booleanp)
87+
6688
(defconst haskell-compilation-error-regexp-alist
6789
`((,(concat
6890
"^ *\\(?1:[^\t\r\n]+?\\):"
@@ -121,42 +143,76 @@ messages pointing to additional source locations."
121143

122144
;;;###autoload
123145
(defun haskell-compile (&optional edit-command)
124-
"Compile the Haskell program including the current buffer.
125-
Tries to locate the next cabal description in current or parent
126-
folders via `haskell-cabal-find-dir' and if found, invoke
127-
`haskell-compile-cabal-build-command' from the cabal package root
128-
folder. If no cabal package could be detected,
129-
`haskell-compile-command' is used instead.
146+
"Run a compile command for the current Haskell buffer.
130147
131-
If prefix argument EDIT-COMMAND is non-nil (and not a negative
132-
prefix `-'), `haskell-compile' prompts for custom compile
133-
command.
134-
135-
If EDIT-COMMAND contains the negative prefix argument `-',
136-
`haskell-compile' calls the alternative command defined in
137-
`haskell-compile-cabal-build-alt-command' if a cabal package was
138-
detected.
148+
Locates stack or cabal definitions and, if found, invokes the
149+
default build command for that build tool. Cabal is preferred
150+
but may be ignored with `haskell-compile-ignore-cabal'.
139151
140-
`haskell-compile' uses `haskell-compilation-mode' which is
141-
derived from `compilation-mode'. See Info
142-
node `(haskell-mode)compilation' for more details."
152+
If prefix argument EDIT-COMMAND is non-nil (and not a negative
153+
prefix `-'), prompt for a custom compile command.
154+
155+
If EDIT-COMMAND contains the negative prefix argument `-', call
156+
the alternative command defined in
157+
`haskell-compile-stack-build-alt-command' /
158+
`haskell-compile-cabal-build-alt-command'.
159+
160+
If there is no prefix argument, the most recent custom compile
161+
command is used, falling back to
162+
`haskell-compile-stack-build-command' for stack builds
163+
`haskell-compile-cabal-build-command' for cabal builds, and
164+
`haskell-compile-command' otherwise.
165+
166+
'% characters in the `-command' templates are replaced by the
167+
base directory for build tools, or the current buffer for
168+
`haskell-compile-command'."
143169
(interactive "P")
144170
(save-some-buffers (not compilation-ask-about-save)
145-
compilation-save-buffers-predicate)
146-
(let* ((cabdir (haskell-cabal-find-dir))
147-
(command1 (if (eq edit-command '-)
148-
haskell-compile-cabal-build-alt-command
149-
haskell-compile-cabal-build-command))
150-
(srcname (buffer-file-name))
151-
(command (if cabdir
152-
(format command1 cabdir)
153-
(if (and srcname (derived-mode-p 'haskell-mode))
154-
(format haskell-compile-command srcname)
155-
command1))))
156-
(when (and edit-command (not (eq edit-command '-)))
157-
(setq command (compilation-read-command command)))
158-
159-
(compilation-start command 'haskell-compilation-mode)))
171+
compilation-save-buffers-predicate)
172+
(if-let ((cabaldir (and
173+
(not haskell-compile-ignore-cabal)
174+
(or (haskell-cabal-find-dir)
175+
(locate-dominating-file default-directory "cabal.project")
176+
(locate-dominating-file default-directory "cabal.project.local")))))
177+
(haskell--compile cabaldir edit-command
178+
'haskell--compile-cabal-last
179+
haskell-compile-cabal-build-command
180+
haskell-compile-cabal-build-alt-command)
181+
(if-let ((stackdir (and haskell-compile-ignore-cabal
182+
(locate-dominating-file default-directory "stack.yaml"))))
183+
(haskell--compile stackdir edit-command
184+
'haskell--compile-stack-last
185+
haskell-compile-stack-build-command
186+
haskell-compile-stack-build-alt-command)
187+
(let ((srcfile (buffer-file-name)))
188+
(haskell--compile srcfile edit-command
189+
'haskell--compile-ghc-last
190+
haskell-compile-command
191+
haskell-compile-command)))))
192+
193+
(defvar haskell--compile-stack-last nil)
194+
(defvar haskell--compile-cabal-last nil)
195+
(defvar haskell--compile-ghc-last nil)
196+
(defun haskell--compile (dir-or-file edit last-sym fallback alt)
197+
(let* ((default (or (symbol-value last-sym) fallback))
198+
(template (pcase edit
199+
('nil default)
200+
('- alt)
201+
(_ (compilation-read-command default))))
202+
(command (format template dir-or-file))
203+
(dir (if (directory-name-p dir-or-file)
204+
dir-or-file
205+
default-directory))
206+
(name (if (directory-name-p dir-or-file)
207+
(file-name-base (directory-file-name dir-or-file))
208+
(file-name-nondirectory dir-or-file))))
209+
(unless (eq edit'-)
210+
(set last-sym template))
211+
(let ((default-directory dir))
212+
(compilation-start
213+
command
214+
'haskell-compilation-mode
215+
(lambda (mode) (format "*%s* <%s>" mode name))))))
160216

161217
(provide 'haskell-compile)
162218
;;; haskell-compile.el ends here

0 commit comments

Comments
 (0)