# HG changeset patch # User Ken Manheimer # Date 1203632893 0 # Node ID fd85a7810d53142532caa6837d2434b4f9d197a9 # Parent a22a49c13e2bb487784d969d66cb00c3c0efd20b Revise pdbtrack functionality to incorporate advances in python-mode.el. (I'm doing this python.el checkin with some byte-compiler warnings. These warnings existed before Nick Roberts or I applied any of the pdbtrack changes, and look very clearly like preexisting, incomplete adoption of code from python-mode.el. I'm going to next look at settling those warnings, though I don't have time for a major reconciliation of the two python-mode implementations.) (python-pdbtrack-toggle-stack-tracking): Clarify docstring. (python-pdbtrack-minor-mode-string): A sign indicating that pdb tracking is happening. (python-pdbtrack-stack-entry-regexp): Better recognize stack traces. (python-pdbtrack-input-prompt): Better recognize PDB prompts. (add python-pdbtrack-track-stack-file to comint-output-filter-functions): Tracking is plugged in to all comint buffers once python.el is loaded. (python-pdbtrack-overlay-arrow): Toggle activation of `python-pdbtrack-minor-mode-string' in addition to the overlay arrow. (python-pdbtrack-track-stack-file): Use new `python-pdbtrack-get-source-buffer' for more flexible access to debugging source files. (python-pdbtrack-get-source-buffer): Identify debugging target buffer according to pdb stack trace, optionally using new `python-pdbtrack-grub-for-buffer' if file is not locally available. (python-pdbtrack-grub-for-buffer): Find most recent python-mode named buffer, or having function with indicated name. (python-shell): Remove comint-output-filter-functions hook addition, it's being done elsewhere. Wrap long line. diff -r a22a49c13e2b -r fd85a7810d53 lisp/ChangeLog --- a/lisp/ChangeLog Thu Feb 21 20:29:34 2008 +0000 +++ b/lisp/ChangeLog Thu Feb 21 22:28:13 2008 +0000 @@ -1,3 +1,30 @@ +2008-02-21 Ken Manheimer + + * python.el (python-pdbtrack-toggle-stack-tracking): Clarify + docstring. + (python-pdbtrack-minor-mode-string): A sign indicating that pdb + tracking is happening. + (python-pdbtrack-stack-entry-regexp): Better recognize stack + traces. + (python-pdbtrack-input-prompt): Better recognize PDB prompts. + (add python-pdbtrack-track-stack-file to + comint-output-filter-functions): Tracking is plugged in to all + comint buffers once python.el is loaded. + (python-pdbtrack-overlay-arrow): Toggle activation of + `python-pdbtrack-minor-mode-string' in addition to the overlay + arrow. + (python-pdbtrack-track-stack-file): Use new + `python-pdbtrack-get-source-buffer' for more flexible access to + debugging source files. + (python-pdbtrack-get-source-buffer): Identify debugging target + buffer according to pdb stack trace, optionally using new + `python-pdbtrack-grub-for-buffer' if file is not locally + available. + (python-pdbtrack-grub-for-buffer): Find most recent python-mode + named buffer, or having function with indicated name. + (python-shell): Remove comint-output-filter-functions hook + addition, it's being done elsewhere. Wrap long line. + 2008-02-21 Michael Olson * net/json.el: Install new file by Edward O'Connor. json.el is a diff -r a22a49c13e2b -r fd85a7810d53 lisp/progmodes/python.el --- a/lisp/progmodes/python.el Thu Feb 21 20:29:34 2008 +0000 +++ b/lisp/progmodes/python.el Thu Feb 21 22:28:13 2008 +0000 @@ -545,15 +545,29 @@ (defcustom python-pdbtrack-do-tracking-p t "*Controls whether the pdbtrack feature is enabled or not. + When non-nil, pdbtrack is enabled in all comint-based buffers, -e.g. shell buffers and the *Python* buffer. When using pdb to debug a -Python program, pdbtrack notices the pdb prompt and displays the -source file and line that the program is stopped at, much the same way -as gud-mode does for debugging C programs with gdb." +e.g. shell interaction buffers and the *Python* buffer. + +When using pdb to debug a Python program, pdbtrack notices the +pdb prompt and presents the line in the source file where the +program is stopped in a pop-up buffer. It's similar to what +gud-mode does for debugging C programs with gdb, but without +having to restart the program." :type 'boolean :group 'python) (make-variable-buffer-local 'python-pdbtrack-do-tracking-p) +(defcustom python-pdbtrack-minor-mode-string " PDB" + "*Minor-mode sign to be displayed when pdbtrack is active." + :type 'string + :group 'python) + +;; Add a designator to the minor mode strings +(or (assq 'python-pdbtrack-is-tracking-p minor-mode-alist) + (push '(python-pdbtrack-is-tracking-p python-pdbtrack-minor-mode-string) + minor-mode-alist)) + ;; Bind python-file-queue before installing the kill-emacs-hook. (defvar python-file-queue nil "Queue of Python temp files awaiting execution. @@ -562,10 +576,10 @@ (defvar python-pdbtrack-is-tracking-p nil) (defconst python-pdbtrack-stack-entry-regexp - "> \\([^(]+\\)(\\([0-9]+\\))[?a-zA-Z0-9_]+()" + "^> \\(.*\\)(\\([0-9]+\\))\\([?a-zA-Z0-9_]+\\)()" "Regular expression pdbtrack uses to find a stack trace entry.") -(defconst python-pdbtrack-input-prompt "\n[(<]?pdb[>)]? " +(defconst python-pdbtrack-input-prompt "\n[(<]*[Pp]db[>)]+ " "Regular expression pdbtrack uses to recognize a pdb prompt.") (defconst python-pdbtrack-track-range 10000 @@ -2375,6 +2389,10 @@ ;;;; Modes. +;; pdb tracking is alert once this file is loaded, but takes no action if +;; `python-pdbtrack-do-tracking-p' is nil. +(add-hook 'comint-output-filter-functions 'python-pdbtrack-track-stack-file) + (defvar outline-heading-end-regexp) (defvar eldoc-documentation-function) (defvar python-mode-running) ;Dynamically scoped var. @@ -2700,17 +2718,16 @@ (python-execute-file pyproc (car python-file-queue)))))) (defun python-pdbtrack-overlay-arrow (activation) - "Activate or de arrow at beginning-of-line in current buffer." - ;; This was derived/simplified from edebug-overlay-arrow - (cond (activation - (setq overlay-arrow-position (make-marker)) - (setq overlay-arrow-string "=>") - (set-marker overlay-arrow-position - (python-point 'bol) (current-buffer)) - (setq python-pdbtrack-is-tracking-p t)) - (python-pdbtrack-is-tracking-p - (setq overlay-arrow-position nil) - (setq python-pdbtrack-is-tracking-p nil)))) + "Activate or deactivate arrow at beginning-of-line in current buffer." + (if activation + (progn + (setq overlay-arrow-position (make-marker) + overlay-arrow-string "=>" + python-pdbtrack-is-tracking-p t) + (set-marker overlay-arrow-position + (python-point 'bol) (current-buffer))) + (setq overlay-arrow-position nil + python-pdbtrack-is-tracking-p nil))) (defun python-pdbtrack-track-stack-file (text) "Show the file indicated by the pdb stack entry line, in a separate window. @@ -2718,49 +2735,131 @@ Activity is disabled if the buffer-local variable `python-pdbtrack-do-tracking-p' is nil. -We depend on the pdb input prompt matching `python-pdbtrack-input-prompt' -at the beginning of the line." +We depend on the pdb input prompt being a match for +`python-pdbtrack-input-prompt'. + +If the traceback target file path is invalid, we look for the +most recently visited python-mode buffer which either has the +name of the current function or class, or which defines the +function or class. This is to provide for scripts not in the +local filesytem (e.g., Zope's 'Script \(Python)', but it's not +Zope specific). If you put a copy of the script in a buffer +named for the script and activate python-mode, then pdbtrack will +find it." ;; Instead of trying to piece things together from partial text ;; (which can be almost useless depending on Emacs version), we ;; monitor to the point where we have the next pdb prompt, and then ;; check all text from comint-last-input-end to process-mark. ;; - ;; KLM: It might be nice to provide an optional override, so this - ;; routine could be fed debugger output strings as the text - ;; argument, for deliberate application elsewhere. - ;; - ;; KLM: We're very conservative about clearing the overlay arrow, to - ;; minimize residue. This means, for instance, that executing other - ;; pdb commands wipes out the highlight. + ;; Also, we're very conservative about clearing the overlay arrow, + ;; to minimize residue. This means, for instance, that executing + ;; other pdb commands wipe out the highlight. You can always do a + ;; 'where' (aka 'w') PDB command to reveal the overlay arrow. + (let* ((origbuf (current-buffer)) (currproc (get-buffer-process origbuf))) + (if (not (and currproc python-pdbtrack-do-tracking-p)) (python-pdbtrack-overlay-arrow nil) - (let* (;(origdir default-directory) - (procmark (process-mark currproc)) + + (let* ((procmark (process-mark currproc)) (block (buffer-substring (max comint-last-input-end (- procmark python-pdbtrack-track-range)) procmark)) - fname lineno) + target target_fname target_lineno target_buffer) + (if (not (string-match (concat python-pdbtrack-input-prompt "$") block)) (python-pdbtrack-overlay-arrow nil) - (if (not (string-match - (concat ".*" python-pdbtrack-stack-entry-regexp ".*") - block)) - (python-pdbtrack-overlay-arrow nil) - (setq fname (match-string 1 block) - lineno (match-string 2 block)) - (if (file-exists-p fname) - (progn - (find-file-other-window fname) - (goto-line (string-to-number lineno)) - (message "pdbtrack: line %s, file %s" lineno fname) - (python-pdbtrack-overlay-arrow t) - (pop-to-buffer origbuf t) ) - (if (= (elt fname 0) ?\<) - (message "pdbtrack: (Non-file source: '%s')" fname) - (message "pdbtrack: File not found: %s" fname))))))))) + + (setq target (python-pdbtrack-get-source-buffer block)) + + (if (stringp target) + (progn + (python-pdbtrack-overlay-arrow nil) + (message "pdbtrack: %s" target)) + + (setq target_lineno (car target) + target_buffer (cadr target) + target_fname (buffer-file-name target_buffer)) + (switch-to-buffer-other-window target_buffer) + (goto-line target_lineno) + (message "pdbtrack: line %s, file %s" target_lineno target_fname) + (python-pdbtrack-overlay-arrow t) + (pop-to-buffer origbuf t) + ;; in large shell buffers, above stuff may cause point to lag output + (goto-char procmark) + ))))) + ) + +(defun python-pdbtrack-get-source-buffer (block) + "Return line number and buffer of code indicated by block's traceback text. + +We look first to visit the file indicated in the trace. + +Failing that, we look for the most recently visited python-mode buffer +with the same name or having the named function. + +If we're unable find the source code we return a string describing the +problem." + + (if (not (string-match python-pdbtrack-stack-entry-regexp block)) + + "Traceback cue not found" + + (let* ((filename (match-string 1 block)) + (lineno (string-to-number (match-string 2 block))) + (funcname (match-string 3 block)) + funcbuffer) + + (cond ((file-exists-p filename) + (list lineno (find-file-noselect filename))) + + ((setq funcbuffer (python-pdbtrack-grub-for-buffer funcname lineno)) + (if (string-match "/Script (Python)$" filename) + ;; Add in number of lines for leading '##' comments: + (setq lineno + (+ lineno + (save-excursion + (set-buffer funcbuffer) + (if (equal (point-min)(point-max)) + 0 + (count-lines + (point-min) + (max (point-min) + (string-match "^\\([^#]\\|#[^#]\\|#$\\)" + (buffer-substring + (point-min) (point-max))) + ))))))) + (list lineno funcbuffer)) + + ((= (elt filename 0) ?\<) + (format "(Non-file source: '%s')" filename)) + + (t (format "Not found: %s(), %s" funcname filename))) + ) + ) + ) + +(defun python-pdbtrack-grub-for-buffer (funcname lineno) + "Find recent python-mode buffer named, or having function named funcname." + (let ((buffers (buffer-list)) + buf + got) + (while (and buffers (not got)) + (setq buf (car buffers) + buffers (cdr buffers)) + (if (and (save-excursion (set-buffer buf) + (string= major-mode "python-mode")) + (or (string-match funcname (buffer-name buf)) + (string-match (concat "^\\s-*\\(def\\|class\\)\\s-+" + funcname "\\s-*(") + (save-excursion + (set-buffer buf) + (buffer-substring (point-min) + (point-max)))))) + (setq got buf))) + got)) (defun python-toggle-shells (arg) "Toggles between the CPython and JPython shells. @@ -2857,14 +2956,12 @@ (switch-to-buffer-other-window (apply 'make-comint python-which-bufname python-which-shell nil args)) (make-local-variable 'comint-prompt-regexp) - (set-process-sentinel (get-buffer-process (current-buffer)) 'python-sentinel) + (set-process-sentinel (get-buffer-process (current-buffer)) + 'python-sentinel) (setq comint-prompt-regexp "^>>> \\|^[.][.][.] \\|^(pdb) ") (add-hook 'comint-output-filter-functions 'python-comint-output-filter-function nil t) ;; pdbtrack - (add-hook 'comint-output-filter-functions - 'python-pdbtrack-track-stack-file nil t) - (setq python-pdbtrack-do-tracking-p t) (set-syntax-table python-mode-syntax-table) (use-local-map python-shell-map)))