summaryrefslogtreecommitdiffstats
path: root/Misc
diff options
context:
space:
mode:
authorBarry Warsaw <barry@python.org>1997-11-26 01:04:44 (GMT)
committerBarry Warsaw <barry@python.org>1997-11-26 01:04:44 (GMT)
commita0ee8cd982940e57a2df05de9be0bd16b561cb3b (patch)
treee63b3b46863df67429f813dce96963820298979c /Misc
parentee9f820cf118d2b88a74fe35b3f7e9476ea40b1b (diff)
downloadcpython-a0ee8cd982940e57a2df05de9be0bd16b561cb3b.zip
cpython-a0ee8cd982940e57a2df05de9be0bd16b561cb3b.tar.gz
cpython-a0ee8cd982940e57a2df05de9be0bd16b561cb3b.tar.bz2
Added comment about where to find details on python-mode.el, pointing
to the Web site. (py-defun-start-re, py-class-start-re): Changed to defconst. (py-traceback-line-re): Regular expression describing what traceback lines look like. (py-point): New defsubst copied from CC Mode. (py-highlight-line): Function which does the work of making a traceback line mouseable. This only works on XEmacs. Someone familar with Emacs text properties and such will have to do that port. (py-mode-map): Added C-c- bound to py-up-exception and C-c= bound to py-down-exception. Also, more concise form for mapcar. (py-mode-output-map): New keymap for the *Python Output* buffer which only has keybindings for py-mouseto-exception and py-goto-exception. All other self-insert-command's are bound to beep. This is actually bogus because the buffer should really be made read-only and the functions that insert in that buffer should bind inhibit-read-only. Also, this map should be bound to highlighted extents in a *Python* shell buffer, but this stuff hasn't been migrated into there. (py-postprocess-output-buffer): New function which extentifies the *Python Output* buffer. The bogosities are that this only runs when the synchronous process in the buffer is finished (so it doesn't work for async procs), and it should also be merged into py-process-filter so the *Python* shell gets mouseable too. (py-shell): Added C-c- and C-c= to the comint buffer's keymap. The bogosity is that py-goto-exception should also be bound, but it cannot be bound to C-cC-c (since that interferes with comint-interrupt-subjob's typical binding). Also, traceback lines aren't mouseable in this buffer. (py-execute-region): Support for traceback jumping. This really is quite a kludge, but necessary based on the way all this stuff works. There's bound to be broken interactions here. (py-jump-to-exception, py-mouseto-exception, py-goto-exception, py-find-next-exception, py-down-exception, py-up-exception): All new commands and functions to implement traceback jumping. (py-compute-indentation): Hope this change doesn't get lost in all the noise above!!!! This fixes broken non-indentation of a line when TAB is hit inside a string that isn't a multi-line string.
Diffstat (limited to 'Misc')
-rw-r--r--Misc/python-mode.el206
1 files changed, 183 insertions, 23 deletions
diff --git a/Misc/python-mode.el b/Misc/python-mode.el
index 20fc4cf..e185bca 100644
--- a/Misc/python-mode.el
+++ b/Misc/python-mode.el
@@ -27,7 +27,8 @@
;; Note: this version of python-mode.el is no longer compatible with
;; Emacs 18. For a gabazillion reasons, I highly recommend upgrading
;; to X/Emacs 19 or X/Emacs 20. For older versions of the 19 series,
-;; you may need to acquire the Custom library.
+;; you may need to acquire the Custom library. Please see
+;; <http://www.python.org/ftp/emacs/> for details.
;; 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,
@@ -344,13 +345,17 @@ Currently-active file is at the head of the list.")
;; change this, you probably have to change `py-current-defun' as
;; well. This is only used by `py-current-defun' to find the name for
;; add-log.el.
-(defvar py-defun-start-re
+(defconst py-defun-start-re
"^\\([ \t]*\\)def[ \t]+\\([a-zA-Z_0-9]+\\)\\|\\(^[a-zA-Z_0-9]+\\)[ \t]*=")
;; Regexp for finding a class name. If you change this, you probably
;; have to change `py-current-defun' as well. This is only used by
;; `py-current-defun' to find the name for add-log.el.
-(defvar py-class-start-re "^class[ \t]*\\([a-zA-Z_0-9]+\\)")
+(defconst py-class-start-re "^class[ \t]*\\([a-zA-Z_0-9]+\\)")
+
+;; Regexp that describes tracebacks
+(defconst py-traceback-line-re
+ "[ \t]+File \"\\([^\"]+\\)\", line \\([0-9]+\\), in ")
@@ -370,6 +375,43 @@ Currently-active file is at the head of the list.")
(and (boundp 'zmacs-region-stays)
(setq zmacs-region-stays t)))
+(defsubst py-point (position)
+ ;; Returns the value of point at certain commonly referenced POSITIONs.
+ ;; POSITION can be one of the following symbols:
+ ;;
+ ;; bol -- beginning of line
+ ;; eol -- end of line
+ ;; bod -- beginning of defun
+ ;; boi -- back to indentation
+ ;;
+ ;; This function does not modify point or mark.
+ (let ((here (point)))
+ (cond
+ ((eq position 'bol) (beginning-of-line))
+ ((eq position 'eol) (end-of-line))
+ ((eq position 'bod) (beginning-of-python-def-or-class))
+ ((eq position 'bob) (beginning-of-buffer))
+ ((eq position 'eob) (end-of-buffer))
+ ((eq position 'boi) (back-to-indentation))
+ (t (error "unknown buffer position requested: %s" position))
+ )
+ (prog1
+ (point)
+ (goto-char here))))
+
+(defsubst py-highlight-line (from to file line)
+ (cond
+ ((fboundp 'make-extent)
+ ;; XEmacs
+ (let ((e (make-extent from to)))
+ (set-extent-property e 'mouse-face 'highlight)
+ (set-extent-property e 'py-exc-info (cons file line))
+ (set-extent-property e 'keymap py-mode-output-map)))
+ (t
+ ;; Emacs -- Please port this!
+ )
+ ))
+
;; Major mode boilerplate
@@ -433,6 +475,8 @@ Currently-active file is at the head of the list.")
(define-key py-mode-map "\C-c\C-hm" 'py-describe-mode)
(define-key py-mode-map "\e\C-a" 'beginning-of-python-def-or-class)
(define-key py-mode-map "\e\C-e" 'end-of-python-def-or-class)
+ (define-key py-mode-map "\C-c-" 'py-up-exception)
+ (define-key py-mode-map "\C-c=" 'py-down-exception)
;; information
(define-key py-mode-map "\C-c\C-b" 'py-submit-bug-report)
(define-key py-mode-map "\C-c\C-v" 'py-version)
@@ -441,10 +485,24 @@ Currently-active file is at the head of the list.")
;; shadow global bindings for newline-and-indent w/ the py- version.
;; BAW - this is extremely bad form, but I'm not going to change it
;; for now.
- (mapcar (function (lambda (key)
- (define-key
- py-mode-map key 'py-newline-and-indent)))
- (where-is-internal 'newline-and-indent))
+ (mapcar #'(lambda (key)
+ (define-key py-mode-map key 'py-newline-and-indent))
+ (where-is-internal 'newline-and-indent))
+ )
+
+(defvar py-mode-output-map nil
+ "Keymap used in *Python Output* buffers*")
+(if py-mode-output-map
+ nil
+ (setq py-mode-output-map (make-sparse-keymap))
+ (define-key py-mode-output-map [button2] 'py-mouseto-exception)
+ (define-key py-mode-output-map "\C-c\C-c" 'py-goto-exception)
+ ;; TBD: Disable all self-inserting keys. This is bogus, we should
+ ;; really implement this as *Python Output* buffer being read-only
+ (mapcar #' (lambda (key)
+ (define-key py-mode-output-map key
+ #'(lambda () (interactive) (beep))))
+ (where-is-internal 'self-insert-command))
)
(defvar py-mode-syntax-table nil
@@ -964,9 +1022,24 @@ Electric behavior is inhibited inside a string or comment."
))
(set-buffer curbuf))))
+(defun py-postprocess-output-buffer (buf)
+ (save-excursion
+ (set-buffer buf)
+ (beginning-of-buffer)
+ (while (re-search-forward py-traceback-line-re nil t)
+ (let ((file (match-string 1))
+ (line (string-to-int (match-string 2))))
+ (py-highlight-line (py-point 'bol) (py-point 'eol) file line))
+ )))
+
;;; Subprocess commands
+;; only used when (memq 'broken-temp-names py-emacs-features)
+(defvar py-serial-number 0)
+(defvar py-exception-buffer nil)
+(defconst py-output-buffer "*Python Output*")
+
;;;###autoload
(defun py-shell ()
"Start an interactive Python interpreter in another window.
@@ -1004,9 +1077,12 @@ filter."
(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))
+ ;; set up keybindings for this subshell
+ (local-set-key [tab] 'self-insert-command)
+ (local-set-key "\C-c-" 'py-up-exception)
+ (local-set-key "\C-c=" 'py-down-exception)
+ )
-
(defun py-clear-queue ()
"Clear the queue of temporary files waiting to execute."
(interactive)
@@ -1015,9 +1091,6 @@ filter."
(setq py-file-queue nil)
(message "%d pending files de-queued." n)))
-;; only used when (memq 'broken-temp-names py-emacs-features)
-(defvar py-serial-number 0)
-
(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
@@ -1046,15 +1119,15 @@ is inserted at the end. See also the command `py-clear-queue'."
(format "python-%d" py-serial-number)
(setq py-serial-number (1+ py-serial-number)))
(make-temp-name "python")))
- (file (concat (file-name-as-directory py-temp-directory) temp))
- (outbuf "*Python Output*"))
+ (file (concat (file-name-as-directory py-temp-directory) temp)))
(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*")))
+ (let* ((buf (generate-new-buffer-name py-output-buffer)))
(start-process "Python" buf py-python-command "-u" file)
(pop-to-buffer buf)
+ (py-postprocess-output-buffer buf)
))
;; if the Python interpreter shell is running, queue it up for
;; execution there.
@@ -1063,10 +1136,13 @@ is inserted at the end. See also the command `py-clear-queue'."
(if (not py-file-queue)
(py-execute-file proc file)
(message "File %s queued for execution" file))
- (push file py-file-queue))
+ (push file py-file-queue)
+ (setq py-exception-buffer (cons file (current-buffer))))
(t
;; otherwise either run it synchronously in a subprocess
- (shell-command-on-region start end py-python-command outbuf)
+ (shell-command-on-region start end py-python-command py-output-buffer)
+ (setq py-exception-buffer (current-buffer))
+ (py-postprocess-output-buffer py-output-buffer)
))))
;; Code execution command
@@ -1080,6 +1156,90 @@ See the `\\[py-execute-region]' docs for an account of some subtleties."
(interactive "P")
(py-execute-region (point-min) (point-max) async))
+
+
+(defun py-jump-to-exception (file line)
+ (let ((buffer (cond ((string-equal file "<stdin>")
+ 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)
+ (goto-line line)
+ (message "Jumping to exception in file %s on line %d" file line)))
+
+(defun py-mouseto-exception (event)
+ (interactive "e")
+ (cond
+ ((fboundp 'event-point)
+ ;; XEmacs
+ (let* ((point (event-point event))
+ (buffer (event-buffer event))
+ (e (and point buffer (extent-at point buffer 'py-exc-info)))
+ (info (and e (extent-property e 'py-exc-info))))
+ (message "Event point: %d, info: %s" point info)
+ (and info
+ (py-jump-to-exception (car info) (cdr info)))
+ ))
+ ;; Emacs -- Please port this!
+ ))
+
+(defun py-goto-exception ()
+ "Go to the line indicated by the traceback."
+ (interactive)
+ (let (file line)
+ (save-excursion
+ (beginning-of-line)
+ (if (looking-at py-traceback-line-re)
+ (setq file (match-string 1)
+ line (string-to-int (match-string 2)))))
+ (if (not file)
+ (error "Not on a traceback line."))
+ (py-jump-to-exception file line)))
+
+(defun py-find-next-exception (start buffer searchdir errwhere)
+ ;; Go to start position in buffer, search in the specified
+ ;; direction, and jump to the exception found. If at the end of the
+ ;; exception, print error message
+ (let (file line)
+ (save-excursion
+ (set-buffer buffer)
+ (goto-char (py-point start))
+ (if (funcall searchdir py-traceback-line-re nil t)
+ (setq file (match-string 1)
+ line (string-to-int (match-string 2)))))
+ (if (and file line)
+ (py-jump-to-exception file line)
+ (error "%s of traceback" errwhere))))
+
+(defun py-down-exception (&optional bottom)
+ "Go to the next line down in the traceback.
+With optional \\[universal-argument], jump to the bottom (innermost)
+exception in the exception stack."
+ (interactive "P")
+ (let* ((proc (get-process "Python"))
+ (buffer (if proc "*Python*" py-output-buffer)))
+ (if bottom
+ (py-find-next-exception 'eob buffer 're-search-backward "Bottom")
+ (py-find-next-exception 'eol buffer 're-search-forward "Bottom"))))
+
+(defun py-up-exception (&optional top)
+ "Go to the previous line up in the traceback.
+With optional \\[universal-argument], jump to the top (outermost)
+exception in the exception stack."
+ (interactive "P")
+ (let* ((proc (get-process "Python"))
+ (buffer (if proc "*Python*" py-output-buffer)))
+ (if top
+ (py-find-next-exception 'bob buffer 're-search-forward "Top")
+ (py-find-next-exception 'boi buffer 're-search-backward "Top"))))
+
;; Electric deletion
(defun py-electric-backspace (arg)
@@ -1198,14 +1358,14 @@ the new line indented."
;; honor-block-close-p is non-nil, statements such as return, raise,
;; break, continue, and pass force one level of outdenting.
(save-excursion
- (let ((pps (parse-partial-sexp (save-excursion
- (beginning-of-python-def-or-class)
- (point))
- (point))))
+ (let* ((bod (py-point 'bod))
+ (pps (parse-partial-sexp bod (point))))
(beginning-of-line)
(cond
- ;; are we inside a string or comment?
- ((or (nth 3 pps) (nth 4 pps))
+ ;; are we inside a multi-line string or comment?
+ ((or (and (nth 3 pps)
+ (nth 3 (parse-partial-sexp bod (py-point 'boi))))
+ (nth 4 pps))
(save-excursion
(if (not py-align-multiline-strings-p) 0
;; skip back over blank & non-indenting comment lines