]> code.delx.au - gnu-emacs/blobdiff - lisp/progmodes/python.el
python.el removed.
[gnu-emacs] / lisp / progmodes / python.el
index c38a6e82f83218ae4126984e0f0b4d3354983bba..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
@@ -67,7 +67,8 @@
 (eval-when-compile
   (require 'cl)
   (require 'compile)
-  (require 'comint))
+  (require 'comint)
+  (require 'hippie-exp))
 
 (autoload 'comint-mode "comint")
 
@@ -95,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 ?_))))
@@ -160,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.
@@ -405,6 +408,7 @@ The criteria are that the line isn't a comment or in string and
 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."
@@ -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)
@@ -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
@@ -1286,7 +1302,7 @@ Don't save anything for STR matching `inferior-python-filter-regexp'."
                     ;; Maybe we could be more selective here.
                     (if (zerop (length res))
                         (not (bolp))
-                      (string-match res ".\\'"))))
+                      (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)))
@@ -1330,30 +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)))
+      (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.
-  ;; Ensure we're at a prompt before doing anything else.
-  (python-send-receive "import emacs; 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
@@ -1369,15 +1385,20 @@ buffer for a list of commands.)"
 (defun python-send-command (command)
   "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 python-buffer (goto-char (point-max)))
+  ;; (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 (concat command "; 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."
@@ -1419,11 +1440,13 @@ COMMAND should be a single statement."
   "Evaluate STRING in inferior Python process."
   (interactive "sPython command: ")
   (comint-send-string (python-proc) string)
-  (comint-send-string (python-proc)
-                      ;; If the string is single-line or if it ends with \n,
-                      ;; only add a single \n, otherwise add 2, so as to
-                      ;; make sure we terminate the multiline instruction.
-                      (if (string-match "\n.+\\'" string) "\n\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."
@@ -1498,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 (derived-mode-p '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.
@@ -1594,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.
 
@@ -1722,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)
@@ -1735,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.
@@ -1957,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).")
@@ -1974,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)))))
@@ -2056,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)
@@ -2193,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)