]> code.delx.au - gnu-emacs/blobdiff - lisp/progmodes/gud.el
Fix and improve GUD Tooltip mode.
[gnu-emacs] / lisp / progmodes / gud.el
index 527bc51eef846af7b1d6960b591e2d85f0f0572d..5946e93f34deca48e7b9c922ef9f71a20cc7a8ef 100644 (file)
@@ -1,6 +1,6 @@
 ;;; gud.el --- Grand Unified Debugger mode for running GDB and other debuggers
 
-;; Copyright (C) 1992-1996, 1998, 2000-2011 Free Software Foundation, Inc.
+;; Copyright (C) 1992-1996, 1998, 2000-2012 Free Software Foundation, Inc.
 
 ;; Author: Eric S. Raymond <esr@snark.thyrsus.com>
 ;; Maintainer: FSF
@@ -37,8 +37,6 @@
 
 ;;; Code:
 
-(eval-when-compile (require 'cl)) ; for case macro
-
 (require 'comint)
 
 (defvar gdb-active-process)
 ;; GUD commands must be visible in C buffers visited by GUD
 
 (defgroup gud nil
-  "Grand Unified Debugger mode for gdb and other debuggers under Emacs.
-Supported debuggers include gdb, sdb, dbx, xdb, perldb, pdb (Python) and jdb."
+  "The \"Grand Unified Debugger\" interface.
+Supported debuggers include gdb, sdb, dbx, xdb, perldb,
+pdb (Python), and jdb."
   :group 'processes
   :group 'tools)
 
 
 (defcustom gud-key-prefix "\C-x\C-a"
   "Prefix of all GUD commands valid in C buffers."
-  :type 'string
+  :type 'key-sequence
   :group 'gud)
 
-(global-set-key (concat gud-key-prefix "\C-l") 'gud-refresh)
+(global-set-key (vconcat gud-key-prefix "\C-l") 'gud-refresh)
 (define-key ctl-x-map " " 'gud-break)  ;; backward compatibility hack
 
 (defvar gud-marker-filter nil)
@@ -103,7 +102,7 @@ If SOFT is non-nil, returns nil if the symbol doesn't already exist."
 
 (defvar gud-running nil
   "Non-nil if debugged program is running.
-Used to grey out relevant toolbar icons.")
+Used to gray out relevant toolbar icons.")
 
 (defvar gud-target-name "--unknown--"
   "The apparent name of the program being debugged in a gud buffer.")
@@ -527,10 +526,10 @@ required by the caller."
                       nil 'gdb-edit-value)
                   nil
                   (if gdb-show-changed-values
-                      (or parent (case status
-                                   (changed 'font-lock-warning-face)
-                                   (out-of-scope 'shadow)
-                                   (t t)))
+                      (or parent (pcase status
+                                   (`changed 'font-lock-warning-face)
+                                   (`out-of-scope 'shadow)
+                                   (_ t)))
                     t)
                   depth)
                (if (eq status 'out-of-scope) (setq parent 'shadow))
@@ -548,10 +547,10 @@ required by the caller."
                         nil 'gdb-edit-value)
                     nil
                     (if gdb-show-changed-values
-                        (or parent (case status
-                                     (changed 'font-lock-warning-face)
-                                     (out-of-scope 'shadow)
-                                     (t t)))
+                        (or parent (pcase status
+                                     (`changed 'font-lock-warning-face)
+                                     (`out-of-scope 'shadow)
+                                     (_ t)))
                       t)
                     depth)
                  (speedbar-make-tag-line
@@ -749,13 +748,15 @@ directory and source-file directory for your debugger."
           "Evaluate C dereferenced pointer expression at point.")
 
   ;; For debugging Emacs only.
-  (gud-def gud-pv "pv1 %e"      "\C-v" "Print the value of the lisp variable.")
+  (gud-def gud-pv "pv %e"      "\C-v" "Print the value of the lisp variable.")
 
   (gud-def gud-until  "until %l" "\C-u" "Continue to current line.")
   (gud-def gud-run    "run"     nil    "Run the program.")
 
   (add-hook 'completion-at-point-functions #'gud-gdb-completion-at-point
             nil 'local)
+  (set (make-local-variable 'gud-gdb-completion-function) 'gud-gdb-completions)
+
   (local-set-key "\C-i" 'completion-at-point)
   (setq comint-prompt-regexp "^(.*gdb[+]?) *")
   (setq paragraph-start comint-prompt-regexp)
@@ -768,6 +769,12 @@ directory and source-file directory for your debugger."
 ;; context-sensitive command completion.  We preserve that feature
 ;; in the GUD buffer by using a GDB command designed just for Emacs.
 
+(defvar gud-gdb-completion-function nil
+  "Completion function for GDB commands.
+It receives two arguments: COMMAND, the prefix for which we seek
+completion; and CONTEXT, the text before COMMAND on the line.
+It should return a list of completion strings.")
+
 ;; The completion process filter indicates when it is finished.
 (defvar gud-gdb-fetch-lines-in-progress)
 
@@ -806,28 +813,32 @@ CONTEXT is the text before COMMAND on the line."
     (and complete-list
         (string-match "^Undefined command: \"complete\"" (car complete-list))
         (error "This version of GDB doesn't support the `complete' command"))
-    ;; Sort the list like readline.
-    (setq complete-list (sort complete-list (function string-lessp)))
-    ;; Remove duplicates.
-    (let ((first complete-list)
-         (second (cdr complete-list)))
-      (while second
-       (if (string-equal (car first) (car second))
-           (setcdr first (setq second (cdr second)))
-         (setq first second
-               second (cdr second)))))
-    ;; Add a trailing single quote if there is a unique completion
-    ;; and it contains an odd number of unquoted single quotes.
-    (and (= (length complete-list) 1)
-        (let ((str (car complete-list))
-              (pos 0)
-              (count 0))
-          (while (string-match "\\([^'\\]\\|\\\\'\\)*'" str pos)
-            (setq count (1+ count)
-                  pos (match-end 0)))
-          (and (= (mod count 2) 1)
-               (setq complete-list (list (concat str "'"))))))
-    complete-list))
+    (gud-gdb-completions-1 complete-list)))
+
+;; This function is also used by `gud-gdbmi-completions'.
+(defun gud-gdb-completions-1 (complete-list)
+  ;; Sort the list like readline.
+  (setq complete-list (sort complete-list (function string-lessp)))
+  ;; Remove duplicates.
+  (let ((first complete-list)
+       (second (cdr complete-list)))
+    (while second
+      (if (string-equal (car first) (car second))
+         (setcdr first (setq second (cdr second)))
+       (setq first second
+             second (cdr second)))))
+  ;; Add a trailing single quote if there is a unique completion
+  ;; and it contains an odd number of unquoted single quotes.
+  (and (= (length complete-list) 1)
+       (let ((str (car complete-list))
+            (pos 0)
+            (count 0))
+        (while (string-match "\\([^'\\]\\|\\\\'\\)*'" str pos)
+          (setq count (1+ count)
+                pos (match-end 0)))
+        (and (= (mod count 2) 1)
+             (setq complete-list (list (concat str "'"))))))
+  complete-list)
 
 (defun gud-gdb-completion-at-point ()
   "Return the data to complete the GDB command before point."
@@ -838,7 +849,7 @@ CONTEXT is the text before COMMAND on the line."
            (point))))
     (list start end
           (completion-table-dynamic
-           (apply-partially #'gud-gdb-completions
+           (apply-partially gud-gdb-completion-function
                             (buffer-substring (comint-line-beginning-position)
                                               start))))))
 
@@ -851,11 +862,11 @@ CONTEXT is the text before COMMAND on the line."
 
 ;; The completion process filter is installed temporarily to slurp the
 ;; output of GDB up to the next prompt and build the completion list.
-(defun gud-gdb-fetch-lines-filter (string filter)
+(defun gud-gdb-fetch-lines-filter (string)
   "Filter used to read the list of lines output by a command.
 STRING is the output to filter.
-It is passed through FILTER before we look at it."
-  (setq string (funcall filter string))
+It is passed through `gud-gdb-marker-filter' before we look at it."
+  (setq string (gud-gdb-marker-filter string))
   (setq string (concat gud-gdb-fetch-lines-string string))
   (while (string-match "\n" string)
     (push (substring string gud-gdb-fetch-lines-break (match-beginning 0))
@@ -880,17 +891,6 @@ It is passed through FILTER before we look at it."
 (defvar gud-gdb-fetched-stack-frame nil
   "Stack frames we are fetching from GDB.")
 
-;(defun gud-gdb-get-scope-data (text token indent)
-;  ;; checkdoc-params: (indent)
-;  "Fetch data associated with a stack frame, and expand/contract it.
-;Data to do this is retrieved from TEXT and TOKEN."
-;  (let ((args nil) (scope nil))
-;    (gud-gdb-run-command-fetch-lines "info args")
-;
-;    (gud-gdb-run-command-fetch-lines "info local")
-;
-;    ))
-
 (defun gud-gdb-get-stackframe (buffer)
   "Extract the current stack frame out of the GUD GDB BUFFER."
   (let ((newlst nil)
@@ -934,21 +934,16 @@ It is passed through FILTER before we look at it."
 BUFFER is the current buffer which may be the GUD buffer in which to run.
 SKIP is the number of chars to skip on each line, it defaults to 0."
   (with-current-buffer gud-comint-buffer
-    (if (and (eq gud-comint-buffer buffer)
-            (save-excursion
-              (goto-char (point-max))
-              (forward-line 0)
-              (not (looking-at comint-prompt-regexp))))
-       nil
-      ;; Much of this copied from GDB complete, but I'm grabbing the stack
-      ;; frame instead.
+    (unless (and (eq gud-comint-buffer buffer)
+                (save-excursion
+                  (goto-char (point-max))
+                  (forward-line 0)
+                  (not (looking-at comint-prompt-regexp))))
       (let ((gud-gdb-fetch-lines-in-progress t)
            (gud-gdb-fetched-lines nil)
            (gud-gdb-fetch-lines-string nil)
            (gud-gdb-fetch-lines-break (or skip 0))
-           (gud-marker-filter
-            `(lambda (string)
-               (gud-gdb-fetch-lines-filter string ',gud-marker-filter))))
+           (gud-marker-filter #'gud-gdb-fetch-lines-filter))
        ;; Issue the command to GDB.
        (gud-basic-call command)
        ;; Slurp the output.
@@ -1050,7 +1045,7 @@ and source-file directory for your debugger."
 (defvar gud-dbx-history nil)
 
 (defcustom gud-dbx-directories nil
-  "*A list of directories that dbx should search for source code.
+  "A list of directories that dbx should search for source code.
 If nil, only source files in the program directory
 will be known to dbx.
 
@@ -1362,7 +1357,7 @@ and source-file directory for your debugger."
 (defvar gud-xdb-history nil)
 
 (defcustom gud-xdb-directories nil
-  "*A list of directories that xdb should search for source code.
+  "A list of directories that xdb should search for source code.
 If nil, only source files in the program directory
 will be known to xdb.
 
@@ -1650,8 +1645,8 @@ and source-file directory for your debugger."
   (gud-common-init command-line nil 'gud-pdb-marker-filter)
   (set (make-local-variable 'gud-minor-mode) 'pdb)
 
-  (gud-def gud-break  "break %f:%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-break  "break %d%f:%l"  "\C-b" "Set breakpoint at current line.")
+  (gud-def gud-remove "clear %d%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.")
@@ -1745,7 +1740,7 @@ and source-file directory for your debugger."
 ;; All the .java files in the directories in gud-jdb-directories are
 ;; syntactically analyzed each time gud jdb is invoked.  It would be
 ;; nice to keep as much information as possible between runs.  It would
-;; be really nice to analyze the files only as neccessary (when the
+;; be really nice to analyze the files only as necessary (when the
 ;; source needs to be displayed.)  I'm not sure to what extent the former
 ;; can be accomplished and I'm not sure the latter can be done at all
 ;; since I don't know of any general way to tell which .class files are
@@ -1815,7 +1810,7 @@ source file information.")
 
 ;; List of Java source file directories.
 (defvar gud-jdb-directories (list ".")
-  "*A list of directories that gud jdb should search for source code.
+  "A list of directories that gud jdb should search for source code.
 The file names should be absolute, or relative to the current
 directory.
 
@@ -1919,7 +1914,7 @@ extension EXTN.  Normally EXTN is given as the regular expression
 ;; in petticoat junction.
 (defun gud-jdb-skip-block ()
 
-  ;; Find the begining of the block.
+  ;; Find the beginning of the block.
   (while
       (not (eq (following-char) ?{))
 
@@ -1936,7 +1931,7 @@ extension EXTN.  Normally EXTN is given as the regular expression
       (gud-jdb-skip-character-literal))
      (t (forward-char))))
 
-  ;; Now at the begining of the block.
+  ;; Now at the beginning of the block.
   (forward-char)
 
   ;; Skip over the body of the block as well as the final brace.
@@ -2766,10 +2761,9 @@ Obeying it means displaying in another window the specified file and line."
                                                  (buffer-file-name)
                                                (car frame)))))
         ((eq key ?F)
-         (setq subst (file-name-sans-extension
-                      (file-name-nondirectory (if insource
-                                                  (buffer-file-name)
-                                                (car frame))))))
+         (setq subst (file-name-base (if insource
+                                          (buffer-file-name)
+                                        (car frame)))))
         ((eq key ?d)
          (setq subst (file-name-directory (if insource
                                               (buffer-file-name)
@@ -3416,13 +3410,13 @@ With arg, dereference expr if ARG is positive, otherwise do not dereference."
 
 (defun gud-tooltip-print-command (expr)
   "Return a suitable command to print the expression EXPR."
-  (case gud-minor-mode
-       (gdbmi (concat "-data-evaluate-expression " expr))
-       (dbx (concat "print " expr))
-       ((xdb pdb) (concat "p " expr))
-       (sdb (concat expr "/"))))
+  (pcase gud-minor-mode
+    (`gdbmi (concat "-data-evaluate-expression \"" expr "\""))
+    (`dbx (concat "print " expr))
+    ((or `xdb `pdb) (concat "p " expr))
+    (`sdb (concat expr "/"))))
 
-(declare-function gdb-input "gdb-mi" (item))
+(declare-function gdb-input "gdb-mi" (command handler))
 (declare-function tooltip-expr-to-print "tooltip" (event))
 (declare-function tooltip-event-buffer "tooltip" (event))
 
@@ -3462,18 +3456,21 @@ This function must return nil if it doesn't handle EVENT."
            (let ((cmd (gud-tooltip-print-command expr)))
              (when (and gud-tooltip-mode (eq gud-minor-mode 'gdb))
                (gud-tooltip-mode -1)
-               (message-box "Using GUD tooltips in this mode is unsafe\n\
+               ;; The blank before the newline is for MS-Windows,
+               ;; whose emulation of message box removes newlines and
+               ;; displays a single long line.
+               (message-box "Using GUD tooltips in this mode is unsafe \n\
 so they have been disabled."))
              (unless (null cmd) ; CMD can be nil if unknown debugger
                (if (eq gud-minor-mode 'gdbmi)
                     (if gdb-macro-info
                         (gdb-input
-                         (list (concat
-                                "server macro expand " expr "\n")
-                               `(lambda () (gdb-tooltip-print-1 ,expr))))
+                         (concat
+                         "server macro expand " expr "\n")
+                        `(lambda () (gdb-tooltip-print-1 ,expr)))
                       (gdb-input
-                       (list  (concat cmd "\n")
-                              `(lambda () (gdb-tooltip-print ,expr)))))
+                      (concat cmd "\n")
+                      `(lambda () (gdb-tooltip-print ,expr))))
                  (setq gud-tooltip-original-filter (process-filter process))
                  (set-process-filter process 'gud-tooltip-process-output)
                  (gud-basic-call cmd))