From aebd72c07077efc9917d00d08bdb0c14ea554421 Mon Sep 17 00:00:00 2001 From: Artur Malabarba Date: Thu, 17 Dec 2015 00:47:36 +0000 Subject: [PATCH] Implement the :here debug action This action takes a coords vector in the message, and tells the debugger to skip any breakpoints before that. --- src/cider/nrepl/middleware/debug.clj | 41 +++++++++++++++---- .../clj/cider/nrepl/middleware/debug_test.clj | 9 ++++ 2 files changed, 42 insertions(+), 8 deletions(-) diff --git a/src/cider/nrepl/middleware/debug.clj b/src/cider/nrepl/middleware/debug.clj index e78851f1a..eec27d17c 100644 --- a/src/cider/nrepl/middleware/debug.clj +++ b/src/cider/nrepl/middleware/debug.clj @@ -62,11 +62,30 @@ Its value is discarded at the end each eval session." nil) +(defn coord< + "Return true if coordinate x comes before y. + Here, \"comes before\" means that a sexp at coord x is evaluated + before a sexp at coord y (assuming a trivial code-flow)." + [x y] + (if (seq x) + (if (seq y) + (let [fa (first x) + fb (first y)] + (if (= fa fb) + (recur (rest x) (rest y)) + (< fa fb))) + ;; If coord `x` goes deeper than `y`, then is `x < y`. + true) + false)) + (defn skip-breaks? "True if the breakpoint at coordinates should be skipped. - If *skip-breaks* is true, return true. - If *skip-breaks* is a vector of integers, return true if coordinates - are deeper than this vector." + If the first element of `*skip-breaks*` is :all, return true. + + Otherwise, the first element should be :deeper or :before. + If :deeper, return true if the given coordinates are deeper than the + rest of `*skip-breaks*`. If :before, return true if they represent a + place before the rest." [coordinates] (when-let [[mode & skip-coords] @*skip-breaks*] (case mode @@ -75,11 +94,13 @@ ;; From :out, skip some breaks. :deeper (let [parent (take (count skip-coords) coordinates)] (and (= skip-coords parent) - (> (count coordinates) (count parent))))))) + (> (count coordinates) (count parent)))) + ;; From :here, skip some breaks. + :before (coord< coordinates skip-coords)))) (defn skip-breaks! "Set the value of *skip-breaks* for the top-level breakpoint. - If bool-or-vec is a vector, mode should be :deeper (see + If bool-or-vec is a vector, mode should be :deeper or :before (see `skip-breaks?`). Otherwise mode should be :all or false." [mode & [bool-or-vec]] (reset! *skip-breaks* (when mode @@ -234,18 +255,22 @@ a :code entry, its value is used for operations such as :eval, which would otherwise interactively prompt for an expression." [value extras] - (let [commands (cond->> [:next :continue :out :inspect :locals :inject :eval :quit] + (let [commands (cond->> [:next :continue :out :here :inspect :locals :inject :eval :quit] (not (map? *msg*)) (remove #{:quit}) (cljs/grab-cljs-env *msg*) identity) response-raw (read-debug extras commands nil) - {:keys [code response page-size] :or {page-size 32}} (if (map? response-raw) response-raw - {:response response-raw}) + + {:keys [code coord response page-size] :or {page-size 32}} + (if (map? response-raw) response-raw + {:response response-raw}) extras (dissoc extras :inspect)] (case response :next value :continue (do (skip-breaks! :all) value) :out (do (skip-breaks! :deeper (butlast (:coor extras))) value) + :here (do (skip-breaks! :before coord) + value) :locals (inspect-then-read-command value extras page-size *locals*) :inspect (->> (read-debug-eval-expression "Inspect value: " extras code) (inspect-then-read-command value extras page-size)) diff --git a/test/clj/cider/nrepl/middleware/debug_test.clj b/test/clj/cider/nrepl/middleware/debug_test.clj index 8a40c29be..fdf272208 100644 --- a/test/clj/cider/nrepl/middleware/debug_test.clj +++ b/test/clj/cider/nrepl/middleware/debug_test.clj @@ -4,6 +4,15 @@ [clojure.tools.nrepl.transport :as t] [cider.nrepl.middleware.debug :as d])) +(deftest coord< + (are [a b] (and (d/coord< a b) + (not (d/coord< b a))) + [1] [] + [0] [1] + [1] [2] + [1 2] [1 3] + [1 0] [1])) + (deftest skip-breaks (binding [d/*skip-breaks* (atom [:all])] (is (#'d/skip-breaks? []))