-
Notifications
You must be signed in to change notification settings - Fork 179
Conditional breakpoints #303
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conditional breakpoints #303
Conversation
Wow. First of all, thanks a ton! :-) I'll make some comments directly in the code, but overall I like how you've implemented it. |
@@ -139,10 +143,10 @@ | |||
;;; `wrap-debug` receives an initial message from the client, stores | |||
;;; it in `debugger-message`, and `breakpoint` answers it when asking | |||
;;; for input. | |||
(def debugger-message |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm fine with this change, but I'd rather leave it to a separate commit (unless it has some relation to this feature).
I pushed a PR for a rudimentary version of the front-end portion, here: clojure-emacs/cider#1591 |
;; If there is a condition and it is falsy, we need to skip | ||
;; the current level (:deeper than parent coor), but only | ||
;; once. Next time, we need to test the condition again. | ||
(binding [*skip-breaks* (if skip?# |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need :deeper? Isn't that the same as skipping everything inside this binding
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My thinking at the time was that if the "skipped" form calls another function which is instrumented, we do want to stop in the debugger, and that using :all
would prevent that. I can add some test cases to verify.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point!
And yes, a test case would be nice.
e9e00a3
to
4a7ab0e
Compare
@Malabarba, I pushed a commit that addresses all your comments, I think. I pared back the functionality to be just the basic conditional break. I removed the special-casing of defns that moved the condition down into the body of the fn. I can re-introduce that in another PR, where we can discuss the best interface. I also added a few more tests, including one (unrelated to conditional breakpoints) that I think should pass but does not. Can you have a look at Thanks! |
Ok, thanks! I'll have a look at the tests when I get a chance. 👍 |
Also some new, high-level tests for the debugger.
4a7ab0e
to
df91bb7
Compare
I rebased this onto master and pushed again |
Ok. Looks like your tests are good. The only 2 failures are the cljs tests which are also failing on master. I've also tested your code locally and it seems to work well. |
Ok. This should now be on clojar. |
Not entirely ready, but I would like to get some more eyes on this and see whether others agree with the approach.
The feature is conditional breakpoints - that is, breakpoints that will only enter the debugger when an expression is truthy.
Conditions are attached to forms as
:break/when
metadata. Example:Evaluating this, you will stop in the debugger only once, when
i
is 1.However, the primary use case (at least for me) is likely to be instrumenting a function with a conditional breakpoint. I have implemented this in cider as
C-u C-u C-M-x
, which prompts for an expression. This can be an expression of the function arguments. The form is then sent to cider-nrepl with#dbg ^{:break/when (the expression)}
prefixed.Making this work required a slightly hairy special-case that moves
:break/when
metadata down from the defn form and onto the forms inside the body of the macroexpanded function.To get some confidence that I have the slightest idea what I'm doing, I wrote a bunch of new tests, in a new test namespace. These interact with cider-nrepl only by sending and receiving nrepl messages, just as a client (i.e. emacs) would.
Thanks everyone, please let me know what you think.