1 ;;; haskell-decl-scan.el --- Declaration scanning module for Haskell Mode
3 ;; Copyright (C) 2004, 2005 Free Software Foundation, Inc.
4 ;; Copyright (C) 1997-1998 Graeme E Moss
6 ;; Authors: 1997-1998 Graeme E Moss <gem@cs.york.ac.uk>
7 ;; Keywords: declarations menu files Haskell
8 ;; URL: http://cvs.haskell.org/cgi-bin/cvsweb.cgi/fptools/CONTRIB/haskell-modes/emacs/haskell-decl-scan.el?rev=HEAD
10 ;; This file is not part of GNU Emacs.
12 ;; This file is free software; you can redistribute it and/or modify
13 ;; it under the terms of the GNU General Public License as published by
14 ;; the Free Software Foundation; either version 2, or (at your option)
17 ;; This file is distributed in the hope that it will be useful,
18 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
19 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 ;; GNU General Public License for more details.
22 ;; You should have received a copy of the GNU General Public License
23 ;; along with GNU Emacs; see the file COPYING. If not, write to the
24 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
25 ;; Boston, MA 02111-1307, USA.
32 ;; Top-level declarations are scanned and placed in a menu. Supports
33 ;; full Latin1 Haskell 1.4 as well as literate scripts.
38 ;; To turn declaration scanning on for all Haskell buffers under the
39 ;; Haskell mode of Moss&Thorn, add this to .emacs:
41 ;; (add-hook haskell-mode-hook 'turn-on-haskell-decl-scan)
43 ;; Otherwise, call `turn-on-haskell-decl-scan'.
48 ;; None available so far.
53 ;; If you have any problems or suggestions, after consulting the list
54 ;; below, email gem@cs.york.ac.uk quoting the version of the library
55 ;; you are using, the version of Emacs you are using, and a small
56 ;; example of the problem or suggestion. Note that this library
57 ;; requires a reasonably recent version of Emacs.
59 ;; Uses `imenu' under Emacs, and `func-menu' under XEmacs.
62 ;; Added support for LaTeX-style literate scripts.
65 ;; Use own syntax table. Fixed bug for very small buffers. Use
66 ;; markers instead of pointers (markers move with the text).
69 ;; Brought over from Haskell mode v1.1.
72 ;; Present Limitations/Future Work (contributions are most welcome!):
74 ;; . Unicode is still a mystery... has anyone used it yet? We still
75 ;; support Latin-ISO-8859-1 though (the character set of Haskell 1.3).
77 ;; . Declarations requiring information extending beyond starting line
78 ;; don't get scanned properly, eg.
82 ;; . Comments placed in the midst of the first few lexemes of a
83 ;; declaration will cause havoc, eg.
84 ;; > infixWithComments :: Int -> Int -> Int
85 ;; > x {-nastyComment-} `infixWithComments` y = x + y
86 ;; but are not worth worrying about.
88 ;; . Would be nice to scan other top-level declarations such as
89 ;; methods of a class, datatype field labels... any more?
91 ;; . Support for GreenCard?
93 ;; . Re-running (literate-)haskell-imenu should not cause the problems
94 ;; that it does. The ability to turn off scanning would also be
95 ;; useful. (Note that re-running (literate-)haskell-mode seems to
96 ;; cause no problems.)
98 ;; . Inconsistency: we define the start of a declaration in `imenu' as
99 ;; the start of the line the declaration starts on, but in
100 ;; `func-menu' as the start of the name that the declaration is
101 ;; given (eg. "class Eq a => Ord a ..." starts at "class" in `imenu'
102 ;; but at "Ord" in `func-menu'). This avoids rescanning of the
103 ;; buffer by the goto functions of `func-menu' but allows `imenu' to
104 ;; have the better definition of the start of the declaration (IMO).
106 ;; . `func-menu' cannot cope well with spaces in declaration names.
107 ;; This is unavoidable in "instance Eq Int" (changing the spaces to
108 ;; underscores would cause rescans of the buffer). Note though that
109 ;; `fume-prompt-function-goto' (usually bound to "C-c g") does cope
112 ;; . Would like to extend the goto functions given by `func-menu'
113 ;; under XEmacs to Emacs. Would have to implement these
114 ;; ourselves as `imenu' does not provide them.
116 ;; . `func-menu' uses its own syntax table when grabbing a declaration
117 ;; name to lookup (why doesn't it use the syntax table of the
118 ;; buffer?) so some declaration names will not be grabbed correctly,
119 ;; eg. "fib'" will be grabbed as "fib" since "'" is not a word or
120 ;; symbol constituent under the syntax table `func-menu' uses.
122 ;; All functions/variables start with
123 ;; `(turn-(on/off)-)haskell-decl-scan' or `haskell-ds-'.
125 ;; The imenu support is based on code taken from `hugs-mode',
126 ;; thanks go to Chris Van Humbeeck.
132 (require 'haskell-mode)
134 (defconst haskell-decl-scan-version "1.9"
135 "Version number of haskell-decl-scan.")
136 (defun haskell-decl-scan-version ()
137 "Echo the current version of haskell-decl-scan in the minibuffer."
139 (message "Using haskell-decl-scan version %s" haskell-decl-scan-version))
142 ;; As `cl' defines macros that `imenu' uses, we must require them at
150 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
151 ;; General declaration scanning functions.
153 (defalias 'haskell-ds-match-string
154 (if (fboundp 'match-string-no-properties)
155 'match-string-no-properties
157 "As `match-string' except that the string is stripped of properties."
158 (format "%s" (match-string num)))))
160 (defvar haskell-ds-start-keywords-re
162 "class\\|data\\|i\\(mport\\|n\\(fix\\(\\|[lr]\\)\\|stance\\)\\)\\|"
163 "module\\|primitive\\|type\\|newtype"
165 "Keywords that may start a declaration.")
167 (defvar haskell-ds-syntax-table
168 (let ((table (copy-syntax-table haskell-mode-syntax-table)))
169 (modify-syntax-entry ?\' "w" table)
170 (modify-syntax-entry ?_ "w" table)
171 (modify-syntax-entry ?\\ "_" table)
173 "Syntax table used for Haskell declaration scanning.")
176 (defun haskell-ds-get-variable (prefix)
177 "Assuming point is looking at the regexp PREFIX followed by the
178 start of a declaration (perhaps in the middle of a series of
179 declarations concerning a single variable), if this declaration is a
180 value binding or type signature, return the variable involved, and
181 otherwise returns nil. Point is not moved in either case."
182 ;; I think I can now handle all declarations bar those with comments
183 ;; nested before the second lexeme.
184 (let ((orig-table (syntax-table))
188 (set-syntax-table haskell-ds-syntax-table)
189 (re-search-forward (concat "\\=" prefix) (point-max) t)
191 (if (looking-at haskell-ds-start-keywords-re)
193 (if (looking-at "(\\(\\s_+\\))")
194 ;; Paranthesised symbolic variable.
195 (setq name (haskell-ds-match-string 1))
196 (if (if (looking-at "(")
197 ;; Skip paranthesised expression.
201 ;; Repeating this code and avoiding moving point if
202 ;; possible speeds things up.
203 (looking-at "\\(\\)\\s-*\\(\\s_+\\|`\\(\\sw+\\)`\\)"))
204 (looking-at "\\(\\sw+\\)\\s-*\\(\\s_+\\|`\\(\\sw+\\)`\\)"))
205 (let ((match2 (haskell-ds-match-string 2)))
206 ;; Weed out `::', `=' and `|' from potential infix
207 ;; symbolic variable.
208 (if (member match2 '("::" "=" "|"))
210 ;; Variable identifier.
211 (setq name (haskell-ds-match-string 1)))
212 (if (eq (aref match2 0) ?\`)
213 ;; Infix variable identifier.
214 (setq name (haskell-ds-match-string 3))
215 ;; Infix symbolic variable.
216 (setq name match2)))))
217 ;; Variable identifier.
218 (if (and (not name) (looking-at "\\sw+"))
219 (setq name (haskell-ds-match-string 0)))))
220 ;; Return the result.
222 (set-syntax-table orig-table)
225 (defun haskell-ds-move-to-start-regexp (inc regexp)
226 "Move to beginning of line that succeeds/preceeds (INC = 1/-1)
227 current line that starts with REGEXP and is not in `font-lock-comment-face'."
228 ;; Making this defsubst instead of defun appears to have little or
229 ;; no effect on efficiency. It is probably not called enough to do
231 (while (and (= (forward-line inc) 0)
232 (or (not (looking-at regexp))
233 (eq (get-text-property (point) 'face)
234 'font-lock-comment-face)))))
236 (defvar literate-haskell-ds-line-prefix "> "
237 "The regexp that matches the start of a line of Bird-style literate
238 code for the purposes of `imenu' support. Current value is \"> \" as we
239 assume top-level declarations start at column 3. Must not contain the
240 special \"^\" regexp as we may not use the regexp at the start of a
241 regexp string. Note this is only for `imenu' support.")
243 (defvar haskell-ds-start-decl-re "\\(\\sw\\|(\\)"
244 "The regexp that starts a Haskell declaration.")
246 (defvar literate-haskell-ds-start-decl-re
247 (concat literate-haskell-ds-line-prefix haskell-ds-start-decl-re)
248 "The regexp that starts a Bird-style literate Haskell declaration.")
250 (defun haskell-ds-move-to-decl (direction bird-literate fix)
251 "General function for moving to the start of a declaration, either
252 forwards or backwards from point, with normal or with Bird-style
253 literate scripts. If DIRECTION is t, then forward, else backward. If
254 BIRD-LITERATE is t, then treat as Bird-style literate scripts, else
255 normal scripts. Returns point if point is left at the start of a
256 declaration, and nil otherwise, ie. because point is at the beginning
257 or end of the buffer and no declaration starts there. If FIX is t,
258 then point does not move if already at the start of a declaration."
259 ;; As `haskell-ds-get-variable' cannot separate an infix variable
260 ;; identifier out of a value binding with non-alphanumeric first
261 ;; argument, this function will treat such value bindings as
262 ;; separate from the declarations surrounding it.
263 (let (;; The variable typed or bound in the current series of
266 ;; The variable typed or bound in the new declaration.
268 ;; Hack to solve hard problem for Bird-style literate scripts
269 ;; that start with a declaration. We are in the abyss if
270 ;; point is before start of this declaration.
272 (line-prefix (if bird-literate literate-haskell-ds-line-prefix ""))
273 ;; The regexp to match for the start of a declaration.
274 (start-decl-re (if bird-literate
275 literate-haskell-ds-start-decl-re
276 haskell-ds-start-decl-re))
277 (increment (if direction 1 -1))
278 (bound (if direction (point-max) (point-min)))
279 ;; Original syntax table.
280 (orig-table (syntax-table))
282 ;; Change syntax table.
283 (set-syntax-table haskell-ds-syntax-table)
284 ;; Move to beginning of line that starts the "current
285 ;; declaration" (dependent on DIRECTION and FIX), and then get
286 ;; the variable typed or bound by this declaration, if any.
287 (let (;; Where point was at call of function.
289 ;; Where the declaration on this line (if any) starts.
292 ;; Checking the face to ensure a declaration starts
293 ;; here seems to be the only addition to make this
294 ;; module support LaTeX-style literate scripts.
295 (if (and (looking-at start-decl-re)
296 (not (eq (get-text-property (point) 'face)
297 'font-lock-comment-face)))
298 (match-beginning 1)))))
300 ;; This complicated boolean determines whether we
301 ;; should include the declaration that starts on the
302 ;; current line as the "current declaration" or not.
303 (or (and (or (and direction (not fix))
304 (and (not direction) fix))
306 (and (or (and direction fix)
307 (and (not direction) (not fix)))
309 ;; If so, we are already at start of the current line, so
312 ;; If point was before start of a declaration on the first
313 ;; line of the buffer (possible for Bird-style literate
314 ;; scripts) then we are in the abyss.
315 (if (and start (bobp))
317 ;; Otherwise we move to the start of the first declaration
318 ;; on a line preceeding the current one.
319 (haskell-ds-move-to-start-regexp -1 start-decl-re))))
320 ;; If we are in the abyss, position and return as appropriate.
324 (re-search-forward (concat "\\=" line-prefix) (point-max) t)
325 (setq result (point)))
326 ;; Get the variable typed or bound by this declaration, if any.
327 (setq name (haskell-ds-get-variable line-prefix))
329 ;; If no such variable, stop at the start of this
330 ;; declaration if moving backward, or move to the next
331 ;; declaration if moving forward.
333 (haskell-ds-move-to-start-regexp 1 start-decl-re))
334 ;; If there is a variable, find the first
335 ;; succeeding/preceeding declaration that does not type or
336 ;; bind it. Check for reaching start/end of buffer.
337 (haskell-ds-move-to-start-regexp increment start-decl-re)
338 (while (and (/= (point) bound)
339 (and (setq newname (haskell-ds-get-variable line-prefix))
340 (string= name newname)))
342 (haskell-ds-move-to-start-regexp increment start-decl-re))
343 ;; If we are going backward, and have either reached a new
344 ;; declaration or the beginning of a buffer that does not
345 ;; start with a declaration, move forward to start of next
346 ;; declaration (which must exist). Otherwise, we are done.
347 (if (and (not direction)
348 (or (and (looking-at start-decl-re)
350 ;; Note we must not use
351 ;; newname here as this may
352 ;; not have been set if we
353 ;; have reached the beginning
355 (haskell-ds-get-variable
357 (and (not (looking-at start-decl-re))
359 (haskell-ds-move-to-start-regexp 1 start-decl-re)))
360 ;; Store whether we are at the start of a declaration or not.
361 ;; Used to calculate final result.
362 (let ((at-start-decl (looking-at start-decl-re)))
363 ;; If we are at the beginning of a line, move over
364 ;; line-prefix, if present at point.
366 (re-search-forward (concat "\\=" line-prefix) (point-max) t))
367 ;; Return point if at the start of a declaration and nil
369 (setq result (if at-start-decl (point) nil))))
370 ;; Replace original syntax table.
371 (set-syntax-table orig-table)
372 ;; Return the result.
375 (defun haskell-ds-bird-p ()
376 (if (boundp 'haskell-literate)
377 (eq haskell-literate 'bird) nil))
379 (defun haskell-ds-backward-decl ()
380 "Move point backward to the first character preceeding the current
381 point that starts a top-level declaration. A series of declarations
382 concerning one variable is treated as one declaration by this
383 function. So, if point is within a top-level declaration then move it
384 to the start of that declaration. If point is already at the start of
385 a top-level declaration, then move it to the start of the preceeding
386 declaration. Returns point if point is left at the start of a
387 declaration, and nil otherwise, ie. because point is at the beginning
388 of the buffer and no declaration starts there."
390 (haskell-ds-move-to-decl nil (haskell-ds-bird-p) nil))
392 (defun haskell-ds-forward-decl ()
393 "As `haskell-ds-backward-decl' but forward."
395 (haskell-ds-move-to-decl t (haskell-ds-bird-p) nil))
397 (defun haskell-ds-generic-find-next-decl (bird-literate)
398 "Find the name, position and type of the declaration at or after
399 point. Returns `((name . (start-position . name-position)) . type)'
400 if one exists and nil otherwise. The start-position is at the start
401 of the declaration, and the name-position is at the start of the name
402 of the declaration. The name is a string, the positions are buffer
403 positions and the type is one of the symbols \"variable\", \"datatype\",
404 \"class\", \"import\" and \"instance\"."
405 (let (;; The name, type and name-position of the declaration to
410 ;; Buffer positions marking the start and end of the space
411 ;; containing a declaration.
414 ;; Original syntax table.
415 (orig-table (syntax-table)))
416 ;; Change to declaration scanning syntax.
417 (set-syntax-table haskell-ds-syntax-table)
418 ;; Stop when we are at the end of the buffer or when a valid
419 ;; declaration is grabbed.
420 (while (not (or (eobp) name))
421 ;; Move forward to next declaration at or after point.
422 (haskell-ds-move-to-decl t bird-literate t)
423 ;; Start and end of search space is currently just the starting
424 ;; line of the declaration.
426 end (progn (end-of-line) (point)))
429 ;; If the start of the top-level declaration does not begin
430 ;; with a starting keyword, then (if legal) must be a type
431 ;; signature or value binding, and the variable concerned is
433 ((not (looking-at haskell-ds-start-keywords-re))
434 (setq name (haskell-ds-get-variable ""))
437 (setq type 'variable)
438 (re-search-forward (regexp-quote name) end t)
439 (setq name-pos (match-beginning 0)))))
440 ;; User-defined datatype declaration.
441 ((re-search-forward "\\=\\(data\\|newtype\\|type\\)\\>" end t)
442 (re-search-forward "=>" end t)
443 (if (looking-at "[ \t]*\\(\\sw+\\)")
445 (setq name (haskell-ds-match-string 1))
446 (setq name-pos (match-beginning 1))
447 (setq type 'datatype))))
448 ;; Class declaration.
449 ((re-search-forward "\\=class\\>" end t)
450 (re-search-forward "=>" end t)
451 (if (looking-at "[ \t]*\\(\\sw+\\)")
453 (setq name (haskell-ds-match-string 1))
454 (setq name-pos (match-beginning 1))
455 (setq type 'class))))
456 ;; Import declaration.
457 ((looking-at "import[ \t]+\\(qualified[ \t]+\\)?\\(\\sw+\\)")
458 (setq name (haskell-ds-match-string 2))
459 (setq name-pos (match-beginning 2))
461 ;; Instance declaration.
462 ((re-search-forward "\\=instance[ \t]+" end t)
463 (re-search-forward "=>[ \t]+" end t)
464 ;; The instance "title" starts just after the `instance' (and
465 ;; any context) and finishes just before the _first_ `where'
466 ;; if one exists. This solution is ugly, but I can't find a
467 ;; nicer one---a simple regexp will pick up the last `where',
468 ;; which may be rare but nevertheless...
469 (setq name-pos (point))
470 (setq name (format "%s"
474 ;; Look for a `where'.
475 (if (re-search-forward "\\<where\\>" end t)
476 ;; Move back to just before the `where'.
478 (re-search-backward "\\s-where")
480 ;; No `where' so move to last non-whitespace
484 (skip-chars-backward " \t")
486 ;; If we did not manage to extract a name, cancel this
487 ;; declaration (eg. when line ends in "=> ").
488 (if (string-match "^[ \t]*$" name) (setq name nil))
489 (setq type 'instance)))
490 ;; Move past start of current declaration.
492 ;; Replace syntax table.
493 (set-syntax-table orig-table)
494 ;; If we have a valid declaration then return it, otherwise return
497 (cons (cons name (cons (copy-marker start t) (copy-marker name-pos t)))
501 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
502 ;; Declaration scanning via `imenu'.
504 (defun haskell-ds-create-imenu-index ()
505 "Function for finding `imenu' declarations in Haskell mode.
506 Finds all declarations (classes, variables, imports, instances and
507 datatypes) in a Haskell file for the `imenu' package."
508 ;; Each list has elements of the form `(INDEX-NAME . INDEX-POSITION)'.
509 ;; These lists are nested using `(INDEX-TITLE . INDEX-ALIST)'.
510 (let* ((bird-literate (haskell-ds-bird-p))
512 (index-class-alist '()) ;; Classes
513 (index-var-alist '()) ;; Variables
514 (index-imp-alist '()) ;; Imports
515 (index-inst-alist '()) ;; Instances
516 (index-type-alist '()) ;; Datatypes
517 ;; Variables for showing progress.
518 (bufname (buffer-name))
519 (divisor-of-progress (max 1 (/ (point-max) 100)))
520 ;; The result we wish to return.
522 (goto-char (point-min))
523 ;; Loop forwards from the beginning of the buffer through the
524 ;; starts of the top-level declarations.
525 (while (< (point) (point-max))
526 (message "Scanning declarations in %s... (%3d%%)" bufname
527 (/ (point) divisor-of-progress))
528 ;; Grab the next declaration.
529 (setq result (haskell-ds-generic-find-next-decl bird-literate))
531 ;; If valid, extract the components of the result.
532 (let* ((name-posns (car result))
533 (name (car name-posns))
534 (posns (cdr name-posns))
535 (start-pos (car posns))
537 ;; Place `(name . start-pos)' in the correct alist.
539 ((eq type 'variable) 'index-var-alist)
540 ((eq type 'datatype) 'index-type-alist)
541 ((eq type 'class) 'index-class-alist)
542 ((eq type 'import) 'index-imp-alist)
543 ((eq type 'instance) 'index-inst-alist))))
544 (set alist (cons (cons name start-pos) (eval alist))))))
545 ;; Now sort all the lists, label them, and place them in one list.
546 (message "Sorting declarations in %s..." bufname)
547 (and index-type-alist
548 (push (cons "Datatypes"
549 (sort index-type-alist 'haskell-ds-imenu-label-cmp))
551 (and index-inst-alist
552 (push (cons "Instances"
553 (sort index-inst-alist 'haskell-ds-imenu-label-cmp))
556 (push (cons "Imports"
557 (sort index-imp-alist 'haskell-ds-imenu-label-cmp))
560 (push (cons "Variables"
561 (sort index-var-alist 'haskell-ds-imenu-label-cmp))
563 (and index-class-alist
564 (push (cons "Classes"
565 (sort index-class-alist 'haskell-ds-imenu-label-cmp))
567 (message "Sorting declarations in %s...done" bufname)
571 (defun haskell-ds-imenu-label-cmp (el1 el2)
572 "Predicate to compare labels in lists produced by
573 `haskell-ds-create-imenu-index'."
574 (string< (car el1) (car el2)))
576 (defun haskell-ds-imenu ()
577 "Install `imenu' for Haskell scripts."
578 (setq imenu-create-index-function 'haskell-ds-create-imenu-index)
579 (if (fboundp 'imenu-add-to-menubar)
580 (imenu-add-to-menubar "Declarations")))
582 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
583 ;; Declaration scanning via `func-menu'.
585 (defun haskell-ds-func-menu-next (buffer)
586 "Non-literate Haskell version of `haskell-ds-generic-func-menu-next'."
587 (haskell-ds-generic-func-menu-next (haskell-ds-bird-p) buffer))
589 (defun haskell-ds-generic-func-menu-next (bird-literate buffer)
590 "Return `(name . pos)' of next declaration."
592 (let ((result (haskell-ds-generic-find-next-decl bird-literate)))
594 (let* ((name-posns (car result))
595 (name (car name-posns))
596 (posns (cdr name-posns))
597 (name-pos (cdr posns))
598 ;;(type (cdr result))
601 ;; func-menu has problems with spaces, and adding a
602 ;; qualifying keyword will not allow the "goto fn"
603 ;; functions to work properly. Sigh.
605 ;; ((eq type 'variable) "")
606 ;; ((eq type 'datatype) "datatype ")
607 ;; ((eq type 'class) "class ")
608 ;; ((eq type 'import) "import ")
609 ;; ((eq type 'instance) "instance "))
614 (defvar haskell-ds-func-menu-regexp
615 (concat "^" haskell-ds-start-decl-re)
616 "Regexp to match the start of a possible declaration.")
618 (defvar literate-haskell-ds-func-menu-regexp
619 (concat "^" literate-haskell-ds-start-decl-re)
620 "As `haskell-ds-func-menu-regexp' but for Bird-style literate scripts.")
622 (defun haskell-ds-func-menu ()
623 "Use `func-menu' to establish declaration scanning for Haskell scripts."
625 (set (make-local-variable 'fume-menubar-menu-name) "Declarations")
626 (set (make-local-variable 'fume-function-name-regexp-alist)
627 (if (haskell-ds-bird-p)
628 '((haskell-mode . literate-haskell-ds-func-menu-regexp))
629 '((haskell-mode . haskell-ds-func-menu-regexp))))
630 (set (make-local-variable 'fume-find-function-name-method-alist)
631 '((haskell-mode . haskell-ds-func-menu-next)))
632 (fume-add-menubar-entry)
633 (local-set-key "\C-cl" 'fume-list-functions)
634 (local-set-key "\C-cg" 'fume-prompt-function-goto)
635 (local-set-key [(meta button1)] 'fume-mouse-function-goto))
638 (defun haskell-ds-keys ()
639 "Map the keys for forward and backward declaration movement."
640 (local-set-key "\M-\C-e" 'haskell-ds-forward-decl)
641 (local-set-key "\M-\C-a" 'haskell-ds-backward-decl))
643 ;; The main functions to turn on declaration scanning.
644 (defun turn-on-haskell-decl-scan ()
645 "Turn on declaration scanning for Haskell mode. Top-level
646 declarations are scanned and listed in the menu item \"Declarations\".
647 Selecting an item from this menu will take point to the start of the
650 \\[haskell-ds-forward-decl] and \\[haskell-ds-backward-decl] move forward and backward to the start of a declaration.
652 Under XEmacs, the following keys are also defined:
654 \\[fume-list-functions] lists the declarations of the current buffer,
655 \\[fume-prompt-function-goto] prompts for a declaration to move to, and
656 \\[fume-mouse-function-goto] moves to the declaration whose name is at point.
658 This may link with `haskell-doc' (only for Emacs currently).
660 For non-literate and LaTeX-style literate scripts, we assume the
661 common convention that top-level declarations start at the first
662 column. For Bird-style literate scripts, we assume the common
663 convention that top-level declarations start at the third column,
666 Anything in `font-lock-comment-face' is not considered for a
667 declaration. Therefore, using Haskell font locking with comments
668 coloured in `font-lock-comment-face' improves declaration scanning.
670 To turn on declaration scanning for all Haskell buffers, add this to
673 (add-hook 'haskell-mode-hook 'turn-on-haskell-decl-scan)
675 To turn declaration scanning on for the current buffer, call
676 `turn-on-haskell-decl-scan'.
678 Literate Haskell scripts are supported: If the value of
679 `haskell-literate' (automatically set by the Haskell mode of
680 Moss&Thorn) is 'bird, a Bird-style literate script is assumed. If it
681 is nil or 'latex, a non-literate or LaTeX-style literate script is
682 assumed, respectively.
684 Invokes `haskell-decl-scan-hook' if not nil.
686 Use `haskell-decl-scan-version' to find out what version this is."
691 (haskell-ds-func-menu))
692 (run-hooks 'haskell-decl-scan-hook))
694 ;; Provide ourselves:
696 (provide 'haskell-decl-scan)
698 ;;; haskell-decl-scan.el ends here