;; Maintainer: FSF
;; Keywords: unix, tools
-;; Copyright (C) 1992, 93, 94, 95, 96, 1998 Free Software Foundation, Inc.
+;; Copyright (C) 1992, 93, 94, 95, 96, 1998, 2000 Free Software Foundation, Inc.
;; This file is part of GNU Emacs.
(defgroup gud nil
"Grand Unified Debugger mode for gdb and other debuggers under Emacs.
-Supported debuggers include gdb, sdb, dbx, xdb, perldb, and jdb."
+Supported debuggers include gdb, sdb, dbx, xdb, perldb, pdb (Python), and jdb."
:group 'unix
:group 'tools)
(defun gud-marker-filter (&rest args)
(apply gud-marker-filter args))
+(defvar gud-minor-mode nil)
+(put 'gud-minor-mode 'permanent-local t)
+
+(defun gud-symbol (sym &optional soft minor-mode)
+ "Return the symbol used for SYM in MINOR-MODE.
+MINOR-MODE defaults to `gud-minor-mode.
+The symbol returned is `gud-<MINOR-MODE>-<SYM>'.
+If SOFT is non-nil, returns nil if the symbol doesn't already exist."
+ (unless (or minor-mode gud-minor-mode) (error "Gud internal error"))
+ (funcall (if soft 'intern-soft 'intern)
+ (format "gud-%s-%s" (or minor-mode gud-minor-mode) sym)))
+
+(defun gud-val (sym &optional minor-mode)
+ "Return the value of `gud-symbol' SYM. Default to nil."
+ (let ((sym (gud-symbol sym t minor-mode)))
+ (if (boundp sym) (symbol-value sym))))
+
(defun gud-find-file (file)
;; Don't get confused by double slashes in the name that comes from GDB.
(while (string-match "//+" file)
(setq file (replace-match "/" t t file)))
- (funcall gud-find-file file))
-
-;; Keymap definitions for menu bar entries common to all debuggers and
-;; slots for debugger-dependent ones in sensible places. (Defined here
-;; before use.)
-(defvar gud-menu-map (make-sparse-keymap "Gud") nil)
-(define-key gud-menu-map [refresh] '("Refresh" . gud-refresh))
-(define-key gud-menu-map [remove] '("Remove Breakpoint" . gud-remove))
-(define-key gud-menu-map [tbreak] nil) ; gdb, sdb and xdb
-(define-key gud-menu-map [break] '("Set Breakpoint" . gud-break))
-(define-key gud-menu-map [up] nil) ; gdb, dbx, and xdb
-(define-key gud-menu-map [down] nil) ; gdb, dbx, and xdb
-(define-key gud-menu-map [print] '("Print Expression" . gud-print))
-(define-key gud-menu-map [finish] nil) ; gdb or xdb
-(define-key gud-menu-map [stepi] '("Step Instruction" . gud-stepi))
-(define-key gud-menu-map [step] '("Step Line" . gud-step))
-(define-key gud-menu-map [next] '("Next Line" . gud-next))
-(define-key gud-menu-map [cont] '("Continue" . gud-cont))
+ (let ((minor-mode gud-minor-mode)
+ (buf (funcall gud-find-file file)))
+ (when buf
+ ;; Copy `gud-minor-mode' to the found buffer to turn on the menu.
+ (with-current-buffer buf
+ (set (make-local-variable 'gud-minor-mode) minor-mode))
+ buf)))
+
+(easy-mmode-defmap gud-menu-map
+ '(([refresh] "Refresh" . gud-refresh)
+ ([remove] "Remove Breakpoint" . gud-remove)
+ ([tbreak] menu-item "Temporary Breakpoint" gud-tbreak
+ :enable (memq gud-minor-mode '(gdb sdb xdb)))
+ ([break] "Set Breakpoint" . gud-break)
+ ([up] menu-item "Up Stack" gud-up
+ :enable (memq gud-minor-mode '(gdb dbx xdb)))
+ ([down] menu-item "Down Stack" gud-down
+ :enable (memq gud-minor-mode '(gdb dbx xdb)))
+ ([print] "Print Expression" . gud-print)
+ ([finish] menu-item "Finish Function" gud-finish
+ :enable (memq gud-minor-mode '(gdb xdb)))
+ ([stepi] "Step Instruction" . gud-stepi)
+ ([step] "Step Line" . gud-step)
+ ([next] "Next Line" . gud-next)
+ ([cont] "Continue" . gud-cont))
+ "Menu for `gud-mode'."
+ :name "Gud")
+
+(easy-mmode-defmap gud-minor-mode-map
+ `(([menu-bar debug] . ("Gud" . ,gud-menu-map)))
+ "Map used in visited files.")
+
+(let ((m (assq 'gud-minor-mode minor-mode-map-alist)))
+ (if m (setcdr m gud-minor-mode-map)
+ (push (cons 'gud-minor-mode gud-minor-mode-map) minor-mode-map-alist)))
+
+(defvar gud-mode-map
+ ;; Will inherit from comint-mode via define-derived-mode.
+ (make-sparse-keymap)
+ "`gud-mode' keymap.")
\f
;; ======================================================================
;; command definition
are interpreted specially if present. These are:
%f name (without directory) of current source file.
+ %F name (without directory or extension) of current source file.
%d directory of current source file.
%l number of current source line
%e text of the C lvalue or function-call expression surrounding point.
;;
;; The job of the find-file method is to visit and return the buffer indicated
;; by the car of gud-tag-frame. This may be a file name, a tag name, or
-;; something else. It would be good if it also copied the Gud menubar entry.
+;; something else.
\f
;; ======================================================================
;; speedbar support functions and variables.
+(eval-when-compile (require 'speedbar))
+
(defvar gud-last-speedbar-buffer nil
"The last GUD buffer used.")
"Description of the currently displayed GUD stack.
t means that there is no stack, and we are in display-file mode.")
+(defvar gud-speedbar-key-map nil
+ "Keymap used when in the buffers display mode.")
+
+(defun gud-install-speedbar-variables ()
+ "Install those variables used by speedbar to enhance gud/gdb."
+ (if gud-speedbar-key-map
+ nil
+ (setq gud-speedbar-key-map (speedbar-make-specialized-keymap))
+
+ (define-key gud-speedbar-key-map "j" 'speedbar-edit-line)
+ (define-key gud-speedbar-key-map "e" 'speedbar-edit-line)
+ (define-key gud-speedbar-key-map "\C-m" 'speedbar-edit-line)))
+
(defvar gud-speedbar-menu-items
;; Note to self. Add expand, and turn off items when not available.
'(["Jump to stack frame" speedbar-edit-line t])
"Additional menu items to add the the speedbar frame.")
+;; Make sure our special speedbar mode is loaded
+(if (featurep 'speedbar)
+ (gud-install-speedbar-variables)
+ (add-hook 'speedbar-load-hook 'gud-install-speedbar-variables))
+
(defun gud-speedbar-buttons (buffer)
"Create a speedbar display based on the current state of GUD.
If the GUD BUFFER is not running a supported debugger, then turn
'speedbar-highlight-face
(cond ((eq ff 'gud-gdb-find-file)
'gud-gdb-goto-stackframe)
- (t (error "Should never be here.")))
+ (t (error "Should never be here")))
(car frames) t))
(setq frames (cdr frames)))
; (let ((selected-frame
; (cond ((eq ff 'gud-gdb-find-file)
; (gud-gdb-selected-frame-info buffer))
-; (t (error "Should never be here."))))))
+; (t (error "Should never be here"))))))
)
(setq gud-last-speedbar-stackframe gud-last-last-frame)))
output))
(defun gud-gdb-find-file (f)
- (save-excursion
- (let ((buf (find-file-noselect f)))
- (set-buffer buf)
- (gud-make-debug-menu)
- (local-set-key [menu-bar debug tbreak]
- '("Temporary Breakpoint" . gud-tbreak))
- (local-set-key [menu-bar debug finish] '("Finish Function" . gud-finish))
- (local-set-key [menu-bar debug up] '("Up Stack" . gud-up))
- (local-set-key [menu-bar debug down] '("Down Stack" . gud-down))
- buf)))
-
-(defvar gdb-minibuffer-local-map nil
- "Keymap for minibuffer prompting of gdb startup command.")
-(if gdb-minibuffer-local-map
- ()
- (setq gdb-minibuffer-local-map (copy-keymap minibuffer-local-map))
- (define-key
- gdb-minibuffer-local-map "\C-i" 'comint-dynamic-complete-filename))
+ (find-file-noselect f 'nowarn))
+
+(easy-mmode-defmap gud-minibuffer-local-map
+ '(("\C-i" . comint-dynamic-complete-filename))
+ "Keymap for minibuffer prompting of gud startup command."
+ :inherit minibuffer-local-map)
+
+(defun gud-query-cmdline (minor-mode &optional init)
+ (let* ((hist-sym (gud-symbol 'history nil minor-mode))
+ (cmd-name (gud-val 'command-name minor-mode)))
+ (unless (boundp hist-sym) (set hist-sym nil))
+ (read-from-minibuffer
+ (format "Run %s (like this): " minor-mode)
+ (or (car-safe (symbol-value hist-sym))
+ (concat (or cmd-name (symbol-name minor-mode)) " " init))
+ gud-minibuffer-local-map nil
+ hist-sym)))
;;;###autoload
(defun gdb (command-line)
"Run gdb 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 (read-from-minibuffer "Run gdb (like this): "
- (if (consp gud-gdb-history)
- (car gud-gdb-history)
- "gdb ")
- gdb-minibuffer-local-map nil
- '(gud-gdb-history . 1))))
+ (interactive (list (gud-query-cmdline 'gdb)))
(gud-common-init command-line 'gud-gdb-massage-args
'gud-gdb-marker-filter 'gud-gdb-find-file)
+ (set (make-local-variable 'gud-minor-mode) 'gdb)
(gud-def gud-break "break %f:%l" "\C-b" "Set breakpoint at current line.")
(gud-def gud-tbreak "tbreak %f:%l" "\C-t" "Set temporary breakpoint at current line.")
available with older versions of GDB."
(interactive)
(let* ((end (point))
- (command (save-excursion
- (beginning-of-line)
- (and (looking-at comint-prompt-regexp)
- (goto-char (match-end 0)))
- (buffer-substring (point) end)))
+ (command (buffer-substring (comint-line-beginning-position) end))
command-word)
;; Find the word break. This match will always succeed.
(string-match "\\(\\`\\| \\)\\([^ ]*\\)\\'" command)
(and gud-gdb-complete-list
(string-match "^Undefined command: \"complete\""
(car gud-gdb-complete-list))
- (error "This version of GDB doesn't support the `complete' command."))
+ (error "This version of GDB doesn't support the `complete' command"))
;; Sort the list like readline.
(setq gud-gdb-complete-list
(sort gud-gdb-complete-list (function string-lessp)))
(let ((newlst nil)
(gud-gdb-fetched-stack-frame-list nil))
(gud-gdb-run-command-fetch-lines "backtrace" buffer)
- (if (string-match "No stack" (car gud-gdb-fetched-stack-frame-list))
+ (if (and (car gud-gdb-fetched-stack-frame-list)
+ (string-match "No stack" (car gud-gdb-fetched-stack-frame-list)))
;; Go into some other mode???
nil
(while gud-gdb-fetched-stack-frame-list
(let ((e (car gud-gdb-fetched-stack-frame-list))
(name nil) (num nil))
(if (not (or
- (string-match "^#\\([0-9]+\\) +[0-9a-fx]+ in \\([0-9a-zA-Z_]+\\) (" e)
- (string-match "^#\\([0-9]+\\) +\\([0-9a-zA-Z_]+\\) (" e)))
+ (string-match "^#\\([0-9]+\\) +[0-9a-fx]+ in \\([:0-9a-zA-Z_]+\\) (" e)
+ (string-match "^#\\([0-9]+\\) +\\([:0-9a-zA-Z_]+\\) (" e)))
(if (not (string-match
"at \\([-0-9a-zA-Z_.]+\\):\\([0-9]+\\)$" e))
nil
(set-buffer buffer)
(if (save-excursion
(goto-char (point-max))
- (beginning-of-line)
+ (forward-line 0)
(not (looking-at comint-prompt-regexp)))
nil
;; Much of this copied from GDB complete, but I'm grabbing the stack
string)
(defun gud-sdb-find-file (f)
- (save-excursion
- (let ((buf (if gud-sdb-needs-tags
- (find-tag-noselect f)
- (find-file-noselect f))))
- (set-buffer buf)
- (gud-make-debug-menu)
- (local-set-key [menu-bar debug tbreak] '("Temporary Breakpoint" . gud-tbreak))
- buf)))
+ (if gud-sdb-needs-tags (find-tag-noselect f) (find-file-noselect f)))
;;;###autoload
(defun sdb (command-line)
"Run sdb 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 (read-from-minibuffer "Run sdb (like this): "
- (if (consp gud-sdb-history)
- (car gud-sdb-history)
- "sdb ")
- nil nil
- '(gud-sdb-history . 1))))
+ (interactive (list (gud-query-cmdline 'sdb)))
+
(if (and gud-sdb-needs-tags
(not (and (boundp 'tags-file-name)
(stringp tags-file-name)
(file-exists-p tags-file-name))))
- (error "The sdb support requires a valid tags table to work."))
+ (error "The sdb support requires a valid tags table to work"))
(gud-common-init command-line 'gud-sdb-massage-args
'gud-sdb-marker-filter 'gud-sdb-find-file)
+ (set (make-local-variable 'gud-minor-mode) 'sdb)
(gud-def gud-break "%l b" "\C-b" "Set breakpoint at current line.")
(gud-def gud-tbreak "%l c" "\C-t" "Set temporary breakpoint at current line.")
(save-excursion
(let ((realf (gud-dbx-file-name f)))
(if realf
- (let ((buf (find-file-noselect realf)))
- (set-buffer buf)
- (gud-make-debug-menu)
- (local-set-key [menu-bar debug up] '("Up Stack" . gud-up))
- (local-set-key [menu-bar debug down] '("Down Stack" . gud-down))
- buf)
- nil))))
+ (find-file-noselect realf)))))
;;;###autoload
(defun dbx (command-line)
"Run dbx 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 (read-from-minibuffer "Run dbx (like this): "
- (if (consp gud-dbx-history)
- (car gud-dbx-history)
- "dbx ")
- nil nil
- '(gud-dbx-history . 1))))
+ (interactive (list (gud-query-cmdline 'dbx)))
(cond
(gud-mips-p
(gud-common-init command-line 'gud-dbx-massage-args
'gud-dbx-marker-filter 'gud-dbx-find-file)))
+ (set (make-local-variable 'gud-minor-mode) 'dbx)
+
(cond
(gud-mips-p
(gud-def gud-up "up %p" "<" "Up (numeric arg) stack frames.")
;; Make dbx give out the source location info that we need.
(process-send-string (get-buffer-process gud-comint-buffer)
"printf \"\032\032%1d:\",(int)$curline;file\n"))
- (gud-dbx-use-stopformat-p
- (process-send-string (get-buffer-process gud-comint-buffer)
- "set $stopformat=1\n"))
(t
(gud-def gud-up "up %p" "<" "Up (numeric arg) stack frames.")
(gud-def gud-down "down %p" ">" "Down (numeric arg) stack frames.")
(gud-def gud-break "file \"%d%f\"\nstop at %l"
- "\C-b" "Set breakpoint at current line.")))
+ "\C-b" "Set breakpoint at current line.")
+ (if gud-dbx-use-stopformat-p
+ (process-send-string (get-buffer-process gud-comint-buffer)
+ "set $stopformat=1\n"))))
(gud-def gud-remove "clear %l" "\C-d" "Remove breakpoint at current line")
(gud-def gud-step "step %p" "\C-s" "Step one line with display.")
(save-excursion
(let ((realf (gud-xdb-file-name f)))
(if realf
- (let ((buf (find-file-noselect realf)))
- (set-buffer buf)
- (gud-make-debug-menu)
- (local-set-key [menu-bar debug tbreak]
- '("Temporary Breakpoint" . gud-tbreak))
- (local-set-key [menu-bar debug finish]
- '("Finish Function" . gud-finish))
- (local-set-key [menu-bar debug up] '("Up Stack" . gud-up))
- (local-set-key [menu-bar debug down] '("Down Stack" . gud-down))
- buf)
- nil))))
+ (find-file-noselect realf)))))
;;;###autoload
(defun xdb (command-line)
You can set the variable 'gud-xdb-directories' to a list of program source
directories if your program contains sources from more than one directory."
- (interactive
- (list (read-from-minibuffer "Run xdb (like this): "
- (if (consp gud-xdb-history)
- (car gud-xdb-history)
- "xdb ")
- nil nil
- '(gud-xdb-history . 1))))
+ (interactive (list (gud-query-cmdline 'xdb)))
(gud-common-init command-line 'gud-xdb-massage-args
'gud-xdb-marker-filter 'gud-xdb-find-file)
+ (set (make-local-variable 'gud-minor-mode) 'xdb)
(gud-def gud-break "b %f:%l" "\C-b" "Set breakpoint at current line.")
(gud-def gud-tbreak "b %f:%l\\t" "\C-t"
;;; History of argument lists passed to perldb.
(defvar gud-perldb-history nil)
+;; Convert a command line as would be typed normally to run a script
+;; into one that invokes an Emacs-enabled debugging session.
+;; "-d" in inserted as the first switch, and "-emacs" is inserted where
+;; it will be $ARGV[0] (see perl5db.pl).
(defun gud-perldb-massage-args (file args)
- (cond ((equal (car args) "-e")
- (cons "-d"
- (cons (car args)
- (cons (nth 1 args)
- (cons "--" (cons "-emacs" (cdr (cdr args))))))))
- (t
- (cons "-d" (cons (car args) (cons "-emacs" (cdr args)))))))
+ (let* ((new-args (list "-d"))
+ (seen-e nil)
+ (shift (lambda ()
+ (setq new-args (cons (car args) new-args))
+ (setq args (cdr args)))))
+
+ ;; Pass all switches and -e scripts through.
+ (while (and args
+ (string-match "^-" (car args))
+ (not (equal "-" (car args)))
+ (not (equal "--" (car args))))
+ (when (equal "-e" (car args))
+ ;; -e goes with the next arg, so shift one extra.
+ (or (funcall shift)
+ ;; -e as the last arg is an error in Perl.
+ (error "No code specified for -e"))
+ (setq seen-e t))
+ (funcall shift))
+
+ (unless seen-e
+ (if (or (not args)
+ (string-match "^-" (car args)))
+ (error "Can't use stdin as the script to debug"))
+ ;; This is the program name.
+ (funcall shift))
+
+ ;; If -e specified, make sure there is a -- so -emacs is not taken
+ ;; as -e macs.
+ (if (and args (equal "--" (car args)))
+ (funcall shift)
+ (and seen-e (push "--" new-args)))
+
+ (push "-emacs" new-args)
+ (while args
+ (funcall shift))
+
+ (nreverse new-args)))
;; There's no guarantee that Emacs will hand the filter the entire
;; marker at once; it could be broken up across several strings. We
output))
(defun gud-perldb-find-file (f)
- (save-excursion
- (let ((buf (find-file-noselect f)))
- (set-buffer buf)
- (gud-make-debug-menu)
- buf)))
+ (find-file-noselect f))
(defcustom gud-perldb-command-name "perl"
"File name for executing Perl."
The directory containing FILE becomes the initial working directory
and source-file directory for your debugger."
(interactive
- (list (read-from-minibuffer "Run perldb (like this): "
- (if (consp gud-perldb-history)
- (car gud-perldb-history)
- (concat gud-perldb-command-name
- " "
- (or (buffer-file-name)
- "-e 0")
- " "))
- nil nil
- '(gud-perldb-history . 1))))
+ (list (gud-query-cmdline 'perldb
+ (concat (or (buffer-file-name) "-e 0") " "))))
(gud-common-init command-line 'gud-perldb-massage-args
'gud-perldb-marker-filter 'gud-perldb-find-file)
+ (set (make-local-variable 'gud-minor-mode) 'perldb)
(gud-def gud-break "b %l" "\C-b" "Set breakpoint at current line.")
(gud-def gud-remove "d %l" "\C-d" "Remove breakpoint at current line")
(setq comint-prompt-regexp "^ DB<+[0-9]+>+ ")
(setq paragraph-start comint-prompt-regexp)
- (run-hooks 'perldb-mode-hook)
- )
+ (run-hooks 'perldb-mode-hook))
+\f
+;; ======================================================================
+;; pdb (Python debugger) functions
+
+;;; History of argument lists passed to pdb.
+(defvar gud-pdb-history nil)
+
+(defun gud-pdb-massage-args (file args)
+ args)
+
+;; Last group is for return value, e.g. "> test.py(2)foo()->None"
+;; Either file or function name may be omitted: "> <string>(0)?()"
+(defvar gud-pdb-marker-regexp
+ "^> \\([-a-zA-Z0-9_/.]*\\|<string>\\)(\\([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 "^> ")
+
+;; 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))))
+
+ ;; 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-find-file (f)
+ (find-file-noselect f))
+
+(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)
+
+;;;###autoload
+(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 'gud-pdb-massage-args
+ 'gud-pdb-marker-filter 'gud-pdb-find-file)
+ (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 %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.")
+
+ (local-set-key [menu-bar debug finish] '("Finish Function" . gud-finish))
+ (local-set-key [menu-bar debug up] '("Up Stack" . gud-up))
+ (local-set-key [menu-bar debug down] '("Down Stack" . gud-down))
+ ;; (setq comint-prompt-regexp "^(.*pdb[+]?) *")
+ (setq comint-prompt-regexp "^(Pdb) *")
+ (setq paragraph-start comint-prompt-regexp)
+ (run-hooks 'pdb-mode-hook))
\f
;; ======================================================================
;;
;; List of Java source file directories.
(defvar gud-jdb-directories (list ".")
"*A list of directories that gud jdb should search for source code.
-The file names should be absolute, or relative to the current directory.")
+The file names should be absolute, or relative to the current
+directory.
+
+The set of .java files residing in the directories listed are
+syntactically analyzed to determine the classes they define and the
+packages in which these classes belong. In this way gud jdb maps the
+package-qualified class names output by the jdb debugger to the source
+file from which the class originated. This allows gud mode to keep
+the source code display in sync with the debugging session.")
;; List of the java source files for this debugging session.
(defvar gud-jdb-source-files nil)
+;; Association list of fully qualified class names (package + class name) and
+;; their source files.
+(defvar gud-jdb-class-source-alist nil)
+
+;; This is used to hold a source file during analysis.
+(defvar gud-jdb-analysis-buffer nil)
+
;; Return a list of java source files. PATH gives the directories in
;; which to search for files with extension EXTN. Normally EXTN is
;; given as the regular expression "\\.java$" .
(defun gud-jdb-build-source-files-list (path extn)
- (apply 'nconc (mapcar (lambda (d) (directory-files d t extn nil)) path)))
+ (apply 'nconc (mapcar (lambda (d)
+ (when (file-directory-p d)
+ (directory-files d t extn nil)))
+ path)))
;; Move point past whitespace.
(defun gud-jdb-skip-whitespace ()
;; Move point past a string literal.
(defun gud-jdb-skip-string-literal ()
(forward-char)
- (while
- (progn
- (if (eq (following-char) ?\\)
- (forward-char 2))
- (not (eq (following-char) ?\042)))
+ (while (not (cond
+ ((eq (following-char) ?\\)
+ (forward-char))
+ ((eq (following-char) ?\042))))
(forward-char))
(forward-char))
(cons c file))
(gud-jdb-analyze-source gud-jdb-analysis-buffer file)))
-;; Association list of fully qualified class names (package + class name) and
-;; their source files.
-(defvar gud-jdb-class-source-alist nil)
-
-;; This is used to hold a source file during analysis.
-(defvar gud-jdb-analysis-buffer nil)
-
;; Return an alist of fully qualified classes and the source files
;; holding their definitions. SOURCES holds a list of all the source
;; files to examine.
(defun gud-jdb-build-class-source-alist (sources)
- (setq gud-jdb-analysis-buffer (get-buffer-create "*gud-jdb-scratch*"))
+ (setq gud-jdb-analysis-buffer (get-buffer-create " *gud-jdb-scratch*"))
(prog1
(apply
'nconc
(if user-error
(progn
(kill-buffer (current-buffer))
- (error "Error: Omit whitespace between '-classpath' and it's value")))
+ (error "Error: Omit whitespace between '-classpath' and its value")))
(if args
(setq massaged-args
if there is. If the \"-classpath\" switch is given, omit all whitespace
between it and it's value."
(interactive
- (list (read-from-minibuffer "Run jdb (like this): "
- (if (consp gud-jdb-history)
- (car gud-jdb-history)
- (concat gud-jdb-command-name " "))
- nil nil
- '(gud-jdb-history . 1))))
+ (list (gud-query-cmdline 'jdb)))
(gud-common-init command-line 'gud-jdb-massage-args
'gud-jdb-marker-filter 'gud-jdb-find-file)
+ (set (make-local-variable 'gud-minor-mode) 'jdb)
- (gud-def gud-break "stop at %l" "\C-b" "Set breakpoint at current line.")
+ (gud-def gud-break "stop at %F:%l" "\C-b" "Set breakpoint at current line.")
(gud-def gud-remove "clear %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 "cont" "\C-r" "Continue with display.")
- (setq comint-prompt-regexp "^> \|^.+\[[0-9]+\] ")
+ (setq comint-prompt-regexp "^> \\|^.+\\[[0-9]+\\] ")
(setq paragraph-start comint-prompt-regexp)
(run-hooks 'jdb-mode-hook)
\f
(put 'gud-mode 'mode-class 'special)
-(defun gud-mode ()
+(define-derived-mode gud-mode comint-mode "Debugger"
"Major mode for interacting with an inferior debugger process.
You start it up with one of the commands M-x gdb, M-x sdb, M-x dbx,
Other commands for interacting with the debugger process are inherited from
comint mode, which see."
- (interactive)
- (comint-mode)
- (setq major-mode 'gud-mode)
- (setq mode-name "Debugger")
(setq mode-line-process '(":%s"))
- (use-local-map comint-mode-map)
- (gud-make-debug-menu)
(define-key (current-local-map) "\C-c\C-l" 'gud-refresh)
- (make-local-variable 'gud-last-frame)
- (setq gud-last-frame nil)
+ (set (make-local-variable 'gud-last-frame) nil)
(make-local-variable 'comint-prompt-regexp)
;; Don't put repeated commands in command history many times.
- (make-local-variable 'comint-input-ignoredups)
- (setq comint-input-ignoredups t)
+ (set (make-local-variable 'comint-input-ignoredups) t)
(make-local-variable 'paragraph-start)
- (make-local-variable 'gud-delete-prompt-marker)
- (setq gud-delete-prompt-marker (make-marker))
- (run-hooks 'gud-mode-hook))
-
-;; Chop STRING into words separated by SPC or TAB and return a list of them.
-(defun gud-chop-words (string)
- (let ((i 0) (beg 0)
- (len (length string))
- (words nil))
- (while (< i len)
- (if (memq (aref string i) '(?\t ? ))
- (progn
- (setq words (cons (substring string beg i) words)
- beg (1+ i))
- (while (and (< beg len) (memq (aref string beg) '(?\t ? )))
- (setq beg (1+ beg)))
- (setq i (1+ beg)))
- (setq i (1+ i))))
- (if (< beg len)
- (setq words (cons (substring string beg) words)))
- (nreverse words)))
+ (set (make-local-variable 'gud-delete-prompt-marker) (make-marker)))
+
+;; Cause our buffers to be displayed, by default,
+;; in the selected window.
+;;;###autoload (add-hook 'same-window-regexps "\\*gud-.*\\*\\(\\|<[0-9]+>\\)")
+
+(defcustom gud-chdir-before-run t
+ "Non-nil if GUD should `cd' to the debugged executable."
+ :group 'gud
+ :type 'boolean)
;; Perform initializations common to all debuggers.
;; The first arg is the specified command line,
;; which starts with the program to debug.
;; The other three args specify the values to use
;; for local variables in the debugger buffer.
-(defun gud-common-init (command-line massage-args marker-filter find-file)
- (let* ((words (gud-chop-words command-line))
+(defun gud-common-init (command-line massage-args marker-filter &optional find-file)
+ (let* ((words (split-string command-line))
(program (car words))
;; Extract the file name from WORDS
;; and put t in its place.
(expand-file-name file-subst)
file-subst)))
(filepart (and file-word (concat "-" (file-name-nondirectory file)))))
- (switch-to-buffer (concat "*gud" filepart "*"))
+ (pop-to-buffer (concat "*gud" filepart "*"))
;; Set default-directory to the file's directory.
(and file-word
+ gud-chdir-before-run
;; Don't set default-directory if no directory was specified.
;; In that case, either the file is found in the current directory,
;; in which case this setq is a no-op,
(gud-mode)
(make-local-variable 'gud-marker-filter)
(setq gud-marker-filter marker-filter)
- (make-local-variable 'gud-find-file)
- (setq gud-find-file find-file)
+ (if find-file (set (make-local-variable 'gud-find-file) find-file))
(set-process-filter (get-buffer-process (current-buffer)) 'gud-filter)
(set-process-sentinel (get-buffer-process (current-buffer)) 'gud-sentinel)
- (gud-set-buffer)
- )
+ (gud-set-buffer))
(defun gud-set-buffer ()
- (cond ((eq major-mode 'gud-mode)
- (setq gud-comint-buffer (current-buffer)))))
+ (when (eq major-mode 'gud-mode)
+ (setq gud-comint-buffer (current-buffer))))
(defvar gud-filter-defer-flag nil
"Non-nil means don't process anything from the debugger right now.
(if gud-filter-pending-text
(setq string (concat gud-filter-pending-text string)
gud-filter-pending-text nil))
- (save-excursion
- (set-buffer (process-buffer proc))
+
+ (with-current-buffer (process-buffer proc)
;; If we have been so requested, delete the debugger prompt.
- (if (marker-buffer gud-delete-prompt-marker)
- (progn
- (delete-region (process-mark proc) gud-delete-prompt-marker)
- (set-marker gud-delete-prompt-marker nil)))
- ;; Save the process output, checking for source file markers.
- (setq output (gud-marker-filter string))
- ;; Check for a filename-and-line number.
- ;; Don't display the specified file
- ;; unless (1) point is at or after the position where output appears
- ;; and (2) this buffer is on the screen.
- (setq process-window
- (and gud-last-frame
- (>= (point) (process-mark proc))
- (get-buffer-window (current-buffer))))
+ (save-restriction
+ (widen)
+ (if (marker-buffer gud-delete-prompt-marker)
+ (progn
+ (delete-region (process-mark proc)
+ gud-delete-prompt-marker)
+ (set-marker gud-delete-prompt-marker nil)))
+ ;; Save the process output, checking for source file markers.
+ (setq output (gud-marker-filter string))
+ ;; Check for a filename-and-line number.
+ ;; Don't display the specified file
+ ;; unless (1) point is at or after the position where output appears
+ ;; and (2) this buffer is on the screen.
+ (setq process-window
+ (and gud-last-frame
+ (>= (point) (process-mark proc))
+ (get-buffer-window (current-buffer)))))
;; Let the comint filter do the actual insertion.
;; That lets us inherit various comint features.
- (comint-output-filter proc output)))
-
- ;; Put the arrow on the source line.
- ;; This must be outside of the save-excursion
- ;; in case the source file is our current buffer.
- (if process-window
- (save-selected-window
- (select-window process-window)
- (gud-display-frame))
- ;; We have to be in the proper buffer, (process-buffer proc),
- ;; but not in a save-excursion, because that would restore point.
- (let ((old-buf (current-buffer)))
- (set-buffer (process-buffer proc))
- (unwind-protect
- (gud-display-frame)
- (set-buffer old-buf))))
+ (comint-output-filter proc output))
+
+ ;; Put the arrow on the source line.
+ ;; This must be outside of the save-excursion
+ ;; in case the source file is our current buffer.
+ (if process-window
+ (save-selected-window
+ (select-window process-window)
+ (gud-display-frame))
+ ;; We have to be in the proper buffer, (process-buffer proc),
+ ;; but not in a save-excursion, because that would restore point.
+ (let ((old-buf (current-buffer)))
+ (set-buffer (process-buffer proc))
+ (unwind-protect
+ (gud-display-frame)
+ (set-buffer old-buf)))))
;; If we deferred text that arrived during this processing,
;; handle it now.
(setq subst (file-name-nondirectory (if insource
(buffer-file-name)
(car frame)))))
+ ((eq key ?F)
+ (setq subst (file-name-sans-extension
+ (file-name-nondirectory (if insource
+ (buffer-file-name)
+ (car frame))))))
((eq key ?d)
(setq subst (file-name-directory (if insource
(buffer-file-name)
(setq subst (if insource
(save-excursion
(beginning-of-line)
- (save-restriction (widen)
- (1+ (count-lines 1 (point)))))
+ (save-restriction
+ (widen)
+ (int-to-string (1+ (count-lines 1 (point))))))
(cdr frame))))
((eq key ?e)
(setq subst (gud-find-c-expr)))
((eq key ?a)
(setq subst (gud-read-address)))
((eq key ?p)
- (setq subst (if arg (int-to-string arg) ""))))
- (setq result (concat result
- (substring str (match-beginning 1) (match-end 1))
- subst)))
+ (setq subst (if arg (int-to-string arg)))))
+ (setq result (concat result (match-string 1 str) subst)))
(setq str (substring str (match-end 2))))
;; There might be text left in STR when the loop ends.
(concat result str)))
;; Arrange for the current prompt to get deleted.
(save-excursion
(set-buffer gud-comint-buffer)
- (goto-char (process-mark proc))
- (beginning-of-line)
- (if (looking-at comint-prompt-regexp)
- (set-marker gud-delete-prompt-marker (point))))
+ (save-restriction
+ (widen)
+ (goto-char (process-mark proc))
+ (forward-line 0)
+ (if (looking-at comint-prompt-regexp)
+ (set-marker gud-delete-prompt-marker (point)))))
(process-send-string proc command)))
(defun gud-refresh (&optional arg)
(or gud-last-frame (setq gud-last-frame gud-last-last-frame))
(gud-display-frame))
\f
-
-(defun gud-new-keymap (map)
- "Return a new keymap which inherits from MAP and has name `Gud'."
- (nconc (make-sparse-keymap "Gud") map))
-
-(defun gud-make-debug-menu ()
- "Make sure the current local map has a [menu-bar debug] submap.
-If it doesn't, replace it with a new map that inherits it,
-and create such a submap in that new map."
- (if (and (current-local-map)
- (lookup-key (current-local-map) [menu-bar debug]))
- nil
- (use-local-map (gud-new-keymap (current-local-map)))
- (define-key (current-local-map) [menu-bar debug]
- (cons "Gud" (gud-new-keymap gud-menu-map)))))
-\f
;;; Code for parsing expressions out of C code. The single entry point is
;;; find-c-expr, which tries to return an lvalue expression from around point.
;;;
(setq test-expr (gud-next-expr))
(while (gud-expr-compound expr test-expr)
(setq expr (cons (car expr) (cdr test-expr)))
- (setq test-expr (gud-next-expr))
- )
+ (setq test-expr (gud-next-expr)))
(buffer-substring (car expr) (cdr expr)))))
(defun gud-innermost-expr ()