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.

1189 lines
44 KiB

4 years ago
  1. ;;; haskell-cabal.el --- Support for Cabal packages -*- lexical-binding: t -*-
  2. ;; Copyright © 2007, 2008 Stefan Monnier
  3. ;; 2016 Arthur Fayzrakhmanov
  4. ;; Author: Stefan Monnier <monnier@iro.umontreal.ca>
  5. ;; This file is not part of GNU Emacs.
  6. ;; This file is free software; you can redistribute it and/or modify
  7. ;; it under the terms of the GNU General Public License as published by
  8. ;; the Free Software Foundation; either version 3, or (at your option)
  9. ;; any later version.
  10. ;; This file is distributed in the hope that it will be useful,
  11. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ;; GNU General Public License for more details.
  14. ;; You should have received a copy of the GNU General Public License
  15. ;; along with GNU Emacs; see the file COPYING. If not, write to
  16. ;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
  17. ;; Boston, MA 02110-1301, USA.
  18. ;;; Commentary:
  19. ;; Todo:
  20. ;; - distinguish continued lines from indented lines.
  21. ;; - indent-line-function.
  22. ;; - outline-minor-mode.
  23. ;;; Code:
  24. ;; (defun haskell-cabal-extract-fields-from-doc ()
  25. ;; (require 'xml)
  26. ;; (let ((section (completing-read
  27. ;; "Section: "
  28. ;; '("general-fields" "library" "executable" "buildinfo"))))
  29. ;; (goto-char (point-min))
  30. ;; (search-forward (concat "<sect3 id=\"" section "\">")))
  31. ;; (let* ((xml (xml-parse-region
  32. ;; (progn (search-forward "<variablelist>") (match-beginning 0))
  33. ;; (progn (search-forward "</variablelist>") (point))))
  34. ;; (varlist (cl-remove-if-not 'consp (cl-cddar xml)))
  35. ;; (syms (mapcar (lambda (entry) (cl-caddr (assq 'literal (assq 'term entry))))
  36. ;; varlist))
  37. ;; (fields (mapcar (lambda (sym) (substring-no-properties sym 0 -1)) syms)))
  38. ;; fields))
  39. (require 'cl-lib)
  40. (require 'haskell-utils)
  41. (defcustom haskell-hasktags-path "hasktags"
  42. "Path to `hasktags' executable."
  43. :group 'haskell
  44. :type 'string)
  45. (defcustom haskell-hasktags-arguments '("-e" "-x")
  46. "Additional arguments for `hasktags' executable.
  47. By default these are:
  48. -e - generate ETAGS file
  49. -x - generate additional information in CTAGS file."
  50. :group 'haskell
  51. :type '(list string))
  52. (defconst haskell-cabal-general-fields
  53. ;; Extracted with (haskell-cabal-extract-fields-from-doc "general-fields")
  54. '("name" "version" "cabal-version" "license" "license-file" "copyright"
  55. "author" "maintainer" "stability" "homepage" "package-url" "synopsis"
  56. "description" "category" "tested-with" "build-depends" "data-files"
  57. "extra-source-files" "extra-tmp-files" "import"))
  58. (defconst haskell-cabal-library-fields
  59. ;; Extracted with (haskell-cabal-extract-fields-from-doc "library")
  60. '("exposed-modules"))
  61. (defconst haskell-cabal-executable-fields
  62. ;; Extracted with (haskell-cabal-extract-fields-from-doc "executable")
  63. '("executable" "main-is"))
  64. (defconst haskell-cabal-buildinfo-fields
  65. ;; Extracted with (haskell-cabal-extract-fields-from-doc "buildinfo")
  66. '("buildable" "other-modules" "hs-source-dirs" "extensions" "ghc-options"
  67. "ghc-prof-options" "hugs-options" "nhc-options" "includes"
  68. "install-includes" "include-dirs" "c-sources" "extra-libraries"
  69. "extra-lib-dirs" "cc-options" "ld-options" "frameworks"))
  70. (defvar haskell-cabal-mode-syntax-table
  71. (let ((st (make-syntax-table)))
  72. ;; The comment syntax can't be described simply in syntax-table.
  73. ;; We could use font-lock-syntactic-keywords, but is it worth it?
  74. ;; (modify-syntax-entry ?- ". 12" st)
  75. (modify-syntax-entry ?\n ">" st)
  76. (modify-syntax-entry ?- "w" st)
  77. st))
  78. (defvar haskell-cabal-font-lock-keywords
  79. ;; The comment syntax can't be described simply in syntax-table.
  80. ;; We could use font-lock-syntactic-keywords, but is it worth it?
  81. '(("^[ \t]*--.*" . font-lock-comment-face)
  82. ("^ *\\([^ \t:]+\\):" (1 font-lock-keyword-face))
  83. ("^\\(Library\\)[ \t]*\\({\\|$\\)" (1 font-lock-keyword-face))
  84. ("^\\(Executable\\|Test-Suite\\|Benchmark\\|Common\\)[ \t]+\\([^\n \t]*\\)"
  85. (1 font-lock-keyword-face) (2 font-lock-function-name-face))
  86. ("^\\(Flag\\)[ \t]+\\([^\n \t]*\\)"
  87. (1 font-lock-keyword-face) (2 font-lock-constant-face))
  88. ("^\\(Source-Repository\\)[ \t]+\\(head\\|this\\)"
  89. (1 font-lock-keyword-face) (2 font-lock-constant-face))
  90. ("^ *\\(if\\)[ \t]+.*\\({\\|$\\)" (1 font-lock-keyword-face))
  91. ("^ *\\(}[ \t]*\\)?\\(else\\)[ \t]*\\({\\|$\\)"
  92. (2 font-lock-keyword-face))
  93. ("\\<\\(?:True\\|False\\)\\>"
  94. (0 font-lock-constant-face))))
  95. (defvar haskell-cabal-buffers nil
  96. "List of Cabal buffers.")
  97. (defun haskell-cabal-buffers-clean (&optional buffer)
  98. "Refresh list of known cabal buffers.
  99. Check each buffer in variable `haskell-cabal-buffers' and remove
  100. it from list if one of the following conditions are hold:
  101. + buffer is killed;
  102. + buffer's mode is not derived from `haskell-cabal-mode';
  103. + buffer is a BUFFER (if given)."
  104. (let ((bufs ()))
  105. (dolist (buf haskell-cabal-buffers)
  106. (if (and (buffer-live-p buf)
  107. (not (eq buf buffer))
  108. (with-current-buffer buf (derived-mode-p 'haskell-cabal-mode)))
  109. (push buf bufs)))
  110. (setq haskell-cabal-buffers bufs)))
  111. (defun haskell-cabal-unregister-buffer ()
  112. "Exclude current buffer from global list of known cabal buffers."
  113. (haskell-cabal-buffers-clean (current-buffer)))
  114. ;;;###autoload
  115. (add-to-list 'auto-mode-alist '("\\.cabal\\'" . haskell-cabal-mode))
  116. (defvar haskell-cabal-mode-map
  117. (let ((map (make-sparse-keymap)))
  118. (define-key map (kbd "C-c C-s") 'haskell-cabal-subsection-arrange-lines)
  119. (define-key map (kbd "C-M-n") 'haskell-cabal-next-section)
  120. (define-key map (kbd "C-M-p") 'haskell-cabal-previous-section)
  121. (define-key map (kbd "M-n") 'haskell-cabal-next-subsection)
  122. (define-key map (kbd "M-p") 'haskell-cabal-previous-subsection)
  123. (define-key map (kbd "C-<down>") 'haskell-cabal-next-subsection)
  124. (define-key map (kbd "C-<up>") 'haskell-cabal-previous-subsection)
  125. (define-key map (kbd "C-c C-f") 'haskell-cabal-find-or-create-source-file)
  126. (define-key map (kbd "M-g l") 'haskell-cabal-goto-library-section)
  127. (define-key map (kbd "M-g e") 'haskell-cabal-goto-executable-section)
  128. (define-key map (kbd "M-g b") 'haskell-cabal-goto-benchmark-section)
  129. (define-key map (kbd "M-g o") 'haskell-cabal-goto-common-section)
  130. (define-key map (kbd "M-g t") 'haskell-cabal-goto-test-suite-section)
  131. map))
  132. ;;;###autoload
  133. (define-derived-mode haskell-cabal-mode fundamental-mode "Haskell-Cabal"
  134. "Major mode for Cabal package description files."
  135. (setq-local font-lock-defaults
  136. '(haskell-cabal-font-lock-keywords t t nil nil))
  137. (add-to-list 'haskell-cabal-buffers (current-buffer))
  138. (add-hook 'change-major-mode-hook 'haskell-cabal-unregister-buffer nil 'local)
  139. (add-hook 'kill-buffer-hook 'haskell-cabal-unregister-buffer nil 'local)
  140. (setq-local comment-start "-- ")
  141. (setq-local comment-start-skip "\\(^[ \t]*\\)--[ \t]*")
  142. (setq-local comment-end "")
  143. (setq-local comment-end-skip "[ \t]*\\(\\s>\\|\n\\)")
  144. (setq-local indent-line-function 'haskell-cabal-indent-line)
  145. (setq indent-tabs-mode nil)
  146. )
  147. (make-obsolete 'haskell-cabal-get-setting
  148. 'haskell-cabal--get-field
  149. "March 14, 2016")
  150. (defalias 'haskell-cabal-get-setting 'haskell-cabal--get-field
  151. "Try to read value of field with NAME from current buffer.
  152. Obsolete function. Defined for backward compatibility. Use
  153. `haskell-cabal--get-field' instead.")
  154. (defun haskell-cabal--get-field (name)
  155. "Try to read value of field with NAME from current buffer."
  156. (save-excursion
  157. (let ((case-fold-search t))
  158. (goto-char (point-min))
  159. (when (re-search-forward
  160. (concat "^[ \t]*" (regexp-quote name)
  161. ":[ \t]*\\(.*\\(\n[ \t]+[ \t\n].*\\)*\\)")
  162. nil t)
  163. (let ((val (match-string 1))
  164. (start 1))
  165. (when (match-end 2) ;Multiple lines.
  166. ;; The documentation is not very precise about what to do about
  167. ;; the \n and the indentation: are they part of the value or
  168. ;; the encoding? I take the point of view that \n is part of
  169. ;; the value (so that values can span multiple lines as well),
  170. ;; and that only the first char in the indentation is part of
  171. ;; the encoding, the rest is part of the value (otherwise, lines
  172. ;; in the value cannot start with spaces or tabs).
  173. (while (string-match "^[ \t]\\(?:\\.$\\)?" val start)
  174. (setq start (1+ (match-beginning 0)))
  175. (setq val (replace-match "" t t val))))
  176. val)))))
  177. (make-obsolete 'haskell-cabal-guess-setting
  178. 'haskell-cabal-get-field
  179. "March 14, 2016")
  180. (defalias 'haskell-cabal-guess-setting 'haskell-cabal-get-field
  181. "Read the value of field with NAME from project's cabal file.
  182. Obsolete function. Defined for backward compatibility. Use
  183. `haskell-cabal-get-field' instead.")
  184. ;;;###autoload
  185. (defun haskell-cabal-get-field (name)
  186. "Read the value of field with NAME from project's cabal file.
  187. If there is no valid .cabal file to get the setting from (or
  188. there is no corresponding setting with that name in the .cabal
  189. file), then this function returns nil."
  190. (interactive)
  191. (when (and name buffer-file-name)
  192. (let ((cabal-file (haskell-cabal-find-file)))
  193. (when (and cabal-file (file-readable-p cabal-file))
  194. (with-temp-buffer
  195. (insert-file-contents cabal-file)
  196. (haskell-cabal--get-field name))))))
  197. ;;;###autoload
  198. (defun haskell-cabal-get-dir (&optional use-defaults)
  199. "Get the Cabal dir for a new project. Various ways of figuring this out,
  200. and indeed just prompting the user. Do them all."
  201. (let* ((file (haskell-cabal-find-file))
  202. (dir (if file (file-name-directory file) default-directory)))
  203. (if use-defaults
  204. dir
  205. (haskell-utils-read-directory-name
  206. (format "Cabal dir%s: " (if file (format " (guessed from %s)" (file-relative-name file)) ""))
  207. dir))))
  208. (defun haskell-cabal-compute-checksum (dir)
  209. "Compute MD5 checksum of package description file in DIR.
  210. Return nil if no Cabal description file could be located via
  211. `haskell-cabal-find-pkg-desc'."
  212. (let ((cabal-file (haskell-cabal-find-pkg-desc dir)))
  213. (when cabal-file
  214. (with-temp-buffer
  215. (insert-file-contents cabal-file)
  216. (md5 (buffer-string))))))
  217. (defun haskell-cabal-find-file (&optional dir)
  218. "Search for package description file upwards starting from DIR.
  219. If DIR is nil, `default-directory' is used as starting point for
  220. directory traversal. Upward traversal is aborted if file owner
  221. changes. Uses `haskell-cabal-find-pkg-desc' internally."
  222. (let ((use-dir (or dir default-directory)))
  223. (while (and use-dir (not (file-directory-p use-dir)))
  224. (setq use-dir (file-name-directory (directory-file-name use-dir))))
  225. (when use-dir
  226. (catch 'found
  227. (let ((user (nth 2 (file-attributes use-dir)))
  228. ;; Abbreviate, so as to stop when we cross ~/.
  229. (root (abbreviate-file-name use-dir)))
  230. ;; traverse current dir up to root as long as file owner doesn't change
  231. (while (and root (equal user (nth 2 (file-attributes root))))
  232. (let ((cabal-file (haskell-cabal-find-pkg-desc root)))
  233. (when cabal-file
  234. (throw 'found cabal-file)))
  235. (let ((proot (file-name-directory (directory-file-name root))))
  236. (if (equal proot root) ;; fix-point reached?
  237. (throw 'found nil)
  238. (setq root proot))))
  239. nil)))))
  240. (defun haskell-cabal-find-pkg-desc (dir &optional allow-multiple)
  241. "Find a package description file in the directory DIR.
  242. Returns nil if none or multiple \".cabal\" files were found. If
  243. ALLOW-MULTIPLE is non nil, in case of multiple \".cabal\" files,
  244. a list is returned instead of failing with a nil result."
  245. ;; This is basically a port of Cabal's
  246. ;; Distribution.Simple.Utils.findPackageDesc function
  247. ;; http://hackage.haskell.org/packages/archive/Cabal/1.16.0.3/doc/html/Distribution-Simple-Utils.html
  248. ;; but without the exception throwing.
  249. (let* ((cabal-files
  250. (cl-remove-if 'file-directory-p
  251. (cl-remove-if-not 'file-exists-p
  252. (directory-files dir t ".\\.cabal\\'")))))
  253. (cond
  254. ((= (length cabal-files) 1) (car cabal-files)) ;; exactly one candidate found
  255. (allow-multiple cabal-files) ;; pass-thru multiple candidates
  256. (t nil))))
  257. (defun haskell-cabal-find-dir (&optional dir)
  258. "Like `haskell-cabal-find-file' but returns directory instead.
  259. See `haskell-cabal-find-file' for meaning of DIR argument."
  260. (let ((cabal-file (haskell-cabal-find-file dir)))
  261. (when cabal-file
  262. (file-name-directory cabal-file))))
  263. ;;;###autoload
  264. (defun haskell-cabal-visit-file (other-window)
  265. "Locate and visit package description file for file visited by current buffer.
  266. This uses `haskell-cabal-find-file' to locate the closest
  267. \".cabal\" file and open it. This command assumes a common Cabal
  268. project structure where the \".cabal\" file is in the top-folder
  269. of the project, and all files related to the project are in or
  270. below the top-folder. If called with non-nil prefix argument
  271. OTHER-WINDOW use `find-file-other-window'."
  272. (interactive "P")
  273. ;; Note: We aren't allowed to rely on haskell-session here (which,
  274. ;; in pathological cases, can have a different .cabal file
  275. ;; associated with the current buffer)
  276. (if buffer-file-name
  277. (let ((cabal-file (haskell-cabal-find-file (file-name-directory buffer-file-name))))
  278. (if cabal-file
  279. (if other-window
  280. (find-file-other-window cabal-file)
  281. (find-file cabal-file))
  282. (error "Could not locate \".cabal\" file for %S" buffer-file-name)))
  283. (error "Cannot locate \".cabal\" file for buffers not visiting any file")))
  284. (defvar haskell-cabal-commands
  285. '("install"
  286. "update"
  287. "list"
  288. "info"
  289. "upgrade"
  290. "fetch"
  291. "unpack"
  292. "check"
  293. "sdist"
  294. "upload"
  295. "report"
  296. "init"
  297. "configure"
  298. "build"
  299. "copy"
  300. "haddock"
  301. "clean"
  302. "hscolour"
  303. "register"
  304. "test"
  305. "help"
  306. "run"))
  307. ;;;###autoload
  308. (defgroup haskell-cabal nil
  309. "Haskell cabal files"
  310. :group 'haskell
  311. )
  312. (defconst haskell-cabal-section-header-regexp "^[[:alnum:]]" )
  313. (defconst haskell-cabal-subsection-header-regexp "^[ \t]*[[:alnum:]]\\w*:")
  314. (defconst haskell-cabal-comment-regexp "^[ \t]*--")
  315. (defconst haskell-cabal-empty-regexp "^[ \t]*$")
  316. (defconst haskell-cabal-conditional-regexp "^[ \t]*\\(\\if\\|else\\|}\\)")
  317. (defun haskell-cabal-classify-line ()
  318. "Classify the current line into 'section-header 'subsection-header 'section-data 'comment and 'empty '"
  319. (save-excursion
  320. (beginning-of-line)
  321. (cond
  322. ((looking-at haskell-cabal-subsection-header-regexp ) 'subsection-header)
  323. ((looking-at haskell-cabal-section-header-regexp) 'section-header)
  324. ((looking-at haskell-cabal-comment-regexp) 'comment)
  325. ((looking-at haskell-cabal-empty-regexp ) 'empty)
  326. ((looking-at haskell-cabal-conditional-regexp ) 'conditional)
  327. (t 'section-data))))
  328. (defun haskell-cabal-header-p ()
  329. "Is the current line a section or subsection header?"
  330. (cl-case (haskell-cabal-classify-line)
  331. ((section-header subsection-header) t)))
  332. (defun haskell-cabal-section-header-p ()
  333. "Is the current line a section or subsection header?"
  334. (cl-case (haskell-cabal-classify-line)
  335. ((section-header) t)))
  336. (defun haskell-cabal-section-beginning ()
  337. "Find the beginning of the current section"
  338. (save-excursion
  339. (while (not (or (bobp) (haskell-cabal-section-header-p)))
  340. (forward-line -1))
  341. (point)))
  342. (defun haskell-cabal-beginning-of-section ()
  343. "go to the beginning of the section"
  344. (interactive)
  345. (goto-char (haskell-cabal-section-beginning))
  346. )
  347. (defun haskell-cabal-section-end ()
  348. "Find the end of the current section"
  349. (interactive)
  350. (save-excursion
  351. (if (re-search-forward "\n\\([ \t]*\n\\)*[[:alnum:]]" nil t)
  352. (match-beginning 0)
  353. (point-max))))
  354. (defun haskell-cabal-end-of-section ()
  355. "go to the end of the section"
  356. (interactive)
  357. (goto-char (haskell-cabal-section-end)))
  358. (defun haskell-cabal-next-section ()
  359. "Go to the next section"
  360. (interactive)
  361. (when (haskell-cabal-section-header-p) (forward-line))
  362. (while (not (or (eobp) (haskell-cabal-section-header-p)))
  363. (forward-line)))
  364. (defun haskell-cabal-previous-section ()
  365. "Go to the next section"
  366. (interactive)
  367. (when (haskell-cabal-section-header-p) (forward-line -1))
  368. (while (not (or (bobp) (haskell-cabal-section-header-p)))
  369. (forward-line -1)))
  370. (defun haskell-cabal-subsection-end ()
  371. "find the end of the current subsection"
  372. (save-excursion
  373. (haskell-cabal-beginning-of-subsection)
  374. (forward-line)
  375. (while (and (not (eobp))
  376. (member (haskell-cabal-classify-line) '(empty section-data)))
  377. (forward-line))
  378. (unless (eobp) (forward-line -1))
  379. (while (and (equal (haskell-cabal-classify-line) 'empty)
  380. (not (bobp)))
  381. (forward-line -1))
  382. (end-of-line)
  383. (point)))
  384. (defun haskell-cabal-end-of-subsection ()
  385. "go to the end of the current subsection"
  386. (interactive)
  387. (goto-char (haskell-cabal-subsection-end)))
  388. (defun haskell-cabal-section ()
  389. "Get the name and data of the associated section"
  390. (save-excursion
  391. (haskell-cabal-beginning-of-section)
  392. (when (and (haskell-cabal-section-header-p)
  393. (looking-at "^\\(\\w+\\)[ \t]*\\(.*\\)$"))
  394. (list :name (match-string-no-properties 1)
  395. :value (match-string-no-properties 2)
  396. :beginning (match-beginning 0)
  397. :end (haskell-cabal-section-end)))))
  398. (defun haskell-cabal-subsection ()
  399. "Get the name and bounds of of the current subsection"
  400. (save-excursion
  401. (haskell-cabal-beginning-of-subsection)
  402. (when (looking-at "\\([ \t]*\\(\\w*\\):\\)[ \t]*")
  403. (list :name (match-string-no-properties 2)
  404. :beginning (match-end 0)
  405. :end (save-match-data (haskell-cabal-subsection-end))
  406. :data-start-column (save-excursion (goto-char (match-end 0))
  407. (current-column))
  408. :data-indent-column (save-excursion (goto-char (match-end 0))
  409. (when (looking-at "\n +\\(\\w*\\)") (goto-char (match-beginning 1)))
  410. (current-column)
  411. )))))
  412. (defun haskell-cabal-section-name (section)
  413. (plist-get section :name))
  414. (defun haskell-cabal-section-value (section)
  415. (plist-get section :value))
  416. (defun haskell-cabal-section-start (section)
  417. (plist-get section :beginning))
  418. (defun haskell-cabal-section-data-start-column (section)
  419. (plist-get section :data-start-column))
  420. (defun haskell-cabal-section-data-indent-column (section)
  421. (plist-get section :data-indent-column))
  422. (defun haskell-cabal-map-component-type (component-type)
  423. "Map from cabal file COMPONENT-TYPE to build command component-type."
  424. (let ((component-type (downcase component-type)))
  425. (cond ((equal component-type "executable") "exe")
  426. ((equal component-type "test-suite") "test")
  427. ((equal component-type "benchmark") "bench"))))
  428. (defun haskell-cabal-enum-targets (&optional process-type)
  429. "Enumerate .cabal targets. PROCESS-TYPE determines the format of the returned target."
  430. (let ((cabal-file (haskell-cabal-find-file))
  431. (process-type (if process-type process-type 'ghci)))
  432. (when (and cabal-file (file-readable-p cabal-file))
  433. (with-temp-buffer
  434. (insert-file-contents cabal-file)
  435. (haskell-cabal-mode)
  436. (goto-char (point-min))
  437. (let ((matches)
  438. (package-name (haskell-cabal--get-field "name")))
  439. (haskell-cabal-next-section)
  440. (while (not (eobp))
  441. (if (haskell-cabal-source-section-p (haskell-cabal-section))
  442. (let* ((section (haskell-cabal-section))
  443. (component-type (haskell-cabal-section-name section))
  444. (val (car (split-string
  445. (haskell-cabal-section-value section)))))
  446. (if (equal (downcase component-type) "library")
  447. (let ((lib-target (if (eq 'stack-ghci process-type)
  448. (concat package-name ":lib")
  449. (concat "lib:" package-name))))
  450. (push lib-target matches))
  451. (push (concat (when (eq 'stack-ghci process-type)
  452. (concat package-name ":"))
  453. (haskell-cabal-map-component-type component-type)
  454. ":"
  455. val)
  456. matches))))
  457. (haskell-cabal-next-section))
  458. (reverse matches))))))
  459. (defmacro haskell-cabal-with-subsection (subsection replace &rest funs)
  460. "Copy subsection data into a temporary buffer, save indentation
  461. and execute FORMS
  462. If REPLACE is non-nil the subsection data is replaced with the
  463. resulting buffer-content"
  464. (let ((section (make-symbol "section"))
  465. (beg (make-symbol "beg"))
  466. (end (make-symbol "end"))
  467. (start-col (make-symbol "start-col"))
  468. (section-data (make-symbol "section-data")))
  469. `(let* ((,section ,subsection)
  470. (,beg (plist-get ,section :beginning))
  471. (,end (plist-get ,section :end))
  472. (,start-col (plist-get ,section :data-start-column))
  473. (,section-data (buffer-substring ,beg ,end)))
  474. (save-excursion
  475. (prog1
  476. (with-temp-buffer
  477. (setq indent-tabs-mode nil)
  478. (indent-to ,start-col)
  479. (insert ,section-data)
  480. (goto-char (point-min))
  481. (prog1
  482. (progn (haskell-cabal-save-indentation ,@funs))
  483. (goto-char (point-min))
  484. (when (looking-at (format "[ ]\\{0,%d\\}" (1+ ,start-col)))
  485. (replace-match ""))
  486. (setq ,section-data (buffer-substring (point-min) (point-max)))))
  487. ,@(when replace
  488. `((delete-region ,beg ,end)
  489. (goto-char ,beg)
  490. (insert ,section-data))))))))
  491. (defmacro haskell-cabal-each-line (&rest fun)
  492. "Execute FORMS on each line"
  493. `(save-excursion
  494. (while (< (point) (point-max))
  495. ,@fun
  496. (forward-line))))
  497. (defun haskell-cabal-chomp-line ()
  498. "Remove leading and trailing whitespaces from current line"
  499. (beginning-of-line)
  500. (when (looking-at "^[ \t]*\\([^ \t]\\|\\(?:[^ \t].*[^ \t]\\)\\)[ \t]*$")
  501. (replace-match (match-string 1) nil t)
  502. t))
  503. (defun haskell-cabal-min-indentation (&optional beg end)
  504. "Compute largest common whitespace prefix of each line in between BEG and END"
  505. (save-excursion
  506. (goto-char (or beg (point-min)))
  507. (let ((min-indent nil))
  508. (while (< (point) (or end (point-max)))
  509. (let ((indent (current-indentation)))
  510. (if (and (not (haskell-cabal-ignore-line-p))
  511. (or (not min-indent)
  512. (< indent min-indent)))
  513. (setq min-indent indent)))
  514. (forward-line))
  515. min-indent)))
  516. (defun haskell-cabal-ignore-line-p ()
  517. "Does line only contain whitespaces and comments?"
  518. (save-excursion
  519. (beginning-of-line)
  520. (looking-at "^[ \t]*\\(?:--.*\\)?$")))
  521. (defun haskell-cabal-kill-indentation ()
  522. "Remove longest common whitespace prefix from each line"
  523. (goto-char (point-min))
  524. (let ((indent (haskell-cabal-min-indentation)))
  525. (haskell-cabal-each-line (unless (haskell-cabal-ignore-line-p)
  526. (delete-char indent)) )
  527. indent))
  528. (defun haskell-cabal-add-indentation (indent)
  529. (goto-char (point-min))
  530. (haskell-cabal-each-line
  531. (unless (haskell-cabal-ignore-line-p)
  532. (indent-to indent))))
  533. (defmacro haskell-cabal-save-indentation (&rest funs)
  534. "Strip indentation from each line, execute FORMS and reinstate indentation
  535. so that the indentation of the FIRST LINE matches"
  536. (let ((old-l1-indent (make-symbol "new-l1-indent"))
  537. (new-l1-indent (make-symbol "old-l1-indent")))
  538. `(let ( (,old-l1-indent (save-excursion
  539. (goto-char (point-min))
  540. (current-indentation))))
  541. (unwind-protect
  542. (progn
  543. (haskell-cabal-kill-indentation)
  544. ,@funs)
  545. (progn
  546. (goto-char (point-min))
  547. (let ((,new-l1-indent (current-indentation)))
  548. (haskell-cabal-add-indentation (- ,old-l1-indent
  549. ,new-l1-indent))))))))
  550. (defun haskell-cabal-comma-separatorp (pos)
  551. "Return non-nil when the char at POS is a comma separator.
  552. Characters that are not a comma, or commas inside a commment or
  553. string, are not comma separators."
  554. (when (eq (char-after pos) ?,)
  555. (let ((ss (syntax-ppss pos)))
  556. (not
  557. (or
  558. ;; inside a string
  559. (nth 3 ss)
  560. ;; inside a comment
  561. (nth 4 ss))))))
  562. (defun haskell-cabal-strip-list-and-detect-style ()
  563. "Strip commas from a comma-separated list.
  564. Detect and return the comma style. The possible options are:
  565. before: a comma at the start of each line (except the first), e.g.
  566. Foo
  567. , Bar
  568. after: a comma at the end of each line (except the last), e.g.
  569. Foo,
  570. Bar
  571. single: everything on a single line, but comma-separated, e.g.
  572. Foo, Bar
  573. nil: no commas, e.g.
  574. Foo Bar
  575. If the styles are mixed, the position of the first comma
  576. determines the style. If there is only one element then `after'
  577. style is assumed."
  578. (let (comma-style)
  579. ;; split list items on single line
  580. (goto-char (point-min))
  581. (while (re-search-forward
  582. "\\([^ \t,\n]\\)[ \t]*\\(,\\)[ \t]*\\([^ \t,\n]\\)" nil t)
  583. (when (haskell-cabal-comma-separatorp (match-beginning 2))
  584. (setq comma-style 'single)
  585. (replace-match "\\1\n\\3" nil nil)))
  586. ;; remove commas before
  587. (goto-char (point-min))
  588. (while (re-search-forward "^\\([ \t]*\\),\\([ \t]*\\)" nil t)
  589. (setq comma-style 'before)
  590. (replace-match "" nil nil))
  591. ;; remove trailing commas
  592. (goto-char (point-min))
  593. (while (re-search-forward ",[ \t]*$" nil t)
  594. (unless (eq comma-style 'before)
  595. (setq comma-style 'after))
  596. (replace-match "" nil nil))
  597. ;; if there is just one line then set default as 'after
  598. (unless comma-style
  599. (goto-char (point-min))
  600. (forward-line)
  601. (when (eobp)
  602. (setq comma-style 'after)))
  603. (goto-char (point-min))
  604. (haskell-cabal-each-line (haskell-cabal-chomp-line))
  605. comma-style))
  606. (defun haskell-cabal-listify (comma-style)
  607. "Add commas so that the buffer contains a comma-separated list.
  608. Respect the COMMA-STYLE, see
  609. `haskell-cabal-strip-list-and-detect-style' for the possible
  610. styles."
  611. (cl-case comma-style
  612. ('before
  613. (goto-char (point-min))
  614. (while (haskell-cabal-ignore-line-p) (forward-line))
  615. (indent-to 2)
  616. (forward-line)
  617. (haskell-cabal-each-line
  618. (unless (haskell-cabal-ignore-line-p)
  619. (insert ", "))))
  620. ('after
  621. (goto-char (point-max))
  622. (while (equal 0 (forward-line -1))
  623. (unless (haskell-cabal-ignore-line-p)
  624. (end-of-line)
  625. (insert ",")
  626. (beginning-of-line))))
  627. ('single
  628. (goto-char (point-min))
  629. (while (not (eobp))
  630. (end-of-line)
  631. (unless (eobp)
  632. (insert ", ")
  633. (delete-char 1)
  634. (just-one-space))))))
  635. (defmacro haskell-cabal-with-cs-list (&rest funs)
  636. "Format the buffer so that each line contains a list element.
  637. Respect the comma style."
  638. (let ((comma-style (make-symbol "comma-style")))
  639. `(let ((,comma-style
  640. (save-excursion
  641. (haskell-cabal-strip-list-and-detect-style))))
  642. (unwind-protect (progn ,@funs)
  643. (haskell-cabal-listify ,comma-style)))))
  644. (defun haskell-cabal-sort-lines-key-fun ()
  645. (when (looking-at "[ \t]*--[ \t,]*")
  646. (goto-char (match-end 0)))
  647. nil)
  648. (defmacro haskell-cabal-save-position (&rest forms)
  649. "Save position as mark, execute FORMs and go back to mark"
  650. `(prog2
  651. (haskell-cabal-mark)
  652. (progn ,@forms)
  653. (haskell-cabal-goto-mark)
  654. (haskell-cabal-remove-mark)))
  655. (defun haskell-cabal-sort-lines-depends-compare (key1 key2)
  656. (let* ((key1str (buffer-substring (car key1) (cdr key1)))
  657. (key2str (buffer-substring (car key2) (cdr key2)))
  658. (base-regex "^[ \t]*base\\($\\|[^[:alnum:]-]\\)"))
  659. (cond
  660. ((string-match base-regex key1str) t)
  661. ((string-match base-regex key2str) nil)
  662. (t (string< key1str key2str)))))
  663. (defun haskell-cabal-subsection-arrange-lines ()
  664. "Sort lines of current subsection"
  665. (interactive)
  666. (haskell-cabal-save-position
  667. (let* ((subsection (haskell-cabal-section-name (haskell-cabal-subsection)))
  668. (compare-lines (if (string= (downcase subsection) "build-depends")
  669. 'haskell-cabal-sort-lines-depends-compare
  670. nil)))
  671. (haskell-cabal-with-subsection
  672. (haskell-cabal-subsection) t
  673. (haskell-cabal-with-cs-list
  674. (sort-subr nil 'forward-line 'end-of-line
  675. 'haskell-cabal-sort-lines-key-fun
  676. 'end-of-line
  677. compare-lines
  678. ))))))
  679. (defun haskell-cabal-subsection-beginning ()
  680. "find the beginning of the current subsection"
  681. (save-excursion
  682. (while (and (not (bobp))
  683. (not (haskell-cabal-header-p)))
  684. (forward-line -1))
  685. (back-to-indentation)
  686. (point)))
  687. (defun haskell-cabal-beginning-of-subsection ()
  688. "go to the beginning of the current subsection"
  689. (interactive)
  690. (goto-char (haskell-cabal-subsection-beginning)))
  691. (defun haskell-cabal-next-subsection ()
  692. "go to the next subsection"
  693. (interactive)
  694. (if (haskell-cabal-header-p) (forward-line))
  695. (while (and (not (eobp))
  696. (not (haskell-cabal-header-p)))
  697. (forward-line))
  698. (haskell-cabal-forward-to-line-entry))
  699. (defun haskell-cabal-previous-subsection ()
  700. "go to the previous subsection"
  701. (interactive)
  702. (if (haskell-cabal-header-p) (forward-line -1))
  703. (while (and (not (bobp))
  704. (not (haskell-cabal-header-p)))
  705. (forward-line -1))
  706. (haskell-cabal-forward-to-line-entry)
  707. )
  708. (defun haskell-cabal-find-subsection-by (section pred)
  709. "Find subsection with name NAME"
  710. (save-excursion
  711. (when section (goto-char (haskell-cabal-section-start section)))
  712. (let* ((end (if section (haskell-cabal-section-end) (point-max)))
  713. (found nil))
  714. (while (and (< (point) end)
  715. (not found))
  716. (let ((subsection (haskell-cabal-subsection)))
  717. (when (and subsection (funcall pred subsection))
  718. (setq found subsection)))
  719. (haskell-cabal-next-subsection))
  720. found)))
  721. (defun haskell-cabal-find-subsection (section name)
  722. "Find subsection with name NAME"
  723. (let ((downcase-name (downcase name)))
  724. (haskell-cabal-find-subsection-by
  725. section
  726. `(lambda (subsection)
  727. (string= (downcase (haskell-cabal-section-name subsection))
  728. ,downcase-name)))))
  729. (defun haskell-cabal-goto-subsection (name)
  730. (let ((subsection (haskell-cabal-find-subsection (haskell-cabal-section) name)))
  731. (when subsection
  732. (goto-char (haskell-cabal-section-start subsection)))))
  733. (defun haskell-cabal-goto-exposed-modules ()
  734. (interactive)
  735. (haskell-cabal-goto-subsection "exposed-modules"))
  736. (defun haskell-cabal-subsection-entry-list (section name)
  737. "Get the data of a subsection as a list"
  738. (let ((subsection (haskell-cabal-find-subsection section name)))
  739. (when subsection
  740. (haskell-cabal-with-subsection
  741. subsection nil
  742. (haskell-cabal-with-cs-list
  743. (delete-matching-lines
  744. (format "\\(?:%s\\)\\|\\(?:%s\\)"
  745. haskell-cabal-comment-regexp
  746. haskell-cabal-empty-regexp)
  747. (point-min) (point-max))
  748. (split-string (buffer-substring-no-properties (point-min) (point-max))
  749. "\n" t))))))
  750. (defun haskell-cabal-remove-mark ()
  751. (remove-list-of-text-properties (point-min) (point-max)
  752. '(haskell-cabal-marker)))
  753. (defun haskell-cabal-mark ()
  754. "Mark the current position with the text property haskell-cabal-marker"
  755. (haskell-cabal-remove-mark)
  756. (put-text-property (line-beginning-position) (line-end-position)
  757. 'haskell-cabal-marker 'marked-line)
  758. (put-text-property (point) (1+ (point))
  759. 'haskell-cabal-marker 'marked))
  760. (defun haskell-cabal-goto-mark ()
  761. "Go to marked line"
  762. (let ((marked-pos (text-property-any (point-min) (point-max)
  763. 'haskell-cabal-marker
  764. 'marked))
  765. (marked-line (text-property-any (point-min) (point-max)
  766. 'haskell-cabal-marker
  767. 'marked-line) )
  768. )
  769. (cond (marked-pos (goto-char marked-pos))
  770. (marked-line (goto-char marked-line)))))
  771. (defmacro haskell-cabal-with-subsection-line (replace &rest forms)
  772. "Mark line, copy subsection data into a temporary buffer, save indentation
  773. and execute FORMS at the marked line.
  774. If REPLACE is non-nil the subsection data is replaced with the
  775. resulting buffer-content. Unmark line at the end."
  776. `(progn
  777. (haskell-cabal-mark)
  778. (unwind-protect
  779. (haskell-cabal-with-subsection (haskell-cabal-subsection) ,replace
  780. (haskell-cabal-goto-mark)
  781. ,@forms)
  782. (haskell-cabal-remove-mark))))
  783. (defun haskell-cabal-get-line-content ()
  784. (haskell-cabal-with-subsection-line
  785. nil
  786. (haskell-cabal-with-cs-list
  787. (haskell-cabal-goto-mark)
  788. (buffer-substring-no-properties (line-beginning-position)
  789. (line-end-position)))))
  790. (defun haskell-cabal-module-to-filename (module)
  791. (concat (replace-regexp-in-string "[.]" "/" module ) ".hs"))
  792. (defconst haskell-cabal-module-sections '("exposed-modules" "other-modules")
  793. "List of sections that contain module names"
  794. )
  795. (defconst haskell-cabal-file-sections
  796. '("main-is" "c-sources" "data-files" "extra-source-files"
  797. "extra-doc-files" "extra-tmp-files" )
  798. "List of subsections that contain filenames"
  799. )
  800. (defconst haskell-cabal-source-bearing-sections
  801. '("library" "executable" "test-suite" "benchmark"))
  802. (defun haskell-cabal-source-section-p (section)
  803. (not (not (member (downcase (haskell-cabal-section-name section))
  804. haskell-cabal-source-bearing-sections))))
  805. (defun haskell-cabal-line-filename ()
  806. "Expand filename in current line according to the subsection type
  807. Module names in exposed-modules and other-modules are expanded by replacing each dot (.) in the module name with a foward slash (/) and appending \".hs\"
  808. Example: Foo.Bar.Quux ==> Foo/Bar/Quux.hs
  809. Source names from main-is and c-sources sections are left untouched
  810. "
  811. (let ((entry (haskell-cabal-get-line-content))
  812. (subsection (downcase (haskell-cabal-section-name
  813. (haskell-cabal-subsection)))))
  814. (cond ((member subsection haskell-cabal-module-sections)
  815. (haskell-cabal-module-to-filename entry))
  816. ((member subsection haskell-cabal-file-sections) entry))))
  817. (defun haskell-cabal-join-paths (&rest args)
  818. "Crude hack to replace f-join"
  819. (mapconcat 'identity args "/")
  820. )
  821. (defun haskell-cabal-find-or-create-source-file ()
  822. "Open the source file this line refers to."
  823. (interactive)
  824. (let* ((src-dirs (append (haskell-cabal-subsection-entry-list
  825. (haskell-cabal-section) "hs-source-dirs")
  826. '("")))
  827. (base-dir (file-name-directory (buffer-file-name)))
  828. (filename (haskell-cabal-line-filename)))
  829. (when filename
  830. (let ((candidates
  831. (delq nil (mapcar
  832. (lambda (dir)
  833. (let ((file (haskell-cabal-join-paths base-dir
  834. dir
  835. filename)))
  836. (when (and (file-readable-p file)
  837. (not (file-directory-p file)))
  838. file)))
  839. src-dirs))))
  840. (if (null candidates)
  841. (unwind-protect
  842. (progn
  843. (haskell-mode-toggle-interactive-prompt-state)
  844. (let* ((src-dir
  845. (haskell-cabal-join-paths base-dir
  846. (or (car src-dirs) "")))
  847. (newfile (haskell-cabal-join-paths src-dir filename))
  848. (do-create-p (y-or-n-p (format "Create file %s ?" newfile))))
  849. (when do-create-p
  850. (find-file-other-window newfile ))))
  851. (haskell-mode-toggle-interactive-prompt-state t))
  852. (find-file-other-window (car candidates)))))))
  853. (defun haskell-cabal-find-section-type (type &optional wrap)
  854. (save-excursion
  855. (haskell-cabal-next-section)
  856. (while
  857. (not
  858. (or
  859. (eobp)
  860. (string=
  861. (downcase type)
  862. (downcase (haskell-cabal-section-name (haskell-cabal-section))))))
  863. (haskell-cabal-next-section))
  864. (if (eobp)
  865. (if wrap (progn
  866. (goto-char (point-min))
  867. (haskell-cabal-find-section-type type nil) )
  868. nil)
  869. (point))))
  870. (defun haskell-cabal-goto-section-type (type)
  871. (let ((section (haskell-cabal-find-section-type type t)))
  872. (if section (goto-char section)
  873. (message "No %s section found" type))))
  874. (defun haskell-cabal-goto-library-section ()
  875. (interactive)
  876. (haskell-cabal-goto-section-type "library"))
  877. (defun haskell-cabal-goto-test-suite-section ()
  878. (interactive)
  879. (haskell-cabal-goto-section-type "test-suite"))
  880. (defun haskell-cabal-goto-executable-section ()
  881. (interactive)
  882. (haskell-cabal-goto-section-type "executable"))
  883. (defun haskell-cabal-goto-benchmark-section ()
  884. (interactive)
  885. (haskell-cabal-goto-section-type "benchmark"))
  886. (defun haskell-cabal-goto-common-section ()
  887. (interactive)
  888. (haskell-cabal-goto-section-type "common"))
  889. (defun haskell-cabal-line-entry-column ()
  890. "Column at which the line entry starts"
  891. (save-excursion
  892. (cl-case (haskell-cabal-classify-line)
  893. (section-data (beginning-of-line)
  894. (when (looking-at "[ ]*\\(?:,[ ]*\\)?")
  895. (goto-char (match-end 0))
  896. (current-column)))
  897. (subsection-header
  898. (haskell-cabal-section-data-start-column (haskell-cabal-subsection))))))
  899. (defun haskell-cabal-forward-to-line-entry ()
  900. "go forward to the beginning of the line entry (but never move backwards)"
  901. (let ((col (haskell-cabal-line-entry-column)))
  902. (when (and col (< (current-column) col))
  903. (beginning-of-line)
  904. (forward-char col))))
  905. (defun haskell-cabal-indent-line ()
  906. "Indent current line according to subsection"
  907. (interactive)
  908. (cl-case (haskell-cabal-classify-line)
  909. (section-data
  910. (save-excursion
  911. (let ((indent (haskell-cabal-section-data-indent-column
  912. (haskell-cabal-subsection))))
  913. (indent-line-to indent)
  914. (beginning-of-line)
  915. (when (looking-at "[ ]*\\([ ]\\{2\\},[ ]*\\)")
  916. (replace-match ", " t t nil 1)))))
  917. (empty
  918. (indent-relative)))
  919. (haskell-cabal-forward-to-line-entry))
  920. (defun haskell-cabal-map-sections (fun)
  921. "Execute fun over each section, collecting the result"
  922. (save-excursion
  923. (goto-char (point-min))
  924. (let ((results nil))
  925. (while (not (eobp))
  926. (let* ((section (haskell-cabal-section))
  927. (result (and section (funcall fun (haskell-cabal-section)))))
  928. (when section (setq results (cons result results))))
  929. (haskell-cabal-next-section))
  930. (nreverse results))))
  931. (defun haskell-cabal-section-add-build-dependency (dependency &optional sort sec)
  932. "Add a build dependency to the build-depends section"
  933. (let* ((section (or sec (haskell-cabal-section)))
  934. (subsection (and section
  935. (haskell-cabal-find-subsection section "build-depends"))))
  936. (when subsection
  937. (haskell-cabal-with-subsection
  938. subsection t
  939. (haskell-cabal-with-cs-list
  940. (insert dependency)
  941. (insert "\n")
  942. (when sort
  943. (goto-char (point-min))
  944. (sort-subr nil 'forward-line 'end-of-line
  945. 'haskell-cabal-sort-lines-key-fun)))))))
  946. (defun haskell-cabal-add-build-dependency (dependency &optional sort silent)
  947. "Add the given DEPENDENCY to every section in cabal file.
  948. If SORT argument is given sort dependencies in section after update.
  949. Pass SILENT argument to update all sections without asking user."
  950. (haskell-cabal-map-sections
  951. (lambda (section)
  952. (when (haskell-cabal-source-section-p section)
  953. (unwind-protect
  954. (progn
  955. (when
  956. (or silent
  957. (y-or-n-p (format "Add dependency %s to %s section %s?"
  958. dependency
  959. (haskell-cabal-section-name section)
  960. (haskell-cabal-section-value section))))
  961. (haskell-cabal-section-add-build-dependency dependency
  962. sort
  963. section))
  964. nil)
  965. (haskell-mode-toggle-interactive-prompt-state t))))))
  966. (defun haskell-cabal-add-dependency
  967. (package &optional version no-prompt sort silent)
  968. "Add PACKAGE to the cabal file.
  969. If VERSION is non-nil it will be appended as a minimum version.
  970. If NO-PROMPT is nil the minimum package version is read from the
  971. minibuffer. When SORT is non-nil the package entries are sorted
  972. afterwards. If SILENT is non-nil the user is prompted for each
  973. source-section."
  974. (interactive
  975. (list (read-from-minibuffer "Package entry: ") nil t t nil))
  976. (haskell-mode-toggle-interactive-prompt-state)
  977. (unwind-protect
  978. (save-window-excursion
  979. (find-file-other-window (haskell-cabal-find-file))
  980. (let ((entry (if no-prompt package
  981. (read-from-minibuffer
  982. "Package entry: "
  983. (concat package
  984. (if version (concat " >= " version) ""))))))
  985. (haskell-cabal-add-build-dependency entry sort silent)
  986. (when (or silent (y-or-n-p "Save cabal file? "))
  987. (save-buffer))))
  988. ;; unwind
  989. (haskell-mode-toggle-interactive-prompt-state t)))
  990. (defun haskell-cabal--find-tags-dir ()
  991. "Return a directory where TAGS file will be generated.
  992. Tries to find cabal file first and if succeeds uses its location.
  993. If cabal file not found uses current file directory. If current
  994. buffer not visiting a file returns nil."
  995. (or (haskell-cabal-find-dir)
  996. (when buffer-file-name
  997. (file-name-directory buffer-file-name))))
  998. (defun haskell-cabal--compose-hasktags-command (dir)
  999. "Prepare command to execute `hasktags` command in DIR folder.
  1000. To customise the command executed, see `haskell-hasktags-path'
  1001. and `haskell-hasktags-arguments'.
  1002. This function takes into account the user's operating system: in case
  1003. of Windows it generates a simple command, relying on Hasktags
  1004. itself to find source files:
  1005. hasktags --output=DIR\TAGS -x -e DIR
  1006. In other cases it uses `find` command to find all source files
  1007. recursively avoiding visiting unnecessary heavy directories like
  1008. .git, .svn, _darcs and build directories created by
  1009. cabal-install, stack, etc and passes list of found files to Hasktags."
  1010. (if (eq system-type 'windows-nt)
  1011. (format "%s --output=%s %s %s"
  1012. haskell-hasktags-path
  1013. (shell-quote-argument (expand-file-name "TAGS" dir))
  1014. (mapconcat #'identity haskell-hasktags-arguments " ")
  1015. (shell-quote-argument dir))
  1016. (format "cd %s && %s | %s"
  1017. (shell-quote-argument dir)
  1018. (concat "find . "
  1019. "-type d \\( "
  1020. "-name .git "
  1021. "-o -name .svn "
  1022. "-o -name _darcs "
  1023. "-o -name .stack-work "
  1024. "-o -name dist "
  1025. "-o -name dist-newstyle "
  1026. "-o -name .cabal-sandbox "
  1027. "\\) -prune "
  1028. "-o -type f \\( "
  1029. "-name '*.hs' "
  1030. "-or -name '*.lhs' "
  1031. "-or -name '*.hsc' "
  1032. "\\) -not \\( "
  1033. "-name '#*' "
  1034. "-or -name '.*' "
  1035. "\\) -print0")
  1036. (format "xargs -0 %s %s"
  1037. (shell-quote-argument haskell-hasktags-path)
  1038. (mapconcat #'identity haskell-hasktags-arguments " ")))))
  1039. (provide 'haskell-cabal)
  1040. ;;; haskell-cabal.el ends here