/ emacs.d / rdebug.el
rdebug.el
  1  ;;  This file adds support for ruby-debug (rdebug) in Emacs.
  2  ;;  Copyright (C) 2007 Martin Nordholts <enselic@gmail.com>
  3  ;;
  4  ;;  This file is based on 'rubydb3x.el' that comes with Ruby which is
  5  ;;  Copyright (C) Yukihiro Matsumoto aka Matz
  6  ;;
  7  ;;  Installation:
  8  ;;  -------------
  9  ;;
 10  ;;    1.  Make sure you have ruby-debug on your system (test by running
 11  ;;        the commmand 'rdebug -v' in a shell).
 12  ;;
 13  ;;    2.  Copy this file into e.g. ~/.elisp and make sure this is in
 14  ;;        your ~/.emacs:
 15  ;;
 16  ;;          (add-to-list 'load-path "~/.elisp")
 17  ;;          (load-library "rdebug")
 18  ;;
 19  ;;        you can then start the debugger with M-x rdebug
 20  ;;
 21  ;;    3.  Setup convenient keybindings etc. This is what I have:
 22  ;;
 23  ;;          (global-set-key [f9] 'gud-step)
 24  ;;          (global-set-key [f10] 'gud-next)
 25  ;;          (global-set-key [f11] 'gud-cont)
 26  ;;
 27  ;;          (global-set-key "\C-c\C-d" 'rdebug)
 28  ;;
 29  ;;    4. Debug like crazy!
 30  ;;
 31  ;;  Bugs:
 32  ;;  -----
 33  ;;
 34  ;;    Basic functionality works fine, though there might be a bug hiding somewhere.
 35  
 36  (require 'gud)
 37  (provide 'rdebug)
 38  
 39  ;; ======================================================================
 40  ;; rdebug functions
 41  
 42  ;;; History of argument lists passed to rdebug.
 43  (defvar gud-rdebug-history nil)
 44  
 45  (if (fboundp 'gud-overload-functions)
 46      (defun gud-rdebug-massage-args (file args)
 47        (cons file args))
 48    (defun gud-rdebug-massage-args (file args)
 49      args))
 50  
 51  ;; There's no guarantee that Emacs will hand the filter the entire
 52  ;; marker at once; it could be broken up across several strings.  We
 53  ;; might even receive a big chunk with several markers in it.  If we
 54  ;; receive a chunk of text which looks like it might contain the
 55  ;; beginning of a marker, we save it here between calls to the
 56  ;; filter.
 57  (defvar gud-rdebug-marker-acc "")
 58  (make-variable-buffer-local 'gud-rdebug-marker-acc)
 59  
 60  (defun gud-rdebug-marker-filter (string)
 61    (setq gud-rdebug-marker-acc (concat gud-rdebug-marker-acc string))
 62    (let ((output ""))
 63  
 64      ;; Process all the complete markers in this chunk.
 65      (while (string-match "\\([^:\n]*\\):\\([0-9]+\\):.*\n"
 66  			 gud-rdebug-marker-acc)
 67        (setq
 68  
 69         ;; Extract the frame position from the marker.
 70         gud-last-frame
 71         (cons (substring gud-rdebug-marker-acc (match-beginning 1) (match-end 1))
 72  	     (string-to-int (substring gud-rdebug-marker-acc
 73  				       (match-beginning 2)
 74  				       (match-end 2))))
 75  
 76  
 77         ;; Append any text before the marker to the output we're going
 78         ;; to return - we don't include the marker in this text.
 79         output (concat output
 80  		      (substring gud-rdebug-marker-acc 0 (match-beginning 0)))
 81         
 82         ;; Set the accumulator to the remaining text.
 83         gud-rdebug-marker-acc (substring gud-rdebug-marker-acc (match-end 0))))
 84      
 85      (setq output (concat output gud-rdebug-marker-acc)
 86  	  gud-rdebug-marker-acc "")
 87      
 88      output))
 89  
 90  (defun gud-rdebug-find-file (f)
 91    (save-excursion
 92      (let ((buf (find-file-noselect f)))
 93        (set-buffer buf)
 94  ;;      (gud-make-debug-menu)
 95        buf)))
 96  
 97  (defvar rdebug-command-name "rdebug"
 98    "File name for executing rdebug.")
 99  
100  ;;;###autoload
101  (defun rdebug (command-line)
102    "Run rdebug on program FILE in buffer *gud-FILE*.
103  The directory containing FILE becomes the initial working directory
104  and source-file directory for your debugger."
105    (interactive
106     (list (read-from-minibuffer "Run rdebug (like this): "
107  			       (if (consp gud-rdebug-history)
108  				   (car gud-rdebug-history)
109  				 (concat rdebug-command-name " "))
110  			       nil nil
111  			       '(gud-rdebug-history . 1))))
112    
113    (if (not (fboundp 'gud-overload-functions))
114        (gud-common-init command-line 'gud-rdebug-massage-args
115  		       'gud-rdebug-marker-filter 'gud-rdebug-find-file)
116      (gud-overload-functions '((gud-massage-args . gud-rdebug-massage-args)
117  			      (gud-marker-filter . gud-rdebug-marker-filter)
118  			      (gud-find-file . gud-rdebug-find-file)))
119      (gud-common-init command-line rdebug-command-name))
120    
121    (gud-def gud-break  "break %d%f:%l"   "\C-b" "Set breakpoint at current line in current file.")
122  ;  (gud-def gud-remove "delete %d%f:%l"  "\C-d" "Remove breakpoint at current line in current file.")
123    (gud-def gud-step   "step"            "\C-s" "Step one source line with display.")
124    (gud-def gud-next   "next"            "\C-n" "Step one line (skip functions).")
125    (gud-def gud-cont   "cont"            "\C-r" "Continue with display.")
126    (gud-def gud-finish "finish"          "\C-f" "Finish executing current function.")
127    (gud-def gud-up     "up %p"           "<" "Up N stack frames (numeric arg).")
128    (gud-def gud-down   "down %p"         ">" "Down N stack frames (numeric arg).")
129    (gud-def gud-print  "p %e"            "\C-p" "Evaluate ruby expression at point.")
130  
131    (setq comint-prompt-regexp "^(rdb:-) ")
132    (if (boundp 'comint-last-output-start)
133        (set-marker comint-last-output-start (point)))
134    (set (make-local-variable 'paragraph-start) comint-prompt-regexp)
135    (run-hooks 'rdebug-mode-hook)
136    )