]> code.delx.au - gnu-emacs/blobdiff - lisp/progmodes/python.el
Fix references to jit-lock properties.
[gnu-emacs] / lisp / progmodes / python.el
index e9f3dafa2f07e4fc9964c8f93721919b3520f074..eff599c77a5853147824216a085e2ffc35784bb6 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
+;;   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
   :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
 
@@ -296,9 +297,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"]
@@ -411,7 +410,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 +418,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-*$")))
@@ -749,7 +748,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" "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 +978,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 +990,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)
@@ -1548,7 +1550,9 @@ 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" "-c" "import sys; sys.path.remove('')")))
               (path (getenv "PYTHONPATH"))
               (process-environment     ; to import emacs.py
                (cons (concat "PYTHONPATH="
@@ -1781,9 +1785,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,10 +1811,9 @@ 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)))))
@@ -2005,9 +2009,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 +2033,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))
@@ -2198,7 +2204,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 +2216,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 +2327,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 +2398,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.
@@ -2503,11 +2488,12 @@ 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)))
+  ;; Let's not mess with hippie-expand.  Symbol-completion should rather be
+  ;; bound to another key, since it has different performance requirements.
+  ;; (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))
@@ -2630,7 +2616,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 +2654,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 +2682,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,8 +2745,7 @@ 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))
@@ -2811,7 +2795,7 @@ filter."
     (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