Anonymous avatar Anonymous committed 95b2a2c

XEmacs package created.

Comments (0)

Files changed (16)

+(setq load-path (cons "~/lib/emacs" load-path))
+(setq auto-mode-alist
+      (append auto-mode-alist
+              '(("\\.[hg]s$"  . haskell-mode)
+                ("\\.hi$"     . haskell-mode)
+                ("\\.l[hg]s$" . literate-haskell-mode))))
+(autoload 'haskell-mode "haskell-mode"
+   "Major mode for editing Haskell scripts." t)
+(autoload 'literate-haskell-mode "haskell-mode"
+   "Major mode for editing literate Haskell scripts." t)
+(add-hook 'haskell-mode-hook 'turn-on-haskell-font-lock)
+(add-hook 'haskell-mode-hook 'turn-on-haskell-decl-scan)
+(add-hook 'haskell-mode-hook 'turn-on-haskell-doc-mode)
+(add-hook 'haskell-mode-hook 'turn-on-haskell-indent)
+;(add-hook 'haskell-mode-hook 'turn-on-haskell-simple-indent)
+(add-hook 'haskell-mode-hook 'turn-on-haskell-hugs)
+2002-04-23  Ville Skytt�  <ville.skytta@xemacs.org>
+
+	* XEmacs package created.
+# Makefile for haskell-mode lisp code
+
+# This file is part of XEmacs.
+
+# XEmacs is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2, or (at your option) any
+# later version.
+
+# XEmacs is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with XEmacs; see the file COPYING.  If not, write to
+# the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+
+VERSION = 1.00
+AUTHOR_VERSION = 1.42
+MAINTAINER = XEmacs Development Team <xemacs-beta@xemacs.org>
+PACKAGE = haskell-mode
+PKG_TYPE = regular
+REQUIRES = dired mail-lib xemacs-base
+CATEGORY = standard
+
+ELCS = haskell-decl-scan.elc haskell-doc.elc haskell-font-lock.elc \
+	haskell-ghci.elc haskell-hugs.elc haskell-indent.elc haskell-mode.elc \
+	haskell-simple-indent.elc
+
+HTML_FILES = index.html installation-guide.html
+HTML_DEP = index.html installation-guide.html
+
+DATA_FILES = fontlock.hs indent.hs
+DATA_DEST = $(PACKAGE)
+
+PRELOADS = -l comint -l cus-face -l font-lock -l func-menu -l imenu \
+	-l ./haskell-mode.el -l ./haskell-indent.el
+
+include ../../XEmacs.rules
+
+GENERATED += custom-load.elc
+
+all:: $(ELCS) auto-autoloads.elc custom-load.elc
+
+srckit: srckit-std
+
+binkit: binkit-common
+-- Comments are coloured brightly and stand out clearly.
+
+repeat :: a -> [a]
+repeat xs = xs where xs = x:xs          -- Keywords are also bright.
+
+head :: [a] -> a
+head (x:_) = x
+head [] = error "PreludeList.head: empty list" -- Strings are coloured softly.
+
+data Maybe a = Nothing | Just a              -- Type constructors, data
+             deriving (Eq, Ord, Read, Show)  -- constructors, class names
+                                             -- and module names are coloured
+                                             -- closer to ordinary code.
+
+{-
+map :: (a -> b) -> [a] -> [b]           -- Commenting out large sections of
+map f []     = []                       -- code can be misleading.  Coloured
+map f (x:xs) = f x : map f xs           -- comments reveal unused definitions.
+-}

haskell-decl-scan.el

+;;; haskell-decl-scan.el --- Declaration scanning module for Haskell Mode
+
+;; Copyright (C) 1997-1998 Graeme E Moss
+
+;; Authors: 1997-1998 Graeme E Moss <gem@cs.york.ac.uk>
+;; Keywords: declarations menu files Haskell
+;; Version: 1.2
+;; URL: http://www.cs.york.ac.uk/~gem/haskell-mode/decl-scan.html
+
+;;; This file is not part of GNU Emacs.
+
+;; This file is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 2, or (at your option)
+;; any later version.
+
+;; This file is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs; see the file COPYING.  If not, write to the
+;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+
+
+;;; Commentary:
+
+;; Purpose:
+;;
+;; Top-level declarations are scanned and placed in a menu.  Supports
+;; full Latin1 Haskell 1.4 as well as literate scripts.
+;;
+;;
+;; Installation:
+;; 
+;; To turn declaration scanning on for all Haskell buffers under the
+;; Haskell mode of Moss&Thorn, add this to .emacs:
+;;
+;;    (add-hook haskell-mode-hook 'turn-on-haskell-decl-scan)
+;;
+;; Otherwise, call `turn-on-haskell-decl-scan'.
+;;
+;;
+;; Customisation:
+;;
+;; None available so far.
+;;
+;;
+;; History:
+;;
+;; If you have any problems or suggestions, after consulting the list
+;; below, email gem@cs.york.ac.uk quoting the version of the library
+;; you are using, the version of emacs you are using, and a small
+;; example of the problem or suggestion.  Note that this library
+;; requires a reasonably recent version of Emacs.
+;;
+;; Uses `imenu' under FSF Emacs, and `func-menu' under XEmacs.
+;;
+;; Version 1.2:
+;;   Added support for LaTeX-style literate scripts.
+;;
+;; Version 1.1:
+;;   Use own syntax table.  Fixed bug for very small buffers.  Use
+;;   markers instead of pointers (markers move with the text).
+;;
+;; Version 1.0:
+;;   Brought over from Haskell mode v1.1.
+;;
+;;
+;; Present Limitations/Future Work (contributions are most welcome!):
+;;
+;; . Unicode is still a mystery...  has anyone used it yet?  We still
+;;   support Latin-ISO-8859-1 though (the character set of Haskell 1.3).
+;;
+;; . Declarations requiring information extending beyond starting line
+;;   don't get scanned properly, eg.
+;;   > class Eq a =>
+;;   >       Test a
+;;
+;; . Comments placed in the midst of the first few lexemes of a
+;;   declaration will cause havoc, eg.
+;;   > infixWithComments :: Int -> Int -> Int
+;;   > x {-nastyComment-} `infixWithComments` y = x + y
+;;   but are not worth worrying about.
+;;
+;; . Would be nice to scan other top-level declarations such as
+;;   methods of a class, datatype field labels...  any more?
+;;
+;; . Support for Green Card?
+;;
+;; . Re-running (literate-)haskell-imenu should not cause the problems
+;;   that it does.  The ability to turn off scanning would also be
+;;   useful.  (Note that re-running (literate-)haskell-mode seems to
+;;   cause no problems.)
+;;
+;; . Inconsistency: we define the start of a declaration in `imenu' as
+;;   the start of the line the declaration starts on, but in
+;;   `func-menu' as the start of the name that the declaration is
+;;   given (eg. "class Eq a => Ord a ..." starts at "class" in `imenu'
+;;   but at "Ord" in `func-menu').  This avoids rescanning of the
+;;   buffer by the goto functions of `func-menu' but allows `imenu' to
+;;   have the better definition of the start of the declaration (IMO).
+;;
+;; . `func-menu' cannot cope well with spaces in declaration names.
+;;   This is unavoidable in "instance Eq Int" (changing the spaces to
+;;   underscores would cause rescans of the buffer).  Note though that
+;;   `fume-prompt-function-goto' (usually bound to "C-c g") does cope
+;;   with spaces okay.
+;;
+;; . Would like to extend the goto functions given by `func-menu'
+;;   under XEmacs to FSF Emacs.  Would have to implement these
+;;   ourselves as `imenu' does not provide them.
+;;
+;; . `func-menu' uses its own syntax table when grabbing a declaration
+;;   name to lookup (why doesn't it use the syntax table of the
+;;   buffer?) so some declaration names will not be grabbed correctly,
+;;   eg. "fib'" will be grabbed as "fib" since "'" is not a word or
+;;   symbol constituent under the syntax table `func-menu' uses.
+
+;;; All functions/variables start with
+;;; `(turn-(on/off)-)haskell-decl-scan' or `haskell-ds-'.
+
+;;; The imenu support is based on code taken from `hugs-mode',
+;;; thanks go to Chris Van Humbeeck.
+
+;; Version.
+(defconst haskell-decl-scan-version "1.1"
+  "haskell-decl-scan version number.")
+(defun haskell-decl-scan-version ()
+  "Echo the current version of haskell-decl-scan in the minibuffer."
+  (interactive)
+  (message "Using haskell-decl-scan version %s" haskell-decl-scan-version))
+
+;;###autoload
+;; As `cl' defines macros that `imenu' uses, we must require them at
+;; compile time.
+(eval-when-compile
+  ;; `imenu' isn't used in XEmacs.
+  (if (not (string-match "Lucid\\|XEmacs" emacs-version))
+      (progn
+	(require 'cl)
+	(require 'imenu))))
+
+;; Are we running FSF Emacs or XEmacs?
+(defvar haskell-ds-running-xemacs
+  (string-match "Lucid\\|XEmacs" emacs-version)
+  "non-nil if we are running XEmacs, nil otherwise.")
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; General declaration scanning functions.
+
+(defun haskell-ds-match-string (num)
+  "As `match-string' except that the string is stripped of properties."
+  (format "%s" (match-string num)))
+
+(defvar haskell-ds-start-keywords-re
+  (concat "\\(\\<"
+	  "class\\|data\\|i\\(mport\\|n\\(fix\\(\\|[lr]\\)\\|stance\\)\\)\\|"
+	  "module\\|primitive\\|type\\|newtype"
+	  "\\)\\>")
+  "Keywords that may start a declaration.")
+
+(defvar haskell-ds-syntax-table nil
+  "Syntax table used for Haskell declaration scanning.")
+
+(if (not haskell-ds-syntax-table)
+    (progn
+      (setq haskell-ds-syntax-table (make-syntax-table))
+  (modify-syntax-entry ?\  " " haskell-ds-syntax-table)
+  (modify-syntax-entry ?\t " " haskell-ds-syntax-table)
+  (modify-syntax-entry ?\" "\"" haskell-ds-syntax-table)
+  (modify-syntax-entry ?\' "w" haskell-ds-syntax-table)
+  (modify-syntax-entry ?_  "w" haskell-ds-syntax-table)
+  (modify-syntax-entry ?\( "()" haskell-ds-syntax-table)
+  (modify-syntax-entry ?\) ")(" haskell-ds-syntax-table)
+  (modify-syntax-entry ?[  "(]" haskell-ds-syntax-table)
+  (modify-syntax-entry ?]  ")[" haskell-ds-syntax-table)
+  (modify-syntax-entry ?{  "(}1" haskell-ds-syntax-table)
+  (modify-syntax-entry ?}  "){4" haskell-ds-syntax-table)
+  (modify-syntax-entry ?-  "_ 23" haskell-ds-syntax-table)
+  (modify-syntax-entry ?\` "$`" haskell-ds-syntax-table)
+  (mapcar (lambda (x)
+            (modify-syntax-entry x "_" haskell-ds-syntax-table))
+          (concat "!#$%&*+./:<=>?@\\^|~"
+                  (haskell-enum-from-to ?\241 ?\277)
+                  "\327\367"))
+  (mapcar (lambda (x)
+            (modify-syntax-entry x "w" haskell-ds-syntax-table))
+          (concat (haskell-enum-from-to ?\300 ?\326)
+                  (haskell-enum-from-to ?\330 ?\337)
+                  (haskell-enum-from-to ?\340 ?\366)
+                  (haskell-enum-from-to ?\370 ?\377)))))
+
+(defun haskell-ds-get-variable (prefix)
+  "Assuming point is looking at the regexp PREFIX followed by the
+start of a declaration (perhaps in the middle of a series of
+declarations concerning a single variable), if this declaration is a
+value binding or type signature, return the variable involved, and
+otherwise returns nil.  Point is not moved in either case."
+  ;; I think I can now handle all declarations bar those with comments
+  ;; nested before the second lexeme.
+  (let ((orig-table (syntax-table))
+	(start (point))
+	par-start
+	name)
+    (set-syntax-table haskell-ds-syntax-table)
+    (re-search-forward (concat "\\=" prefix) (point-max) t)
+    ;; Keyword.
+    (if (looking-at haskell-ds-start-keywords-re)
+	()
+      (if (looking-at "(\\(\\s_+\\))")
+	  ;; Paranthesised symbolic variable.
+	  (setq name (haskell-ds-match-string 1))
+	(if (if (looking-at "(")
+		;; Skip paranthesised expression.
+		(progn
+		  (setq par-start t)
+		  (forward-sexp)
+		  ;; Repeating this code and avoiding moving point if
+		  ;; possible speeds things up.
+		  (looking-at "\\(\\)\\s-*\\(\\s_+\\|`\\(\\sw+\\)`\\)"))
+	      (looking-at "\\(\\sw+\\)\\s-*\\(\\s_+\\|`\\(\\sw+\\)`\\)"))
+	    (let ((match2 (haskell-ds-match-string 2)))
+	      ;; Weed out `::', `=' and `|' from potential infix
+	      ;; symbolic variable.
+	      (if (member match2 '("::" "=" "|"))
+		  (if (not par-start)
+		      ;; Variable identifier.
+		      (setq name (haskell-ds-match-string 1)))
+		(if (eq (aref match2 0) ?\`)
+		    ;; Infix variable identifier.
+		    (setq name (haskell-ds-match-string 3))
+		  ;; Infix symbolic variable.
+		  (setq name match2)))))
+	;; Variable identifier.
+	(if (and (not name) (looking-at "\\sw+"))
+	    (setq name (haskell-ds-match-string 0)))))
+    ;; Return the result.
+    (goto-char start)
+    (set-syntax-table orig-table)
+    name))
+
+(defun haskell-ds-move-to-start-regexp (inc regexp)
+  "Move to beginning of line that succeeds/preceeds (INC = 1/-1)
+current line that starts with REGEXP and is not in `font-lock-comment-face'."
+  ;; Making this defsubst instead of defun appears to have little or
+  ;; no effect on efficiency.  It is probably not called enough to do
+  ;; so.
+  (while (and (= (forward-line inc) 0)
+	      (or (not (looking-at regexp))
+		  (eq (get-text-property (point) 'face)
+		      'font-lock-comment-face)))))
+
+(defvar literate-haskell-ds-line-prefix "> "
+  "The regexp that matches the start of a line of Bird-style literate
+code for the purposes of `imenu' support.  Current value is \"> \" as we
+assume top-level declarations start at column 3.  Must not contain the
+special \"^\" regexp as we may not use the regexp at the start of a
+regexp string.  Note this is only for `imenu' support.")
+
+(defvar haskell-ds-start-decl-re "\\(\\sw\\|(\\)"
+  "The regexp that starts a Haskell declaration.")
+
+(defvar literate-haskell-ds-start-decl-re
+  (concat literate-haskell-ds-line-prefix haskell-ds-start-decl-re)
+  "The regexp that starts a Bird-style literate Haskell declaration.")
+
+(defun haskell-ds-move-to-decl (direction bird-literate fix)
+  "General function for moving to the start of a declaration, either
+forwards or backwards from point, with normal or with Bird-style
+literate scripts.  If DIRECTION is t, then forward, else backward.  If
+BIRD-LITERATE is t, then treat as Bird-style literate scripts, else
+normal scripts.  Returns point if point is left at the start of a
+declaration, and nil otherwise, ie. because point is at the beginning
+or end of the buffer and no declaration starts there.  If FIX is t,
+then point does not move if already at the start of a declaration."
+  ;; As `haskell-ds-get-variable' cannot separate an infix variable
+  ;; identifier out of a value binding with non-alphanumeric first
+  ;; argument, this function will treat such value bindings as
+  ;; separate from the declarations surrounding it.
+  (let (;; The variable typed or bound in the current series of
+	;; declarations.
+	name
+	;; The variable typed or bound in the new declaration.
+	newname
+	;; Hack to solve hard problem for Bird-style literate scripts
+	;; that start with a declaration.  We are in the abyss if
+	;; point is before start of this declaration.
+	abyss
+	(line-prefix (if bird-literate literate-haskell-ds-line-prefix ""))
+	;; The regexp to match for the start of a declaration.
+	(start-decl-re (if bird-literate
+			   literate-haskell-ds-start-decl-re
+			 haskell-ds-start-decl-re))
+	(increment (if direction 1 -1))
+	(bound (if direction (point-max) (point-min)))
+	;; Original syntax table.
+	(orig-table (syntax-table))
+	result)
+    ;; Change syntax table.
+    (set-syntax-table haskell-ds-syntax-table)
+    ;; Move to beginning of line that starts the "current
+    ;; declaration" (dependent on DIRECTION and FIX), and then get
+    ;; the variable typed or bound by this declaration, if any.
+    (let (;; Where point was at call of function.
+	  (here (point))
+	  ;; Where the declaration on this line (if any) starts.
+	  (start (progn
+		   (beginning-of-line)
+                   ;; Checking the face to ensure a declaration starts
+                   ;; here seems to be the only addition to make this
+                   ;; module support LaTeX-style literate scripts.
+		   (if (and (looking-at start-decl-re)
+                            (not (eq (get-text-property (point) 'face)
+                                     'font-lock-comment-face)))
+		       (match-beginning 1)))))
+      (if (and start
+	       ;; This complicated boolean determines whether we
+	       ;; should include the declaration that starts on the
+	       ;; current line as the "current declaration" or not.
+	       (or (and (or (and direction (not fix))
+			    (and (not direction) fix))
+			(>= here start))
+		   (and (or (and direction fix)
+			    (and (not direction) (not fix)))
+			(> here start))))
+	  ;; If so, we are already at start of the current line, so
+	  ;; do nothing.
+	  ()
+	;; If point was before start of a declaration on the first
+	;; line of the buffer (possible for Bird-style literate
+	;; scripts) then we are in the abyss.
+	(if (and start (bobp))
+	    (setq abyss t)
+	  ;; Otherwise we move to the start of the first declaration
+	  ;; on a line preceeding the current one.
+	  (haskell-ds-move-to-start-regexp -1 start-decl-re))))
+    ;; If we are in the abyss, position and return as appropriate.
+    (if abyss
+	(if (not direction)
+	    (setq result nil)
+	  (re-search-forward (concat "\\=" line-prefix) (point-max) t)
+	  (setq result (point)))
+      ;; Get the variable typed or bound by this declaration, if any. 
+      (setq name (haskell-ds-get-variable line-prefix))
+      (if (not name)
+	  ;; If no such variable, stop at the start of this
+	  ;; declaration if moving backward, or move to the next
+	  ;; declaration if moving forward.
+	  (if direction
+	      (haskell-ds-move-to-start-regexp 1 start-decl-re))
+	;; If there is a variable, find the first
+	;; succeeding/preceeding declaration that does not type or
+	;; bind it.  Check for reaching start/end of buffer.
+	(haskell-ds-move-to-start-regexp increment start-decl-re)
+	(while (and (/= (point) bound)
+		    (and (setq newname (haskell-ds-get-variable line-prefix))
+			 (string= name newname)))
+	  (setq name newname)
+	  (haskell-ds-move-to-start-regexp increment start-decl-re))
+	;; If we are going backward, and have either reached a new
+	;; declaration or the beginning of a buffer that does not
+	;; start with a declaration, move forward to start of next
+	;; declaration (which must exist).  Otherwise, we are done.
+	(if (and (not direction)
+		 (or (and (looking-at start-decl-re)
+			  (not (string= name
+					;; Note we must not use
+					;; newname here as this may
+					;; not have been set if we
+					;; have reached the beginning
+					;; of the buffer.
+					(haskell-ds-get-variable
+					 line-prefix))))
+		     (and (not (looking-at start-decl-re))
+			  (bobp))))
+	    (haskell-ds-move-to-start-regexp 1 start-decl-re)))
+      ;; Store whether we are at the start of a declaration or not.
+      ;; Used to calculate final result.
+      (let ((at-start-decl (looking-at start-decl-re)))
+	;; If we are at the beginning of a line, move over
+	;; line-prefix, if present at point.
+	(if (bolp)
+	    (re-search-forward (concat "\\=" line-prefix) (point-max) t))
+	;; Return point if at the start of a declaration and nil
+	;; otherwise.
+	(setq result (if at-start-decl (point) nil))))
+    ;; Replace original syntax table.
+    (set-syntax-table orig-table)
+    ;; Return the result.
+    result))
+
+(defun haskell-ds-backward-decl ()
+  "Move point backward to the first character preceeding the current
+point that starts a top-level declaration.  A series of declarations
+concerning one variable is treated as one declaration by this
+function.  So, if point is within a top-level declaration then move it
+to the start of that declaration.  If point is already at the start of
+a top-level declaration, then move it to the start of the preceeding
+declaration.  Returns point if point is left at the start of a
+declaration, and nil otherwise, ie. because point is at the beginning
+of the buffer and no declaration starts there."
+  (interactive)
+  (haskell-ds-move-to-decl nil
+                           (if (boundp 'haskell-literate)
+                               (eq haskell-literate 'bird) nil)
+                           nil))
+
+(defun haskell-ds-forward-decl ()
+  "As `haskell-ds-backward-decl' but forward."
+  (interactive)
+  (haskell-ds-move-to-decl t
+                           (if (boundp 'haskell-literate)
+                               (eq haskell-literate 'bird) nil)
+                           nil))
+
+(defun haskell-ds-generic-find-next-decl (bird-literate)
+  "Find the name, position and type of the declaration at or after
+point.  Returns `((name . (start-position . name-position)) . type)'
+if one exists and nil otherwise.  The start-position is at the start
+of the declaration, and the name-position is at the start of the name
+of the declaration.  The name is a string, the positions are buffer
+positions and the type is one of the symbols \"variable\", \"datatype\",
+\"class\", \"import\" and \"instance\"."
+  (let (;; The name, type and name-position of the declaration to
+	;; return.
+	name
+	type
+	name-pos
+	;; Buffer positions marking the start and end of the space
+	;; containing a declaration.
+	start
+	end
+	;; Original syntax table.
+	(orig-table (syntax-table)))
+    ;; Change to declaration scanning syntax.
+    (set-syntax-table haskell-ds-syntax-table)
+    ;; Stop when we are at the end of the buffer or when a valid
+    ;; declaration is grabbed.
+    (while (not (or (eobp) name))
+      ;; Move forward to next declaration at or after point.
+      (haskell-ds-move-to-decl t bird-literate t)
+      ;; Start and end of search space is currently just the starting
+      ;; line of the declaration.
+      (setq start (point)
+	    end   (progn (end-of-line) (point)))
+      (goto-char start)
+      (cond
+       ;; If the start of the top-level declaration does not begin
+       ;; with a starting keyword, then (if legal) must be a type
+       ;; signature or value binding, and the variable concerned is
+       ;; grabbed.
+       ((not (looking-at haskell-ds-start-keywords-re))
+	(setq name (haskell-ds-get-variable ""))
+	(if name
+	    (progn
+	      (setq type 'variable)
+	      (re-search-forward (regexp-quote name) end t)
+	      (setq name-pos (match-beginning 0)))))
+       ;; User-defined datatype declaration.
+       ((re-search-forward "\\=\\(data\\|newtype\\|type\\)\\>" end t)
+	(re-search-forward "=>" end t)
+	(if (looking-at "[ \t]*\\(\\sw+\\)")
+	    (progn
+	      (setq name (haskell-ds-match-string 1))
+	      (setq name-pos (match-beginning 1))
+	      (setq type 'datatype))))
+       ;; Class declaration.
+       ((re-search-forward "\\=class\\>" end t)
+	(re-search-forward "=>" end t)
+	(if (looking-at "[ \t]*\\(\\sw+\\)")
+	    (progn
+	      (setq name (haskell-ds-match-string 1))
+	      (setq name-pos (match-beginning 1))
+	      (setq type 'class))))
+       ;; Import declaration.
+       ((looking-at "import[ \t]+\\(qualified[ \t]+\\)?\\(\\sw+\\)")
+	(setq name (haskell-ds-match-string 2))
+	(setq name-pos (match-beginning 2))
+	(setq type 'import))
+       ;; Instance declaration.
+       ((re-search-forward "\\=instance[ \t]+" end t)
+	(re-search-forward "=>[ \t]+" end t)
+	;; The instance "title" starts just after the `instance' (and
+	;; any context) and finishes just before the _first_ `where'
+	;; if one exists.  This solution is ugly, but I can't find a
+	;; nicer one---a simple regexp will pick up the last `where',
+	;; which may be rare but nevertheless...
+	(setq name-pos (point))
+	(setq name (format "%s"
+			   (buffer-substring
+			    (point)
+			    (progn			       
+			      ;; Look for a `where'.
+			      (if (re-search-forward "\\<where\\>" end t)
+				  ;; Move back to just before the `where'.
+				  (progn
+				    (re-search-backward "\\s-where")
+				    (point))
+				;; No `where' so move to last non-whitespace
+				;; before `end'.
+				(progn
+				  (goto-char end)
+				  (skip-chars-backward " \t")
+				  (point)))))))
+	;; If we did not manage to extract a name, cancel this
+	;; declaration (eg. when line ends in "=> ").
+	(if (string-match "^[ \t]*$" name) (setq name nil))
+	(setq type 'instance)))
+      ;; Move past start of current declaration.
+      (goto-char end))
+    ;; Replace syntax table.
+    (set-syntax-table orig-table)
+    ;; If we have a valid declaration then return it, otherwise return
+    ;; nil.
+    (if name
+	(cons (cons name (cons (copy-marker start t) (copy-marker name-pos t)))
+	      type)
+      nil)))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Declaration scanning via `imenu'.
+
+(defun haskell-ds-create-imenu-index ()
+  "Non-literate Haskell version of `haskell-ds-generic-create-menu-index'."
+  (haskell-ds-generic-create-imenu-index nil))
+
+(defun literate-haskell-ds-create-imenu-index ()
+  "Bird-style literate Haskell version of
+`haskell-ds-generic-create-menu-index'."
+  (haskell-ds-generic-create-imenu-index t))
+
+(defun haskell-ds-generic-create-imenu-index (bird-literate)
+  "Function for finding `imenu' declarations in (BIRD-LITERATE) Haskell mode.
+Finds all declarations (classes, variables, imports, instances and
+datatypes) in a Haskell file for the `imenu' package."
+  ;; Each list has elements of the form `(INDEX-NAME . INDEX-POSITION)'.
+  ;; These lists are nested using `(INDEX-TITLE . INDEX-ALIST)'.
+  (let* ((index-alist '())
+	 (index-class-alist '())   ;; Classes
+	 (index-var-alist '())     ;; Variables
+	 (index-imp-alist '())     ;; Imports
+	 (index-inst-alist '())    ;; Instances
+	 (index-type-alist '())    ;; Datatypes
+	 ;; Variables for showing progress.
+	 (bufname (buffer-name))
+	 (divisor-of-progress (max 1 (/ (point-max) 100)))
+	 ;; The result we wish to return.
+	 result)
+    (goto-char (point-min))
+    ;; Loop forwards from the beginning of the buffer through the
+    ;; starts of the top-level declarations.
+    (while (< (point) (point-max))
+      (message "Scanning declarations in %s... (%3d%%)" bufname
+	       (/ (point) divisor-of-progress))
+      ;; Grab the next declaration.
+      (setq result (haskell-ds-generic-find-next-decl bird-literate))
+      (if result
+	  ;; If valid, extract the components of the result.
+	  (let* ((name-posns (car result))
+		 (name (car name-posns))
+		 (posns (cdr name-posns))
+		 (start-pos (car posns))
+		 (type (cdr result))
+		 ;; Place `(name . start-pos)' in the correct alist.
+		 (alist (cond
+			 ((eq type 'variable) 'index-var-alist)
+			 ((eq type 'datatype) 'index-type-alist)
+			 ((eq type 'class) 'index-class-alist)
+			 ((eq type 'import) 'index-imp-alist)
+			 ((eq type 'instance) 'index-inst-alist))))
+	    (set alist (cons (cons name start-pos) (eval alist))))))
+    ;; Now sort all the lists, label them, and place them in one list.
+    (message "Sorting declarations in %s..." bufname)
+    (and index-type-alist
+	 (push (cons "Datatypes"
+		     (sort index-type-alist 'haskell-ds-imenu-label-cmp))
+	       index-alist))
+    (and index-inst-alist
+	 (push (cons "Instances"
+		     (sort index-inst-alist 'haskell-ds-imenu-label-cmp))
+	       index-alist))
+    (and index-imp-alist
+	 (push (cons "Imports"
+		     (sort index-imp-alist 'haskell-ds-imenu-label-cmp))
+	       index-alist))
+    (and index-var-alist
+	 (push (cons "Variables"
+		     (sort index-var-alist 'haskell-ds-imenu-label-cmp))
+	       index-alist))
+    (and index-class-alist
+	 (push (cons "Classes"
+		     (sort index-class-alist 'haskell-ds-imenu-label-cmp))
+	       index-alist))
+    (message "Sorting declarations in %s...done" bufname)
+    ;; Return the alist.
+    index-alist))
+
+(defun haskell-ds-imenu-label-cmp (el1 el2)
+  "Predicate to compare labels in lists produced by
+`haskell-ds-create-imenu-index'."
+  (string< (car el1) (car el2)))
+
+(defun haskell-ds-imenu (bird-literate)
+  "Install `imenu' for (BIRD-LITERATE) Haskell scripts."
+  ;; Would prefer to toggle imenu but can't see how to turn it off...
+  (require 'imenu)
+  ;; In emacs-20's imenu we have to bind some functions first -- HWL
+  (if (and  (not haskell-ds-running-xemacs)
+	    (>= (string-to-number (substring emacs-version 0 2)) 20)
+	    (not (fboundp 'imenu-extract-index-name-function)))
+    (setq imenu-extract-index-name-function
+	  (if bird-literate (function literate-haskell-ds-create-imenu-index)
+	    (function haskell-ds-create-imenu-index))))
+  (setq imenu-create-index-function
+	(if bird-literate (function literate-haskell-ds-create-imenu-index)
+	  (function haskell-ds-create-imenu-index)))
+  (if (fboundp 'imenu-add-to-menubar)
+      (imenu-add-to-menubar "Declarations")))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Declaration scanning via `func-menu'.
+
+(defun haskell-ds-func-menu-next (buffer)
+  "Non-literate Haskell version of `haskell-ds-generic-func-menu-next'." 
+  (haskell-ds-generic-func-menu-next nil buffer)) 
+
+(defun literate-haskell-ds-func-menu-next (buffer)
+  "Bird-style literate Haskell version of `haskell-ds-generic-func-menu-next'."
+  (haskell-ds-generic-func-menu-next t buffer)) 
+
+(defun haskell-ds-generic-func-menu-next (bird-literate buffer)
+  "Returns `(name . pos)' of next declaration."
+  (set-buffer buffer)
+  (let ((result (haskell-ds-generic-find-next-decl bird-literate)))
+    (if result
+	(let* ((name-posns (car result))
+	       (name (car name-posns))
+	       (posns (cdr name-posns))
+	       (name-pos (cdr posns))
+	       ;(type (cdr result))
+	       )
+	  (cons ;(concat
+		 ;; func-menu has problems with spaces, and adding a
+		 ;; qualifying keyword will not allow the "goto fn"
+		 ;; functions to work properly.  Sigh.
+;		 (cond
+;		  ((eq type 'variable) "")
+;		  ((eq type 'datatype) "datatype ")
+;		  ((eq type 'class) "class ")
+;		  ((eq type 'import) "import ")
+;		  ((eq type 'instance) "instance "))
+		 name;)
+		name-pos))
+      nil)))
+
+(defvar haskell-ds-func-menu-regexp
+  (concat "^" haskell-ds-start-decl-re)
+  "Regexp to match the start of a possible declaration.")
+
+(defvar literate-haskell-ds-func-menu-regexp
+  (concat "^" literate-haskell-ds-start-decl-re)
+  "As `haskell-ds-func-menu-regexp' but for Bird-style literate scripts.")
+
+(defun haskell-ds-func-menu (bird-literate)
+  "Uses `func-menu' to establish declaration scanning for (BIRD-LITERATE)
+Haskell scripts."
+  (require 'func-menu)
+  (make-local-variable 'fume-menubar-menu-name)
+  (setq fume-menubar-menu-name "Declarations")
+  (make-local-variable 'fume-function-name-regexp-alist)
+  (setq fume-function-name-regexp-alist
+	(if bird-literate
+            '((haskell-mode . literate-haskell-ds-func-menu-regexp))
+          '((haskell-mode . haskell-ds-func-menu-regexp))))
+  (make-local-variable 'fume-find-function-name-method-alist)
+  (setq fume-find-function-name-method-alist
+        (if bird-literate
+            '((haskell-mode . literate-haskell-ds-func-menu-next))
+          '((haskell-mode . haskell-ds-func-menu-next))))
+  (fume-add-menubar-entry)
+  (local-set-key "\C-cl" 'fume-list-functions)
+  (local-set-key "\C-cg" 'fume-prompt-function-goto)
+  (local-set-key [(meta button1)] 'fume-mouse-function-goto))
+
+;; Key mappings.
+(defun haskell-ds-keys ()
+  "Map the keys for forward and backward declaration movement."
+  (local-set-key "\M-\C-e" 'haskell-ds-forward-decl)
+  (local-set-key "\M-\C-a" 'haskell-ds-backward-decl))
+
+;; The main functions to turn on declaration scanning.
+(defun turn-on-haskell-decl-scan ()
+  "Turn on declaration scanning for Haskell mode.  Top-level
+declarations are scanned and listed in the menu item \"Declarations\".
+Selecting an item from this menu will take point to the start of the
+declaration.
+
+\\[haskell-ds-forward-decl] and \\[haskell-ds-backward-decl] move forward and backward to the start of a declaration.
+
+Under XEmacs, the following keys are also defined:
+
+\\[fume-list-functions] lists the declarations of the current buffer,
+\\[fume-prompt-function-goto] prompts for a declaration to move to, and
+\\[fume-mouse-function-goto] moves to the declaration whose name is at point.
+
+This may link with `haskell-doc' (only for FSF Emacs currently).
+
+For non-literate and LaTeX-style literate scripts, we assume the
+common convention that top-level declarations start at the first
+column.  For Bird-style literate scripts, we assume the common
+convention that top-level declarations start at the third column,
+ie. after \"> \".
+
+Anything in `font-lock-comment-face' is not considered for a
+declaration.  Therefore, using Haskell font locking with comments
+coloured in `font-lock-comment-face' improves declaration scanning.
+
+To turn on declaration scanning for all Haskell buffers, add this to
+.emacs:
+
+  (add-hook 'haskell-mode-hook 'turn-on-haskell-decl-scan)
+
+To turn declaration scanning on for the current buffer, call
+`turn-on-haskell-decl-scan'.
+
+Literate Haskell scripts are supported: If the value of
+`haskell-literate' (automatically set by the Haskell mode of
+Moss&Thorn) is 'bird, a Bird-style literate script is assumed.  If it
+is nil or 'latex, a non-literate or LaTeX-style literate script is
+assumed, respectively.
+
+Invokes `haskell-decl-scan-hook' if not nil.
+
+Use `haskell-decl-scan-version' to find out what version this is."
+  (interactive)
+  (haskell-ds-keys)
+  (let ((bird-literate (if (boundp 'haskell-literate)
+                           (eq haskell-literate 'bird) nil)))
+    (if haskell-ds-running-xemacs
+        (haskell-ds-func-menu bird-literate)
+      (haskell-ds-imenu bird-literate)))
+  (run-hooks 'haskell-decl-scan-hook))
+
+;;; Provide ourselves:
+
+(provide 'haskell-decl-scan)
+
+;;; haskell-decl-scan ends here.
+;;; haskell-doc.el --- show function types in echo area
+
+;; Time-stamp: <Thu Dec 10 1998 17:26:21 Stardate: [-30]2203.42 hwloidl>
+
+;; Copyright (C) 1997 Hans-Wolfgang Loidl
+
+;; Author: Hans-Wolfgang Loidl <hwloidl@dcs.glasgow.ac.uk>
+;; Maintainer: Hans-Wolfgang Loidl <hwloidl@dcs.glasgow.ac.uk>
+;; Temporary Maintainer and Hacker: Graeme E Moss <gem@cs.york.ac.uk>
+;; Keywords: extensions, minor mode, language mode, Haskell
+;; Created: 1997-06-17
+;; Revision: $Revision$
+;; FTP archive: /ftp@ftp.dcs.gla.ac.uk:/pub/glasgow-fp/authors/Hans_Loidl/Elisp/haskell-doc.el
+;; Status: Beta version
+
+;; $Id$
+
+;;; Copyright:
+;;  ==========
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 2, or (at your option)
+;; any later version.
+;;
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program; if not, you can either send email to this
+;; program's maintainer or write to: The Free Software Foundation,
+;; Inc.; 59 Temple Place, Suite 330; Boston, MA 02111-1307, USA.
+
+;;; Commentary:
+;;  ===========
+
+;; This program shows the type of the Haskell function under the cursor in the
+;; minibuffer. It acts as a kind of "emacs background process", by regularly
+;; checking the word under the cursor and matching it against a list of
+;; prelude, library, local and global functions.
+
+;; The preferred usage of this package is in combination with
+;; `haskell-hugs-mode'.
+;; In that case `haskell-doc-mode' checks an internal variable updated by
+;; `imenu' to access the types of all local functions. In `haskell-mode' this
+;; is not possible. However, types of prelude functions are still shown.
+
+;; To show types of global functions, i.e. functions defined in a module 
+;; imported by the current module, call the function 
+;; `turn-on-haskell-doc-global-types'. This automatically loads all modules
+;; and builds `imenu' tables to get the types of all functions (again this 
+;; currently requires `haskell-hugs-mode'). 
+;; Note: The modules are loaded recursively, so you might pull in
+;;       many modules by just turning on global function support.
+;; This features is currently not very well supported.
+
+;; This program was inspired by the `eldoc.el' package by Noah Friedman.
+
+;;; Installation:
+;;  =============
+
+;; One useful way to enable this minor mode is to put the following in your
+;; .emacs:
+;;
+;;      (autoload 'turn-on-haskell-doc-mode "haskell-doc" nil t)
+
+;;   and depending on the major mode you use for your Haskell programs:
+;;      (add-hook 'hugs-mode-hook 'turn-on-haskell-doc-mode)    ; hugs-mode
+;;     or
+;;      (add-hook 'haskell-mode-hook 'turn-on-haskell-doc-mode) ; haskell-mode
+
+;;; Customisation:
+;;  ==============
+
+;; You can control what exactly is shown by setting the following variables to
+;; either t or nil:
+;;  `haskell-doc-show-global-types' (default: nil)
+;;  `haskell-doc-show-reserved'     (default: t)
+;;  `haskell-doc-show-prelude'      (default: '1.4)
+;;  `haskell-doc-show-strategy'     (default: t)
+;;  `haskell-doc-show-user-defined' (default: t)
+
+;; If you want to define your own strings for some identifiers define an
+;; alist of (ID . STRING) and set `haskell-doc-show-user-defined' to t. 
+;; E.g:
+;;
+;;   (setq haskell-doc-show-user-defined t)
+;;   (setq haskell-doc-user-defined-ids 
+;;	(list 
+;;	   '("main" . "just another pathetic main function")
+;;	   '("foo" . "a very dummy name")
+;;	   '("bar" . "another dummy name")))
+
+;;  The following two variables are useful to make the type fit on one line:
+;;  If `haskell-doc-chop-off-context' is non-nil the context part of the type
+;;  of a local fct will be eliminated (default: t). 
+;;  If `haskell-doc-chop-off-fctname' is non-nil the function name is not 
+;;  shown together with the type (default: nil).
+
+;;; Internals:
+;;  ==========
+
+;; `haskell-doc-mode' is implemented as a minor-mode. So, you can combine it
+;; with any other mode. To enable it just type
+;;   M-x turn-on-haskell-doc-mode
+
+;; These are the names of the functions that can be called directly by the
+;; user (with keybindings in `haskell-hugs-mode' and `haskell-mode'):
+;;  `haskell-doc-mode' ... toggle haskell-doc-mode; with prefix turn it on
+;;                        unconditionally if the prefix is greater 0 otherwise
+;;                        turn it off
+;;                        Key: CTRL-c CTRL-o (CTRL-u CTRL-c CTRL-o)
+;;  `haskell-doc-ask-mouse-for-type' ... show the type of the id under the mouse
+;;                                      Key: C-S-M-mouse-3
+;;  `haskell-doc-show-reserved'     ... toggle echoing of reserved id's types
+;;  `haskell-doc-show-prelude'      ... toggle echoing of prelude id's types
+;;  `haskell-doc-show-strategy'     ... toggle echoing of strategy id's types
+;;  `haskell-doc-show-user-defined' ... toggle echoing of user def id's types
+;;  `haskell-doc-check-active' ... check whether haskell-doc is active via the 
+;;                                `post-command-idle-hook' (for testing); 
+;;                                 Key: CTRL-c ESC-/
+
+;;; ToDo:
+;;  =====
+
+;;   - Fix byte-compile problems in `haskell-doc-prelude-types' for getArgs etc 
+;;   - Write a parser for .hi files and make haskell-doc independent from
+;;     hugs-mode. Read library interfaces via this parser.
+;;   - Support both Haskell 1.4 and 1.2
+;;   - Indicate kind of object with colours
+;;   - Handle multi-line types
+;;   - Encode i-am-fct info in the alist of ids and types.
+;;   - Replace the usage of `post-command-idle-hook' with idle timers
+
+;;; Bugs:
+;;  =====
+
+;;   - Some prelude fcts aren't displayed properly. This might be due to a 
+;;     name clash of Haskell and Elisp functions (e.g. length) which
+;;     confuses emacs when reading `haskell-doc-prelude-types'
+
+;;; Changelog:
+;;  ==========
+;;  $Log$
+;;  Revision 1.1  2001/07/19 16:17:36  rrt
+;;  Add the current version of the Moss/Thorn/Marlow Emacs mode, along with its
+;;  web pages and sample files. This is now the preferred mode, and the
+;;  haskell.org pages are being changed to reflect that. Also includes the new
+;;  GHCi mode from Chris Webb.
+;;
+;;  Revision 1.6  1998/12/10 16:27:25  hwloidl
+;;  Minor changes ("Doc" as modeline string, mouse-3 moved to C-S-M-mouse-3)
+;;
+;;  Revision 1.5  1998/09/24 14:25:46  gem
+;;  Fixed minor compatibility bugs with Haskell mode of Moss&Thorn.
+;;  Disabled M-/ binding.
+;;
+;;  Revision 1.4  1997/11/12 23:51:19  hwloidl
+;;  Fixed start-up problem under emacs-19.34.
+;;  Added support for wrapped (multi-line) types and 2 vars to control the
+;;  behaviour with long fct types
+;;
+;;  Revision 1.3  1997/11/03 00:48:03  hwloidl
+;;  Major revision for first release.
+;;  Added alists for showing prelude fcts, haskell syntax, and strategies
+;;  Added mouse interface to show type under mouse
+;;  Fixed bug which causes demon to fall over
+;;  Works now with hugs-mode and haskell-mode under emacs 19.34,20 and xemacs 19.15
+;;
+
+;;; Code:
+;;  =====
+
+;@menu
+;* Constants and Variables::	
+;* Install as minor mode::	
+;* Menubar Support::		
+;* Haskell Doc Mode::		
+;* Switch it on or off::	
+;* Check::			
+;* Top level function::		
+;* Mouse interface::		
+;* Print fctsym::		
+;* Movement::			
+;* Bug Reports::		
+;* Visit home site::		
+;* Index::			
+;* Token::			
+;@end menu
+
+;@node top, Constants and Variables, (dir), (dir)
+;@top
+
+;@node Constants and Variables, Install as minor mode, top, top
+;@section Constants and Variables
+
+;@menu
+;* Emacs portability::		
+;* Maintenance stuff::		
+;* Mode Variable::		
+;* Variables::			
+;* Prelude types::		
+;* Test membership::		
+;@end menu
+
+;@node Emacs portability, Maintenance stuff, Constants and Variables, Constants and Variables
+;@subsection Emacs portability
+
+(defconst haskell-doc-xemacs-p (string-match "XEmacs\\|Lucid" emacs-version)
+  "Running under XEmacs?")
+
+(defconst haskell-doc-emacs-p (and (or (string-match "^19" emacs-version)
+				       (string-match "^20" emacs-version))
+				(not haskell-doc-xemacs-p))
+  "Running under Emacs?")
+
+;@node Maintenance stuff, Mode Variable, Emacs portability, Constants and Variables
+;@subsection Maintenance stuff
+
+(defconst haskell-doc-version "$Revision$"
+ "Version of `haskell-doc-mode' as RCS Revision.")
+
+(defconst haskell-doc-maintainer "Hans-Wolfgang Loidl <hwloidl@dcs.glasgow.ac.uk>"
+  "Maintainer of `haskell-doc-mode'.")
+
+(defconst haskell-doc-ftp-site "/ftp@ftp.dcs.gla.ac.uk:/pub/glasgow-fp/authors/Hans_Loidl/Elisp/"
+  "Main FTP site with latest version of `haskell-doc-mode' and sample files.")
+
+;@node Mode Variable, Variables, Maintenance stuff, Constants and Variables
+;@subsection Mode Variable
+
+;;;###autoload
+(defvar haskell-doc-mode nil
+  "*If non-nil, show the type of the function near point or a related comment.
+
+If the identifier near point is a Haskell keyword and the variable
+`haskell-doc-show-reserved' is non-nil show a one line summary
+of the syntax.
+
+If the identifier near point is a Prelude or one of the standard library 
+functions and `haskell-doc-show-prelude' is non-nil show its type. Currently 
+only Haskell 1.4 functions are supported. In future versions the 
+`haskell-doc-show-prelude' variable should determine which prelude/library
+to use for type lookup.
+
+If the identifier near point is local \(i.e. defined in this module\) check
+the `imenu' list of functions for the type. This obviously requires that
+your language mode uses `imenu' \(`haskell-hugs-mode' 0.6 for example\).
+
+If the identifier near point is global \(i.e. defined in an imported module\) 
+and the variable `haskell-doc-show-global-types' is non-nil show the type of its 
+function.
+
+If the identifier near point is a standard strategy or a function, type related
+related to strategies and `haskell-doc-show-strategy' is non-nil show the type
+of the function. Strategies are special to the parallel execution of Haskell.
+If you're not interested in that just turn it off.
+
+If the identifier near point is a user defined function that occurs as key
+in the alist `haskell-doc-user-defined-ids' and the variable 
+`haskell-doc-show-user-defined' is non-nil show the type of the function.
+
+This variable is buffer-local.")
+(make-variable-buffer-local 'haskell-doc-mode)
+
+(defvar haskell-doc-mode-hook nil
+ "Hook invoked when entering `haskell-doc-mode'.")
+
+(defvar haskell-doc-index nil
+ "Variable holding an alist matching file names to fct-type alists.
+The function `haskell-doc-make-global-fct-index' rebuilds this variables \(similar to an
+`imenu' rescan\).
+This variable is buffer-local.")
+(make-variable-buffer-local 'haskell-doc-index)
+
+(defvar haskell-doc-show-global-types nil
+ "*If non-nil, search for the types of global functions by loading the files.
+This variable is buffer-local.")
+(make-variable-buffer-local 'haskell-doc-show-global-types)
+
+(defvar haskell-doc-show-reserved t
+ "*If non-nil, show a documentation string for reserved ids.
+This variable is buffer-local.")
+(make-variable-buffer-local 'haskell-doc-show-reserved)
+
+(defvar haskell-doc-show-prelude t ; '1.4
+ "*If non-nil, show a documentation string for prelude functions.
+Possible values are Haskell versions. Currently, only `1.4' is supported.
+This variable is buffer-local.")
+(make-variable-buffer-local 'haskell-doc-show-prelude)
+
+(defvar haskell-doc-show-strategy t
+ "*If non-nil, show a documentation string for strategies.
+This variable is buffer-local.")
+(make-variable-buffer-local 'haskell-doc-show-strategy)
+
+(defvar haskell-doc-show-user-defined t
+ "*If non-nil, show a documentation string for user defined ids.
+This variable is buffer-local.")
+(make-variable-buffer-local 'haskell-doc-show-user-defined)
+
+(defvar haskell-doc-chop-off-context t
+ "*If non-nil eliminate the context part in a Haskell type.")
+
+(defvar haskell-doc-chop-off-fctname nil
+ "*If non-nil omit the function name and show only the type.")
+
+(defvar haskell-doc-search-distance 40  ; distance in characters
+ "*How far to search when looking for the type declaration of fct under cursor.")
+
+;@node Variables, Prelude types, Mode Variable, Constants and Variables
+;@subsection Variables
+
+(defvar haskell-doc-idle-delay 0.50
+  "*Number of seconds of idle time to wait before printing.
+If user input arrives before this interval of time has elapsed after the
+last input, no documentation will be printed.
+
+If this variable is set to 0, no idle time is required.")
+
+(defvar haskell-doc-argument-case 'identity ; 'upcase
+  "Case to display argument names of functions, as a symbol.
+This has two preferred values: `upcase' or `downcase'.
+Actually, any name of a function which takes a string as an argument and
+returns another string is acceptable.")
+
+(defvar haskell-doc-mode-message-commands nil
+  "*Obarray of command names where it is appropriate to print in the echo area.
+
+This is not done for all commands since some print their own
+messages in the echo area, and these functions would instantly overwrite
+them.  But `self-insert-command' as well as most motion commands are good
+candidates.
+
+It is probably best to manipulate this data structure with the commands
+`haskell-doc-add-command' and `haskell-doc-remove-command'.")
+
+;(cond ((null haskell-doc-mode-message-commands)
+;       ;; If you increase the number of buckets, keep it a prime number.
+;       (setq haskell-doc-mode-message-commands (make-vector 31 0))
+;       (let ((list '("self-insert-command"
+;                     "next-"         "previous-"
+;                     "forward-"      "backward-"
+;                     "beginning-of-" "end-of-"
+;                     "goto-"
+;                     "recenter"
+;                     "scroll-"))
+;             (syms nil))
+;         (while list
+;           (setq syms (all-completions (car list) obarray 'fboundp))
+;           (setq list (cdr list))
+;           (while syms
+;             (set (intern (car syms) haskell-doc-mode-message-commands) t)
+;             (setq syms (cdr syms)))))))
+
+;; Bookkeeping; the car contains the last symbol read from the buffer.
+;; The cdr contains the string last displayed in the echo area, so it can
+;; be printed again if necessary without reconsing.
+(defvar haskell-doc-last-data '(nil . nil))
+
+(defvar haskell-doc-minor-mode-string " Doc"              ; " Haskell-Doc"
+  "*String to display in mode line when Haskell-Doc Mode is enabled.")
+
+(defconst haskell-doc-varlist
+  (list
+   'haskell-doc-xemacs-p
+   'haskell-doc-emacs-p
+   'haskell-doc-version
+   'haskell-doc-mode
+   'haskell-doc-mode-hook
+   'haskell-doc-index
+   'haskell-doc-show-global-types
+   'haskell-doc-show-reserved
+   'haskell-doc-show-prelude
+   'haskell-doc-show-strategy
+   'haskell-doc-show-user-defined
+   'haskell-doc-idle-delay
+   'haskell-doc-argument-case
+   'haskell-doc-mode-message-commands
+  )
+  "List of variables sent via `haskell-doc-submit-bug-report'.")
+
+;@node Prelude types, Test membership, Variables, Constants and Variables
+;@subsection Prelude types
+
+;@cindex haskell-doc-reserved-ids
+
+(defvar haskell-doc-reserved-ids
+ (list
+  '("case" . "case exp of { alts [;] }")
+  '("class" . "class [context =>] simpleclass [where { cbody [;] }]")
+  '("data" . "data [context =>] simpletype = constrs [deriving]")
+  '("default" . "default (type1 , ... , typen)")
+  '("deriving" . "deriving (dclass | (dclass1, ... , dclassn))") ; used with data or newtype
+  '("do" . "do { stmts [;] }  stmts -> exp [; stmts] | pat <- exp ; stmts | let decllist ; stmts")
+  '("else" . "if exp then exp else exp")
+  '("if" . "if exp then exp else exp")
+  '("import" . "import [qualified] modid [as modid] [impspec]")
+  '("in" . "let decllist in exp")
+  '("infix" . "infix [digit] ops")
+  '("infixl" . "infixl [digit] ops")
+  '("infixr" . "infixr [digit] ops")
+  '("instance" . "instance [context =>] qtycls inst [where { valdefs [;] }]")
+  '("let" . "let { decl; ...; decl [;] } in exp")
+  '("module" . "module modid [exports] where body")
+  '("newtype" . "newtype [context =>] simpletype = con atype [deriving]")
+  '("of" . "case exp of { alts [;] }")
+  '("then" . "if exp then exp else exp")
+  '("type" . "type simpletype = type")
+  '("where" . "exp where { decl; ...; decl [;] }") ; check that ; see also class, instance, module
+  '("as" . "import [qualified] modid [as modid] [impspec]")
+  '("qualified" . "import [qualified] modid [as modid] [impspec]")
+  '("hiding" . "hiding ( import1 , ... , importn [ , ] )")
+ )
+ "An alist of reserved identifiers and a string describing the construct they are used in.")
+
+;@cindex haskell-doc-prelude-types
+
+(defvar haskell-doc-prelude-types
+ (list
+ ; Taken from the prelude of the 1.4 report
+ ; ToDo: clean this up
+ ; ToDo: add overloaded fcts at the beginning of the report.
+; '("subtract"          . "(Num a) => a -> a -> a")
+; '("odd"               . "(Integral a) => a -> Bool")
+; '("even"              . "(Integral a) => a -> Bool")
+; '("gcd"               . "(Integral a) => a -> a -> a")
+; '("lcm"               . "(Integral a) => a -> a -> a")
+; ;'("^"                . "(Num a, Integral b) => a -> b -> a")
+; ;'("^^"               . "(Fractional a, Integral b) => a -> b -> a")
+; '("fromIntegral"      . "(Integral a, Num b) => a -> b")
+; '("fromRealFrac"      . "(RealFrac a, Fractional b) => a -> b")
+; '("atan2"             . "(RealFloat a) => a -> a -> a")
+; '("map"               . "(Functor f) => (a -> b) -> f a -> f b")
+; ;'("(>>=)             . "(Monad m) => m a -> (a -> m b) -> m b")
+; ;'("(>>)              . "(Monad m) => m a -> m b -> m b")
+; '("return"            . "(Monad m) => a -> m a")
+; '("zero"              . "(Monad m) => m a")
+; ;'("(++)              . "(Monad m) => m a -> m a -> m a")
+; '("accumulate"        . "Monad m => [m a] -> m [a] ")
+; '("sequence"          . "Monad m => [m a] -> m () ")
+; '("mapM"              . "Monad m => (a -> m b) -> [a] -> m [b]")
+; '("mapM_"             . "Monad m => (a -> m b) -> [a] -> m ()")
+; '("guard"             . "MonadZero m => Bool -> m ()")
+; '("filter"            . "MonadZero m => (a -> Bool) -> m a -> m a")
+; '("concat"            . "MonadPlus m => [m a] -> m a")
+; '("applyM"            . "Monad m => (a -> m b) -> m a -> m b")
+; '("seq"               . "(Eval a) => a -> b -> b")
+; '("strict"            . "(Eval a) => (a -> b) -> a -> b")
+; '("id"                . "a -> a")
+; '("const"             . "a -> b -> a")
+; ; '("."               . "(b -> c) -> (a -> b) -> a -> c")
+; '("flip"              . "(a -> b -> c) -> b -> a -> c")
+; ;'("$"                . "(a -> b) -> a -> b")
+; ;'("&&"               . "Bool -> Bool -> Bool")
+; ;'("||"               . "Bool -> Bool -> Bool")
+; '("not"               . "Bool -> Bool")
+; '("maybe"             . "b -> (a -> b) -> Maybe a -> b")
+; '("either"            . "(a -> c) -> (b -> c) -> Either a b -> c")
+; '("numericEnumFrom"          . "(Real a) => a -> [a]")
+; '("numericEnumFromThen"      . "(Real a) => a -> a -> [a]")
+; '("numericEnumFromTo"        . "(Real a) => a -> a -> [a]")
+; '("numericEnumFromThenTo"    . "(Real a) => a -> a -> a -> [a]")
+; '("fst"               . "(a,b) -> a")
+; '("snd"               . "(a,b) -> b")
+; '("curry"             . "((a, b) -> c) -> a -> b -> c")
+; '("uncurry"           . "(a -> b -> c) -> ((a, b) -> c)")
+; '("until"             . "(a -> Bool) -> (a -> a) -> a -> a")
+; '("asTypeOf"          . "a -> a -> a")
+; '("error"             . "String -> a")
+; '("undefined"         . "a")
+; ; List fcts
+; '("head"              . "[a] -> a")
+; '("last"              . "[a] -> a")
+; '("tail"              . "[a] -> [a]")
+; '("init"              . "[a] -> [a]")
+; '("null"              . "[a] -> Bool")
+; '("length"            . "[a] -> Int")
+; ; '("!!"              . "[a] -> Int -> a")
+; '("foldl"             . "(a -> b -> a) -> a -> [b] -> a")
+; '("foldl1"            . "(a -> a -> a) -> [a] -> a")
+; '("scanl"             . "(a -> b -> a) -> a -> [b] -> [a]")
+; '("scanl1"            . "(a -> a -> a) -> [a] -> [a]")
+; '("foldr"             . "(a -> b -> b) -> b -> [a] -> b")
+; '("foldr1"            . "(a -> a -> a) -> [a] -> a")
+; '("scanr"             . "(a -> b -> b) -> b -> [a] -> [b]")
+; '("scanr1"            . "(a -> a -> a) -> [a] -> [a]")
+; '("iterate"           . "(a -> a) -> a -> [a]")
+; '("repeat"            . "a -> [a]")
+; '("replicate"         . "Int -> a -> [a]")
+; '("cycle"             . "[a] -> [a]")
+; '("take"              . "Int -> [a] -> [a]")
+; '("drop"              . "Int -> [a] -> [a]")
+; '("splitAt"           . "Int -> [a] -> ([a],[a])")
+; '("takeWhile"         . "(a -> Bool) -> [a] -> [a]")
+; '("dropWhile"         . "(a -> Bool) -> [a] -> [a]")
+; '("span"              . "(a -> Bool) -> [a] -> ([a],[a])")
+; '("break"             . "(a -> Bool) -> [a] -> ([a],[a])")
+; '("lines"             . "String -> [String]")
+; '("words"             . "String -> [String]")
+; '("unlines"           . "[String] -> String")
+; '("unwords"           . "[String] -> String")
+; '("reverse"           . "[a] -> [a]")
+; '("and"               . "[Bool] -> Bool")
+; '("or"                . "[Bool] -> Bool")
+; '("any"               . "(a -> Bool) -> [a] -> Bool")
+; '("all"               . "(a -> Bool) -> [a] -> Bool")
+; '("elem"              . "(Eq a) => a -> [a] -> Bool")
+; '("notElem"           . "(Eq a) => a -> [a] -> Bool")
+; '("lookup"            . "(Eq a) => a -> [(a,b)] -> Maybe b")
+; '("sum"               . "(Num a) => [a] -> a")
+; '("product"           . "(Num a) => [a] -> a")
+; '("maximum"           . "(Ord a) => [a] -> a")
+; '("minimum"           . "(Ord a) => [a] -> a")
+; '("concatMap"         . "(a -> [b]) -> [a] -> [b]")
+; '("zip"               . "[a] -> [b] -> [(a,b)]")
+; '("zip3"              . "[a] -> [b] -> [c] -> [(a,b,c)]")
+; '("zipWith"           . "(a->b->c) -> [a]->[b]->[c]")
+; '("zipWith3"          . "(a->b->c->d) -> [a]->[b]->[c]->[d]")
+; '("unzip"             . "[(a,b)] -> ([a],[b])")
+; '("unzip3"            . "[(a,b,c)] -> ([a],[b],[c])")
+; '("readsPrec"         . "(Read a) => Int -> ReadS a")
+; '("readList"          . "(Read a) => ReadS [a]")
+; '("showsPrec"         . "(Show a) => Int -> a -> ShowS")
+; '("showList"          . "(Show a) => [a] -> ShowS")
+; '("reads"             . "(Read a) => ReadS a")
+; '("shows"             . "(Show a) => a -> ShowS")
+; '("read"              . "(Read a) => String -> a")
+; '("show"              . "(Show a) => a -> String")
+; '("showChar"          . "Char -> ShowS")
+; '("showString"        . "String -> ShowS")
+; '("showParen"         . "Bool -> ShowS -> ShowS")
+; '("readParen"         . "Bool -> ReadS a -> ReadS a")
+; '("lex"               . "ReadS String")
+; '("lexDigits"         . "ReadS String ")
+; '("nonnull"           . "(Char -> Bool) -> ReadS String")
+; '("lexLitChar"        . "ReadS String")
+; ;'("showSigned"       . "(Real a) => (a -> ShowS) -> Int -> a -> ShowS")
+; ;'("readSigned"       . "(Real a) => ReadS a -> ReadS a")
+; ;'("showInt"          . "(Integral a) => a -> ShowS")
+; ;'("readInt"          . "(Integral a) => a -> (Char -> Bool) -> (Char -> Int) -> ReadS a")
+; '("readDec"           . "(Integral a) => ReadS a")
+; '("readOct"           . "(Integral a) => ReadS a")
+; '("readHex"           . "(Integral a) => ReadS a")
+; ; IO fcts
+; '("fail"              . "IOError -> IO a")
+; '("userError"         . "String -> IOError")
+; '("catch"             . "IO a -> (IOError -> IO a) -> IO a ")
+; '("putChar"           . "Char -> IO ()")
+; '("putStr"            . "String -> IO ()")
+; '("putStrLn"          . "String -> IO ()")
+; '("print"             . "Show a => a -> rIO ()")
+; '("getChar"           . "IO Char")
+; '("getLine"           . "IO String")
+; '("getContents"       . "IO String")
+; '("interact"          . "(String -> String) -> IO ()")
+; '("readFile"          . "FilePath -> IO String")
+; '("writeFile"         . "FilePath -> String -> IO ()")
+; '("appendFile"        . "FilePath -> String -> IO ()")
+; '("readIO"            . "Read a => String -> IO a")
+; '("readLn"            . "Read a => IO a")
+ ;; ---------------------------------------------------------------------------
+ ;; taken from Prelude Index of the Haskell 1.4 report
+ '("!!"             . "[a] -> Int -> a ")
+ '("$"              . "(a -> b) -> a -> b ")
+ '("&&"             . "Bool -> Bool -> Bool ")
+ '("||"             . "Bool -> Bool -> Bool ")
+ '("*"              . "Num a => a -> a -> a ")
+ '("**"             . "Floating a => a -> a -> a ")
+ '("+"              . "Num a => a -> a -> a")
+ '("++"             . "MonadPlus m => m a -> m a -> m a ")
+ '("-"              . "Num a => a -> a -> a ")
+ '("."              . "(b -> c) -> (a -> b) -> a -> c ")
+ '("/"              . "Fractional a => a -> a -> a ")
+ '("/="             . "Eq a => a -> a -> Bool ")
+ '("<"              . "Ord a => a -> a -> Bool ")
+ '("<="             . "Ord a => a -> a -> Bool ")
+ '("=="             . "Eq a => a -> a -> Bool ")
+ '(">"              . "Ord a => a -> a -> Bool ")
+ '(">="             . "Ord a => a -> a -> Bool ")
+ '(">>"             . "m a -> m b -> m b ")
+ '(">>="            . "Monad m => m a -> (a -> m b) -> m b ")
+ '("^"              . "(Num a, Integral b) => a -> b -> a ")
+ '("^^"             . "(Fractional a, Integral b) => a -> b -> a ")
+ '("abs"              . "Num a => a -> a ")
+ '("accumulate"       . "Monad m => [m a] -> m [a] ")
+ '("acos"             . "Floating a => a -> a ")
+ '("acosh"            . "Floating a => a -> a ")
+ '("all"              . "(a -> Bool) -> [a] -> Bool ")
+ '("and"              . "[Bool] -> Bool ")
+ '("any"              . "(a -> Bool) -> [a] -> Bool ")
+ '("appendFile"       . "FilePath -> String -> IO ()")
+ '("applyM"           . "Monad m => (a -> m b) -> m a -> m b")
+ '("asTypeOf"         . "a -> a -> a ")
+ '("asin"             . "Floating a => a -> a ")
+ '("asinh"            . "Floating a => a -> a ")
+ '("atan"             . "Floating a => a -> a ")
+ '("atan2"            . "RealFrac a => a -> a ")
+ '("atanh"            . "Floating a => a -> a ")
+ '("break"            . "(a -> Bool) -> [a] -> ([a], [a]) ")
+ '("catch"            . "IO a -> (IOError -> IO a) -> IO a ")
+ '("ceiling"          . "(RealFrac a, Integral b) => a -> b ")
+ '("compare"          . "Ord a => a -> a -> Ordering ")
+ '("concat"           . "MonadPlus m => [m a] -> m a ")
+ '("concatMap"        . "(a -> [b]) -> [a] -> [b]")
+ '("const"            . "a -> b -> a")
+ '("cos"              . "Floating a => a -> a ")
+ '("cosh"             . "Floating a => a -> a ")
+ '("curry"            . "((a, b) -> c) -> a -> b -> c")
+ '("cycle"            . "[a] -> [a] ")
+ '("decodeFloat"      . "RealFloat a => a -> (Integer, Int) ")
+ '("div"              . "Integral a => a -> a -> a ")
+ '("divMod"           . "Integral a => a -> a -> (a, a) ")
+ '("drop"             . "Int -> [a] -> [a] ")
+ '("dropWhile"        . "(a -> Bool) -> [a] -> [a] ")
+ '("elem"             . "Eq a => a -> [a] -> Bool ")
+ '("encodeFloat"      . "RealFloat a => Integer -> Int -> a ")
+ '("enumFrom"         . "Enum a => a -> [a] ")
+ '("enumFromThen"     . "Enum a => a -> a -> [a] ")
+ '("enumFromThenTo"   . "Enum a => a -> a -> a -> [a] ")
+ '("enumFromTo"       . "Enum a => a -> a -> [a] ")
+ '("error"            . "String -> a ")
+ '("even"             . "Integral a => a -> Bool")
+ '("exp"              . "Floating a => a -> a ")
+ '("exponent"         . "RealFloat a => a -> Int ")
+ '("fail"             . "IOError -> IO a ")
+ '("filter"           . "MonadZero m => (a -> Bool) -> m a -> m a ")
+ '("flip"             . "(a -> b -> c) -> (b -> a -> c)")
+ '("floatDigits"      . "RealFloat a => a -> Int ")
+ '("floatRadix"       . "RealFloat a => a -> Integer ")
+ '("floatRange"       . "RealFloat a => a -> (Int, Int) ")
+ '("floor"            . "(RealFrac a, Integral b) => a -> b ")
+ '("foldl"            . "(a -> b -> a) -> a -> [b] -> a ")
+ '("foldl1"           . "(a -> a -> a) -> [a] -> a ")
+ '("foldr"            . "(a -> b -> b) -> b -> [a] -> b ")
+ '("foldr1"           . "(a -> a -> a) -> [a] -> a ")
+ '("fromEnum"         . "Enum a => a -> Int ")
+ '("fromInteger"      . "Num a => Integer -> a ")
+ '("fromIntegral"     . "(Integral a, Num b) => a -> b")
+ '("fromRational"     . "Fractional a => Rational -> a ")
+ '("fromRealFrac"     . "(RealFrac a, Fractional b) => a -> b")
+ '("fst"              . "(a, b) -> a")
+ '("gcd"              . "(Integral a) => a -> a -> a")
+ '("getChar"          . "IO Char ")
+ '("getContents"      . "IO String")
+ '("getLine"          . "IO Char ")
+ '("guard"            . "MonadZero m => Bool -> m ()")
+ '("head"             . "[a] -> a")
+ '("id"               . "a -> a")
+ '("init"             . "[a] -> [a]")
+ '("interact"         . "(String -> String) -> IO ()")
+ '("isDenormalized"   . "RealFloat a => a -> Bool ")
+ '("isIEEE"           . "RealFloat a => a -> Bool ")
+ '("isInfinite"       . "RealFloat a => a -> Bool ")
+ '("isNaN"            . "RealFloat a => a -> Bool ")
+ '("isNegativeZero"   . "RealFloat a => a -> Bool ")
+ '("iterate"          . "(a -> a) -> a -> [a] ")
+ '("last"             . "[a] -> a ")
+ '("lcm"              . "Integral a => a -> a -> a")
+ '("length"           . "[a] -> Int")
+ '("lex"              . "ReadS String ")
+ '("lines"            . "String -> [String]")
+ '("log"              . "Floating a => a -> a ")
+ '("logBase"          . "Floating a => a -> a -> a ")
+ '("lookup"           . "Eq a => a -> [(a, b)] -> Maybe b")
+ '("map"              . "Functor f => (a -> b) -> f a -> f b ")
+ '("mapM"             . "Monad m => (a -> m b) -> [a] -> m [b]")
+ '("mapM_"            . "Monad m => (a -> m b) -> [a] -> m ()")
+ '("max"              . "Ord a => a -> a -> a ")
+ '("maxBound"         . "Bounded a => a ")
+ '("maximum"          . "Ord a => [a] -> a")
+ '("maybe"            . "b -> (a -> b) -> Maybe a -> b ")
+ '("min"              . "Ord a => a -> a -> a ")
+ '("minBound"         . "Bounded a => a ")
+ '("minimum"          . "Ord a => [a] -> a")
+ '("mod"              . "Integral a => a -> a -> a ")
+ '("negate"           . "Num a => a -> a ")
+ '("not"              . "Bool -> Bool")
+ '("notElem"          . "Eq a => a -> [a] -> Bool")
+ '("null"             . "[a] -> Bool")
+ '("odd"              . "Integral a => a -> Bool")
+ '("or"               . "[Bool] -> Bool")
+ '("otherwise"        . "Bool")
+ '("pi"               . "Floating a => a ")
+ '("pred"             . "Enum a => a -> a ")
+ '("print"            . "Show a => IO () ")
+ '("product"          . "Num a => [a] -> a")
+ '("properFraction"   . "(RealFrac a, Integral b) => a -> (b, a) ")
+ '("putChar"          . "Char -> IO ()")
+ '("putStr"           . "String -> IO ()")
+ '("putStrLn"         . "String -> IO () ")
+ '("quot"             . "Integral a => a -> a -> a ")
+ '("quotRem"          . "Integral a => a -> a -> (a, a) ")
+ '("read"             . "Read a => String -> a")
+ '("readFile"         . "FilePath -> IO String")
+ '("readIO"           . "Read a => String -> IO a ")
+ '("readList"         . "Read a => ReadS [a]")
+ '("readLn"           . "Read a => IO a")
+ '("readParen"        . "Bool -> ReadS a -> ReadS a")
+ '("reads"            . "Read a => ReadS a ")
+ '("readsPrec"        . "Read a => Int -> ReadS a")
+ '("recip"            . "Fractional a => a -> a ")
+ '("rem"              . "Integral a => a -> a -> a ")
+ '("repeat"           . "a -> [a] ")
+ '("replicate"        . "Int -> a -> [a] ")
+ '("return"           . "Monad m => a -> m a ")
+ '("reverse"          . "[a] -> [a] ")
+ '("round"            . "(RealFrac a, Integral b) => a -> b ")
+ '("scaleFloat"       . "RealFloat a => Int -> a -> a ")
+ '("scanl"            . "(a -> b -> a) -> a -> [b] -> [a] ")
+ '("scanl1"           . "(a -> a -> a) -> [a] -> [a] ")
+ '("scanr"            . "(a -> b -> b) -> b -> [a] -> [b] ")
+ '("scanr1"           . "(a -> a -> a) -> [a] -> [a] ")
+ '("seq"              . "Eval a => a -> a -> b ")
+ '("sequence"         . "Monad m => [m a] -> m () ")
+ '("show"             . "Show a => a -> String ")
+ '("showChar"         . "Char -> ShowS")
+ '("showList"         . "Show a => [a] -> ShowS")
+ '("showParen"        . "Bool -> ShowS -> ShowS")
+ '("showString"       . "String -> ShowS")
+ '("shows"            . "Show a => a -> ShowS ")
+ '("showsPrec"        . "Show a => Int -> a -> ShowS ")
+ '("significand"      . "RealFloat a => a -> a ")
+ '("signum"           . "Num a => a -> a ")
+ '("sin"              . "Floating a => a -> a ")
+ '("sinh"             . "Floating a => a -> a ")
+ '("snd"              . "(a, b) -> b")
+ '("span"             . "(a -> Bool) -> [a] -> ([a], [a]) ")
+ '("splitAt"          . "Int -> [a] -> ([a], [a]) ")
+ '("sqrt"             . "Floating a => a -> a ")
+ '("strict"           . "Eval a => (a -> b) -> (a -> b) ")
+ '("subtract"         . "Num a => a -> a -> a")
+ '("succ"             . "Enum a => a -> a ")
+ '("sum"              . "Num a => [a] -> a ")
+ '("tail"             . "[a] -> [a] ")
+ '("take"             . "Int -> [a] -> [a] ")
+ '("takeWhile"        . "(a -> Bool) -> [a] -> [a] ")
+ '("tan"              . "Floating a => a -> a ")
+ '("tanh"             . "Floating a => a -> a ")
+ '("toEnum"           . "Enum a => Int -> a ")
+ '("toInteger"        . "Integral a => a -> Integer ")
+ '("toRational"       . "Real a => a -> Rational ")
+ '("truncate"         . "(RealFrac a, Integral b) => a -> b ")
+ '("uncurry"          . "(a -> b -> c) -> ((a, b) -> c)")
+ '("undefined"        . "a ")
+ '("unlines"          . "[String] -> String")
+ '("until"            . "(a -> Bool) -> (a -> a) -> a -> a ")
+ '("unwords"          . "[String] -> String")
+ '("unzip"            . "[(a, b)] -> ([a], [b]) ")
+ '("unzip3"           . "[(a, b, c)] -> ([a], [b], [c])")
+ '("userError"        . "String  -> IOError")
+ '("words"            . "String -> [String] ")
+ '("writeFile"        . "FilePath -> String -> IO ()")
+ '("zero"             . "MonadZero m => m a ")
+ '("zip"              . "[a] -> [b] -> [(a, b)] ")
+ '("zip3"             . "[a] -> [b] -> [c] -> [(a, b, c)]")
+ '("zipWith"          . "(a -> b -> c) -> [a] -> [b] -> [c] ")
+ '("zipWith3"         . "(a -> b -> c -> d) -> [a] -> [b] -> [c] -> [d]")
+ ;; ---------------------------------------------------------------------------
+ ;; The following functions are from the 1.4 Library Report (headers/ dir)
+ ;; headers/Ratio.hs
+ '("numerator"               . "(Integral a) => Ratio a -> a")
+ '("denominator"             . "(Integral a) => Ratio a -> a")
+ '("approxRational"          . "(RealFrac a) => a -> a -> Rational")
+ ;; headers/Complex.hs
+ '("realPart" . "(RealFloat a) => Complex a -> a")
+ '("imagPart" . "(RealFloat a) => Complex a -> a")
+ '("conjugate"	 . "(RealFloat a) => Complex a -> Complex a")
+ '("mkPolar"		 . "(RealFloat a) => a -> a -> Complex a")
+ '("cis"		 . "(RealFloat a) => a -> Complex a")
+ '("polar"		 . "(RealFloat a) => Complex a -> (a,a)")
+ '("magnitude" . "(RealFloat a) => Complex a -> a")
+ '("phase" . "(RealFloat a) => Complex a -> a")
+ ;; headers/Numeric.hs
+ '("fromRat" . "(RealFloat a) => Rational -> a")
+ '("fromRat'" . "(RealFloat a) => Rational -> a")
+ '("scaleRat" . "Rational -> Int -> Rational -> Rational -> Int -> Rational -> (Rational, Int)")
+ '("minExpt" . "Int")
+ '("maxExpt" . "Int")
+ '("expt" . "Integer -> Int -> Integer")
+ '("expts" . "Array Int Integer")
+ '("integerLogBase" . "Integer -> Integer -> Int")
+ '("showSigned"    . "Real a => (a -> ShowS) -> Int -> a -> ShowS")
+ '("showInt"    . "Integral a => a -> ShowS")
+ '("readSigned" . "(Real a) => ReadS a -> ReadS a")
+ '("readInt" . "(Integral a) => a -> (Char -> Bool) -> (Char -> Int) -> ReadS a")
+ '("readDec" . "(Integral a) => ReadS a")
+ '("readOct" . "(Integral a) => ReadS a")
+ '("readHex" . "(Integral a) => ReadS a")
+ '("showEFloat"     . "(RealFloat a) => Maybe Int -> a -> ShowS")
+ '("showFFloat"     . "(RealFloat a) => Maybe Int -> a -> ShowS")
+ '("showGFloat"     . "(RealFloat a) => Maybe Int -> a -> ShowS")
+ '("showFloat"      . "(RealFloat a) => a -> ShowS")
+ '("formatRealFloat" . "(RealFloat a) => FFFormat -> Maybe Int -> a -> String")
+ '("roundTo" . "Int -> Int -> [Int] -> (Int, [Int])")
+ '("floatToDigits" . "(RealFloat a) => Integer -> a -> ([Int], Int)")
+ '("readFloat"     . "(RealFloat a) => ReadS a")
+ '("lexDigits"        . "ReadS String ")
+ '("nonnull"          . "(Char -> Bool) -> ReadS String")
+ ;; headers/Ix.hs
+ '("rangeSize" . "Ix a => (a,a) -> Int")
+ ;; headers/Array.hs
+ '("array"           . "(Ix a) => (a,a) -> [(a,b)] -> Array a b")
+ '("listArray"       . "(Ix a) => (a,a) -> [b] -> Array a b")
+ ; '("(!)            . "(Ix a) => Array a b -> a -> b")
+ '("bounds"          . "(Ix a) => Array a b -> (a,a)")
+ '("indices"         . "(Ix a) => Array a b -> [a]")
+ '("elems"           . "(Ix a) => Array a b -> [b]")
+ '("assocs"          . "(Ix a) => Array a b -> [(a,b)]")
+ '("accumArray"      . "(Ix a) => (b -> c -> b) -> b -> (a,a) -> [(a,c)] -> Array a b")
+ ; (//)            . (Ix a) => Array a b -> [(a,b)] -> Array a b
+ '("accum"           . "(Ix a) => (b -> c -> b) -> Array a b -> [(a,c)] -> Array a b")
+ '("ixmap"           . "(Ix a, Ix b) => (a,a) -> (a -> b) -> Array b c -> Array a c")
+ ;; headers/List.hs (omitted; see 1.2 List module above)
+ ;; headers/Maybe.hs
+ '("isJust"                 . "Maybe a -> Bool")
+ '("fromJust"               . "Maybe a -> a")
+ '("fromMaybe"              . "a -> Maybe a -> a")
+ '("maybeToList"            . "Maybe a -> [a]")
+ '("listToMaybe"            . "[a] -> Maybe a")
+ '("catMaybes"              . "[Maybe a] -> [a]")
+ '("mapMaybe"               . "(a -> Maybe b) -> [a] -> [b]")
+ '("unfoldr"                . "([a] -> Maybe ([a], a)) -> [a] -> ([a],[a])")
+ ;; headers/Char.hs
+ '("isAscii" . "Char -> Bool")
+ '("isControl" . "Char -> Bool")
+ '("isPrint" . "Char -> Bool")
+ '("isSpace" . "Char -> Bool")
+ '("isUpper" . "Char -> Bool")
+ '("isLower" . "Char -> Bool")
+ '("isAlpha" . "Char -> Bool")
+ '("isDigit" . "Char -> Bool")
+ '("isOctDigit" . "Char -> Bool")
+ '("isHexDigit" . "Char -> Bool")
+ '("isAlphanum" . "Char -> Bool")
+ '("digitToInt" . "Char -> Int")
+ '("intToDigit" . "Int -> Char")
+ '("toUpper"                  . "Char -> Char")
+ '("toLower"                  . "Char -> Char")
+ '("ord"                     . "Char -> Int")
+ '("chr"                     . "Int  -> Char")
+ '("readLitChar"             . "ReadS Char")
+ '("sshowLitChar"               . "Char -> ShowS")
+ '("lexLitChar"          . "ReadS String")
+ ;; headers/Monad.hs
+ '("unless"           . "(Monad m) => Bool -> m () -> m ()")
+ '("ap"               . "(Monad m) => m (a -> b) -> m a -> m b")
+ '("liftM"            . "(Monad m) => (a -> b) -> (m a -> m b)")
+ '("liftM2"           . "(Monad m) => (a -> b -> c) -> (m a -> m b -> m c)")
+ '("liftM3"           . "(Monad m) => (a -> b -> c -> d) -> (m a -> m b -> m c -> m d)")
+ '("liftM4"           . "(Monad m) => (a -> b -> c -> d -> e) -> (m a -> m b -> m c -> m d -> m e)")
+ '("liftM5"           . "(Monad m) => (a -> b -> c -> d -> e -> f) -> (m a -> m b -> m c -> m d -> m e -> m f)")
+ ;; headers/IO.hs
+; '("try"            . "IO a -> IO (Either IOError a)")
+; '("bracket"        . "IO a -> (a -> IO b) -> (a -> IO c) -> IO c")
+; '("bracket_"        . "IO a -> (a -> IO b) -> IO c -> IO c")
+ ;; Directory
+; '("createDirectory"  . "FilePath -> IO ()")
+; '("removeDirectory"  . "FilePath -> IO ()")
+; '("removeFile"  . "FilePath -> IO ()")
+; '("renameDirectory"  . "FilePath -> FilePath -> IO ()")
+; '("renameFile"  . "FilePath -> FilePath -> IO ()")
+; '("getDirectoryContents"  . "FilePath -> IO [FilePath]")
+; '("getCurrentDirectory"  . "IO FilePath")
+; '("setCurrentDirectory"  . "FilePath -> IO ()")
+; '("doesFileExist" . "FilePath -> IO Bool")
+; '("doesDirectoryExist" . "FilePath -> IO Bool")
+; '("getPermissions" . "FilePath -> IO Permissions")
+; '("setPermissions" . "FilePath -> Permissions -> IO ()")
+; '("getModificationTime" . "FilePath -> IO ClockTime")
+ ;; System
+; '("getArgs"  . "IO [String]")
+; '("getProgName"  . "IO String")
+; '("getEnv"         . "String -> IO String")
+; '("system"         . "String -> IO ExitCode")
+; '("exitWith"    . "ExitCode -> IO a")
+ ;; headers/Time.hs
+ '("getClockTime"            . "IO ClockTime")
+ '("addToClockTime"          . "TimeDiff     -> ClockTime -> ClockTime")
+ '("diffClockTimes"          . "ClockTime    -> ClockTime -> TimeDiff")
+ '("toCalendarTime"          . "ClockTime    -> IO CalendarTime")
+ '("toUTCTime"               . "ClockTime    -> CalendarTime")
+ '("toClockTime"             . "CalendarTime -> ClockTime")
+ '("calendarTimeToString"    . "CalendarTime -> String")
+ '("formatCalendarTime" . "TimeLocale -> String -> CalendarTime -> String")
+ '("show2" . "Int -> String")
+ '("show2'" . "Int -> String")
+ '("show3" . "Int -> String")
+ ;; headers/Locale.hs
+ '("defaultTimeLocale" . "TimeLocale ")
+ ;; headers/Random.hs
+ '("random"    . "(Integer,Integer) -> Integer -> [Integer]")
+ '("randomIO"  . "(Integer,Integer) -> IO [Integer]")
+ )
+"alist of prelude functions and their types.")
+
+;@cindex haskell-doc-strategy-ids
+
+(defvar haskell-doc-strategy-ids
+ (list
+  '("par"  . "Done -> Done -> Done ; [infixr 0]")
+  '("seq"  . "Done -> Done -> Done ; [infixr 1]")
+
+  '("using"      . "a -> Strategy a -> a ; [infixl 0]")
+  '("demanding"  . "a -> Done -> a ; [infixl 0]")
+  '("sparking"   . "a -> Done -> a ; [infixl 0]")
+
+  '(">||" . "Done -> Done -> Done ; [infixr 2]")
+  '(">|" .  "Done -> Done -> Done ; [infixr 3]")
+  '("$||" . "(a -> b) -> Strategy a -> a -> b ; [infixl 6]")
+  '("$|"  . "(a -> b) -> Strategy a -> a -> b ; [infixl 6]")
+  '(".|"  . "(b -> c) -> Strategy b -> (a -> b) -> (a -> c) ; [infixl 9]")
+  '(".||" . "(b -> c) -> Strategy b -> (a -> b) -> (a -> c) ; [infixl 9]")
+  '("-|"  . "(a -> b) -> Strategy b -> (b -> c) -> (a -> c) ; [infixl 9]")
+  '("-||" . "(a -> b) -> Strategy b -> (b -> c) -> (a -> c) ; [infixl 9]")
+
+  '("Done" . "type Done = ()")
+  '("Strategy" . "type Strategy a = a -> Done")
+
+  '("r0"    . "Strategy a")
+  '("rwhnf" . "Eval a => Strategy a")
+  '("rnf" . "Strategy a")
+  '("NFData" . "class Eval a => NFData a where rnf :: Strategy a")
+  '("NFDataIntegral" ."class (NFData a, Integral a) => NFDataIntegral a")
+  '("NFDataOrd" . "class (NFData a, Ord a) => NFDataOrd a")
+
+  '("markStrat" . "Int -> Strategy a -> Strategy a")
+
+  '("seqPair" . "Strategy a -> Strategy b -> Strategy (a,b)")
+  '("parPair" . "Strategy a -> Strategy b -> Strategy (a,b)")
+  '("seqTriple" . "Strategy a -> Strategy b -> Strategy c -> Strategy (a,b,c)")
+  '("parTriple" . "Strategy a -> Strategy b -> Strategy c -> Strategy (a,b,c)")
+
+  '("parList"  . "Strategy a -> Strategy [a]")
+  '("parListN"  . "(Integral b) => b -> Strategy a -> Strategy [a]")
+  '("parListNth"  . "Int -> Strategy a -> Strategy [a]")
+  '("parListChunk"  . "Int -> Strategy a -> Strategy [a]")
+  '("parMap"  . "Strategy b -> (a -> b) -> [a] -> [b]")
+  '("parFlatMap"  . "Strategy [b] -> (a -> [b]) -> [a] -> [b]")
+  '("parZipWith"  . "Strategy c -> (a -> b -> c) -> [a] -> [b] -> [c]")
+  '("seqList"  . "Strategy a -> Strategy [a]")
+  '("seqListN"  . "(Integral a) => a -> Strategy b -> Strategy [b]")
+  '("seqListNth"  . "Int -> Strategy b -> Strategy [b]")
+
+  '("parBuffer"  . "Int -> Strategy a -> [a] -> [a]")
+
+  '("seqArr"  . "(Ix b) => Strategy a -> Strategy (Array b a)")
+  '("parArr"  . "(Ix b) => Strategy a -> Strategy (Array b a)")
+
+  '("fstPairFstList"  . "(NFData a) => Strategy [(a,b)]")
+  '("force"  . "(NFData a) => a -> a ")
+  '("sforce"  . "(NFData a) => a -> b -> b")
+  )
+"alist of strategy functions and their types as defined in Strategies.lhs.")
+
+(defvar haskell-doc-user-defined-ids nil
+ "alist of functions and strings defined by the user.")
+
+;@node Test membership,  , Prelude types, Constants and Variables
+;@subsection Test membership
+
+;@cindex haskell-doc-is-of
+(defsubst haskell-doc-is-of (fn types)
+  "Check whether FN is one of the functions in the alist TYPES and return the type."
+  (assoc fn types) )
+
+;@node Install as minor mode, Menubar Support, Constants and Variables, top
+;@section Install as minor mode
+
+;; Put this minor mode on the global minor-mode-alist.
+(or (assq 'haskell-doc-mode (default-value 'minor-mode-alist))
+    (setq-default minor-mode-alist
+                  (append (default-value 'minor-mode-alist)
+                          '((haskell-doc-mode haskell-doc-minor-mode-string)))))
+
+;; In emacs 19.29 and later, and XEmacs 19.13 and later, all messages are
+;; recorded in a log.  Do not put haskell-doc messages in that log since
+;; they are Legion.
+
+;@cindex haskell-doc-message
+
+(defmacro haskell-doc-message (&rest args)
+  (if (fboundp 'display-message)
+      ;; XEmacs 19.13 way of preventing log messages.
+      ;(list 'display-message '(quote no-log) (apply 'list 'format args))
+      ;; XEmacs 19.15 seems to be a bit different
+      (list 'display-message '(quote message) (apply 'list 'format args))
+    (list 'let (list (list 'message-log-max 'nil))
+          (apply 'list 'message args))))
+
+
+;@node Menubar Support, Haskell Doc Mode, Install as minor mode, top
+;@section Menubar Support
+
+; a dummy definition needed for xemacs (I know, it's horrible :-(
+(if (and (string-match "XEmacs" emacs-version)
+	 (not (functionp 'define-key-after)))
+  (defun define-key-after (map seq con name)))
+
+;@cindex haskell-doc-install-keymap
+
+(defun haskell-doc-install-keymap ()
+  "Install a menu for `haskell-doc-mode' as a submenu of \"Hugs\"."
+ (interactive)
+ ; define a keymap `haskell-doc-keymap' for the derive menu
+ (if nil ; (keymapp haskell-doc-keymap)
+       nil
+     (setq haskell-doc-keymap (make-sparse-keymap))
+     (define-key haskell-doc-keymap [visit]
+       '("Visit FTP home site" . haskell-doc-visit-home))
+     (define-key haskell-doc-keymap [submit]
+       '("Submit bug report" . haskell-doc-submit-bug-report))
+     (define-key haskell-doc-keymap [dummy]
+       '("---" . nil))
+     (define-key haskell-doc-keymap [make-index]
+       '("Make global fct index" . haskell-doc-make-global-fct-index))
+     (define-key haskell-doc-keymap [global-types-on]
+       '("Toggle display of global types" . haskell-doc-show-global-types))
+     (define-key haskell-doc-keymap [strategy-on]
+       '("Toggle display of strategy ids" . haskell-doc-show-strategy))
+     (define-key haskell-doc-keymap [user-defined-on]
+       '("Toggle display of user defined ids" . haskell-doc-show-user-defined))
+     (define-key haskell-doc-keymap [prelude-on]
+       '("Toggle display of prelude functions" . haskell-doc-show-prelude))
+     (define-key haskell-doc-keymap [reserved-ids-on]
+       '("Toggle display of reserved ids" . haskell-doc-show-reserved))
+     (define-key haskell-doc-keymap [haskell-doc-on]
+       '("Toggle haskell-doc mode" . haskell-doc-mode))
+  )
+
+ ; add the menu to the hugs menu as last entry
+ (cond 
+  ((eq major-mode 'haskell-hugs-mode)
+   (let ((hugsmap (lookup-key haskell-hugs-mode-map [menu-bar Hugs])))
+	 (if (and (not haskell-doc-xemacs-p) ; XEmacs has problems here
+		  (not (lookup-key hugsmap [haskell-doc])))
+	     (define-key-after hugsmap [haskell-doc] (cons "Haskell-doc" haskell-doc-keymap)
+	       [Haskell-doc mode]))
+     ; add shortcuts for these commands
+     (define-key haskell-hugs-mode-map "\C-c\e/" 'haskell-doc-check-active) ; for testing 
+     (define-key haskell-hugs-mode-map "\C-c\C-o" 'haskell-doc-mode) 
+     (if (not haskell-doc-xemacs-p) 
+	 (define-key haskell-hugs-mode-map [C-S-M-mouse-3] 'haskell-doc-ask-mouse-for-type))))
+  ((eq major-mode 'haskell-mode)
+   ; add shortcuts for these commands
+   (local-set-key "\C-c\e/" 'haskell-doc-check-active) ; for testing 
+   (local-set-key "\C-c\C-o" 'haskell-doc-mode) 
+   (if (not haskell-doc-xemacs-p)
+       (local-set-key [C-S-M-mouse-3] 'haskell-doc-ask-mouse-for-type)) ) ))
+
+
+;@node Haskell Doc Mode, Switch it on or off, Menubar Support, top
+;@section Haskell Doc Mode
+
+;@cindex haskell-doc-mode
+
+;;;###autoload
+(defun haskell-doc-mode (&optional prefix)
+  "Enter `haskell-doc-mode' for showing fct types in the echo area.
+See variable docstring."
+  (interactive "P")
+
+  ;; Make sure it's on the post-command-idle-hook if defined, otherwise put
+  ;; it on post-command-hook.  The former first appeared in Emacs 19.30.
+  (setq haskell-doc-mode
+  	 (if prefix
+  	     (or (listp prefix);; C-u alone
+  		 (> (prefix-numeric-value prefix) 0))
+  	   (not haskell-doc-mode)))
+
+  (and haskell-doc-mode-hook
+       haskell-doc-mode
+       (run-hooks 'haskell-doc-mode-hook))
+
+  ;; ToDo: replace binding of `post-command-idle-hook' by `run-with-idle-timer'
+  (and haskell-doc-mode
+       (not (memq 'haskell-doc-mode-print-current-symbol-info 
+		  (if (boundp 'post-command-idle-hook)
+		     post-command-idle-hook
+		   post-command-hook)))
+       (add-hook (if (boundp 'post-command-idle-hook)
+		     'post-command-idle-hook
+		   'post-command-hook)
+		 'haskell-doc-mode-print-current-symbol-info))
+
+  (and (not haskell-doc-mode)
+       (memq 'haskell-doc-mode-print-current-symbol-info 
+	     (if (boundp 'post-command-idle-hook)
+			post-command-idle-hook
+		   post-command-hook))
+       (remove-hook (if (boundp 'post-command-idle-hook)
+			'post-command-idle-hook
+		   'post-command-hook)
+		 'haskell-doc-mode-print-current-symbol-info))
+
+  (and haskell-doc-mode
+       haskell-doc-show-global-types
+       (progn
+	 (setq haskell-doc-minor-mode-string " Haskell-DOC")
+	 (haskell-doc-make-global-fct-index))  ; build type index for global fcts
+       (setq haskell-doc-minor-mode-string " Haskell-Doc"))
+
+  (if haskell-doc-mode
+      (haskell-doc-install-keymap))
+
+  (and (interactive-p)
+       (if haskell-doc-mode
+           (message "haskell-doc-mode is enabled")
+         (message "haskell-doc-mode is disabled")))
+  haskell-doc-mode)
+
+;;@cindex haskell-doc-show-global-types
+
+;;;;###autoload
+;(defun haskell-doc-show-global-types (&optional prefix)
+;  "*If non-nil, then enable display of global types in `haskell-doc-mode'."
+;  (interactive "P")
+;  ;; toggle mode or set it based on prefix value
+;  (setq haskell-doc-show-global-types
+;	(if prefix
+;	    (>= (prefix-numeric-value prefix) 0)
+;	  (not haskell-doc-show-global-types)))
+
+;  (cond (haskell-doc-show-global-types
+;	 ;; set mode string to reflect value of `haskell-doc-show-global-types'
+;	 (setq haskell-doc-minor-mode-string " Haskell-DOC")
+;	 ;; build index (note: this can be quite expensive)
+;	 (haskell-doc-make-global-fct-index))
+;	(t
+;	 (setq haskell-doc-minor-mode-string " Haskell-Doc")) ) )
+
+
+(defmacro haskell-doc-toggle-var (id prefix)
+  ;; toggle variable or set it based on prefix value
+  (setq id
+	(if prefix
+	    (>= (prefix-numeric-value prefix) 0)
+	  (not id))) )
+
+;@cindex haskell-doc-show-global-types
+(defun haskell-doc-show-global-types (&optional prefix)
+  "Turn on global types information in `haskell-doc-mode'."
+  (interactive "P")
+  (haskell-doc-toggle-var haskell-doc-show-global-types prefix)
+  (if haskell-doc-show-global-types
+      (setq haskell-doc-minor-mode-string " Haskell-DOC")
+    (setq haskell-doc-minor-mode-string " Haskell-Doc")) )
+
+;@cindex haskell-doc-show-reserved
+(defun haskell-doc-show-reserved (&optional prefix)
+  "Toggle the automatic display of a doc string for reserved ids."
+  (interactive "P")
+  (haskell-doc-toggle-var haskell-doc-show-reserved prefix))
+
+;@cindex haskell-doc-show-prelude
+(defun haskell-doc-show-prelude (&optional prefix)
+  "Toggle the automatic display of a doc string for reserved ids."
+  (interactive "P")
+  (haskell-doc-toggle-var haskell-doc-show-prelude prefix))
+
+;@cindex haskell-doc-show-strategy
+(defun haskell-doc-show-strategy (&optional prefix)
+  "Toggle the automatic display of a doc string for strategy ids."
+  (interactive "P")
+  (haskell-doc-toggle-var haskell-doc-show-strategy prefix))
+
+;@cindex haskell-doc-show-user-defined
+(defun haskell-doc-show-user-defined (&optional prefix)
+  "Toggle the automatic display of a doc string for user defined ids."
+  (interactive "P")
+  (haskell-doc-toggle-var haskell-doc-show-user-defined prefix))
+
+;@node Switch it on or off, Check, Haskell Doc Mode, top
+;@section Switch it on or off
+
+;@cindex turn-on-haskell-doc-mode
+
+;;;###autoload
+(defun turn-on-haskell-doc-mode ()
+  "Unequivocally turn on `haskell-doc-mode' (see variable documentation)."
+  (interactive)
+  (haskell-doc-mode 1))
+
+;@cindex  turn-off-haskell-doc-mode
+
+;;;###autoload
+(defun turn-off-haskell-doc-mode ()
+  "Unequivocally turn off `haskell-doc-mode' (see variable documentation)."
+  (interactive)
+  (haskell-doc-mode 0))
+
+;@node Check, Top level function, Switch it on or off, top
+;@section Check
+
+;@cindex haskell-doc-check-active
+
+(defun haskell-doc-check-active ()
+ "Check whether the print function is hooked in. 
+Should be the same as the value of `haskell-doc-mode' but alas currently it 
+is not."
+ (interactive)
+ (message 
+  (if (memq 'haskell-doc-mode-print-current-symbol-info 
+	    (if (boundp 'post-command-idle-hook)
+		post-command-idle-hook
+	      post-command-hook))
+      "haskell-doc is ACTIVE"
+    "haskell-doc is not ACTIVE \(Use C-u C-c C-o to turn it on\)")))
+
+;@node Top level function, Mouse interface, Check, top
+;@section Top level function
+
+;@cindex haskell-doc-mode-print-current-symbol-info
+;; This is the function hooked into the elisp command engine
+(defun haskell-doc-mode-print-current-symbol-info ()
+ "Print the type of the symbol under the cursor. 
+
+This function is hooked into the `post-command-idle-hook' to print the type
+automatically if `haskell-doc-mode' is turned on. It can also be called 
+directly to ask for the type of a function."
+  (interactive)
+  (and haskell-doc-mode
+       (not executing-kbd-macro)
+       ;; Having this mode operate in the minibuffer makes it impossible to
+       ;; see what you're doing.
+       (not (eq (selected-window) (minibuffer-window)))
+       ; take a nap
+       (sit-for haskell-doc-idle-delay)
+       ; good morning! read the word under the cursor for breakfast
+       (let ((current-symbol (haskell-doc-get-current-word)) ); (haskell-doc-current-symbol)) )
+             ; (current-fnsym  (haskell-doc-fnsym-in-current-sexp)))
+	 (haskell-doc-show-type current-symbol)) ))
+
+;	 ; ToDo: find surrounding fct
+;         (cond ((eq current-symbol current-fnsym)
+;                (haskell-doc-show-type current-fnsym))
+;               (t
+;                (or nil ; (haskell-doc-print-var-docstring current-symbol)
+;                    (haskell-doc-show-type current-fnsym)))))))
+
+
+;@node Mouse interface, Print fctsym, Top level function, top
+;@section Mouse interface for interactive query
+
+;@cindex haskell-doc-ask-mouse-for-type
+(defun haskell-doc-ask-mouse-for-type (event)
+ "Read the identifier under the mouse and echo its type.
+This uses the same underlying function `haskell-doc-show-type' as the hooked
+function. Only the user interface is different."
+ (interactive "e")
+ (save-excursion
+   (select-window (posn-window (event-end event)))
+   (goto-char (posn-point (event-end event)))
+   (haskell-doc-show-type )))
+ 
+
+;@node Print fctsym, Movement, Mouse interface, top
+;@section Print fctsym
+
+;@menu
+;* Show type::			
+;* Aux::			
+;* Global fct type::		
+;* Local fct type::		
+;@end menu
+
+;@node Show type, Aux, Print fctsym, Print fctsym
+;@subsection Show type
+
+;@cindex haskell-doc-show-type
+
+;;;###autoload
+(defun haskell-doc-show-type (&optional symbol)
+  "Show the type of the function near point.
+For the function under point, show the type in the echo area.
+This information is extracted from the `haskell-doc-prelude-types' alist
+of prelude functions and their types, or from the local functions in the
+current buffer."
+  (interactive)
+  (let* ((sym (or symbol (haskell-doc-get-current-word))) 
+	; (haskell-doc-current-symbol))); (haskell-doc-fnsym-in-current-sexp)))
+        (printit t)
+        (i-am-prelude nil)
+        (i-am-fct nil)
+        (type nil)
+	(is-reserved (haskell-doc-is-of sym haskell-doc-reserved-ids))
+	(is-prelude  (haskell-doc-is-of sym haskell-doc-prelude-types))
+	(is-strategy (haskell-doc-is-of sym haskell-doc-strategy-ids))
+	(is-user-defined (haskell-doc-is-of sym haskell-doc-user-defined-ids))
+	(is-prelude  (haskell-doc-is-of sym haskell-doc-prelude-types)))
+   (cond
+	  ;; if printed before do not print it again
+          ((string= sym (car haskell-doc-last-data))
+           (setq printit nil)
+           (setq type (cdr haskell-doc-last-data)))
+	  ;; if reserved id (i.e. Haskell keyword
+	  ((and haskell-doc-show-reserved
+	       is-reserved)
+	   (setq type (cdr is-reserved))
+           (setcdr haskell-doc-last-data type))
+	  ;; if built-in function get type from docstring
+          ((and (not (null haskell-doc-show-prelude))
+		is-prelude)
+           (setq type (cdr is-prelude)) ; (cdr (assoc sym haskell-doc-prelude-types)))
+	   (if (= 2 (length type)) ; horrible hack to remove bad formatting
+	       (setq type (car (cdr type))))
+	   (setq i-am-prelude t)
+	   (setq i-am-fct t)
+           (setcdr haskell-doc-last-data type))
+	  ((and haskell-doc-show-strategy
+	       is-strategy)
+	   (setq i-am-fct t)
+	   (setq type (cdr is-strategy))
+           (setcdr haskell-doc-last-data type))
+	  ((and haskell-doc-show-user-defined
+	       is-user-defined)
+	   ; (setq i-am-fct t)
+	   (setq type (cdr is-user-defined))
+           (setcdr haskell-doc-last-data type))
+          (t
+	   (let ( (x (haskell-doc-get-and-format-fct-type sym)) )
+	     (if (null x)
+		 (setcdr haskell-doc-last-data nil) ; if not found reset last data
+	       (setq type (car x))
+	       (setq i-am-fct (string= "Variables" (cdr x)))
+	       (if (and haskell-doc-show-global-types (null type))
+		   (setq type (haskell-doc-get-global-fct-type sym)))
+	       (setcdr haskell-doc-last-data type)))) )
+    ;; ToDo: encode i-am-fct info into alist of types
+    (and type
+         printit
+	 ; drop `::' if it's not a fct
+	 (let ( (str (cond ((and i-am-fct (not haskell-doc-chop-off-fctname))
+			    (format "%s :: %s" sym type))
+			   (t 
+			    (format "%s" type)))) )
+	   (if i-am-prelude
+	       (add-text-properties 0 (1- (length str)) '(face bold) str))
+	   (haskell-doc-message str)))) )
+
+
+;; ToDo: define your own notion of `near' to find surrounding fct
+;(defun haskell-doc-fnsym-in-current-sexp ()
+;  (let* ((p (point))
+;         (sym (progn
+;		(forward-word -1)
+;;                (while (and (forward-word -1) ; (haskell-doc-forward-sexp-safe -1)
+;;                            (> (point) (point-min))))
+;                (cond ((or (= (point) (point-min))
+;                           (memq (or (char-after (point)) 0)
+;                                 '(?\( ?\"))
+;                           ;; If we hit a quotation mark before a paren, we
+;                           ;; are inside a specific string, not a list of
+;                           ;; symbols.
+;                           (eq (or (char-after (1- (point))) 0) ?\"))
+;                       nil)
+;                      (t (condition-case nil
+;                             (read (current-buffer))
+;                           (error nil)))))))
+;    (goto-char p)
+;    (if sym
+;	(format "%s" sym)
+;      sym) ) )
+
+;;    (and (symbolp sym)
+;;         sym)))
+
+;@node Aux, Global fct type, Show type, Print fctsym
+;@subsection Aux
+
+;; ToDo: handle open brackets to decide if it's a wrapped type
+
+;@cindex haskell-doc-grab-line
+(defun haskell-doc-grab-line (fct-and-pos)
+ "Get the type of an \(FCT POSITION\) pair from the current buffer."
+; (if (null fct-and-pos)
+;     "" ; fn is not a local fct
+  (let ( (str ""))
+   (goto-char (cdr fct-and-pos))
+   (beginning-of-line)
+   ;; search for start of type (phsp give better bound?)
+   (if (null (search-forward "::" (+ (point) haskell-doc-search-distance) t))
+       ""
+     (setq str (haskell-doc-grab))        ; leaves point at end of line
+     (while (haskell-doc-wrapped-type-p)  ; while in a multi-line type expr
+       (forward-line 1)
+       (beginning-of-line)
+       (skip-chars-forward " \t")
+       (setq str (concat str (haskell-doc-grab))))
+     (haskell-doc-string-nub-ws           ; squeeze string
+      (if haskell-doc-chop-off-context    ; no context 
+	  (haskell-doc-chop-off-context str)
+	str)))))
+  ; (concat (car fct-and-pos) "::" (haskell-doc-string-nub-ws str))))
+
+;@cindex haskell-doc-wrapped-type-p
+(defun haskell-doc-wrapped-typ