]> code.delx.au - gnu-emacs/blobdiff - lisp/progmodes/python.el
python.el removed.
[gnu-emacs] / lisp / progmodes / python.el
index 40f4e8aab5715f47924d959e5b403acc80da41dd..e57c7e639c9fa50de3fc844e5873c302552bf5d5 100644 (file)
@@ -1,6 +1,6 @@
 ;;; python.el --- silly walks for Python
 
-;; Copyright (C) 2003, 2004, 2005, 2006  Free Software Foundation, Inc.
+;; Copyright (C) 2003, 2004, 2005, 2006, 2007  Free Software Foundation, Inc.
 
 ;; Author: Dave Love <fx@gnu.org>
 ;; Maintainer: FSF
 ;;; Code:
 
 (eval-when-compile
+  (require 'cl)
   (require 'compile)
-  (require 'comint))
+  (require 'comint)
+  (require 'hippie-exp))
 
 (autoload 'comint-mode "comint")
 
@@ -94,7 +96,9 @@
             "import" "in" "is" "lambda" "not" "or" "pass" "print"
             "raise" "return" "try" "while" "yield"
             ;; Future keywords
-            "as" "None")
+            "as" "None"
+             ;; Not real keywords, but close enough to be fontified as such
+             "self" "True" "False")
         symbol-end)
     ;; Definitions
     (,(rx symbol-start (group "class") (1+ space) (group (1+ (or word ?_))))
@@ -159,7 +163,7 @@ Used for syntactic keywords.  N is the match number (1, 2 or 3)."
               (= (match-beginning 1) (match-end 1))) ; prefix is null
          (and (= n 1)                  ; prefix
               (/= (match-beginning 1) (match-end 1)))) ; non-empty
-      (unless (eq 'string (syntax-ppss-context (syntax-ppss)))
+      (unless (nth 3 (syntax-ppss))
         (eval-when-compile (string-to-syntax "|"))))
      ;; Otherwise (we're in a non-matching string) the property is
      ;; nil, which is OK.
@@ -400,18 +404,19 @@ The criteria are that the line isn't a comment or in string and
 ;;;; Indentation.
 
 (defcustom python-indent 4
-  "*Number of columns for a unit of indentation in Python mode.
+  "Number of columns for a unit of indentation in Python mode.
 See also `\\[python-guess-indent]'"
   :group 'python
   :type 'integer)
+(put 'python-indent 'safe-local-variable 'integerp)
 
 (defcustom python-guess-indent t
-  "*Non-nil means Python mode guesses `python-indent' for the buffer."
+  "Non-nil means Python mode guesses `python-indent' for the buffer."
   :type 'boolean
   :group 'python)
 
 (defcustom python-indent-string-contents t
-  "*Non-nil means indent contents of multi-line strings together.
+  "Non-nil means indent contents of multi-line strings together.
 This means indent them the same as the preceding non-blank line.
 Otherwise preserve their indentation.
 
@@ -430,7 +435,7 @@ are always indented in lines with preceding comments."
   :group 'python)
 
 (defcustom python-continuation-offset 4
-  "*Number of columns of additional indentation for continuation lines.
+  "Number of columns of additional indentation for continuation lines.
 Continuation lines follow a backslash-terminated line starting a
 statement."
   :group 'python
@@ -547,40 +552,39 @@ Set `python-indent' locally to the value guessed."
        ((looking-at (rx (0+ space) (syntax comment-start)
                        (not (any " \t\n")))) ; non-indentable comment
        (current-indentation))
-       (t (let ((point (point)))
-           (if python-honour-comment-indentation
-               ;; Back over whitespace, newlines, non-indentable comments.
-               (catch 'done
-                 (while t
-                   (if (cond ((bobp))
-                             ;; not at comment start
-                             ((not (forward-comment -1))
-                              (python-beginning-of-statement)
-                              t)
-                             ;; trailing comment
-                             ((/= (current-column) (current-indentation))
-                              (python-beginning-of-statement)
-                              t)
-                             ;; indentable comment like python-mode.el
-                             ((and (looking-at (rx (syntax comment-start)
-                                                   (or space line-end)))
-                                   (/= 0 (current-column)))))
-                       (throw 'done t)))))
-           (python-indentation-levels)
-           ;; Prefer to indent comments with an immediately-following
-           ;; statement, e.g.
-           ;;       ...
-           ;;   # ...
-           ;;   def ...
-           (when (and (> python-indent-list-length 1)
-                      (python-comment-line-p))
-             (forward-line)
-             (unless (python-comment-line-p)
-               (let ((elt (assq (current-indentation) python-indent-list)))
-                 (setq python-indent-list
-                       (nconc (delete elt python-indent-list)
-                              (list elt))))))
-           (caar (last python-indent-list))))))))
+       (t (if python-honour-comment-indentation
+              ;; Back over whitespace, newlines, non-indentable comments.
+              (catch 'done
+                (while t
+                  (if (cond ((bobp))
+                            ;; not at comment start
+                            ((not (forward-comment -1))
+                             (python-beginning-of-statement)
+                             t)
+                            ;; trailing comment
+                            ((/= (current-column) (current-indentation))
+                             (python-beginning-of-statement)
+                             t)
+                            ;; indentable comment like python-mode.el
+                            ((and (looking-at (rx (syntax comment-start)
+                                                  (or space line-end)))
+                                  (/= 0 (current-column)))))
+                      (throw 'done t)))))
+          (python-indentation-levels)
+          ;; Prefer to indent comments with an immediately-following
+          ;; statement, e.g.
+          ;;       ...
+          ;;   # ...
+          ;;   def ...
+          (when (and (> python-indent-list-length 1)
+                     (python-comment-line-p))
+            (forward-line)
+            (unless (python-comment-line-p)
+              (let ((elt (assq (current-indentation) python-indent-list)))
+                (setq python-indent-list
+                      (nconc (delete elt python-indent-list)
+                             (list elt))))))
+          (caar (last python-indent-list)))))))
 
 ;;;; Cycling through the possible indentations with successive TABs.
 
@@ -755,13 +759,13 @@ reached start of buffer."
   (let ((ci (current-indentation))
        (def-re (rx line-start (0+ space) (or "def" "class") (1+ space)
                    (group (1+ (or word (syntax symbol))))))
-       found lep def-line)
+       found lep) ;; def-line
     (if (python-comment-line-p)
        (setq ci most-positive-fixnum))
     (while (and (not (bobp)) (not found))
       ;; Treat bol at beginning of function as outside function so
       ;; that successive C-M-a makes progress backwards.
-      (setq def-line (looking-at def-re))
+      ;;(setq def-line (looking-at def-re))
       (unless (bolp) (end-of-line))
       (setq lep (line-end-position))
       (if (and (re-search-backward def-re nil 'move)
@@ -773,7 +777,7 @@ reached start of buffer."
                     ;; Not sure why it was like this -- fails in case of
                     ;; last internal function followed by first
                     ;; non-def statement of the main body.
-;;                  (and def-line (= in ci))
+                     ;;(and def-line (= in ci))
                     (= in ci)
                     (< in ci)))
               (not (python-in-string/comment)))
@@ -977,11 +981,15 @@ don't move and return nil.  Otherwise return t."
                       (_ (if (python-comment-line-p)
                              (python-skip-comments/blanks t)))
                       (ci (current-indentation))
-                      (open (python-open-block-statement-p)))
+                      (open (python-open-block-statement-p))
+                      opoint)
                  (if (and (zerop ci) (not open))
                      (not (goto-char point))
                    (catch 'done
-                     (while (zerop (python-next-statement))
+                     (setq opoint (point))
+                     (while (and (zerop (python-next-statement))
+                                 (not (= opoint (point))))
+                       (setq opoint (point))
                        (when (or (and open (<= (current-indentation) ci))
                                  (< (current-indentation) ci))
                          (python-skip-comments/blanks t)
@@ -1094,7 +1102,7 @@ Repeat ARG times."
 ;;;; pychecker
 
 (defcustom python-check-command "pychecker --stdlib"
-  "*Command used to check a Python file."
+  "Command used to check a Python file."
   :type 'string
   :group 'python)
 
@@ -1126,7 +1134,7 @@ See `python-check-command' for the default."
 ;; Fixme: Make sure we can work with IPython.
 
 (defcustom python-python-command "python"
-  "*Shell command to run Python interpreter.
+  "Shell command to run Python interpreter.
 Any arguments can't contain whitespace.
 Note that IPython may not work properly; it must at least be used
 with the `-cl' flag, i.e. use `ipython -cl'."
@@ -1134,7 +1142,7 @@ with the `-cl' flag, i.e. use `ipython -cl'."
   :type 'string)
 
 (defcustom python-jython-command "jython"
-  "*Shell command to run Jython interpreter.
+  "Shell command to run Jython interpreter.
 Any arguments can't contain whitespace."
   :group 'python
   :type 'string)
@@ -1146,7 +1154,7 @@ modified by the user.  Additional arguments are added when the command
 is used by `run-python' et al.")
 
 (defvar python-buffer nil
-  "*The current python process buffer.
+  "*The current Python process buffer.
 
 Commands that send text from source buffers to Python processes have
 to choose a process to send to.  This is determined by buffer-local
@@ -1191,6 +1199,15 @@ local value.")
     ;; (define-key map "\C-c\C-f" 'python-describe-symbol)
     map))
 
+(defvar inferior-python-mode-syntax-table
+  (let ((st (make-syntax-table python-mode-syntax-table)))
+    ;; Don't get confused by apostrophes in the process's output (e.g. if
+    ;; you execute "help(os)").
+    (modify-syntax-entry ?\' "." st)
+    ;; Maybe we should do the same for double quotes?
+    ;; (modify-syntax-entry ?\" "." st)
+    st))
+
 ;; Fixme: This should inherit some stuff from `python-mode', but I'm
 ;; not sure how much: at least some keybindings, like C-c C-f;
 ;; syntax?; font-locking, e.g. for triple-quoted strings?
@@ -1213,7 +1230,6 @@ For running multiple processes in multiple buffers, see `run-python' and
 
 \\{inferior-python-mode-map}"
   :group 'python
-  (set-syntax-table python-mode-syntax-table)
   (setq mode-line-process '(":%s"))
   (set (make-local-variable 'comint-input-filter) 'python-input-filter)
   (add-hook 'comint-preoutput-filter-functions #'python-preoutput-filter
@@ -1227,7 +1243,7 @@ For running multiple processes in multiple buffers, see `run-python' and
   (compilation-shell-minor-mode 1))
 
 (defcustom inferior-python-filter-regexp "\\`\\s-*\\S-?\\S-?\\s-*\\'"
-  "*Input matching this regexp is not saved on the history list.
+  "Input matching this regexp is not saved on the history list.
 Default ignores all inputs of 0, 1, or 2 non-blank characters."
   :type 'regexp
   :group 'python)
@@ -1250,47 +1266,57 @@ Don't save anything for STR matching `inferior-python-filter-regexp'."
 (defvar python-preoutput-result nil
   "Data from last `_emacs_out' line seen by the preoutput filter.")
 
-(defvar python-preoutput-continuation nil
-  "If non-nil, funcall this when `python-preoutput-filter' sees `_emacs_ok'.")
-
 (defvar python-preoutput-leftover nil)
+(defvar python-preoutput-skip-next-prompt nil)
 
 ;; Using this stops us getting lines in the buffer like
 ;; >>> ... ... >>>
-;; Also look for (and delete) an `_emacs_ok' string and call
-;; `python-preoutput-continuation' if we get it.
 (defun python-preoutput-filter (s)
   "`comint-preoutput-filter-functions' function: ignore prompts not at bol."
   (when python-preoutput-leftover
     (setq s (concat python-preoutput-leftover s))
     (setq python-preoutput-leftover nil))
-  (cond ((and (string-match (rx string-start (repeat 3 (any ".>"))
-                               " " string-end)
-                            s)
-              (/= (let ((inhibit-field-text-motion t))
-                    (line-beginning-position))
-                  (point)))
-        ;; The need for this seems to be system-dependent:
-         ;; What is this all about, exactly?  --Stef
-        ;; (if (and (eq ?. (aref s 0)))
-        ;;     (accept-process-output (get-buffer-process (current-buffer)) 1))
-         "")
-        ((string= s "_emacs_ok\n")
-         (when python-preoutput-continuation
-           (funcall python-preoutput-continuation)
-           (setq python-preoutput-continuation nil))
-         "")
-        ((string-match "_emacs_out \\(.*\\)\n" s)
-         (setq python-preoutput-result (match-string 1 s))
-         "")
-       ((string-match ".*\n" s)
-        s)
-       ((or (eq t (compare-strings s nil nil "_emacs_ok\n" nil (length s)))
-            (let ((end (min (length "_emacs_out ") (length s))))
-              (eq t (compare-strings s nil end "_emacs_out " nil end))))
-        (setq python-preoutput-leftover s)
-        "")
-        (t s)))
+  (let ((start 0)
+        (res ""))
+    ;; First process whole lines.
+    (while (string-match "\n" s start)
+      (let ((line (substring s start (setq start (match-end 0)))))
+        ;; Skip prompt if needed.
+        (when (and python-preoutput-skip-next-prompt
+                   (string-match comint-prompt-regexp line))
+          (setq python-preoutput-skip-next-prompt nil)
+          (setq line (substring line (match-end 0))))
+        ;; Recognize special _emacs_out lines.
+        (if (and (string-match "\\`_emacs_out \\(.*\\)\n\\'" line)
+                 (local-variable-p 'python-preoutput-result))
+            (progn
+              (setq python-preoutput-result (match-string 1 line))
+              (set (make-local-variable 'python-preoutput-skip-next-prompt) t))
+          (setq res (concat res line)))))
+    ;; Then process the remaining partial line.
+    (unless (zerop start) (setq s (substring s start)))
+    (cond ((and (string-match comint-prompt-regexp s)
+                ;; Drop this prompt if it follows an _emacs_out...
+                (or python-preoutput-skip-next-prompt
+                    ;; ... or if it's not gonna be inserted at BOL.
+                    ;; Maybe we could be more selective here.
+                    (if (zerop (length res))
+                        (not (bolp))
+                      (string-match ".\\'" res))))
+           ;; The need for this seems to be system-dependent:
+           ;; What is this all about, exactly?  --Stef
+           ;; (if (and (eq ?. (aref s 0)))
+           ;;     (accept-process-output (get-buffer-process (current-buffer)) 1))
+           (setq python-preoutput-skip-next-prompt nil)
+           res)
+          ((let ((end (min (length "_emacs_out ") (length s))))
+             (eq t (compare-strings s nil end "_emacs_out " nil end)))
+           ;; The leftover string is a prefix of _emacs_out so we don't know
+           ;; yet whether it's an _emacs_out or something else: wait until we
+           ;; get more output so we can resolve this ambiguity.
+           (set (make-local-variable 'python-preoutput-leftover) s)
+           res)
+          (t (concat res s)))))
 
 (autoload 'comint-check-proc "comint")
 
@@ -1320,31 +1346,30 @@ buffer for a list of commands.)"
   ;; (not a name) in Python buffers from which `run-python' &c is
   ;; invoked.  Would support multiple processes better.
   (when (or new (not (comint-check-proc python-buffer)))
-    (save-current-buffer
-      (let* ((cmdlist (append (python-args-to-list cmd) '("-i")))
-            (path (getenv "PYTHONPATH"))
-            (process-environment       ; to import emacs.py
-             (cons (concat "PYTHONPATH=" data-directory
-                           (if path (concat ":" path)))
-                   process-environment)))
-       (set-buffer (apply 'make-comint-in-buffer "Python"
-                          (generate-new-buffer "*Python*")
-                          (car cmdlist) nil (cdr cmdlist)))
-       (setq-default python-buffer (current-buffer))
-       (setq python-buffer (current-buffer)))
+    (with-current-buffer
+        (let* ((cmdlist (append (python-args-to-list cmd) '("-i")))
+               (path (getenv "PYTHONPATH"))
+               (process-environment    ; to import emacs.py
+                (cons (concat "PYTHONPATH=" data-directory
+                              (if path (concat ":" path)))
+                      process-environment)))
+          (apply 'make-comint-in-buffer "Python"
+                 (if new (generate-new-buffer "*Python*") "*Python*")
+                 (car cmdlist) nil (cdr cmdlist)))
+      (setq-default python-buffer (current-buffer))
+      (setq python-buffer (current-buffer))
       (accept-process-output (get-buffer-process python-buffer) 5)
-      (inferior-python-mode)))
-  (if (eq 'python-mode major-mode)
+      (inferior-python-mode)
+      ;; Load function definitions we need.
+      ;; Before the preoutput function was used, this was done via -c in
+      ;; cmdlist, but that loses the banner and doesn't run the startup
+      ;; file.  The code might be inline here, but there's enough that it
+      ;; seems worth putting in a separate file, and it's probably cleaner
+      ;; to put it in a module.
+      ;; Ensure we're at a prompt before doing anything else.
+      (python-send-receive "import emacs; print '_emacs_out ()'")))
+  (if (derived-mode-p 'python-mode)
       (setq python-buffer (default-value 'python-buffer))) ; buffer-local
-  ;; Load function definitions we need.
-  ;; Before the preoutput function was used, this was done via -c in
-  ;; cmdlist, but that loses the banner and doesn't run the startup
-  ;; file.  The code might be inline here, but there's enough that it
-  ;; seems worth putting in a separate file, and it's probably cleaner
-  ;; to put it in a module.
-  (python-send-string "import emacs")
-  ;; Ensure we're at a prompt before doing anything else.
-  (python-send-receive "print '_emacs_out ()'")
   ;; Without this, help output goes into the inferior python buffer if
   ;; the process isn't already running.
   (sit-for 1 t)        ;Should we use accept-process-output instead?  --Stef
@@ -1358,16 +1383,22 @@ buffer for a list of commands.)"
 ;; commands having set up such a state.
 
 (defun python-send-command (command)
-  "Like `python-send-string' but resets `compilation-shell-minor-mode'."
-  (let ((end (marker-position (process-mark (python-proc)))))
-    (with-current-buffer python-buffer (goto-char (point-max)))
+  "Like `python-send-string' but resets `compilation-shell-minor-mode'.
+COMMAND should be a single statement."
+  ;; (assert (not (string-match "\n" command)))
+  ;; (let ((end (marker-position (process-mark (python-proc)))))
+  (with-current-buffer (process-buffer (python-proc))
+    (goto-char (point-max))
     (compilation-forget-errors)
     (python-send-string command)
+    (setq compilation-last-buffer (current-buffer)))
+    ;; No idea what this is for but it breaks the call to
+    ;; compilation-fake-loc in python-send-region.  -- Stef
     ;; Must wait until this has completed before re-setting variables below.
-    (python-send-receive "print '_emacs_out ()'")
-    (with-current-buffer python-buffer
-      (set-marker compilation-parsing-end end)
-      (setq compilation-last-buffer (current-buffer)))))
+    ;; (python-send-receive "print '_emacs_out ()'")
+    ;; (with-current-buffer python-buffer
+    ;;   (set-marker compilation-parsing-end end))
+    ) ;;)
 
 (defun python-send-region (start end)
   "Send the region to the inferior Python process."
@@ -1409,7 +1440,13 @@ buffer for a list of commands.)"
   "Evaluate STRING in inferior Python process."
   (interactive "sPython command: ")
   (comint-send-string (python-proc) string)
-  (comint-send-string (python-proc) "\n\n"))
+  (unless (string-match "\n\\'" string)
+    ;; Make sure the text is properly LF-terminated.
+    (comint-send-string (python-proc) "\n"))
+  (when (string-match "\n[ \t].*\n?\\'" string)
+    ;; If the string contains a final indented line, add a second newline so
+    ;; as to make sure we terminate the multiline instruction.
+    (comint-send-string (python-proc) "\n")))
 
 (defun python-send-buffer ()
   "Send the current buffer to the inferior Python process."
@@ -1441,7 +1478,7 @@ Then switch to the process buffer."
   (python-switch-to-python t))
 
 (defcustom python-source-modes '(python-mode jython-mode)
-  "*Used to determine if a buffer contains Python source code.
+  "Used to determine if a buffer contains Python source code.
 If a file is loaded into a buffer that is in one of these major modes,
 it is considered Python source by `python-load-file', which uses the
 value to determine defaults."
@@ -1484,9 +1521,9 @@ See variable `python-buffer'.  Starts a new process if necessary."
   ;; isn't one for `python-buffer'.
   (unless (comint-check-proc python-buffer)
     (run-python nil t))
-  (get-buffer-process (or (if (eq major-mode 'inferior-python-mode)
-                                 (current-buffer)
-                               python-buffer))))
+  (get-buffer-process (if (derived-mode-p 'inferior-python-mode)
+                          (current-buffer)
+                        python-buffer)))
 
 (defun python-set-proc ()
   "Set the default value of `python-buffer' to correspond to this buffer.
@@ -1561,14 +1598,16 @@ will."
 
 (defun python-send-receive (string)
   "Send STRING to inferior Python (if any) and return result.
-The result is what follows `_emacs_out' in the output (or nil)."
+The result is what follows `_emacs_out' in the output."
+  (python-send-string string)
   (let ((proc (python-proc)))
-    (python-send-string string)
-    (setq python-preoutput-result nil)
-    (while (progn
-            (accept-process-output proc 5)
-            python-preoutput-leftover))
-    python-preoutput-result))
+    (with-current-buffer (process-buffer proc)
+      (set (make-local-variable 'python-preoutput-result) nil)
+      (while (progn
+               (accept-process-output proc 5)
+               (null python-preoutput-result)))
+      (prog1 python-preoutput-result
+        (kill-local-variable 'python-preoutput-result)))))
 
 ;; Fixme:  Is there anything reasonable we can do with random methods?
 ;; (Currently only works with functions.)
@@ -1578,24 +1617,26 @@ Only works when point is in a function name, not its arg list, for
 instance.  Assumes an inferior Python is running."
   (let ((symbol (with-syntax-table python-dotty-syntax-table
                  (current-word))))
-    ;; First try the symbol we're on.
-    (or (and symbol
-            (python-send-receive (format "emacs.eargs(%S, %s)"
-                                         symbol python-imports)))
-       ;; Try moving to symbol before enclosing parens.
-       (let ((s (syntax-ppss)))
-         (unless (zerop (car s))
-           (when (eq ?\( (char-after (nth 1 s)))
-             (save-excursion
-               (goto-char (nth 1 s))
-               (skip-syntax-backward "-")
-               (let ((point (point)))
-                 (skip-chars-backward "a-zA-Z._")
-                 (if (< (point) point)
-                     (python-send-receive
-                      (format "emacs.eargs(%S, %s)"
-                              (buffer-substring-no-properties (point) point)
-                              python-imports)))))))))))
+    ;; This is run from timers, so inhibit-quit tends to be set.
+    (with-local-quit
+      ;; First try the symbol we're on.
+      (or (and symbol
+               (python-send-receive (format "emacs.eargs(%S, %s)"
+                                            symbol python-imports)))
+          ;; Try moving to symbol before enclosing parens.
+          (let ((s (syntax-ppss)))
+            (unless (zerop (car s))
+              (when (eq ?\( (char-after (nth 1 s)))
+                (save-excursion
+                  (goto-char (nth 1 s))
+                  (skip-syntax-backward "-")
+                  (let ((point (point)))
+                    (skip-chars-backward "a-zA-Z._")
+                    (if (< (point) point)
+                        (python-send-receive
+                         (format "emacs.eargs(%S, %s)"
+                                 (buffer-substring-no-properties (point) point)
+                                 python-imports))))))))))))
 \f
 ;;;; Info-look functionality.
 
@@ -1706,12 +1747,11 @@ Otherwise, do nothing."
               (orig (point))
               (start (nth 8 syntax))
               end)
-         (cond ((eq t (nth 3 syntax))      ; in fenced string
-                (goto-char (nth 8 syntax)) ; string start
-                (condition-case ()         ; for unbalanced quotes
-                    (progn (forward-sexp)
-                           (setq end (point)))
-                  (error (setq end (point-max)))))
+         (cond ((eq t (nth 3 syntax))        ; in fenced string
+                (goto-char (nth 8 syntax))   ; string start
+                (setq end (condition-case () ; for unbalanced quotes
+                               (progn (forward-sexp) (point))
+                             (error (point-max)))))
                ((re-search-backward "\\s|\\s-*\\=" nil t) ; end of fenced
                                                           ; string
                 (forward-char)
@@ -1719,13 +1759,17 @@ Otherwise, do nothing."
                 (condition-case ()
                     (progn (backward-sexp)
                            (setq start (point)))
-                  (error nil))))
+                  (error (setq end nil)))))
          (when end
            (save-restriction
              (narrow-to-region start end)
              (goto-char orig)
-             (fill-paragraph justify))))))
-      t)
+              (let ((paragraph-separate
+                     ;; Make sure that fenced-string delimiters that stand
+                     ;; on their own line stay there.
+                     (concat "[ \t]*['\"]+[ \t]*$\\|" paragraph-separate)))
+                (fill-paragraph justify))))))
+      t))
 
 (defun python-shift-left (start end &optional count)
   "Shift lines in region COUNT (the prefix arg) columns to the left.
@@ -1912,7 +1956,7 @@ Repeating the command scrolls the completion window."
 
 (defun python-try-complete (old)
   "Completion function for Python for use with `hippie-expand'."
-  (when (eq major-mode 'python-mode)   ; though we only add it locally
+  (when (derived-mode-p 'python-mode)  ; though we only add it locally
     (unless old
       (let ((symbol (python-partial-symbol)))
        (he-init-string (- (point) (length symbol)) (point))
@@ -1941,6 +1985,13 @@ Repeating the command scrolls the completion window."
 \f
 ;;;; Skeletons
 
+(defcustom python-use-skeletons nil
+  "Non-nil means template skeletons will be automagically inserted.
+This happens when pressing \"if<SPACE>\", for example, to prompt for
+the if condition."
+  :type 'boolean
+  :group 'python)
+
 (defvar python-skeletons nil
   "Alist of named skeletons for Python mode.
 Elements are of the form (NAME . EXPANDER-FUNCTION).")
@@ -1958,7 +2009,8 @@ The default contents correspond to the elements of `python-skeletons'.")
         (function (intern (concat "python-insert-" name))))
     `(progn
        (add-to-list 'python-skeletons ',(cons name function))
-       (define-abbrev python-mode-abbrev-table ,name "" ',function nil t)
+       (if python-use-skeletons
+          (define-abbrev python-mode-abbrev-table ,name "" ',function nil t))
        (define-skeleton ,function
         ,(format "Insert Python \"%s\" template." name)
         ,@elements)))))
@@ -2040,7 +2092,7 @@ The default contents correspond to the elements of `python-skeletons'.")
   > _ \n)
 
 (defvar python-default-template "if"
-  "Default template to expand by `python-insert-template'.
+  "Default template to expand by `python-expand-template'.
 Updated on each expansion.")
 
 (defun python-expand-template (name)
@@ -2078,36 +2130,35 @@ without confirmation."
       (unless (fboundp 'brm-rename)
        (pymacs-load "bikeemacs" "brm-") ; first line of normal recipe
        (let ((py-mode-map (make-sparse-keymap)) ; it assumes this
-             (features (cons 'python-mode features)) ; and requires this
-             menu)
-         (brm-init)                    ; second line of normal recipe
-         (remove-hook 'python-mode-hook ; undo this from `brm-init'
-                      '(lambda () (easy-menu-add brm-menu)))
-         (easy-menu-define
-           python-brm-menu python-mode-map
-           "Bicycle Repair Man"
-           '("BicycleRepairMan"
-             :help "Interface to navigation and refactoring tool"
-             "Queries"
-             ["Find References" brm-find-references
-              :help "Find references to name at point in compilation buffer"]
-             ["Find Definition" brm-find-definition
-              :help "Find definition of name at point"]
-             "-"
-             "Refactoring"
-             ["Rename" brm-rename
-              :help "Replace name at point with a new name everywhere"]
-             ["Extract Method" brm-extract-method
-              :active (and mark-active (not buffer-read-only))
-              :help "Replace statements in region with a method"]
-             ["Extract Local Variable" brm-extract-local-variable
-              :active (and mark-active (not buffer-read-only))
-              :help "Replace expression in region with an assignment"]
-             ["Inline Local Variable" brm-inline-local-variable
-              :help
-              "Substitute uses of variable at point with its definition"]
-             ;; Fixme:  Should check for anything to revert.
-             ["Undo Last Refactoring" brm-undo :help ""]))))
+             (features (cons 'python-mode features))) ; and requires this
+         (brm-init))                   ; second line of normal recipe
+        (remove-hook 'python-mode-hook ; undo this from `brm-init'
+                     '(lambda () (easy-menu-add brm-menu)))
+        (easy-menu-define
+          python-brm-menu python-mode-map
+          "Bicycle Repair Man"
+          '("BicycleRepairMan"
+            :help "Interface to navigation and refactoring tool"
+            "Queries"
+            ["Find References" brm-find-references
+             :help "Find references to name at point in compilation buffer"]
+            ["Find Definition" brm-find-definition
+             :help "Find definition of name at point"]
+            "-"
+            "Refactoring"
+            ["Rename" brm-rename
+             :help "Replace name at point with a new name everywhere"]
+            ["Extract Method" brm-extract-method
+             :active (and mark-active (not buffer-read-only))
+             :help "Replace statements in region with a method"]
+            ["Extract Local Variable" brm-extract-local-variable
+             :active (and mark-active (not buffer-read-only))
+             :help "Replace expression in region with an assignment"]
+            ["Inline Local Variable" brm-inline-local-variable
+             :help
+             "Substitute uses of variable at point with its definition"]
+            ;; Fixme:  Should check for anything to revert.
+            ["Undo Last Refactoring" brm-undo :help ""])))
     (error (error "Bicyclerepairman setup failed: %s" data))))
 \f
 ;;;; Modes.
@@ -2131,6 +2182,8 @@ without confirmation."
   (add-hook 'post-command-hook 'python-abbrev-pc-hook nil t))
 (modify-syntax-entry ?/ "w" python-abbrev-syntax-table)
 
+(defvar python-mode-running)            ;Dynamically scoped var.
+
 ;;;###autoload
 (define-derived-mode python-mode fundamental-mode "Python"
   "Major mode for editing Python files.
@@ -2176,6 +2229,7 @@ with skeleton expansions for compound statement templates.
                                   ;;  . python-font-lock-syntactic-face-function)
                                   ))
   (set (make-local-variable 'parse-sexp-lookup-properties) t)
+  (set (make-local-variable 'parse-sexp-ignore-comments) t)
   (set (make-local-variable 'comment-start) "# ")
   (set (make-local-variable 'indent-line-function) #'python-indent-line)
   (set (make-local-variable 'indent-region-function) #'python-indent-region)
@@ -2218,7 +2272,12 @@ with skeleton expansions for compound statement templates.
   (if (featurep 'hippie-exp)
       (set (make-local-variable 'hippie-expand-try-functions-list)
           (cons 'python-try-complete hippie-expand-try-functions-list)))
+  ;; Python defines TABs as being 8-char wide.
+  (set (make-local-variable 'tab-width) 8)
   (when python-guess-indent (python-guess-indent))
+  ;; Let's make it harder for the user to shoot himself in the foot.
+  (unless (= tab-width python-indent)
+    (setq indent-tabs-mode nil))
   (set (make-local-variable 'python-command) python-python-command)
   (python-find-imports)
   (unless (boundp 'python-mode-running)        ; kill the recursion from jython-mode
@@ -2227,9 +2286,9 @@ with skeleton expansions for compound statement templates.
 
 (custom-add-option 'python-mode-hook 'imenu-add-menubar-index)
 (custom-add-option 'python-mode-hook
-                  '(lambda ()
-                     "Turn off Indent Tabs mode."
-                     (set (make-local-variable 'indent-tabs-mode) nil)))
+                  (lambda ()
+                     "Turn off Indent Tabs mode."
+                     (set (make-local-variable 'indent-tabs-mode) nil)))
 (custom-add-option 'python-mode-hook 'turn-on-eldoc-mode)
 (custom-add-option 'python-mode-hook 'abbrev-mode)
 (custom-add-option 'python-mode-hook 'python-setup-brm)