changeset 111753:f84b2c2c0b1b

Backport fixes for Bug#5390 and Bug#5694 from trunk. * progmodes/python.el: Add Ipython support (Bug#5390). (python-shell-prompt-alist) (python-shell-continuation-prompt-alist): New options. (python--set-prompt-regexp): New function. (inferior-python-mode, run-python, python-shell): Require ansi-color. Use python--set-prompt-regexp to set the comint prompt based on the Python interpreter. (python--prompt-regexp): New var. (python-check-comint-prompt) (python-comint-output-filter-function): Use it. (run-python): Use a pipe (Bug#5694).
author Chong Yidong <cyd@stupidchicken.com>
date Sun, 21 Nov 2010 12:04:43 -0500
parents 3776ded7f730
children 5cb4c579f559
files lisp/ChangeLog lisp/progmodes/python.el
diffstat 2 files changed, 85 insertions(+), 24 deletions(-) [+]
line wrap: on
line diff
--- a/lisp/ChangeLog	Sun Nov 21 11:52:05 2010 -0500
+++ b/lisp/ChangeLog	Sun Nov 21 12:04:43 2010 -0500
@@ -1,3 +1,17 @@
+2010-11-21  Chong Yidong  <cyd@stupidchicken.com>
+
+	* progmodes/python.el: Add Ipython support (Bug#5390).
+	(python-shell-prompt-alist)
+	(python-shell-continuation-prompt-alist): New options.
+	(python--set-prompt-regexp): New function.
+	(inferior-python-mode, run-python, python-shell): Require
+	ansi-color.  Use python--set-prompt-regexp to set the comint
+	prompt based on the Python interpreter.
+	(python--prompt-regexp): New var.
+	(python-check-comint-prompt)
+	(python-comint-output-filter-function): Use it.
+	(run-python): Use a pipe (Bug#5694).
+
 2010-11-21  Chong Yidong  <cyd@stupidchicken.com>
 
 	* progmodes/python.el (run-python): Doc fix.
--- a/lisp/progmodes/python.el	Sun Nov 21 11:52:05 2010 -0500
+++ b/lisp/progmodes/python.el	Sun Nov 21 12:04:43 2010 -0500
@@ -570,6 +570,33 @@
   "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
@@ -1302,13 +1329,9 @@
 
 ;;;; 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 @@
 ;; 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 @@
 
 \\{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))
@@ -1522,12 +1560,12 @@
 				     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
@@ -1554,6 +1592,7 @@
   (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)
@@ -1572,8 +1611,10 @@
 			      (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)))
@@ -1629,7 +1670,12 @@
   ;; 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)
@@ -1829,7 +1875,9 @@
 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.)
@@ -2545,9 +2593,7 @@
   "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))
@@ -2759,6 +2805,7 @@
 	  (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.
@@ -2798,6 +2845,7 @@
 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))
@@ -2814,10 +2862,9 @@
 			       ))))
     (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