mirror of https://github.com/python/cpython
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:
parent
bfa9f13e14
commit
a97a3f34d6
|
@ -6,7 +6,6 @@
|
||||||
;; 1992-1994 Tim Peters
|
;; 1992-1994 Tim Peters
|
||||||
;; Maintainer: python-mode@python.org
|
;; Maintainer: python-mode@python.org
|
||||||
;; Created: Feb 1992
|
;; Created: Feb 1992
|
||||||
;; Version: 3.0
|
|
||||||
;; Keywords: python languages oop
|
;; Keywords: python languages oop
|
||||||
|
|
||||||
(defconst py-version "3.0"
|
(defconst py-version "3.0"
|
||||||
|
@ -32,10 +31,10 @@
|
||||||
|
|
||||||
;; python-mode.el is currently distributed with XEmacs 19 and XEmacs
|
;; 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,
|
;; 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
|
;; but it is compatible with 19.34 and the current 20 series Emacsen.
|
||||||
;; Emacsen. By default, in XEmacs when you visit a .py file, it is
|
;; By default, in XEmacs when you visit a .py file, it is put in
|
||||||
;; put in Python mode. In Emacs, you need to add the following to
|
;; Python mode. In Emacs, you need to add the following to your
|
||||||
;; your .emacs file (you don't need this for XEmacs):
|
;; .emacs file (you don't need this for XEmacs):
|
||||||
;;
|
;;
|
||||||
;; (autoload 'python-mode "python-mode" "Python editing mode." t)
|
;; (autoload 'python-mode "python-mode" "Python editing mode." t)
|
||||||
;; (setq auto-mode-alist
|
;; (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
|
;; Python subprocess utilities and filters
|
||||||
;;;###autoload
|
(defun py-execute-file (proc filename)
|
||||||
(defun py-shell ()
|
;; Send a properly formatted execfile('FILENAME') to the underlying
|
||||||
"Start an interactive Python interpreter in another window.
|
;; Python interpreter process FILENAME. Make that process's buffer
|
||||||
This is like Shell mode, except that Python is running in the window
|
;; visible and force display. Also make comint believe the user
|
||||||
instead of a shell. See the `Interactive Shell' and `Shell Mode'
|
;; typed this string so that kill-output-from-shell does The Right
|
||||||
sections of the Emacs manual for details, especially for the key
|
;; Thing.
|
||||||
bindings active in the `*Python*' buffer.
|
(let ((curbuf (current-buffer))
|
||||||
|
(procbuf (process-buffer proc))
|
||||||
See the docs for variable `py-scroll-buffer' for info on scrolling
|
(comint-scroll-to-bottom-on-output t)
|
||||||
behavior in the process window.
|
(msg (format "## working on region in file %s...\n" filename))
|
||||||
|
(cmd (format "execfile('%s')\n" filename)))
|
||||||
Warning: Don't use an interactive Python if you change sys.ps1 or
|
(unwind-protect
|
||||||
sys.ps2 from their default values, or if you're running code that
|
(progn
|
||||||
prints `>>> ' or `... ' at the start of a line. `python-mode' can't
|
(set-buffer procbuf)
|
||||||
distinguish your output from Python's output, and assumes that `>>> '
|
(goto-char (point-max))
|
||||||
at the start of a line is a prompt from Python. Similarly, the Emacs
|
(move-marker (process-mark proc) (point))
|
||||||
Shell mode code assumes that both `>>> ' and `... ' at the start of a
|
(funcall (process-filter proc) proc msg))
|
||||||
line are Python prompts. Bad things can happen if you fool either
|
(set-buffer curbuf))
|
||||||
mode.
|
(process-send-string proc cmd)))
|
||||||
|
|
||||||
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)))
|
|
||||||
|
|
||||||
(defun py-process-filter (pyproc string)
|
(defun py-process-filter (pyproc string)
|
||||||
(let ((curbuf (current-buffer))
|
(let ((curbuf (current-buffer))
|
||||||
(pbuf (process-buffer pyproc))
|
(pbuf (process-buffer pyproc))
|
||||||
(pmark (process-mark pyproc))
|
(pmark (process-mark pyproc))
|
||||||
file-finished)
|
file-finished)
|
||||||
|
|
||||||
;; make sure we switch to a different buffer at least once. if we
|
;; 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
|
;; *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
|
;; 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))))
|
(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.
|
"Send the contents of the buffer to a Python interpreter.
|
||||||
If there is a *Python* process buffer it is used. If a clipping
|
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
|
restriction is in effect, only the accessible portion of the buffer is
|
||||||
sent. A trailing newline will be supplied if needed.
|
sent. A trailing newline will be supplied if needed.
|
||||||
|
|
||||||
See the `\\[py-execute-region]' docs for an account of some subtleties."
|
See the `\\[py-execute-region]' docs for an account of some subtleties."
|
||||||
(interactive)
|
(interactive "P")
|
||||||
(py-execute-region (point-min) (point-max)))
|
(py-execute-region (point-min) (point-max) async))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
;; Functions for Python style indentation
|
;; 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)))
|
(intern (buffer-substring (match-beginning 1) (match-end 1)))
|
||||||
nil)))
|
nil)))
|
||||||
|
|
||||||
(defun py-make-temp-name ()
|
|
||||||
(make-temp-name
|
|
||||||
(concat (file-name-as-directory py-temp-directory) "python")))
|
|
||||||
|
|
||||||
(defun py-delete-file-silently (fname)
|
(defun py-delete-file-silently (fname)
|
||||||
(condition-case nil
|
(condition-case nil
|
||||||
(delete-file fname)
|
(delete-file fname)
|
||||||
|
@ -2378,30 +2393,6 @@ local bindings to py-newline-and-indent."))
|
||||||
(py-delete-file-silently (car py-file-queue))
|
(py-delete-file-silently (car py-file-queue))
|
||||||
(setq py-file-queue (cdr 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 ()
|
(defun py-current-defun ()
|
||||||
;; tell add-log.el how to find the current function/method/variable
|
;; tell add-log.el how to find the current function/method/variable
|
||||||
(save-excursion
|
(save-excursion
|
||||||
|
|
Loading…
Reference in New Issue