--- /dev/null
+/*.elc
+/*~
+/COPYING
+/INSTALL
+/Makefile
+/Makefile.in
+/aclocal.m4
+/autom4te.cache
+/config.log
+/config.status
+/configure
+/elc-stamp
+/elc-temp
+/elisp-comp
+/install-sh
+/missing
--- /dev/null
+rockyb@rubyforge.org
--- /dev/null
+lisp_files := $(wildcard *.el)
+test_files := $(wildcard test/test-*.el)
+
+EXTRA_DIST = $(lisp_files) $(test_files) test/behave.el
+
+CHECK_FILES = $(notdir $(test_files:.el=.run))
+
+if INSTALL_EMACS_LISP
+lisp_LISP = $(lisp_files)
+
+check: $(CHECK_FILES)
+
+
+# FIGURE out how to DRY the run rules.
+test-core.run:
+ (cd $(srcdir)/test && $(EMACS) -batch -Q -l $(@:.run=.el) )
+test-file.run:
+ (cd $(srcdir)/test && $(EMACS) -batch -Q -l $(@:.run=.el) )
+test-loc.run:
+ (cd $(srcdir)/test && $(EMACS) -batch -Q -l $(@:.run=.el) )
+test-lochist.run:
+ (cd $(srcdir)/test && $(EMACS) -batch -Q -l $(@:.run=.el) )
+test-regexp.run:
+ (cd $(srcdir)/test && $(EMACS) -batch -Q -l $(@:.run=.el) )
+test-regexp2.run:
+ (cd $(srcdir)/test && $(EMACS) -batch -Q -l $(@:.run=.el) )
+test-track.run:
+ (cd $(srcdir)/test && $(EMACS) -batch -Q -l $(@:.run=.el) )
+
+endif
+
+.PHONY: $(CHECK_FILES)
+
+if MAINTAINER_MODE
+
+CL = ChangeLog
+ChangeLog:
+ git log --pretty --numstat --summary | $(GIT2CL) > $@
+
+ACLOCAL_AMFLAGS=-I .
+
+endif
+
+test: check
+
+
+
+
--- /dev/null
+Here we have code to facilitate rbdbgr-Emacs interaction.
--- /dev/null
+AC_INIT(rbdbgr-emacs, 0.01vc,)
+AC_CONFIG_SRCDIR(rbdbg-loc.el)
+AM_INIT_AUTOMAKE
+AM_MAINTAINER_MODE
+
+##
+## Find out where to install the debugger emacs lisp files
+##
+AM_PATH_LISPDIR
+AM_CONDITIONAL(INSTALL_EMACS_LISP, test "x$lispdir" != "x")
+
+AC_CONFIG_FILES([Makefile])
+AC_OUTPUT
--- /dev/null
+; Should dbgr-file-loc-from-line be here or elsewhere?
+
+(defun dbgr-directory ()
+ "The directory of this file, or nil."
+ (let ((file-name (or load-file-name
+ (symbol-file 'dbgr-directory))))
+ (if file-name
+ (file-name-directory file-name)
+ nil)))
+
+(eval-when-compile (require 'cl)
+
+(setq load-path (cons (dbgr-directory) load-path))
+(load "dbgr-loc")
+(setq load-path (cdr load-path)))
+
+
+(defun dbgr-file-line-count(filename)
+ "Return the number of lines in file FILENAME, or nil FILENAME can't be
+found"
+ (lexical-let ((saved-buffer (current-buffer))
+ (result nil))
+ (if (file-exists-p filename)
+ (progn (find-file filename)
+ (setq result (line-number-at-pos (point-max)))))
+ (switch-to-buffer saved-buffer)
+ result))
+
+(defun dbgr-file-loc-from-line(filename line-number)
+ "Return a dbgr-loc for FILENAME and LINE-NUMBER
+
+If we're unable find the source code we return a string describing the
+problem as best as we can determine."
+
+ (if (file-exists-p filename)
+ (if (integerp line-number)
+ (if (> line-number 0)
+ (lexical-let ((line-count))
+ (if (setq line-count (dbgr-file-line-count filename))
+ (if (> line-count line-number)
+ ; And you thought we'd never get around to
+ ; doing something other than validation?
+ (make-dbgr-loc :filename filename
+ :line-number line-number
+ :marker (make-marker))
+ (format "File %s has only %d lines. (Line %d requested.)"
+ filename line-count line-number))
+ (format "Problem getting line count for file `%s'" filename)))
+ (format "line number %s should be greater than 0" line-number))
+ (format "%s is not an integer" line-number))
+ (format "File named `%s' not found" filename)))
+
+(provide 'dbgr-file)
+
--- /dev/null
+(eval-when-compile (require 'cl))
+
+(defun dbgr-directory ()
+ "The directory of this file, or nil."
+ (let ((file-name (or load-file-name
+ (symbol-file 'dbgr-directory)
+ (buffer-file-name (current-buffer))
+ )))
+ (if file-name
+ (expand-file-name (file-name-directory file-name))
+ nil)))
+
+(defun dbgr-require-relative (filename-list &optional source-first)
+ "load FILENAME relative to `dbgr-directory' if FILENAME is
+already loaded it is reloaded. FILENAME can also be a list of
+strings in which case each element is loaded. Suffixes '.el' and
+'.elc' are automatically appended to filenames. If optional
+argument SOURCE-FILE is t, then we prefer the source source file
+over a compiled name."
+ (if (not (listp filename-list)) (setq filename-list (list filename-list)))
+ (loop for filename in filename-list do
+ (lexical-let* ((ext (file-name-extension filename))
+ (file-name-short
+ (expand-file-name (concat (dbgr-directory) filename)))
+ (first-filename file-name-short)
+ (el (concat file-name-short ".el"))
+ (elc (concat file-name-short ".elc"))
+ file-list ret-value)
+ (cond ((equal ext "el")
+ (setq first-filename file-name-short)
+ (setq el nil))
+ ((equal ext "elc")
+ (setq first-filename file-name-short)
+ (setq elc nil)))
+
+ (if source-first
+ (setq file-list (list first-filename el elc))
+ (setq file-list (list first-filename elc el)))
+ (loop for filename in file-list do
+ (if (and filename (file-readable-p filename))
+ (progn
+ (load filename)
+ (setq ret-value t)
+ (return))
+ ))
+ ret-value)
+ ))
+
+(defun dbgr-load-all-files()
+ (lexical-let ((file-list '("dbgr-regexp" "dbgr-procbuf-var"
+ "dbgr-loc" "dbgr-lochist" "dbgr-file"
+ "dbgr-window" "dbgr-track" "dbgr-track-mode"))
+ (filename)
+ (full-filename))
+ (setq load-path (cons (dbgr-directory) load-path))
+ (loop for filename in file-list do
+ ;; We always want the source for now
+ (setq full-filename (format "%s%s.el" (dbgr-directory) filename))
+ (message "Rocky is loading %s" full-filename)
+ (load-file full-filename))
+ (setq load-path (cdr load-path))
+ ))
+
+(provide 'dbgr-load)
--- /dev/null
+;;; dbgr-locr.el --- Debugger location
+;;; Commentary:
+
+;; This describes a debugger location structure and has code for
+;; working with them.
+
+(eval-when-compile (require 'cl))
+
+(defstruct dbgr-loc
+"Our own location type. Even though a mark contains a
+file-name (via a buffer) and a line number (via an offset), we
+want to save the values that were seen/requested originally."
+ (filename :type string)
+ (line-number :type integer)
+ (marker :type marker))
+
+(defalias 'dbgr-loc? 'dbgr-loc-p)
+
+(defun dbgr-loc-current()
+ "Create a location object for the point in the current buffer."
+ (make-dbgr-loc :filename (buffer-file-name (current-buffer))
+ :line-number (line-number-at-pos)
+ :marker (point-marker)))
+
+(defun dbgr-loc-marker=(loc marker)
+ (setf (dbgr-loc-marker loc) marker))
+
+(defun dbgr-loc-goto(loc &optional window-fn &rest args)
+ "Goto the LOC which may involve switching buffers and moving
+the point to the places indicated by LOC. In the process, the buffer
+and marker inside loc may be updated. If WINDOW-FN and ARGS are given,
+WINDOW-FN is called before switching buffers"
+ (if (dbgr-loc-p loc)
+ (lexical-let* ((filename (dbgr-loc-filename loc))
+ (line-number (dbgr-loc-line-number loc))
+ (marker (dbgr-loc-marker loc))
+ (buffer (marker-buffer (or marker (make-marker)))))
+ (if (not buffer)
+ (setq buffer (find-file-noselect filename)))
+ (if buffer
+ (progn
+ (if window-fn (apply window-fn args))
+ (switch-to-buffer buffer)
+ (if (and marker (marker-position marker))
+ (goto-char (marker-position marker))
+ (progn
+ (goto-char (point-min))
+ (forward-line (- line-number 1))
+ (dbgr-loc-marker= loc (point-marker))))))
+ )))
+
+(provide 'dbgr-loc)
--- /dev/null
+;;; dbgr-locring.el --- Debugger location ring
+;;; Commentary:
+
+;; This file manages a ring of (recently stopped) positions to allow
+;; the programmer to move between them.
+
+
+;;; Code:
+
+(require 'ring)
+(eval-when-compile
+ (require 'cl)
+ (setq load-path (cons nil (cons ".." load-path)))
+ (load "dbgr-loc")
+ (setq load-path (cddr load-path)))
+
+
+(defcustom dbgr-loc-hist-size 10 ; For testing. Should really be larger.
+ "Size of dbgr position history ring"
+ :type 'integer
+ :group 'dbgr)
+
+(defstruct dbgr-loc-hist
+ "A list of source-code positions recently encountered"
+ (position -1 :type integer)
+ (ring (make-ring dbgr-loc-hist-size) :type (type-of make-ring 0)))
+
+(defun dbgr-loc-hist-item-at(loc-hist position)
+ "Get the current item stored at POSITION of the ring
+component in LOC-HIST"
+ (lexical-let ((ring (dbgr-loc-hist-ring loc-hist)))
+ (if (ring-empty-p ring)
+ nil
+ (ring-ref ring position))))
+
+(defun dbgr-loc-hist-item(loc-hist)
+ "Get the current item of LOC-HIST at the position previously set"
+ (dbgr-loc-hist-item-at
+ loc-hist
+ (dbgr-loc-hist-position loc-hist)))
+
+(defun dbgr-loc-hist-add(loc-hist item)
+ "Add FRAME to LOC-HIST"
+ ;; Switching frames shouldn't save a new ring
+ ;; position. Also make sure no position is different.
+ ;; Perhaps duplicates should be controlled by an option.
+ (lexical-let* ((ring (dbgr-loc-hist-ring loc-hist))
+ (head (car ring)))
+ (unless (equal (dbgr-loc-hist-item loc-hist) item)
+ (setf (dbgr-loc-hist-position loc-hist) (- head 1))
+ (ring-insert-at-beginning ring item))))
+
+(defun dbgr-loc-hist-clear(loc-hist)
+ "Clear out all source locations in LOC-HIST"
+ (lexical-let* ((ring (ring-ref (dbgr-loc-hist-ring loc-hist)
+ (dbgr-loc-hist-position loc-hist)))
+ (head (car ring)))
+ (setf (dbgr-loc-hist-position loc-hist) (- head 1))
+ (while (not (ring-empty-p ring))
+ (ring-remove ring))))
+
+(defun dbgr-loc-hist-index(loc-hist)
+ "Return the ring-index value of LOC-HIST"
+ (lexical-let* (
+ (ring (dbgr-loc-hist-ring loc-hist))
+ (head (car ring))
+ (ringlen (cadr ring))
+ (index (mod (+ ringlen head
+ (- (dbgr-loc-hist-position loc-hist)))
+ ringlen)))
+ (if (zerop index) ringlen index)
+ ))
+
+(defun dbgr-loc-hist-set (loc-hist position)
+ "Set LOC-HIST to POSITION in the stopping history"
+ (setf (dbgr-loc-hist-position loc-hist) position))
+
+;; FIXME: add numeric arg?
+(defun dbgr-loc-hist-newer (loc-hist)
+ "Set LOC-HIST position to an newer position."
+
+ (setf (dbgr-loc-hist-position loc-hist)
+ (ring-plus1 (dbgr-loc-hist-position loc-hist)
+ (ring-length (dbgr-loc-hist-ring loc-hist)))))
+
+(defun dbgr-loc-hist-newest (loc-hist)
+ "Set LOC-HIST position to the newest position."
+ (setf (dbgr-loc-hist-position loc-hist) -1))
+
+;; FIXME: add numeric arg?
+(defun dbgr-loc-hist-older (loc-hist)
+ "Set LOC-HIST position to an older position."
+ (setf (dbgr-loc-hist-position loc-hist)
+ (ring-minus1 (dbgr-loc-hist-position loc-hist)
+ (ring-length (dbgr-loc-hist-ring loc-hist)))))
+
+(defun dbgr-loc-hist-oldest (loc-hist)
+ "Set LOC-HIST to the oldest stopping point."
+ (lexical-let* ((ring (dbgr-loc-hist-ring loc-hist))
+ (head (car ring)))
+ (setf (dbgr-loc-hist-position loc-hist) head)))
+
+(provide 'dbgr-loc-hist)
+
+;;; Local variables:
+;;; eval:(put 'dbgr-debug-enter 'lisp-indent-hook 1)
+;;; End:
+
+;;; dbgr-lochist.el ends here
--- /dev/null
+;;; dbgr-procbuf-var.el --- debugger variables (other than regexps) for
+;;; a process buffer
+(eval-when-compile (require 'cl))
+
+(defstruct dbgr-info
+ "The debugger object/structure specific to a process buffer."
+ (name :type string) ; Name of debugger
+ (loc-regexp :type string) ; Location regular expression string
+ ; FIXME: use include?
+ (file-group :type integer)
+ (line-group :type integer)
+ (loc-hist) ; ring of locations seen in the course of execution
+ ; see dbgr-lochist
+)
+
+(provide 'dbgr-procbuf-var)
+
+;;; Local variables:
+;;; eval:(put 'dbgr-debug-enter 'lisp-indent-hook 1)
+;;; End:
+
+;;; dbgr-procbuf-var.el ends here
--- /dev/null
+;;; dbgr-regexp.el --- Debugger regular expressions for many kinds of
+;; debuggers
+
+;; Here we have regular expressions and names for matched patterns
+;; of those regular expressions.
+
+;;; Code:
+
+;; -------------------------------------------------------------------
+;; Variables defining regular expressions (regexp:s).
+;;
+
+(defstruct dbgr-loc-pat
+ "Information to match and extract a file and line number location from
+a string output by a debugger inside a process shell"
+ (regexp :type string)
+ (file-group :type integer)
+ (line-group :type integer))
+
+(defvar dbgr-pat-hash (make-hash-table :test 'equal)
+ "Hash key is the debugger name, a string. The values of a hash entry
+ is a dbgr-loc-pat struct")
+
+;; FIXME? If this file gets too long and cumbersome, split each debugger
+;; section to its own file.
+
+; Create one for the Ruby 1.9 debugger "rbdbgr".
+(setf (gethash "rbdbgr" dbgr-pat-hash)
+ (make-dbgr-loc-pat
+ :regexp ".. (\\(?:.+ \\(?:via\\|remapped\\) \\)?\\(.+\\):\\([0-9]+\\))"
+ :file-group 1
+ :line-group 2))
+
+; Create one for ruby-debug
+(setf (gethash "rdebug" dbgr-pat-hash)
+ (make-dbgr-loc-pat
+ :regexp "\1a\1a\\(?:source \\)?\\(\\(?:[a-zA-Z]:\\)?[^:\n]*\\):\\([0-9]*\\).*\n"
+ :file-group 2
+ :line-group 3))
+
+; Now one for the Python debugger "pydbgr".
+(setf (gethash "pydbgr" dbgr-pat-hash)
+ (make-dbgr-loc-pat
+ :regexp "^(\\(\\(?:[a-zA-Z]:\\)?[-a-zA-Z0-9_/.\\\\ ]+\\):\\([0-9]+\\))"
+ :file-group 1
+ :line-group 2))
+
+; And the older Python debugger "pydb".
+(setf (gethash "pydb" dbgr-pat-hash)
+ (make-dbgr-loc-pat
+ :regexp "^(\\(\\(?:[a-zA-Z]:\\)?[-a-zA-Z0-9_/.\\\\ ]+\\):\\([0-9]+\\))"
+ :file-group 1
+ :line-group 2))
+
+; Create one for the Korn Shell debugger "kshdb".
+(setf (gethash "kshdb" dbgr-pat-hash)
+ (make-dbgr-loc-pat
+ :regexp "\\(^\\|\n\\)(\\([^:]+\\):\\([0-9]*\\))"
+ :file-group 2
+ :line-group 3))
+
+; And Z Shell debugger "zshdb".
+(setf (gethash "zshdb" dbgr-pat-hash)
+ (make-dbgr-loc-pat
+ :regexp "\\(^\\|\n\\)(\\([^:]+\\):\\([0-9]*\\))"
+ :file-group 2
+ :line-group 3))
+
+; One for the Bash debugger "bashdb".
+(setf (gethash "bashdb" dbgr-pat-hash)
+ (make-dbgr-loc-pat
+ :regexp "\\(^\\|\n\\)(\\([^:]+\\):\\([0-9]*\\))"
+ :file-group 2
+ :line-group 3))
+
+; And finally for GNU Make + debugger "remake".
+(setf (gethash "remake" dbgr-pat-hash)
+ (make-dbgr-loc-pat
+ :regexp "\\(?:^\\|\n\\)(\\(\\(?:[a-zA-Z]:\\)?[-a-zA-Z0-9_/.\\\\ ]+\\):\\([0-9]+\\))"
+ :file-group 1
+ :line-group 2))
+
+(provide 'dbgr-regexp)
+
+;;; Local variables:
+;;; eval:(put 'dbgr-debug-enter 'lisp-indent-hook 1)
+;;; End:
+
+;;; dbgrr-regexp.el ends here
--- /dev/null
+;;; rbdbg-scriptbuf-var.el --- debugger variables (other than regexps)
+;;; for a script to be debugged.
+(eval-when-compile (require 'cl))
+
+(defstruct rbdbg-scriptbuf-var
+ "debugger object/structure specific to a (top-level) Ruby file
+to be debugged."
+ (name :type string) ;; Name of debugger
+ (cmd :type string) ;; Debugger command invocation. FIXME: turn
+ ;; into a ring of recent invocations.
+ (cmdproc) ;; buffer containing debugger process
+)
+
+(defvar rbdbgr-scriptvar (make-rbdbg-scriptbuf-var
+ :name "rbdbgr"
+ :cmd "rbdbgr"
+ :cmdproc nil
+ )
+ "Debugger object for a process buffer.")
+(make-variable-buffer-local 'rbdbgr-dbgr-scriptbuf-var)
+
+(provide 'rbdbg-scriptbuf-var)
+
+;;; Local variables:
+;;; eval:(put 'rbdbgr-debug-enter 'lisp-indent-hook 1)
+;;; End:
+
+;;; rbdbgr-scriptbuf-var.el ends here
--- /dev/null
+;; `dbgr-track-mode' tracks shell output
+
+(defun dbgr-directory ()
+ "The directory of this file, or nil."
+ (let ((file-name (or load-file-name
+ (symbol-file 'dbgr-directory))))
+ (if file-name
+ (file-name-directory file-name)
+ nil)))
+
+(eval-when-compile (require 'cl))
+(require 'dbgr-track)
+(setq load-path (cons nil (cons (dbgr-directory) load-path)))
+(load "dbgr-track")
+(load "dbgr-loc")
+(load "dbgr-lochist")
+(load "dbgr-file")
+(load "dbgr-procbuf-var")
+(load "dbgr-window")
+(load "dbgr-regexp")
+(require 'dbgr-regexp)
+(setq load-path (cddr load-path))
+
+(make-variable-buffer-local 'dbgr-info)
+(defvar dbgr-inof (make-dbgr-info
+ :name "unknown-debugger-name"
+ :loc-regexp nil
+ :file-group -1
+ :line-group -1
+ :loc-hist nil)
+ "Debugger object for a process buffer.")
+
+(defvar dbgr-track-minor-mode nil
+ "Non-nil if using dbgr-track mode as a minor mode of some other mode.
+Use the command `dbgr-track-minor-mode' to toggle or set this variable.")
+
+(defvar dbgr-track-minor-mode-map
+ (let ((map (make-sparse-keymap)))
+ (define-key map [M-right] 'dbgr-track-hist-newest)
+ (define-key map [M-down] 'dbgr-track-hist-newer)
+ (define-key map [M-up] 'dbgr-track-hist-older)
+ (define-key map [M-S-down] 'dbgr-track-hist-newest)
+ (define-key map [M-S-up] 'dbgr-track-hist-oldest)
+ map)
+ "Keymap used in `dbgr-track-minor-mode'.")
+
+(define-minor-mode dbgr-track-mode
+ "Minor mode for tracking ruby debugging inside a process shell."
+ :init-value nil
+ ;; :lighter " dbgrr" ;; indicator in the mode line.
+ ;; The minor mode bindings.
+ :global nil
+ :group 'dbgr
+ :keymap dbgr-track-minor-mode-map
+ (if dbgr-track-mode
+ (progn
+ (add-hook 'comint-output-filter-functions
+ 'dbgr-track-comint-output-filter-hook)
+ (add-hook 'eshell-output-filter-functions
+ 'dbgr-track-eshell-output-filter-hook)
+
+ ;; FIXME: the following is customized for the debugger dbgrr.
+ ;; Other debuggers will be put in dbgr-dbgr-pat-hash and the
+ ;; below should be customizable for those debuggers by setting
+ ;; dbg-name accordingly. Put this in a subroutine.
+ (dbgr-track-set-debugger "dbgrr")
+ (run-mode-hooks 'dbgr-track-mode-hook)
+ )
+ (progn
+ (remove-hook 'comint-output-filter-functions
+ 'dbgr-track-comint-output-filter-hook)
+ (remove-hook 'eshell-output-filter-functions
+ 'dbgr-track-eshell-output-filter-hook)
+ )))
+
+;; -------------------------------------------------------------------
+;; The end.
+;;
+
+(provide 'dbgr-track-mode)
+
+;;; Local variables:
+;;; eval:(put 'dbgr-debug-enter 'lisp-indent-hook 1)
+;;; End:
+
+;;; dbgr-track.el ends here
--- /dev/null
+;;; dbgr-track.el --- Debugger tracking a comint or eshell buffer.
+
+;; -------------------------------------------------------------------
+;; Variables.
+;;
+
+(defconst dbgr-track-char-range 10000
+ "Max number of characters from end of buffer to search for stack entry.")
+
+
+;; -------------------------------------------------------------------
+;; Dependencies.
+;;
+
+(require 'comint)
+
+; For eshell-output-filter-functions, eshell-last-input-start:
+(require 'esh-mode)
+
+(eval-when-compile
+ (require 'cl)
+ (setq load-path (cons nil (cons ".." load-path)))
+ (load "dbgr-loc")
+ (load "dbgr-lochist")
+ (load "dbgr-file")
+ (load "dbgr-procbuf-var")
+ (load "dbgr-window")
+ (load "dbgr-regexp")
+ (setq load-path (cddr load-path)))
+(require 'dbgr-file)
+(require 'dbgr-loc)
+(require 'dbgr-regexp)
+
+(defun dbgr-track-comint-output-filter-hook(text)
+ "An output-filter hook custom for comint shells. Find
+location/s, if any, and run the action(s) associated with
+finding a new location/s. The parameter TEXT appears because it
+is part of the comint-output-filter-functions API. Instead we use
+marks set in buffer-local variables to extract text"
+
+ ;; Instead of trying to piece things together from partial text
+ ;; (which can be almost useless depending on Emacs version), we
+ ;; monitor to the point where we have the next dbgr prompt, and then
+ ;; check all text from comint-last-input-end to process-mark.
+
+ ; FIXME: Add unwind-protect?
+ (lexical-let* ((proc-buff (current-buffer))
+ (proc-window (selected-window))
+ (curr-proc (get-buffer-process proc-buff))
+ (last-output-end (process-mark curr-proc))
+ (last-output-start (max comint-last-input-end
+ (- last-output-end dbgr-track-char-range)))
+ (loc (dbgr-track-from-region last-output-start
+ last-output-end)))
+
+ (if loc (dbgr-track-loc-action loc proc-buff proc-window))))
+
+(defun dbgr-track-eshell-output-filter-hook()
+ "An output-filter hook custom for eshell shells. Find
+location(s), if any, and run the action(s) associated with We use
+marks set in buffer-local variables to extract text"
+
+ ; FIXME: Add unwind-protect?
+ (lexical-let ((proc-buff (current-buffer))
+ (proc-window (selected-window))
+ (loc (dbgr-track-from-region eshell-last-output-start
+ eshell-last-output-end)))
+ (dbgr-track-loc-action loc proc-buff proc-window)))
+
+(defun dbgr-track-from-region(from to)
+ (interactive "r")
+ (if (> from to) (psetq to from from to))
+ (dbgr-track-loc (buffer-substring from to)))
+
+(defun dbgr-track-hist-fn-internal(fn)
+ (interactive)
+ (lexical-let* ((loc-hist (dbgr-dbgr-loc-hist dbgr-dbgr))
+ (cmd-window (selected-window))
+ (cmd-buff (current-buffer))
+ (position (funcall fn loc-hist))
+ (loc (dbgr-loc-hist-item loc-hist)))
+ (dbgr-loc-goto loc 'dbgr-split-or-other-window)
+ (message "history position %s line %s"
+ (dbgr-loc-hist-index loc-hist)
+ (dbgr-loc-line-number loc))
+ ; FIXME: Combine common code with loc-action?
+ ; See also comments why we do the below there.
+ (set-buffer cmd-buff)
+ (select-window cmd-window))
+ )
+
+; FIXME: Can we dry code more via a macro?
+(defun dbgr-track-hist-newer()
+ (interactive)
+ (dbgr-track-hist-fn-internal 'dbgr-loc-hist-newer))
+
+(defun dbgr-track-hist-newest()
+ (interactive)
+ (dbgr-track-hist-fn-internal 'dbgr-loc-hist-newest))
+
+(defun dbgr-track-hist-older()
+ (interactive)
+ (dbgr-track-hist-fn-internal 'dbgr-loc-hist-older))
+
+(defun dbgr-track-hist-oldest()
+ (interactive)
+ (dbgr-track-hist-fn-internal 'dbgr-loc-hist-oldest))
+
+(defun dbgr-track-loc-action(loc &optional cmd-buff cmd-window)
+ "If loc is valid, show loc and do whatever actions we do for
+encountering a new loc."
+ (if (dbgr-loc-p loc)
+ (progn
+ (if (null cmd-buff) (setq cmd-buff (current-buffer)))
+ (if (null cmd-window) (setq cmd-window (selected-window)))
+
+ (dbgr-loc-goto loc 'dbgr-split-or-other-window)
+
+ ; We need to go back to the process/command buffer because other
+ ; output-filter hooks run after this may assume they are in that
+ ; buffer.
+ (set-buffer cmd-buff)
+
+ ; hist add has to be done in cmd-buff since dbgr-dbgr
+ (dbgr-loc-hist-add (dbgr-dbgr-loc-hist dbgr-dbgr) loc)
+
+ ; I like to stay on the debugger prompt rather than the found
+ ; source location. Folks like Anders (who would like to totally
+ ; get rid of the command line) no doubt feel differently about this.
+ (select-window cmd-window))
+ (message "%s" loc)))
+
+(defun dbgr-track-loc(text &optional opt-regexp opt-file-group opt-line-group)
+ "Do regular-expression matching to find a file name and line number inside
+string TEXT. If we match we will turn the result into a dbgr-loc struct.
+Otherwise return nil."
+
+ ; NOTE: dbgr-info is a buffer variable local to the process running
+ ; the debugger. It contains a dbgr-info "struct". In that struct are
+ ; the fields loc-regexp, file-group, and line-group. By setting the
+ ; the fields of dbgr-info appropriately we can accomodate a family
+ ; of debuggers -- one at a time -- for the buffer process.
+
+ (lexical-let ((loc-regexp (or opt-regexp (dbgr-info-loc-regexp dbgr-info)))
+ (file-group (or opt-file-group (dbgr-info-file-group dbgr-info)))
+ (line-group (or opt-line-group (dbgr-info-line-group dbgr-info))))
+ (if (and loc-regexp (string-match loc-regexp text))
+ (lexical-let* ((filename (match-string file-group text))
+ (line-str (match-string line-group text))
+ (lineno (string-to-number (or line-str "1"))))
+ (unless line-str (message "line number not found -- using 1"))
+ (if (and filename lineno)
+ (dbgr-file-loc-from-line filename lineno)
+ nil))
+ nil)))
+
+(defun dbgr-track-set-debugger(debugger-name)
+ (interactive "sDebugger name: ")
+ (lexical-let ((loc-pat (gethash debugger-name dbgr-info-pat-hash)))
+ (if loc-pat
+ (setq dbgr-info (make-dbgr-info
+ :name debugger-name
+ :loc-regexp (dbgr-info-loc-pat-regexp loc-pat)
+ :file-group (dbgr-info-loc-pat-file-group loc-pat)
+ :line-group (dbgr-info-loc-pat-line-group loc-pat)
+ :loc-hist (make-dbgr-loc-hist)))
+ (message "I Don't have %s listed as a debugger." debugger-name)
+ ))
+ )
+
+;; -------------------------------------------------------------------
+;; The end.
+;;
+
+(provide 'dbgr-track)
+
+;;; Local variables:
+;;; eval:(put 'dbgr-debug-enter 'lisp-indent-hook 1)
+;;; End:
+
+;;; dbgr-track.el ends here
--- /dev/null
+(defun dbgr-split-or-other-window()
+ "Split the window if there is only one in the current
+ frame. However if there is more than one window move to that"
+ (interactive)
+ ;; Anders code has more complicated logic for figuring out
+ ;; which of serveral "other" windows is the one you want to switch
+ ;; to.
+ (if (one-window-p 't) (split-window) (other-window 1)))
+
--- /dev/null
+;; -------------------------------------------------------------------
+;; Dependencies.
+;;
+(eval-when-compile
+ (require 'cl))
+
+(defun rbdbgr-directory ()
+ "The directory of this file, or nil."
+ (let ((file-name (or load-file-name
+ (symbol-file 'rbdbgr-directory))))
+ (if file-name
+ (file-name-directory file-name)
+ nil)))
+
+(setq load-path (cons nil (cons (rbdbgr-directory) load-path)))
+(require 'rbdbg-track)
+(require 'gud) ; FIXME: GUD is BAD! It is too far broken to be fixed.
+(require 'rbdbgr-regexp)
+(require 'rbdbg-scriptbuf-var)
+(setq load-path (cddr load-path))
+
+
+;; FIXME: move to a more common location. rbdbg-core ?
+(defun rbdbgr-strip-command-arg (args two-args opt-two-args)
+ "return ARGS with the first argument, an 'option'
+removed.
+
+However if that option argument may take another argument, remove
+that as well. TWO-ARGS is list of options (strings without the
+leading dash) that take a mandatory additional
+argument. OPT-TWO-ARGS is a list of options might take two
+arguments. The rule for an optional argument we use: if the next
+parameter starts with a dash ('-'), it is not part of the
+preceeding parameter when that parameter is optional.
+
+NOTE: we don't check whether the first arguments of ARGS is an
+option by testing to see if it starts say with a dash. So on
+return the first argument is always removed.
+"
+ (let ((arg (car args))
+ (d-two-args (mapcar (lambda(x) (concat "-" x)) two-args))
+ (d-opt-two-args (mapcar (lambda(x) (concat "-" x)) opt-two-args))
+ (remaining (cdr args)))
+ (cond
+ ((member arg d-two-args)
+ (if remaining (cdr remaining)
+ (progn
+ (message "Expecting an argument after %s. Continuing anyway."
+ arg)
+ remaining)))
+ ((member arg d-opt-two-args)
+ (if (and remaining (not (string-match "^-" (car remaining))))
+ (cdr remaining)
+ remaining))
+ (t remaining))))
+
+(defun rbdbgr-get-script-name (orig-args)
+ "Parse command line ARGS for the annotate level and name of script to debug.
+
+ARGS should contain a tokenized list of the command line to run.
+
+We return the script name to be debugged and whether option the
+annotate option (either '--annotate' or '-A') was set."
+ ;; Parse the following:
+ ;;
+ ;; [ruby ruby-options] rbdbgr rbdbgr-options script-name script-options
+ (let ((args orig-args)
+ (script-name nil)
+ (annotate-p nil)
+ (ruby-opt-two-args '("0" "C" "e" "E" "F" "i"))
+ ;; Ruby doesn't have mandatory 2-arg options in our sense,
+ ;; since the two args can be run together, e.g. "-C/tmp" or "-C /tmp"
+ ;;
+ (ruby-two-args '())
+ (debugger-name)
+ ;; One dash is added automatically to the below, so
+ ;; h is really -h and -host is really --host.
+ (rbdbgr-two-args '("h" "-host" "p" "-port"
+ "I" "-include" "-r" "-require"))
+ (rbdbgr-opt-two-args '()))
+ (if (not (and args))
+ ;; Got nothing: return '(nil, nil)
+ '(script-name annotate-p)
+ ;; else
+ ;; Strip off optional "ruby" or "ruby182" etc.
+ (when (string-match "^ruby[-0-9]*$"
+ (file-name-sans-extension
+ (file-name-nondirectory (car args))))
+ (pop args) ; remove whatever "ruby" thing found.
+
+ ;; Strip off Ruby-specific options
+ (while (and args
+ (string-match "^-" (car args)))
+ (setq args (rbdbgr-strip-command-arg
+ args ruby-two-args ruby-opt-two-args))))
+
+ ;; Remove "rbdbgr" from "rbdbgr --rbdbgr-options script
+ ;; --script-options"
+ (setq debugger-name (file-name-sans-extension
+ (file-name-nondirectory (car args))))
+ (unless (string-match "^rbdbgr$" debugger-name)
+ (message
+ "Expecting debugger name to be rbdbgr; got `%s'. Stripping anyway."
+ debugger-name))
+ (pop args)
+ ;; Skip to the first non-option argument.
+ (while (and args (not script-name))
+ (let ((arg (car args)))
+ (cond
+ ;; Annotation or emacs option with level number.
+ ((or (member arg '("--annotate" "-A"))
+ (equal arg "--emacs"))
+ (setq annotate-p t)
+ (pop args))
+ ;; Combined annotation and level option.
+ ((string-match "^--annotate=[0-9]" arg)
+ (pop args)
+ (setq annotate-p t))
+ ;; Options with arguments.
+ ((string-match "^-" arg)
+ (setq args (rbdbgr-strip-command-arg
+ args rbdbgr-two-args rbdbgr-opt-two-args)))
+ ;; Anything else must be the script to debug.
+ (t (setq script-name arg)))))
+ (list script-name annotate-p))))
+
+(defun rbdbgr-file-ruby-mode? (filename)
+ "Return true if FILENAME is a buffer we are visiting a buffer
+that is in ruby-mode"
+ (let ((buffer (and filename (find-buffer-visiting filename)))
+ (cur-buff (current-buffer))
+ (match-pos))
+ (if buffer
+ (progn
+ (save-excursion
+ (switch-to-buffer buffer 't)
+ (setq match-pos (string-match "^ruby-" (format "%s" major-mode))))
+ (switch-to-buffer cur-buff)
+ (and match-pos (= 0 match-pos)))
+ nil)))
+
+
+(defun rbdbgr-suggest-ruby-file ()
+ "Suggest a Ruby file to debug. First priority is given to the
+current buffer. If the major mode is Ruby-mode, then we are
+done. If the major mode is not Ruby, we'll use priority 2 and we
+keep going. Then we will try files in the default-directory. Of
+those that we are visiting we will see if the major mode is Ruby,
+the first one we find we will return. Failing this, we see if the
+file is executable and has a .rb suffix. These have priority 8.
+Failing that, we'll go for just having a .rb suffix. These have
+priority 7. And other executable files have priority 6. Within a
+given priority, we use the first one we find."
+ (let* ((file)
+ (file-list (directory-files default-directory))
+ (priority 2)
+ (result (buffer-file-name)))
+ (if (not (rbdbgr-file-ruby-mode? result))
+ (while (and (setq file (car-safe file-list)) (< priority 8))
+ (setq file-list (cdr file-list))
+ (if (rbdbgr-file-ruby-mode? file)
+ (progn
+ (setq result file)
+ (setq priority
+ (if (file-executable-p file)
+ (setq priority 8)
+ (setq priority 7)))))
+ ;; The file isn't in a Ruby-mode buffer,
+ ;; Check for an executable file with a .rb extension.
+ (if (and file (file-executable-p file)
+ (not (file-directory-p file)))
+ (if (and (string-match "\.rb$" file))
+ (if (< priority 6)
+ (progn
+ (setq result file)
+ (setq priority 6))))
+ ;; Found some sort of executable file.
+ (if (< priority 5)
+ (progn
+ (setq result file)
+ (setq priority 5))))))
+ result))
+
+(defun rbdbgr-query-cmdline ()
+ "Prompt for a rbdbgr debugger command invocation to run.
+Analogous to `gud-query-cmdline'"
+ ;; FIXME: keep a list of recent invocations.
+ (let ((debugger (rbdbg-scriptbuf-var-name rbdbgr-scriptvar))
+ (cmd-name (rbdbg-scriptbuf-var-cmd rbdbgr-scriptvar)))
+ (read-from-minibuffer
+ (format "Run %s (like this): " debugger)
+ (concat cmd-name " " (or (rbdbgr-suggest-ruby-file))))))
+
+(defun rbdbgr-goto-line-for-type (type pt)
+ "Display the location mentioned in line described by PT. TYPE is used
+to get a regular-expresion pattern matching information."
+ (interactive "d")
+ (save-excursion
+ (goto-char pt)
+ (lexical-let* ((proc-buff (current-buffer))
+ (proc-window (selected-window))
+ (curr-proc (get-buffer-process proc-buff))
+ (start (line-beginning-position))
+ (end (line-end-position))
+ (tb (gethash type rbdbgr-dbgr-pat-hash))
+ ;; FIXME check that tb is not null and abort if it is.
+ (loc (rbdbg-track-loc (buffer-substring start end)
+ (rbdbg-dbgr-loc-pat-regexp tb)
+ (rbdbg-dbgr-loc-pat-file-group tb)
+ (rbdbg-dbgr-loc-pat-line-group tb)
+ )))
+ (if loc (rbdbg-track-loc-action loc proc-buff proc-window)))))
+
+(defun rbdbgr-goto-traceback-line (pt)
+ "Display the location mentioned by the Ruby traceback line
+described by PT."
+ (interactive "d")
+ (rbdbgr-goto-line-for-type "traceback" pt))
+
+(defun rbdbgr-goto-dollarbang-traceback-line (pt)
+ "Display the location mentioned by the Ruby $! traceback line
+described by PT."
+ (interactive "d")
+ (rbdbgr-goto-line-for-type "dollar-bang" pt))
+
+;; 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 rbdbgr-common-init (rbdbgr-buffer-name rbdbgr-cmd-buffer target-name
+;;; program args
+;;; marker-filter
+;;; &optional find-file)
+;;; "Perform initializations common to all debuggers.
+
+;;; RBDBGR-BUFFER-NAME is the specified command line, which starts
+;;; with the program to debug. PROGRAM, ARGS and MARKER-FILTER
+;;; specify the values to use for local variables in the debugger
+;;; buffer."
+;;; (if rbdbgr-cmd-buffer
+;;; (progn
+;;; (pop-to-buffer rbdbgr-cmd-buffer)
+;;; (when (and rbdbgr-cmd-buffer (get-buffer-process rbdbgr-cmd-buffer))
+;;; (error "This program is already being debugged"))
+;;; (apply 'make-comint rbdbgr-buffer-name program nil args)
+;;; (or (bolp) (newline)))
+;;; (pop-to-buffer (setq rbdbgr-cmd-buffer
+;;; (apply 'make-comint rbdbgr-buffer-name program nil
+;;; args))))
+
+;;; ;; Since comint clobbered the mode, we don't set it until now.
+;;; (gud-mode)
+;;; (set (make-local-variable 'gud-target-name) target-name)
+;;; (set (make-local-variable 'gud-marker-filter) marker-filter)
+;;; (set (make-local-variable 'gud-debugger) 'rbdbgr)
+;;; (set (make-local-variable 'gud-last-frame) nil)
+;;; (set (make-local-variable 'gud-last-last-frame) nil)
+
+;;; (let ((buffer-process (get-buffer-process (current-buffer))))
+;;; (if buffer-process
+;;; (progn
+;;; (set-process-filter buffer-process 'gud-filter)
+;;; (set-process-sentinel buffer-process 'gud-sentinel))))
+;;; (gud-set-buffer))
+
+;; ;;;###autoload
+;; (defun rbdbgr (command-line)
+;; "Invoke the rbdbgr Ruby debugger and start the Emacs user interface.
+
+;; String COMMAND-LINE specifies how to run rbdbgr."
+;; (interactive
+;; (let ((init (buffer-file-name)))
+;; (setq init (and init
+;; (file-name-nondirectory init)))
+;; (list (gud-query-cmdline 'rbdbgr init))))
+;; ;; (rbdbgr-set-window-configuration-state 'debugger t)
+;; ;; Parse the command line and pick out the script name and whether
+;; ;; --annotate has been set.
+;; (let* ((words (with-no-warnings
+;; (split-string-and-unquote command-line)))
+;; (script-name-annotate-p (rbdbgr-get-script-name
+;; (gud-rbdbgr-massage-args "1" words)))
+;; (target-name (file-name-nondirectory (car script-name-annotate-p)))
+;; (annotate-p (cadr script-name-annotate-p))
+;; (cmd-buffer-name (format "rbdbgr-cmd-%s" target-name))
+;; (rbdbgr-cmd-buffer-name (format "*%s*" cmd-buffer-name))
+;; (rbdbgr-cmd-buffer (get-buffer rbdbgr-cmd-buffer-name))
+;; (program (car words))
+;; (args (cdr words))
+;; (gud-chdir-before-run nil))
+
+;; ;; `gud-rbdbgr-massage-args' needs whole `command-line'.
+;; ;; command-line is refered through dynamic scope.
+;; (rbdbgr-common-init cmd-buffer-name rbdbgr-cmd-buffer target-name
+;; program args
+;; 'gud-rbdbgr-marker-filter
+;; 'gud-rbdbgr-find-file)
+;; (setq comint-process-echoes t)
+
+;; ;; (setq rbdbgr-inferior-status "running")
+
+;; (rbdbgr-command-initialization)
+
+;; ;; Setup exit callback so that the original frame configuration
+;; ;; can be restored.
+;; ;; (let ((process (get-buffer-process rbdbg-buffer)))
+;; ;; (when process
+;; ;; (unless (equal rbdbgr-line-width 120)
+;; ;; (gud-call (format "set width %d" rbdbgr-line-width)))
+;; ;; (set-process-sentinel process
+;; ;; 'rbdbgr-process-sentinel)))
+
+
+;; ;; Add the buffer-displaying commands to the Gud buffer,
+;; ;; FIXME: combine with code in rbdbgr-track.el; make common
+;; ;; command buffer mode map.
+;; (let ((prefix-map (make-sparse-keymap)))
+;; (define-key (current-local-map) gud-key-prefix prefix-map)
+;; (define-key prefix-map "t" 'rbdbgr-goto-traceback-line)
+;; (define-key prefix-map "!" 'rbdbgr-goto-dollarbang-traceback-line)
+;; (rbdbgr-populate-secondary-buffer-map-plain prefix-map))
+
+;; (rbdbgr-populate-common-keys (current-local-map))
+;; (rbdbgr-populate-debugger-menu (current-local-map))
+
+;; ;; (setq comint-prompt-regexp (concat "^" rbdbgr-input-prompt-regexp))
+;; ;; (setq paragraph-start comint-prompt-regexp)
+
+;; ;; (setcdr (assq 'rbdbgr-debugger-support-minor-mode minor-mode-map-alist)
+;; ;; rbdbgr-debugger-support-minor-mode-map-when-active)
+;; ;; (when rbdbgr-many-windows
+;; ;; (rbdbgr-setup-windows-initially))
+
+;; (run-hooks 'rbdbgr-mode-hook)))
+
+
+(defun rbdbgr-reset ()
+ "Rbdbgr cleanup - remove debugger's internal buffers (frame,
+breakpoints, etc.)."
+ (interactive)
+ ;; (rbdbgr-breakpoint-remove-all-icons)
+ (dolist (buffer (buffer-list))
+ (when (string-match "\\*rbdbgr-[a-z]+\\*" (buffer-name buffer))
+ (let ((w (get-buffer-window buffer)))
+ (when w
+ (delete-window w)))
+ (kill-buffer buffer))))
+
+;; (defun rbdbgr-reset-keymaps()
+;; "This unbinds the special debugger keys of the source buffers."
+;; (interactive)
+;; (setcdr (assq 'rbdbgr-debugger-support-minor-mode minor-mode-map-alist)
+;; rbdbgr-debugger-support-minor-mode-map-when-deactive))
+
+
+(defun rbdbgr-customize ()
+ "Use `customize' to edit the settings of the `rbdbgr' debugger."
+ (interactive)
+ (customize-group 'rbdbgr))
+
+
+;; -------------------------------------------------------------------
+;; The end.
+;;
+
+(provide 'rbdbgr-core)
+
+;;; Local variables:
+;;; eval:(put 'rbdbgr-debug-enter 'lisp-indent-hook 1)
+;;; End:
+
+;;; rbdbgr-core.el ends here
--- /dev/null
+;;; rdebug-regexp.el --- Ruby debugger regular expressions
+
+;; -------------------------------------------------------------------
+;; Variables defining regular expressions (regexp:s).
+;;
+(eval-when-compile
+ (setq load-path (cons nil (cons ".." load-path)))
+ (require 'cl)
+ (load "dbgr-regexp") ; for make-dbgr-loc-pat
+ (setq load-path (cddr load-path)))
+
+
+(defvar rbdbgr-pat-hash (make-hash-table :test 'equal)
+ "Hash key is the what kind of pattern we want to match: traceback, prompt, etc.
+The values of a hash entry is a dbgr-dbgr-loc-pat struct")
+
+;; Regular expression that describes a rbdbgr command prompt
+(setf (gethash "prompt" rbdbgr-pat-hash)
+ (make-dbgr-loc-pat
+ :regexp ".. (.*?\\(?:via \\)?\\([-a-zA-Z0-9_/.]+\\):\\([0-9]+\\))"
+ :file-group 1
+ :line-group 2))
+
+;; Regular expression that describes a Ruby traceback line.
+(setf (gethash "traceback" rbdbgr-pat-hash)
+ (make-dbgr-loc-pat
+ :regexp "^[ \t]+from \\([^:]+\\):\\([0-9]+\\)\\(?: in `.*'\\)?"
+ :file-group 1
+ :line-group 2))
+
+;; Regular expression that describes a Ruby $! string
+(setf (gethash "dollar-bang" rbdbgr-pat-hash)
+ (make-dbgr-loc-pat
+ :regexp "^[ \t]*[[]?\\(.+\\):\\([0-9]+\\):in `.*'"
+ :file-group 1
+ :line-group 2))
+
+
+(provide 'rbdbgr-regexp)
+
+;;; Local variables:
+;;; eval:(put 'rbdbgr-debug-enter 'lisp-indent-hook 1)
+;;; End:
+
+;;; rbdbgr-regexp.el ends here
--- /dev/null
+;;; rbdbgr-track-mode.el --- Ruby "rbdbgr" Debugger tracking a comint
+;;; or eshell buffer.
+
+(eval-when-compile
+ (require 'cl))
+
+(defun rbdbgr-directory ()
+ "The directory of this file, or nil."
+ (let ((file-name (or load-file-name
+ (symbol-file 'rbdbgr-directory))))
+ (if file-name
+ (file-name-directory file-name)
+ nil)))
+
+(setq load-path (cons nil (cons (rbdbgr-directory) load-path)))
+(require 'rbdbg-track-mode)
+(require 'rbdbgr-core)
+(setq load-path (cddr load-path))
+
+
+(defvar rbdbgr-track-mode nil
+ "Non-nil if using rbdbgr-track mode as a minor mode of some other mode.
+Use the command `rbdbgr-track-mode' to toggle or set this variable.")
+
+(defvar rbdbgr-track-mode-map
+ (let ((map (make-sparse-keymap)))
+ (define-key map [C-c !] 'rbdbgr-goto-dollarbang-traceback-line)
+ (define-key map [C-c e] 'rbdbgr-goto-traceback-line)
+ map)
+ "Keymap used in `rbdbgr-track-mode'.")
+
+(define-minor-mode rbdbgr-track-mode
+ "Minor mode for tracking ruby debugging inside a process shell."
+ :init-value nil
+ :lighter " rbdbgr" ;; indicator in the mode line.
+ ;; The minor mode bindings.
+ :global nil
+ :group 'rbdbgr
+ :keymap rbdbgr-track-mode-map
+
+ (rbdbg-track-set-debugger "rbdbgr")
+ (if rbdbgr-track-mode
+ (progn
+ (rbdbg-track-mode 't)
+ ;; FIXME: until I figure out why this isn't set in the mode
+ (local-set-key "\C-c!" 'rbdbgr-goto-dollarbang-traceback-line)
+ (local-set-key "\C-ce" 'rbdbgr-goto-traceback-line)
+ (run-mode-hooks 'rbdbgr-track-mode-hook))
+ (progn
+ ;; FIXME: until I figure out why this isn't set in the mode
+ (rbdbg-track-mode nil)
+ (local-unset-key "\C-c!")
+ (local-unset-key "\C-ce"))
+ ))
+
+
+;; -------------------------------------------------------------------
+;; The end.
+;;
+
+(provide 'rbdbgr-track-mode)
+
+;;; Local variables:
+;;; eval:(put 'rbdbg-debug-enter 'lisp-indent-hook 1)
+;;; End:
+
+;;; rbdbgr-track.el ends here
--- /dev/null
+;; `rbdbgr' Main interface to rbdbgr via Emacs
+(if (< emacs-major-version 22)
+ (error
+ "You need at least Emacs 22 or greater to run this - you have version %d"
+ emacs-major-version))
+
+(eval-when-compile
+ (setq load-path (cons nil (cons ".." load-path)))
+ (require 'cl)
+ (load "rbdbgr-core")
+ (setq load-path (cddr load-path)))
+
+;; This is needed, or at least the docstring part of it is needed to
+;; get the customization menu to work in Emacs 23.
+(defgroup rbdbgr nil
+ "The Ruby 1.9 debugger"
+ :group 'processes
+ :group 'tools)
+
+;; -------------------------------------------------------------------
+;; User definable variables
+;;
+
+(defcustom gud-rbdbgr-command-name
+ ;;"rbdbgr --emacs 3"
+ "rbdbgr"
+ "File name for executing the Ruby debugger and command options.
+This should be an executable on your path, or an absolute file name."
+ :type 'string
+ :group 'gud)
+
+
+;; -------------------------------------------------------------------
+;; The end.
+;;
+
+(provide 'rbdbgr)
+
+;;; rbdbgr.el ends here
+
--- /dev/null
+# Whatever it is you want to do, it should be forwarded to the
+# to top-level irectories
+PHONY=check all
+all: check
+
+%:
+ $(MAKE) -C .. $@
--- /dev/null
+;;; behave.el --- Emacs Lisp Behaviour-Driven Development framework
+
+;; Copyright (C) 2007 Phil Hagelberg
+
+;; Author: Phil Hagelberg
+;; URL: http://dev.technomancy.us/wiki/behave.el
+;; Created: 19 Jan 2007
+;; Version: 0.1
+;; Keywords: bdd specification specs
+
+;; This file is NOT part of GNU Emacs.
+
+;; This is free software; you can redistribute it and/or modify it under
+;; the terms of the GNU General Public License as published by the Free
+;; Software Foundation; either version 3, or (at your option) any later
+;; version.
+
+;; This file is distributed in the hope that it will be useful, but
+;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+;; General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with Emacs; see the file COPYING, or type `C-h C-c'. If not,
+;; write to the Free Software Foundation at this address:
+
+;; Free Software Foundation
+;; 51 Franklin Street, Fifth Floor
+;; Boston, MA 02110-1301
+;; USA
+
+;;; Commentary:
+
+;; behave.el allows you to write executable specifications for your
+;; Emacs Lisp code. Executable specifications allow you to check that
+;; your code is working correctly in an automated fashion that you can
+;; use to drive the focus of your development. (It's related to
+;; Test-Driven Development.) You can read up on it at
+;; http://behaviour-driven.org.
+
+;; Specifications and contexts both must have docstrings so that when
+;; the specifications aren't met it is easy to see what caused the
+;; failure. Each specification should live within a context. In each
+;; context, you can set up relevant things to test, such as necessary
+;; buffers or data structures. (Be sure to use lexical-let for setting
+;; up the variables you need--since the specify macro uses lambdas,
+;; closures will be made for those variables.) Everything within the
+;; context is executed normally.
+
+;; Each context can be tagged with the TAG form. This allows you to
+;; group your contexts by tags. When you execute the specs, M-x behave
+;; will ask you to give some tags, and it will execute all contexts
+;; that match those tags.
+
+;; When you want to run the specs, evaluate them and press M-x
+;; behave. Enter the tags you want to run (or "all"), and they will be
+;; executed with results in the *behave* buffer. You can also do M-x
+;; specifications to show a list of all the specified behaviours of
+;; the code.
+
+;;; Implementation
+
+;; Contexts are stored in the *behave-contexts* list as structs. Each
+;; context has a "specs" slot that contains a list of its specs, which
+;; are stored as closures. The expect form ensures that expectations
+;; are met and signals behave-spec-failed if they are not.
+
+;; Warning: the variables CONTEXT and SPEC-DESC are used within macros
+;; in such a way that they could shadow variables of the same name in
+;; the code being tested. Future versions will use gensyms to solve
+;; this issue, but in the mean time avoid relying upon variables with
+;; those names.
+
+;;; To do:
+
+;; See open tickets on my Trac:
+;; http://dev.technomancy.us/phil/query?status=new&status=assigned&status=reopened&component=behave&order=priority
+
+;; Main issues: more expect predicates
+
+;;; Usage:
+
+;; See meta.el for specifications for behave.el. Evaluate meta.el and
+;; M-x specifications meta RET to see the specifications explained.
+
+(eval-when-compile
+ (require 'cl))
+
+(defvar *behave-contexts* '()
+ "A list of contexts and their specs.")
+
+(defvar *behave-default-tags* "all")
+
+(defstruct context description tags (specs '()) refreshing-vars)
+
+(put 'behave-spec-failed 'error-conditions '(failure))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Core Macros
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defmacro context (description &rest body)
+ "Defines a context for specifications to run in."
+ (setq *behave-contexts* (delete (context-find description) *behave-contexts*))
+ `(lexical-let ((context (make-context)))
+ (setf (context-description context) ,description)
+ (add-to-list '*behave-contexts* context)
+ ,@body))
+
+(defmacro specify (description &rest body)
+ "Add a specification and its description to the current context."
+ `(push (lambda () ,description (let ((spec-desc ,description))
+ ,@body)) (context-specs context)))
+
+(defmacro expect (actual &optional predicate expected)
+ "State expectations the code should fulfill."
+ (case predicate
+ ((equals equal)
+ `(if (not (equal ,actual ,expected))
+ (signal 'behave-spec-failed (list (context-description context) spec-desc))))
+ (t
+ `(or ,actual
+ (signal 'behave-spec-failed (list (context-description context) spec-desc))))))
+
+(defmacro tag (&rest tags)
+ "Give a context tags for easy reference. (Must be used within a context.)"
+ `(setf (context-tags context) (append '(,@tags) (context-tags context))))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Context-management
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defun behave-clear-contexts ()
+ (interactive)
+ (setq *behave-contexts* '())
+ (message "Behave: contexts cleared"))
+
+(defun context-find (description)
+ "Find a context by its description."
+ (find description *behave-contexts* :test (lambda (description context) (equal description (context-description context)))))
+
+(defun context-find-by-tag (tag)
+ (remove-if (lambda (context) (not (find tag (context-tags context))))
+ *behave-contexts*))
+
+(defun context-find-by-tags (tags)
+ (if (find 'all tags)
+ *behave-contexts*
+ (delete nil (remove-duplicates (mapcan 'context-find-by-tag tags)))))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Execution
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defun behave (&optional tags)
+ "Execute all contexts that match given tags"
+ (interactive)
+ (let ((tags-string (or tags (read-string (concat "Execute specs matching these tags (default " *behave-default-tags* "): ")
+ nil nil *behave-default-tags*)))
+ (start-time (cadr (current-time)))
+ (failures nil)
+ (spec-count 0))
+ (setq *behave-default-tags* tags-string) ; update default for next time
+ (with-output-to-temp-buffer "*behave*"
+ (princ (concat "Running specs tagged \"" tags-string "\":\n\n"))
+ (dolist (context (context-find-by-tags (mapcar 'intern (split-string tags-string " "))))
+ (execute-context context))
+ (behave-describe-failures failures start-time))
+ (if noninteractive
+ (progn
+ (switch-to-buffer "*behave*")
+ (message "%s" (buffer-substring (point-min) (point-max)))))
+ (length failures)))
+
+(defun execute-context (context)
+ (condition-case failure
+ (mapcar #'execute-spec (reverse (context-specs context)))
+ (error (princ "E")
+ (switch-to-buffer "*behave*")
+ (overlay-put (make-overlay (point) (- (point) 1)) 'face '(foreground-color . "red"))
+ (switch-to-buffer nil)
+ (add-to-list 'failures (list "Error:" failure) t))
+ (failure (princ "F")
+ (switch-to-buffer "*behave*")
+ (overlay-put (make-overlay (point) (- (point) 1)) 'face '(foreground-color . "red"))
+ (switch-to-buffer nil)
+ (add-to-list 'failures (cdr failure) t))))
+
+(defun execute-spec (spec)
+ (incf spec-count)
+ (funcall spec)
+ (princ "."))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Reporting
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defun behave-describe-failures (failures start-time)
+ (princ (concat "\n\n" (number-to-string (length failures)) " problem" (unless (= 1 (length failures)) "s") " in "
+ (number-to-string spec-count)
+ " specification" (unless (= 1 spec-count) "s")
+ ". (" (number-to-string (- (cadr (current-time)) start-time)) " seconds)\n\n"))
+ (dolist (failure failures)
+ (behave-report-result failure)))
+
+(defun behave-report-result (failure)
+ (princ failure)
+ (princ "\n\n"))
+
+(defun specifications (&optional tags)
+ "Show specifications for all contexts that match given tags"
+ (interactive)
+ (let ((tags-string (or tags (read-string (concat "Show specs matching these tags (default " *behave-default-tags* "): ")
+ nil nil *behave-default-tags*))))
+ (with-output-to-temp-buffer "*behave*"
+ (princ "Specifications:\n")
+ (mapcar #'specify-context (context-find-by-tags (mapcar 'intern (split-string tags-string " ")))))))
+
+(defun specify-context (context)
+ (princ (concat "\n" (context-description context) "...\n"))
+ (dolist (spec (context-specs context))
+ (princ (concat " * " (caddr spec) "\n"))))
+
+(provide 'behave)
--- /dev/null
+(setq rbdbgr-core "../rbdbgr-core.el")
+(load-file "./behave.el")
+(load-file rbdbgr-core)
+
+(behave-clear-contexts)
+
+(context "command argument processing: "
+ (tag cmd-args)
+ (lexical-let ((opt-two-args '("0" "C" "e" "E" "F" "i")))
+ (specify "Two args found, none remain afterwards though."
+ (expect
+ (rbdbgr-strip-command-arg '("-0" "a") '() opt-two-args)
+ equal nil))
+ (specify "Two args not found, strip first arg though."
+ (expect
+ (rbdbgr-strip-command-arg '("-5" "a" "-0") '() opt-two-args)
+ equal '("a" "-0")))
+ (specify "Degenerate case - no args"
+ (expect
+ (rbdbgr-strip-command-arg '() '() opt-two-args)
+ equal nil))
+
+ (specify "Strip ruby and its arg."
+ (expect
+ (rbdbgr-get-script-name
+ '("/usr/bin/ruby1.9" "-W" "rbdbgr" "foo"))
+ equal '("foo" nil)))
+
+ (specify "ruby with two args and rbdbgr with two args"
+ (expect
+ (rbdbgr-get-script-name
+ '("ruby1.9" "-T3" "rbdbgr" "--port" "123" "bar"))
+ equal '("bar" nil)))
+
+ (specify "rbdbgr with annotate args"
+ (expect
+ (rbdbgr-get-script-name
+ '("rbdbgr" "--port 123" "--annotate=3" "foo"))
+ equal '("foo" t)))
+
+ (specify "rbdbgr with emacs"
+ (expect
+ (rbdbgr-get-script-name
+ '("ruby" "-I/usr/lib/ruby" "rbdbgr" "-h" "foo"
+ "--emacs" "baz"))
+ equal '("baz" t)))
+
+ ;; FIXME: move to another file.
+ (specify "ruby-mode? with Lisp file"
+ (expect
+ (rbdbgr-file-ruby-mode? rbdbgr-core) equal nil))
+ ;; (specify "ruby-mode? with Ruby file"
+ ;; ;; Set major mode to Ruby-mode
+ ;; (expect
+ ;; (rbdbgr-file-ruby-mode? rbdbgr-core) equal t))
+ ))
+
+
+
+(behave "cmd-args")
+
--- /dev/null
+(load-file "./behave.el")
+(load-file "../dbgr-loc.el")
+(load-file "../dbgr-file.el")
+
+(behave-clear-contexts)
+
+(lexical-let ((filename (symbol-file 'behave)))
+
+ (context "dbgr-file-line-count: "
+ (tag file)
+ (specify "File not found"
+ (expect (dbgr-file-line-count "not-found-file") equal nil))
+ (specify "File found"
+ (expect (integerp (dbgr-file-line-count filename)) t))
+ )
+
+ (context "dbgr-file-loc-from-line: "
+ (tag file)
+ (specify "File not found"
+ (expect (stringp (dbgr-file-loc-from-line "not-found-file" 5)) t))
+ (specify "invalid real line number"
+ (expect (stringp (dbgr-file-loc-from-line filename 5.5)) t))
+ (specify "negative number"
+ (expect (stringp (dbgr-file-loc-from-line filename -1)) t))
+ (specify "Line number too large for file"
+ (expect (stringp (dbgr-file-loc-from-line filename 10001)) t))
+ (specify "Line number too large for file"
+ (expect (dbgr-loc-p (dbgr-file-loc-from-line filename 30)) t))
+ ))
+(behave "file")
+
--- /dev/null
+(load-file "./behave.el")
+(load-file "../dbgr-load.el")
+
+(defun setup()
+ (setq loc-current (symbol-file 'dbgr-loc-current))
+ (if loc-current
+ (progn
+ (fmakunbound 'dbgr-loc-current)
+ (setq load-history '())
+ (load-file "../dbgr-load.el")))
+ (setq dbgr-loc-file (concat (dbgr-directory) "dbgr-loc.el")))
+
+(behave-clear-contexts)
+
+(context "rdbg-load: "
+ (tag load)
+ (specify "Initialized history"
+ (setup)
+ (expect (symbol-file 'dbgr-loc-current) equal nil))
+ (specify "Read el file when none exists"
+ (dbgr-require-relative "dbgr-loc.el" t)
+ (expect (symbol-file 'dbgr-loc-current) equal
+ dbgr-loc-file))
+ (setup)
+ ;; Try byte compiling a file and then rereading
+ (setq dbgr-loc-file-compiled (concat dbgr-loc-file "c"))
+ (unless (file-readable-p dbgr-loc-file-compiled)
+ (byte-compile-file dbgr-loc-file))
+ (if (file-readable-p dbgr-loc-file-compiled)
+ (progn
+ (dbgr-require-relative "dbgr-loc.elc" nil)
+ (specify "Read elc file when we already have read in an el file"
+ (dbgr-require-relative (file-name-nondirectory
+ dbgr-loc-file-compiled))
+ (expect (symbol-file 'dbgr-loc-current) equal
+ dbgr-loc-file-compiled))
+ ;; (setup)
+ ;; (specify "Read el file by default when we already
+ ;; have read in an elc file"
+ ;; (dbgr-require-relative "rdbg-loc" t)
+ ;; (expect (symbol-file 'dbgr-loc-current) equal
+ ;; dbgr-loc-file))
+ )))
+
+(behave "load")
+
--- /dev/null
+(load-file "./behave.el")
+(load-file "../dbgr-loc.el")
+
+(behave-clear-contexts)
+
+(lexical-let ((saved-buffer (current-buffer)))
+ ; Below, we need to make sure current-buffer has an associated
+ ; file with it.
+ (find-file (symbol-file 'behave))
+
+ (context "location field extraction: "
+ (tag loc)
+ (lexical-let* ((filename (buffer-file-name (current-buffer)))
+ (marker (point-marker))
+ (good-loc (make-dbgr-loc
+ :filename filename
+ :line-number 5
+ :marker marker))
+ (good-loc2 (make-dbgr-loc
+ :filename filename
+ :line-number 6))
+ (good-loc3 (dbgr-loc-current)))
+
+ (specify "line-number extraction"
+ (expect (dbgr-loc-line-number good-loc) equal 5))
+ (specify "marker extraction"
+ (expect (dbgr-loc-marker good-loc) equal marker))
+
+ (specify "marker set"
+ (dbgr-loc-marker= good-loc2 marker)
+ (expect (dbgr-loc-marker good-loc2) equal marker))
+
+ ))
+ (switch-to-buffer saved-buffer))
+(behave "loc")
+
+; TODO: add test for debug-loc-goto, e.g.
+;(dbgr-loc-goto (dbgr-loc-new "/tmp/bashdb.diff" 8))
+;(dbgr-loc-goto (dbgr-loc-new "/tmp/bashdb.diff" 8) 'other-window 1)
+
+
--- /dev/null
+(load-file "./behave.el")
+(load-file "../dbgr-loc.el")
+(load-file "../dbgr-lochist.el")
+
+(behave-clear-contexts)
+
+;;; (defun setup()
+;;; (lexical-let ((loc-hist (make-dbgr-loc-hist))
+;;; (filename (buffer-file-name (current-buffer)))
+;;; (loc (dbgr-loc-current)))
+;;; (dbgr-loc-hist-add loc-hist loc)))
+;;; ;; (message "aa ring-index %s"
+;;; ;; (dbgr-loc-hist-index loc-hist))))
+
+;;; (setup)
+
+
+(lexical-let ((saved-buffer (current-buffer)))
+ ; Below, we need to make sure current-buffer has an associated
+ ; file with it.
+ (find-file (symbol-file 'behave))
+
+ (context "location ring initialization and fields access: "
+ (tag lochist)
+ (lexical-let ((loc-hist (make-dbgr-loc-hist))
+ (filename (buffer-file-name (current-buffer)))
+ (loc (dbgr-loc-current)))
+
+ (specify "get ring component for a new history ring"
+ (expect (ring-p (dbgr-loc-hist-ring loc-hist)) t))
+
+ (specify "ring position for an empty history ring is -1"
+ (expect (dbgr-loc-hist-position loc-hist)
+ equal -1))
+
+ (specify "get item for an empty history ring"
+ (expect (dbgr-loc-hist-item loc-hist) equal nil))
+
+ (specify "add an item to an empty history ring"
+ (dbgr-loc-hist-add loc-hist loc)
+ (expect (dbgr-loc-hist-item loc-hist) equal loc))
+
+ (specify "One item in history ring"
+ (expect (ring-length
+ (dbgr-loc-hist-ring loc-hist))
+ equal 1))
+
+ (specify "ring index in history ring is 1"
+ (expect (dbgr-loc-hist-index loc-hist) equal 1))
+
+ (specify "duplicate item added is ignored"
+ (dbgr-loc-hist-add loc-hist loc)
+ (expect (ring-length
+ (dbgr-loc-hist-ring loc-hist))
+ equal 1))
+
+ (specify "ring index in history ring after dup ignore is still 1"
+ (expect (dbgr-loc-hist-index loc-hist) equal 1))
+
+
+ (specify "Set to newest position"
+ (expect (dbgr-loc-hist-newest loc-hist) equal -1))
+
+ ))
+ (behave "lochist")
+ (switch-to-buffer saved-buffer))
+
--- /dev/null
+(load-file "./behave.el")
+(load-file "../dbgr-regexp.el")
+(load-file "../dbgr-procbuf-var.el")
+
+(behave-clear-contexts)
+
+
+; Some setup usually done in setting up the buffer.
+; We customize this for the debugger rbdbgr. Others may follow.
+; FIXME: encapsulate this.
+(setq dbg-name "rbdbgr")
+(setq loc-pat (gethash dbg-name dbgr-pat-hash))
+
+(setq dbgr (make-dbgr-info
+ :name dbg-name
+ :loc-regexp (dbgr-loc-pat-regexp loc-pat)
+ :file-group (dbgr-loc-pat-file-group loc-pat)
+ :line-group (dbgr-loc-pat-line-group loc-pat)))
+
+
+(defun loc-match(text)
+ (string-match (dbgr-info-loc-regexp dbgr) text)
+)
+
+(context "location matching: "
+ (tag regexp)
+ (lexical-let ((text ".. (./dbgrr.rb:73)")
+ (text2 "C> ((eval):1 via /tmp/eval2.rb:2)")
+ (text3 "-- (<internal:prelude>:28 remapped prelude.rb:28)")
+ (text4 "-- (/src/external-vcs/dbgrr/processor/command/info_subcmd/registers_subcmd/dfp.rb:2)\nrequire_relative %w(.. .. base subsubcmd)\n")
+ )
+ (specify "basic location"
+ (expect (numberp (loc-match text)) t))
+ (specify "extract file name"
+ (expect (match-string (dbgr-info-file-group dbgr)
+ text)
+ equal "./dbgrr.rb"))
+ (specify "extract line number"
+ (expect (match-string (dbgr-info-line-group dbgr)
+ text)
+ equal "73"))
+ (specify "more compex location"
+ (expect (numberp (loc-match text4)) t))
+
+
+ ;; Now try via
+ (specify "basic via location"
+ (expect (numberp (loc-match text2)) t))
+ (specify "extract via file name"
+ (expect (match-string (dbgr-info-file-group dbgr)
+ text2)
+ equal "/tmp/eval2.rb"))
+ (specify "extract via line number"
+ (expect (match-string (dbgr-info-line-group dbgr)
+ text2)
+ equal "2"))
+
+ ;; Now try remap
+ (specify "basic via location"
+ (expect (numberp (loc-match text3)) t))
+
+ ;;
+ (specify "unmatched location"
+ (setq text "--> #0 METHOD Object#square(x) in file ./rbdbgr.rb at line 73")
+ (expect (numberp (loc-match text)) equal nil))
+
+ ))
+
+(behave "regexp")
+
--- /dev/null
+(load-file "./behave.el")
+(load-file "../ruby/rbdbgr-regexp.el")
+
+(behave-clear-contexts)
+
+
+(setq tb (gethash "traceback" rbdbgr-pat-hash))
+
+(defun tb-loc-match(text)
+ (string-match (dbgr-loc-pat-regexp tb) text)
+)
+
+;; FIXME: we get a void variable somewhere in here when running
+;; even though we define it in lexical-let. Dunno why.
+;; setq however will workaround this.
+(setq text " from /usr/local/bin/irb:12:in `<main>'")
+(context "traceback location matching: "
+ (tag regexp-rbdbgr)
+ (lexical-let ((text " from /usr/local/bin/irb:12:in `<main>'"))
+ (specify "basic traceback location"
+ (expect (numberp (tb-loc-match text)) t))
+ (specify "extract file name"
+ (expect (match-string (dbgr-loc-pat-file-group tb)
+ text)
+ equal "/usr/local/bin/irb")))
+ (specify "extract line number"
+ (expect (match-string (dbgr-loc-pat-line-group tb)
+ text)
+ equal "12"))
+ )
+
+(behave "regexp-rbdbgr")
+
--- /dev/null
+(load-file "./behave.el")
+(load-file "../dbgr-regexp.el")
+(load-file "../dbgr-loc.el")
+(load-file "../dbgr-procbuf-var.el")
+(load-file "../dbgr-track.el")
+
+(behave-clear-contexts)
+
+;; Some setup usually done in setting up the buffer.
+;; We customize this for the debugger rbdbgr. Others may follow.
+;; FIXME: encapsulate this.
+(setq dbg-name "rbdbgr")
+(setq loc-pat (gethash dbg-name dbgr-pat-hash))
+
+;; dbgr-info is supposed to exist in the process buffer
+;; and be buffer local
+(make-variable-buffer-local 'dbgr-info)
+(setq dbgr-info (make-dbgr-info
+ :name dbg-name
+ :loc-regexp (dbgr-loc-pat-regexp loc-pat)
+ :file-group (dbgr-loc-pat-file-group loc-pat)
+ :line-group (dbgr-loc-pat-line-group loc-pat)))
+
+;; FIXME/WARNING the below is customized for rbdbgr
+(lexical-let* ((filename (symbol-file 'behave))
+ (line-number 7)
+ (debugger-output (format "-> (%s:%d)\n(rbdbgr):\n"
+ filename line-number))
+ (loc (dbgr-track-loc debugger-output)))
+
+ (context "dbgr-track: "
+ (tag track)
+ (specify "loc extracted"
+ (expect (dbgr-loc-p loc) t))
+ (specify "loc filename extracted"
+ (expect (dbgr-loc-filename loc) equal filename))
+ (specify "loc line-number extracted"
+ (expect (dbgr-loc-line-number loc) equal line-number))
+ ))
+
+(behave "track")
+