diff lisp/modes/python-mode.el @ 4:b82b59fe008d r19-15b3

Import from CVS: tag r19-15b3
author cvs
date Mon, 13 Aug 2007 08:46:56 +0200
parents ac2d302a0011
children 8fc7fe29b841
line wrap: on
line diff
--- a/lisp/modes/python-mode.el	Mon Aug 13 08:46:35 2007 +0200
+++ b/lisp/modes/python-mode.el	Mon Aug 13 08:46:56 2007 +0200
@@ -6,8 +6,8 @@
 ;;         1992-1994 Tim Peters
 ;; Maintainer:    python-mode@python.org
 ;; Created:       Feb 1992
-;; Version:       2.67
-;; Last Modified: 1996/08/01 20:11:51
+;; Version:       2.83
+;; Last Modified: 1996/10/23 20:44:59
 ;; Keywords: python languages oop
 
 ;; This software is provided as-is, without express or implied
@@ -17,12 +17,11 @@
 ;; notice and this paragraph appear in all copies.
 
 ;;; Commentary:
-;;
 
 ;; This is a major mode for editing Python programs.  It was developed
 ;; by Tim Peters after an original idea by Michael A. Guravage.  Tim
-;; left the net for a while and in the interim, Barry Warsaw has
-;; undertaken maintenance of the mode.
+;; subsequently left the net; in 1995, Barry Warsaw inherited the
+;; mode and is the current maintainer.
 
 ;; At some point this mode will undergo a rewrite to bring it more in
 ;; line with GNU Emacs Lisp coding standards, and to wax all the Emacs
@@ -59,7 +58,8 @@
 ;; - proper interaction with pending-del and del-sel modes.
 ;; - Better support for outdenting: py-electric-colon (:) and
 ;;   py-indent-line (TAB) improvements; one level of outdentation
-;;   added after a return, raise, break, or continue statement
+;;   added after a return, raise, break, pass, or continue statement.
+;;   Defeated by prefixing command with C-u.
 ;; - New py-electric-colon (:) command for improved outdenting  Also
 ;;   py-indent-line (TAB) should handle outdented lines better
 ;; - improved (I think) C-c > and C-c <
@@ -84,6 +84,8 @@
 ;;   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-error or some such that would scan an exception in
+;;   the py-shell buffer, and pop you to that line in the file.
 
 ;; If you can think of more things you'd like to see, drop me a line.
 ;; If you want to report bugs, use py-submit-bug-report (C-c C-b).
@@ -207,7 +209,7 @@
 the Emacs bell is also rung as a warning.")
 
 (defconst python-font-lock-keywords
-  (let* ((keywords '("access"     "and"        "break"      "class"
+  (let* ((keywords '("and"        "break"      "class"
 		     "continue"   "def"        "del"        "elif"
 		     "else:"      "except"     "except:"    "exec"
 		     "finally:"   "for"        "from"       "global"
@@ -385,14 +387,37 @@
 			     "while\\s +.*:"
 			     "for\\s +.*:"
 			     "if\\s +.*:"
-			     "elif\\s +.*:")
+			     "elif\\s +.*:"
+			     "\\(return\\|break\\|raise\\|continue\\)[ \t\n]"
+			     )
 			   "\\|")
 	  "\\)")
   "Regexp matching lines to not outdent after.")
 
+(defvar py-defun-start-re
+  "^\\([ \t]*\\)def[ \t]+\\([a-zA-Z_0-9]+\\)\\|\\(^[a-zA-Z_0-9]+\\)[ \t]*="
+  "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.")
+
+(defvar py-class-start-re "^class[ \t]*\\([a-zA-Z_0-9]+\\)"
+  "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.")
+
+
 
 ;; Menu definitions, only relevent if you have the easymenu.el package
 ;; (standard in the latest Emacs 19 and XEmacs 19 distributions).
+(defvar py-menu nil
+  "Menu for Python Mode.
+
+This menu will get created automatically if you have the easymenu
+package.  Note that the latest XEmacs 19 and Emacs 19 versions contain
+this package.")
+
 (if (condition-case nil
 	(require 'easymenu)
       (error nil))
@@ -489,8 +514,8 @@
 ;; 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)
+(defvar imenu-example--python-generic-regexp nil)
+(defvar imenu-example--python-generic-parens nil)
 
 
 ;;;###autoload
@@ -650,11 +675,35 @@
 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"
   (interactive)
+  ;; set up local variables
   (kill-all-local-variables)
+  (make-local-variable 'font-lock-defaults)
+  (make-local-variable 'paragraph-separate)
+  (make-local-variable 'paragraph-start)
+  (make-local-variable 'require-final-newline)
+  (make-local-variable 'comment-start)
+  (make-local-variable 'comment-start-skip)
+  (make-local-variable 'comment-column)
+  (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)
+  (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-start-skip     "# *"
+	comment-column         40
+	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
+	)
   (use-local-map py-mode-map)
   ;; add the menu
   (if py-menu
@@ -662,18 +711,6 @@
   ;; Emacs 19 requires this
   (if (or py-this-is-lucid-emacs-p py-this-is-emacs-19-p)
       (setq comment-multi-line nil))
-  ;; BAW -- style...
-  (mapcar (function (lambda (x)
-		      (make-local-variable (car x))
-		      (set (car x) (cdr x))))
-	  '((paragraph-separate . "^[ \t]*$")
-	    (paragraph-start	 . "^[ \t]*$")
-	    (require-final-newline . t)
-	    (comment-start .		"# ")
-	    (comment-start-skip .	"# *")
-	    (comment-column . 40)
-	    (indent-region-function . py-indent-region)
-	    (indent-line-function . py-indent-line)))
   ;; hack to allow overriding the tabsize in the file (see tokenizer.c)
   ;;
   ;; not sure where the magic comment has to be; to save time
@@ -752,12 +789,12 @@
       (save-excursion
 	(let ((here (point))
 	      (outdent 0)
-	      (indent (py-compute-indentation)))
+	      (indent (py-compute-indentation t)))
 	  (if (and (not arg)
 		   (py-outdent-p)
 		   (= indent (save-excursion
-			       (forward-line -1)
-			       (py-compute-indentation)))
+			       (py-next-statement -1)
+			       (py-compute-indentation t)))
 		   )
 	      (setq outdent py-indent-offset))
 	  ;; Don't indent, only outdent.  This assumes that any lines that
@@ -774,6 +811,7 @@
 
 
 ;;; Functions that execute Python commands in a subprocess
+;;;###autoload
 (defun py-shell ()
   "Start an interactive Python interpreter in another window.
 This is like Shell mode, except that Python is running in the window
@@ -895,42 +933,47 @@
     ;; read_process_output has update_mode_lines++ for a similar
     ;; reason?  beats me ...
 
-    ;; BAW - we want to check to see if this still applies
-    (if (eq curbuf pbuf)		; mysterious ugly hack
-	(set-buffer (get-buffer-create "*scratch*")))
+    (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-delete-file-silently (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 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-delete-file-silently (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-execute-buffer ()
   "Send the contents of the buffer to a Python interpreter.
@@ -995,12 +1038,17 @@
 (put 'py-delete-char 'delete-selection 'supersede)
 (put 'py-delete-char 'pending-delete   'supersede)
 
-(defun py-indent-line ()
-  "Fix the indentation of the current line according to Python rules."
-  (interactive)
+(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)
+
+This function is normally bound to `indent-line-function' so
+\\[indent-for-tab-command] will call it."
+  (interactive "P")
   (let* ((ci (current-indentation))
 	 (move-to-indentation-p (<= (current-column) ci))
-	 (need (py-compute-indentation)))
+	 (need (py-compute-indentation (not arg))))
     ;; see if we need to outdent
     (if (py-outdent-p)
 	(setq need (- need py-indent-offset)))
@@ -1026,7 +1074,10 @@
       (insert-char ?\n 1)
       (move-to-column ci))))
 
-(defun py-compute-indentation ()
+(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.
   (save-excursion
     (let ((pps (parse-partial-sexp (save-excursion
 				     (beginning-of-python-def-or-class)
@@ -1172,7 +1223,7 @@
 	(+ (current-indentation)
 	   (if (py-statement-opens-block-p)
 	       py-indent-offset
-	     (if (py-statement-closes-block-p)
+	     (if (and honor-block-close-p (py-statement-closes-block-p))
 		 (- py-indent-offset)
 	       0)))
 	)))))
@@ -1332,7 +1383,7 @@
 	  (target-column 0)		; column to which to indent
 	  (base-shifted-by 0)		; amount last base line was shifted
 	  (indent-base (if (looking-at "[ \t\n]")
-			   (py-compute-indentation)
+			   (py-compute-indentation t)
 			 0))
 	  ci)
       (while (< (point) end)
@@ -1728,10 +1779,12 @@
   (interactive "p")
   (let ((case-fold-search nil))
     (if (> arg 0)
-	(re-search-forward "\\W*\\([A-Z_]*[a-z0-9]*\\)" (point-max) t arg)
+	(re-search-forward
+	 "\\(\\W\\|[_]\\)*\\([A-Z]*[a-z0-9]*\\)"
+	 (point-max) t arg)
       (while (and (< arg 0)
 		  (re-search-backward
-		   "\\(\\(\\W\\|[a-z0-9]\\)[A-Z]+\\|\\W\\w+\\)"
+		   "\\(\\W\\|[a-z0-9]\\)[A-Z]+\\|\\(\\W\\|[_]\\)\\w+"
 		   (point-min) 0))
 	(forward-char 1)
 	(setq arg (1+ arg)))))
@@ -1776,8 +1829,7 @@
 				 (where-is-internal func py-mode-map)
 				 ", "))))
 	 ((equal funckind "v")		; variable
-	  (setq funcdoc (substitute-command-keys
-			 (get func 'variable-documentation))
+	  (setq funcdoc (documentation-property func 'variable-documentation)
 		keys (if (assq func locals)
 			 (concat
 			  "Local/Global values: "
@@ -2180,12 +2232,12 @@
 
 (defun py-statement-closes-block-p ()
   ;; true iff the current statement `closes' a block == the line
-  ;; starts with `return', `raise', `break' or `continue'.  doesn't
-  ;; catch embedded statements
+  ;; starts with `return', `raise', `break', `continue', and `pass'.
+  ;; doesn't catch embedded statements
   (let ((here (point)))
     (back-to-indentation)
     (prog1
-	(looking-at "\\(return\\|raise\\|break\\|continue\\)\\>")
+	(looking-at "\\(return\\|raise\\|break\\|continue\\|pass\\)\\>")
       (goto-char here))))
 
 ;; go to point right beyond final line of block begun by the current
@@ -2309,9 +2361,20 @@
     (set-buffer cbuf))
   (sit-for 0))
 
+(defun py-current-defun ()
+  ;; tell 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)
+	    (let ((method (match-string 2)))
+	      (if (and (not (zerop (length (match-string 1))))
+		       (re-search-backward py-class-start-re nil t))
+		  (concat (match-string 1) "." method)
+		method)))
+      nil)))
 
 
-(defconst py-version "2.67"
+(defconst py-version "2.83"
   "`python-mode' version number.")
 (defconst py-help-address "python-mode@python.org"
   "Address accepting submission of bug reports.")