comparison .emacs.d/haskell-mode/haskell-mode.el @ 0:2764b4f45f9f

1st commit
author Shohei KOKUBO <e105744@ie.u-ryukyu.ac.jp>
date Mon, 21 Apr 2014 04:30:59 +0900
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:2764b4f45f9f
1 ;;; haskell-mode.el --- A Haskell editing mode -*- coding: utf-8 -*-
2
3 ;; Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc
4 ;; Copyright (C) 1992, 1997-1998 Simon Marlow, Graeme E Moss, and Tommy Thorn
5
6 ;; Author: 1992 Simon Marlow
7 ;; 1997-1998 Graeme E Moss <gem@cs.york.ac.uk> and
8 ;; Tommy Thorn <thorn@irisa.fr>,
9 ;; 2001-2002 Reuben Thomas (>=v1.4)
10 ;; 2003 Dave Love <fx@gnu.org>
11 ;; Keywords: faces files Haskell
12 ;; URL: https://github.com/haskell/haskell-mode
13
14 ;; This file is not part of GNU Emacs.
15
16 ;; This file is free software; you can redistribute it and/or modify
17 ;; it under the terms of the GNU General Public License as published by
18 ;; the Free Software Foundation; either version 3, or (at your option)
19 ;; any later version.
20
21 ;; This file is distributed in the hope that it will be useful,
22 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
23 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 ;; GNU General Public License for more details.
25
26 ;; You should have received a copy of the GNU General Public License
27 ;; along with this program. If not, see <http://www.gnu.org/licenses/>.
28
29 ;;; Commentary:
30
31 ;; A major mode for editing Haskell (the functional programming
32 ;; language, see URL `http://www.haskell.org') in Emacs.
33 ;;
34 ;; Some of its major features include:
35 ;;
36 ;; - syntax highlighting (font lock),
37 ;;
38 ;; - automatic indentation,
39 ;;
40 ;; - on-the-fly documentation,
41 ;;
42 ;; - interaction with inferior GHCi/Hugs instance,
43 ;;
44 ;; - scans declarations and places them in a menu.
45 ;;
46 ;; See URL `https://github.com/haskell/haskell-mode' and/or
47 ;; Info node `(haskell-mode)Introduction' for more information.
48 ;;
49 ;; Use `M-x haskell-mode-view-news` (after Haskell Mode is installed)
50 ;; to show information on recent changes in Haskell Mode.
51
52 ;;; Change Log:
53
54 ;; This mode is based on an editing mode by Simon Marlow 11/1/92
55 ;; and heavily modified by Graeme E Moss and Tommy Thorn 7/11/98.
56 ;;
57 ;; Version 1.5:
58 ;; Added autoload for haskell-indentation
59 ;;
60 ;; Version 1.43:
61 ;; Various tweaks to doc strings and customization support from
62 ;; Ville Skyttä <scop@xemacs.org>.
63 ;;
64 ;; Version 1.42:
65 ;; Added autoload for GHCi inferior mode (thanks to Scott
66 ;; Williams for the bug report and fix).
67 ;;
68 ;; Version 1.41:
69 ;; Improved packaging, and made a couple more variables
70 ;; interactively settable.
71 ;;
72 ;; Version 1.4:
73 ;; Added GHCi mode from Chris Webb, and tidied up a little.
74 ;;
75 ;; Version 1.3:
76 ;; The literate or non-literate style of a buffer is now indicated
77 ;; by just the variable haskell-literate: nil, `bird', or `tex'.
78 ;; For literate buffers with ambiguous style, the value of
79 ;; haskell-literate-default is used.
80 ;;
81 ;; Version 1.2:
82 ;; Separated off font locking, declaration scanning and simple
83 ;; indentation, and made them separate modules. Modules can be
84 ;; added easily now. Support for modules haskell-doc,
85 ;; haskell-indent, and haskell-hugs. Literate and non-literate
86 ;; modes integrated into one mode, and literate buffer indicated by
87 ;; value of haskell-literate(-bird-style).
88 ;;
89 ;; Version 1.1:
90 ;; Added support for declaration scanning under XEmacs via
91 ;; func-menu. Moved operators to level two fontification.
92 ;;
93 ;; Version 1.0:
94 ;; Added a nice indention support from Heribert Schuetz
95 ;; <Heribert.Schuetz@informatik.uni-muenchen.de>:
96 ;;
97 ;; I have just hacked an Emacs Lisp function which you might prefer
98 ;; to `indent-relative' in haskell-mode.el. See below. It is not
99 ;; really Haskell-specific because it does not take into account
100 ;; keywords like `do', `of', and `let' (where the layout rule
101 ;; applies), but I already find it useful.
102 ;;
103 ;; Cleaned up the imenu support. Added support for literate scripts.
104 ;;
105 ;; Version 0.103 [HWL]:
106 ;; From Hans Wolfgang Loidl <hwloidl@dcs.gla.ac.uk>:
107 ;;
108 ;; I (HWL) added imenu support by copying the appropriate functions
109 ;; from hugs-mode. A menu-bar item "Declarations" is now added in
110 ;; haskell mode. The new code, however, needs some clean-up.
111 ;;
112 ;; Version 0.102:
113 ;;
114 ;; Moved C-c C-c key binding to comment-region. Leave M-g M-g to do
115 ;; the work. comment-start-skip is changed to comply with comment-start.
116 ;;
117 ;; Version 0.101:
118 ;;
119 ;; Altered indent-line-function to indent-relative.
120 ;;
121 ;; Version 0.100:
122 ;;
123 ;; First official release.
124
125 ;;; Code:
126
127 (require 'dabbrev)
128 (require 'compile)
129 (require 'flymake)
130 (require 'outline)
131 (require 'haskell-align-imports)
132 (require 'haskell-sort-imports)
133 (require 'haskell-string)
134 (with-no-warnings (require 'cl))
135
136 ;; FIXME: code-smell: too many forward decls for haskell-session are required here
137 (defvar haskell-session)
138 (declare-function haskell-process-do-try-info "haskell-process" (sym))
139 (declare-function haskell-process-generate-tags "haskell-process" (&optional and-then-find-this-tag))
140 (declare-function haskell-session "haskell-session" ())
141 (declare-function haskell-session-all-modules "haskell-session" (&optional DONTCREATE))
142 (declare-function haskell-session-cabal-dir "haskell-session" (session))
143 (declare-function haskell-session-maybe "haskell-session" ())
144 (declare-function haskell-session-tags-filename "haskell-session" (session))
145 (declare-function haskell-session-current-dir "haskell-session" (session))
146
147 ;; All functions/variables start with `(literate-)haskell-'.
148
149 ;; Version of mode.
150 (defconst haskell-version "@VERSION@"
151 "The release version of `haskell-mode'.")
152
153 (defconst haskell-git-version "@GIT_VERSION@"
154 "The Git version of `haskell-mode'.")
155
156 (defvar haskell-mode-pkg-base-dir (file-name-directory load-file-name)
157 "Package base directory of installed `haskell-mode'.
158 Used for locating additional package data files.")
159
160 ;;;###autoload
161 (defun haskell-version (&optional here)
162 "Show the `haskell-mode` version in the echo area.
163 With prefix argument HERE, insert it at point.
164 When FULL is non-nil, use a verbose version string.
165 When MESSAGE is non-nil, display a message with the version."
166 (interactive "P")
167 (let* ((haskell-mode-dir (ignore-errors
168 (file-name-directory (or (locate-library "haskell-mode") ""))))
169 (_version (format "haskell-mode version %s (%s @ %s)"
170 haskell-version
171 haskell-git-version
172 haskell-mode-dir)))
173 (if here
174 (insert _version)
175 (message "%s" _version))))
176
177 ;;;###autoload
178 (defun haskell-mode-view-news ()
179 "Display information on recent changes to haskell-mode."
180 (interactive)
181 (with-current-buffer (find-file-read-only (expand-file-name "NEWS" haskell-mode-pkg-base-dir))
182 (goto-char (point-min))
183 (hide-sublevels 1)
184 (outline-next-visible-heading 1)
185 (show-subtree)))
186
187 (defgroup haskell nil
188 "Major mode for editing Haskell programs."
189 :link '(custom-manual "(haskell-mode)")
190 :group 'languages
191 :prefix "haskell-")
192
193 ;;;###autoload
194 (defun haskell-customize ()
195 "Browse the haskell customize sub-tree.
196 This calls 'customize-browse' with haskell as argument and makes
197 sure all haskell customize definitions have been loaded."
198 (interactive)
199 ;; make sure all modules with (defcustom ...)s are loaded
200 (mapc 'require
201 '(haskell-checkers haskell-compile haskell-doc haskell-font-lock haskell-indentation haskell-indent haskell-interactive-mode haskell-menu haskell-process haskell-yas inf-haskell))
202 (customize-browse 'haskell))
203
204 ;; Are we looking at a literate script?
205 (defvar haskell-literate nil
206 "*If not nil, the current buffer contains a literate Haskell script.
207 Possible values are: `bird' and `tex', for Bird-style and LaTeX-style
208 literate scripts respectively. Set by `haskell-mode' and
209 `literate-haskell-mode'. For an ambiguous literate buffer -- i.e. does
210 not contain either \"\\begin{code}\" or \"\\end{code}\" on a line on
211 its own, nor does it contain \">\" at the start of a line -- the value
212 of `haskell-literate-default' is used.")
213 (make-variable-buffer-local 'haskell-literate)
214 (put 'haskell-literate 'safe-local-variable 'symbolp)
215 ;; Default literate style for ambiguous literate buffers.
216 (defcustom haskell-literate-default 'bird
217 "Default value for `haskell-literate'.
218 Used if the style of a literate buffer is ambiguous. This variable should
219 be set to the preferred literate style."
220 :group 'haskell
221 :type '(choice (const bird) (const tex) (const nil)))
222
223 ;;;###autoload
224 (defvar haskell-mode-map
225 (let ((map (make-sparse-keymap)))
226 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
227 ;; For inferior haskell mode, use the below bindings
228 ;; (define-key map [?\M-C-x] 'inferior-haskell-send-defun)
229 ;; (define-key map [?\C-x ?\C-e] 'inferior-haskell-send-last-sexp)
230 ;; (define-key map [?\C-c ?\C-r] 'inferior-haskell-send-region)
231 (define-key map [?\C-x ?\C-d] 'inferior-haskell-send-decl)
232 (define-key map [?\C-c ?\C-z] 'switch-to-haskell)
233 (define-key map [?\C-c ?\C-l] 'inferior-haskell-load-file)
234 ;; I think it makes sense to bind inferior-haskell-load-and-run to C-c
235 ;; C-r, but since it used to be bound to `reload' until June 2007, I'm
236 ;; going to leave it out for now.
237 ;; (define-key map [?\C-c ?\C-r] 'inferior-haskell-load-and-run)
238 (define-key map [?\C-c ?\C-b] 'switch-to-haskell)
239 ;; (define-key map [?\C-c ?\C-s] 'inferior-haskell-start-process)
240 ;; That's what M-; is for.
241 ;; (define-key map "\C-c\C-c" 'comment-region)
242 (define-key map (kbd "C-c C-t") 'inferior-haskell-type)
243 (define-key map (kbd "C-c C-i") 'inferior-haskell-info)
244 (define-key map (kbd "C-c M-.") 'inferior-haskell-find-definition)
245 (define-key map (kbd "C-c C-d") 'inferior-haskell-find-haddock)
246 (define-key map [?\C-c ?\C-v] 'haskell-check)
247
248 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
249 ;; Editing-specific commands
250 (define-key map (kbd "C-c C-.") 'haskell-mode-format-imports)
251 (define-key map [remap delete-indentation] 'haskell-delete-indentation)
252
253 map)
254 "Keymap used in Haskell mode.")
255
256 (easy-menu-define haskell-mode-menu haskell-mode-map
257 "Menu for the Haskell major mode."
258 ;; Suggestions from Pupeno <pupeno@pupeno.com>:
259 ;; - choose the underlying interpreter
260 ;; - look up docs
261 `("Haskell"
262 ["Indent line" indent-according-to-mode]
263 ["Indent region" indent-region mark-active]
264 ["(Un)Comment region" comment-region mark-active]
265 "---"
266 ["Start interpreter" switch-to-haskell]
267 ["Load file" inferior-haskell-load-file]
268 "---"
269 ["Load tidy core" ghc-core-create-core]
270 "---"
271 ,(if (default-boundp 'eldoc-documentation-function)
272 ["Doc mode" eldoc-mode
273 :style toggle :selected (bound-and-true-p eldoc-mode)]
274 ["Doc mode" haskell-doc-mode
275 :style toggle :selected (and (boundp 'haskell-doc-mode) haskell-doc-mode)])
276 ["Customize" (customize-group 'haskell)]
277 ))
278
279 ;; Syntax table.
280 (defvar haskell-mode-syntax-table
281 (let ((table (make-syntax-table)))
282 (modify-syntax-entry ?\ " " table)
283 (modify-syntax-entry ?\t " " table)
284 (modify-syntax-entry ?\" "\"" table)
285 (modify-syntax-entry ?\' "\'" table)
286 (modify-syntax-entry ?_ "w" table)
287 (modify-syntax-entry ?\( "()" table)
288 (modify-syntax-entry ?\) ")(" table)
289 (modify-syntax-entry ?\[ "(]" table)
290 (modify-syntax-entry ?\] ")[" table)
291
292 (cond ((featurep 'xemacs)
293 ;; I don't know whether this is equivalent to the below
294 ;; (modulo nesting). -- fx
295 (modify-syntax-entry ?{ "(}5" table)
296 (modify-syntax-entry ?} "){8" table)
297 (modify-syntax-entry ?- "_ 1267" table))
298 (t
299 ;; In Emacs 21, the `n' indicates that they nest.
300 ;; The `b' annotation is actually ignored because it's only
301 ;; meaningful on the second char of a comment-starter, so
302 ;; on Emacs 20 and before we get wrong results. --Stef
303 (modify-syntax-entry ?\{ "(}1nb" table)
304 (modify-syntax-entry ?\} "){4nb" table)
305 (modify-syntax-entry ?- "_ 123" table)))
306 (modify-syntax-entry ?\n ">" table)
307
308 (let (i lim)
309 (map-char-table
310 (lambda (k v)
311 (when (equal v '(1))
312 ;; The current Emacs 22 codebase can pass either a char
313 ;; or a char range.
314 (if (consp k)
315 (setq i (car k)
316 lim (cdr k))
317 (setq i k
318 lim k))
319 (while (<= i lim)
320 (when (> i 127)
321 (modify-syntax-entry i "_" table))
322 (setq i (1+ i)))))
323 (standard-syntax-table)))
324
325 (modify-syntax-entry ?\` "$`" table)
326 (modify-syntax-entry ?\\ "\\" table)
327 (mapc (lambda (x)
328 (modify-syntax-entry x "_" table))
329 ;; Some of these are actually OK by default.
330 "!#$%&*+./:<=>?@^|~")
331 (unless (featurep 'mule)
332 ;; Non-ASCII syntax should be OK, at least in Emacs.
333 (mapc (lambda (x)
334 (modify-syntax-entry x "_" table))
335 (concat "¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿"
336 "×÷"))
337 (mapc (lambda (x)
338 (modify-syntax-entry x "w" table))
339 (concat "ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ"
340 "ØÙÚÛÜÝÞß"
341 "àáâãäåæçèéêëìíîïðñòóôõö"
342 "øùúûüýþÿ")))
343 table)
344 "Syntax table used in Haskell mode.")
345
346 (defun haskell-ident-at-point ()
347 "Return the identifier under point, or nil if none found.
348 May return a qualified name."
349 (let ((reg (haskell-ident-pos-at-point)))
350 (when reg
351 (buffer-substring-no-properties (car reg) (cdr reg)))))
352
353 (defun haskell-ident-pos-at-point ()
354 "Return the span of the identifier under point, or nil if none found.
355 May return a qualified name."
356 (save-excursion
357 ;; Skip whitespace if we're on it. That way, if we're at "map ", we'll
358 ;; see the word "map".
359 (if (and (not (eobp))
360 (eq ? (char-syntax (char-after))))
361 (skip-chars-backward " \t"))
362
363 (let ((case-fold-search nil))
364 (multiple-value-bind (start end)
365 (if (looking-at "\\s_")
366 (list (progn (skip-syntax-backward "_") (point))
367 (progn (skip-syntax-forward "_") (point)))
368 (list
369 (progn (skip-syntax-backward "w'")
370 (skip-syntax-forward "'") (point))
371 (progn (skip-syntax-forward "w'") (point))))
372 ;; If we're looking at a module ID that qualifies further IDs, add
373 ;; those IDs.
374 (goto-char start)
375 (while (and (looking-at "[[:upper:]]") (eq (char-after end) ?.)
376 ;; It's a module ID that qualifies further IDs.
377 (goto-char (1+ end))
378 (save-excursion
379 (when (not (zerop (skip-syntax-forward
380 (if (looking-at "\\s_") "_" "w'"))))
381 (setq end (point))))))
382 ;; If we're looking at an ID that's itself qualified by previous
383 ;; module IDs, add those too.
384 (goto-char start)
385 (if (eq (char-after) ?.) (forward-char 1)) ;Special case for "."
386 (while (and (eq (char-before) ?.)
387 (progn (forward-char -1)
388 (not (zerop (skip-syntax-backward "w'"))))
389 (skip-syntax-forward "'")
390 (looking-at "[[:upper:]]"))
391 (setq start (point)))
392 ;; This is it.
393 (cons start end)))))
394
395 (defun haskell-delete-indentation (&optional arg)
396 "Like `delete-indentation' but ignoring Bird-style \">\"."
397 (interactive "*P")
398 (let ((fill-prefix (or fill-prefix (if (eq haskell-literate 'bird) ">"))))
399 (delete-indentation arg)))
400
401 ;; Various mode variables.
402
403 (defcustom haskell-mode-hook nil
404 "Hook run after entering `haskell-mode'.
405
406 Some of the supported modules that can be activated via this hook:
407
408 `haskell-decl-scan', Graeme E Moss
409 Scans top-level declarations, and places them in a menu.
410
411 `haskell-doc', Hans-Wolfgang Loidl
412 Echoes types of functions or syntax of keywords when the cursor is idle.
413
414 `haskell-indentation', Kristof Bastiaensen
415 Intelligent semi-automatic indentation Mk2
416
417 `haskell-indent', Guy Lapalme
418 Intelligent semi-automatic indentation.
419
420 `haskell-simple-indent', Graeme E Moss and Heribert Schuetz
421 Simple indentation.
422
423 Module X is activated using the command `turn-on-X'. For example,
424 `haskell-doc' is activated using `turn-on-haskell-doc'.
425 For more information on a specific module, see the help for its `X-mode'
426 function. Some modules can be deactivated using `turn-off-X'.
427
428 See Info node `(haskell-mode)haskell-mode-hook' for more details.
429
430 Warning: do not enable more than one of the three indentation
431 modes. See Info node `(haskell-mode)indentation' for more
432 details."
433 :type 'hook
434 :group 'haskell
435 :link '(info-link "(haskell-mode)haskell-mode-hook")
436 :link '(function-link haskell-mode)
437 :options `(capitalized-words-mode
438 imenu-add-menubar-index
439 turn-on-eldoc-mode
440 turn-on-haskell-decl-scan
441 turn-on-haskell-doc
442 turn-on-haskell-indent
443 turn-on-haskell-indentation
444 turn-on-haskell-simple-indent
445 turn-on-haskell-unicode-input-method))
446
447 (defvar eldoc-print-current-symbol-info-function)
448
449 ;; For compatibility with Emacs < 24, derive conditionally
450 (defalias 'haskell-parent-mode
451 (if (fboundp 'prog-mode) 'prog-mode 'fundamental-mode))
452
453 ;; The main mode functions
454 ;;;###autoload
455 (define-derived-mode haskell-mode haskell-parent-mode "Haskell"
456 "Major mode for editing Haskell programs.
457
458 See also Info node `(haskell-mode)Getting Started' for more
459 information about this mode.
460
461 \\<haskell-mode-map>
462 Literate scripts are supported via `literate-haskell-mode'.
463 The variable `haskell-literate' indicates the style of the script in the
464 current buffer. See the documentation on this variable for more details.
465
466 Use `haskell-version' to find out what version of Haskell mode you are
467 currently using.
468
469 Additional Haskell mode modules can be hooked in via `haskell-mode-hook';
470 see documentation for that variable for more details."
471 :group 'haskell
472 (set (make-local-variable 'paragraph-start) (concat "^$\\|" page-delimiter))
473 (set (make-local-variable 'paragraph-separate) paragraph-start)
474 (set (make-local-variable 'fill-paragraph-function) 'haskell-fill-paragraph)
475 ;; (set (make-local-variable 'adaptive-fill-function) 'haskell-adaptive-fill)
476 (set (make-local-variable 'adaptive-fill-mode) nil)
477 (set (make-local-variable 'comment-start) "-- ")
478 (set (make-local-variable 'comment-padding) 0)
479 (set (make-local-variable 'comment-start-skip) "[-{]-[ \t]*")
480 (set (make-local-variable 'comment-end) "")
481 (set (make-local-variable 'comment-end-skip) "[ \t]*\\(-}\\|\\s>\\)")
482 (set (make-local-variable 'parse-sexp-ignore-comments) nil)
483 (set (make-local-variable 'indent-line-function) 'haskell-mode-suggest-indent-choice)
484 ;; Set things up for eldoc-mode.
485 (set (make-local-variable 'eldoc-documentation-function)
486 'haskell-doc-current-info)
487 ;; Set things up for imenu.
488 (set (make-local-variable 'imenu-create-index-function)
489 'haskell-ds-create-imenu-index)
490 ;; Set things up for font-lock.
491 (set (make-local-variable 'font-lock-defaults)
492 '(haskell-font-lock-choose-keywords
493 nil nil ((?\' . "w") (?_ . "w")) nil
494 (font-lock-syntactic-keywords
495 . haskell-font-lock-choose-syntactic-keywords)
496 (font-lock-syntactic-face-function
497 . haskell-syntactic-face-function)
498 ;; Get help from font-lock-syntactic-keywords.
499 (parse-sexp-lookup-properties . t)))
500 ;; Haskell's layout rules mean that TABs have to be handled with extra care.
501 ;; The safer option is to avoid TABs. The second best is to make sure
502 ;; TABs stops are 8 chars apart, as mandated by the Haskell Report. --Stef
503 (set (make-local-variable 'indent-tabs-mode) nil)
504 (set (make-local-variable 'tab-width) 8)
505 ;; dynamic abbrev support: recognize Haskell identifiers
506 ;; Haskell is case-sensitive language
507 (set (make-local-variable 'dabbrev-case-fold-search) nil)
508 (set (make-local-variable 'dabbrev-case-distinction) nil)
509 (set (make-local-variable 'dabbrev-case-replace) nil)
510 (set (make-local-variable 'dabbrev-abbrev-char-regexp) "\\sw\\|[.]")
511 (setq haskell-literate nil)
512 (add-hook 'before-save-hook 'haskell-mode-before-save-handler nil t)
513 (add-hook 'after-save-hook 'haskell-mode-after-save-handler nil t)
514 )
515
516 (defun haskell-fill-paragraph (justify)
517 (save-excursion
518 ;; Fill paragraph should only work in comments.
519 ;; The -- comments are handled properly by default
520 ;; The {- -} comments need some extra love.
521 (let* ((syntax-values (syntax-ppss))
522 (comment-num (nth 4 syntax-values)))
523 (cond
524 ((eq t comment-num)
525 ;; standard fill works wonders inside a non-nested comment
526 (fill-comment-paragraph justify))
527
528 ((integerp comment-num)
529 ;; we are in a nested comment. lets narrow to comment content
530 ;; and use plain paragraph fill for that
531 (let* ((comment-start-point (nth 8 syntax-values))
532 (comment-end-point
533 (save-excursion
534 (re-search-forward "-}" (point-max) t comment-num)
535 (point)))
536 (fill-paragraph-handle-comment nil))
537 (save-restriction
538 (narrow-to-region (+ 2 comment-start-point) (- comment-end-point 2))
539 (fill-paragraph justify))))
540 ((eolp)
541 ;; do nothing outside of a comment
542 t)
543 (t
544 ;; go to end of line and try again
545 (end-of-line)
546 (haskell-fill-paragraph justify))))))
547
548
549 ;; (defun haskell-adaptive-fill ()
550 ;; ;; We want to use "-- " as the prefix of "-- |", etc.
551 ;; (let* ((line-end (save-excursion (end-of-line) (point)))
552 ;; (line-start (point)))
553 ;; (save-excursion
554 ;; (unless (in-comment)
555 ;; ;; Try to find the start of a comment. We only fill comments.
556 ;; (search-forward-regexp comment-start-skip line-end t))
557 ;; (when (in-comment)
558 ;; (let ();(prefix-start (point)))
559 ;; (skip-syntax-forward "^w")
560 ;; (make-string (- (point) line-start) ?\s))))))
561
562
563
564 ;;;###autoload
565 (define-derived-mode literate-haskell-mode haskell-mode "LitHaskell"
566 "As `haskell-mode' but for literate scripts."
567 (setq haskell-literate
568 (save-excursion
569 (goto-char (point-min))
570 (cond
571 ((re-search-forward "^\\\\\\(begin\\|end\\){code}$" nil t) 'tex)
572 ((re-search-forward "^>" nil t) 'bird)
573 (t haskell-literate-default))))
574 (if (eq haskell-literate 'bird)
575 ;; fill-comment-paragraph isn't much use there, and even gets confused
576 ;; by the syntax-table text-properties we add to mark the first char
577 ;; of each line as a comment-starter.
578 (set (make-local-variable 'fill-paragraph-handle-comment) nil))
579 (set (make-local-variable 'mode-line-process)
580 '("/" (:eval (symbol-name haskell-literate)))))
581
582 ;;;###autoload(add-to-list 'auto-mode-alist '("\\.\\(?:[gh]s\\|hi\\)\\'" . haskell-mode))
583 ;;;###autoload(add-to-list 'auto-mode-alist '("\\.l[gh]s\\'" . literate-haskell-mode))
584 ;;;###autoload(add-to-list 'interpreter-mode-alist '("runghc" . haskell-mode))
585 ;;;###autoload(add-to-list 'interpreter-mode-alist '("runhaskell" . haskell-mode))
586
587 (defcustom haskell-hoogle-command
588 (if (executable-find "hoogle") "hoogle")
589 "Name of the command to use to query Hoogle.
590 If nil, use the Hoogle web-site."
591 :group 'haskell
592 :type '(choice (const :tag "Use Web-site" nil)
593 string))
594
595 ;;;###autoload
596 (defun haskell-hoogle (query)
597 "Do a Hoogle search for QUERY."
598 (interactive
599 (let ((def (haskell-ident-at-point)))
600 (if (and def (symbolp def)) (setq def (symbol-name def)))
601 (list (read-string (if def
602 (format "Hoogle query (default %s): " def)
603 "Hoogle query: ")
604 nil nil def))))
605 (if (null haskell-hoogle-command)
606 (browse-url (format "http://haskell.org/hoogle/?q=%s" query))
607 (lexical-let ((temp-buffer (help-buffer)))
608 (with-output-to-temp-buffer temp-buffer
609 (with-current-buffer standard-output
610 (let ((hoogle-process
611 (start-process "hoogle" (current-buffer) haskell-hoogle-command query))
612 (scroll-to-top
613 (lambda (process event)
614 (set-window-start (get-buffer-window temp-buffer t) 1))))
615 (set-process-sentinel hoogle-process scroll-to-top)))))))
616
617 ;;;###autoload
618 (defalias 'hoogle 'haskell-hoogle)
619
620 ;;;###autoload
621 (defun haskell-hayoo (query)
622 "Do a Hayoo search for QUERY."
623 (interactive
624 (let ((def (haskell-ident-at-point)))
625 (if (and def (symbolp def)) (setq def (symbol-name def)))
626 (list (read-string (if def
627 (format "Hayoo query (default %s): " def)
628 "Hayoo query: ")
629 nil nil def))))
630 (browse-url (format "http://holumbus.fh-wedel.de/hayoo/hayoo.html?query=%s" query)))
631
632 ;;;###autoload
633 (defalias 'hayoo 'haskell-hayoo)
634
635 (defcustom haskell-check-command "hlint"
636 "*Command used to check a Haskell file."
637 :group 'haskell
638 :type '(choice (const "hlint")
639 (const "ghc -fno-code")
640 (string :tag "Other command")))
641
642 (defcustom haskell-completing-read-function 'ido-completing-read
643 "Default function to use for completion."
644 :group 'haskell
645 :type '(choice
646 (function-item :tag "ido" :value ido-completing-read)
647 (function-item :tag "helm" :value helm--completing-read-default)
648 (function-item :tag "completing-read" :value completing-read)
649 (function :tag "Custom function")))
650
651 (defcustom haskell-stylish-on-save nil
652 "Whether to run stylish-haskell on the buffer before saving."
653 :group 'haskell
654 :type 'boolean)
655
656 (defcustom haskell-tags-on-save nil
657 "Generate tags via hasktags after saving."
658 :group 'haskell
659 :type 'boolean)
660
661 (defvar haskell-saved-check-command nil
662 "Internal use.")
663
664 (defcustom haskell-indent-spaces 2
665 "Number of spaces to indent inwards.")
666
667 ;; Like Python. Should be abstracted, sigh.
668 (defun haskell-check (command)
669 "Check a Haskell file (default current buffer's file).
670 Runs COMMAND, a shell command, as if by `compile'.
671 See `haskell-check-command' for the default."
672 (interactive
673 (list (read-string "Checker command: "
674 (or haskell-saved-check-command
675 (concat haskell-check-command " "
676 (let ((name (buffer-file-name)))
677 (if name
678 (file-name-nondirectory name))))))))
679 (setq haskell-saved-check-command command)
680 (save-some-buffers (not compilation-ask-about-save) nil)
681 (compilation-start command))
682
683 (defun haskell-flymake-init ()
684 "Flymake init function for Haskell.
685 To be added to `flymake-init-create-temp-buffer-copy'."
686 (let ((checker-elts (and haskell-saved-check-command
687 (split-string haskell-saved-check-command))))
688 (list (car checker-elts)
689 (append (cdr checker-elts)
690 (list (flymake-init-create-temp-buffer-copy
691 'flymake-create-temp-inplace))))))
692
693 (add-to-list 'flymake-allowed-file-name-masks '("\\.l?hs\\'" haskell-flymake-init))
694
695 (defun haskell-mode-suggest-indent-choice ()
696 "Ran when the user tries to indent in the buffer but no indentation mode has been selected.
697 Brings up the documentation for haskell-mode-hook."
698 (describe-variable 'haskell-mode-hook))
699
700 (defun haskell-mode-format-imports ()
701 "Format the imports by aligning and sorting them."
702 (interactive)
703 (let ((col (current-column)))
704 (haskell-sort-imports)
705 (haskell-align-imports)
706 (goto-char (+ (line-beginning-position)
707 col))))
708
709 (defun haskell-mode-message-line (str)
710 "Message only one line, multiple lines just disturbs the programmer."
711 (let ((lines (split-string str "\n" t)))
712 (when (and (car lines) (stringp (car lines)))
713 (message "%s"
714 (concat (car lines)
715 (if (and (cdr lines) (stringp (cadr lines)))
716 (format " [ %s .. ]" (haskell-string-take (haskell-trim (cadr lines)) 10))
717 ""))))))
718
719 (defun haskell-mode-contextual-space ()
720 "Contextually do clever stuff when hitting space."
721 (interactive)
722 (if (not (haskell-session-maybe))
723 (self-insert-command 1)
724 (cond ((save-excursion (forward-word -1)
725 (looking-at "^import$"))
726 (insert " ")
727 (let ((module (funcall haskell-completing-read-function "Module: " (haskell-session-all-modules))))
728 (insert module)
729 (haskell-mode-format-imports)))
730 ((not (string= "" (save-excursion (forward-char -1) (haskell-ident-at-point))))
731 (let ((ident (save-excursion (forward-char -1) (haskell-ident-at-point))))
732 (insert " ")
733 (haskell-process-do-try-info ident)))
734 (t (insert " ")))))
735
736 (defun haskell-mode-before-save-handler ()
737 "Function that will be called before buffer's saving."
738 )
739
740 (defun haskell-mode-after-save-handler ()
741 "Function that will be called after buffer's saving."
742 (when haskell-tags-on-save
743 (ignore-errors (when (and (boundp 'haskell-session) haskell-session)
744 (haskell-process-generate-tags))))
745 (when haskell-stylish-on-save
746 (ignore-errors (haskell-mode-stylish-buffer)))
747 (let ((before-save-hook '())
748 (after-save-hook '()))
749 (basic-save-buffer))
750 )
751
752 (defun haskell-mode-buffer-apply-command (cmd)
753 "Execute shell command CMD with current buffer as input and
754 replace the whole buffer with the output. If CMD fails the buffer
755 remains unchanged."
756 (set-buffer-modified-p t)
757 (let* ((chomp (lambda (str)
758 (while (string-match "\\`\n+\\|^\\s-+\\|\\s-+$\\|\n+\\'" str)
759 (setq str (replace-match "" t t str)))
760 str))
761 (errout (lambda (fmt &rest args)
762 (let* ((warning-fill-prefix " "))
763 (display-warning cmd (apply 'format fmt args) :warning))))
764 (filename (buffer-file-name (current-buffer)))
765 (cmd-prefix (replace-regexp-in-string " .*" "" cmd))
766 (tmp-file (make-temp-file cmd-prefix))
767 (err-file (make-temp-file cmd-prefix))
768 (default-directory (if (and (boundp 'haskell-session)
769 haskell-session)
770 (haskell-session-cabal-dir haskell-session)
771 default-directory))
772 (errcode (with-temp-file tmp-file
773 (call-process cmd filename
774 (list (current-buffer) err-file) nil)))
775 (stderr-output
776 (with-temp-buffer
777 (insert-file-contents err-file)
778 (funcall chomp (buffer-substring-no-properties (point-min) (point-max)))))
779 (stdout-output
780 (with-temp-buffer
781 (insert-file-contents tmp-file)
782 (buffer-substring-no-properties (point-min) (point-max)))))
783 (if (string= "" stderr-output)
784 (if (string= "" stdout-output)
785 (funcall errout
786 "Error: %s produced no output, leaving buffer alone" cmd)
787 (save-restriction
788 (widen)
789 ;; command successful, insert file with replacement to preserve
790 ;; markers.
791 (insert-file-contents tmp-file nil nil nil t)))
792 ;; non-null stderr, command must have failed
793 (funcall errout "%s failed: %s" cmd stderr-output)
794 )
795 (delete-file tmp-file)
796 (delete-file err-file)
797 ))
798
799 (defun haskell-mode-stylish-buffer ()
800 "Apply stylish-haskell to the current buffer."
801 (interactive)
802 (let ((column (current-column))
803 (line (line-number-at-pos)))
804 (haskell-mode-buffer-apply-command "stylish-haskell")
805 (goto-char (point-min))
806 (forward-line (1- line))
807 (goto-char (+ column (point)))))
808
809 (defun haskell-mode-tag-find (&optional next-p)
810 "The tag find function, specific for the particular session."
811 (interactive "P")
812 (cond
813 ((eq 'font-lock-string-face
814 (get-text-property (point) 'face))
815 (let* ((string (save-excursion
816 (buffer-substring-no-properties
817 (1+ (search-backward-regexp "\"" (line-beginning-position) nil 1))
818 (1- (progn (forward-char 1)
819 (search-forward-regexp "\"" (line-end-position) nil 1))))))
820 (fp (expand-file-name string
821 (haskell-session-cabal-dir (haskell-session)))))
822 (find-file
823 (read-file-name
824 ""
825 fp
826 fp))))
827 (t (let ((tags-file-name (haskell-session-tags-filename (haskell-session)))
828 (tags-revert-without-query t)
829 (ident (haskell-ident-at-point)))
830 (when (not (string= "" (haskell-trim ident)))
831 (cond ((file-exists-p tags-file-name)
832 (find-tag ident next-p))
833 (t (haskell-process-generate-tags ident))))))))
834
835 ;; From Bryan O'Sullivan's blog:
836 ;; http://www.serpentine.com/blog/2007/10/09/using-emacs-to-insert-scc-annotations-in-haskell-code/
837 (defun haskell-mode-insert-scc-at-point ()
838 "Insert an SCC annotation at point."
839 (interactive)
840 (if (or (looking-at "\\b\\|[ \t]\\|$") (and (not (bolp))
841 (save-excursion
842 (forward-char -1)
843 (looking-at "\\b\\|[ \t]"))))
844 (let ((space-at-point (looking-at "[ \t]")))
845 (unless (and (not (bolp)) (save-excursion
846 (forward-char -1)
847 (looking-at "[ \t]")))
848 (insert " "))
849 (insert "{-# SCC \"\" #-}")
850 (unless space-at-point
851 (insert " "))
852 (forward-char (if space-at-point -5 -6)))
853 (error "Not over an area of whitespace")))
854
855 ;; Also Bryan O'Sullivan's.
856 (defun haskell-mode-kill-scc-at-point ()
857 "Kill the SCC annotation at point."
858 (interactive)
859 (save-excursion
860 (let ((old-point (point))
861 (scc "\\({-#[ \t]*SCC \"[^\"]*\"[ \t]*#-}\\)[ \t]*"))
862 (while (not (or (looking-at scc) (bolp)))
863 (forward-char -1))
864 (if (and (looking-at scc)
865 (<= (match-beginning 1) old-point)
866 (> (match-end 1) old-point))
867 (kill-region (match-beginning 0) (match-end 0))
868 (error "No SCC at point")))))
869
870 (defun haskell-rgrep (&optional prompt)
871 "Grep the effective project for the symbol at point. Very
872 useful for codebase navigation. Prompts for an arbitrary regexp
873 given a prefix arg."
874 (interactive "P")
875 (let ((sym (if prompt
876 (read-from-minibuffer "Look for: ")
877 (haskell-ident-at-point))))
878 (rgrep sym
879 "*.hs" ;; TODO: common Haskell extensions.
880 (haskell-session-current-dir (haskell-session)))))
881
882 (defun haskell-fontify-as-mode (text mode)
883 "Fontify TEXT as MODE, returning the fontified text."
884 (with-temp-buffer
885 (funcall mode)
886 (insert text)
887 (font-lock-fontify-buffer)
888 (buffer-substring (point-min) (point-max))))
889
890 (defun haskell-guess-module-name ()
891 "Guess the current module name of the buffer."
892 (interactive)
893 (let ((components (loop for part
894 in (reverse (split-string (buffer-file-name) "/"))
895 while (let ((case-fold-search nil))
896 (string-match "^[A-Z]+" part))
897 collect (replace-regexp-in-string "\\.l?hs$" "" part))))
898 (mapconcat 'identity (reverse components) ".")))
899
900
901 ;; Provide ourselves:
902
903 (provide 'haskell-mode)
904
905 ;; Local Variables:
906 ;; byte-compile-warnings: (not cl-functions)
907 ;; End:
908
909 ;;; haskell-mode.el ends here