|
|
;;; haskell-doc.el --- show function types in echo area -*- coding: utf-8; lexical-binding: t -*- |
|
|
|
|
|
;; Copyright (C) 2004, 2005, 2006, 2007, 2009 Free Software Foundation, Inc. |
|
|
;; Copyright (C) 1997 Hans-Wolfgang Loidl |
|
|
|
|
|
;; Author: 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 |
|
|
;; URL: http://cvs.haskell.org/cgi-bin/cvsweb.cgi/fptools/CONTRIB/haskell-modes/emacs/haskell-doc.el?rev=HEAD |
|
|
|
|
|
;; This file is not part of GNU Emacs. |
|
|
|
|
|
;; 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 3, 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, see <http://www.gnu.org/licenses/>. |
|
|
|
|
|
;;; 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. |
|
|
|
|
|
;; This program was inspired by the `eldoc.el' package by Noah Friedman. |
|
|
|
|
|
;; Installation: |
|
|
|
|
|
;; Depending on the major mode you use for your Haskell programs add |
|
|
;; one of the following to your .emacs: |
|
|
;; |
|
|
;; (add-hook 'haskell-mode-hook 'haskell-doc-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: t) |
|
|
;; `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 haskell-doc-mode |
|
|
|
|
|
;; These are the names of the functions that can be called directly by the |
|
|
;; user (with keybindings in `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; |
|
|
;; Key: CTRL-c ESC-/ |
|
|
|
|
|
;; ToDo: |
|
|
|
|
|
;; - Fix byte-compile problems in `haskell-doc-prelude-types' for getArgs etc |
|
|
;; - Write a parser for .hi files. Read library interfaces via this parser. |
|
|
;; - Indicate kind of object with colours |
|
|
;; - Handle multi-line types |
|
|
;; - Encode i-am-fct info in the alist of ids and types. |
|
|
|
|
|
;; 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: haskell-doc.el,v $ |
|
|
;; Revision 1.31 2015/07/23 10:34:20 ankhers |
|
|
;; (turn-on-haskell-doc-mode): marked obsolete |
|
|
;; (turn-on-haskell-doc): marked obsolete |
|
|
;; other packages have been moving away from (turn-on-haskell-*) |
|
|
;; |
|
|
;; Revision 1.30 2009/02/02 21:00:33 monnier |
|
|
;; (haskell-doc-imported-list): Don't add current buffer |
|
|
;; to the imported file list if it is not (yet?) visiting a file. |
|
|
;; |
|
|
;; Revision 1.29 2007-12-12 04:04:19 monnier |
|
|
;; (haskell-doc-in-code-p): New function. |
|
|
;; (haskell-doc-show-type): Use it. |
|
|
;; |
|
|
;; Revision 1.28 2007/08/30 03:10:08 monnier |
|
|
;; Comment/docs fixes. |
|
|
;; |
|
|
;; Revision 1.27 2007/07/30 17:36:50 monnier |
|
|
;; (displayed-month): Remove declaration since it's not used here. |
|
|
;; |
|
|
;; Revision 1.26 2007/02/10 06:28:55 monnier |
|
|
;; (haskell-doc-get-current-word): Remove. |
|
|
;; Change all refs to it, to use haskell-ident-at-point instead. |
|
|
;; |
|
|
;; Revision 1.25 2007/02/09 21:53:42 monnier |
|
|
;; (haskell-doc-get-current-word): Correctly distinguish |
|
|
;; variable identifiers and infix identifiers. |
|
|
;; (haskell-doc-rescan-files): Avoid switch-to-buffer. |
|
|
;; (haskell-doc-imported-list): Operate on current buffer. |
|
|
;; (haskell-doc-make-global-fct-index): Adjust call. |
|
|
;; |
|
|
;; Revision 1.24 2006/11/20 20:18:24 monnier |
|
|
;; (haskell-doc-mode-print-current-symbol-info): Fix thinko. |
|
|
;; |
|
|
;; Revision 1.23 2006/10/20 03:12:31 monnier |
|
|
;; Drop post-command-idle-hook in favor of run-with-idle-timer. |
|
|
;; (haskell-doc-timer, haskell-doc-buffers): New vars. |
|
|
;; (haskell-doc-mode): Use them. |
|
|
;; (haskell-doc-check-active): Update the check. |
|
|
;; (haskell-doc-mode-print-current-symbol-info): Remove the interactive spec. |
|
|
;; Don't sit-for unless it's really needed. |
|
|
;; |
|
|
;; Revision 1.22 2006/09/20 18:42:35 monnier |
|
|
;; Doc fix. |
|
|
;; |
|
|
;; Revision 1.21 2005/11/21 21:48:52 monnier |
|
|
;; * haskell-doc.el (haskell-doc-extract-types): Get labelled data working. |
|
|
;; (haskell-doc-prelude-types): Update via auto-generation. |
|
|
;; |
|
|
;; * haskell-doc.el (haskell-doc-extract-types): Get it partly working. |
|
|
;; (haskell-doc-fetch-lib-urls): Don't use a literal if we apply |
|
|
;; `nreverse' on it later on. |
|
|
;; (haskell-doc-prelude-types): Update some parts by auto-generation. |
|
|
;; (haskell-doc-grab, haskell-doc-string-nub-ws): Simplify. |
|
|
;; |
|
|
;; * haskell-doc.el (haskell-doc-maintainer, haskell-doc-varlist) |
|
|
;; (haskell-doc-submit-bug-report, haskell-doc-ftp-site) |
|
|
;; (haskell-doc-visit-home): Remove. |
|
|
;; (haskell-doc-reserved-ids, haskell-doc-fetch-lib-urls) |
|
|
;; (haskell-doc-extract-and-insert-types): New funs. |
|
|
;; (haskell-doc-reserved-ids): Fix type of `map'. |
|
|
;; |
|
|
;; Revision 1.20 2005/11/21 21:27:57 monnier |
|
|
;; (haskell-doc-extract-types): Get labelled data working. |
|
|
;; (haskell-doc-prelude-types): Update via auto-generation. |
|
|
;; |
|
|
;; Revision 1.19 2005/11/21 20:44:13 monnier |
|
|
;; (haskell-doc-extract-types): Get it partly working. |
|
|
;; (haskell-doc-fetch-lib-urls): Don't use a literal if we apply |
|
|
;; `nreverse' on it later on. |
|
|
;; (haskell-doc-prelude-types): Update some parts by auto-generation. |
|
|
;; (haskell-doc-grab, haskell-doc-string-nub-ws): Simplify. |
|
|
;; |
|
|
;; Revision 1.18 2005/11/21 18:02:15 monnier |
|
|
;; (haskell-doc-maintainer, haskell-doc-varlist) |
|
|
;; (haskell-doc-submit-bug-report, haskell-doc-ftp-site) |
|
|
;; (haskell-doc-visit-home): Remove. |
|
|
;; (haskell-doc-reserved-ids, haskell-doc-fetch-lib-urls) |
|
|
;; (haskell-doc-extract-and-insert-types): New funs. |
|
|
;; (haskell-doc-reserved-ids): Fix type of `map'. |
|
|
;; |
|
|
;; Revision 1.17 2005/11/20 23:55:09 monnier |
|
|
;; Add coding cookie. |
|
|
;; |
|
|
;; Revision 1.16 2005/11/07 01:28:16 monnier |
|
|
;; (haskell-doc-xemacs-p, haskell-doc-emacs-p) |
|
|
;; (haskell-doc-message): Remove. |
|
|
;; (haskell-doc-is-id-char-at): Remove. |
|
|
;; (haskell-doc-get-current-word): Rewrite. |
|
|
;; |
|
|
;; Revision 1.15 2005/11/04 17:11:12 monnier |
|
|
;; Add arch-tag. |
|
|
;; |
|
|
;; Revision 1.14 2005/08/24 11:36:32 monnier |
|
|
;; (haskell-doc-message): Paren typo. |
|
|
;; |
|
|
;; Revision 1.13 2005/08/23 19:23:27 monnier |
|
|
;; (haskell-doc-show-type): Assume that the availability |
|
|
;; of display-message won't change at runtime. |
|
|
;; |
|
|
;; Revision 1.12 2005/07/18 21:04:14 monnier |
|
|
;; (haskell-doc-message): Remove. |
|
|
;; (haskell-doc-show-type): inline it. Do nothing for if there's no doc to show. |
|
|
;; |
|
|
;; Revision 1.11 2004/12/10 17:33:18 monnier |
|
|
;; (haskell-doc-minor-mode-string): Make it dynamic. |
|
|
;; (haskell-doc-install-keymap): Remove conflicting C-c C-o binding. |
|
|
;; (haskell-doc-mode): Make a nil arg turn the mode ON. |
|
|
;; (turn-on-haskell-doc-mode): Make it an alias for haskell-doc-mode. |
|
|
;; (haskell-doc-mode): Don't touch haskell-doc-minor-mode-string. |
|
|
;; (haskell-doc-show-global-types): Don't touch |
|
|
;; haskell-doc-minor-mode-string. Call haskell-doc-make-global-fct-index. |
|
|
;; (haskell-doc-check-active): Fix message. |
|
|
;; (define-key-after): Don't define. |
|
|
;; (haskell-doc-install-keymap): Check existence of define-key-after. |
|
|
;; |
|
|
;; Revision 1.10 2004/11/25 23:03:23 monnier |
|
|
;; (haskell-doc-sym-doc): Make even the last char bold. |
|
|
;; |
|
|
;; Revision 1.9 2004/11/24 22:14:36 monnier |
|
|
;; (haskell-doc-install-keymap): Don't blindly assume there's a Hugs menu. |
|
|
;; |
|
|
;; Revision 1.8 2004/11/22 10:45:35 simonmar |
|
|
;; Fix type of getLine |
|
|
;; |
|
|
;; Revision 1.7 2004/10/14 22:27:47 monnier |
|
|
;; (turn-off-haskell-doc-mode, haskell-doc-current-info): Don't autoload. |
|
|
;; |
|
|
;; Revision 1.6 2004/10/13 22:45:22 monnier |
|
|
;; (haskell-doc): New group. |
|
|
;; (haskell-doc-show-reserved, haskell-doc-show-prelude) |
|
|
;; (haskell-doc-show-strategy, haskell-doc-show-user-defined) |
|
|
;; (haskell-doc-chop-off-context, haskell-doc-chop-off-fctname): |
|
|
;; Make them custom vars. |
|
|
;; (haskell-doc-keymap): Declare and fill it right there. |
|
|
;; (haskell-doc-mode): Simplify. |
|
|
;; (haskell-doc-toggle-var): Make it into what it was supposed to be. |
|
|
;; (haskell-doc-mode-print-current-symbol-info): Simplify. |
|
|
;; (haskell-doc-current-info): New autoloaded function. |
|
|
;; (haskell-doc-sym-doc): New fun extracted from haskell-doc-show-type. |
|
|
;; (haskell-doc-show-type): Use it. |
|
|
;; (haskell-doc-wrapped-type-p): Remove unused var `lim'. |
|
|
;; (haskell-doc-forward-sexp-safe, haskell-doc-current-symbol): Remove. Unused. |
|
|
;; (haskell-doc-visit-home): Don't require ange-ftp, it's autoloaded. |
|
|
;; (haskell-doc-install-keymap): Simplify. |
|
|
;; |
|
|
;; Revision 1.5 2003/01/09 11:56:26 simonmar |
|
|
;; Patches from Ville Skyttä <scop@xemacs.org>, the XEmacs maintainer of |
|
|
;; the haskell-mode: |
|
|
;; |
|
|
;; - Make the auto-mode-alist modifications autoload-only. |
|
|
;; |
|
|
;; Revision 1.4 2002/10/14 09:55:03 simonmar |
|
|
;; Patch to update the Prelude/libraries function names and to remove |
|
|
;; support for older versions of Haskell. |
|
|
;; |
|
|
;; Submitted by: Anders Lau Olsen <alauo@mip.sdu.dk> |
|
|
;; |
|
|
;; Revision 1.3 2002/04/30 09:34:37 rrt |
|
|
;; Remove supporting Haskell 1.4 and 1.2 from the ToDo list. It's Far Too Late. |
|
|
;; |
|
|
;; Add (require 'imenu). Thanks to N. Y. Kwok. |
|
|
;; |
|
|
;; Revision 1.2 2002/04/23 14:45:10 simonmar |
|
|
;; Tweaks to the doc strings and support for customization, from |
|
|
;; Ville Skyttä <scop@xemacs.org>. |
|
|
;; |
|
|
;; 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: |
|
|
|
|
|
(eval-when-compile (require 'cl)) |
|
|
|
|
|
(require 'haskell-mode) |
|
|
(require 'haskell-process) |
|
|
(require 'haskell) |
|
|
(require 'inf-haskell) |
|
|
(require 'imenu) |
|
|
(require 'eldoc) |
|
|
|
|
|
;;;###autoload |
|
|
(defgroup haskell-doc nil |
|
|
"Show Haskell function types in echo area." |
|
|
:group 'haskell |
|
|
:prefix "haskell-doc-") |
|
|
|
|
|
|
|
|
(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. |
|
|
|
|
|
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'. |
|
|
|
|
|
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) |
|
|
|
|
|
;;;###autoload |
|
|
(defcustom 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." |
|
|
:group 'haskell-doc |
|
|
:type 'boolean) |
|
|
(make-variable-buffer-local 'haskell-doc-show-global-types) |
|
|
|
|
|
;;;###autoload |
|
|
(defcustom haskell-doc-show-reserved t |
|
|
"If non-nil, show a documentation string for reserved ids. |
|
|
This variable is buffer-local." |
|
|
:group 'haskell-doc |
|
|
:type 'boolean) |
|
|
(make-variable-buffer-local 'haskell-doc-show-reserved) |
|
|
|
|
|
;;;###autoload |
|
|
(defcustom haskell-doc-show-prelude t |
|
|
"If non-nil, show a documentation string for prelude functions. |
|
|
This variable is buffer-local." |
|
|
:group 'haskell-doc |
|
|
:type 'boolean) |
|
|
(make-variable-buffer-local 'haskell-doc-show-prelude) |
|
|
|
|
|
;;;###autoload |
|
|
(defcustom haskell-doc-show-strategy t |
|
|
"If non-nil, show a documentation string for strategies. |
|
|
This variable is buffer-local." |
|
|
:group 'haskell-doc |
|
|
:type 'boolean) |
|
|
(make-variable-buffer-local 'haskell-doc-show-strategy) |
|
|
|
|
|
;;;###autoload |
|
|
(defcustom haskell-doc-show-user-defined t |
|
|
"If non-nil, show a documentation string for user defined ids. |
|
|
This variable is buffer-local." |
|
|
:group 'haskell-doc |
|
|
:type 'boolean) |
|
|
(make-variable-buffer-local 'haskell-doc-show-user-defined) |
|
|
|
|
|
;;;###autoload |
|
|
(defcustom haskell-doc-chop-off-context t |
|
|
"If non-nil eliminate the context part in a Haskell type." |
|
|
:group 'haskell-doc |
|
|
:type 'boolean) |
|
|
|
|
|
;;;###autoload |
|
|
(defcustom haskell-doc-chop-off-fctname nil |
|
|
"If non-nil omit the function name and show only the type." |
|
|
:group 'haskell-doc |
|
|
:type 'boolean) |
|
|
|
|
|
(defcustom haskell-doc-use-inf-haskell nil |
|
|
"If non-nil use inf-haskell.el to get type and kind information." |
|
|
:group 'haskell-doc |
|
|
:type 'boolean) |
|
|
|
|
|
(defvar haskell-doc-search-distance 40 ; distance in characters |
|
|
"*How far to search when looking for the type declaration of fct under cursor.") |
|
|
|
|
|
|
|
|
(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 |
|
|
'(haskell-doc-show-global-types " DOC" " Doc") |
|
|
"*String to display in mode line when Haskell-Doc Mode is enabled.") |
|
|
|
|
|
|
|
|
(defvar haskell-doc-reserved-ids |
|
|
'(("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. |
|
|
Each element is of the form (ID . DOC) where both ID and DOC are strings. |
|
|
DOC should be a concise single-line string describing the construct in which |
|
|
the keyword is used.") |
|
|
|
|
|
(eval-and-compile |
|
|
(defalias 'haskell-doc-split-string |
|
|
(if (condition-case () |
|
|
(split-string "" nil t) |
|
|
(wrong-number-of-arguments nil)) |
|
|
'split-string |
|
|
;; copied from Emacs 22 |
|
|
(lambda (string &optional separators omit-nulls) |
|
|
(let ((keep-nulls (not (if separators omit-nulls t))) |
|
|
(rexp (or separators "[ \f\t\n\r\v]+")) |
|
|
(start 0) |
|
|
notfirst |
|
|
(list nil)) |
|
|
(while (and (string-match rexp string |
|
|
(if (and notfirst |
|
|
(= start (match-beginning 0)) |
|
|
(< start (length string))) |
|
|
(1+ start) start)) |
|
|
(< start (length string))) |
|
|
(setq notfirst t) |
|
|
(if (or keep-nulls (< start (match-beginning 0))) |
|
|
(setq list |
|
|
(cons (substring string start (match-beginning 0)) |
|
|
list))) |
|
|
(setq start (match-end 0))) |
|
|
(if (or keep-nulls (< start (length string))) |
|
|
(setq list |
|
|
(cons (substring string start) |
|
|
list))) |
|
|
(nreverse list)))))) |
|
|
|
|
|
|
|
|
(defun haskell-doc-extract-types (url) |
|
|
(with-temp-buffer |
|
|
(insert-file-contents url) |
|
|
(goto-char (point-min)) |
|
|
(while (search-forward " " nil t) (replace-match " " t t)) |
|
|
|
|
|
;; First, focus on the actual code, removing the surrounding HTML text. |
|
|
(goto-char (point-min)) |
|
|
(let ((last (point-min)) |
|
|
(modules nil)) |
|
|
(while (re-search-forward "^module +\\([[:alnum:]]+\\)" nil t) |
|
|
(let ((module (match-string 1))) |
|
|
(if (member module modules) |
|
|
;; The library nodes of the HTML doc contain modules twice: |
|
|
;; once at the top, with only type declarations, and once at |
|
|
;; the bottom with an actual sample implementation which may |
|
|
;; include declaration of non-exported values. |
|
|
;; We're now at this second occurrence is the implementation |
|
|
;; which should thus be ignored. |
|
|
nil |
|
|
(push module modules) |
|
|
(delete-region last (point)) |
|
|
(search-forward "</tt>") |
|
|
;; Some of the blocks of code are split. |
|
|
(while (looking-at "\\(<[^<>]+>[ \t\n]*\\)*<tt>") |
|
|
(goto-char (match-end 0)) |
|
|
(search-forward "</tt>")) |
|
|
(setq last (point))))) |
|
|
(delete-region last (point-max)) |
|
|
|
|
|
;; Then process the HTML encoding to get back to pure ASCII. |
|
|
(goto-char (point-min)) |
|
|
(while (search-forward "<br>" nil t) (replace-match "\n" t t)) |
|
|
;; (goto-char (point-min)) |
|
|
;; (while (re-search-forward "<[^<>]+>" nil t) (replace-match "" t t)) |
|
|
(goto-char (point-min)) |
|
|
(while (search-forward ">" nil t) (replace-match ">" t t)) |
|
|
(goto-char (point-min)) |
|
|
(while (search-forward "<" nil t) (replace-match "<" t t)) |
|
|
(goto-char (point-min)) |
|
|
(while (search-forward "&" nil t) (replace-match "&" t t)) |
|
|
(goto-char (point-min)) |
|
|
(if (re-search-forward "&[a-z]+;" nil t) |
|
|
(error "Unexpected charref %s" (match-string 0))) |
|
|
;; Remove TABS. |
|
|
(goto-char (point-min)) |
|
|
(while (search-forward "\t" nil t) (replace-match " " t t)) |
|
|
|
|
|
;; Finally, extract the actual data. |
|
|
(goto-char (point-min)) |
|
|
(let* ((elems nil) |
|
|
(space-re "[ \t\n]*\\(?:--.*\n[ \t\n]*\\)*") |
|
|
(comma-re (concat " *," space-re)) |
|
|
;; A list of identifiers. We have to be careful to weed out |
|
|
;; entries like "ratPrec = 7 :: Int". Also ignore entries |
|
|
;; which start with a < since they're actually in the HTML text |
|
|
;; part. And the list may be spread over several lines, cut |
|
|
;; after a comma. |
|
|
(idlist-re |
|
|
(concat "\\([^< \t\n][^ \t\n]*" |
|
|
"\\(?:" comma-re "[^ \t\n]+\\)*\\)")) |
|
|
;; A type. A few types are spread over 2 lines, |
|
|
;; cut after the "=>", so we have to handle these as well. |
|
|
(type-re "\\(.*[^\n>]\\(?:>[ \t\n]+.*[^\n>]\\)*\\) *$") |
|
|
;; A decl of a list of values, possibly indented. |
|
|
(val-decl-re |
|
|
(concat "^\\( +\\)?" idlist-re "[ \t\n]*::[ \t\n]*" type-re)) |
|
|
(re (concat |
|
|
;; 3 possibilities: a class decl, a data decl, or val decl. |
|
|
;; First, let's match a class decl. |
|
|
"^class \\(?:.*=>\\)? *\\(.*[^ \t\n]\\)[ \t\n]*where" |
|
|
|
|
|
;; Or a value decl: |
|
|
"\\|" val-decl-re |
|
|
|
|
|
"\\|" ;; Or a data decl. We only handle single-arm |
|
|
;; datatypes with labels. |
|
|
"^data +\\([[:alnum:]][[:alnum:] ]*[[:alnum:]]\\)" |
|
|
" *=.*{\\([^}]+\\)}" |
|
|
)) |
|
|
(re-class (concat "^[^ \t\n]\\|" re)) |
|
|
curclass) |
|
|
(while (re-search-forward (if curclass re-class re) nil t) |
|
|
(cond |
|
|
;; A class decl. |
|
|
((match-end 1) (setq curclass (match-string 1))) |
|
|
;; A value decl. |
|
|
((match-end 4) |
|
|
(let ((type (match-string 4)) |
|
|
(vars (match-string 3)) |
|
|
(indented (match-end 2))) |
|
|
(if (string-match "[ \t\n][ \t\n]+" type) |
|
|
(setq type (replace-match " " t t type))) |
|
|
(if (string-match " *\\(--.*\\)?\\'" type) |
|
|
(setq type (substring type 0 (match-beginning 0)))) |
|
|
(if indented |
|
|
(if curclass |
|
|
(if (string-match "\\`\\(.*[^ \t\n]\\) *=> *" type) |
|
|
(let ((classes (match-string 1 type))) |
|
|
(setq type (substring type (match-end 0))) |
|
|
(if (string-match "\\`(.*)\\'" classes) |
|
|
(setq classes (substring classes 1 -1))) |
|
|
(setq type (concat "(" curclass ", " classes |
|
|
") => " type))) |
|
|
(setq type (concat curclass " => " type))) |
|
|
;; It's actually not an error: just a type annotation on |
|
|
;; some local variable. |
|
|
;; (error "Indentation outside a class in %s: %s" |
|
|
;; module vars) |
|
|
nil) |
|
|
(setq curclass nil)) |
|
|
(dolist (var (haskell-doc-split-string vars comma-re t)) |
|
|
(if (string-match "(.*)" var) (setq var (substring var 1 -1))) |
|
|
(push (cons var type) elems)))) |
|
|
;; A datatype decl. |
|
|
((match-end 5) |
|
|
(setq curclass nil) |
|
|
(let ((name (match-string 5))) |
|
|
(save-excursion |
|
|
(save-restriction |
|
|
(narrow-to-region (match-beginning 6) (match-end 6)) |
|
|
(goto-char (point-min)) |
|
|
(while (re-search-forward val-decl-re nil t) |
|
|
(let ((vars (match-string 2)) |
|
|
(type (match-string 3))) |
|
|
(if (string-match "[ \t\n][ \t\n]+" type) |
|
|
(setq type (replace-match " " t t type))) |
|
|
(if (string-match " *\\(--.*\\)?\\'" type) |
|
|
(setq type (substring type 0 (match-beginning 0)))) |
|
|
(if (string-match ",\\'" type) |
|
|
(setq type (substring type 0 -1))) |
|
|
(setq type (concat name " -> " type)) |
|
|
(dolist (var (haskell-doc-split-string vars comma-re t)) |
|
|
(if (string-match "(.*)" var) |
|
|
(setq var (substring var 1 -1))) |
|
|
(push (cons var type) elems)))))))) |
|
|
|
|
|
;; The end of a class declaration. |
|
|
(t (setq curclass nil) (beginning-of-line)))) |
|
|
(cons (car (last modules)) elems))))) |
|
|
|
|
|
(defun haskell-doc-fetch-lib-urls (base-url) |
|
|
(with-temp-buffer |
|
|
(insert-file-contents base-url) |
|
|
(goto-char (point-min)) |
|
|
(search-forward "Part II: Libraries") |
|
|
(delete-region (point-min) (point)) |
|
|
(search-forward "</table>") |
|
|
(delete-region (point) (point-max)) |
|
|
(goto-char (point-min)) |
|
|
(let ((libs (list "standard-prelude.html"))) |
|
|
(while (re-search-forward "<a href=\"\\([^\"]+\\)\">" nil t) |
|
|
(push (match-string 1) libs)) |
|
|
(mapcar (lambda (s) (expand-file-name s (file-name-directory base-url))) |
|
|
(nreverse libs))))) |
|
|
|
|
|
(defun haskell-doc-extract-and-insert-types (url) |
|
|
"Fetch the types from the online doc and insert them at point. |
|
|
URL is the URL of the online doc." |
|
|
(interactive (if current-prefix-arg |
|
|
(read-file-name "URL: ") |
|
|
(list "http://www.haskell.org/onlinereport/"))) |
|
|
(let ((urls (haskell-doc-fetch-lib-urls url))) |
|
|
(dolist (url urls) |
|
|
(let ((data (haskell-doc-extract-types url))) |
|
|
(insert ";; " (pop data)) (indent-according-to-mode) (newline) |
|
|
(dolist (elem (sort data (lambda (x y) (string-lessp (car x) (car y))))) |
|
|
(prin1 elem (current-buffer)) |
|
|
(indent-according-to-mode) (newline)))))) |
|
|
|
|
|
(defvar haskell-doc-prelude-types |
|
|
;; This list was auto generated by `haskell-doc-extract-and-insert-types'. |
|
|
'( |
|
|
;; Prelude |
|
|
("!!" . "[a] -> Int -> a") |
|
|
("$" . "(a -> b) -> a -> b") |
|
|
("$!" . "(a -> b) -> a -> b") |
|
|
("&&" . "Bool -> Bool -> Bool") |
|
|
("*" . "Num a => a -> a -> a") |
|
|
("**" . "Floating a => a -> a -> a") |
|
|
("+" . "Num a => a -> a -> a") |
|
|
("++" . "[a] -> [a] -> [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") |
|
|
("=<<" . "Monad m => (a -> m b) -> m a -> m b") |
|
|
("==" . "Eq a => a -> a -> Bool") |
|
|
(">" . "Ord a => a -> a -> Bool") |
|
|
(">=" . "Ord a => a -> a -> Bool") |
|
|
(">>" . "Monad m => 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") |
|
|
("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 ()") |
|
|
("asTypeOf" . "a -> a -> a") |
|
|
("asin" . "Floating a => a -> a") |
|
|
("asinh" . "Floating a => a -> a") |
|
|
("atan" . "Floating a => a -> a") |
|
|
("atan2" . "RealFloat a => 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" . "[[a]] -> [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]") |
|
|
("either" . "(a -> c) -> (b -> c) -> Either a b -> c") |
|
|
("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" . "Monad m => String -> m a") |
|
|
("filter" . "(a -> Bool) -> [a] -> [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") |
|
|
("fmap" . "Functor f => (a -> b) -> f a -> f 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") |
|
|
("fst" . "(a,b) -> a") |
|
|
("gcd" . "(Integral a) => a -> a -> a") |
|
|
("getChar" . "IO Char") |
|
|
("getContents" . "IO String") |
|
|
("getLine" . "IO String") |
|
|
("head" . "[a] -> a") |
|
|
("id" . "a -> a") |
|
|
("init" . "[a] -> [a]") |
|
|
("interact" . "(String -> String) -> IO ()") |
|
|
("ioError" . "IOError -> IO a") |
|
|
("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" . "(a -> b) -> [a] -> [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") |
|
|
("numericEnumFrom" . "(Fractional a) => a -> [a]") |
|
|
("numericEnumFromThen" . "(Fractional a) => a -> a -> [a]") |
|
|
("numericEnumFromThenTo" . "(Fractional a, Ord a) => a -> a -> a -> [a]") |
|
|
("numericEnumFromTo" . "(Fractional a, Ord a) => a -> a -> [a]") |
|
|
("odd" . "(Integral a) => a -> Bool") |
|
|
("or" . "[Bool] -> Bool") |
|
|
("otherwise" . "Bool") |
|
|
("pi" . "Floating a => a") |
|
|
("pred" . "Enum a => a -> a") |
|
|
("print" . "Show a => 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") |
|
|
("realToFrac" . "(Real a, Fractional b) => a -> b") |
|
|
("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" . "a -> b -> b") |
|
|
("sequence" . "Monad m => [m a] -> m [a]") |
|
|
("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") |
|
|
("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 ()") |
|
|
("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]") |
|
|
("||" . "Bool -> Bool -> Bool") |
|
|
;; Ratio |
|
|
("%" . "(Integral a) => a -> a -> Ratio a") |
|
|
("approxRational" . "(RealFrac a) => a -> a -> Rational") |
|
|
("denominator" . "(Integral a) => Ratio a -> a") |
|
|
("numerator" . "(Integral a) => Ratio a -> a") |
|
|
;; Complex |
|
|
("cis" . "(RealFloat a) => a -> Complex a") |
|
|
("conjugate" . "(RealFloat a) => Complex a -> Complex a") |
|
|
("imagPart" . "(RealFloat a) => Complex a -> a") |
|
|
("magnitude" . "(RealFloat a) => Complex a -> a") |
|
|
("mkPolar" . "(RealFloat a) => a -> a -> Complex a") |
|
|
("phase" . "(RealFloat a) => Complex a -> a") |
|
|
("polar" . "(RealFloat a) => Complex a -> (a,a)") |
|
|
("realPart" . "(RealFloat a) => Complex a -> a") |
|
|
;; Numeric |
|
|
("floatToDigits" . "(RealFloat a) => Integer -> a -> ([Int], Int)") |
|
|
("fromRat" . "(RealFloat a) => Rational -> a") |
|
|
("lexDigits" . "ReadS String") |
|
|
("readDec" . "(Integral a) => ReadS a") |
|
|
("readFloat" . "(RealFrac a) => ReadS a") |
|
|
("readHex" . "(Integral a) => ReadS a") |
|
|
("readInt" . "(Integral a) => a -> (Char -> Bool) -> (Char -> Int) -> ReadS a") |
|
|
("readOct" . "(Integral a) => ReadS a") |
|
|
("readSigned" . "(Real a) => ReadS a -> ReadS a") |
|
|
("showEFloat" . "(RealFloat a) => Maybe Int -> a -> ShowS") |
|
|
("showFFloat" . "(RealFloat a) => Maybe Int -> a -> ShowS") |
|
|
("showFloat" . "(RealFloat a) => a -> ShowS") |
|
|
("showGFloat" . "(RealFloat a) => Maybe Int -> a -> ShowS") |
|
|
("showHex" . "Integral a => a -> ShowS") |
|
|
("showInt" . "Integral a => a -> ShowS") |
|
|
("showIntAtBase" . "Integral a => a -> (Int -> Char) -> a -> ShowS") |
|
|
("showOct" . "Integral a => a -> ShowS") |
|
|
("showSigned" . "(Real a) => (a -> ShowS) -> Int -> a -> ShowS") |
|
|
;; Ix |
|
|
("inRange" . "Ix a => (a,a) -> a -> Bool") |
|
|
("index" . "Ix a => (a,a) -> a -> Int") |
|
|
("range" . "Ix a => (a,a) -> [a]") |
|
|
("rangeSize" . "Ix a => (a,a) -> Int") |
|
|
;; Array |
|
|
("!" . "(Ix a) => Array a b -> a -> b") |
|
|
("//" . "(Ix a) => Array a b -> [(a,b)] -> Array a b") |
|
|
("accum" . "(Ix a) => (b -> c -> b) -> Array a b -> [(a,c)]") |
|
|
("accumArray" . "(Ix a) => (b -> c -> b) -> b -> (a,a) -> [(a,c)]") |
|
|
("array" . "(Ix a) => (a,a) -> [(a,b)] -> Array a b") |
|
|
("assocs" . "(Ix a) => Array a b -> [(a,b)]") |
|
|
("bounds" . "(Ix a) => Array a b -> (a,a)") |
|
|
("elems" . "(Ix a) => Array a b -> [b]") |
|
|
("indices" . "(Ix a) => Array a b -> [a]") |
|
|
("ixmap" . "(Ix a, Ix b) => (a,a) -> (a -> b) -> Array b c") |
|
|
("listArray" . "(Ix a) => (a,a) -> [b] -> Array a b") |
|
|
;; List |
|
|
("\\\\" . "Eq a => [a] -> [a] -> [a]") |
|
|
("delete" . "Eq a => a -> [a] -> [a]") |
|
|
("deleteBy" . "(a -> a -> Bool) -> a -> [a] -> [a]") |
|
|
("deleteFirstsBy" . "(a -> a -> Bool) -> [a] -> [a] -> [a]") |
|
|
("elemIndex" . "Eq a => a -> [a] -> Maybe Int") |
|
|
("elemIndices" . "Eq a => a -> [a] -> [Int]") |
|
|
("find" . "(a -> Bool) -> [a] -> Maybe a") |
|
|
("findIndex" . "(a -> Bool) -> [a] -> Maybe Int") |
|
|
("findIndices" . "(a -> Bool) -> [a] -> [Int]") |
|
|
("genericDrop" . "Integral a => a -> [b] -> [b]") |
|
|
("genericIndex" . "Integral a => [b] -> a -> b") |
|
|
("genericLength" . "Integral a => [b] -> a") |
|
|
("genericReplicate" . "Integral a => a -> b -> [b]") |
|
|
("genericSplitAt" . "Integral a => a -> [b] -> ([b],[b])") |
|
|
("genericTake" . "Integral a => a -> [b] -> [b]") |
|
|
("group" . "Eq a => [a] -> [[a]]") |
|
|
("groupBy" . "(a -> a -> Bool) -> [a] -> [[a]]") |
|
|
("inits" . "[a] -> [[a]]") |
|
|
("insert" . "Ord a => a -> [a] -> [a]") |
|
|
("insertBy" . "(a -> a -> Ordering) -> a -> [a] -> [a]") |
|
|
("intersect" . "Eq a => [a] -> [a] -> [a]") |
|
|
("intersectBy" . "(a -> a -> Bool) -> [a] -> [a] -> [a]") |
|
|
("intersperse" . "a -> [a] -> [a]") |
|
|
("isPrefixOf" . "Eq a => [a] -> [a] -> Bool") |
|
|
("isSuffixOf" . "Eq a => [a] -> [a] -> Bool") |
|
|
("mapAccumL" . "(a -> b -> (a, c)) -> a -> [b] -> (a, [c])") |
|
|
("mapAccumR" . "(a -> b -> (a, c)) -> a -> [b] -> (a, [c])") |
|
|
("maximumBy" . "(a -> a -> Ordering) -> [a] -> a") |
|
|
("minimumBy" . "(a -> a -> Ordering) -> [a] -> a") |
|
|
("nub" . "Eq a => [a] -> [a]") |
|
|
("nubBy" . "(a -> a -> Bool) -> [a] -> [a]") |
|
|
("partition" . "(a -> Bool) -> [a] -> ([a],[a])") |
|
|
("sort" . "Ord a => [a] -> [a]") |
|
|
("sortBy" . "(a -> a -> Ordering) -> [a] -> [a]") |
|
|
("tails" . "[a] -> [[a]]") |
|
|
("transpose" . "[[a]] -> [[a]]") |
|
|
("unfoldr" . "(b -> Maybe (a,b)) -> b -> [a]") |
|
|
("union" . "Eq a => [a] -> [a] -> [a]") |
|
|
("unionBy" . "(a -> a -> Bool) -> [a] -> [a] -> [a]") |
|
|
("unzip4" . "[(a,b,c,d)] -> ([a],[b],[c],[d])") |
|
|
("unzip5" . "[(a,b,c,d,e)] -> ([a],[b],[c],[d],[e])") |
|
|
("unzip6" . "[(a,b,c,d,e,f)] -> ([a],[b],[c],[d],[e],[f])") |
|
|
("unzip7" . "[(a,b,c,d,e,f,g)] -> ([a],[b],[c],[d],[e],[f],[g])") |
|
|
("zip4" . "[a] -> [b] -> [c] -> [d] -> [(a,b,c,d)]") |
|
|
("zip5" . "[a] -> [b] -> [c] -> [d] -> [e] -> [(a,b,c,d,e)]") |
|
|
("zip6" . "[a] -> [b] -> [c] -> [d] -> [e] -> [f]") |
|
|
("zip7" . "[a] -> [b] -> [c] -> [d] -> [e] -> [f] -> [g]") |
|
|
("zipWith4" . "(a->b->c->d->e) -> [a]->[b]->[c]->[d]->[e]") |
|
|
("zipWith5" . "(a->b->c->d->e->f) ->") |
|
|
("zipWith6" . "(a->b->c->d->e->f->g) -> [a]->[b]->[c]->[d]->[e]->[f]->[g]") |
|
|
("zipWith7" . "(a->b->c->d->e->f->g->h) -> [a]->[b]->[c]->[d]->[e]->[f]->[g]->[h]") |
|
|
;; Maybe |
|
|
("catMaybes" . "[Maybe a] -> [a]") |
|
|
("fromJust" . "Maybe a -> a") |
|
|
("fromMaybe" . "a -> Maybe a -> a") |
|
|
("isJust" . "Maybe a -> Bool") |
|
|
("isNothing" . "Maybe a -> Bool") |
|
|
("listToMaybe" . "[a] -> Maybe a") |
|
|
("mapMaybe" . "(a -> Maybe b) -> [a] -> [b]") |
|
|
("maybeToList" . "Maybe a -> [a]") |
|
|
;; Char |
|
|
("chr" . "Int -> Char") |
|
|
("digitToInt" . "Char -> Int") |
|
|
("intToDigit" . "Int -> Char") |
|
|
("isAlpha" . "Char -> Bool") |
|
|
("isAlphaNum" . "Char -> Bool") |
|
|
("isAscii" . "Char -> Bool") |
|
|
("isControl" . "Char -> Bool") |
|
|
("isDigit" . "Char -> Bool") |
|
|
("isHexDigit" . "Char -> Bool") |
|
|
("isLatin1" . "Char -> Bool") |
|
|
("isLower" . "Char -> Bool") |
|
|
("isOctDigit" . "Char -> Bool") |
|
|
("isPrint" . "Char -> Bool") |
|
|
("isSpace" . "Char -> Bool") |
|
|
("isUpper" . "Char -> Bool") |
|
|
("lexLitChar" . "ReadS String") |
|
|
("ord" . "Char -> Int") |
|
|
("readLitChar" . "ReadS Char") |
|
|
("showLitChar" . "Char -> ShowS") |
|
|
("toLower" . "Char -> Char") |
|
|
("toUpper" . "Char -> Char") |
|
|
;; Monad |
|
|
("ap" . "Monad m => m (a -> b) -> m a -> m b") |
|
|
("filterM" . "Monad m => (a -> m Bool) -> [a] -> m [a]") |
|
|
("foldM" . "Monad m => (a -> b -> m a) -> a -> [b] -> m a") |
|
|
("guard" . "MonadPlus m => Bool -> m ()") |
|
|
("join" . "Monad m => m (m a) -> m a") |
|
|
("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)") |
|
|
("mapAndUnzipM" . "Monad m => (a -> m (b,c)) -> [a] -> m ([b], [c])") |
|
|
("mplus" . "MonadPlus m => m a -> m a -> m a") |
|
|
("msum" . "MonadPlus m => [m a] -> m a") |
|
|
("mzero" . "MonadPlus m => m a") |
|
|
("unless" . "Monad m => Bool -> m () -> m ()") |
|
|
("when" . "Monad m => Bool -> m () -> m ()") |
|
|
("zipWithM" . "Monad m => (a -> b -> m c) -> [a] -> [b] -> m [c]") |
|
|
("zipWithM_" . "Monad m => (a -> b -> m c) -> [a] -> [b] -> m ()") |
|
|
;; IO |
|
|
("bracket" . "IO a -> (a -> IO b) -> (a -> IO c) -> IO c") |
|
|
("bracket_" . "IO a -> (a -> IO b) -> IO c -> IO c") |
|
|
("hClose" . "Handle -> IO ()") |
|
|
("hFileSize" . "Handle -> IO Integer") |
|
|
("hFlush" . "Handle -> IO ()") |
|
|
("hGetBuffering" . "Handle -> IO BufferMode") |
|
|
("hGetChar" . "Handle -> IO Char") |
|
|
("hGetContents" . "Handle -> IO String") |
|
|
("hGetLine" . "Handle -> IO String") |
|
|
("hGetPosn" . "Handle -> IO HandlePosn") |
|
|
("hIsClosed" . "Handle -> IO Bool") |
|
|
("hIsEOF" . "Handle -> IO Bool") |
|
|
("hIsOpen" . "Handle -> IO Bool") |
|
|
("hIsReadable" . "Handle -> IO Bool") |
|
|
("hIsSeekable" . "Handle -> IO Bool") |
|
|
("hIsWritable" . "Handle -> IO Bool") |
|
|
("hLookAhead" . "Handle -> IO Char") |
|
|
("hPrint" . "Show a => Handle -> a -> IO ()") |
|
|
("hPutChar" . "Handle -> Char -> IO ()") |
|
|
("hPutStr" . "Handle -> String -> IO ()") |
|
|
("hPutStrLn" . "Handle -> String -> IO ()") |
|
|
("hReady" . "Handle -> IO Bool") |
|
|
("hSeek" . "Handle -> SeekMode -> Integer -> IO ()") |
|
|
("hSetBuffering" . "Handle -> BufferMode -> IO ()") |
|
|
("hSetPosn" . "HandlePosn -> IO ()") |
|
|
("hWaitForInput" . "Handle -> Int -> IO Bool") |
|
|
("ioeGetErrorString" . "IOError -> String") |
|
|
("ioeGetFileName" . "IOError -> Maybe FilePath") |
|
|
("ioeGetHandle" . "IOError -> Maybe Handle") |
|
|
("isAlreadyExistsError" . "IOError -> Bool") |
|
|
("isAlreadyInUseError" . "IOError -> Bool") |
|
|
("isDoesNotExistError" . "IOError -> Bool") |
|
|
("isEOF" . "IO Bool") |
|
|
("isEOFError" . "IOError -> Bool") |
|
|
("isFullError" . "IOError -> Bool") |
|
|
("isIllegalOperation" . "IOError -> Bool") |
|
|
("isPermissionError" . "IOError -> Bool") |
|
|
("isUserError" . "IOError -> Bool") |
|
|
("openFile" . "FilePath -> IOMode -> IO Handle") |
|
|
("stderr" . "Handle") |
|
|
("stdin" . "Handle") |
|
|
("stdout" . "Handle") |
|
|
("try" . "IO a -> IO (Either IOError a)") |
|
|
;; Directory |
|
|
("createDirectory" . "FilePath -> IO ()") |
|
|
("doesDirectoryExist" . "FilePath -> IO Bool") |
|
|
("doesFileExist" . "FilePath -> IO Bool") |
|
|
("executable" . "Permissions -> Bool") |
|
|
("getCurrentDirectory" . "IO FilePath") |
|
|
("getDirectoryContents" . "FilePath -> IO [FilePath]") |
|
|
("getModificationTime" . "FilePath -> IO ClockTime") |
|
|
("getPermissions" . "FilePath -> IO Permissions") |
|
|
("readable" . "Permissions -> Bool") |
|
|
("removeDirectory" . "FilePath -> IO ()") |
|
|
("removeFile" . "FilePath -> IO ()") |
|
|
("renameDirectory" . "FilePath -> FilePath -> IO ()") |
|
|
("renameFile" . "FilePath -> FilePath -> IO ()") |
|
|
("searchable" . "Permissions -> Bool") |
|
|
("setCurrentDirectory" . "FilePath -> IO ()") |
|
|
("setPermissions" . "FilePath -> Permissions -> IO ()") |
|
|
("writable" . "Permissions -> Bool") |
|
|
;; System |
|
|
("exitFailure" . "IO a") |
|
|
("exitWith" . "ExitCode -> IO a") |
|
|
("getArgs" . "IO [String]") |
|
|
("getEnv" . "String -> IO String") |
|
|
("getProgName" . "IO String") |
|
|
("system" . "String -> IO ExitCode") |
|
|
;; Time |
|
|
("addToClockTime" . "TimeDiff -> ClockTime -> ClockTime") |
|
|
("calendarTimeToString" . "CalendarTime -> String") |
|
|
("ctDay" . "CalendarTime -> Int") |
|
|
("ctHour" . "CalendarTime -> Int") |
|
|
("ctIsDST" . "CalendarTime -> Bool") |
|
|
("ctMin" . "CalendarTime -> Int") |
|
|
("ctMonth" . "CalendarTime -> Month") |
|
|
("ctPicosec" . "CalendarTime -> Integer") |
|
|
("ctSec" . "CalendarTime -> Int") |
|
|
("ctTZ" . "CalendarTime -> Int") |
|
|
("ctTZName" . "CalendarTime -> String") |
|
|
("ctWDay" . "CalendarTime -> Day") |
|
|
("ctYDay" . "CalendarTime -> Int") |
|
|
("ctYear" . "CalendarTime -> Int") |
|
|
("diffClockTimes" . "ClockTime -> ClockTime -> TimeDiff") |
|
|
("formatCalendarTime" . "TimeLocale -> String -> CalendarTime -> String") |
|
|
("getClockTime" . "IO ClockTime") |
|
|
("tdDay" . "TimeDiff -> Int") |
|
|
("tdHour" . "TimeDiff -> Int") |
|
|
("tdMin" . "TimeDiff -> Int") |
|
|
("tdMonth" . "TimeDiff -> Int") |
|
|
("tdPicosec" . "TimeDiff -> Integer") |
|
|
("tdSec" . "TimeDiff -> Int") |
|
|
("tdYear" . "TimeDiff -> Int") |
|
|
("toCalendarTime" . "ClockTime -> IO CalendarTime") |
|
|
("toClockTime" . "CalendarTime -> ClockTime") |
|
|
("toUTCTime" . "ClockTime -> CalendarTime") |
|
|
;; Locale |
|
|
("amPm" . "TimeLocale -> (String, String)") |
|
|
("dateFmt" . "TimeLocale -> String") |
|
|
("dateTimeFmt" . "TimeLocale -> String") |
|
|
("defaultTimeLocale" . "TimeLocale") |
|
|
("months" . "TimeLocale -> [(String, String)]") |
|
|
("time12Fmt" . "TimeLocale -> String") |
|
|
("timeFmt" . "TimeLocale -> String") |
|
|
("wDays" . "TimeLocale -> [(String, String)]") |
|
|
;; CPUTime |
|
|
("cpuTimePrecision" . "Integer") |
|
|
("getCPUTime" . "IO Integer") |
|
|
;; Random |
|
|
("genRange" . "RandomGen g => g -> (Int, Int)") |
|
|
("getStdGen" . "IO StdGen") |
|
|
("getStdRandom" . "(StdGen -> (a, StdGen)) -> IO a") |
|
|
("mkStdGen" . "Int -> StdGen") |
|
|
("newStdGen" . "IO StdGen") |
|
|
("next" . "RandomGen g => g -> (Int, g)") |
|
|
("random" . "(Random a, RandomGen g) => g -> (a, g)") |
|
|
("randomIO" . "Random a => IO a") |
|
|
("randomR" . "(Random a, RandomGen g) => (a, a) -> g -> (a, g)") |
|
|
("randomRIO" . "Random a => (a,a) -> IO a") |
|
|
("randomRs" . "(Random a, RandomGen g) => (a, a) -> g -> [a]") |
|
|
("randoms" . "(Random a, RandomGen g) => g -> [a]") |
|
|
("setStdGen" . "StdGen -> IO ()") |
|
|
("split" . "RandomGen g => g -> (g, g)") |
|
|
) |
|
|
"Alist of prelude functions and their types.") |
|
|
|
|
|
|
|
|
(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.") |
|
|
|
|
|
|
|
|
(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) ) |
|
|
|
|
|
|
|
|
;; 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))))) |
|
|
|
|
|
;; a dummy definition needed for XEmacs (I know, it's horrible :-( |
|
|
|
|
|
|
|
|
(defvar haskell-doc-keymap |
|
|
(let ((map (make-sparse-keymap))) |
|
|
(define-key map [visit] |
|
|
'("Visit FTP home site" . haskell-doc-visit-home)) |
|
|
(define-key map [submit] |
|
|
'("Submit bug report" . haskell-doc-submit-bug-report)) |
|
|
(define-key map [dummy] '("---" . nil)) |
|
|
(define-key map [make-index] |
|
|
'("Make global fct index" . haskell-doc-make-global-fct-index)) |
|
|
(define-key map [global-types-on] |
|
|
'("Toggle display of global types" . haskell-doc-show-global-types)) |
|
|
(define-key map [strategy-on] |
|
|
'("Toggle display of strategy ids" . haskell-doc-show-strategy)) |
|
|
(define-key map [user-defined-on] |
|
|
'("Toggle display of user defined ids" . haskell-doc-show-user-defined)) |
|
|
(define-key map [prelude-on] |
|
|
'("Toggle display of prelude functions" . haskell-doc-show-prelude)) |
|
|
(define-key map [reserved-ids-on] |
|
|
'("Toggle display of reserved ids" . haskell-doc-show-reserved)) |
|
|
(define-key map [haskell-doc-on] |
|
|
'("Toggle haskell-doc mode" . haskell-doc-mode)) |
|
|
map)) |
|
|
|
|
|
(defun haskell-doc-install-keymap () |
|
|
"Install a menu for `haskell-doc-mode' as a submenu of \"Hugs\"." |
|
|
(interactive) |
|
|
;; Add the menu to the hugs menu as last entry. |
|
|
(let ((hugsmap (lookup-key (current-local-map) [menu-bar Hugs]))) |
|
|
(if (not (or (featurep 'xemacs) ; XEmacs has problems here |
|
|
(not (keymapp hugsmap)) |
|
|
(lookup-key hugsmap [haskell-doc]))) |
|
|
(if (functionp 'define-key-after) |
|
|
(define-key-after hugsmap [haskell-doc] |
|
|
(cons "Haskell-doc" haskell-doc-keymap) |
|
|
[Haskell-doc mode])))) |
|
|
;; Add shortcuts for these commands. |
|
|
(local-set-key "\C-c\e/" 'haskell-doc-check-active) |
|
|
;; Conflicts with the binding of haskell-insert-otherwise. |
|
|
;; (local-set-key "\C-c\C-o" 'haskell-doc-mode) |
|
|
(local-set-key [(control shift meta mouse-3)] |
|
|
'haskell-doc-ask-mouse-for-type)) |
|
|
|
|
|
|
|
|
(defvar haskell-doc-timer nil) |
|
|
(defvar haskell-doc-buffers nil) |
|
|
|
|
|
;;;###autoload |
|
|
(defun haskell-doc-mode (&optional arg) |
|
|
"Enter `haskell-doc-mode' for showing fct types in the echo area. |
|
|
See variable docstring." |
|
|
(interactive (list (or current-prefix-arg 'toggle))) |
|
|
|
|
|
(setq haskell-doc-mode |
|
|
(cond |
|
|
((eq arg 'toggle) (not haskell-doc-mode)) |
|
|
(arg (> (prefix-numeric-value arg) 0)) |
|
|
(t))) |
|
|
|
|
|
;; First, unconditionally turn the mode OFF. |
|
|
|
|
|
(setq haskell-doc-buffers (delq (current-buffer) haskell-doc-buffers)) |
|
|
;; Refresh the buffers list. |
|
|
(dolist (buf haskell-doc-buffers) |
|
|
(unless (and (buffer-live-p buf) |
|
|
(with-current-buffer buf haskell-doc-mode)) |
|
|
(setq haskell-doc-buffers (delq buf haskell-doc-buffers)))) |
|
|
;; Turn off the idle timer (or idle post-command-hook). |
|
|
(when (and haskell-doc-timer (null haskell-doc-buffers)) |
|
|
(cancel-timer haskell-doc-timer) |
|
|
(setq haskell-doc-timer nil)) |
|
|
(remove-hook 'post-command-hook |
|
|
'haskell-doc-mode-print-current-symbol-info 'local) |
|
|
|
|
|
(when haskell-doc-mode |
|
|
;; Turning the mode ON. |
|
|
(push (current-buffer) haskell-doc-buffers) |
|
|
|
|
|
(if (fboundp 'run-with-idle-timer) |
|
|
(unless haskell-doc-timer |
|
|
(setq haskell-doc-timer |
|
|
(run-with-idle-timer |
|
|
haskell-doc-idle-delay t |
|
|
'haskell-doc-mode-print-current-symbol-info))) |
|
|
(add-hook 'post-command-hook |
|
|
'haskell-doc-mode-print-current-symbol-info nil 'local)) |
|
|
(and haskell-doc-show-global-types |
|
|
(haskell-doc-make-global-fct-index)) ; build type index for global fcts |
|
|
|
|
|
(haskell-doc-install-keymap) |
|
|
|
|
|
(run-hooks 'haskell-doc-mode-hook)) |
|
|
|
|
|
(and (called-interactively-p 'any) |
|
|
(message "haskell-doc-mode is %s" |
|
|
(if haskell-doc-mode "enabled" "disabled"))) |
|
|
haskell-doc-mode) |
|
|
|
|
|
(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))) ) |
|
|
|
|
|
(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 |
|
|
(haskell-doc-make-global-fct-index))) |
|
|
|
|
|
(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)) |
|
|
|
|
|
(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)) |
|
|
|
|
|
(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)) |
|
|
|
|
|
(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)) |
|
|
|
|
|
|
|
|
;;;###autoload |
|
|
(defalias 'turn-on-haskell-doc-mode 'haskell-doc-mode) |
|
|
(make-obsolete 'turn-on-haskell-doc-mode |
|
|
'haskell-doc-mode |
|
|
"2015-07-23") |
|
|
|
|
|
;;;###autoload |
|
|
(defalias 'turn-on-haskell-doc 'haskell-doc-mode) |
|
|
(make-obsolete 'turn-on-haskell-doc |
|
|
'haskell-doc-mode |
|
|
"2015-07-23") |
|
|
|
|
|
(defalias 'turn-off-haskell-doc-mode 'turn-off-haskell-doc) |
|
|
|
|
|
(defun turn-off-haskell-doc () |
|
|
"Unequivocally turn off `haskell-doc-mode' (which see)." |
|
|
(haskell-doc-mode 0)) |
|
|
|
|
|
(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 "%s" |
|
|
(if (or (and haskell-doc-mode haskell-doc-timer) |
|
|
(memq 'haskell-doc-mode-print-current-symbol-info |
|
|
post-command-hook)) |
|
|
"haskell-doc is ACTIVE" |
|
|
(substitute-command-keys |
|
|
"haskell-doc is not ACTIVE \(Use \\[haskell-doc-mode] to turn it on\)")))) |
|
|
|
|
|
|
|
|
;; 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 run by an idle timer to print the type |
|
|
automatically if `haskell-doc-mode' is turned on." |
|
|
(and haskell-doc-mode |
|
|
(not (eobp)) |
|
|
(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, if run straight from post-command-hook. |
|
|
(if (fboundp 'run-with-idle-timer) t |
|
|
(sit-for haskell-doc-idle-delay)) |
|
|
;; good morning! read the word under the cursor for breakfast |
|
|
(haskell-doc-show-type))) |
|
|
;; ;; 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))))))) |
|
|
|
|
|
;;;###autoload |
|
|
(defun haskell-doc-current-info () |
|
|
"Return the info about symbol at point. |
|
|
Meant for `eldoc-documentation-function'." |
|
|
;; There are a number of possible documentation functions. |
|
|
;; Some of them are asynchronous. |
|
|
(let ((msg (or |
|
|
(haskell-doc-current-info--interaction) |
|
|
(haskell-doc-sym-doc (haskell-ident-at-point))))) |
|
|
(unless (symbolp msg) msg))) |
|
|
|
|
|
|
|
|
|
|
|
(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))) |
|
|
|
|
|
(defun haskell-doc-in-code-p () |
|
|
(not (or (and (eq haskell-literate 'bird) |
|
|
;; Copied from haskell-indent-bolp. |
|
|
(<= (current-column) 2) |
|
|
(eq (char-after (line-beginning-position)) ?\>)) |
|
|
(nth 8 (syntax-ppss))))) |
|
|
|
|
|
;;;###autoload |
|
|
(defun haskell-doc-show-type (&optional sym) |
|
|
"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) |
|
|
(unless sym (setq sym (haskell-ident-at-point))) |
|
|
;; if printed before do not print it again |
|
|
(unless (string= sym (car haskell-doc-last-data)) |
|
|
(let ((doc (or (haskell-doc-current-info--interaction t) |
|
|
(haskell-doc-sym-doc sym)))) |
|
|
(when (and doc (haskell-doc-in-code-p)) |
|
|
;; 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. |
|
|
(if (eval-when-compile (fboundp 'display-message)) |
|
|
;; XEmacs 19.13 way of preventing log messages. |
|
|
;;(display-message 'no-log (format <args>)) |
|
|
;; XEmacs 19.15 seems to be a bit different. |
|
|
(display-message 'message (format "%s" doc)) |
|
|
(let ((message-log-max nil)) |
|
|
(message "%s" doc))))))) |
|
|
|
|
|
(defvar haskell-doc-current-info--interaction-last nil |
|
|
"If non-nil, a previous eldoc message from an async call, that |
|
|
hasn't been displayed yet.") |
|
|
|
|
|
(defun haskell-doc-current-info--interaction (&optional sync) |
|
|
"Asynchronous call to `haskell-process-get-type', suitable for |
|
|
use in the eldoc function `haskell-doc-current-info'. |
|
|
|
|
|
If SYNC is non-nil, the call will be synchronous instead, and |
|
|
instead of calling `eldoc-print-current-symbol-info', the result |
|
|
will be returned directly." |
|
|
;; Return nil if nothing is available, or 'async if something might |
|
|
;; be available, but asynchronously later. This will call |
|
|
;; `eldoc-print-current-symbol-info' later. |
|
|
(let (sym prev-message) |
|
|
(cond |
|
|
((setq prev-message haskell-doc-current-info--interaction-last) |
|
|
(setq haskell-doc-current-info--interaction-last nil) |
|
|
(cdr prev-message)) |
|
|
((setq sym |
|
|
(if (use-region-p) |
|
|
(buffer-substring-no-properties |
|
|
(region-beginning) (region-end)) |
|
|
(haskell-ident-at-point))) |
|
|
(if sync |
|
|
(haskell-process-get-type sym #'identity t) |
|
|
(haskell-process-get-type |
|
|
sym (lambda (response) |
|
|
(setq haskell-doc-current-info--interaction-last |
|
|
(cons 'async response)) |
|
|
(eldoc-print-current-symbol-info)))))))) |
|
|
|
|
|
(defun haskell-process-get-type (expr-string &optional callback sync) |
|
|
"Asynchronously get the type of a given string. |
|
|
|
|
|
EXPR-STRING should be an expression passed to :type in ghci. |
|
|
|
|
|
CALLBACK will be called with a formatted type string. |
|
|
|
|
|
If SYNC is non-nil, make the call synchronously instead." |
|
|
(unless callback (setq callback (lambda (response) (message "%s" response)))) |
|
|
(let ((process (and (haskell-session-maybe) |
|
|
(haskell-session-process (haskell-session-maybe)))) |
|
|
;; Avoid passing bad strings to ghci |
|
|
(expr-okay |
|
|
(and (not (string-match-p "\\`[[:space:]]*\\'" expr-string)) |
|
|
(not (string-match-p "\n" expr-string)))) |
|
|
(ghci-command (concat ":type " expr-string)) |
|
|
(process-response |
|
|
(lambda (response) |
|
|
;; Responses with empty first line are likely errors |
|
|
(if (string-match-p (rx string-start line-end) response) |
|
|
(setq response nil) |
|
|
;; Remove a newline at the end |
|
|
(setq response (replace-regexp-in-string "\n\\'" "" response)) |
|
|
;; Propertize for eldoc |
|
|
(save-match-data |
|
|
(when (string-match " :: " response) |
|
|
;; Highlight type |
|
|
(let ((name (substring response 0 (match-end 0))) |
|
|
(type (propertize |
|
|
(substring response (match-end 0)) |
|
|
'face 'eldoc-highlight-function-argument))) |
|
|
(setq response (concat name type))))) |
|
|
(when haskell-doc-prettify-types |
|
|
(dolist (re '(("::" . "∷") ("=>" . "⇒") ("->" . "→"))) |
|
|
(setq response |
|
|
(replace-regexp-in-string (car re) (cdr re) response)))) |
|
|
response)))) |
|
|
(when (and process expr-okay) |
|
|
(if sync |
|
|
(let ((response (haskell-process-queue-sync-request process ghci-command))) |
|
|
(funcall callback (funcall process-response response))) |
|
|
(lexical-let ((process process) |
|
|
(callback callback) |
|
|
(ghci-command ghci-command) |
|
|
(process-response process-response)) |
|
|
(haskell-process-queue-command |
|
|
process |
|
|
(make-haskell-command |
|
|
:go (lambda (_) (haskell-process-send-string process ghci-command)) |
|
|
:complete |
|
|
(lambda (_ response) |
|
|
(funcall callback (funcall process-response response)))))) |
|
|
'async)))) |
|
|
|
|
|
(defun haskell-doc-sym-doc (sym) |
|
|
"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. |
|
|
If `haskell-doc-use-inf-haskell' is non-nil, this function will consult |
|
|
the inferior Haskell process for type/kind information, rather than using |
|
|
the haskell-doc database." |
|
|
(if haskell-doc-use-inf-haskell |
|
|
(unless (or (null sym) (string= "" sym)) |
|
|
(let* ((message-log-max nil) |
|
|
(result (ignore-errors |
|
|
(unwind-protect |
|
|
(inferior-haskell-type sym) |
|
|
(message ""))))) |
|
|
(if (and result (string-match " :: " result)) |
|
|
result |
|
|
(setq result (unwind-protect |
|
|
(inferior-haskell-kind sym) |
|
|
(message ""))) |
|
|
(and result (string-match " :: " result) result)))) |
|
|
(let ((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))) |
|
|
(cond |
|
|
;; 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 |
|
|
;; 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 (length str) '(face bold) str)) |
|
|
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))) |
|
|
|
|
|
|
|
|
;; ToDo: handle open brackets to decide if it's a wrapped type |
|
|
|
|
|
(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)))) |
|
|
|
|
|
(defun haskell-doc-wrapped-type-p () |
|
|
"Check whether the type under the cursor is wrapped over several lines. |
|
|
The cursor must be at the end of a line, which contains the type. |
|
|
Currently, only the following is checked: |
|
|
If this line ends with a `->' or the next starts with an `->' it is a |
|
|
multi-line type \(same for `=>'\). |
|
|
`--' comments are ignored. |
|
|
ToDo: Check for matching parenthesis!." |
|
|
(save-excursion |
|
|
(let ( (here (point)) |
|
|
(lim (progn (beginning-of-line) (point))) |
|
|
;; (foo "") |
|
|
(res nil) |
|
|
) |
|
|
(goto-char here) |
|
|
(search-backward "--" lim t) ; skip over `--' comment |
|
|
(skip-chars-backward " \t") |
|
|
(if (bolp) ; skip empty lines |
|
|
(progn |
|
|
(forward-line 1) |
|
|
(end-of-line) |
|
|
(setq res (haskell-doc-wrapped-type-p))) |
|
|
(forward-char -1) |
|
|
;; (setq foo (concat foo (char-to-string (preceding-char)) (char-to-string (following-char)))) |
|
|
(if (or (and (or (char-equal (preceding-char) ?-) (char-equal (preceding-char) ?=)) |
|
|
(char-equal (following-char) ?>)) ; (or -!> =!> |
|
|
(char-equal (following-char) ?,)) ; !,) |
|
|
(setq res t) |
|
|
(forward-line) |
|
|
(let ((here (point))) |
|
|
(goto-char here) |
|
|
(skip-chars-forward " \t") |
|
|
(if (looking-at "--") ; it is a comment line |
|
|
(progn |
|
|
(forward-line 1) |
|
|
(end-of-line) |
|
|
(setq res (haskell-doc-wrapped-type-p))) |
|
|
(forward-char 1) |
|
|
;; (setq foo (concat foo (char-to-string (preceding-char)) (char-to-string (following-char)))) |
|
|
;; (message "|%s|" foo) |
|
|
(if (and (or (char-equal (preceding-char) ?-) (char-equal (preceding-char) ?=)) |
|
|
(char-equal (following-char) ?>)) ; -!> or =!> |
|
|
(setq res t)))))) |
|
|
res))) |
|
|
|
|
|
(defun haskell-doc-grab () |
|
|
"Return the text from point to the end of the line, chopping off comments. |
|
|
Leaves point at end of line." |
|
|
(let ((str (buffer-substring-no-properties |
|
|
(point) (progn (end-of-line) (point))))) |
|
|
(if (string-match "--" str) |
|
|
(substring str 0 (match-beginning 0)) |
|
|
str))) |
|
|
|
|
|
(defun haskell-doc-string-nub-ws (str) |
|
|
"Replace all sequences of whitespace in STR by just one space. |
|
|
ToDo: Also eliminate leading and trailing whitespace." |
|
|
(let ((i -1)) |
|
|
(while (setq i (string-match " [ \t\n]+\\|[\t\n]+" str (1+ i))) |
|
|
(setq str (replace-match " " t t str))) |
|
|
str)) |
|
|
|
|
|
;; ToDo: make this more efficient!! |
|
|
;;(defun haskell-doc-string-nub-ws (str) |
|
|
;; "Replace all sequences of whitespaces in STR by just one whitespace." |
|
|
;; (let ( (res "") |
|
|
;; (l (length str)) |
|
|
;; (i 0) |
|
|
;; (j 0) |
|
|
;; (in-ws nil)) |
|
|
;; (while (< i l) |
|
|
;; (let* ( (c (string-to-char (substring str i (1+ i)))) |
|
|
;; (is-ws (eq (char-syntax c) ? )) ) |
|
|
;; (if (not (and in-ws is-ws)) |
|
|
;; (setq res (concat res (char-to-string c)))) |
|
|
;; (setq in-ws is-ws) |
|
|
;; (setq i (1+ i)))) |
|
|
;; res)) |
|
|
|
|
|
(defun haskell-doc-chop-off-context (str) |
|
|
"Eliminate the context in a type represented by the string STR." |
|
|
(let ((i (string-match "=>" str)) ) |
|
|
(if (null i) |
|
|
str |
|
|
(substring str (+ i 2))))) |
|
|
|
|
|
(defun haskell-doc-get-imenu-info (obj kind) |
|
|
"Return a string describing OBJ of KIND \(Variables, Types, Data\)." |
|
|
(cond |
|
|
((eq major-mode 'haskell-mode) |
|
|
(let* ((imenu-info-alist (cdr (assoc kind imenu--index-alist))) |
|
|
;; (names (mapcar 'car imenu-info-alist)) |
|
|
(x (assoc obj imenu-info-alist))) |
|
|
(when x (haskell-doc-grab-line x)))) |
|
|
|
|
|
(t ;; (error "Cannot get local functions in %s mode, sorry" major-mode))) |
|
|
nil))) |
|
|
|
|
|
;; ToDo: |
|
|
;; - modular way of defining a mapping of module name to file |
|
|
;; - use a path to search for file (not just current directory) |
|
|
|
|
|
|
|
|
(defun haskell-doc-imported-list () |
|
|
"Return a list of the imported modules in current buffer." |
|
|
(interactive "fName of outer `include' file: ") ; (buffer-file-name)) |
|
|
;; Don't add current buffer to the imported file list if it is not (yet?) |
|
|
;; visiting a file since it leads to errors further down. |
|
|
(let ((imported-file-list (and buffer-file-name (list buffer-file-name)))) |
|
|
(widen) |
|
|
(goto-char (point-min)) |
|
|
(while (re-search-forward "^\\s-*import\\s-+\\([^ \t\n]+\\)" nil t) |
|
|
(let ((basename (match-string 1))) |
|
|
(dolist (ext '(".hs" ".lhs")) |
|
|
(let ((file (concat basename ext))) |
|
|
(if (file-exists-p file) |
|
|
(push file imported-file-list)))))) |
|
|
(nreverse imported-file-list) |
|
|
;;(message imported-file-list) |
|
|
)) |
|
|
|
|
|
;; ToDo: generalise this to "Types" etc (not just "Variables") |
|
|
|
|
|
(defun haskell-doc-rescan-files (filelist) |
|
|
"Do an `imenu' rescan on every file in FILELIST and return the fct-list. |
|
|
This function switches to and potentially loads many buffers." |
|
|
(save-current-buffer |
|
|
(mapcar (lambda (f) |
|
|
(set-buffer (find-file-noselect f)) |
|
|
(imenu--make-index-alist t) |
|
|
(cons f |
|
|
(mapcar (lambda (x) |
|
|
`(,(car x) . ,(haskell-doc-grab-line x))) |
|
|
(cdr (assoc "Variables" imenu--index-alist))))) |
|
|
filelist))) |
|
|
|
|
|
(defun haskell-doc-make-global-fct-index () |
|
|
"Scan imported files for types of global fcts and update `haskell-doc-index'." |
|
|
(interactive) |
|
|
(setq haskell-doc-index |
|
|
(haskell-doc-rescan-files (haskell-doc-imported-list)))) |
|
|
|
|
|
;; ToDo: use a separate munge-type function to format type concisely |
|
|
|
|
|
(defun haskell-doc-get-global-fct-type (&optional sym) |
|
|
"Get type for function symbol SYM by examining `haskell-doc-index'." |
|
|
(interactive) ; "fName of outer `include' file: \nsFct:") |
|
|
(save-excursion |
|
|
;; (switch-to-buffer "*scratch*") |
|
|
;; (goto-char (point-max)) |
|
|
;; ;; Produces a list of fct-type alists |
|
|
;; (if (null sym) |
|
|
;; (setq sym (progn (forward-word -1) (read (current-buffer))))) |
|
|
(or sym |
|
|
(current-word)) |
|
|
(let* ( (fn sym) ; (format "%s" sym)) |
|
|
(fal haskell-doc-index) |
|
|
(res "") ) |
|
|
(while (not (null fal)) |
|
|
(let* ( (l (car fal)) |
|
|
(f (car l)) |
|
|
(x (assoc fn (cdr l))) ) |
|
|
(if (not (null x)) |
|
|
(let* ( (ty (cdr x)) ; the type as string |
|
|
(idx (string-match "::" ty)) |
|
|
(str (if (null idx) |
|
|
ty |
|
|
(substring ty (+ idx 2)))) ) |
|
|
(setq res (format "[%s] %s" f str)))) |
|
|
(setq fal (cdr fal)))) |
|
|
res))) ; (message res)) ) |
|
|
|
|
|
(defun haskell-doc-get-and-format-fct-type (fn) |
|
|
"Get the type and kind of FN by checking local and global functions." |
|
|
(save-excursion |
|
|
(save-match-data |
|
|
(let ((docstring "") |
|
|
(doc nil) |
|
|
) |
|
|
;; is it a local function? |
|
|
(setq docstring (haskell-doc-get-imenu-info fn "Variables")) |
|
|
(if (not (null docstring)) |
|
|
;; (string-match (format "^%s\\s-+::\\s-+\\(.*\\)$" fn) docstring)) |
|
|
(setq doc `(,docstring . "Variables"))) ; `(,(match-string 1 docstring) . "Variables") )) |
|
|
;; is it a type declaration? |
|
|
(setq docstring (haskell-doc-get-imenu-info fn "Types")) |
|
|
(if (not (null docstring)) |
|
|
;; (string-match (format "^\\s-*type\\s-+%s.*$" fn) docstring)) |
|
|
(setq doc `(,docstring . "Types"))) ; `(,(match-string 0 docstring) . "Types")) ) |
|
|
(if (not (null docstring)) |
|
|
;; (string-match (format "^\\s-*data.*%s.*$" fn) docstring)) |
|
|
(setq doc `(,docstring . "Data"))) ; (setq doc `(,(match-string 0 docstring) . "Data")) ) |
|
|
;; return the result |
|
|
doc )))) |
|
|
|
|
|
(provide 'haskell-doc) |
|
|
|
|
|
;;; haskell-doc.el ends here
|
|
|
|