interface for Emacs imenu
diff --git a/Misc/pyimenu.el b/Misc/pyimenu.el
new file mode 100755
index 0000000..738de7d
--- /dev/null
+++ b/Misc/pyimenu.el
@@ -0,0 +1,305 @@
+;;; PYIMENU.EL --- 
+
+;; Copyright (C) 1995 Perry A. Stoll
+
+;; Author: Perry A. Stoll <stoll@atr-sw.atr.co.jp>
+;; Created: 12 May 1995
+;; Version: 1.0
+;; Keywords: tools python imenu
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 2, or (at your option)
+;; any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; A copy of the GNU General Public License can be obtained from the
+;; Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
+;; USA.
+
+;;;; COMMENTS
+
+;; I use the imenu package a lot for looking at Lisp and C/C++
+;; code. When I started using Python, I was dismayed that I couldn't
+;; use it to look at Python source. So here's a rough go at it.
+
+;;;; USAGE
+
+;; This program is used in conjunction with the imenu package. When
+;; you call imenu in python-mode in a python buffer, a list of
+;; functions and classes is built. The top level menu has a list of
+;; all functions and classes defined at the top indentation
+;; level. Classes which have methods defined in them have a submenu
+;; which contains all definitions contained in them. Selecting any
+;; item will bring you to that point in the file.
+
+;;;; INSTALLATION
+
+;; You know the routine:
+;; 1) Save this file as pyimenu.el,
+;; 2) Place that file somewhere in your emacs load path (maybe ~/emacs
+;;    or ~/emacs/lisp),
+;; 3) Byte compile it (M-x byte-compile-file),
+;; 4) Add the following (between "cut here" and "end here") to your
+;;    ~/.emacs file,
+;; 5) Reboot. (joke: DON'T do that, although you'll probably have to
+;;    either reload your ~/.emacs file or start a new emacs)
+
+;;--------------cut here-------------------------------------------
+;;;; Load the pyimenu index function
+;;(autoload 'imenu "imenu" nil t)
+;;(autoload 'imenu-example--create-python-index "pyimenu")
+;;;; Add the index creation function to the python-mode-hook 
+;;(add-hook 'python-mode-hook
+;;	  (function
+;;	   (lambda ()
+;;	     (setq imenu-create-index-function
+;;		   (function imenu-example--create-python-index)))))
+;;----------------end here--------------------------------------------
+;;
+;; That is all you need. Of course, the following provides a more
+;; useful interface. i.e. this is how I have it set up ;-)
+;;
+;;----------------optionally cut here----------------------------------
+;;(autoload 'imenu-add-to-menubar "imenu" nil t)
+;;(defun my-imenu-install-hook ()
+;;  (imenu-add-to-menubar (format "%s-%s" "IM" mode-name)))
+;;(add-hook 'python-mode-hook (function my-imenu-install-hook))
+;;;; Bind imenu to some convenient (?) mouse key. This really lets you
+;;;; fly around the buffer. Here it is set to Meta-Shift-Mouse3Click.
+;;(global-set-key [M-S-down-mouse-3] (function imenu))
+;;-----------------optionaly end here-----------------------------------
+
+;;;; CAVEATS/NOTES
+
+;; 0) I'm not a professional elisp programmer and it shows in the code
+;;    below. If anyone there has suggestions/changes, I'd love to
+;;    hear them. I've tried the code out on a bunch of python files
+;;    from the python-1.1.1 Demo distribution and it worked with
+;;    them - your mileage may very.
+;;
+;; 1) You must have the imenu package to use this file. This file
+;;    works with imenu version 1.11 (the version included with emacs
+;;    19.28) and imenu version 1.14; if you have a later version, this
+;;    may not work with it.
+;;
+;; 2) This setup assumes you also have python-mode.el, so that it can
+;;    use the python-mode-hook. It comes with the python distribution.
+;;
+;; 3) I don't have the Python 1.2 distribution yet, so again, this may
+;;    not work with that.
+;;
+
+(require 'imenu)
+
+;;;
+;;; VARIABLES: customizable in your .emacs file.
+;;;
+
+(defvar imenu-example--python-show-method-args-p nil 
+  "*When using imenu package with python-mode, whether the arguments of
+the function/methods should be printed in the imenu buffer in addition
+to the function/method name. If non-nil, args are printed.")
+
+;;;
+;;; VARIABLES: internal use.
+;;;
+(defvar imenu-example--python-class-regexp
+  (concat                              ; <<classes>>
+   "\\("                               ;
+   "^[ \t]*"                           ; newline and maybe whitespace
+   "\\(class[ \t]+[a-zA-Z0-9_]+\\)"    ; class name
+                                       ; possibly multiple superclasses
+   "\\([ \t]*\\((\\([a-zA-Z0-9_, \t\n]\\)*)\\)?\\)"
+   "[ \t]*:"                           ; and the final :
+   "\\)"                               ; >>classes<<
+   )
+  "Regexp for Python classes for use with the imenu package."
+)
+
+(defvar imenu-example--python-method-regexp
+  (concat                               ; <<methods and functions>>
+   "\\("                                ; 
+   "^[ \t]*"                            ; new line and maybe whitespace
+   "\\(def[ \t]+"                       ; function definitions start with def
+   "\\([a-zA-Z0-9_]+\\)"                ;   name is here
+					;   function arguments...
+   "[ \t]*(\\([a-zA-Z0-9_=,\* \t\n]*\\))"
+   "\\)"                                ; end of def
+   "[ \t]*:"                            ; and then the :
+   "\\)"                                ; >>methods and functions<<
+   )
+  "Regexp for Python methods/functions for use with the imenu package."
+  )
+
+(defvar imenu-example--python-method-no-arg-parens '(2 8)
+  "Indicies into the parenthesis list of the regular expression for
+python for use with imenu. Using these values will result in smaller
+imenu lists, as arguments to functions are not listed.
+
+See the variable imenu-example--python-show-method-args-p to for
+information")
+
+(defvar imenu-example--python-method-arg-parens '(2 7)
+  "Indicies into the parenthesis list of the regular expression for
+python for use with imenu. Using these values will result in large
+imenu lists, as arguments to functions are listed.
+
+See the variable imenu-example--python-show-method-args-p to for
+information")
+
+;; Note that in this format, this variable can still be used with the
+;; imenu--generic-function. Otherwise, there is no real reason to have
+;; it.
+(defvar imenu-example--generic-python-expression
+  (cons
+   (concat 
+    imenu-example--python-class-regexp
+    "\\|"  ; or...
+    imenu-example--python-method-regexp
+    )
+   imenu-example--python-method-no-arg-parens)
+  "Generic Python expression which may be used directly with imenu by
+setting the variable imenu-generic-expression to this value. Also, see
+the function \\[imenu-example--create-python-index] for an alternate
+way of finding the index.")
+
+;; These next two variables are used when searching for the python
+;; class/definitions. Just saving some time in accessing the
+;; generic-python-expression, really.
+(defvar imenu-example--python-generic-regexp)
+(defvar imenu-example--python-generic-parens)
+
+;;;
+;;; CODE:
+;;;
+
+;; Note:
+;; At first, I tried using some of the functions supplied by
+;; python-mode to navigate through functions and classes, but after a
+;; while, I decided dump it. This file is relatively self contained
+;; and I liked it that.
+
+;;;###autoload
+(defun imenu-example--create-python-index ()
+  "Interface function for imenu package to find all python classes and
+functions/methods. Calls function
+\\[imenu-example--create-python-index-engine]. See that function for
+the details of how this works."
+  (setq imenu-example--python-generic-regexp
+	(car imenu-example--generic-python-expression))
+  (setq imenu-example--python-generic-parens
+	(if imenu-example--python-show-method-args-p
+	    imenu-example--python-method-arg-parens
+	  imenu-example--python-method-no-arg-parens))
+  (goto-char (point-min))
+  (imenu-example--create-python-index-engine nil))
+
+(defun imenu-example--create-python-index-engine (&optional start-indent)
+"Function for finding all definitions (classes, methods, or functions)
+in a python file for the imenu package. 
+
+Retuns a possibly nested alist of the form \(INDEX-NAME
+ INDEX-POSITION). The second element of the alist may be an alist,
+producing a nested list as in \(INDEX-NAME . INDEX-ALIST).
+
+This function should not be called directly, as it calls itself
+recursively and requires some setup. Rather this is the engine for the
+function \\[imenu-example--create-python-index].
+
+It works recursively by looking for all definitions at the current
+indention level. When it finds one, it adds it to the alist. If it
+finds a definition at a greater indentation level, it removes the
+previous definition from the alist. In it's place it adds all
+definitions found at the next indentation level. When it finds a
+definition that is less indented then the current level, it retuns the
+alist it has created thus far.
+
+ The optional argument START-INDENT indicates the starting indentation
+at which to continue looking for python classes, methods, or
+functions. If this is not supplied, the function uses the indentation
+of the first definition found. "
+  (let ((index-alist '())
+	(sub-method-alist '())
+	looking-p
+	def-name prev-name
+	cur-indent def-pos
+	(class-paren (first  imenu-example--python-generic-parens)) 
+	(def-paren   (second imenu-example--python-generic-parens)))
+    (setq looking-p
+	  (re-search-forward imenu-example--python-generic-regexp
+			     (point-max) t))
+    (while looking-p
+      (save-excursion
+	;; used to set def-name to this value but generic-extract-name is
+	;; new to imenu-1.14. this way it still works with imenu-1.11
+	;;(imenu--generic-extract-name imenu-example--python-generic-parens))
+	(let ((cur-paren (if (match-beginning class-paren)
+			     class-paren def-paren)))
+	  (setq def-name
+		(buffer-substring (match-beginning cur-paren)
+				  (match-end  cur-paren))))
+	(beginning-of-line)
+	(setq cur-indent (current-indentation)))
+
+      ;; HACK: want to go to the correct definition location. Assuming
+      ;; here that there are only two..which is true for python.
+      (setq def-pos
+	    (or  (match-beginning class-paren)
+		 (match-beginning def-paren)))
+
+      ; if we don't have a starting indent level, take this one
+      (or start-indent
+	  (setq start-indent cur-indent))
+
+      ; if we don't have class name yet, take this one
+      (or prev-name
+	  (setq prev-name def-name))
+
+      ;; what level is the next definition on? 
+      ;; must be same, deeper or shallower indentation
+      (cond
+
+       ;; at the same indent level, add it to the list...
+       ((= start-indent cur-indent)
+	(push (cons def-name def-pos) index-alist))
+
+       ;; deeper indented expression, recur...
+       ((< start-indent cur-indent)
+
+	;; the point is currently on the expression we're supposed to
+	;; start on, so go back to the last expression. The recursive
+	;; call will find this place again and add it to the correct
+	;; list
+	(re-search-backward imenu-example--python-generic-regexp
+			    (point-min) 'move)
+	(setq sub-method-alist (imenu-example--create-python-index-engine
+				cur-indent))
+
+	(if sub-method-alist
+	    ;; we put the last element on the index-alist on the start
+	    ;; of the submethod alist so the user can still get to it.
+	    (let ((save-elmt (pop index-alist)))
+	      (push (cons (imenu-create-submenu-name prev-name)
+			  (cons save-elmt sub-method-alist))
+		    index-alist))))
+
+       ;; found less indented expression, we're done.
+       (t 
+	(setq looking-p nil)
+	(re-search-backward imenu-example--python-generic-regexp 
+			    (point-min) t)))
+      (setq prev-name def-name)
+      (and looking-p
+	   (setq looking-p
+		 (re-search-forward imenu-example--python-generic-regexp
+				    (point-max) 'move))))
+    (nreverse index-alist)))
+
+(provide 'pyimenu)
+
+;;; PyImenu.EL ends here