First round of changes, mostly subprocess stuff.

(py-execute-file): Better interaction with comint.  Set
comint-scroll-to-bottom-on-output to t.  Wrapper buffer change in
unwind-protect in case process filter fails.

(py-shell): Start Python with -i flag to fix tty problem on Windows;
presumably -- not yet tested.

(py-clear-queue): New function to clear the pending exec file queue.
Not currently keybound.

(py-execute-region, py-execute-buffer): Added optional async flag (use
via C-u prefix) to execute the region in a new asynchrous buffer, even
if the Python shell is running.

(py-append-to-process-buffer): Removed as obsolete.  Comint provides
this functionality.

Removed fbound test defun of match-string.  All modern X/Emacsen have
this function.
This commit is contained in:
Barry Warsaw 1997-11-04 18:47:06 +00:00
parent bfa9f13e14
commit a97a3f34d6
1 changed files with 129 additions and 138 deletions

View File

@ -6,7 +6,6 @@
;; 1992-1994 Tim Peters
;; Maintainer: python-mode@python.org
;; Created: Feb 1992
;; Version: 3.0
;; Keywords: python languages oop
(defconst py-version "3.0"
@ -32,10 +31,10 @@
;; python-mode.el is currently distributed with XEmacs 19 and XEmacs
;; 20. Since this file is not GPL'd it is not distributed with Emacs,
;; but it is compatible with the EOL 19 series and current 20 series
;; Emacsen. By default, in XEmacs when you visit a .py file, it is
;; put in Python mode. In Emacs, you need to add the following to
;; your .emacs file (you don't need this for XEmacs):
;; but it is compatible with 19.34 and the current 20 series Emacsen.
;; By default, in XEmacs when you visit a .py file, it is put in
;; Python mode. In Emacs, you need to add the following to your
;; .emacs file (you don't need this for XEmacs):
;;
;; (autoload 'python-mode "python-mode" "Python editing mode." t)
;; (setq auto-mode-alist
@ -854,110 +853,32 @@ Electric behavior is inhibited inside a string or comment."
)))))
;;; Functions that execute Python commands in a subprocess
;;;###autoload
(defun py-shell ()
"Start an interactive Python interpreter in another window.
This is like Shell mode, except that Python is running in the window
instead of a shell. See the `Interactive Shell' and `Shell Mode'
sections of the Emacs manual for details, especially for the key
bindings active in the `*Python*' buffer.
See the docs for variable `py-scroll-buffer' for info on scrolling
behavior in the process window.
Warning: Don't use an interactive Python if you change sys.ps1 or
sys.ps2 from their default values, or if you're running code that
prints `>>> ' or `... ' at the start of a line. `python-mode' can't
distinguish your output from Python's output, and assumes that `>>> '
at the start of a line is a prompt from Python. Similarly, the Emacs
Shell mode code assumes that both `>>> ' and `... ' at the start of a
line are Python prompts. Bad things can happen if you fool either
mode.
Warning: If you do any editing *in* the process buffer *while* the
buffer is accepting output from Python, do NOT attempt to `undo' the
changes. Some of the output (nowhere near the parts you changed!) may
be lost if you do. This appears to be an Emacs bug, an unfortunate
interaction between undo and process filters; the same problem exists in
non-Python process buffers using the default (Emacs-supplied) process
filter."
;; BAW - should undo be disabled in the python process buffer, if
;; this bug still exists?
(interactive)
(require 'comint)
(switch-to-buffer-other-window (make-comint "Python" py-python-command))
(make-local-variable 'comint-prompt-regexp)
(setq comint-prompt-regexp "^>>> \\|^[.][.][.] ")
(set-process-filter (get-buffer-process (current-buffer)) nil)
(set-syntax-table py-mode-syntax-table)
(local-set-key [tab] 'self-insert-command))
(defun py-execute-region (start end)
"Send the region between START and END to a Python interpreter.
If there is a *Python* process it is used.
Hint: If you want to execute part of a Python file several times
\(e.g., perhaps you're developing a function and want to flesh it out
a bit at a time), use `\\[narrow-to-region]' to restrict the buffer to
the region of interest, and send the code to a *Python* process via
`\\[py-execute-buffer]' instead.
Following are subtleties to note when using a *Python* process:
If a *Python* process is used, the region is copied into a temporary
file (in directory `py-temp-directory'), and an `execfile' command is
sent to Python naming that file. If you send regions faster than
Python can execute them, `python-mode' will save them into distinct
temp files, and execute the next one in the queue the next time it
sees a `>>> ' prompt from Python. Each time this happens, the process
buffer is popped into a window (if it's not already in some window) so
you can see it, and a comment of the form
\t## working on region in file <name> ...
is inserted at the end.
Caution: No more than 26 regions can be pending at any given time.
This limit is (indirectly) inherited from libc's mktemp(3).
`python-mode' does not try to protect you from exceeding the limit.
It's extremely unlikely that you'll get anywhere close to the limit in
practice, unless you're trying to be a jerk <grin>.
See the `\\[py-shell]' docs for additional warnings."
(interactive "r")
(or (< start end)
(error "Region is empty"))
(let ((pyproc (get-process "Python"))
fname)
(if (null pyproc)
(let ((outbuf "*Python Output*"))
(shell-command-on-region start end py-python-command outbuf)
(save-excursion
(set-buffer outbuf)
;; TBD: ???
(goto-char (point-max))))
;; else feed it thru a temp file
(setq fname (py-make-temp-name))
(write-region start end fname nil 'no-msg)
(setq py-file-queue (append py-file-queue (list fname)))
(if (cdr py-file-queue)
(message "File %s queued for execution" fname)
;; else
(py-execute-file pyproc fname)))))
(defun py-execute-file (pyproc fname)
(py-append-to-process-buffer
pyproc
(format "## working on region in file %s ...\n" fname))
(process-send-string pyproc (format "execfile('%s')\n" fname)))
;; Python subprocess utilities and filters
(defun py-execute-file (proc filename)
;; Send a properly formatted execfile('FILENAME') to the underlying
;; Python interpreter process FILENAME. Make that process's buffer
;; visible and force display. Also make comint believe the user
;; typed this string so that kill-output-from-shell does The Right
;; Thing.
(let ((curbuf (current-buffer))
(procbuf (process-buffer proc))
(comint-scroll-to-bottom-on-output t)
(msg (format "## working on region in file %s...\n" filename))
(cmd (format "execfile('%s')\n" filename)))
(unwind-protect
(progn
(set-buffer procbuf)
(goto-char (point-max))
(move-marker (process-mark proc) (point))
(funcall (process-filter proc) proc msg))
(set-buffer curbuf))
(process-send-string proc cmd)))
(defun py-process-filter (pyproc string)
(let ((curbuf (current-buffer))
(pbuf (process-buffer pyproc))
(pmark (process-mark pyproc))
file-finished)
;; make sure we switch to a different buffer at least once. if we
;; *don't* do this, then if the process buffer is in the selected
;; window, and point is before the end, and lots of output is
@ -1017,16 +938,114 @@ See the `\\[py-shell]' docs for additional warnings."
))
(set-buffer curbuf))))
(defun py-execute-buffer ()
;;; Subprocess commands
;;;###autoload
(defun py-shell ()
"Start an interactive Python interpreter in another window.
This is like Shell mode, except that Python is running in the window
instead of a shell. See the `Interactive Shell' and `Shell Mode'
sections of the Emacs manual for details, especially for the key
bindings active in the `*Python*' buffer.
See the docs for variable `py-scroll-buffer' for info on scrolling
behavior in the process window.
Warning: Don't use an interactive Python if you change sys.ps1 or
sys.ps2 from their default values, or if you're running code that
prints `>>> ' or `... ' at the start of a line. `python-mode' can't
distinguish your output from Python's output, and assumes that `>>> '
at the start of a line is a prompt from Python. Similarly, the Emacs
Shell mode code assumes that both `>>> ' and `... ' at the start of a
line are Python prompts. Bad things can happen if you fool either
mode.
Warning: If you do any editing *in* the process buffer *while* the
buffer is accepting output from Python, do NOT attempt to `undo' the
changes. Some of the output (nowhere near the parts you changed!) may
be lost if you do. This appears to be an Emacs bug, an unfortunate
interaction between undo and process filters; the same problem exists in
non-Python process buffers using the default (Emacs-supplied) process
filter."
;; BAW - should undo be disabled in the python process buffer, if
;; this bug still exists?
(interactive)
(require 'comint)
(switch-to-buffer-other-window (make-comint "Python" py-python-command "-i"))
(make-local-variable 'comint-prompt-regexp)
(setq comint-prompt-regexp "^>>> \\|^[.][.][.] ")
(set-process-filter (get-buffer-process (current-buffer)) 'py-process-filter)
(set-syntax-table py-mode-syntax-table)
(local-set-key [tab] 'self-insert-command))
(defun py-clear-queue ()
"Clear the queue of temporary files waiting to execute."
(interactive)
(let ((n (length py-file-queue)))
(mapcar 'delete-file py-file-queue)
(setq py-file-queue nil)
(message "%d pending files de-queued." n)))
(defun py-execute-region (start end &optional async)
"Execute the the region in a Python interpreter.
The region is first copied into a temporary file (in the directory
`py-temp-directory'). If there is no Python interpreter shell
running, this file is executed synchronously using
`shell-command-on-region'. If the program is long running, use an
optional \\[universal-argument] to run the command asynchronously in
its own buffer.
If the Python interpreter shell is running, the region is execfile()'d
in that shell. If you try to execute regions too quickly,
`python-mode' will queue them up and execute them one at a time when
it sees a `>>> ' prompt from Python. Each time this happens, the
process buffer is popped into a window (if it's not already in some
window) so you can see it, and a comment of the form
\t## working on region in file <name>...
is inserted at the end. See also the command `py-clear-queue'."
(interactive "r\nP")
(or (< start end)
(error "Region is empty"))
(let* ((proc (get-process "Python"))
(temp (make-temp-name "python"))
(file (concat (file-name-as-directory py-temp-directory) temp))
(outbuf "*Python Output*"))
(write-region start end file nil 'nomsg)
(cond
;; always run the code in it's own asynchronous subprocess
(async
(let* ((buf (generate-new-buffer-name "*Python Output*")))
(start-process "Python" buf py-python-command "-u" file)
(pop-to-buffer buf)
))
;; if the Python interpreter shell is running, queue it up for
;; execution there.
(proc
;; use the existing python shell
(if (not py-file-queue)
(py-execute-file proc file)
(push file py-file-queue)
(message "File %s queued for execution" file))
)
(t
;; otherwise either run it synchronously in a subprocess
(shell-command-on-region start end py-python-command outbuf)
))))
;; Code execution command
(defun py-execute-buffer (&optional async)
"Send the contents of the buffer to a Python interpreter.
If there is a *Python* process buffer it is used. If a clipping
restriction is in effect, only the accessible portion of the buffer is
sent. A trailing newline will be supplied if needed.
See the `\\[py-execute-region]' docs for an account of some subtleties."
(interactive)
(py-execute-region (point-min) (point-max)))
(interactive "P")
(py-execute-region (point-min) (point-max) async))
;; Functions for Python style indentation
@ -2363,10 +2382,6 @@ local bindings to py-newline-and-indent."))
(intern (buffer-substring (match-beginning 1) (match-end 1)))
nil)))
(defun py-make-temp-name ()
(make-temp-name
(concat (file-name-as-directory py-temp-directory) "python")))
(defun py-delete-file-silently (fname)
(condition-case nil
(delete-file fname)
@ -2378,30 +2393,6 @@ local bindings to py-newline-and-indent."))
(py-delete-file-silently (car py-file-queue))
(setq py-file-queue (cdr py-file-queue)))))
;; make PROCESS's buffer visible, append STRING to it, and force
;; display; also make shell-mode believe the user typed this string,
;; so that kill-output-from-shell and show-output-from-shell work
;; "right"
(defun py-append-to-process-buffer (process string)
(let ((cbuf (current-buffer))
(pbuf (process-buffer process))
(py-scroll-process-buffer t))
(set-buffer pbuf)
(goto-char (point-max))
(move-marker (process-mark process) (point))
(funcall (process-filter process) process string)
(set-buffer cbuf))
(sit-for 0))
;; older Emacsen don't have this function
(if (not (fboundp 'match-string))
(defun match-string (n)
(let ((beg (match-beginning n))
(end (match-end n)))
(if (and beg end)
(buffer-substring beg end)
nil))))
(defun py-current-defun ()
;; tell add-log.el how to find the current function/method/variable
(save-excursion