Added emacs scripts
This commit is contained in:
604
.emacs.d/elpa/haskell-mode-13.12/haskell-decl-scan.el
Normal file
604
.emacs.d/elpa/haskell-mode-13.12/haskell-decl-scan.el
Normal file
@@ -0,0 +1,604 @@
|
||||
;;; haskell-decl-scan.el --- Declaration scanning module for Haskell Mode
|
||||
|
||||
;; Copyright (C) 2004, 2005, 2007, 2009 Free Software Foundation, Inc.
|
||||
;; Copyright (C) 1997-1998 Graeme E Moss
|
||||
|
||||
;; Author: 1997-1998 Graeme E Moss <gem@cs.york.ac.uk>
|
||||
;; Maintainer: Stefan Monnier <monnier@gnu.org>
|
||||
;; Keywords: declarations menu files Haskell
|
||||
;; URL: http://cvs.haskell.org/cgi-bin/cvsweb.cgi/fptools/CONTRIB/haskell-modes/emacs/haskell-decl-scan.el?rev=HEAD
|
||||
|
||||
;; 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 3, 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
;;; 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:
|
||||
;;
|
||||
;; M-x customize-group haskell-decl-scan
|
||||
;;
|
||||
;;
|
||||
;; 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 Emacs.
|
||||
;;
|
||||
;; 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!):
|
||||
;;
|
||||
;; . 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 GreenCard?
|
||||
;;
|
||||
;; . 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.)
|
||||
|
||||
;; 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.
|
||||
|
||||
;;; Code:
|
||||
|
||||
(require 'cl-lib)
|
||||
(require 'haskell-mode)
|
||||
(require 'syntax)
|
||||
(require 'imenu)
|
||||
|
||||
(defgroup haskell-decl-scan nil
|
||||
"Haskell declaration scanning (`imenu' support)."
|
||||
:link '(custom-manual "(haskell-mode)haskell-decl-scan-mode")
|
||||
:group 'haskell
|
||||
:prefix "haskell-decl-scan-")
|
||||
|
||||
(defcustom haskell-decl-scan-bindings-as-variables nil
|
||||
"Whether to put top-level value bindings into a \"Variables\" category."
|
||||
:group 'haskell-decl-scan
|
||||
:type 'boolean)
|
||||
|
||||
(defcustom haskell-decl-scan-add-to-menubar t
|
||||
"Whether to add a \"Declarations\" menu entry to menu bar."
|
||||
:group 'haskell-decl-scan
|
||||
:type 'boolean)
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; General declaration scanning functions.
|
||||
|
||||
(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
|
||||
(let ((table (copy-syntax-table haskell-mode-syntax-table)))
|
||||
(modify-syntax-entry ?\' "w" table)
|
||||
(modify-syntax-entry ?_ "w" table)
|
||||
(modify-syntax-entry ?\\ "_" table)
|
||||
table)
|
||||
"Syntax table used for Haskell declaration scanning.")
|
||||
|
||||
|
||||
(defun haskell-ds-get-variable (prefix)
|
||||
"Return variable involved in value binding or type signature.
|
||||
Assumes 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). Otherwise return nil.
|
||||
Point is not changed."
|
||||
;; I think I can now handle all declarations bar those with comments
|
||||
;; nested before the second lexeme.
|
||||
(save-excursion
|
||||
(with-syntax-table haskell-ds-syntax-table
|
||||
(if (looking-at prefix) (goto-char (match-end 0)))
|
||||
;; Keyword.
|
||||
(if (looking-at haskell-ds-start-keywords-re)
|
||||
nil
|
||||
(or ;; Parenthesized symbolic variable.
|
||||
(and (looking-at "(\\(\\s_+\\))") (match-string-no-properties 1))
|
||||
;; General case.
|
||||
(if (looking-at
|
||||
(if (eq ?\( (char-after))
|
||||
;; Skip paranthesised expression.
|
||||
(progn
|
||||
(forward-sexp)
|
||||
;; Repeating this code and avoiding moving point if
|
||||
;; possible speeds things up.
|
||||
"\\(\\'\\)?\\s-*\\(\\s_+\\|`\\(\\sw+\\)`\\)")
|
||||
"\\(\\sw+\\)?\\s-*\\(\\s_+\\|`\\(\\sw+\\)`\\)"))
|
||||
(let ((match2 (match-string-no-properties 2)))
|
||||
;; Weed out `::', `∷',`=' and `|' from potential infix
|
||||
;; symbolic variable.
|
||||
(if (member match2 '("::" "∷" "=" "|"))
|
||||
;; Variable identifier.
|
||||
(match-string-no-properties 1)
|
||||
(if (eq (aref match2 0) ?\`)
|
||||
;; Infix variable identifier.
|
||||
(match-string-no-properties 3)
|
||||
;; Infix symbolic variable.
|
||||
match2))))
|
||||
;; Variable identifier.
|
||||
(and (looking-at "\\sw+") (match-string-no-properties 0)))))))
|
||||
|
||||
(defun haskell-ds-move-to-start-regexp (inc regexp)
|
||||
"Move to beginning of line that succeeds/precedes (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)))))
|
||||
|
||||
(defun haskell-ds-move-to-start-regexp-skipping-comments (inc regexp)
|
||||
"Like haskell-ds-move-to-start-regexp, but uses syntax-ppss to
|
||||
skip comments"
|
||||
(let (p)
|
||||
(cl-loop
|
||||
do (setq p (point))
|
||||
(haskell-ds-move-to-start-regexp inc regexp)
|
||||
while (and (nth 4 (syntax-ppss))
|
||||
(/= p (point))))))
|
||||
|
||||
(defvar literate-haskell-ds-line-prefix "> ?"
|
||||
"Regexp matching start of a line of Bird-style literate code.
|
||||
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))))
|
||||
;; Change syntax table.
|
||||
(with-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 (elt (syntax-ppss) 4)))
|
||||
(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 preceding the current one, skipping comments
|
||||
(haskell-ds-move-to-start-regexp-skipping-comments -1 start-decl-re))))
|
||||
;; If we are in the abyss, position and return as appropriate.
|
||||
(if abyss
|
||||
(if (not direction)
|
||||
nil
|
||||
(re-search-forward (concat "\\=" line-prefix) nil t)
|
||||
(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-skipping-comments 1 start-decl-re))
|
||||
;; If there is a variable, find the first
|
||||
;; succeeding/preceding declaration that does not type or
|
||||
;; bind it. Check for reaching start/end of buffer and
|
||||
;; comments.
|
||||
(haskell-ds-move-to-start-regexp-skipping-comments 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-skipping-comments 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-skipping-comments 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.
|
||||
(if at-start-decl (point) nil))))))
|
||||
|
||||
(defun haskell-ds-bird-p ()
|
||||
(and (boundp 'haskell-literate) (eq haskell-literate 'bird)))
|
||||
|
||||
(defun haskell-ds-backward-decl ()
|
||||
"Move backward to the first character 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 preceding 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 (haskell-ds-bird-p) nil))
|
||||
|
||||
(defun haskell-ds-forward-decl ()
|
||||
"As `haskell-ds-backward-decl' but forward."
|
||||
(interactive)
|
||||
(haskell-ds-move-to-decl t (haskell-ds-bird-p) nil))
|
||||
|
||||
(defun haskell-ds-generic-find-next-decl (bird-literate)
|
||||
"Find the name, position and type of the declaration at or after point.
|
||||
Return ((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)
|
||||
;; Change to declaration scanning syntax.
|
||||
(with-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 (line-end-position))
|
||||
(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 (match-string-no-properties 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 (match-string-no-properties 1))
|
||||
(setq name-pos (match-beginning 1))
|
||||
(setq type 'class))))
|
||||
;; Import declaration.
|
||||
((looking-at "import[ \t]+\\(?:safe[\t ]+\\)?\\(?:qualified[ \t]+\\)?\\(?:\"[^\"]*\"[\t ]+\\)?\\(\\(?:\\sw\\|.\\)+\\)")
|
||||
(setq name (match-string-no-properties 1))
|
||||
(setq name-pos (match-beginning 1))
|
||||
(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 (buffer-substring-no-properties
|
||||
(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))
|
||||
;; 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'.
|
||||
|
||||
;;;###autoload
|
||||
(defun haskell-ds-create-imenu-index ()
|
||||
"Function for finding `imenu' declarations in 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* ((bird-literate (haskell-ds-bird-p))
|
||||
(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 (/ (buffer-size) 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) (point-min)) 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.
|
||||
(sym (cdr (assq type
|
||||
'((variable . index-var-alist)
|
||||
(datatype . index-type-alist)
|
||||
(class . index-class-alist)
|
||||
(import . index-imp-alist)
|
||||
(instance . index-inst-alist))))))
|
||||
(set sym (cons (cons name start-pos) (symbol-value sym))))))
|
||||
;; Now sort all the lists, label them, and place them in one list.
|
||||
(message "Sorting declarations in %s..." bufname)
|
||||
(when index-type-alist
|
||||
(push (cons "Datatypes"
|
||||
(sort index-type-alist 'haskell-ds-imenu-label-cmp))
|
||||
index-alist))
|
||||
(when index-inst-alist
|
||||
(push (cons "Instances"
|
||||
(sort index-inst-alist 'haskell-ds-imenu-label-cmp))
|
||||
index-alist))
|
||||
(when index-imp-alist
|
||||
(push (cons "Imports"
|
||||
(sort index-imp-alist 'haskell-ds-imenu-label-cmp))
|
||||
index-alist))
|
||||
(when index-class-alist
|
||||
(push (cons "Classes"
|
||||
(sort index-class-alist 'haskell-ds-imenu-label-cmp))
|
||||
index-alist))
|
||||
(when index-var-alist
|
||||
(if haskell-decl-scan-bindings-as-variables
|
||||
(push (cons "Variables"
|
||||
(sort index-var-alist 'haskell-ds-imenu-label-cmp))
|
||||
index-alist)
|
||||
(setq index-alist (append index-alist
|
||||
(sort index-var-alist 'haskell-ds-imenu-label-cmp)))))
|
||||
(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 from `haskell-ds-create-imenu-index'."
|
||||
(string< (car el1) (car el2)))
|
||||
|
||||
(defun haskell-ds-imenu ()
|
||||
"Install `imenu' for Haskell scripts."
|
||||
(setq imenu-create-index-function 'haskell-ds-create-imenu-index)
|
||||
(when haskell-decl-scan-add-to-menubar
|
||||
(imenu-add-to-menubar "Declarations")))
|
||||
|
||||
;; The main functions to turn on declaration scanning.
|
||||
;;;###autoload
|
||||
(defun turn-on-haskell-decl-scan ()
|
||||
"Unconditionally activate `haskell-decl-scan-mode'."
|
||||
(interactive)
|
||||
(haskell-decl-scan-mode))
|
||||
|
||||
;;;###autoload
|
||||
(define-minor-mode haskell-decl-scan-mode
|
||||
"Toggle Haskell declaration scanning minor mode on or off.
|
||||
With a prefix argument ARG, enable minor mode if ARG is
|
||||
positive, and disable it otherwise. If called from Lisp, enable
|
||||
the mode if ARG is omitted or nil, and toggle it if ARG is `toggle'.
|
||||
|
||||
See also info node `(haskell-mode)haskell-decl-scan-mode' for
|
||||
more details about this minor mode.
|
||||
|
||||
Top-level declarations are scanned and listed in the menu item
|
||||
\"Declarations\" (if enabled via option
|
||||
`haskell-decl-scan-add-to-menubar'). Selecting an item from this
|
||||
menu will take point to the start of the declaration.
|
||||
|
||||
\\[beginning-of-defun] and \\[end-of-defun] move forward and backward to the start of a declaration.
|
||||
|
||||
This may link with `haskell-doc-mode'.
|
||||
|
||||
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.
|
||||
|
||||
Literate Haskell scripts are supported: If the value of
|
||||
`haskell-literate' (set automatically by `literate-haskell-mode')
|
||||
is `bird', a Bird-style literate script is assumed. If it is nil
|
||||
or `tex', a non-literate or LaTeX-style literate script is
|
||||
assumed, respectively.
|
||||
|
||||
Invokes `haskell-decl-scan-mode-hook' on activation."
|
||||
:group 'haskell-decl-scan
|
||||
|
||||
(kill-local-variable 'beginning-of-defun-function)
|
||||
(kill-local-variable 'end-of-defun-function)
|
||||
(kill-local-variable 'imenu-create-index-function)
|
||||
(unless haskell-decl-scan-mode
|
||||
;; How can we cleanly remove the "Declarations" menu?
|
||||
(when haskell-decl-scan-add-to-menubar
|
||||
(local-set-key [menu-bar index] nil)))
|
||||
|
||||
(when haskell-decl-scan-mode
|
||||
(set (make-local-variable 'beginning-of-defun-function)
|
||||
'haskell-ds-backward-decl)
|
||||
(set (make-local-variable 'end-of-defun-function)
|
||||
'haskell-ds-forward-decl)
|
||||
(haskell-ds-imenu)))
|
||||
|
||||
|
||||
;; Provide ourselves:
|
||||
|
||||
(provide 'haskell-decl-scan)
|
||||
|
||||
;;; haskell-decl-scan.el ends here
|
Reference in New Issue
Block a user