Klimi's new dotfiles with stow.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

225 regels
9.0 KiB

4 jaren geleden
  1. ;;; haskell-compile.el --- Haskell/GHC compilation sub-mode -*- lexical-binding: t -*-
  2. ;; Copyright (C) 2013 Herbert Valerio Riedel
  3. ;; Author: Herbert Valerio Riedel <hvr@gnu.org>
  4. ;; This file is not part of GNU Emacs.
  5. ;; This file is free software; you can redistribute it and/or modify
  6. ;; it under the terms of the GNU General Public License as published by
  7. ;; the Free Software Foundation; either version 3 of the License, or
  8. ;; (at your option) any later version.
  9. ;; This file is distributed in the hope that it will be useful,
  10. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. ;; GNU General Public License for more details.
  13. ;; You should have received a copy of the GNU General Public License
  14. ;; along with this program. If not, see <http://www.gnu.org/licenses/>.
  15. ;;; Commentary:
  16. ;; Simple GHC-centric compilation sub-mode; see info node
  17. ;; `(haskell-mode)compilation' for more information
  18. ;;; Code:
  19. (require 'compile)
  20. (require 'haskell-cabal)
  21. (require 'ansi-color)
  22. (eval-when-compile (require 'subr-x))
  23. ;;;###autoload
  24. (defgroup haskell-compile nil
  25. "Settings for Haskell compilation mode"
  26. :link '(custom-manual "(haskell-mode)compilation")
  27. :group 'haskell)
  28. (defcustom haskell-compile-cabal-build-command
  29. "cabal build --ghc-option=-ferror-spans"
  30. "Default build command to use for `haskell-cabal-build' when a cabal file is detected.
  31. For legacy compat, `%s' is replaced by the cabal package top folder."
  32. :group 'haskell-compile
  33. :type 'string)
  34. (defcustom haskell-compile-cabal-build-alt-command
  35. "cabal clean -s && cabal build --ghc-option=-ferror-spans"
  36. "Alternative build command to use when `haskell-cabal-build' is called with a negative prefix argument.
  37. For legacy compat, `%s' is replaced by the cabal package top folder."
  38. :group 'haskell-compile
  39. :type 'string)
  40. (defcustom haskell-compile-stack-build-command
  41. "stack build --fast"
  42. "Default build command to use for `haskell-stack-build' when a stack file is detected.
  43. For legacy compat, `%s' is replaced by the stack package top folder."
  44. :group 'haskell-compile
  45. :type 'string)
  46. (defcustom haskell-compile-stack-build-alt-command
  47. "stack clean && stack build --fast"
  48. "Alternative build command to use when `haskell-stack-build' is called with a negative prefix argument.
  49. For legacy compat, `%s' is replaced by the stack package top folder."
  50. :group 'haskell-compile
  51. :type 'string)
  52. (defcustom haskell-compile-command
  53. "ghc -Wall -ferror-spans -fforce-recomp -c %s"
  54. "Default build command to use for `haskell-cabal-build' when no cabal file is detected.
  55. The `%s' placeholder is replaced by the current buffer's filename."
  56. :group 'haskell-compile
  57. :type 'string)
  58. (defcustom haskell-compile-ghc-filter-linker-messages
  59. t
  60. "Filter out unremarkable \"Loading package...\" linker messages during compilation."
  61. :group 'haskell-compile
  62. :type 'boolean)
  63. (defcustom haskell-compile-ignore-cabal nil
  64. "Ignore cabal build definitions files for this buffer when detecting the build tool."
  65. :group 'haskell-compile
  66. :type 'boolean)
  67. (make-variable-buffer-local 'haskell-compile-ignore-cabal)
  68. (put 'haskell-compile-ignore-cabal 'safe-local-variable #'booleanp)
  69. (defconst haskell-compilation-error-regexp-alist
  70. `((,(concat
  71. "^ *\\(?1:[^\t\r\n]+?\\):"
  72. "\\(?:"
  73. "\\(?2:[0-9]+\\):\\(?4:[0-9]+\\)\\(?:-\\(?5:[0-9]+\\)\\)?" ;; "121:1" & "12:3-5"
  74. "\\|"
  75. "(\\(?2:[0-9]+\\),\\(?4:[0-9]+\\))-(\\(?3:[0-9]+\\),\\(?5:[0-9]+\\))" ;; "(289,5)-(291,36)"
  76. "\\)"
  77. ":\\(?6:\n?[ \t]+[Ww]arning:\\)?")
  78. 1 (2 . 3) (4 . 5) (6 . nil)) ;; error/warning locus
  79. ;; multiple declarations
  80. ("^ \\(?:Declared at:\\| \\) \\(?1:[^ \t\r\n]+\\):\\(?2:[0-9]+\\):\\(?4:[0-9]+\\)$"
  81. 1 2 4 0) ;; info locus
  82. ;; failed tasty tests
  83. (".*error, called at \\(.*\\.hs\\):\\([0-9]+\\):\\([0-9]+\\) in .*" 1 2 3 2 1)
  84. (" +\\(.*\\.hs\\):\\([0-9]+\\):$" 1 2 nil 2 1)
  85. ;; this is the weakest pattern as it's subject to line wrapping et al.
  86. (" at \\(?1:[^ \t\r\n]+\\):\\(?2:[0-9]+\\):\\(?4:[0-9]+\\)\\(?:-\\(?5:[0-9]+\\)\\)?[)]?$"
  87. 1 2 (4 . 5) 0)) ;; info locus
  88. "Regexps used for matching GHC compile messages.
  89. See `compilation-error-regexp-alist' for semantics.")
  90. (defvar haskell-compilation-mode-map
  91. (let ((map (make-sparse-keymap)))
  92. (set-keymap-parent map compilation-mode-map))
  93. "Keymap for `haskell-compilation-mode' buffers.
  94. This is a child of `compilation-mode-map'.")
  95. (defun haskell-compilation-filter-hook ()
  96. "Local `compilation-filter-hook' for `haskell-compilation-mode'."
  97. (when haskell-compile-ghc-filter-linker-messages
  98. (delete-matching-lines "^ *Loading package [^ \t\r\n]+ [.]+ linking [.]+ done\\.$"
  99. (save-excursion (goto-char compilation-filter-start)
  100. (line-beginning-position))
  101. (point)))
  102. (let ((inhibit-read-only t))
  103. (ansi-color-apply-on-region compilation-filter-start (point-max))))
  104. (define-compilation-mode haskell-compilation-mode "HsCompilation"
  105. "Haskell/GHC specific `compilation-mode' derivative.
  106. This mode provides support for GHC 7.[46]'s compile
  107. messages. Specifically, also the `-ferror-spans` source location
  108. format is supported, as well as info-locations within compile
  109. messages pointing to additional source locations."
  110. (setq-local compilation-error-regexp-alist
  111. haskell-compilation-error-regexp-alist)
  112. (add-hook 'compilation-filter-hook
  113. 'haskell-compilation-filter-hook nil t)
  114. )
  115. ;;;###autoload
  116. (defun haskell-compile (&optional edit-command)
  117. "Run a compile command for the current Haskell buffer.
  118. Locates stack or cabal definitions and, if found, invokes the
  119. default build command for that build tool. Cabal is preferred
  120. but may be ignored with `haskell-compile-ignore-cabal'.
  121. If prefix argument EDIT-COMMAND is non-nil (and not a negative
  122. prefix `-'), prompt for a custom compile command.
  123. If EDIT-COMMAND contains the negative prefix argument `-', call
  124. the alternative command defined in
  125. `haskell-compile-stack-build-alt-command' /
  126. `haskell-compile-cabal-build-alt-command'.
  127. If there is no prefix argument, the most recent custom compile
  128. command is used, falling back to
  129. `haskell-compile-stack-build-command' for stack builds
  130. `haskell-compile-cabal-build-command' for cabal builds, and
  131. `haskell-compile-command' otherwise.
  132. '% characters in the `-command' templates are replaced by the
  133. base directory for build tools, or the current buffer for
  134. `haskell-compile-command'."
  135. (interactive "P")
  136. (save-some-buffers (not compilation-ask-about-save)
  137. compilation-save-buffers-predicate)
  138. (let ((cabaldir (and
  139. (not haskell-compile-ignore-cabal)
  140. (or (haskell-cabal-find-dir)
  141. (locate-dominating-file default-directory "cabal.project")
  142. (locate-dominating-file default-directory "cabal.project.local")))))
  143. (if cabaldir
  144. (haskell--compile cabaldir edit-command
  145. 'haskell--compile-cabal-last
  146. haskell-compile-cabal-build-command
  147. haskell-compile-cabal-build-alt-command)
  148. (let ((stackdir (and haskell-compile-ignore-cabal
  149. (locate-dominating-file default-directory "stack.yaml"))))
  150. (if stackdir
  151. (haskell--compile stackdir edit-command
  152. 'haskell--compile-stack-last
  153. haskell-compile-stack-build-command
  154. haskell-compile-stack-build-alt-command)
  155. (let ((srcfile (buffer-file-name)))
  156. (haskell--compile srcfile edit-command
  157. 'haskell--compile-ghc-last
  158. haskell-compile-command
  159. haskell-compile-command)))))))
  160. (defvar haskell--compile-stack-last nil)
  161. (defvar haskell--compile-cabal-last nil)
  162. (defvar haskell--compile-ghc-last nil)
  163. (defun haskell--directory-name-p (name)
  164. "Version of `directory-name-p', which is unavailable in Emacs 24.4."
  165. (string= (file-name-as-directory name) name))
  166. (defun haskell--compile (dir-or-file edit last-sym fallback alt)
  167. (let* ((default (or (symbol-value last-sym) fallback))
  168. (template (cond
  169. ((null edit) default)
  170. ((< edit 0) alt)
  171. (t (compilation-read-command default))))
  172. (command (format template dir-or-file))
  173. (dir (if (haskell--directory-name-p dir-or-file)
  174. dir-or-file
  175. default-directory))
  176. (name (if (haskell--directory-name-p dir-or-file)
  177. (file-name-base (directory-file-name dir-or-file))
  178. (file-name-nondirectory dir-or-file))))
  179. (unless (eq edit'-)
  180. (set last-sym template))
  181. (let ((default-directory dir))
  182. (compilation-start
  183. command
  184. 'haskell-compilation-mode
  185. (lambda (mode) (format "*%s* <%s>" mode name))))))
  186. (provide 'haskell-compile)
  187. ;;; haskell-compile.el ends here