changeset 33434:032684266f4b

(gud-minor-mode): New var. (gud-symbol, gud-val): New functions. (gud-find-file): Copy gud-minor-mode to the new buffer. (gud-menu-map): Include entries for commands that are not always available, using :enable to (de)activate them. (gud-minor-mode-map): New map. Add it to minor-mode-map-alist. (gud-mode-map): New map. (gud-gdb-find-file, gud-sdb-find-file, gud-dbx-find-file) (gud-xdb-find-file, gud-perldb-find-file, gud-pdb-find-file): Don't set up gud's menu (it's done by the minor-mode). (gud-minibuffer-local-map): New. Replace gdb-minibuffer-local-map and pdb-minibuffer-local-map. (gud-query-cmdline): New function. (gdb, sdb, dbx, xdb, perldb, pdb, jdb): Use it. Set gud-minor-mode. (gud-mode): Use define-derived-mode. Don't set up gud's menu (it's done by the minor-mode). (gud-chop-words): Remove. (gud-common-init): Use split-string instead. (gud-new-keymap, gud-make-debug-menu): Eradicate.
author Stefan Monnier <monnier@iro.umontreal.ca>
date Sun, 12 Nov 2000 18:48:22 +0000
parents e8794ae4f856
children 4ef19e88da9a
files lisp/gud.el
diffstat 1 files changed, 105 insertions(+), 188 deletions(-) [+]
line wrap: on
line diff
--- a/lisp/gud.el	Sun Nov 12 18:09:09 2000 +0000
+++ b/lisp/gud.el	Sun Nov 12 18:48:22 2000 +0000
@@ -68,28 +68,67 @@
 (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))
+  (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)))
 
-;; 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))
+(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.")
 
 ;; ======================================================================
 ;; command definition
@@ -171,7 +210,7 @@
 ;;
 ;; 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.
 
 ;; ======================================================================
 ;; speedbar support functions and variables.
@@ -330,40 +369,34 @@
     output))
 
 (defun gud-gdb-find-file (f)
-  (save-excursion
-    (let ((buf (find-file-noselect f 'nowarn)))
-      (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)))
+  (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)
 
-(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))
+(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)))
+  (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.")
@@ -646,27 +679,15 @@
   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)))
+  (interactive (list (gud-query-cmdline 'sdb)))
+
   (if (and gud-sdb-needs-tags
 	   (not (and (boundp 'tags-file-name)
 		     (stringp tags-file-name)
@@ -675,6 +696,7 @@
 
   (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.")
@@ -981,26 +1003,14 @@
   (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)))
+  (interactive (list (gud-query-cmdline 'dbx)))
 
   (cond
    (gud-mips-p
@@ -1016,6 +1026,8 @@
     (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.")
@@ -1123,17 +1135,7 @@
   (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)
@@ -1143,16 +1145,11 @@
 
 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)))
+  (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"
@@ -1274,11 +1271,7 @@
     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."
@@ -1291,19 +1284,12 @@
 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)))
+   (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")
@@ -1317,8 +1303,7 @@
 
   (setq comint-prompt-regexp "^  DB<+[0-9]+>+ ")
   (setq paragraph-start comint-prompt-regexp)
-  (run-hooks 'perldb-mode-hook)
-  )
+  (run-hooks 'perldb-mode-hook))
 
 ;; ======================================================================
 ;; pdb (Python debugger) functions
@@ -1395,22 +1380,7 @@
     output))
 
 (defun gud-pdb-find-file (f)
-  (save-excursion
-    (let ((buf (find-file-noselect f)))
-      (set-buffer buf)
-      (gud-make-debug-menu)
-      ;; (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 pdb-minibuffer-local-map nil
-  "Keymap for minibuffer prompting of pdb startup command.")
-(if pdb-minibuffer-local-map
-    ()
-  (setq pdb-minibuffer-local-map (copy-keymap minibuffer-local-map))
-  (define-key
-    pdb-minibuffer-local-map "\C-i" 'comint-dynamic-complete-filename))
+  (find-file-noselect f))
 
 (defcustom gud-pdb-command-name "pdb"
   "File name for executing the Python debugger.
@@ -1424,15 +1394,11 @@
 The directory containing FILE becomes the initial working directory
 and source-file directory for your debugger."
   (interactive
-   (list (read-from-minibuffer "Run pdb (like this): "
-			       (if (consp gud-pdb-history)
-				   (car gud-pdb-history)
-				 (concat gud-pdb-command-name " "))
-			       pdb-minibuffer-local-map nil
-			       'gud-pdb-history)))
+   (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")
@@ -1911,15 +1877,11 @@
 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)))
+   (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 %F:%l" "\C-b" "Set breakpoint at current line.")
   (gud-def gud-remove "clear %l" "\C-d" "Remove breakpoint at current line")
@@ -1991,7 +1953,7 @@
 
 (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,
@@ -2045,42 +2007,14 @@
 
 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.
@@ -2092,7 +2026,7 @@
 ;; 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))
+  (let* ((words (split-string command-line))
 	 (program (car words))
 	 ;; Extract the file name from WORDS
 	 ;; and put t in its place.
@@ -2145,12 +2079,11 @@
 
   (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.
@@ -2400,21 +2333,6 @@
   (or gud-last-frame (setq gud-last-frame gud-last-last-frame))
   (gud-display-frame))
 
-
-(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."
-  (use-local-map (gud-new-keymap (current-local-map)))
-  (define-key (current-local-map) [menu-bar]
-    (gud-new-keymap (lookup-key (current-local-map) [menu-bar])))
-  (define-key (current-local-map) [menu-bar debug]
-    (cons "Gud" (gud-new-keymap gud-menu-map))))
-
 ;;; 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.
 ;;;
@@ -2445,8 +2363,7 @@
       (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 ()