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
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