--- /home/weiner/id-dev/python-mode-4.1.el Wed Apr 18 08:48:25 2001 +++ /home/weiner/infodock/id-lisp/prog/python-mode.el Mon Apr 23 01:44:53 2001 @@ -8,7 +8,7 @@ ;; Created: Feb 1992 ;; Keywords: python languages oop -(defconst py-version "$Revision: 4.1 $" +(defconst py-version "$Revision: 1.1 $" "`python-mode' version number.") ;; This software is provided as-is, without express or implied @@ -324,6 +324,9 @@ ;; functions '("\\bdef[ \t]+\\([a-zA-Z_]+[a-zA-Z0-9_]*\\)" 1 font-lock-function-name-face) + ;; singly quoted `argument' names + '("`\\(\\(\\sw\\|\\*+\\)\\sw+\\)'" + 1 font-lock-reference-face prepend) )) "Additional expressions to highlight in Python mode.") (put 'python-mode 'font-lock-defaults '(python-font-lock-keywords)) @@ -450,6 +453,9 @@ (if py-mode-map nil (setq py-mode-map (make-sparse-keymap)) + ;; doc keys + ;; NOTE: pydoc.el globably binds {C-c M-h} to (pydoc-commands) + ;; so don't reuse that key in this map. ;; electric keys (define-key py-mode-map ":" 'py-electric-colon) ;; indentation level modifiers @@ -693,6 +699,8 @@ (easy-menu-define py-menu py-mode-map "Python Mode menu" '("Python" + ["PyDoc Help Commands" pydoc-commands t] + "-" ["Comment Out Region" py-comment-region (mark)] ["Uncomment Region" (py-comment-region (point) (mark) '(4)) (mark)] "-" @@ -996,7 +1004,7 @@ )) ;; Set the default shell if not already set (when (null py-which-shell) - (py-toggle-shells py-default-interpreter)) + (py-toggle-shells py-default-interpreter t)) ) @@ -1072,10 +1080,11 @@ (save-excursion (set-buffer procbuf) (goto-char (point-max)) + (funcall (process-filter proc) proc msg) (move-marker (process-mark proc) (point)) - (funcall (process-filter proc) proc msg)) - (set-buffer curbuf)) - (process-send-string proc cmd))) + (process-send-string proc cmd) + (move-marker (process-mark proc) (point))) + (set-buffer curbuf)))) (defun py-comint-output-filter-function (string) "Watch output for Python prompt and exec next file waiting in queue. @@ -1085,12 +1094,13 @@ (and (>= (length string) 5) (string-equal (substring string -5) "\n>>> "))) py-file-queue) - (py-safe (delete-file (car py-file-queue))) - (setq py-file-queue (cdr py-file-queue)) - (if py-file-queue - (let ((pyproc (get-buffer-process (current-buffer)))) - (py-execute-file pyproc (car py-file-queue)))) - )) + (let ((pyproc (get-buffer-process (current-buffer)))) + (goto-char (point-max)) + (move-marker (process-mark pyproc) (point)) + (py-safe (delete-file (car py-file-queue))) + (setq py-file-queue (cdr py-file-queue)) + (if py-file-queue + (py-execute-file pyproc (car py-file-queue)))))) (defun py-pdbtrack-overlay-arrow (activation) "Activate or de arrow at beginning-of-line in current buffer." @@ -1192,7 +1202,7 @@ (make-variable-buffer-local 'py-which-args) (make-variable-buffer-local 'py-which-bufname) -(defun py-toggle-shells (arg) +(defun py-toggle-shells (arg &optional inhibit-message-p) "Toggles between the CPython and JPython shells. With positive argument ARG (interactively \\[universal-argument]), @@ -1230,12 +1240,17 @@ msg "JPython" mode-name "JPython")) ) - (message "Using the %s shell" msg) + (unless (or noninteractive inhibit-message-p) + (message "Using the %s shell" msg)) (setq py-output-buffer (format "*%s Output*" py-which-bufname)))) + ;;;###autoload (defun py-shell (&optional argprompt) - "Start an interactive Python interpreter in another window. + "Start a Python interpreter in another window when called interactively. +When called programmatically, start the shell and make it the current buffer +temporarily (for the duration of the current command) but do not display it. + 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 @@ -1274,7 +1289,7 @@ (interactive "P") ;; Set the default shell if not already set (when (null py-which-shell) - (py-toggle-shells py-default-interpreter)) + (py-toggle-shells py-default-interpreter (not (interactive-p)))) (let ((args py-which-args)) (when (and argprompt (interactive-p) @@ -1286,8 +1301,11 @@ (concat (mapconcat 'identity py-which-args " ") " ") )))) - (switch-to-buffer-other-window - (apply 'make-comint py-which-bufname py-which-shell nil args)) + ;; When called interactively, display the shell buffer. When + ;; called programmatically, use the shell as a background process + ;; for Python code evaluation and don't display it. + (funcall (if (interactive-p) 'switch-to-buffer-other-window 'set-buffer) + (apply 'make-comint py-which-bufname py-which-shell nil args)) (make-local-variable 'comint-prompt-regexp) (setq comint-prompt-regexp "^>>> \\|^[.][.][.] \\|^(pdb) ") (add-hook 'comint-output-filter-functions @@ -1310,6 +1328,8 @@ (defun py-execute-region (start end &optional async) "Execute the region in a Python interpreter. +Return the output buffer name or nil in some cases +when there is no output. The region is first copied into a temporary file (in the directory `py-temp-directory'). If there is no Python interpreter shell @@ -1336,7 +1356,10 @@ (interactive "r\nP") (or (< start end) (error "Region is empty")) - (let* ((proc (get-process py-which-bufname)) + (let* ((proc (let ((proc (get-process py-which-bufname))) + ;; Use interactive Python buffer only if its + ;; subprocess is running. + (and proc (eq (process-status proc) 'run) proc))) (temp (if (memq 'broken-temp-names py-emacs-features) (let ((sn py-serial-number) @@ -1348,12 +1371,13 @@ (make-temp-name "python-"))) (file (expand-file-name temp py-temp-directory)) (cur (current-buffer)) - (buf (get-buffer-create file))) + (input-buf (get-buffer-create file)) + output-buf) ;; Write the contents of the buffer, watching out for indented regions. (save-excursion (goto-char start) - (let ((needs-if (/= (py-point 'bol) (py-point 'boi)))) - (set-buffer buf) + (let ((needs-if (looking-at "[ \t]"))) + (set-buffer input-buf) (when needs-if (insert "if 1:\n")) (insert-buffer-substring cur start end))) @@ -1362,15 +1386,15 @@ (async ;; User explicitly wants this to run in its own async subprocess (save-excursion - (set-buffer buf) + (set-buffer input-buf) (write-region (point-min) (point-max) file nil 'nomsg)) - (let* ((buf (generate-new-buffer-name py-output-buffer)) - ;; TBD: a horrible hack, but why create new Custom variables? + (setq output-buf (generate-new-buffer-name py-output-buffer)) + (let* (;; TBD: a horrible hack, but why create new Custom variables? (arg (if (string-equal py-which-bufname "Python") "-u" ""))) - (start-process py-which-bufname buf py-which-shell arg file) - (pop-to-buffer buf) - (py-postprocess-output-buffer buf) + (start-process py-which-bufname output-buf py-which-shell arg file) + (pop-to-buffer output-buf) + (py-postprocess-output-buffer output-buf) ;; TBD: clean up the temporary file! )) ;; if the Python interpreter shell is running, queue it up for @@ -1378,27 +1402,30 @@ (proc ;; use the existing python shell (save-excursion - (set-buffer buf) + (set-buffer input-buf) (write-region (point-min) (point-max) file nil 'nomsg)) + (setq output-buf (and (process-buffer proc) + (buffer-name (process-buffer proc)))) (if (not py-file-queue) (py-execute-file proc file) (message "File %s queued for execution" file)) (setq py-file-queue (append py-file-queue (list file))) (setq py-exception-buffer (cons file (current-buffer)))) (t - ;; TBD: a horrible hack, buy why create new Custom variables? + ;; TBD: a horrible hack, but why create new Custom variables? (let ((cmd (concat py-which-shell (if (string-equal py-which-bufname "JPython") " -" "")))) ;; otherwise either run it synchronously in a subprocess (save-excursion - (set-buffer buf) + (set-buffer input-buf) (shell-command-on-region (point-min) (point-max) cmd py-output-buffer)) ;; shell-command-on-region kills the output buffer if it never ;; existed and there's no output from the command (if (not (get-buffer py-output-buffer)) (message "No output.") + (setq output-buf py-output-buffer) (setq py-exception-buffer (current-buffer)) (let ((err-p (py-postprocess-output-buffer py-output-buffer))) (pop-to-buffer py-output-buffer) @@ -1409,7 +1436,9 @@ ) ) ;; Clean up after ourselves. - (kill-buffer buf))) + (kill-buffer input-buf) + ;; return the output buffer name + output-buf)) ;; Code execution commands @@ -1430,7 +1459,11 @@ (buffer (or (get-file-buffer filename) (find-file-noselect filename)))) (set-buffer buffer))) - (py-execute-region (point-min) (point-max) async)) + (let ((py-execute-buffer t)) + ;; Above setting used by py-execute-region's subcall of + ;; `py-jump-to-exception' to indicate that this is a full buffer + ;; and not a region for which line numbers are unavailable. + (py-execute-region (point-min) (point-max) async))) (defun py-execute-import-or-reload (&optional async) "Import the current buffer's file in a Python interpreter. @@ -1497,6 +1530,8 @@ (defun py-execute-string (string &optional async) "Send the argument STRING to a Python interpreter. +Return the output buffer name or nil in some cases +when there is no output. If there is a *Python* process buffer it is used. @@ -1504,8 +1539,15 @@ subtleties, including the use of the optional ASYNC argument." (interactive "sExecute Python command: ") (save-excursion - (set-buffer (get-buffer-create - (generate-new-buffer-name " *Python Command*"))) + ;; Reuse this buffer across calls; otherwise, too many buffers can + ;; be created. + (set-buffer (get-buffer-create " *Python Command*")) + (setq buffer-read-only nil) + (erase-buffer) + ;; Must invoke python-mode here or the `py-which-shell' variable + ;; will not be set and will trigger an error during the + ;; `py-execute-region' call. + (if (not (eq major-mode 'python-mode)) (python-mode)) (insert string) (py-execute-region (point-min) (point-max) async))) @@ -1513,25 +1555,30 @@ (defun py-jump-to-exception (file line) "Jump to the Python code in FILE at LINE." - (let ((buffer (cond ((string-equal file "") - (if (consp py-exception-buffer) - (cdr py-exception-buffer) - py-exception-buffer)) - ((and (consp py-exception-buffer) - (string-equal file (car py-exception-buffer))) - (cdr py-exception-buffer)) - ((py-safe (find-file-noselect file))) - ;; could not figure out what file the exception - ;; is pointing to, so prompt for it - (t (find-file (read-file-name "Exception file: " - nil - file t)))))) - (pop-to-buffer buffer) - ;; Force Python mode - (if (not (eq major-mode 'python-mode)) - (python-mode)) - (goto-line line) - (message "Jumping to exception in file %s on line %d" file line))) + ;; Avoid jumping to the wrong line when a subregion from the current + ;; buffer was sent for execution (since the line is improperly computed + ;; from the temporary buffer holding the region). + (unless (and (string-equal file "") + (not (and (boundp 'py-execute-buffer) py-execute-buffer))) + (let ((buffer (cond ((string-equal file "") + (if (consp py-exception-buffer) + (cdr py-exception-buffer) + py-exception-buffer)) + ((and (consp py-exception-buffer) + (string-equal file (car py-exception-buffer))) + (cdr py-exception-buffer)) + ((py-safe (find-file-noselect file))) + ;; could not figure out what file the exception + ;; is pointing to, so prompt for it + (t (find-file (read-file-name "Exception file: " + nil + file t)))))) + (pop-to-buffer buffer) + ;; Force Python mode + (if (not (eq major-mode 'python-mode)) + (python-mode)) + (goto-line line) + (message "Jumping to exception in file %s on line %d" file line)))) (defun py-mouseto-exception (event) "Jump to the code which caused the Python exception at EVENT.