merge emacs-23
[bpt/emacs.git] / lisp / progmodes / python.el
index e9f3daf..6fdaa12 100644 (file)
@@ -1,6 +1,7 @@
 ;;; python.el --- silly walks for Python  -*- coding: iso-8859-1 -*-
 
-;; Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008  Free Software Foundation, Inc.
+;; Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
+;;   Free Software Foundation, Inc.
 
 ;; Author: Dave Love <fx@gnu.org>
 ;; Maintainer: FSF
 
 ;; This file is part of GNU Emacs.
 
-;; GNU Emacs is free software; you can redistribute it and/or modify
+;; GNU Emacs is free software: you can redistribute it and/or modify
 ;; it under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 3, or (at your option)
-;; any later version.
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
 
 ;; GNU Emacs is distributed in the hope that it will be useful,
 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
 ;; GNU General Public License for more details.
 
 ;; You should have received a copy of the GNU General Public License
-;; along with GNU Emacs; see the file COPYING.  If not, write to the
-;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-;; Boston, MA 02110-1301, USA.
+;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
 
 ;;; Commentary:
 
 ;; Major mode for editing Python, with support for inferior processes.
 
-;; There is another Python mode, python-mode.el, used by XEmacs and
-;; maintained with Python.  That isn't covered by an FSF copyright
-;; assignment, unlike this code, and seems not to be well-maintained
-;; for Emacs (though I've submitted fixes).  This mode is rather
-;; simpler and is better in other ways.  In particular, using the
-;; syntax functions with text properties maintained by font-lock makes
-;; it more correct with arbitrary string and comment contents.
+;; There is another Python mode, python-mode.el:
+;; http://launchpad.net/python-mode
+;; used by XEmacs, and originally maintained with Python.
+;; That isn't covered by an FSF copyright assignment (?), unlike this
+;; code, and seems not to be well-maintained for Emacs (though I've
+;; submitted fixes).  This mode is rather simpler and is better in
+;; other ways.  In particular, using the syntax functions with text
+;; properties maintained by font-lock makes it more correct with
+;; arbitrary string and comment contents.
 
 ;; This doesn't implement all the facilities of python-mode.el.  Some
 ;; just need doing, e.g. catching exceptions in the inferior Python
@@ -44,7 +45,7 @@
 ;; `forward-into-nomenclature' should be done separately, since it's
 ;; not specific to Python, and I've installed a minor mode to do the
 ;; job properly in Emacs 23.  [CC mode 5.31 contains an incompatible
-;; feature, `c-subword-mode' which is intended to have a similar
+;; feature, `subword-mode' which is intended to have a similar
 ;; effect, but actually only affects word-oriented keybindings.]
 
 ;; Other things seem more natural or canonical here, e.g. the
@@ -72,7 +73,6 @@
   (require 'compile)
   (require 'hippie-exp))
 
-(require 'sym-comp)
 (autoload 'comint-mode "comint")
 
 (defgroup python nil
   :link '(emacs-commentary-link "python"))
 \f
 ;;;###autoload
-(add-to-list 'interpreter-mode-alist '("jython" . jython-mode))
+(add-to-list 'interpreter-mode-alist (cons (purecopy "jython") 'jython-mode))
 ;;;###autoload
-(add-to-list 'interpreter-mode-alist '("python" . python-mode))
+(add-to-list 'interpreter-mode-alist (cons (purecopy "python") 'python-mode))
 ;;;###autoload
-(add-to-list 'auto-mode-alist '("\\.py\\'" . python-mode))
-(add-to-list 'same-window-buffer-names "*Python*")
+(add-to-list 'auto-mode-alist (cons (purecopy "\\.py\\'")  'python-mode))
+(add-to-list 'same-window-buffer-names (purecopy "*Python*"))
 \f
 ;;;; Font lock
 
 (defvar python-font-lock-keywords
   `(,(rx symbol-start
-        ;; From v 2.5 reference, § keywords.
+        ;; From v 2.7 reference, § keywords.
         ;; def and class dealt with separately below
         (or "and" "as" "assert" "break" "continue" "del" "elif" "else"
             "except" "exec" "finally" "for" "from" "global" "if"
              ;; Not real keywords, but close enough to be fontified as such
              "self" "True" "False")
         symbol-end)
-    (,(rx symbol-start "None" symbol-end)      ; see § Keywords in 2.5 manual
+    (,(rx symbol-start "None" symbol-end)      ; see § Keywords in 2.7 manual
      . font-lock-constant-face)
     ;; Definitions
     (,(rx symbol-start (group "class") (1+ space) (group (1+ (or word ?_))))
     ;; Top-level assignments are worth highlighting.
     (,(rx line-start (group (1+ (or word ?_))) (0+ space) "=")
      (1 font-lock-variable-name-face))
-    (,(rx line-start (* (any " \t")) (group "@" (1+ (or word ?_)))) ; decorators
+    ;; Decorators.
+    (,(rx line-start (* (any " \t")) (group "@" (1+ (or word ?_))
+                                           (0+ "." (1+ (or word ?_)))))
      (1 font-lock-type-face))
     ;; Built-ins.  (The next three blocks are from
-    ;; `__builtin__.__dict__.keys()' in Python 2.5.1.)  These patterns
+    ;; `__builtin__.__dict__.keys()' in Python 2.7)  These patterns
     ;; are debateable, but they at least help to spot possible
     ;; shadowing of builtins.
     (,(rx symbol-start (or
          "SystemExit" "TabError" "TypeError" "UnboundLocalError"
          "UnicodeDecodeError" "UnicodeEncodeError" "UnicodeError"
          "UnicodeTranslateError" "UnicodeWarning" "UserWarning"
-         "ValueError" "Warning" "ZeroDivisionError") symbol-end)
+         "ValueError" "Warning" "ZeroDivisionError"
+         ;; Python 2.7
+         "BufferError" "BytesWarning" "WindowsError") symbol-end)
      . font-lock-type-face)
     (,(rx (or line-start (not (any ". \t"))) (* (any " \t")) symbol-start
          (group (or
          "range" "raw_input" "reduce" "reload" "repr" "reversed"
          "round" "set" "setattr" "slice" "sorted" "staticmethod"
          "str" "sum" "super" "tuple" "type" "unichr" "unicode" "vars"
-         "xrange" "zip")) symbol-end)
+         "xrange" "zip"
+         ;; Python 2.7.
+         "bin" "bytearray" "bytes" "format" "memoryview" "next" "print"
+         )) symbol-end)
      (1 font-lock-builtin-face))
     (,(rx symbol-start (or
          ;; other built-ins
          "True" "False" "None" "Ellipsis"
-         "_" "__debug__" "__doc__" "__import__" "__name__") symbol-end)
+         "_" "__debug__" "__doc__" "__import__" "__name__" "__package__")
+          symbol-end)
      . font-lock-builtin-face)))
 
 (defconst python-font-lock-syntactic-keywords
   ;; Make outer chars of matching triple-quote sequences into generic
   ;; string delimiters.  Fixme: Is there a better way?
   ;; First avoid a sequence preceded by an odd number of backslashes.
-  `((,(rx (not (any ?\\))
-         ?\\ (* (and ?\\ ?\\))
-         (group (syntax string-quote))
-         (backref 1)
-         (group (backref 1)))
-     (2 ,(string-to-syntax "\"")))     ; dummy
-    (,(rx (group (optional (any "uUrR"))) ; prefix gets syntax property
-         (optional (any "rR"))           ; possible second prefix
-         (group (syntax string-quote))   ; maybe gets property
-         (backref 2)                     ; per first quote
-         (group (backref 2)))            ; maybe gets property
-     (1 (python-quote-syntax 1))
+  `((,(concat "\\(?:\\([RUru]\\)[Rr]?\\|^\\|[^\\]\\(?:\\\\.\\)*\\)" ;Prefix.
+              "\\(?:\\('\\)'\\('\\)\\|\\(?2:\"\\)\"\\(?3:\"\\)\\)")
+     (1 (python-quote-syntax 1) nil lax)
      (2 (python-quote-syntax 2))
      (3 (python-quote-syntax 3)))
     ;; This doesn't really help.
@@ -211,9 +210,9 @@ Used for syntactic keywords.  N is the match number (1, 2 or 3)."
              (eval-when-compile (string-to-syntax "|"))))))
      ;; Consider property for initial char, accounting for prefixes.
      ((or (and (= n 2)                 ; leading quote (not prefix)
-              (= (match-beginning 1) (match-end 1))) ; prefix is null
+              (not (match-end 1)))     ; prefix is null
          (and (= n 1)                  ; prefix
-              (/= (match-beginning 1) (match-end 1)))) ; non-empty
+              (match-end 1)))          ; non-empty
       (let ((font-lock-syntactic-keywords nil))
        (unless (eq 'string (syntax-ppss-context (syntax-ppss)))
          (eval-when-compile (string-to-syntax "|")))))
@@ -267,7 +266,7 @@ Used for syntactic keywords.  N is the match number (1, 2 or 3)."
     (define-key map "\C-c\C-z" 'python-switch-to-python)
     (define-key map "\C-c\C-m" 'python-load-file)
     (define-key map "\C-c\C-l" 'python-load-file) ; a la cmuscheme
-    (substitute-key-definition 'complete-symbol 'symbol-complete
+    (substitute-key-definition 'complete-symbol 'completion-at-point
                               map global-map)
     (define-key map "\C-c\C-i" 'python-find-imports)
     (define-key map "\C-c\C-t" 'python-expand-template)
@@ -296,9 +295,7 @@ Used for syntactic keywords.  N is the match number (1, 2 or 3)."
        ("Templates..."
         :help "Expand templates for compound statements"
         :filter (lambda (&rest junk)
-                  (mapcar (lambda (elt)
-                            (vector (car elt) (cdr elt) t))
-                          python-skeletons))) ; defined later
+                   (abbrev-table-menu python-mode-abbrev-table)))
        "-"
        ["Start interpreter" python-shell
         :help "Run `inferior' Python in separate buffer"]
@@ -320,7 +317,7 @@ Used for syntactic keywords.  N is the match number (1, 2 or 3)."
        "-"
        ["Help on symbol" python-describe-symbol
         :help "Use pydoc on symbol at point"]
-       ["Complete symbol" symbol-complete
+       ["Complete symbol" completion-at-point
         :help "Complete (qualified) symbol before point"]
        ["Find function" python-find-function
         :help "Try to find source definition of function at point"]
@@ -411,7 +408,7 @@ comments and strings, or that point is within brackets/parens."
                    (error nil))))))))
 
 (defun python-comment-line-p ()
-  "Return non-nil iff current line has only a comment."
+  "Return non-nil if and only if current line has only a comment."
   (save-excursion
     (end-of-line)
     (when (eq 'comment (syntax-ppss-context (syntax-ppss)))
@@ -419,7 +416,7 @@ comments and strings, or that point is within brackets/parens."
       (looking-at (rx (or (syntax comment-start) line-end))))))
 
 (defun python-blank-line-p ()
-  "Return non-nil iff current line is blank."
+  "Return non-nil if and only if current line is blank."
   (save-excursion
     (beginning-of-line)
     (looking-at "\\s-*$")))
@@ -573,10 +570,37 @@ having to restart the program."
   "Queue of Python temp files awaiting execution.
 Currently-active file is at the head of the list.")
 
+(defcustom python-shell-prompt-alist
+  '(("ipython" . "^In \\[[0-9]+\\]: *")
+    (t . "^>>> "))
+  "Alist of Python input prompts.
+Each element has the form (PROGRAM . REGEXP), where PROGRAM is
+the value of `python-python-command' for the python process and
+REGEXP is a regular expression matching the Python prompt.
+PROGRAM can also be t, which specifies the default when no other
+element matches `python-python-command'."
+  :type 'string
+  :group 'python
+  :version "24.1")
+
+(defcustom python-shell-continuation-prompt-alist
+  '(("ipython" . "^   [.][.][.]+: *")
+    (t . "^[.][.][.] "))
+  "Alist of Python continued-line prompts.
+Each element has the form (PROGRAM . REGEXP), where PROGRAM is
+the value of `python-python-command' for the python process and
+REGEXP is a regular expression matching the Python prompt for
+continued lines.
+PROGRAM can also be t, which specifies the default when no other
+element matches `python-python-command'."
+  :type 'string
+  :group 'python
+  :version "24.1")
+
 (defvar python-pdbtrack-is-tracking-p nil)
 
 (defconst python-pdbtrack-stack-entry-regexp
-  "^> \\(.*\\)(\\([0-9]+\\))\\([?a-zA-Z0-9_]+\\)()"
+  "^> \\(.*\\)(\\([0-9]+\\))\\([?a-zA-Z0-9_<>]+\\)()"
   "Regular expression pdbtrack uses to find a stack trace entry.")
 
 (defconst python-pdbtrack-input-prompt "\n[(<]*[Pp]db[>)]+ "
@@ -749,7 +773,7 @@ Set `python-indent' locally to the value guessed."
   '(("else" "if" "elif" "while" "for" "try" "except")
     ("elif" "if" "elif")
     ("except" "try" "except")
-    ("finally" "try"))
+    ("finally" "else" "try" "except"))
   "Alist of keyword matches.
 The car of an element is a keyword introducing a statement which
 can close a block opened by a keyword in the cdr.")
@@ -979,9 +1003,11 @@ Accounts for continuation lines, multi-line strings, and
 multi-line bracketed expressions."
   (beginning-of-line)
   (python-beginning-of-string)
-  (let ((point (point)))
+  (let (point)
     (while (and (python-continuation-line-p)
-               (> point (setq point (point))))
+               (if point
+                   (< (point) point)
+                 t))
       (beginning-of-line)
       (if (python-backslash-continuation-line-p)
          (progn
@@ -989,14 +1015,15 @@ multi-line bracketed expressions."
            (while (python-backslash-continuation-line-p)
              (forward-line -1)))
        (python-beginning-of-string)
-       (python-skip-out))))
+       (python-skip-out))
+      (setq point (point))))
   (back-to-indentation))
 
 (defun python-skip-out (&optional forward syntax)
   "Skip out of any nested brackets.
 Skip forward if FORWARD is non-nil, else backward.
 If SYNTAX is non-nil it is the state returned by `syntax-ppss' at point.
-Return non-nil iff skipping was done."
+Return non-nil if and only if skipping was done."
   (let ((depth (syntax-ppss-depth (or syntax (syntax-ppss))))
        (forward (if forward -1 1)))
     (unless (zerop depth)
@@ -1302,13 +1329,9 @@ See `python-check-command' for the default."
 \f
 ;;;; Inferior mode stuff (following cmuscheme).
 
-;; Fixme: Make sure we can work with IPython.
-
 (defcustom python-python-command "python"
   "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'."
+Any arguments can't contain whitespace."
   :group 'python
   :type 'string)
 
@@ -1386,6 +1409,23 @@ local value.")
 ;; Autoloaded.
 (declare-function compilation-shell-minor-mode "compile" (&optional arg))
 
+(defvar python--prompt-regexp nil)
+
+(defun python--set-prompt-regexp ()
+  (let ((prompt  (cdr-safe (or (assoc python-python-command
+                                     python-shell-prompt-alist)
+                              (assq t python-shell-prompt-alist))))
+       (cprompt (cdr-safe (or (assoc python-python-command
+                                     python-shell-continuation-prompt-alist)
+                              (assq t python-shell-continuation-prompt-alist)))))
+    (set (make-local-variable 'comint-prompt-regexp)
+        (concat "\\("
+                (mapconcat 'identity
+                           (delq nil (list prompt cprompt "^([Pp]db) "))
+                           "\\|")
+                "\\)"))
+    (set (make-local-variable 'python--prompt-regexp) prompt)))
+
 ;; 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?
@@ -1408,14 +1448,12 @@ For running multiple processes in multiple buffers, see `run-python' and
 
 \\{inferior-python-mode-map}"
   :group 'python
+  (require 'ansi-color) ; for ipython
   (setq mode-line-process '(":%s"))
   (set (make-local-variable 'comint-input-filter) 'python-input-filter)
   (add-hook 'comint-preoutput-filter-functions #'python-preoutput-filter
            nil t)
-  ;; Still required by `comint-redirect-send-command', for instance
-  ;; (and we need to match things like `>>> ... >>> '):
-  (set (make-local-variable 'comint-prompt-regexp)
-       (rx line-start (1+ (and (or (repeat 3 (any ">.")) "(Pdb)") " "))))
+  (python--set-prompt-regexp)
   (set (make-local-variable 'compilation-error-regexp-alist)
        python-compilation-regexp-alist)
   (compilation-shell-minor-mode 1))
@@ -1426,6 +1464,16 @@ Default ignores all inputs of 0, 1, or 2 non-blank characters."
   :type 'regexp
   :group 'python)
 
+(defcustom python-remove-cwd-from-path t
+  "Whether to allow loading of Python modules from the current directory.
+If this is non-nil, Emacs removes '' from sys.path when starting
+an inferior Python process.  This is the default, for security
+reasons, as it is easy for the Python process to be started
+without the user's realization (e.g. to perform completion)."
+  :type 'boolean
+  :group 'python
+  :version "23.3")
+
 (defun python-input-filter (str)
   "`comint-input-filter' function for inferior Python.
 Don't save anything for STR matching `inferior-python-filter-regexp'."
@@ -1512,34 +1560,39 @@ Don't save anything for STR matching `inferior-python-filter-regexp'."
                                     cmd)))
     (unless (shell-command-to-string cmd)
       (error "Can't run Python command `%s'" cmd))
-    (let* ((res (shell-command-to-string (concat cmd " --version"))))
-      (string-match "Python \\([0-9]\\)\\.\\([0-9]\\)" res)
-      (unless (and (equal "2" (match-string 1 res))
-                  (match-beginning 2)
-                  (>= (string-to-number (match-string 2 res)) 2))
-       (error "Only Python versions >= 2.2 and < 3.0 supported")))
+    (let* ((res (shell-command-to-string
+                 (concat cmd
+                         " -c \"from sys import version_info;\
+print version_info >= (2, 2) and version_info < (3, 0)\""))))
+      (unless (string-match "True" res)
+       (error "Only Python versions >= 2.2 and < 3.0 are supported")))
     (setq python-version-checked t)))
 
 ;;;###autoload
 (defun run-python (&optional cmd noshow new)
   "Run an inferior Python process, input and output via buffer *Python*.
-CMD is the Python command to run.  NOSHOW non-nil means don't show the
-buffer automatically.
-
-Normally, if there is a process already running in `python-buffer',
-switch to that buffer.  Interactively, a prefix arg allows you to edit
-the initial command line (default is `python-command'); `-i' etc. args
-will be added to this as appropriate.  A new process is started if:
-one isn't running attached to `python-buffer', or interactively the
-default `python-command', or argument NEW is non-nil.  See also the
-documentation for `python-buffer'.
-
-Runs the hook `inferior-python-mode-hook' \(after the
-`comint-mode-hook' is run).  \(Type \\[describe-mode] in the process
-buffer for a list of commands.)"
+CMD is the Python command to run.  NOSHOW non-nil means don't
+show the buffer automatically.
+
+Interactively, a prefix arg means to prompt for the initial
+Python command line (default is `python-command').
+
+A new process is started if one isn't running attached to
+`python-buffer', or if called from Lisp with non-nil arg NEW.
+Otherwise, if a process is already running in `python-buffer',
+switch to that buffer.
+
+This command runs the hook `inferior-python-mode-hook' after
+running `comint-mode-hook'.  Type \\[describe-mode] in the
+process buffer for a list of commands.
+
+By default, Emacs inhibits the loading of Python modules from the
+current working directory, for security reasons.  To disable this
+behavior, change `python-remove-cwd-from-path' to nil."
   (interactive (if current-prefix-arg
                   (list (read-string "Run Python: " python-command) nil t)
                 (list python-command)))
+  (require 'ansi-color) ; for ipython
   (unless cmd (setq cmd python-command))
   (python-check-version cmd)
   (setq python-command cmd)
@@ -1548,15 +1601,20 @@ buffer for a list of commands.)"
   ;; invoked.  Would support multiple processes better.
   (when (or new (not (comint-check-proc python-buffer)))
     (with-current-buffer
-       (let* ((cmdlist (append (python-args-to-list cmd) '("-i")))
+       (let* ((cmdlist
+               (append (python-args-to-list cmd) '("-i")
+                       (if python-remove-cwd-from-path
+                           '("-c" "import sys; sys.path.remove('')"))))
               (path (getenv "PYTHONPATH"))
               (process-environment     ; to import emacs.py
                (cons (concat "PYTHONPATH="
                              (if path (concat path path-separator))
                              data-directory)
                      process-environment))
-              ;; Suppress use of pager for help output:
-              (process-connection-type nil))
+               ;; If we use a pipe, unicode characters are not printed
+               ;; correctly (Bug#5794) and IPython does not work at
+               ;; all (Bug#5390).
+              (process-connection-type t))
          (apply 'make-comint-in-buffer "Python"
                 (generate-new-buffer "*Python*")
                 (car cmdlist) nil (cdr cmdlist)))
@@ -1612,7 +1670,12 @@ buffer for a list of commands.)"
   ;; non-ASCII.
   (interactive "r")
   (let* ((f (make-temp-file "py"))
-        (command (format "emacs.eexecfile(%S)" f))
+        (command
+          ;; IPython puts the FakeModule module into __main__ so
+          ;; emacs.eexecfile becomes useless.
+          (if (string-match "^ipython" python-command)
+              (format "execfile %S" f)
+            (format "emacs.eexecfile(%S)" f)))
         (orig-start (copy-marker start)))
     (when (save-excursion
            (goto-char start)
@@ -1781,9 +1844,10 @@ will."
     (with-output-to-temp-buffer (help-buffer)
       (with-current-buffer standard-output
        ;; Fixme: Is this actually useful?
-       (help-setup-xref (list 'python-describe-symbol symbol) (interactive-p))
+       (help-setup-xref (list 'python-describe-symbol symbol)
+                        (called-interactively-p 'interactive))
        (set (make-local-variable 'comint-redirect-subvert-readonly) t)
-       (print-help-return-message))))
+       (help-print-return-message))))
   (comint-redirect-send-command-to-process (format "emacs.ehelp(%S, %s)"
                                                   symbol python-imports)
    "*Help*" (python-proc) nil nil))
@@ -1806,13 +1870,14 @@ This is a no-op if `python-check-comint-prompt' returns nil."
          (kill-local-variable 'python-preoutput-result))))))
 
 (defun python-check-comint-prompt (&optional proc)
-  "Return non-nil iff there's a normal prompt in the inferior buffer.
-If there isn't, it's probably not appropriate to send input to return
-Eldoc information etc.  If PROC is non-nil, check the buffer for that
-process."
+  "Return non-nil if and only if there's a normal prompt in the inferior buffer.
+If there isn't, it's probably not appropriate to send input to return Eldoc
+information etc.  If PROC is non-nil, check the buffer for that process."
   (with-current-buffer (process-buffer (or proc (python-proc)))
     (save-excursion
-      (save-match-data (re-search-backward ">>> \\=" nil t)))))
+      (save-match-data
+       (re-search-backward (concat python--prompt-regexp " *\\=")
+                           nil t)))))
 
 ;; Fixme:  Is there anything reasonable we can do with random methods?
 ;; (Currently only works with functions.)
@@ -2005,9 +2070,10 @@ COUNT defaults to `python-indent'.  If region isn't active, just shift
 current line.  The region shifted includes the lines in which START and
 END lie.  It is an error if any lines in the region are indented less than
 COUNT columns."
-  (interactive (if mark-active
-                  (list (region-beginning) (region-end) current-prefix-arg)
-                (list (point) (point) current-prefix-arg)))
+  (interactive
+   (if mark-active
+       (list (region-beginning) (region-end) current-prefix-arg)
+     (list (line-beginning-position) (line-end-position) current-prefix-arg)))
   (if count
       (setq count (prefix-numeric-value count))
     (setq count python-indent))
@@ -2028,9 +2094,10 @@ COUNT columns."
 COUNT defaults to `python-indent'.  If region isn't active, just shift
 current line.  The region shifted includes the lines in which START and
 END lie."
-  (interactive (if mark-active
-                  (list (region-beginning) (region-end) current-prefix-arg)
-                (list (point) (point) current-prefix-arg)))
+  (interactive
+   (if mark-active
+       (list (region-beginning) (region-end) current-prefix-arg)
+     (list (line-beginning-position) (line-end-position) current-prefix-arg)))
   (if count
       (setq count (prefix-numeric-value count))
     (setq count python-indent))
@@ -2141,20 +2208,21 @@ Uses `python-beginning-of-block', `python-end-of-block'."
   "Return a list of completions of the string SYMBOL from Python process.
 The list is sorted.
 Uses `python-imports' to load modules against which to complete."
-  (when symbol
+  (when (stringp symbol)
     (let ((completions
           (condition-case ()
               (car (read-from-string
                     (python-send-receive
-                     (format "emacs.complete(%S,%s)" symbol python-imports))))
+                     (format "emacs.complete(%S,%s)"
+                             (substring-no-properties symbol)
+                             python-imports))))
             (error nil))))
       (sort
        ;; We can get duplicates from the above -- don't know why.
        (delete-dups completions)
        #'string<))))
 
-(defun python-partial-symbol ()
-  "Return the partial symbol before point (for completion)."
+(defun python-completion-at-point ()
   (let ((end (point))
        (start (save-excursion
                 (and (re-search-backward
@@ -2162,7 +2230,9 @@ Uses `python-imports' to load modules against which to complete."
                           (group (1+ (regexp "[[:alnum:]._]"))) point)
                       nil t)
                      (match-beginning 1)))))
-    (if start (buffer-substring-no-properties start end))))
+    (when start
+      (list start end
+            (completion-table-dynamic 'python-symbol-completions)))))
 \f
 ;;;; FFAP support
 
@@ -2198,7 +2268,8 @@ Interactively, prompt for name."
     (unless file (error "Don't know where `%s' is defined" name))
     (pop-to-buffer (find-file-noselect file))
     (when (integerp line)
-      (goto-line line))))
+      (goto-char (point-min))
+      (forward-line (1- line)))))
 \f
 ;;;; Skeletons
 
@@ -2209,33 +2280,26 @@ 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).")
-
 (define-abbrev-table 'python-mode-abbrev-table ()
-  "Abbrev table for Python mode.
-The default contents correspond to the elements of `python-skeletons'."
-  ;; Allow / in abbrevs.
-  :regexp "\\<\\([[:word:]/]+\\)\\W*")
+  "Abbrev table for Python mode."
+  :case-fixed t
+  ;; Allow / inside abbrevs.
+  :regexp "\\(?:^\\|[^/]\\)\\<\\([[:word:]/]+\\)\\W*"
+  ;; Only expand in code.
+  :enable-function (lambda () (not (python-in-string/comment))))
 
 (eval-when-compile
-  ;; Define a user-level skeleton and add it to `python-skeletons' and
-  ;; the abbrev table.
+  ;; Define a user-level skeleton and add it to the abbrev table.
 (defmacro def-python-skeleton (name &rest elements)
   (let* ((name (symbol-name name))
         (function (intern (concat "python-insert-" name))))
     `(progn
-       (add-to-list 'python-skeletons ',(cons name function))
        ;; Usual technique for inserting a skeleton, but expand
        ;; to the original abbrev instead if in a comment or string.
-       (define-abbrev python-mode-abbrev-table ,name ""
-        ;; Quote this to give a readable abbrev table.
-        '(lambda ()
-           (if (python-in-string/comment)
-               (insert ,name)
-             (,function)))
-        nil t)                         ; system abbrev
+       (when python-use-skeletons
+         (define-abbrev python-mode-abbrev-table ,name ""
+           ',function
+           nil t))                      ; system abbrev
        (define-skeleton ,function
         ,(format "Insert Python \"%s\" template." name)
         ,@elements)))))
@@ -2327,13 +2391,14 @@ Interactively, prompt for the name with completion."
   (interactive
    (list (completing-read (format "Template to expand (default %s): "
                                  python-default-template)
-                         python-skeletons nil t)))
+                         python-mode-abbrev-table nil t nil nil
+                          python-default-template)))
   (if (equal "" name)
       (setq name python-default-template)
     (setq python-default-template name))
-  (let ((func (cdr (assoc name python-skeletons))))
-    (if func
-       (funcall func)
+  (let ((sym (abbrev-symbol name python-mode-abbrev-table)))
+    (if sym
+        (abbrev-insert sym)
       (error "Undefined template: %s" name))))
 \f
 ;;;; Bicycle Repair Man support
@@ -2397,22 +2462,6 @@ without confirmation."
 (defvar eldoc-documentation-function)
 (defvar python-mode-running)            ;Dynamically scoped var.
 
-;; Stuff to allow expanding abbrevs with non-word constituents.
-(defun python-abbrev-pc-hook ()
-  "Reset the syntax table after possibly expanding abbrevs."
-  (remove-hook 'post-command-hook 'python-abbrev-pc-hook t)
-  (set-syntax-table python-mode-syntax-table))
-
-(defvar python-abbrev-syntax-table
-  (copy-syntax-table python-mode-syntax-table)
-  "Syntax table used when expanding abbrevs.")
-
-(defun python-pea-hook ()
-  "Set the syntax table before possibly expanding abbrevs."
-  (set-syntax-table python-abbrev-syntax-table)
-  (add-hook 'post-command-hook 'python-abbrev-pc-hook nil t))
-(modify-syntax-entry ?/ "w" python-abbrev-syntax-table)
-
 ;;;###autoload
 (define-derived-mode python-mode fundamental-mode "Python"
   "Major mode for editing Python files.
@@ -2486,10 +2535,8 @@ with skeleton expansions for compound statement templates.
   (add-hook 'eldoc-mode-hook
            (lambda () (run-python nil t)) ; need it running
            nil t)
-  (set (make-local-variable 'symbol-completion-symbol-function)
-       'python-partial-symbol)
-  (set (make-local-variable 'symbol-completion-completions-function)
-       'python-symbol-completions)
+  (add-hook 'completion-at-point-functions
+            'python-completion-at-point nil 'local)
   ;; Fixme: should be in hideshow.  This seems to be of limited use
   ;; since it isn't (can't be) indentation-based.  Also hide-level
   ;; doesn't seem to work properly.
@@ -2503,11 +2550,6 @@ with skeleton expansions for compound statement templates.
        '((< '(backward-delete-char-untabify (min python-indent
                                                 (current-column))))
         (^ '(- (1+ (current-indentation))))))
-  (add-hook 'pre-abbrev-expand-hook 'python-pea-hook nil t)
-  (if (featurep 'hippie-exp)
-      (set (make-local-variable 'hippie-expand-try-functions-list)
-          (cons 'symbol-completion-try-complete
-                hippie-expand-try-functions-list)))
   ;; Python defines TABs as being 8-char wide.
   (set (make-local-variable 'tab-width) 8)
   (unless font-lock-mode (font-lock-mode 1))
@@ -2551,9 +2593,7 @@ Runs `jython-mode-hook' after `python-mode-hook'."
   "Watch output for Python prompt and exec next file waiting in queue.
 This function is appropriate for `comint-output-filter-functions'."
   ;; TBD: this should probably use split-string
-  (when (and (or (string-equal string ">>> ")
-                (and (>= (length string) 5)
-                     (string-equal (substring string -5) "\n>>> ")))
+  (when (and (string-match python--prompt-regexp string)
             python-file-queue)
     (condition-case nil
         (delete-file (car python-file-queue))
@@ -2630,7 +2670,8 @@ find it."
                   target_buffer (cadr target)
                   target_fname (buffer-file-name target_buffer))
             (switch-to-buffer-other-window target_buffer)
-            (goto-line target_lineno)
+            (goto-char (point-min))
+            (forward-line (1- target_lineno))
             (message "pdbtrack: line %s, file %s" target_lineno target_fname)
             (python-pdbtrack-overlay-arrow t)
             (pop-to-buffer origbuf t)
@@ -2667,8 +2708,7 @@ problem."
                  ;; Add in number of lines for leading '##' comments:
                  (setq lineno
                        (+ lineno
-                          (save-excursion
-                            (set-buffer funcbuffer)
+                          (with-current-buffer funcbuffer
                             (if (equal (point-min)(point-max))
                                 0
                               (count-lines
@@ -2696,13 +2736,12 @@ problem."
     (while (and buffers (not got))
       (setq buf (car buffers)
             buffers (cdr buffers))
-      (if (and (save-excursion (set-buffer buf)
-                               (string= major-mode "python-mode"))
+      (if (and (with-current-buffer buf
+                 (string= major-mode "python-mode"))
                (or (string-match funcname (buffer-name buf))
                    (string-match (concat "^\\s-*\\(def\\|class\\)\\s-+"
                                          funcname "\\s-*(")
-                                 (save-excursion
-                                   (set-buffer buf)
+                                 (with-current-buffer buf
                                    (buffer-substring (point-min)
                                                      (point-max))))))
           (setq got buf)))
@@ -2760,13 +2799,13 @@ comint believe the user typed this string so that
         ;; add some comment, so that we can filter it out of history
        (cmd (format "execfile(r'%s') # PYTHON-MODE\n" filename)))
     (unwind-protect
-       (save-excursion
-         (set-buffer procbuf)
+       (with-current-buffer procbuf
          (goto-char (point-max))
          (move-marker (process-mark proc) (point))
          (funcall (process-filter proc) proc msg))
       (set-buffer curbuf))
     (process-send-string proc cmd)))
+
 ;;;###autoload
 (defun python-shell (&optional argprompt)
   "Start an interactive Python interpreter in another window.
@@ -2781,7 +2820,7 @@ command is used to switch to an existing process, only when a new
 process is started.  If you use this, you will probably want to ensure
 that the current arguments are retained (they will be included in the
 prompt).  This argument is ignored when this function is called
-programmatically, or when running in Emacs 19.34 or older.
+programmatically.
 
 Note: You can toggle between using the CPython interpreter and the
 JPython interpreter by hitting \\[python-toggle-shells].  This toggles
@@ -2806,12 +2845,13 @@ interaction between undo and process filters; the same problem exists in
 non-Python process buffers using the default (Emacs-supplied) process
 filter."
   (interactive "P")
+  (require 'ansi-color) ; For ipython
   ;; Set the default shell if not already set
   (when (null python-which-shell)
     (python-toggle-shells python-default-interpreter))
   (let ((args python-which-args))
     (when (and argprompt
-              (interactive-p)
+              (called-interactively-p 'interactive)
               (fboundp 'split-string))
       ;; TBD: Perhaps force "-i" in the final list?
       (setq args (split-string
@@ -2822,10 +2862,9 @@ filter."
                               ))))
     (switch-to-buffer-other-window
      (apply 'make-comint python-which-bufname python-which-shell nil args))
-    (make-local-variable 'comint-prompt-regexp)
     (set-process-sentinel (get-buffer-process (current-buffer))
                           'python-sentinel)
-    (setq comint-prompt-regexp "^>>> \\|^[.][.][.] \\|^(pdb) ")
+    (python--set-prompt-regexp)
     (add-hook 'comint-output-filter-functions
              'python-comint-output-filter-function nil t)
     ;; pdbtrack
@@ -2858,5 +2897,4 @@ filter."
 (provide 'python)
 (provide 'python-21)
 
-;; arch-tag: 6fce1d99-a704-4de9-ba19-c6e4912b0554
 ;;; python.el ends here