Commit e7aca521 authored by Ken Manheimer's avatar Ken Manheimer

Enhanced pdbtrack to provide for source code that's not findable by

the reported path.  (Eg, precompiled scripts with a file path suitable
for a different host, scripts actually running on a remote system or
with no valid path, like Zope through-the-web python scripts.)

On failing to find the code on the reported path, pdbtrack takes the
function name and looks through the buffers, from most to least
recent, seeking the first python-mode buffer that either is named for
the function or has a definition (def or class) for that function.  So
to get source tracking for code that's not located where the path
indicates, you put a copy of the script in a buffer, and pdbtrack will
find it.

Also, fixed a small bug so pdbtrack now properly presents the overlay
arrow when you run the pdb 'w'here command.
parent ad5e76a8
...@@ -472,7 +472,8 @@ Currently-active file is at the head of the list.") ...@@ -472,7 +472,8 @@ Currently-active file is at the head of the list.")
;; pdbtrack contants ;; pdbtrack contants
(defconst py-pdbtrack-stack-entry-regexp (defconst py-pdbtrack-stack-entry-regexp
"> \\([^(]+\\)(\\([0-9]+\\))[?a-zA-Z0-9_]+()" ; "^> \\([^(]+\\)(\\([0-9]+\\))\\([?a-zA-Z0-9_]+\\)()"
"^> \\(.*\\)(\\([0-9]+\\))\\([?a-zA-Z0-9_]+\\)()"
"Regular expression pdbtrack uses to find a stack trace entry.") "Regular expression pdbtrack uses to find a stack trace entry.")
(defconst py-pdbtrack-input-prompt "\n[(<]?pdb[>)]? " (defconst py-pdbtrack-input-prompt "\n[(<]?pdb[>)]? "
...@@ -1276,49 +1277,124 @@ Activity is disabled if the buffer-local variable ...@@ -1276,49 +1277,124 @@ Activity is disabled if the buffer-local variable
`py-pdbtrack-do-tracking-p' is nil. `py-pdbtrack-do-tracking-p' is nil.
We depend on the pdb input prompt matching `py-pdbtrack-input-prompt' We depend on the pdb input prompt matching `py-pdbtrack-input-prompt'
at the beginning of the line." at the beginning of the line.
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 remote scripts, eg, Zope's 'Script
(Python)' - put a _copy_ of the script in a python-mode buffer named
for the script and pdbtrack will find it.)"
;; Instead of trying to piece things together from partial text ;; Instead of trying to piece things together from partial text
;; (which can be almost useless depending on Emacs version), we ;; (which can be almost useless depending on Emacs version), we
;; monitor to the point where we have the next pdb prompt, and then ;; monitor to the point where we have the next pdb prompt, and then
;; check all text from comint-last-input-end to process-mark. ;; check all text from comint-last-input-end to process-mark.
;; ;;
;; KLM: It might be nice to provide an optional override, so this ;; Also, we're very conservative about clearing the overlay arrow,
;; routine could be fed debugger output strings as the text ;; to minimize residue. This means, for instance, that executing
;; argument, for deliberate application elsewhere. ;; other pdb commands wipe out the highlight. You can always do a
;; ;; 'where' (aka 'w') command to reveal the overlay arrow.
;; 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.
(let* ((origbuf (current-buffer)) (let* ((origbuf (current-buffer))
(currproc (get-buffer-process origbuf))) (currproc (get-buffer-process origbuf)))
(if (not (and currproc py-pdbtrack-do-tracking-p)) (if (not (and currproc py-pdbtrack-do-tracking-p))
(py-pdbtrack-overlay-arrow nil) (py-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 (block (buffer-substring (max comint-last-input-end
(- procmark (- procmark
py-pdbtrack-track-range)) py-pdbtrack-track-range))
procmark)) procmark))
fname lineno) target target_fname target_lineno)
(if (not (string-match (concat py-pdbtrack-input-prompt "$") block)) (if (not (string-match (concat py-pdbtrack-input-prompt "$") block))
(py-pdbtrack-overlay-arrow nil) (py-pdbtrack-overlay-arrow nil)
(if (not (string-match
(concat ".*" py-pdbtrack-stack-entry-regexp ".*") (setq target (py-pdbtrack-get-source-buffer block))
block))
(py-pdbtrack-overlay-arrow nil) (if (stringp target)
(setq fname (match-string 1 block) (message "pdbtrack: %s" target)
lineno (match-string 2 block))
(if (file-exists-p fname) (setq target_lineno (car target))
(progn (setq target_buffer (cadr target))
(find-file-other-window fname) (setq target_fname (buffer-file-name target_buffer))
(goto-line (string-to-int lineno)) (switch-to-buffer-other-window target_buffer)
(message "pdbtrack: line %s, file %s" lineno fname) (goto-line target_lineno)
(py-pdbtrack-overlay-arrow t) (message "pdbtrack: line %s, file %s" target_lineno target_fname)
(pop-to-buffer origbuf t) ) (py-pdbtrack-overlay-arrow t)
(if (= (elt fname 0) ?\<) (pop-to-buffer origbuf t)
(message "pdbtrack: (Non-file source: '%s')" fname)
(message "pdbtrack: File not found: %s" fname)) )))))
))))))) )
(defun py-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
having the named function.
If we're unable find the source code we return a string describing the
problem as best as we can determine."
(if (not (string-match py-pdbtrack-stack-entry-regexp block))
"Traceback cue not found"
(let* ((filename (match-string 1 block))
(lineno (string-to-int (match-string 2 block)))
(funcname (match-string 3 block))
funcbuffer)
(cond ((file-exists-p filename)
(list lineno (find-file-noselect filename)))
((setq funcbuffer (py-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)
(count-lines
(point-min)
(string-match "^\\([^#]\\|#[^#]\\|#$\\)"
(buffer-substring (point-min)
(point-max)
funcbuffer)))))))
(list lineno funcbuffer))
((= (elt filename 0) ?\<)
(format "(Non-file source: '%s')" filename))
(t (format "Function/file not found: %s(), %s" funcname filename)))
)
)
)
(defun py-pdbtrack-grub-for-buffer (funcname lineno)
"Find most recent buffer itself named or having function funcname.
Must have a least int(lineno) lines in it."
(let ((buffers (buffer-list))
;(buffers (list (get-buffer "workflow_do_action.py")))
curbuf
got)
(while (and buffers (not got))
(setq buf (car buffers)
buffers (cdr buffers))
(if (or (save-excursion (set-buffer buf)
(string= major-mode "python-mode"))
(and (string-match funcname (buffer-name buf))
(string-match (concat "^\\s-*\\(def\\|class\\)\\s-+"
funcname "\\s-*(")
(buffer-substring (point-min buf)
(point-max buf)
buf))))
(setq got buf)))
got))
(defun py-postprocess-output-buffer (buf) (defun py-postprocess-output-buffer (buf)
"Highlight exceptions found in BUF. "Highlight exceptions found in BUF.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment