1. xemacs
  2. prog-modes

Commits

steveb  committed 2b7d09f

python.el-3.77, postscript regexp fix

  • Participants
  • Parent commits 0ded6e9
  • Branches default

Comments (0)

Files changed (4)

File ChangeLog

View file
+1998-09-04  Gunnar Evermann  <Gunnar.Evermann@nats.informatik.uni-hamburg.de>
+
+	* postscript.el: (postscript-font-lock-keywords) eliminate
+	redundancy from regexp for strings.
+
 1998-07-20  Tomasz Cholewo  <tjchol01@aivo.spd.louisville.edu>
 
 	* postscript.el: Fixed syntax table entry for '}'.

File Makefile

View file
 # the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 # Boston, MA 02111-1307, USA.
 
-VERSION = 1.08
+VERSION = 1.09
 AUTHOR_VERSION =
 MAINTAINER = XEmacs Development Team <xemacs-beta@xemacs.org>
 PACKAGE = prog-modes

File postscript.el

View file
 (defconst postscript-font-lock-keywords (purecopy
    (list
     ;; Proper rule for Postscript strings
-    '("(\\([^)]\\|\\\\.\\|\\\\\n\\)*)" . font-lock-string-face)
+    '("(\\([^)]*\\))" . font-lock-string-face)
     ;; Make any line beginning with a / be a ``keyword''
     '("^/[^\n%]*" . font-lock-keyword-face)
     ;; Make brackets of all forms be keywords

File python-mode.el

View file
 
 ;; Copyright (C) 1992,1993,1994  Tim Peters
 
-;; Author: 1995-1997 Barry A. Warsaw
+;; Author: 1995-1998 Barry A. Warsaw
 ;;         1992-1994 Tim Peters
 ;; Maintainer: python-mode@python.org
 ;; Created:    Feb 1992
 ;; Keywords:   python languages oop
 
-(defconst py-version "3.28"
+(defconst py-version "3.77"
   "`python-mode' version number.")
 
 ;; This software is provided as-is, without express or implied
 
 ;; This is a major mode for editing Python programs.  It was developed
 ;; by Tim Peters after an original idea by Michael A. Guravage.  Tim
-;; subsequently left the net; in 1995, Barry Warsaw inherited the
-;; mode and is the current maintainer.
-
-;; COMPATIBILITY:
+;; subsequently left the net; in 1995, Barry Warsaw inherited the mode
+;; and is the current maintainer.
 
 ;; This version of python-mode.el is no longer compatible with Emacs
-;; 18.  For a gabazillion reasons, I highly recommend upgrading to
-;; X/Emacs 19 or X/Emacs 20.  I recommend at least Emacs 19.34 or
-;; XEmacs 19.15.  Any of the v20 X/Emacsen should be fine.
-
-;; NOTE TO FSF EMACS USERS:
-
-;; You may need to acquire the Custom library -- this applies to users
-;; of Emacs 19.34 and NTEmacs based on 19.34, but not to Emacs 20
-;; users.  You must also byte-compile this file before use -- this
-;; applies to FSF's Emacs 19.34, 20.x, and NTEmacs based on 19.34.
-;; None of this applies to XEmacs (although byte compilation is still
-;; recommended).  You will also need to add the following to your
-;; .emacs file so that the .py files come up in python-mode:
+;; 18.  I am striving to maintain compatibility with the X/Emacs 19
+;; lineage but as time goes on that becomes more and more difficult.
+;; I current recommend that you upgrade to the latest stable released
+;; version of your favorite branch: Emacs 20.2 or better, or XEmacs
+;; 20.4 or better (Emacs 20.3 and XEmacs 21.0 are in beta testing as
+;; of this writing 20-Aug-1998 but both appear to work fine with this
+;; version of python-mode.el).  Even Windows users should be using at
+;; least NTEmacs 20.2, and XEmacs 21.0 will work very nicely on
+;; Windows when it is released.
+
+;; FOR MORE INFORMATION:
+
+;; For more information on installing python-mode.el, especially with
+;; respect to compatibility information, please see
 ;;
-;;     (autoload 'python-mode "python-mode" "Python editing mode." t)
-;;     (setq auto-mode-alist
-;;	     (cons '("\\.py$" . python-mode) auto-mode-alist))
-;;     (setq interpreter-mode-alist
-;;           (cons '("python" . python-mode) interpreter-mode-alist))
+;;     http://www.python.org/emacs/python-mode/
 ;;
-;; Assuming python-mode.el is on your load-path, it will be invoked
-;; when you visit a .py file, or a file with a first line that looks
-;; like:
-;;
-;;   #! /usr/bin/env python
-
-;; NOTE TO XEMACS USERS:
-
-;; An older version of this file was distributed with XEmacs 19.15,
-;; 19.16 and 20.3.  By default, in XEmacs when you visit a .py file,
-;; the buffer is put in Python mode.  Likewise for executable scripts
-;; with the word `python' on the first line.  You shouldn't need to do
-;; much except make sure this new version is earlier in your
-;; load-path, and byte-compile this file.
-
-;; FOR MORE INFORMATION:
-
-;; Please see <http://www.python.org/ftp/emacs/pmdetails.html> for the
-;; latest information and compatibility notes.
+;; This site also contains links to other packages that you might find 
+;; useful, such as pdb interfaces, OO-Browser links, etc.
 
 ;; BUG REPORTING:
 
 ;; doubtful that a texinfo manual would be very useful, but if you
 ;; want to contribute one, I'll certainly accept it!
 
-;; If you are using XEmacs, you may also want to check out OO-Browser
-;; that comes bundled with it, including documentation in the info
-;; pages.  For GNU Emacs you have to install it yourself.  To read
-;; more about OO-Browser, follow these links:
-
-;; http://www.python.org/workshops/1996-06/papers/h.pasanen/oobr_contents.html
-;; http://www.infodock.com/manuals/alt-oobr-cover.html
-
-;; You may also want to take a look at Harri Pasanen's "Python Library
-;; Reference Hot-Key Help System for XEmacs (or PLRHKHSX for short ;),
-;; version 1.0"
-;;
-;; <http://www.iki.fi/hpa/>
-
 ;; TO DO LIST:
 
 ;; - Better integration with pdb.py and gud-mode for debugging.
 ;; - Rewrite according to GNU Emacs Lisp standards.
-;; - possibly force indent-tabs-mode == nil, and add a
-;;   write-file-hooks that runs untabify on the whole buffer (to work
-;;   around potential tab/space mismatch problems).  In practice this
-;;   hasn't been a problem... yet.
 ;; - have py-execute-region on indented code act as if the region is
 ;;   left justified.  Avoids syntax errors.
 ;; - add a py-goto-block-down, bound to C-c C-d
 
 ;;; Code:
 
+(require 'comint)
 (require 'custom)
 (eval-when-compile
   (require 'cl)
-  (require 'custom)
-  ;; Stock Emacs 19.34 has a broken/old Custom library that does more
-  ;; harm than good
-  (or (fboundp 'defcustom)
+  (if (not (and (condition-case nil
+		    (require 'custom)
+		  (error nil))
+		;; Stock Emacs 19.34 has a broken/old Custom library
+		;; that does more harm than good.  Fortunately, it is
+		;; missing defcustom
+		(fboundp 'defcustom)))
       (error "STOP! STOP! STOP! STOP!
 
 The Custom library was not found or is out of date.  A more current
   :type 'string
   :group 'python)
 
+(defcustom py-jpython-command "jpython"
+  "*Shell command used to start the JPython interpreter."
+  :type 'string
+  :group 'python)
+
+(defcustom py-python-command-args '("-i")
+  "*List of string arguments to be used when starting a Python shell."
+  :type '(repeat string)
+  :group 'python)
+
+(defcustom py-jpython-command-args '("-i")
+  "*List of string arguments to be used when starting a JPython shell."
+  :type '(repeat string)
+  :group 'python)
+
 (defcustom py-indent-offset 4
-  "*Amount of offset per level of indentation
-Note that `\\[py-guess-indent-offset]' can usually guess a good value
-when you're editing someone else's Python code."
+  "*Amount of offset per level of indentation.
+`\\[py-guess-indent-offset]' can usually guess a good value when
+you're editing someone else's Python code."
   :type 'integer
   :group 'python)
 
+(defcustom py-smart-indentation t
+  "*Should `python-mode' try to automagically set some indentation variables?
+When this variable is non-nil, two things happen when a buffer is set
+to `python-mode':
+
+    1. `py-indent-offset' is guess from existing code in the buffer.
+       Only guessed values between 2 and 8 are considered.  If a valid
+       guess can't be made (perhaps because you are visiting a new
+       file), then the value in `py-indent-offset' is used.
+
+    2. `indent-tabs-mode' is turned off if `py-indent-offset' does not
+       equal `tab-width' (`indent-tabs-mode' is never turned on by
+       Python mode).  This means that for newly written code, tabs are
+       only inserted in indentation if one tab is one indentation
+       level, otherwise only spaces are used.
+
+Note that both these settings occur *after* `python-mode-hook' is run,
+so if you want to defeat the automagic configuration, you must also
+set `py-smart-indentation' to nil in your `python-mode-hook'."
+  :type 'boolean
+  :group 'python)
+
 (defcustom py-align-multiline-strings-p t
   "*Flag describing how multi-line triple quoted strings are aligned.
 When this flag is non-nil, continuation lines are lined up under the
 
 When t, lines that begin with a single `#' are a hint to subsequent
 line indentation.  If the previous line is such a comment line (as
-opposed to one that starts with `py-block-comment-prefix'), then it's
+opposed to one that starts with `py-block-comment-prefix'), then its
 indentation is used as a hint for this line's indentation.  Lines that
 begin with `py-block-comment-prefix' are ignored for indentation
 purposes.
 	  )
   :group 'python)
 
-(defcustom py-scroll-process-buffer t
-  "*Scroll Python process buffer as output arrives.
-If nil, the Python process buffer acts, with respect to scrolling, like
-Shell-mode buffers normally act.  This is surprisingly complicated and
-so won't be explained here; in fact, you can't get the whole story
-without studying the Emacs C code.
-
-If non-nil, the behavior is different in two respects (which are
-slightly inaccurate in the interest of brevity):
-
-  - If the buffer is in a window, and you left point at its end, the
-    window will scroll as new output arrives, and point will move to the
-    buffer's end, even if the window is not the selected window (that
-    being the one the cursor is in).  The usual behavior for shell-mode
-    windows is not to scroll, and to leave point where it was, if the
-    buffer is in a window other than the selected window.
-
-  - If the buffer is not visible in any window, and you left point at
-    its end, the buffer will be popped into a window as soon as more
-    output arrives.  This is handy if you have a long-running
-    computation and don't want to tie up screen area waiting for the
-    output.  The usual behavior for a shell-mode buffer is to stay
-    invisible until you explicitly visit it.
-
-Note the `and if you left point at its end' clauses in both of the
-above:  you can `turn off' the special behaviors while output is in
-progress, by visiting the Python buffer and moving point to anywhere
-besides the end.  Then the buffer won't scroll, point will remain where
-you leave it, and if you hide the buffer it will stay hidden until you
-visit it again.  You can enable and disable the special behaviors as
-often as you like, while output is in progress, by (respectively) moving
-point to, or away from, the end of the buffer.
-
-Warning:  If you expect a large amount of output, you'll probably be
-happier setting this option to nil.
-
-Obscure:  `End of buffer' above should really say `at or beyond the
-process mark', but if you know what that means you didn't need to be
-told <grin>."
-  :type 'boolean
-  :group 'python)
-
 (defcustom py-temp-directory
   (let ((ok '(lambda (x)
 	       (and x
 	(funcall ok "/tmp")
 	(funcall ok  ".")
 	(error
-	 "Couldn't find a usable temp directory -- set py-temp-directory")))
+	 "Couldn't find a usable temp directory -- set `py-temp-directory'")))
   "*Directory used for temp files created by a *Python* process.
 By default, the first directory from this list that exists and that you
 can write into:  the value (if any) of the environment variable TMPDIR,
   :group 'python)
 
 (defcustom py-beep-if-tab-change t
-  "*Ring the bell if tab-width is changed.
+  "*Ring the bell if `tab-width' is changed.
 If a comment of the form
 
   \t# vi:set tabsize=<number>:
 
 (defcustom py-jump-on-exception t
   "*Jump to innermost exception frame in *Python Output* buffer.
-When this variable is non-nil and ane exception occurs when running
+When this variable is non-nil and an exception occurs when running
 Python code synchronously in a subprocess, jump immediately to the
-source code of the innermost frame.")
+source code of the innermost traceback frame."
+  :type 'boolean
+  :group 'python)
+
+(defcustom py-ask-about-save t
+  "If not nil, ask about which buffers to save before executing some code.
+Otherwise, all modified buffers are saved without asking."
+  :type 'boolean
+  :group 'python)
 
 (defcustom py-backspace-function 'backward-delete-char-untabify
   "*Function called by `py-electric-backspace' when deleting backwards."
   :type 'function
   :group 'python)
 
+;; Not customizable
+(defvar py-master-file nil
+  "If non-nil, execute the named file instead of the buffer's file.
+The intent is to allow you to set this variable in the file's local
+variable section, e.g.:
+
+    # Local Variables:
+    # py-master-file: \"master.py\"
+    # End:
+
+so that typing \\[py-execute-buffer] in that buffer executes the named
+master file instead of the buffer's file.  Note that if the file name
+has a relative path, the value of `default-directory' for the buffer
+is prepended to come up with a file name.")
+(make-variable-buffer-local 'py-master-file)
+
 
 
 ;; ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 ;; Constants
 
-;; Regexp matching a Python string literal
 (defconst py-stringlit-re
   (concat
-   "'\\([^'\n\\]\\|\\\\.\\)*'"		; single-quoted
+   ;; These fail if backslash-quote ends the string (not worth
+   ;; fixing?).  They precede the short versions so that the first two
+   ;; quotes don't look like an empty short string.
+   ;;
+   ;; (maybe raw), long single quoted triple quoted strings (SQTQ),
+   ;; with potential embedded single quotes
+   "[rR]?'''[^']*\\(\\('[^']\\|''[^']\\)[^']*\\)*'''"
+   "\\|"
+   ;; (maybe raw), long double quoted triple quoted strings (DQTQ),
+   ;; with potential embedded double quotes
+   "[rR]?\"\"\"[^\"]*\\(\\(\"[^\"]\\|\"\"[^\"]\\)[^\"]*\\)*\"\"\""
+   "\\|"
+   "[rR]?'\\([^'\n\\]\\|\\\\.\\)*'"	; single-quoted
    "\\|"				; or
-   "\"\\([^\"\n\\]\\|\\\\.\\)*\""))	; double-quoted
-
-;; Regexp matching Python lines that are continued via backslash.
-;; This is tricky because a trailing backslash does not mean
-;; continuation if it's in a comment
+   "[rR]?\"\\([^\"\n\\]\\|\\\\.\\)*\""	; double-quoted
+   )
+  "Regular expression matching a Python string literal.")
+
 (defconst py-continued-re
+  ;; This is tricky because a trailing backslash does not mean
+  ;; continuation if it's in a comment
   (concat
    "\\(" "[^#'\"\n\\]" "\\|" py-stringlit-re "\\)*"
-   "\\\\$"))
+   "\\\\$")
+  "Regular expression matching Python backslash continuation lines.")
   
-;; Regexp matching blank or comment lines.
-(defconst py-blank-or-comment-re "[ \t]*\\($\\|#\\)")
-
-;; Regexp matching clauses to be outdented one level.
+(defconst py-blank-or-comment-re "[ \t]*\\($\\|#\\)"
+  "Regular expression matching a blank or comment line.")
+
 (defconst py-outdent-re
   (concat "\\(" (mapconcat 'identity
 			   '("else:"
 			     "finally:"
 			     "elif\\s +.*:")
 			   "\\|")
-	  "\\)"))
+	  "\\)")
+  "Regular expression matching statements to be dedented one level.")
   
-
-;; Regexp matching keywords which typically close a block
 (defconst py-block-closing-keywords-re
-  "\\(return\\|raise\\|break\\|continue\\|pass\\)")
-
-;; Regexp matching lines to not outdent after.
+  "\\(return\\|raise\\|break\\|continue\\|pass\\)"
+  "Regular expression matching keywords which typically close a block.")
+
 (defconst py-no-outdent-re
   (concat
    "\\("
 		    (concat py-block-closing-keywords-re "[ \t\n]")
 		    )
 	      "\\|")
-	  "\\)"))
-
-;; Regexp matching a function, method or variable assignment.  If you
-;; change this, you probably have to change `py-current-defun' as
-;; well.  This is only used by `py-current-defun' to find the name for
-;; add-log.el.
+	  "\\)")
+  "Regular expression matching lines not to dedent after.")
+
 (defconst py-defun-start-re
-  "^\\([ \t]*\\)def[ \t]+\\([a-zA-Z_0-9]+\\)\\|\\(^[a-zA-Z_0-9]+\\)[ \t]*=")
-
-;; Regexp for finding a class name.  If you change this, you probably
-;; have to change `py-current-defun' as well.  This is only used by
-;; `py-current-defun' to find the name for add-log.el.
-(defconst py-class-start-re "^class[ \t]*\\([a-zA-Z_0-9]+\\)")
-
-;; Regexp that describes tracebacks
+  "^\\([ \t]*\\)def[ \t]+\\([a-zA-Z_0-9]+\\)\\|\\(^[a-zA-Z_0-9]+\\)[ \t]*="
+  ;; If you change this, you probably have to change py-current-defun
+  ;; as well.  This is only used by py-current-defun to find the name
+  ;; for add-log.el.
+  "Regular expression matching a function, method, or variable assignment.")
+
+(defconst py-class-start-re "^class[ \t]*\\([a-zA-Z_0-9]+\\)"
+  ;; If you change this, you probably have to change py-current-defun
+  ;; as well.  This is only used by py-current-defun to find the name
+  ;; for add-log.el.
+  "Regular expression for finding a class name.")
+
 (defconst py-traceback-line-re
-  "[ \t]+File \"\\([^\"]+\\)\", line \\([0-9]+\\)")
+  "[ \t]+File \"\\([^\"]+\\)\", line \\([0-9]+\\)"
+  "Regular expression that describes tracebacks.")
 
 
 
 ;; Utilities
 
 (defmacro py-safe (&rest body)
-  ;; safely execute BODY, return nil if an error occurred
+  "Safely execute BODY, return nil if an error occurred."
   (` (condition-case nil
 	 (progn (,@ body))
        (error nil))))
 
 (defsubst py-keep-region-active ()
-  ;; Do whatever is necessary to keep the region active in XEmacs.
+  "Keep the region active in XEmacs."
   ;; Ignore byte-compiler warnings you might see.  Also note that
   ;; FSF's Emacs 19 does it differently; its policy doesn't require us
   ;; to take explicit action.
        (setq zmacs-region-stays t)))
 
 (defsubst py-point (position)
-  ;; Returns the value of point at certain commonly referenced POSITIONs.
-  ;; POSITION can be one of the following symbols:
-  ;; 
-  ;; bol  -- beginning of line
-  ;; eol  -- end of line
-  ;; bod  -- beginning of defun
-  ;; boi  -- back to indentation
-  ;; 
-  ;; This function does not modify point or mark.
+  "Returns the value of point at certain commonly referenced POSITIONs.
+POSITION can be one of the following symbols:
+
+  bol  -- beginning of line
+  eol  -- end of line
+  bod  -- beginning of def or class
+  eod  -- end of def or class
+  bob  -- beginning of buffer
+  eob  -- end of buffer
+  boi  -- back to indentation
+  bos  -- beginning of statement
+
+This function does not modify point or mark."
   (let ((here (point)))
     (cond
      ((eq position 'bol) (beginning-of-line))
      ((eq position 'eol) (end-of-line))
-     ((eq position 'bod) (beginning-of-python-def-or-class))
+     ((eq position 'bod) (py-beginning-of-def-or-class))
+     ((eq position 'eod) (py-end-of-def-or-class))
+     ;; Kind of funny, I know, but useful for py-up-exception.
      ((eq position 'bob) (beginning-of-buffer))
      ((eq position 'eob) (end-of-buffer))
      ((eq position 'boi) (back-to-indentation))
-     (t (error "unknown buffer position requested: %s" position))
+     ((eq position 'bos) (py-goto-initial-line))
+     (t (error "Unknown buffer position requested: %s" position))
      )
     (prog1
 	(point)
     )
    ))
 
+(defun py-in-literal (&optional lim)
+  "Return non-nil if point is in a Python literal (a comment or string).
+Optional argument LIM indicates the beginning of the containing form,
+i.e. the limit on how far back to scan."
+  ;; This is the version used for non-XEmacs, which has a nicer
+  ;; interface.
+  ;;
+  ;; WARNING: Watch out for infinite recursion.
+  (let* ((lim (or lim (c-point 'bod)))
+	 (state (parse-partial-sexp lim (point))))
+    (cond
+     ((nth 3 state) 'string)
+     ((nth 4 state) 'comment)
+     (t nil))))
+
+;; XEmacs has a built-in function that should make this much quicker.
+;; In this case, lim is ignored
+(defun py-fast-in-literal (&optional lim)
+  "Fast version of `py-in-literal', used only by XEmacs.
+Optional LIM is ignored."
+  ;; don't have to worry about context == 'block-comment
+  (buffer-syntactic-context))
+
+(if (fboundp 'buffer-syntactic-context)
+    (defalias 'py-in-literal 'py-fast-in-literal))
+
+
 
 ;; Major mode boilerplate
 
 (defvar python-mode-hook nil
   "*Hook called by `python-mode'.")
 
-;; in previous version of python-mode.el, the hook was incorrectly
-;; called py-mode-hook, and was not defvar'd.  deprecate its use.
+;; In previous version of python-mode.el, the hook was incorrectly
+;; called py-mode-hook, and was not defvar'd.  Deprecate its use.
 (and (fboundp 'make-obsolete-variable)
      (make-obsolete-variable 'py-mode-hook 'python-mode-hook))
 
   (define-key py-mode-map "\C-c>"     'py-shift-region-right)
   ;; subprocess commands
   (define-key py-mode-map "\C-c\C-c"  'py-execute-buffer)
+  (define-key py-mode-map "\C-c\C-m"  'py-execute-import-or-reload)
+  (define-key py-mode-map "\C-c\C-s"  'py-execute-string)
   (define-key py-mode-map "\C-c|"     'py-execute-region)
+  (define-key py-mode-map "\e\C-x"    'py-execute-def-or-class)
   (define-key py-mode-map "\C-c!"     'py-shell)
+  (define-key py-mode-map "\C-c\C-t"  'py-toggle-shells)
   ;; Caution!  Enter here at your own risk.  We are trying to support
   ;; several behaviors and it gets disgusting. :-( This logic ripped
   ;; largely from CC Mode.
   (define-key py-mode-map "\C-c#"     'py-comment-region)
   (define-key py-mode-map "\C-c?"     'py-describe-mode)
   (define-key py-mode-map "\C-c\C-hm" 'py-describe-mode)
-  (define-key py-mode-map "\e\C-a"    'beginning-of-python-def-or-class)
-  (define-key py-mode-map "\e\C-e"    'end-of-python-def-or-class)
+  (define-key py-mode-map "\e\C-a"    'py-beginning-of-def-or-class)
+  (define-key py-mode-map "\e\C-e"    'py-end-of-def-or-class)
   (define-key py-mode-map "\C-c-"     'py-up-exception)
   (define-key py-mode-map "\C-c="     'py-down-exception)
   ;; information
   (define-key py-mode-map "\C-c\C-b" 'py-submit-bug-report)
   (define-key py-mode-map "\C-c\C-v" 'py-version)
   ;; py-newline-and-indent mappings
-  (define-key py-mode-map "\n" 'py-newline-and-indent)
+  (define-key py-mode-map "\n"   'py-newline-and-indent)
+  (define-key py-mode-map "\C-m" 'py-newline-and-indent)
   ;; shadow global bindings for newline-and-indent w/ the py- version.
   ;; BAW - this is extremely bad form, but I'm not going to change it
   ;; for now.
   )
 
 (defvar py-mode-output-map nil
-  "Keymap used in *Python Output* buffers*")
+  "Keymap used in *Python Output* buffers.")
 (if py-mode-output-map
     nil
   (setq py-mode-output-map (make-sparse-keymap))
 	     (where-is-internal 'self-insert-command))
   )
 
+(defvar py-shell-map nil
+  "Keymap used in *Python* shell buffers.")
+(if py-shell-map
+    nil
+  (setq py-shell-map (copy-keymap comint-mode-map))
+  (define-key py-shell-map [tab]   'tab-to-tab-stop)
+  (define-key py-shell-map "\C-c-" 'py-up-exception)
+  (define-key py-shell-map "\C-c=" 'py-down-exception)
+  )
+
 (defvar py-mode-syntax-table nil
   "Syntax table used in `python-mode' buffers.")
 (if py-mode-syntax-table
 	["Shift region left"    py-shift-region-left (mark)]
 	["Shift region right"   py-shift-region-right (mark)]
 	"-"
+	["Import/reload file"   py-execute-import-or-reload t]
 	["Execute buffer"       py-execute-buffer t]
 	["Execute region"       py-execute-region (mark)]
+	["Execute def or class" py-execute-def-or-class (mark)]
+	["Execute string"       py-execute-string t]
 	["Start interpreter..." py-shell t]
 	"-"
 	["Go to start of block" py-goto-block-up t]
-	["Go to start of class" (beginning-of-python-def-or-class t) t]
-	["Move to end of class" (end-of-python-def-or-class t) t]
-	["Move to start of def" beginning-of-python-def-or-class t]
-	["Move to end of def"   end-of-python-def-or-class t]
+	["Go to start of class" (py-beginning-of-def-or-class t) t]
+	["Move to end of class" (py-end-of-def-or-class t) t]
+	["Move to start of def" py-beginning-of-def-or-class t]
+	["Move to end of def"   py-end-of-def-or-class t]
 	"-"
 	["Describe mode"        py-describe-mode t]
 	)))
    "^[ \t]*"				; newline and maybe whitespace
    "\\(class[ \t]+[a-zA-Z0-9_]+\\)"	; class name
 					; possibly multiple superclasses
-   "\\([ \t]*\\((\\([a-zA-Z0-9_, \t\n]\\)*)\\)?\\)"
+   "\\([ \t]*\\((\\([a-zA-Z0-9_,. \t\n]\\)*)\\)?\\)"
    "[ \t]*:"				; and the final :
    "\\)"				; >>classes<<
    )
    "\\(def[ \t]+"                       ; function definitions start with def
    "\\([a-zA-Z0-9_]+\\)"                ;   name is here
 					;   function arguments...
-   "[ \t]*(\\([a-zA-Z0-9_=,\* \t\n]*\\))"
+   "[ \t]*(\\([-+/a-zA-Z0-9_=,\* \t\n.()\"'#]*\\))"
    "\\)"                                ; end of def
    "[ \t]*:"                            ; and then the :
    "\\)"                                ; >>methods and functions<<
 	    imenu-example--python-method-arg-parens
 	  imenu-example--python-method-no-arg-parens))
   (goto-char (point-min))
-  (append (imenu-example--create-python-index-engine nil)
-	  (list (cons "* Top *" (point-min)))))
+  (imenu-example--create-python-index-engine nil))
 
 (defun imenu-example--create-python-index-engine (&optional start-indent)
   "Function for finding imenu definitions in Python.
 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
+previous definition from the alist. In its 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.
 	  (setq def-name
 		(buffer-substring-no-properties (match-beginning cur-paren)
 						(match-end  cur-paren))))
+	(save-match-data
+	  (py-beginning-of-def-or-class))
 	(beginning-of-line)
 	(setq cur-indent (current-indentation)))
 
 VARIABLES
 
 py-indent-offset\t\tindentation increment
-py-block-comment-prefix\t\tcomment string used by comment-region
+py-block-comment-prefix\t\tcomment string used by `comment-region'
 py-python-command\t\tshell command to invoke Python interpreter
-py-scroll-process-buffer\t\talways scroll Python process buffer
 py-temp-directory\t\tdirectory used for temp files (if needed)
-py-beep-if-tab-change\t\tring the bell if tab-width is changed"
+py-beep-if-tab-change\t\tring the bell if `tab-width' is changed"
   (interactive)
   ;; set up local variables
   (kill-all-local-variables)
   (make-local-variable 'comment-end)
   (make-local-variable 'comment-start-skip)
   (make-local-variable 'comment-column)
+  (make-local-variable 'comment-indent-function)
   (make-local-variable 'indent-region-function)
   (make-local-variable 'indent-line-function)
   (make-local-variable 'add-log-current-defun-function)
   ;;
   (set-syntax-table py-mode-syntax-table)
-  (setq major-mode             'python-mode
-	mode-name              "Python"
-	local-abbrev-table     python-mode-abbrev-table
-	font-lock-defaults     '(python-font-lock-keywords)
-	paragraph-separate     "^[ \t]*$"
-	paragraph-start        "^[ \t]*$"
-	require-final-newline  t
-	comment-start          "# "
-	comment-end            ""
-	comment-start-skip     "# *"
-	comment-column         40
-	indent-region-function 'py-indent-region
-	indent-line-function   'py-indent-line
+  (setq major-mode              'python-mode
+	mode-name               "Python"
+	local-abbrev-table      python-mode-abbrev-table
+	font-lock-defaults      '(python-font-lock-keywords)
+	paragraph-separate      "^[ \t]*$"
+	paragraph-start         "^[ \t]*$"
+	require-final-newline   t
+	comment-start           "# "
+	comment-end             ""
+	comment-start-skip      "# *"
+	comment-column          40
+	comment-indent-function 'py-comment-indent-function
+	indent-region-function  'py-indent-region
+	indent-line-function    'py-indent-line
 	;; tell add-log.el how to find the current function/method/variable
 	add-log-current-defun-function 'py-current-defun
 	)
   ;; Emacs 19 requires this
   (if (boundp 'comment-multi-line)
       (setq comment-multi-line nil))
-  ;; hack to allow overriding the tabsize in the file (see tokenizer.c)
-  ;;
-  ;; not sure where the magic comment has to be; to save time
-  ;; searching for a rarity, we give up if it's not found prior to the
-  ;; first executable statement.
-  ;;
-  ;; BAW - on first glance, this seems like complete hackery.  Why was
-  ;; this necessary, and is it still necessary?
-  (let ((case-fold-search nil)
-	(start (point))
-	new-tab-width)
-    (if (re-search-forward
-	 "^[ \t]*#[ \t]*vi:set[ \t]+tabsize=\\([0-9]+\\):"
-	 (prog2 (py-next-statement 1) (point) (goto-char 1))
-	 t)
-	(progn
-	  (setq new-tab-width
-		(string-to-int
-		 (buffer-substring (match-beginning 1) (match-end 1))))
-	  (if (= tab-width new-tab-width)
-	      nil
-	    (setq tab-width new-tab-width)
-	    (message "Caution: tab-width changed to %d" new-tab-width)
-	    (if py-beep-if-tab-change (beep)))))
-    (goto-char start))
-
-  ;; install imenu
-  (if (py-safe (require 'imenu))
-      (progn
-	(make-variable-buffer-local 'imenu-create-index-function)
-	(setq imenu-create-index-function
-	      (function imenu-example--create-python-index))
-	(setq imenu-generic-expression
-	      imenu-example--generic-python-expression)
-	(if (fboundp 'imenu-add-to-menubar)
-	    (imenu-add-to-menubar (format "%s-%s" "IM" mode-name)))
-	))
-
-  ;; run the mode hook. py-mode-hook use is deprecated
+  ;; Install Imenu, only works for Emacs.
+  (when (py-safe (require 'imenu))
+    (make-variable-buffer-local 'imenu-create-index-function)
+    (setq imenu-create-index-function
+	  (function imenu-example--create-python-index))
+    (setq imenu-generic-expression
+	  imenu-example--generic-python-expression)
+    (if (fboundp 'imenu-add-to-menubar)
+	(imenu-add-to-menubar (format "%s-%s" "IM" mode-name)))
+    )
+  ;; Run the mode hook.  Note that py-mode-hook is deprecated.
   (if python-mode-hook
       (run-hooks 'python-mode-hook)
-    (run-hooks 'py-mode-hook)))
+    (run-hooks 'py-mode-hook))
+  ;; Now do the automagical guessing
+  (if py-smart-indentation
+    (let ((offset py-indent-offset))
+      ;; It's okay if this fails to guess a good value
+      (if (and (py-safe (py-guess-indent-offset))
+	       (<= py-indent-offset 8)
+	       (>= py-indent-offset 2))
+	  (setq offset py-indent-offset))
+      (setq py-indent-offset offset)
+      ;; Only turn indent-tabs-mode off if tab-width !=
+      ;; py-indent-offset.  Never turn it on, because the user must
+      ;; have explicitly turned it off.
+      (if (/= tab-width py-indent-offset)
+	  (setq indent-tabs-mode nil))
+      )))
 
 
 ;; electric characters
 (defun py-outdent-p ()
-  ;; returns non-nil if the current line should outdent one level
+  "Returns non-nil if the current line should dedent one level."
   (save-excursion
     (and (progn (back-to-indentation)
 		(looking-at py-outdent-re))
-	 (progn (backward-to-indentation 1)
+	 (progn (forward-line -1)
+		(py-goto-initial-line)
+		(back-to-indentation)
 		(while (or (looking-at py-blank-or-comment-re)
 			   (bobp))
 		  (backward-to-indentation 1))
       
 (defun py-electric-colon (arg)
   "Insert a colon.
-In certain cases the line is outdented appropriately.  If a numeric
-argument is provided, that many colons are inserted non-electrically.
-Electric behavior is inhibited inside a string or comment."
+In certain cases the line is dedented appropriately.  If a numeric
+argument ARG is provided, that many colons are inserted
+non-electrically.  Electric behavior is inhibited inside a string or
+comment."
   (interactive "P")
   (self-insert-command (prefix-numeric-value arg))
   ;; are we in a string or comment?
   (if (save-excursion
 	(let ((pps (parse-partial-sexp (save-excursion
-					 (beginning-of-python-def-or-class)
+					 (py-beginning-of-def-or-class)
 					 (point))
 				       (point))))
 	  (not (or (nth 3 pps) (nth 4 pps)))))
 			       (py-compute-indentation t)))
 		   )
 	      (setq outdent py-indent-offset))
-	  ;; Don't indent, only outdent.  This assumes that any lines that
-	  ;; are already outdented relative to py-compute-indentation were
-	  ;; put there on purpose.  Its highly annoying to have `:' indent
-	  ;; for you.  Use TAB, C-c C-l or C-c C-r to adjust.  TBD: Is
-	  ;; there a better way to determine this???
+	  ;; Don't indent, only dedent.  This assumes that any lines
+	  ;; that are already dedented relative to
+	  ;; py-compute-indentation were put there on purpose.  It's
+	  ;; highly annoying to have `:' indent for you.  Use TAB, C-c
+	  ;; C-l or C-c C-r to adjust.  TBD: Is there a better way to
+	  ;; determine this???
 	  (if (< (current-indentation) indent) nil
 	    (goto-char here)
 	    (beginning-of-line)
 
 ;; Python subprocess utilities and filters
 (defun py-execute-file (proc filename)
-  ;; Send a properly formatted execfile('FILENAME') to the underlying
-  ;; Python interpreter process FILENAME.  Make that process's buffer
-  ;; visible and force display.  Also make comint believe the user
-  ;; typed this string so that kill-output-from-shell does The Right
-  ;; Thing.
+  "Send to Python interpreter process PROC \"execfile('FILENAME')\".
+Make that process's buffer visible and force display.  Also make
+comint believe the user typed this string so that
+`kill-output-from-shell' does The Right Thing."
   (let ((curbuf (current-buffer))
 	(procbuf (process-buffer proc))
-	(comint-scroll-to-bottom-on-output t)
+;	(comint-scroll-to-bottom-on-output t)
 	(msg (format "## working on region in file %s...\n" filename))
 	(cmd (format "execfile('%s')\n" filename)))
     (unwind-protect
-	(progn
+	(save-excursion
 	  (set-buffer procbuf)
 	  (goto-char (point-max))
 	  (move-marker (process-mark proc) (point))
       (set-buffer curbuf))
     (process-send-string proc cmd)))
 
-(defun py-process-filter (pyproc string)
-  (let ((curbuf (current-buffer))
-	(pbuf (process-buffer pyproc))
-	(pmark (process-mark pyproc))
-	file-finished)
-    ;; make sure we switch to a different buffer at least once.  if we
-    ;; *don't* do this, then if the process buffer is in the selected
-    ;; window, and point is before the end, and lots of output is
-    ;; coming at a fast pace, then (a) simple cursor-movement commands
-    ;; like C-p, C-n, C-f, C-b, C-a, C-e take an incredibly long time
-    ;; to have a visible effect (the window just doesn't get updated,
-    ;; sometimes for minutes(!)), and (b) it takes about 5x longer to
-    ;; get all the process output (until the next python prompt).
-    ;;
-    ;; #b makes no sense to me at all.  #a almost makes sense: unless
-    ;; we actually change buffers, set_buffer_internal in buffer.c
-    ;; doesn't set windows_or_buffers_changed to 1, & that in turn
-    ;; seems to make the Emacs command loop reluctant to update the
-    ;; display.  Perhaps the default process filter in process.c's
-    ;; read_process_output has update_mode_lines++ for a similar
-    ;; reason?  beats me ...
-
-    (unwind-protect
-	;; make sure current buffer is restored
-	;; BAW - we want to check to see if this still applies
-	(progn
-	  ;; mysterious ugly hack
-	  (if (eq curbuf pbuf)
-	      (set-buffer (get-buffer-create "*scratch*")))
-
-	  (set-buffer pbuf)
-	  (let* ((start (point))
-		 (goback (< start pmark))
-		 (goend (and (not goback) (= start (point-max))))
-		 (buffer-read-only nil))
-	    (goto-char pmark)
-	    (insert string)
-	    (move-marker pmark (point))
-	    (setq file-finished
-		  (and py-file-queue
-		       (equal ">>> "
-			      (buffer-substring
-			       (prog2 (beginning-of-line) (point)
-				 (goto-char pmark))
-			       (point)))))
-	    (if goback (goto-char start)
-	      ;; else
-	      (if py-scroll-process-buffer
-		  (let* ((pop-up-windows t)
-			 (pwin (display-buffer pbuf)))
-		    (set-window-point pwin (point)))))
-	    (set-buffer curbuf)
-	    (if file-finished
-		(progn
-		  (py-safe (delete-file (car py-file-queue)))
-		  (setq py-file-queue (cdr py-file-queue))
-		  (if py-file-queue
-		      (py-execute-file pyproc (car py-file-queue)))))
-	    (and goend
-		 (progn (set-buffer pbuf)
-			(goto-char (point-max))))
-	    ))
-      (set-buffer curbuf))))
+(defun py-comint-output-filter-function (string)
+  "Watch output for Python prompt and exec next file waiting in queue.
+This function is appropriate for `comint-output-filter-functions'."
+  (when (and (string-equal ">>> " string)
+	     py-file-queue)
+    (py-safe (delete-file (car py-file-queue)))
+    (setq py-file-queue (cdr py-file-queue))
+    (if py-file-queue
+	(let ((pyproc (get-buffer-process (current-buffer))))
+	  (py-execute-file pyproc (car py-file-queue))))
+    ))
 
 (defun py-postprocess-output-buffer (buf)
-  (let (line file bol)
+  "Highlight exceptions found in BUF.
+If an exception occurred return t, otherwise return nil.  BUF must exist."
+  (let (line file bol err-p)
     (save-excursion
       (set-buffer buf)
       (beginning-of-buffer)
 	(setq file (match-string 1)
 	      line (string-to-int (match-string 2))
 	      bol (py-point 'bol))
-	(py-highlight-line bol (py-point 'eol) file line))
-      (when (and py-jump-on-exception line)
-	(beep)
-	(py-jump-to-exception file line))
-      )))
+	(py-highlight-line bol (py-point 'eol) file line)))
+    (when (and py-jump-on-exception line)
+      (beep)
+      (py-jump-to-exception file line)
+      (setq err-p t))
+    err-p))
 
 
 
 (defvar py-serial-number 0)
 (defvar py-exception-buffer nil)
 (defconst py-output-buffer "*Python Output*")
+(make-variable-buffer-local 'py-output-buffer)
+
+;; for toggling between CPython and JPython
+(defvar py-which-shell py-python-command)
+(defvar py-which-args  py-python-command-args)
+(defvar py-which-bufname "Python")
+(make-variable-buffer-local 'py-which-shell)
+(make-variable-buffer-local 'py-which-args)
+(make-variable-buffer-local 'py-which-bufname)
+
+(defun py-toggle-shells (arg)
+  "Toggles between the CPython and JPython shells.
+With positive argument ARG (interactively \\[universal-argument]),
+uses the CPython shell, with negative ARG uses the JPython shell, and
+with a zero argument, toggles the shell."
+  (interactive "P")
+  ;; default is to toggle
+  (if (null arg)
+      (setq arg 0))
+  ;; toggle if zero
+  (if (= arg 0)
+      (if (string-equal py-which-bufname "Python")
+	  (setq arg -1)
+	(setq arg 1)))
+  (let (msg)
+    (cond
+     ((< 0 arg)
+      ;; set to CPython
+      (setq py-which-shell py-python-command
+	    py-which-args py-python-command-args
+	    py-which-bufname "Python"
+	    msg "CPython"
+	    mode-name "Python"))
+     ((> 0 arg)
+      (setq py-which-shell py-jpython-command
+	    py-which-args py-jpython-command-args
+	    py-which-bufname "JPython"
+	    msg "JPython"
+	    mode-name "JPython"))
+     )
+    (message "Using the %s shell" msg)
+    (setq py-output-buffer (format "*%s Output*" py-which-bufname))))
 
 ;;;###autoload
 (defun py-shell ()
 sections of the Emacs manual for details, especially for the key
 bindings active in the `*Python*' buffer.
 
-See the docs for variable `py-scroll-buffer' for info on scrolling
-behavior in the process window.
+Note: You can toggle between using the CPython interpreter and the
+JPython interpreter by hitting \\[py-toggle-shells].  This toggles
+buffer local variables which control whether all your subshell
+interactions happen to the `*JPython*' or `*Python*' buffers (the
+latter is the name used for the CPython buffer).
 
 Warning: Don't use an interactive Python if you change sys.ps1 or
 sys.ps2 from their default values, or if you're running code that
   ;; BAW - should undo be disabled in the python process buffer, if
   ;; this bug still exists?
   (interactive)
-  (require 'comint)
   (switch-to-buffer-other-window
-   (make-comint "Python" py-python-command nil "-i"))
+   (apply 'make-comint py-which-bufname py-which-shell nil py-which-args))
   (make-local-variable 'comint-prompt-regexp)
-  (setq comint-prompt-regexp "^>>> \\|^[.][.][.] ")
-  (set-process-filter (get-buffer-process (current-buffer)) 'py-process-filter)
+  (setq comint-prompt-regexp "^>>> \\|^[.][.][.] \\|^(pdb) ")
+  (add-hook 'comint-output-filter-functions 'py-comint-output-filter-function)
   (set-syntax-table py-mode-syntax-table)
-  ;; set up keybindings for this subshell
-  (local-set-key [tab]   'self-insert-command)
-  (local-set-key "\C-c-" 'py-up-exception)
-  (local-set-key "\C-c=" 'py-down-exception)
+  (use-local-map py-shell-map)
   )
 
 (defun py-clear-queue ()
     (setq py-file-queue nil)
     (message "%d pending files de-queued." n)))
 
+
 (defun py-execute-region (start end &optional async)
-  "Execute the the region in a Python interpreter.
+  "Execute the region in a Python interpreter.
+
 The region is first copied into a temporary file (in the directory
 `py-temp-directory').  If there is no Python interpreter shell
 running, this file is executed synchronously using
-`shell-command-on-region'.  If the program is long running, use an
-optional \\[universal-argument] to run the command asynchronously in
-its own buffer.
+`shell-command-on-region'.  If the program is long running, use
+\\[universal-argument] to run the command asynchronously in its own
+buffer.
+
+When this function is used programmatically, arguments START and END
+specify the region to execute, and optional third argument ASYNC, if
+non-nil, specifies to run the command asynchronously in its own
+buffer.
 
 If the Python interpreter shell is running, the region is execfile()'d
 in that shell.  If you try to execute regions too quickly,
       (error "Region is empty"))
   (let* ((proc (get-process "Python"))
 	 (temp (if (memq 'broken-temp-names py-emacs-features)
-		   (prog1
-		       (format "python-%d" py-serial-number)
-		     (setq py-serial-number (1+ py-serial-number)))
-		 (make-temp-name "python")))
-	 (file (concat (file-name-as-directory py-temp-directory) temp)))
+		   (let
+		       ((sn py-serial-number)
+			(pid (and (fboundp 'emacs-pid) (emacs-pid))))
+		     (setq py-serial-number (1+ py-serial-number))
+		     (if pid
+			 (format "python-%d-%d" sn pid)
+		       (format "python-%d" sn)))
+		 (make-temp-name "python-")))
+	 (file (expand-file-name temp py-temp-directory)))
     (write-region start end file nil 'nomsg)
     (cond
-     ;; always run the code in it's own asynchronous subprocess
+     ;; always run the code in its own asynchronous subprocess
      (async
       (let* ((buf (generate-new-buffer-name py-output-buffer)))
 	(start-process "Python" buf py-python-command "-u" file)
       (if (not py-file-queue)
 	  (py-execute-file proc file)
 	(message "File %s queued for execution" file))
-      (push file py-file-queue)
+      (setq py-file-queue (append py-file-queue (list file)))
       (setq py-exception-buffer (cons file (current-buffer))))
      (t
       ;; otherwise either run it synchronously in a subprocess
       (shell-command-on-region start end py-python-command py-output-buffer)
-      (setq py-exception-buffer (current-buffer))
-      (py-postprocess-output-buffer py-output-buffer)
-      ))))
-
-;; Code execution command
+      ;; shell-command-on-region kills the output buffer if it never
+      ;; existed and there's no output from the command
+      (if (not (get-buffer py-output-buffer))
+	  (message "No output.")
+	(setq py-exception-buffer (current-buffer))
+	(let ((err-p (py-postprocess-output-buffer py-output-buffer)))
+	  (pop-to-buffer py-output-buffer)
+	  (if err-p
+	      (pop-to-buffer py-exception-buffer)))
+	))
+     )))
+
+
+;; Code execution commands
 (defun py-execute-buffer (&optional async)
   "Send the contents of the buffer to a Python interpreter.
+If the file local variable `py-master-file' is non-nil, execute the
+named file instead of the buffer's file.
+
 If there is a *Python* process buffer it is used.  If a clipping
 restriction is in effect, only the accessible portion of the buffer is
 sent.  A trailing newline will be supplied if needed.
 
-See the `\\[py-execute-region]' docs for an account of some subtleties."
+See the `\\[py-execute-region]' docs for an account of some
+subtleties, including the use of the optional ASYNC argument."
   (interactive "P")
+  (if py-master-file
+      (let* ((filename (expand-file-name py-master-file))
+	     (buffer (or (get-file-buffer filename)
+			 (find-file-noselect filename))))
+	(set-buffer buffer)))
   (py-execute-region (point-min) (point-max) async))
 
+(defun py-execute-import-or-reload (&optional async)
+  "Import the current buffer's file in a Python interpreter.
+
+If the file has already been imported, then do reload instead to get
+the latest version.
+
+If the file's name does not end in \".py\", then do execfile instead.
+
+If the current buffer is not visiting a file, do `py-execute-buffer'
+instead.
+
+If the file local variable `py-master-file' is non-nil, import or
+reload the named file instead of the buffer's file.  The file may be
+saved based on the value of `py-execute-import-or-reload-save-p'.
+
+See the `\\[py-execute-region]' docs for an account of some
+subtleties, including the use of the optional ASYNC argument.
+
+This may be preferable to `\\[py-execute-buffer]' because:
+
+ - Definitions stay in their module rather than appearing at top
+   level, where they would clutter the global namespace and not affect
+   uses of qualified names (MODULE.NAME).
+
+ - The Python debugger gets line number information about the functions."
+  (interactive "P")
+  ;; Check file local variable py-master-file
+  (if py-master-file
+      (let* ((filename (expand-file-name py-master-file))
+             (buffer (or (get-file-buffer filename)
+                         (find-file-noselect filename))))
+        (set-buffer buffer)))
+  (let ((file (buffer-file-name (current-buffer))))
+    (if file
+        (progn
+	  ;; Maybe save some buffers
+	  (save-some-buffers (not py-ask-about-save) nil)
+          (py-execute-string
+           (if (string-match "\\.py$" file)
+               (let ((f (file-name-sans-extension
+			 (file-name-nondirectory file))))
+                 (format "if globals().has_key('%s'):\n    reload(%s)\nelse:\n    import %s\n"
+                         f f f))
+             (format "execfile('%s')\n" file))
+           async))
+      ;; else
+      (py-execute-buffer async))))
+
+
+(defun py-execute-def-or-class (&optional async)
+  "Send the current function or class definition to a Python interpreter.
+
+If there is a *Python* process buffer it is used.
+
+See the `\\[py-execute-region]' docs for an account of some
+subtleties, including the use of the optional ASYNC argument."
+  (interactive "P")
+  (save-excursion
+    (py-mark-def-or-class)
+    ;; mark is before point
+    (py-execute-region (mark) (point) async)))
+
+
+(defun py-execute-string (string &optional async)
+  "Send the argument STRING to a Python interpreter.
+
+If there is a *Python* process buffer it is used.
+
+See the `\\[py-execute-region]' docs for an account of some
+subtleties, including the use of the optional ASYNC argument."
+  (interactive "sExecute Python command: ")
+  (save-excursion
+    (set-buffer (get-buffer-create
+                 (generate-new-buffer-name " *Python Command*")))
+    (insert string)
+    (py-execute-region (point-min) (point-max) async)))
+
 
 
 (defun py-jump-to-exception (file line)
+  "Jump to the Python code in FILE at LINE."
   (let ((buffer (cond ((string-equal file "<stdin>")
-		       py-exception-buffer)
+		       (if (consp py-exception-buffer)
+			   (cdr py-exception-buffer)
+			 py-exception-buffer))
 		      ((and (consp py-exception-buffer)
 			    (string-equal file (car py-exception-buffer)))
 		       (cdr py-exception-buffer))
 						    nil
 						    file t))))))
     (pop-to-buffer buffer)
+    ;; Force Python mode
+    (if (not (eq major-mode 'python-mode))
+	(python-mode))
     (goto-line line)
     (message "Jumping to exception in file %s on line %d" file line)))
 
 (defun py-mouseto-exception (event)
+  "Jump to the code which caused the Python exception at EVENT.
+EVENT is usually a mouse click."
   (interactive "e")
   (cond
    ((fboundp 'event-point)
 	  (setq file (match-string 1)
 		line (string-to-int (match-string 2)))))
     (if (not file)
-	(error "Not on a traceback line."))
+	(error "Not on a traceback line"))
     (py-jump-to-exception file line)))
 
 (defun py-find-next-exception (start buffer searchdir errwhere)
-  ;; Go to start position in buffer, search in the specified
-  ;; direction, and jump to the exception found.  If at the end of the
-  ;; exception, print error message
+  "Find the next Python exception and jump to the code that caused it.
+START is the buffer position in BUFFER from which to begin searching
+for an exception.  SEARCHDIR is a function, either
+`re-search-backward' or `re-search-forward' indicating the direction
+to search.  ERRWHERE is used in an error message if the limit (top or
+bottom) of the trackback stack is encountered."
   (let (file line)
     (save-excursion
       (set-buffer buffer)
 
 (defun py-down-exception (&optional bottom)
   "Go to the next line down in the traceback.
-With optional \\[universal-argument], jump to the bottom (innermost)
-exception in the exception stack."
+With \\[univeral-argument] (programmatically, optional argument
+BOTTOM), jump to the bottom (innermost) exception in the exception
+stack."
   (interactive "P")
   (let* ((proc (get-process "Python"))
 	 (buffer (if proc "*Python*" py-output-buffer)))
 
 (defun py-up-exception (&optional top)
   "Go to the previous line up in the traceback.
-With optional \\[universal-argument], jump to the top (outermost)
-exception in the exception stack."
+With \\[universal-argument] (programmatically, optional argument TOP)
+jump to the top (outermost) exception in the exception stack."
   (interactive "P")
   (let* ((proc (get-process "Python"))
 	 (buffer (if proc "*Python*" py-output-buffer)))
 
 ;; Electric deletion
 (defun py-electric-backspace (arg)
-  "Deletes preceding character or levels of indentation.
+  "Delete preceding character or levels of indentation.
 Deletion is performed by calling the function in `py-backspace-function'
 with a single argument (the number of characters to delete).
 
-If point is at the leftmost column, deletes the preceding newline.
+If point is at the leftmost column, delete the preceding newline.
 
 Otherwise, if point is at the leftmost non-whitespace character of a
 line that is neither a continuation line nor a non-indenting comment
 line, or if point is at the end of a blank line, this command reduces
 the indentation to match that of the line that opened the current
 block of code.  The line that opened the block is displayed in the
-echo area to help you keep track of where you are.  With numeric arg,
-outdents that many blocks (but not past column zero).
+echo area to help you keep track of where you are.  With
+\\[universal-argument] dedents that many blocks (but not past column
+zero).
 
 Otherwise the preceding character is deleted, converting a tab to
 spaces if needed so that only a single column position is deleted.
-Numeric argument deletes that many preceding characters."
+\\[universal-argument] specifies how many characters to delete
+(default is 1).
+
+When used programmatically, argument ARG specifies the number of
+blocks to dedent, or the number of characters to delete, as indicated
+above."
   (interactive "*p")
   (if (or (/= (current-indentation) (current-column))
 	  (bolp)
 
 
 (defun py-electric-delete (arg)
-  "Deletes preceding or following character or levels of whitespace.
+  "Delete preceding or following character or levels of whitespace.
 
 The behavior of this function depends on the variable
 `delete-key-deletes-forward'.  If this variable is nil (or does not
-exist, as in older Emacsen), then this function behaves identical to
-\\[c-electric-backspace].
+exist, as in older Emacsen and non-XEmacs versions), then this
+function behaves identically to \\[c-electric-backspace].
 
 If `delete-key-deletes-forward' is non-nil and is supported in your
 Emacs, then deletion occurs in the forward direction, by calling the
-function in `py-delete-function'."
+function in `py-delete-function'.
+
+\\[universal-argument] (programmatically, argument ARG) specifies the
+number of characters to delete (default is 1)."
   (interactive "*p")
   (if (and (boundp 'delete-key-deletes-forward)
 	   delete-key-deletes-forward)
 
 (defun py-indent-line (&optional arg)
   "Fix the indentation of the current line according to Python rules.
-With \\[universal-argument], ignore outdenting rules for block
-closing statements (e.g. return, raise, break, continue, pass)
+With \\[universal-argument] (programmatically, the optional argument
+ARG non-nil), ignore dedenting rules for block closing statements
+(e.g. return, raise, break, continue, pass)
 
 This function is normally bound to `indent-line-function' so
 \\[indent-for-tab-command] will call it."
   (let* ((ci (current-indentation))
 	 (move-to-indentation-p (<= (current-column) ci))
 	 (need (py-compute-indentation (not arg))))
-    ;; see if we need to outdent
+    ;; see if we need to dedent
     (if (py-outdent-p)
 	(setq need (- need py-indent-offset)))
     (if (/= ci need)
       (move-to-column ci))))
 
 (defun py-compute-indentation (honor-block-close-p)
-  ;; implements all the rules for indentation computation.  when
-  ;; honor-block-close-p is non-nil, statements such as return, raise,
-  ;; break, continue, and pass force one level of outdenting.
+  "Compute Python indentation.
+When HONOR-BLOCK-CLOSE-P is non-nil, statements such as `return',
+`raise', `break', `continue', and `pass' force one level of
+dedenting."
   (save-excursion
+    (beginning-of-line)
     (let* ((bod (py-point 'bod))
 	   (pps (parse-partial-sexp bod (point)))
 	   (boipps (parse-partial-sexp bod (py-point 'boi))))
-      (beginning-of-line)
       (cond
        ;; are we inside a multi-line string or comment?
        ((or (and (nth 3 pps) (nth 3 boipps))
 		  (while (and (< (point) startpos)
 			      (looking-at "[ \t]*[#\n\\\\]")) ; skip noise
 		    (forward-line 1))
-		  (if (< (point) startpos)
+		  (if (and (< (point) startpos)
+			   (/= startpos
+			       (save-excursion
+				 (goto-char (1+ open-bracket-pos))
+				 (forward-comment (point-max))
+				 (point))))
 		      ;; again mimic the first list item
 		      (current-indentation)
 		    ;; else they're about to enter the first item
        ;; The rules for indenting comment lines are a line where:
        ;;   - the first non-whitespace character is `#', and
        ;;   - the character following the `#' is whitespace, and
-       ;;   - the line is outdented with respect to (i.e. to the left
+       ;;   - the line is dedented with respect to (i.e. to the left
        ;;     of) the indentation of the preceding non-blank line.
 
        ;; The first non-blank line following an indenting comment
        ;; purposes.
 
        ;; Are we looking at a comment-only line which is *not* an
-       ;; indenting comment line?  If so, we assume that its been
+       ;; indenting comment line?  If so, we assume that it's been
        ;; placed at the desired indentation, so leave it alone.
        ;; Indenting comment lines are aligned as statements down
        ;; below.
 	    (forward-comment (- (point-max)))
 	  (let (done)
 	    (while (not done)
-	      (re-search-backward "^[ \t]*\\([^ \t\n#]\\|#[ \t\n]\\)"
-				  nil 'move)
-	      (setq done (or (eq py-honor-comment-indentation t)
-			     (bobp)
-			     (/= (following-char) ?#)
-			     (not (zerop (current-column)))))
+	      (re-search-backward "^[ \t]*\\([^ \t\n#]\\|#\\)" nil 'move)
+	      (setq done (or (bobp)
+			     (and (eq py-honor-comment-indentation t)
+				  (save-excursion
+				    (back-to-indentation)
+				    (not (looking-at py-block-comment-prefix))
+				    ))
+			     (and (not (eq py-honor-comment-indentation t))
+				  (save-excursion
+				    (back-to-indentation)
+				    (not (zerop (current-column)))))
+			     ))
 	      )))
 	;; if we landed inside a string, go to the beginning of that
 	;; string. this handles triple quoted, multi-line spanning
 	;; strings.
+	(let* ((delim (nth 3 (parse-partial-sexp bod (point))))
+	       (skip (and delim (make-string 1 delim))))
+	  (when skip
+	    (save-excursion
+	      (py-safe (search-backward skip))
+	      (if (and (eq (char-before) delim)
+		       (eq (char-before (1- (point))) delim))
+		  (setq skip (make-string 3 delim))))
+	    ;; we're looking at a triple-quoted string
+	    (py-safe (search-backward skip))))
+	;; now skip backward over continued lines
 	(py-goto-initial-line)
 	(+ (current-indentation)
 	   (if (py-statement-opens-block-p)
 
 (defun py-guess-indent-offset (&optional global)
   "Guess a good value for, and change, `py-indent-offset'.
-By default (without a prefix arg), makes a buffer-local copy of
-`py-indent-offset' with the new value.  This will not affect any other
-Python buffers.  With a prefix arg, changes the global value of
-`py-indent-offset'.  This affects all Python buffers (that don't have
-their own buffer-local copy), both those currently existing and those
-created later in the Emacs session.
+
+By default, make a buffer-local copy of `py-indent-offset' with the
+new value, so that other Python buffers are not affected.  With
+\\[universal-argument] (programmatically, optional argument GLOBAL),
+change the global value of `py-indent-offset'.  This affects all
+Python buffers (that don't have their own buffer-local copy), both
+those currently existing and those created later in the Emacs session.
 
 Some people use a different value for `py-indent-offset' than you use.
 There's no excuse for such foolishness, but sometimes you have to deal
   (interactive "P")			; raw prefix arg
   (let (new-value
 	(start (point))
-	restart
+	(restart (point))
 	(found nil)
 	colon-indent)
     (py-goto-initial-line)
     (while (not (or found (eobp)))
-      (if (re-search-forward ":[ \t]*\\($\\|[#\\]\\)" nil 'move)
-	  (progn
-	    (setq restart (point))
-	    (py-goto-initial-line)
-	    (if (py-statement-opens-block-p)
-		(setq found t)
-	      (goto-char restart)))))
-    (if found
-	()
+      (when (and (re-search-forward ":[ \t]*\\($\\|[#\\]\\)" nil 'move)
+		 (not (py-in-literal restart)))
+	(setq restart (point))
+	(py-goto-initial-line)
+	(if (py-statement-opens-block-p)
+	    (setq found t)
+	  (goto-char restart))))
+    (unless found
       (goto-char start)
       (py-goto-initial-line)
       (while (not (or found (bobp)))
-	(setq found
-	      (and
-	       (re-search-backward ":[ \t]*\\($\\|[#\\]\\)" nil 'move)
-	       (or (py-goto-initial-line) t) ; always true -- side effect
-	       (py-statement-opens-block-p)))))
+	(setq found (and
+		     (re-search-backward ":[ \t]*\\($\\|[#\\]\\)" nil 'move)
+		     (or (py-goto-initial-line) t) ; always true -- side effect
+		     (py-statement-opens-block-p)))))
     (setq colon-indent (current-indentation)
 	  found (and found (zerop (py-next-statement 1)))
 	  new-value (- (current-indentation) colon-indent))
     (goto-char start)
-    (if found
-	(progn
-	  (funcall (if global 'kill-local-variable 'make-local-variable)
-		   'py-indent-offset)
-	  (setq py-indent-offset new-value)
-	  (message "%s value of py-indent-offset set to %d"
-		   (if global "Global" "Local")
-		   py-indent-offset))
-      (error "Sorry, couldn't guess a value for py-indent-offset"))))
-
+    (if (not found)
+	(error "Sorry, couldn't guess a value for py-indent-offset")
+      (funcall (if global 'kill-local-variable 'make-local-variable)
+	       'py-indent-offset)
+      (setq py-indent-offset new-value)
+      (message "%s value of py-indent-offset set to %d"
+	       (if global "Global" "Local")
+	       py-indent-offset))
+    ))
+
+(defun py-comment-indent-function ()
+  "Python version of `comment-indent-function'."
+  ;; This is required when filladapt is turned off.  Without it, when
+  ;; filladapt is not used, comments which start in column zero
+  ;; cascade one character to the right
+  (save-excursion
+    (beginning-of-line)
+    (let ((eol (py-point 'eol)))
+      (and comment-start-skip
+	   (re-search-forward comment-start-skip eol t)
+	   (setq eol (match-beginning 0)))
+      (goto-char eol)
+      (skip-chars-backward " \t")
+      (max comment-column (+ (current-column) (if (bolp) 0 1)))
+      )))
+
+
 (defun py-shift-region (start end count)
+  "Indent lines from START to END by COUNT spaces."
   (save-excursion
-    (goto-char end)   (beginning-of-line) (setq end (point))
-    (goto-char start) (beginning-of-line) (setq start (point))
+    (goto-char end)
+    (beginning-of-line)
+    (setq end (point))
+    (goto-char start)
+    (beginning-of-line)
+    (setq start (point))
     (indent-rigidly start end count)))
 
 (defun py-shift-region-left (start end &optional count)
 shifted to the left, by `py-indent-offset' columns.
 
 If a prefix argument is given, the region is instead shifted by that
-many columns.  With no active region, outdent only the current line.
-You cannot outdent the region if any line is already at column zero."
+many columns.  With no active region, dedent only the current line.
+You cannot dedent the region if any line is already at column zero."
   (interactive
    (let ((p (point))
 	 (m (mark))
       (back-to-indentation)
       (if (and (zerop (current-column))
 	       (not (looking-at "\\s *$")))
-	  (error "Region is at left edge."))
+	  (error "Region is at left edge"))
       (forward-line 1)))
   (py-shift-region start end (- (prefix-numeric-value
 				 (or count py-indent-offset))))
 
 ;; Functions for moving point
 (defun py-previous-statement (count)
-  "Go to the start of previous Python statement.
-If the statement at point is the i'th Python statement, goes to the
-start of statement i-COUNT.  If there is no such statement, goes to the
-first statement.  Returns count of statements left to move.
-`Statements' do not include blank, comment, or continuation lines."
+  "Go to the start of the COUNTth preceding Python statement.
+By default, goes to the previous statement.  If there is no such
+statement, goes to the first statement.  Return count of statements
+left to move.  `Statements' do not include blank, comment, or
+continuation lines."
   (interactive "p")			; numeric prefix arg
   (if (< count 0) (py-next-statement (- count))
     (py-goto-initial-line)
       (goto-char start)
       (error "Enclosing block not found"))))
 
-(defun beginning-of-python-def-or-class (&optional class)
-  "Move point to start of def (or class, with prefix arg).
+(defun py-beginning-of-def-or-class (&optional class count)
+  "Move point to start of `def' or `class'.
 
 Searches back for the closest preceding `def'.  If you supply a prefix
-arg, looks for a `class' instead.  The docs assume the `def' case;
-just substitute `class' for `def' for the other case.
-
-If point is in a def statement already, and after the `d', simply
+arg, looks for a `class' instead.  The docs below assume the `def'
+case; just substitute `class' for `def' for the other case.
+Programmatically, if CLASS is `either', then moves to either `class'
+or `def'.
+
+When second optional argument is given programmatically, move to the
+COUNTth start of `def'.
+
+If point is in a `def' statement already, and after the `d', simply
 moves point to the start of the statement.
 
-Else (point is not in a def statement, or at or before the `d' of a
-def statement), searches for the closest preceding def statement, and
-leaves point at its start.  If no such statement can be found, leaves
-point at the start of the buffer.
-
-Returns t iff a def statement is found by these rules.
+Otherwise (i.e. when point is not in a `def' statement, or at or
+before the `d' of a `def' statement), searches for the closest
+preceding `def' statement, and leaves point at its start.  If no such
+statement can be found, leaves point at the start of the buffer.
+
+Returns t iff a `def' statement is found by these rules.
 
 Note that doing this command repeatedly will take you closer to the
 start of the buffer each time.
 
-If you want to mark the current def/class, see
-`\\[py-mark-def-or-class]'."
+To mark the current `def', see `\\[py-mark-def-or-class]'."
   (interactive "P")			; raw prefix arg
+  (if (not count)
+      (setq count 1))
   (let ((at-or-before-p (<= (current-column) (current-indentation)))
-	(start-of-line (progn (beginning-of-line) (point)))
-	(start-of-stmt (progn (py-goto-initial-line) (point))))
-    (if (or (/= start-of-stmt start-of-line)
-	    (not at-or-before-p))
-	(end-of-line))			; OK to match on this line
-    (re-search-backward (if class "^[ \t]*class\\>" "^[ \t]*def\\>")
-			nil 'move)))
-
-(defun end-of-python-def-or-class (&optional class)
-  "Move point beyond end of def (or class, with prefix arg) body.
-
-By default, looks for an appropriate `def'.  If you supply a prefix arg,
-looks for a `class' instead.  The docs assume the `def' case; just
-substitute `class' for `def' for the other case.
-
-If point is in a def statement already, this is the def we use.
-
-Else if the def found by `\\[beginning-of-python-def-or-class]'
-contains the statement you started on, that's the def we use.
-
-Else we search forward for the closest following def, and use that.
-
-If a def can be found by these rules, point is moved to the start of
-the line immediately following the def block, and the position of the
-start of the def is returned.
+	(start-of-line (goto-char (py-point 'bol)))
+	(start-of-stmt (goto-char (py-point 'bos)))
+	(start-re (cond ((eq class 'either) "^[ \t]*\\(class\\|def\\)\\>")
+			(class "^[ \t]*class\\>")
+			(t "^[ \t]*def\\>")))
+	)
+    ;; searching backward
+    (if (and (< 0 count)
+	     (or (/= start-of-stmt start-of-line)
+		 (not at-or-before-p)))
+	(end-of-line))
+    ;; search forward
+    (if (and (> 0 count)
+	     (zerop (current-column))
+	     (looking-at start-re))
+	(end-of-line))
+    (re-search-backward start-re nil 'move count)
+    (goto-char (match-beginning 0))))
+
+;; Backwards compatibility
+(defalias 'beginning-of-python-def-or-class 'py-beginning-of-def-or-class)
+
+(defun py-end-of-def-or-class (&optional class count)
+  "Move point beyond end of `def' or `class' body.
+
+By default, looks for an appropriate `def'.  If you supply a prefix
+arg, looks for a `class' instead.  The docs below assume the `def'
+case; just substitute `class' for `def' for the other case.
+Programmatically, if CLASS is `either', then moves to either `class'
+or `def'.
+
+When second optional argument is given programmatically, move to the
+COUNTth end of `def'.
+
+If point is in a `def' statement already, this is the `def' we use.
+
+Else, if the `def' found by `\\[py-beginning-of-def-or-class]'
+contains the statement you started on, that's the `def' we use.
+
+Otherwise, we search forward for the closest following `def', and use that.
+
+If a `def' can be found by these rules, point is moved to the start of
+the line immediately following the `def' block, and the position of the
+start of the `def' is returned.
 
 Else point is moved to the end of the buffer, and nil is returned.
 
 Note that doing this command repeatedly will take you closer to the
 end of the buffer each time.
 
-If you want to mark the current def/class, see
-`\\[py-mark-def-or-class]'."
+To mark the current `def', see `\\[py-mark-def-or-class]'."
   (interactive "P")			; raw prefix arg
+  (if (and count (/= count 1))
+      (py-beginning-of-def-or-class (- 1 count)))
   (let ((start (progn (py-goto-initial-line) (point)))
-	(which (if class "class" "def"))
+	(which (cond ((eq class 'either) "\\(class\\|def\\)")
+		     (class "class")
+		     (t "def")))
 	(state 'not-found))
     ;; move point to start of appropriate def/class
     (if (looking-at (concat "[ \t]*" which "\\>")) ; already on one
 	(setq state 'at-beginning)
-      ;; else see if beginning-of-python-def-or-class hits container
-      (if (and (beginning-of-python-def-or-class class)
+      ;; else see if py-beginning-of-def-or-class hits container
+      (if (and (py-beginning-of-def-or-class class)
 	       (progn (py-goto-beyond-block)
 		      (> (point) start)))
 	  (setq state 'at-end)
      ((eq state 'at-beginning) (py-goto-beyond-block) t)
      ((eq state 'at-end) t)
      ((eq state 'not-found) nil)
-     (t (error "internal error in end-of-python-def-or-class")))))
+     (t (error "Internal error in `py-end-of-def-or-class'")))))
+
+;; Backwards compabitility
+(defalias 'end-of-python-def-or-class 'py-end-of-def-or-class)
 
 
 ;; Functions for marking regions
 modes do this, but although it's handy it's never documented ...).
 
 In most Emacs language modes, this function bears at least a
-hallucinogenic resemblance to `\\[end-of-python-def-or-class]' and
-`\\[beginning-of-python-def-or-class]'.
+hallucinogenic resemblance to `\\[py-end-of-def-or-class]' and
+`\\[py-beginning-of-def-or-class]'.
 
 And in earlier versions of Python mode, all 3 were tightly connected.
 Turned out that was more confusing than useful: the `goto start' and
 pleasant."
   (interactive "P")			; raw prefix arg
   (let ((start (point))
-	(which (if class "class" "def")))
+	(which (cond ((eq class 'either) "\\(class\\|def\\)")
+		     (class "class")
+		     (t "def"))))
     (push-mark start)
     (if (not (py-go-up-tree-to-keyword which))
 	(progn (goto-char start)
-	       (error "Enclosing %s not found" which))
+	       (error "Enclosing %s not found"
+		      (if (eq class 'either)
+			  "def or class"
+			which)))
       ;; else enclosing def/class found
       (setq start (point))
       (py-goto-beyond-block)
 ;; ripped from cc-mode
 (defun py-forward-into-nomenclature (&optional arg)
   "Move forward to end of a nomenclature section or word.
-With arg, to it arg times.
+With \\[universal-argument] (programmatically, optional argument ARG), 
+do it that many times.
 
 A `nomenclature' is a fancy way of saying AWordWithMixedCaseNotUnderscores."
   (interactive "p")
 
 @EXECUTING PYTHON CODE
 
+\\[py-execute-import-or-reload]\timports or reloads the file in the Python interpreter
 \\[py-execute-buffer]\tsends the entire buffer to the Python interpreter
 \\[py-execute-region]\tsends the current region
+\\[py-execute-def-or-class]\tsends the current function or class definition
+\\[py-execute-string]\tsends an arbitrary string
 \\[py-shell]\tstarts a Python interpreter window; this will be used by
-\tsubsequent \\[py-execute-buffer] or \\[py-execute-region] commands
+\tsubsequent Python execution commands
+%c:py-execute-import-or-reload
 %c:py-execute-buffer
 %c:py-execute-region
+%c:py-execute-def-or-class
+%c:py-execute-string
 %c:py-shell
 
 @VARIABLES
 py-block-comment-prefix\tcomment string used by comment-region
 
 py-python-command\tshell command to invoke Python interpreter
-py-scroll-process-buffer\talways scroll Python process buffer
 py-temp-directory\tdirectory used for temp files (if needed)
 
 py-beep-if-tab-change\tring the bell if tab-width is changed
 %v:py-indent-offset
 %v:py-block-comment-prefix
 %v:py-python-command
-%v:py-scroll-process-buffer
 %v:py-temp-directory
 %v:py-beep-if-tab-change
 
 \\[py-previous-statement]\t move to statement preceding point
 \\[py-next-statement]\t move to statement following point
 \\[py-goto-block-up]\t move up to start of current block
-\\[beginning-of-python-def-or-class]\t move to start of def
-\\[universal-argument] \\[beginning-of-python-def-or-class]\t move to start of class
-\\[end-of-python-def-or-class]\t move to end of def
-\\[universal-argument] \\[end-of-python-def-or-class]\t move to end of class
+\\[py-beginning-of-def-or-class]\t move to start of def
+\\[universal-argument] \\[py-beginning-of-def-or-class]\t move to start of class
+\\[py-end-of-def-or-class]\t move to end of def
+\\[universal-argument] \\[py-end-of-def-or-class]\t move to end of class
 
 The first two move to one statement beyond the statement that contains
 point.  A numeric prefix argument tells them to move that many
 %c:py-previous-statement
 %c:py-next-statement
 %c:py-goto-block-up
-%c:beginning-of-python-def-or-class
-%c:end-of-python-def-or-class
+%c:py-beginning-of-def-or-class
+%c:py-end-of-def-or-class
 
 @LITTLE-KNOWN EMACS COMMANDS PARTICULARLY USEFUL IN PYTHON MODE
 
    "\\|"
    "^[^ #\t\n]"))
 
-;; returns the parse state at point (see parse-partial-sexp docs)
 (defun py-parse-state ()
+  "Return the parse state at point (see `parse-partial-sexp' docs)."
   (save-excursion
     (let ((here (point))
-	  pps done ci)
+	  pps done)
       (while (not done)
 	;; back up to the first preceding line (if any; else start of
 	;; buffer) that begins with a popular Python keyword, or a
 	;; at a non-zero nesting level.  It may be slow for people who
 	;; write huge code blocks or huge lists ... tough beans.
 	(re-search-backward py-parse-state-re nil 'move)
-	(setq ci (current-indentation))
 	(beginning-of-line)
-	(save-excursion
-	  (setq pps (parse-partial-sexp (point) here)))
-	;; make sure we don't land inside a triple-quoted string
-	(setq done (or (zerop ci)
-		       (not (nth 3 pps))
-		       (bobp)))
-	)
+	;; In XEmacs, we have a much better way to test for whether
+	;; we're in a triple-quoted string or not.  Emacs does not
+	;; have this built-in function, which is its loss because
+	;; without scanning from the beginning of the buffer, there's
+	;; no accurate way to determine this otherwise.
+	(if (not (fboundp 'buffer-syntactic-context))
+	    ;; Emacs
+	    (progn
+	      (save-excursion (setq pps (parse-partial-sexp (point) here)))
+	      ;; make sure we don't land inside a triple-quoted string
+	      (setq done (or (not (nth 3 pps))
+			     (bobp))))
+	  ;; XEmacs
+	  (setq done (or (not (buffer-syntactic-context))
+			 (bobp)))
+	  (when done
+	    (setq pps (parse-partial-sexp (point) here)))
+	  ))
       pps)))
 
-;; if point is at a non-zero nesting level, returns the number of the
-;; character that opens the smallest enclosing unclosed list; else
-;; returns nil.
 (defun py-nesting-level ()
-  (let ((status (py-parse-state)) )
+  "Return the buffer position of the last unclosed enclosing list.
+If nesting level is zero, return nil."
+  (let ((status (py-parse-state)))
     (if (zerop (car status))
 	nil				; not in a nest
       (car (cdr status)))))		; char# of open bracket
 
-;; t iff preceding line ends with backslash that's not in a comment
 (defun py-backslash-continuation-line-p ()
+  "Return t iff preceding line ends with backslash that is not in a comment."
   (save-excursion
     (beginning-of-line)
     (and
      (forward-line -1)			; always true -- side effect
      (looking-at py-continued-re))))
 
-;; t iff current line is a continuation line
 (defun py-continuation-line-p ()
+  "Return t iff current line is a continuation line."
   (save-excursion
     (beginning-of-line)
     (or (py-backslash-continuation-line-p)
 	(py-nesting-level))))
 
-;; go to initial line of current statement; usually this is the line
-;; we're on, but if we're on the 2nd or following lines of a
-;; continuation block, we need to go up to the first line of the
-;; block.
-;;
-;; Tricky: We want to avoid quadratic-time behavior for long continued
-;; blocks, whether of the backslash or open-bracket varieties, or a
-;; mix of the two.  The following manages to do that in the usual
-;; cases.
 (defun py-goto-initial-line ()
-  (let ( open-bracket-pos )
+  "Go to the initial line of the current statement.
+Usually this is the line we're on, but if we're on the 2nd or
+following lines of a continuation block, we need to go up to the first
+line of the block."
+  ;; Tricky: We want to avoid quadratic-time behavior for long
+  ;; continued blocks, whether of the backslash or open-bracket
+  ;; varieties, or a mix of the two.  The following manages to do that
+  ;; in the usual cases.
+  ;;
+  ;; Also, if we're sitting inside a triple quoted string, this will
+  ;; drop us at the line that begins the string.
+  (let (open-bracket-pos)
     (while (py-continuation-line-p)
       (beginning-of-line)
       (if (py-backslash-continuation-line-p)
 	  (goto-char open-bracket-pos)))))
   (beginning-of-line))
 
-;; go to point right beyond final line of current statement; usually
-;; this is the start of the next line, but if this is a multi-line
-;; statement we need to skip over the continuation lines.  Tricky:
-;; Again we need to be clever to avoid quadratic time behavior.
 (defun py-goto-beyond-final-line ()
+  "Go to the point just beyond the fine line of the current statement.
+Usually this is the start of the next line, but if this is a
+multi-line statement we need to skip over the continuation lines."
+  ;; Tricky: Again we need to be clever to avoid quadratic time
+  ;; behavior.
+  ;;
+  ;; XXX: Not quite the right solution, but deals with multi-line doc
+  ;; strings
+  (if (looking-at (concat "[ \t]*\\(" py-stringlit-re "\\)"))
+      (goto-char (match-end 0)))
+  ;;
   (forward-line 1)
   (let (state)
     (while (and (py-continuation-line-p)
 	    (parse-partial-sexp (point) (point-max) 0 nil state)
 	    (forward-line 1))))))
 
-;; t iff statement opens a block == iff it ends with a colon that's
-;; not in a comment.  point should be at the start of a statement
 (defun py-statement-opens-block-p ()
+  "Return t iff the current statement opens a block.
+I.e., iff it ends with a colon that is not in a comment.  Point should 
+be at the start of a statement."
   (save-excursion
     (let ((start (point))
 	  (finish (progn (py-goto-beyond-final-line) (1- (point))))
       answer)))
 
 (defun py-statement-closes-block-p ()
-  ;; true iff the current statement `closes' a block == the line
-  ;; starts with `return', `raise', `break', `continue', and `pass'.
-  ;; doesn't catch embedded statements
+  "Return t iff the current statement closes a block.
+I.e., if the line starts with `return', `raise', `break', `continue',
+and `pass'.  This doesn't catch embedded statements."
   (let ((here (point)))
     (back-to-indentation)
     (prog1
 	(looking-at (concat py-block-closing-keywords-re "\\>"))
       (goto-char here))))
 
-;; go to point right beyond final line of block begun by the current
-;; line.  This is the same as where py-goto-beyond-final-line goes
-;; unless we're on colon line, in which case we go to the end of the
-;; block.  assumes point is at bolp
 (defun py-goto-beyond-block ()
+  "Go to point just beyond the final line of block begun by the current line.
+This is the same as where `py-goto-beyond-final-line' goes unless
+we're on colon line, in which case we go to the end of the block.
+Assumes point is at the beginning of the line."
   (if (py-statement-opens-block-p)
       (py-mark-block nil 'just-move)
     (py-goto-beyond-final-line)))
 
-;; go to start of first statement (not blank or comment or
-;; continuation line) at or preceding point.  returns t if there is
-;; one, else nil
 (defun py-goto-statement-at-or-above ()
+  "Go to the start of the first statement at or preceding point.
+Return t if there is such a statement, otherwise nil.  `Statement'
+does not include blank lines, comments, or continuation lines."
   (py-goto-initial-line)
   (if (looking-at py-blank-or-comment-re)
       ;; skip back over blank & comment lines
 	nil)
     t))
 
-;; go to start of first statement (not blank or comment or
-;; continuation line) following the statement containing point returns
-;; t if there is one, else nil
 (defun py-goto-statement-below ()
+  "Go to start of the first statement following the statement containing point.
+Return t if there is such a statement, otherwise nil.  `Statement'
+does not include blank lines, comments, or continuation lines."
   (beginning-of-line)
   (let ((start (point)))
     (py-goto-beyond-final-line)
 	(progn (goto-char start) nil)
       t)))
 
-;; go to start of statement, at or preceding point, starting with
-;; keyword KEY.  Skips blank lines and non-indenting comments upward
-;; first.  If that statement starts with KEY, done, else go back to
-;; first enclosing block starting with KEY.  If successful, leaves
-;; point at the start of the KEY line & returns t.  Else leaves point
-;; at an undefined place & returns nil.
 (defun py-go-up-tree-to-keyword (key)
+  "Go to begining of statement starting with KEY, at or preceding point.
+
+KEY is a regular expression describing a Python keyword.  Skip blank
+lines and non-indenting comments.  If the statement found starts with
+KEY, then stop, otherwise go back to first enclosing block starting
+with KEY.  If successful, leave point at the start of the KEY line and 
+return t.  Otherwise, leav point at an undefined place and return nil."
   ;; skip blanks and non-indenting #
   (py-goto-initial-line)
   (while (and
     (beginning-of-line)
     found))
 
-;; return string in buffer from start of indentation to end of line;
-;; prefix "..." if leading whitespace was skipped
 (defun py-suck-up-leading-text ()
+  "Return string in buffer from start of indentation to end of line.
+Prefix with \"...\" if leading whitespace was skipped."
   (save-excursion
     (back-to-indentation)
     (concat
      (if (bolp) "" "...")
      (buffer-substring (point) (progn (end-of-line) (point))))))
 
-;; assuming point at bolp, return first keyword ([a-z]+) on the line,
-;; as a Lisp symbol; return nil if none
 (defun py-suck-up-first-keyword ()
+  "Return first keyword on the line as a Lisp symbol.
+`Keyword' is defined (essentially) as the regular expression
+([a-z]+).  Returns nil if none was found."
   (let ((case-fold-search nil))
     (if (looking-at "[ \t]*\\([a-z]+\\)\\b")
 	(intern (buffer-substring (match-beginning 1) (match-end 1)))
       nil)))
 
 (defun py-current-defun ()
-  ;; tell add-log.el how to find the current function/method/variable
+  "Python value for `add-log-current-defun-function'.
+This tells add-log.el how to find the current function/method/variable."
   (save-excursion
     (if (re-search-backward py-defun-start-re nil t)
 	(or (match-string 3)
 
 (defun py-submit-bug-report (enhancement-p)
   "Submit via mail a bug report on `python-mode'.
-With \\[universal-argument] just submit an enhancement request."
+With \\[universal-argument] (programmatically, argument ENHANCEMENT-P
+non-nil) just submit an enhancement request."
   (interactive
    (list (not (y-or-n-p
-	       "Is this a bug report? (hit `n' to send other comments) "))))
+	       "Is this a bug report (hit `n' to send other comments)? "))))
   (let ((reporter-prompt-for-summary-p (if enhancement-p
 					   "(Very) brief summary: "
 					 t)))
        '(py-python-command
 	 py-indent-offset
 	 py-block-comment-prefix
-	 py-scroll-process-buffer
 	 py-temp-directory
 	 py-beep-if-tab-change))
      nil				;pre-hooks
 
 
 (defun py-kill-emacs-hook ()
+  "Delete files in `py-file-queue'.
+These are Python temporary files awaiting execution."
   (mapcar #'(lambda (filename)
 	      (py-safe (delete-file filename)))
 	  py-file-queue))