]> code.delx.au - gnu-emacs/blobdiff - lisp/progmodes/python.el
(gnus-newsrc-file-version): Add defvar.
[gnu-emacs] / lisp / progmodes / python.el
index 274480a36deed90452b2eaebaabaa5658ac5cdca..433476f79579206d15e6e7acef605e7fdb0a49db 100644 (file)
@@ -1,6 +1,6 @@
 ;;; python.el --- silly walks for Python
 
-;; Copyright (C) 2003, 04  Free Software Foundation, Inc.
+;; Copyright (C) 2003, 2004, 2005  Free Software Foundation, Inc.
 
 ;; Author: Dave Love <fx@gnu.org>
 ;; Maintainer: FSF
@@ -21,8 +21,8 @@
 
 ;; 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., 59 Temple Place - Suite 330,
-;; Boston, MA 02111-1307, USA.
+;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+;; Boston, MA 02110-1301, USA.
 
 ;;; Commentary:
 
 (eval-when-compile
   (require 'compile)
   (autoload 'info-lookup-maybe-add-help "info-look"))
-(autoload 'compilation-start "compile")
 
 (defgroup python nil
-  "Silly walks in the Python language"
+  "Silly walks in the Python language."
   :group 'languages
-  :version "21.4"
+  :version "22.1"
   :link '(emacs-commentary-link "python"))
 \f
 ;;;###autoload
 (defconst python-font-lock-syntactic-keywords
   ;; Make outer chars of matching triple-quote sequences into generic
   ;; string delimiters.  Fixme: Is there a better way?
-  `((,(rx (and (group (optional (any "uUrR"))) ; prefix gets syntax property
+  `((,(rx (and (or line-start buffer-start (not (syntax escape))) ; avoid escaped
+                                                      ; leading quote
+              (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
@@ -130,32 +131,31 @@ Used for syntactic keywords.  N is the match number (1, 2 or 3)."
   ;;  ur"""ar""" x='"' # """
   ;; x = ''' """ ' a
   ;; '''
-  ;; x '"""' x
+  ;; x '"""' x """ \"""" x
   (save-excursion
     (goto-char (match-beginning 0))
-    (unless (eq ?\\ (char-before))
-      (cond
-       ;; Consider property for the last char if in a fenced string.
-       ((= n 3)
-       (let ((syntax (syntax-ppss)))
-         (when (eq t (nth 3 syntax))    ; after unclosed fence
-           (goto-char (nth 8 syntax))   ; fence position
-           ;; Skip any prefix.
-           (if (memq (char-after) '(?u ?U ?R ?r))
-               (skip-chars-forward "uUrR"))
-           ;; Is it a matching sequence?
-           (if (eq (char-after) (char-after (match-beginning 2)))
-               (eval-when-compile (string-to-syntax "|"))))))
-       ;; Consider property for initial char, accounting for prefixes.
-       ((or (and (= n 2)                               ; not prefix
-                (= (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)))
-         (eval-when-compile (string-to-syntax "|")))))
-      ;; Otherwise (we're in a non-matching string) the property is
-      ;; nil, which is OK.
-      )))
+    (cond
+     ;; Consider property for the last char if in a fenced string.
+     ((= n 3)
+      (let ((syntax (syntax-ppss)))
+       (when (eq t (nth 3 syntax))     ; after unclosed fence
+         (goto-char (nth 8 syntax))    ; fence position
+         ;; Skip any prefix.
+         (if (memq (char-after) '(?u ?U ?R ?r))
+             (skip-chars-forward "uUrR"))
+         ;; Is it a matching sequence?
+         (if (eq (char-after) (char-after (match-beginning 2)))
+             (eval-when-compile (string-to-syntax "|"))))))
+     ;; Consider property for initial char, accounting for prefixes.
+     ((or (and (= n 2)                 ; not prefix
+              (= (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)))
+       (eval-when-compile (string-to-syntax "|"))))
+     ;; Otherwise (we're in a non-matching string) the property is
+     ;; nil, which is OK.
+     )))
 
 ;; This isn't currently in `font-lock-defaults' as probably not worth
 ;; it -- we basically only mess with a few normally-symbol characters.
@@ -335,14 +335,14 @@ keyword `raise', `break', `continue' or `pass'."
     (unless bos (python-beginning-of-statement))
     (back-to-indentation)
     (looking-at (rx (and (or "return" "raise" "break" "continue" "pass")
-                        word-end)))))
+                        symbol-end)))))
 
 (defun python-outdent-p ()
   "Return non-nil if current line should outdent a level."
   (save-excursion
     (back-to-indentation)
-    (and (looking-at (rx (and (or (and (or "else" "finally") word-end)
-                                 (and (or "except" "elif") word-end
+    (and (looking-at (rx (and (or (and (or "else" "finally") symbol-end)
+                                 (and (or "except" "elif") symbol-end
                                       (1+ (not (any ?:)))))
                              (optional space) ":" (optional space)
                              (or (syntax comment-start) line-end))))
@@ -354,8 +354,8 @@ keyword `raise', `break', `continue' or `pass'."
         ;; Fixme: check this
         (not (looking-at (rx (and (or (and (or "if" "elif" "except"
                                                "for" "while")
-                                           word-end (1+ (not (any ?:))))
-                                      (and "try" word-end))
+                                           symbol-end (1+ (not (any ?:))))
+                                      (and "try" symbol-end))
                                   (optional space) ":" (optional space)
                                   (or (syntax comment-start) line-end)))))
         (progn (end-of-line)
@@ -710,16 +710,17 @@ Accounts for continuation lines, multi-line strings, and multi-line bracketed
 expressions."
   (beginning-of-line)
   (python-beginning-of-string)
-  (while (python-continuation-line-p)
-    (beginning-of-line)
-    (if (python-backslash-continuation-line-p)
-       (while (python-backslash-continuation-line-p)
-         (forward-line -1))
-      (python-beginning-of-string)
-      ;; Skip forward out of nested brackets.
-      (condition-case ()               ; beware invalid syntax
-         (progn (backward-up-list (syntax-ppss-depth (syntax-ppss))) t)
-       (error (end-of-line)))))
+  (catch 'foo
+    (while (python-continuation-line-p)
+      (beginning-of-line)
+      (if (python-backslash-continuation-line-p)
+         (while (python-backslash-continuation-line-p)
+           (forward-line -1))
+       (python-beginning-of-string)
+       ;; Skip forward out of nested brackets.
+       (condition-case ()              ; beware invalid syntax
+           (progn (backward-up-list (syntax-ppss-depth (syntax-ppss))) t)
+         (error (throw 'foo nil))))))
   (back-to-indentation))
 
 (defun python-end-of-statement ()
@@ -947,6 +948,7 @@ See `python-check-command' for the default."
                                    (if name
                                        (file-name-nondirectory name))))))))
   (setq python-saved-check-command command)
+  (require 'compile)                    ;To define compilation-* variables.
   (save-some-buffers (not compilation-ask-about-save) nil)
   (let ((compilation-error-regexp-alist
         (cons '("(\\([^,]+\\), line \\([0-9]+\\))" 1 2)
@@ -1064,7 +1066,7 @@ For running multiple processes in multiple buffers, see `python-buffer'.
   ;; Still required by `comint-redirect-send-command', for instance
   ;; (and we need to match things like `>>> ... >>> '):
   (set (make-local-variable 'comint-prompt-regexp)
-       (rx (and line-start (1+ (and (repeat 3 (any ">.")) ?\ )))))
+       (rx (and line-start (1+ (and (repeat 3 (any ">.")) ?\s)))))
   (set (make-local-variable 'compilation-error-regexp-alist)
        python-compilation-regexp-alist)
   (compilation-shell-minor-mode 1))
@@ -1096,28 +1098,40 @@ Don't save anything for STR matching `inferior-python-filter-regexp'."
 (defvar python-preoutput-continuation nil
   "If non-nil, funcall this when `python-preoutput-filter' sees `_emacs_ok'.")
 
+(defvar python-preoutput-leftover 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 (and string-start (repeat 3 (any ".>"))
-                                    " " string-end))
-                           s)
-             (/= (let ((inhibit-field-text-motion t))
-                   (line-beginning-position))
-                 (point)))
+                                     " " string-end))
+                            s)
+              (/= (let ((inhibit-field-text-motion t))
+                    (line-beginning-position))
+                  (point)))
+         "")
+        ((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)
         "")
-       ((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))
-        "")
-       (t s)))
+        (t s)))
 
 ;;;###autoload
 (defun run-python (&optional cmd noshow)
@@ -1126,7 +1140,7 @@ CMD is the Python command to run.  NOSHOW non-nil means don't show the
 buffer automatically.
 If there is a process already running in `*Python*', 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
+command line (default is `python-command'); `-i' etc.  args will be added
 to this as appropriate.  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.)"
@@ -1142,12 +1156,12 @@ to this as appropriate.  Runs the hook `inferior-python-mode-hook'
     (let* ((cmdlist (append (python-args-to-list cmd) '("-i")))
           (path (getenv "PYTHONPATH"))
           (process-environment         ; to import emacs.py
-           (push (concat "PYTHONPATH=" data-directory
+           (cons (concat "PYTHONPATH=" data-directory
                          (if path (concat ":" path)))
                  process-environment)))
       (set-buffer (apply 'make-comint "Python" (car cmdlist) nil
                         (cdr cmdlist)))
-      (setq python-buffer "*Python*"))
+      (setq python-buffer (buffer-name)))
     (inferior-python-mode)
     ;; Load function defintions we need.
     ;; Before the preoutput function was used, this was done via -c in
@@ -1203,13 +1217,12 @@ to this as appropriate.  Runs the hook `inferior-python-mode-hook'
        (set-marker orig-start (line-beginning-position 0)))
       (write-region "if True:\n" nil f nil 'nomsg))
     (write-region start end f t 'nomsg)
-    (let ((proc (python-proc)))                ;Make sure we're running a process.
-      (with-current-buffer python-buffer
-       (python-send-command command)
-       ;; Tell compile.el to redirect error locations in file `f' to
-       ;; positions past marker `orig-start'.  It has to be done *after*
-       ;; python-send-command's call to compilation-forget-errors.
-       (compilation-fake-loc orig-start f)))))
+    (with-current-buffer (process-buffer (python-proc))        ;Runs python if needed.
+      (python-send-command command)
+      ;; Tell compile.el to redirect error locations in file `f' to
+      ;; positions past marker `orig-start'.  It has to be done *after*
+      ;; python-send-command's call to compilation-forget-errors.
+      (compilation-fake-loc orig-start f))))
 
 (defun python-send-string (string)
   "Evaluate STRING in inferior Python process."
@@ -1234,15 +1247,11 @@ to this as appropriate.  Runs the hook `inferior-python-mode-hook'
   "Switch to the Python process buffer.
 With prefix arg, position cursor at end of buffer."
   (interactive "P")
-  (if (get-buffer python-buffer)
-      (pop-to-buffer python-buffer)
-    (error "No current process buffer.  See variable `python-buffer'"))
+  (pop-to-buffer (process-buffer (python-proc))) ;Runs python if needed.
   (when eob-p
     (push-mark)
     (goto-char (point-max))))
 
-(add-to-list 'debug-ignored-errors "^No current process buffer.")
-
 (defun python-send-region-and-go (start end)
   "Send the region to the inferior Python process.
 Then switch to the process buffer."
@@ -1274,17 +1283,16 @@ module-qualified names."
   (comint-check-source file-name)     ; Check to see if buffer needs saving.
   (setq python-prev-dir/file (cons (file-name-directory file-name)
                                   (file-name-nondirectory file-name)))
-  (let ((proc (python-proc)))          ;Make sure we have a process.
-    (with-current-buffer python-buffer
-      ;; Fixme: I'm not convinced by this logic from python-mode.el.
-      (python-send-command
-       (if (string-match "\\.py\\'" file-name)
-          (let ((module (file-name-sans-extension
-                         (file-name-nondirectory file-name))))
-            (format "emacs.eimport(%S,%S)"
-                    module (file-name-directory file-name)))
-        (format "execfile(%S)" file-name)))
-      (message "%s loaded" file-name))))
+  (with-current-buffer (process-buffer (python-proc)) ;Runs python if needed.
+    ;; Fixme: I'm not convinced by this logic from python-mode.el.
+    (python-send-command
+     (if (string-match "\\.py\\'" file-name)
+        (let ((module (file-name-sans-extension
+                       (file-name-nondirectory file-name))))
+          (format "emacs.eimport(%S,%S)"
+                  module (file-name-directory file-name)))
+       (format "execfile(%S)" file-name)))
+    (message "%s loaded" file-name)))
 
 ;; Fixme: If we need to start the process, wait until we've got the OK
 ;; from the startup.
@@ -1363,7 +1371,9 @@ The result is what follows `_emacs_out' in the output (or nil)."
   (let ((proc (python-proc)))
     (python-send-string string)
     (setq python-preoutput-result nil)
-    (accept-process-output proc 5)
+    (while (progn
+            (accept-process-output proc 5)
+            python-preoutput-leftover))
     python-preoutput-result))
 
 ;; Fixme: try to make it work with point in the arglist.  Also, is
@@ -1566,7 +1576,8 @@ of current line."
        (beginning-of-defun)
        (if (looking-at (rx (and (0+ space) (or "def" "class") (1+ space)
                                 (group (1+ (or word (syntax symbol))))
-                                word-end)))
+                                ;; Greediness makes this unnecessary?  --Stef
+                                symbol-end)))
            (push (match-string 1) accum)))
       (if accum (mapconcat 'identity accum ".")))))
 
@@ -1669,7 +1680,7 @@ Repeating the command scrolls the completion window."
 ;;;; Modes.
 
 (defvar outline-heading-end-regexp)
-(defvar eldoc-print-current-symbol-info-function)
+(defvar eldoc-documentation-function)
 
 ;;;###autoload
 (define-derived-mode python-mode fundamental-mode "Python"
@@ -1706,9 +1717,9 @@ lines count as headers.
        '(python-font-lock-keywords nil nil ((?_ . "w")) nil
                                   (font-lock-syntactic-keywords
                                    . python-font-lock-syntactic-keywords)
-;;; This probably isn't worth it.
-;;;                               (font-lock-syntactic-face-function
-;;;                                . python-font-lock-syntactic-face-function)
+                                  ;; This probably isn't worth it.
+                                  ;; (font-lock-syntactic-face-function
+                                  ;;  . python-font-lock-syntactic-face-function)
                                   ))
   (set (make-local-variable 'parse-sexp-lookup-properties) t)
   (set (make-local-variable 'comment-start) "# ")
@@ -1716,7 +1727,7 @@ lines count as headers.
   (set (make-local-variable 'indent-line-function) #'python-indent-line)
   (set (make-local-variable 'paragraph-start) "\\s-*$")
   (set (make-local-variable 'fill-paragraph-function) 'python-fill-paragraph)
-  (set (make-local-variable 'require-final-newline) t)
+  (set (make-local-variable 'require-final-newline) mode-require-final-newline)
   (set (make-local-variable 'add-log-current-defun-function)
        #'python-current-defun)
   ;; Fixme: Generalize to do all blocks?
@@ -1729,7 +1740,7 @@ lines count as headers.
        'python-beginning-of-defun)
   (set (make-local-variable 'end-of-defun-function) 'python-end-of-defun)
   (setq imenu-create-index-function #'python-imenu-create-index)
-  (set (make-local-variable 'eldoc-print-current-symbol-info-function)
+  (set (make-local-variable 'eldoc-documentation-function)
        #'python-eldoc-function)
   (add-hook 'eldoc-mode-hook
            '(lambda () (run-python 0 t)) nil t) ; need it running