]> code.delx.au - gnu-emacs-elpa/commitdiff
Start the Grand Unified Debugger Rewrite.
authorrockyb <rocky@gnu.org>
Wed, 28 Oct 2009 17:23:47 +0000 (13:23 -0400)
committerrockyb <rocky@gnu.org>
Wed, 28 Oct 2009 17:23:47 +0000 (13:23 -0400)
33 files changed:
.gitignore [new file with mode: 0644]
AUTHORS [new file with mode: 0644]
ChangeLog [new file with mode: 0644]
Makefile.am [new file with mode: 0644]
NEWS [new file with mode: 0644]
README [new file with mode: 0644]
configure.ac [new file with mode: 0644]
dbgr-file.el [new file with mode: 0644]
dbgr-load.el [new file with mode: 0644]
dbgr-loc.el [new file with mode: 0644]
dbgr-lochist.el [new file with mode: 0644]
dbgr-procbuf-var.el [new file with mode: 0644]
dbgr-regexp.el [new file with mode: 0644]
dbgr-scriptbuf-var.el [new file with mode: 0644]
dbgr-track-mode.el [new file with mode: 0644]
dbgr-track.el [new file with mode: 0644]
dbgr-window.el [new file with mode: 0644]
ruby/.gitignore [new file with mode: 0644]
ruby/rbdbgr-core.el [new file with mode: 0644]
ruby/rbdbgr-regexp.el [new file with mode: 0644]
ruby/rbdbgr-track-mode.el [new file with mode: 0644]
ruby/rbdbgr.el [new file with mode: 0644]
test/.gitignore [new file with mode: 0644]
test/Makefile [new file with mode: 0644]
test/behave.el [new file with mode: 0644]
test/test-core.el [new file with mode: 0644]
test/test-file.el [new file with mode: 0644]
test/test-load.el [new file with mode: 0644]
test/test-loc.el [new file with mode: 0644]
test/test-lochist.el [new file with mode: 0644]
test/test-regexp.el [new file with mode: 0644]
test/test-regexp2.el [new file with mode: 0644]
test/test-track.el [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..84971f8
--- /dev/null
@@ -0,0 +1,16 @@
+/*.elc
+/*~
+/COPYING
+/INSTALL
+/Makefile
+/Makefile.in
+/aclocal.m4
+/autom4te.cache
+/config.log
+/config.status
+/configure
+/elc-stamp
+/elc-temp
+/elisp-comp
+/install-sh
+/missing
diff --git a/AUTHORS b/AUTHORS
new file mode 100644 (file)
index 0000000..ab69da5
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1 @@
+rockyb@rubyforge.org
diff --git a/ChangeLog b/ChangeLog
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/Makefile.am b/Makefile.am
new file mode 100644 (file)
index 0000000..2b2698a
--- /dev/null
@@ -0,0 +1,48 @@
+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
+
+
+
+
diff --git a/NEWS b/NEWS
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..7a4ed60
--- /dev/null
+++ b/README
@@ -0,0 +1 @@
+Here we have code to facilitate rbdbgr-Emacs interaction.
diff --git a/configure.ac b/configure.ac
new file mode 100644 (file)
index 0000000..97cc2c0
--- /dev/null
@@ -0,0 +1,13 @@
+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
diff --git a/dbgr-file.el b/dbgr-file.el
new file mode 100644 (file)
index 0000000..bf4a5c8
--- /dev/null
@@ -0,0 +1,54 @@
+; 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)
+
diff --git a/dbgr-load.el b/dbgr-load.el
new file mode 100644 (file)
index 0000000..02af0cb
--- /dev/null
@@ -0,0 +1,64 @@
+(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)
diff --git a/dbgr-loc.el b/dbgr-loc.el
new file mode 100644 (file)
index 0000000..6e3218f
--- /dev/null
@@ -0,0 +1,52 @@
+;;; 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)
diff --git a/dbgr-lochist.el b/dbgr-lochist.el
new file mode 100644 (file)
index 0000000..1fbb647
--- /dev/null
@@ -0,0 +1,109 @@
+;;; 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
diff --git a/dbgr-procbuf-var.el b/dbgr-procbuf-var.el
new file mode 100644 (file)
index 0000000..76856d3
--- /dev/null
@@ -0,0 +1,22 @@
+;;; 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
diff --git a/dbgr-regexp.el b/dbgr-regexp.el
new file mode 100644 (file)
index 0000000..bc10948
--- /dev/null
@@ -0,0 +1,89 @@
+;;; 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
diff --git a/dbgr-scriptbuf-var.el b/dbgr-scriptbuf-var.el
new file mode 100644 (file)
index 0000000..080ae6c
--- /dev/null
@@ -0,0 +1,28 @@
+;;; 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
diff --git a/dbgr-track-mode.el b/dbgr-track-mode.el
new file mode 100644 (file)
index 0000000..d3dc8b9
--- /dev/null
@@ -0,0 +1,86 @@
+;;  `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
diff --git a/dbgr-track.el b/dbgr-track.el
new file mode 100644 (file)
index 0000000..567106c
--- /dev/null
@@ -0,0 +1,181 @@
+;;; 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
diff --git a/dbgr-window.el b/dbgr-window.el
new file mode 100644 (file)
index 0000000..1b1333a
--- /dev/null
@@ -0,0 +1,9 @@
+(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)))
+
diff --git a/ruby/.gitignore b/ruby/.gitignore
new file mode 100644 (file)
index 0000000..aeaec0f
--- /dev/null
@@ -0,0 +1 @@
+/*~
diff --git a/ruby/rbdbgr-core.el b/ruby/rbdbgr-core.el
new file mode 100644 (file)
index 0000000..353bab7
--- /dev/null
@@ -0,0 +1,373 @@
+;; -------------------------------------------------------------------
+;; 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
diff --git a/ruby/rbdbgr-regexp.el b/ruby/rbdbgr-regexp.el
new file mode 100644 (file)
index 0000000..2f36d30
--- /dev/null
@@ -0,0 +1,45 @@
+;;; 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
diff --git a/ruby/rbdbgr-track-mode.el b/ruby/rbdbgr-track-mode.el
new file mode 100644 (file)
index 0000000..6c23f9a
--- /dev/null
@@ -0,0 +1,67 @@
+;;; 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
diff --git a/ruby/rbdbgr.el b/ruby/rbdbgr.el
new file mode 100644 (file)
index 0000000..44640a1
--- /dev/null
@@ -0,0 +1,40 @@
+;;  `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
+
diff --git a/test/.gitignore b/test/.gitignore
new file mode 100644 (file)
index 0000000..aeaec0f
--- /dev/null
@@ -0,0 +1 @@
+/*~
diff --git a/test/Makefile b/test/Makefile
new file mode 100644 (file)
index 0000000..bc80236
--- /dev/null
@@ -0,0 +1,7 @@
+# Whatever it is you want to do, it should be forwarded to the 
+# to top-level irectories
+PHONY=check all
+all: check
+
+%: 
+       $(MAKE) -C .. $@
diff --git a/test/behave.el b/test/behave.el
new file mode 100644 (file)
index 0000000..f5743c2
--- /dev/null
@@ -0,0 +1,224 @@
+;;; 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)
diff --git a/test/test-core.el b/test/test-core.el
new file mode 100644 (file)
index 0000000..46a8cf0
--- /dev/null
@@ -0,0 +1,61 @@
+(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")
+
diff --git a/test/test-file.el b/test/test-file.el
new file mode 100644 (file)
index 0000000..ac38ab9
--- /dev/null
@@ -0,0 +1,31 @@
+(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")
+
diff --git a/test/test-load.el b/test/test-load.el
new file mode 100644 (file)
index 0000000..ed73464
--- /dev/null
@@ -0,0 +1,46 @@
+(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")
+
diff --git a/test/test-loc.el b/test/test-loc.el
new file mode 100644 (file)
index 0000000..85b2724
--- /dev/null
@@ -0,0 +1,41 @@
+(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)
+
+
diff --git a/test/test-lochist.el b/test/test-lochist.el
new file mode 100644 (file)
index 0000000..124fa01
--- /dev/null
@@ -0,0 +1,67 @@
+(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))
+
diff --git a/test/test-regexp.el b/test/test-regexp.el
new file mode 100644 (file)
index 0000000..341f4e4
--- /dev/null
@@ -0,0 +1,70 @@
+(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")
+
diff --git a/test/test-regexp2.el b/test/test-regexp2.el
new file mode 100644 (file)
index 0000000..6da0859
--- /dev/null
@@ -0,0 +1,33 @@
+(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")
+
diff --git a/test/test-track.el b/test/test-track.el
new file mode 100644 (file)
index 0000000..18404a8
--- /dev/null
@@ -0,0 +1,42 @@
+(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")
+