[Python-Dev] Enhancement to pdb in gud.el (original) (raw)

Nick Roberts nick at nick.uklinux.net
Sat Sep 20 11:20:50 EDT 2003


Kevin J. Butler writes:

...

After my patch: (Pdb) cl 3 Deleted breakpoint 3 at z:\work\wm\wm.py:136 (Pdb) cl wm.py:17 Deleted breakpoint 5 at z:\work\wm\wm.py:17

I've applied your patch manually to my files bdb.py and pdb.py (I have 2.2) and it appears to work. If you load the file below in Emacs (M-x eval-buffer or M-x load-file), then type M-x pdb, the debugger (with your patch) should work with breakpoint icons in the display margin. Emacs must be a version from the CVS repository to work straight away. This will also give you buttons for debugging if you turn the toolbar on (M-x tool-bar-mode).

I've tested it on GNU/Linux but it should work on Windows too if I've defined the regexp correctly.

I've just noticed that you can enable/disable breakpoints in python. In my mode for gdb, the breakpoints are greyed out when the breakpoints become disabled. I could do this for python too if these commands were changed to emit a message.

If your patches are accepted (by SF?) then I will integrate my changes into gud.el in the Emacs CVS repository.

Nick


(require 'gud)

(defun gud-sentinel (proc msg) (cond ((null (buffer-name (process-buffer proc))) ;; buffer killed ;; Stop displaying an arrow in a source file. (setq overlay-arrow-position nil) (set-process-buffer proc nil) (if (memq gud-minor-mode-type '(gdba pdb)) (gdb-reset) (gud-reset))) ((memq (process-status proc) '(signal exit)) ;; Stop displaying an arrow in a source file. (setq overlay-arrow-position nil) (with-current-buffer gud-comint-buffer (if (memq gud-minor-mode '(gdba pdb)) (gdb-reset) (gud-reset))) (let* ((obuf (current-buffer))) ;; save-excursion isn't the right thing if ;; process-buffer is current-buffer (unwind-protect (progn ;; Write something in compilation and hack its mode line, (set-buffer (process-buffer proc)) ;; Fix the mode line. (setq mode-line-process (concat ":" (symbol-name (process-status proc)))) (force-mode-line-update) (if (eobp) (insert ?\n mode-name " " msg) (save-excursion (goto-char (point-max)) (insert ?\n mode-name " " msg))) ;; If buffer and mode line will show that the process ;; is dead, we can delete it now. Otherwise it ;; will stay around until M-x list-processes. (delete-process proc)) ;; Restore old buffer, but don't restore old point ;; if obuf is the gud buffer. (set-buffer obuf))))))

(defun gdb-reset () "Exit a debugging session cleanly by killing the gdb buffers and resetting the source buffers." (dolist (buffer (buffer-list)) (if (not (eq buffer gud-comint-buffer)) (with-current-buffer buffer (if (memq gud-minor-mode '(gdba pdb)) (if (string-match "^*.+*$" (buffer-name)) (kill-buffer nil) (if (display-images-p) (remove-images (point-min) (point-max)) (gdb-remove-strings (point-min) (point-max))) (setq left-margin-width 0) (setq gud-minor-mode nil) (kill-local-variable 'tool-bar-map) (setq gud-running nil) (if (get-buffer-window (current-buffer)) (set-window-margins (get-buffer-window (current-buffer)) left-margin-width right-margin-width))))))))

(defun gdb-put-string (putstring pos) "Put string PUTSTRING in front of POS in the current buffer. PUTSTRING is displayed by putting an overlay into the current buffer with a before-string' STRING that has a display' property whose value is PUTSTRING." (let ((gdb-string "x") (buffer (current-buffer))) (let ((overlay (make-overlay pos pos buffer)) (prop (list (list 'margin 'left-margin) putstring))) (put-text-property 0 (length gdb-string) 'display prop gdb-string) (overlay-put overlay 'put-break t) (overlay-put overlay 'before-string gdb-string))))

(defun gdb-remove-strings (start end &optional buffer) "Remove strings between START and END in BUFFER. Remove only strings that were put in BUFFER with calls to `put-string'. BUFFER nil or omitted means use the current buffer." (unless buffer (setq buffer (current-buffer))) (let ((overlays (overlays-in start end))) (while overlays (let ((overlay (car overlays))) (when (overlay-get overlay 'put-break) (delete-overlay overlay))) (setq overlays (cdr overlays)))))

(defconst breakpoint-xpm-data "/* XPM */ static char magick[] = { / columns rows colors chars-per-pixel / "12 12 2 1", " c red", "+ c None", / pixels */ "++++++++++++", "+++ +++", "++ ++", "+ +", "+ +", "+ +", "+ +", "+ +", "+ +", "++ ++", "+++ +++", "++++++++++++" };" "XPM data used for breakpoint icon.")

(defconst breakpoint-enabled-pbm-data "P1 12 12", 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 0 0 0 0 0 1 1 1 1 1 1 1 1 0 0 0 1 1 1 1 1 1 1 1 1 1 0 0 1 1 1 1 1 1 1 1 1 1 0 0 1 1 1 1 1 1 1 1 1 1 0 0 1 1 1 1 1 1 1 1 1 1 0 0 1 1 1 1 1 1 1 1 1 1 0 0 1 1 1 1 1 1 1 1 1 1 0 0 0 1 1 1 1 1 1 1 1 0 0 0 0 0 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0" "PBM data used for enabled breakpoint icon.")

(defvar breakpoint-enabled-icon (find-image `((:type xpm :data ,breakpoint-xpm-data) (:type pbm :data ,breakpoint-enabled-pbm-data))) "Icon for enabled breakpoint in display margin")

;; ====================================================================== ;; pdb (Python debugger) functions

;; History of argument lists passed to pdb. (defvar gud-pdb-history nil)

;; Last group is for return value, e.g. "> test.py(2)foo()->None" ;; Either file or function name may be omitted: "> (0)?()" (defvar gud-pdb-marker-regexp "^> \([-a-zA-Z0-9_/.:\]*\|\)(\([0-9]+\))\([a-zA-Z0-9_]*\|\?\)()\(->[^\n]*\)?\n") (defvar gud-pdb-marker-regexp-file-group 1) (defvar gud-pdb-marker-regexp-line-group 2) (defvar gud-pdb-marker-regexp-fnname-group 3)

(defvar gud-pdb-marker-regexp-start "^> ")

(defvar gud-pdb-marker-regexp-breakpoint "reakpoint [0-9]+ at \(\([a-zA-Z]:\)?[^:\n]*\):\([0-9]*\)\n")

;; There's no guarantee that Emacs will hand the filter the entire ;; marker at once; it could be broken up across several strings. We ;; might even receive a big chunk with several markers in it. If we ;; receive a chunk of text which looks like it might contain the ;; beginning of a marker, we save it here between calls to the ;; filter. (defun gud-pdb-marker-filter (string) (setq gud-marker-acc (concat gud-marker-acc string)) (let ((output ""))

;; Process all the complete markers in this chunk.
(while (string-match gud-pdb-marker-regexp gud-marker-acc)
  (setq

   ;; Extract the frame position from the marker.
   gud-last-frame
   (let ((file (match-string gud-pdb-marker-regexp-file-group
             gud-marker-acc))
     (line (string-to-int
        (match-string gud-pdb-marker-regexp-line-group
              gud-marker-acc))))
 (if (string-equal file "<string>")
     gud-last-frame
   (cons file line)))

   ;; Output everything instead of the below
   output (concat output (substring gud-marker-acc 0 (match-end 0)))

;; ;; Append any text before the marker to the output we're going ;; ;; to return - we don't include the marker in this text. ;; output (concat output ;; (substring gud-marker-acc 0 (match-beginning 0))) ;; Set the accumulator to the remaining text. gud-marker-acc (substring gud-marker-acc (match-end 0))))

(if (string-match (concat "B" gud-pdb-marker-regexp-breakpoint)
          gud-marker-acc)
(let ((file (match-string 1 gud-marker-acc))
      (line (match-string 3 gud-marker-acc)))
  (gud-pdb-insert-breakpoint file line)))	 
(if (string-match (concat "Deleted b" gud-pdb-marker-regexp-breakpoint)
          gud-marker-acc) 
(let ((file (match-string 1 gud-marker-acc))
      (line (match-string 3 gud-marker-acc)))
  (gud-pdb-remove-breakpoint file line)))	 

;; Does the remaining text look like it might end with the
;; beginning of another marker?  If it does, then keep it in
;; gud-marker-acc until we receive the rest of it.	Since we
;; know the full marker regexp above failed, it's pretty simple to
;; test for marker starts.
(if (string-match gud-pdb-marker-regexp-start gud-marker-acc)
(progn
  ;; Everything before the potential marker start can be output.
  (setq output (concat output (substring gud-marker-acc
                     0 (match-beginning 0))))

  ;; Everything after, we save, to combine with later input.
  (setq gud-marker-acc
    (substring gud-marker-acc (match-beginning 0))))

  (setq output (concat output gud-marker-acc)
    gud-marker-acc ""))

output))

(defun gud-pdb-insert-breakpoint (file line) (with-current-buffer (find-file-noselect file) (save-current-buffer (set (make-local-variable 'gud-minor-mode) 'pdb) (set (make-local-variable 'tool-bar-map) gud-tool-bar-map) (setq left-margin-width 2) (if (get-buffer-window (current-buffer)) (set-window-margins (get-buffer-window (current-buffer)) left-margin-width right-margin-width))) (save-excursion (goto-line (string-to-number line)) (let ((start (progn (beginning-of-line) (- (point) 1))) (end (progn (end-of-line) (+ (point) 1)))) (if (display-images-p) (progn (remove-images start end) (put-image breakpoint-enabled-icon (+ start 1) "breakpoint icon enabled" 'left-margin)) (gdb-remove-strings start end) (gdb-put-string "B" (+ start 1)))))))

(defun gud-pdb-remove-breakpoint (file line) (with-current-buffer (find-file-noselect file) (save-excursion (goto-line (string-to-number line)) (let ((start (progn (beginning-of-line) (- (point) 1))) (end (progn (end-of-line) (+ (point) 1)))) (if (display-images-p) (remove-images start end) (gdb-remove-strings start end))))))

(defcustom gud-pdb-command-name "pdb" "File name for executing the Python debugger. This should be an executable on your path, or an absolute file name." :type 'string :group 'gud)

(defun pdb (command-line) "Run pdb on program FILE in buffer `gud-FILE'. The directory containing FILE becomes the initial working directory and source-file directory for your debugger." (interactive (list (gud-query-cmdline 'pdb)))

(gud-common-init command-line nil 'gud-pdb-marker-filter) (set (make-local-variable 'gud-minor-mode) 'pdb)

(gud-def gud-break "break %l" "\C-b" "Set breakpoint at current line.") (gud-def gud-remove "clear %f:%l" "\C-d" "Remove breakpoint at current line") (gud-def gud-step "step" "\C-s" "Step one source line with display.") (gud-def gud-next "next" "\C-n" "Step one line (skip functions).") (gud-def gud-cont "continue" "\C-r" "Continue with display.") (gud-def gud-finish "return" "\C-f" "Finish executing current function.") (gud-def gud-up "up" "<" "Up one stack frame.") (gud-def gud-down "down" ">" "Down one stack frame.") (gud-def gud-print "p %e" "\C-p" "Evaluate Python expression at point.") ;; Is this right? (gud-def gud-statement "! %e" "\C-e" "Execute Python statement at point.")

;; (setq comint-prompt-regexp "^(.*pdb[+]?) *") (setq comint-prompt-regexp "^(Pdb) *") (setq paragraph-start comint-prompt-regexp) (run-hooks 'pdb-mode-hook))



More information about the Python-Dev mailing list