[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: python-mode: make sure output is not eaten

From: Stefan Monnier
Subject: Re: python-mode: make sure output is not eaten
Date: Wed, 23 Aug 2006 00:04:40 -0400
User-agent: Gnus/5.11 (Gnus v5.11) Emacs/22.0.50 (gnu/linux)

> #>    (cond ((and (string-match (rx string-start (repeat 3 (any ".>"))
> #>                            " " string-end)
> #> -                            s)
> #> +                              s start)
> as you setq `s' to the appropriate substring one line earlier, in 
>   (unless (zerop start) (setq s (substring s start)))

Oh, right.  I missed this one spot, sorry.

> Also, "\n\n" in python-send-string still needs to be changed into a
> single "\n" in order to avoid spurious prompts.

Yes, of course.  BTW do you have any idea why the current code uses "\n\n"?

> Finally, when you test this patch, make sure you also try enabling
> eldoc-mode (it doesn't work too well, a patch to improve it a bit is
> forthcoming, but even now it works for built-in functions like "apply"
> or "map"). It is important to make sure no extra ">>>"s get added to
> the inferior buffer when eldoc is talking to Python process.

Would it be because eldoc ends up sending commands to the underlying process
while some other command is still being processed?  Maybe we'd need
a "python-process-busy" variable to prevent eldoc from interfering.

> This is -- partially -- the reason why it is important to save
> whatever text exists in front of "_emacs_out"... For example, when I
> python-send-buffer I can get output like "\nTest!\n>>> _emacs_out
> ()\n>>> "... and the ">>>" after "Test!" must show in the buffer. On
> the other hand, after eldoc asks Python about argument list, the
> output may look like this: "_emacs_out apply(object[, args[,
> kwargs]])\n>>> " and it is important that *nothing* is shown in the
> inferior buffer.

The handling of the prompt looks pretty messy, indeed.  I think we should
never send a command followed by "\n" followed by "print _emacs_out ()", but
instead we should send the command augmented with "; print _emacs_out ()\n".
This should avoid those nasty intermediate prompts.

How 'bout the patch below which also removes the _emacs_ok and preoutput
continuation stuff which doesn't seem to be used any more.


--- python.el   20 aoû 2006 14:13:46 -0400      1.41
+++ python.el   23 aoû 2006 00:00:28 -0400      
@@ -1250,47 +1250,45 @@
 (defvar python-preoutput-result nil
   "Data from last `_emacs_out' line seen by the preoutput filter.")
-(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))
+  (let ((start 0)
+        (res ""))
+    ;; First process whole lines.
+    (while (string-match "\n" s start)
+      (let ((line (substring s start (setq start (match-end 0)))))
+        (if (string-match "\\`_emacs_out \\(.*\\)\n\\'" line)
+            (setq python-preoutput-result (match-string 1 line))
+          (setq res (concat res line)))))
+    ;; Then process the remaining partial line.
+    (unless (zerop start) (setq s (substring s start)))
   (cond ((and (string-match (rx string-start (repeat 3 (any ".>"))
                                " " string-end)
-              (/= (let ((inhibit-field-text-motion t))
-                    (line-beginning-position))
-                  (point)))
+                ;; Drop this prompt only if it's not gonna be inserted at BOL.
+                (if (zerop (length res))
+                    (not (bolp))
+                  (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)))
         ;;     (accept-process-output (get-buffer-process (current-buffer)) 1))
-         "")
-        ((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))))
+           res)
+          ((let ((end (min (length "_emacs_out ") (length s))))
+             (eq t (compare-strings s nil end "_emacs_out " nil end)))
+           ;; The leftover string is a prefix of _emacs_out so we don't know
+           ;; yet whether it's an _emacs_out or something else: wait until we
+           ;; get more output so we can resolve this ambiguity.
         (setq python-preoutput-leftover s)
-        "")
-        (t s)))
+           res)
+          (t (concat res s)))))
 (autoload 'comint-check-proc "comint")
@@ -1342,9 +1340,8 @@
   ;; 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.
-  (python-send-string "import emacs")
   ;; Ensure we're at a prompt before doing anything else.
-  (python-send-receive "print '_emacs_out ()'")
+  (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
@@ -1362,9 +1359,8 @@
   (let ((end (marker-position (process-mark (python-proc)))))
     (with-current-buffer python-buffer (goto-char (point-max)))
-    (python-send-string command)
     ;; Must wait until this has completed before re-setting variables below.
-    (python-send-receive "print '_emacs_out ()'")
+    (python-send-receive (concat comand "; print '_emacs_out ()'"))
     (with-current-buffer python-buffer
       (set-marker compilation-parsing-end end)
       (setq compilation-last-buffer (current-buffer)))))
@@ -1409,7 +1405,7 @@
   "Evaluate STRING in inferior Python process."
   (interactive "sPython command: ")
   (comint-send-string (python-proc) string)
-  (comint-send-string (python-proc) "\n\n"))
+  (comint-send-string (python-proc) "\n"))
 (defun python-send-buffer ()
   "Send the current buffer to the inferior Python process."

reply via email to

[Prev in Thread] Current Thread [Next in Thread]