{"action":"created","comment":{"url":"https://api.github.com/repos/clojure-emacs/cider-nrepl/pulls/comments/54269743","id":54269743,"diff_hunk":"@@ -346,20 +350,40 @@\n (defmacro breakpoint\n   \"Send the result of form and its coordinates to the client.\n   Sends a response to the message stored in debugger-message.\"\n+  [form {:keys [coor]} original-form]\n+  `(let [val# ~form]\n+     (cond\n+       (skip-breaks? ~coor) val#\n+       ;; The length of `coor` is a good indicator of current code\n+       ;; depth.\n+       (= (first @*skip-breaks*) :trace)\n+       (do (print-step-indented ~(count coor) '~original-form val#)\n+           val#)\n+       ;; Nothing special. Here's the actual breakpoint logic.\n+       :else (->> (pr-short val#)\n+                  (assoc *extras* :debug-value)\n+                  (read-debug-command val#)))))\n+\n+(defmacro maybe-breakpoint\n+  \"Same as `breakpoint` unless there is a condition attached to the\n+  form as `:break/when` metadata, and it is falsy.\"\n   [form {:keys [coor] :as extras} original-form]\n-  `(with-debug-bindings ~extras\n-     (let [val# ~form]\n-       (cond\n-         (skip-breaks? ~coor) val#\n-         ;; The length of `coor` is a good indicator of current code\n-         ;; depth.\n-         (= (first @*skip-breaks*) :trace)\n-         (do (print-step-indented ~(count coor) '~original-form val#)\n-             val#)\n-         ;; Nothing special. Here's the actual breakpoint logic.\n-         :else (->> (pr-short val#)\n-                    (assoc *extras* :debug-value)\n-                    (read-debug-command val#))))))\n+  (let [has-condition? (contains? (meta form) :break/when)\n+        condition      (:break/when (meta form))\n+        parent-coor    (vec (butlast coor))]\n+    (if has-condition?\n+      `(with-debug-bindings ~extras\n+         (let [skip?# (not ~condition)]\n+           ;; If there is a condition and it is falsy, we need to skip\n+           ;; the current level (:deeper than parent coor), but only\n+           ;; once. Next time, we need to test the condition again.\n+           (binding [*skip-breaks* (if skip?#","path":"src/cider/nrepl/middleware/debug.clj","position":78,"original_position":78,"commit_id":"e9e00a30664fe6efbfdf6711275a30f533bd34fd","original_commit_id":"e9e00a30664fe6efbfdf6711275a30f533bd34fd","user":{"login":"Malabarba","id":453029,"avatar_url":"https://avatars.githubusercontent.com/u/453029?v=3","gravatar_id":"","url":"https://api.github.com/users/Malabarba","html_url":"https://github.com/Malabarba","followers_url":"https://api.github.com/users/Malabarba/followers","following_url":"https://api.github.com/users/Malabarba/following{/other_user}","gists_url":"https://api.github.com/users/Malabarba/gists{/gist_id}","starred_url":"https://api.github.com/users/Malabarba/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Malabarba/subscriptions","organizations_url":"https://api.github.com/users/Malabarba/orgs","repos_url":"https://api.github.com/users/Malabarba/repos","events_url":"https://api.github.com/users/Malabarba/events{/privacy}","received_events_url":"https://api.github.com/users/Malabarba/received_events","type":"User","site_admin":false},"body":"Do we need :deeper? Isn't that the same as skipping everything inside this `binding`?","created_at":"2016-02-26T16:58:52Z","updated_at":"2016-02-26T16:58:52Z","html_url":"https://github.com/clojure-emacs/cider-nrepl/pull/303#discussion_r54269743","pull_request_url":"https://api.github.com/repos/clojure-emacs/cider-nrepl/pulls/303","_links":{"self":{"href":"https://api.github.com/repos/clojure-emacs/cider-nrepl/pulls/comments/54269743"},"html":{"href":"https://github.com/clojure-emacs/cider-nrepl/pull/303#discussion_r54269743"},"pull_request":{"href":"https://api.github.com/repos/clojure-emacs/cider-nrepl/pulls/303"}}},"pull_request":{"url":"https://api.github.com/repos/clojure-emacs/cider-nrepl/pulls/303","id":60847423,"html_url":"https://github.com/clojure-emacs/cider-nrepl/pull/303","diff_url":"https://github.com/clojure-emacs/cider-nrepl/pull/303.diff","patch_url":"https://github.com/clojure-emacs/cider-nrepl/pull/303.patch","issue_url":"https://api.github.com/repos/clojure-emacs/cider-nrepl/issues/303","number":303,"state":"open","locked":false,"title":"Conditional breakpoints","user":{"login":"grammati","id":94716,"avatar_url":"https://avatars.githubusercontent.com/u/94716?v=3","gravatar_id":"","url":"https://api.github.com/users/grammati","html_url":"https://github.com/grammati","followers_url":"https://api.github.com/users/grammati/followers","following_url":"https://api.github.com/users/grammati/following{/other_user}","gists_url":"https://api.github.com/users/grammati/gists{/gist_id}","starred_url":"https://api.github.com/users/grammati/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/grammati/subscriptions","organizations_url":"https://api.github.com/users/grammati/orgs","repos_url":"https://api.github.com/users/grammati/repos","events_url":"https://api.github.com/users/grammati/events{/privacy}","received_events_url":"https://api.github.com/users/grammati/received_events","type":"User","site_admin":false},"body":"Not entirely ready, but I would like to get some more eyes on this and see whether others agree with the approach.\r\n\r\nThe feature is conditional breakpoints - that is, breakpoints that will only enter the debugger when an expression is truthy.\r\n\r\nConditions are attached to forms as `:break/when` metadata. Example:\r\n\r\n```clojure\r\n(for [i (range 3)]\r\n  #dbg ^{:break/when (odd? i)\r\n  (inc i))\r\n```\r\n\r\nEvaluating this, you will stop in the debugger only once, when `i` is 1.\r\n\r\nHowever, 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.\r\n\r\nMaking 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.\r\n\r\nTo 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.\r\n\r\nThanks everyone, please let me know what you think.\r\n","created_at":"2016-02-26T14:16:20Z","updated_at":"2016-02-26T16:58:52Z","closed_at":null,"merged_at":null,"merge_commit_sha":"137ce5a2da471330e4afa510b46f31a6e2e6b6cf","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/clojure-emacs/cider-nrepl/pulls/303/commits","review_comments_url":"https://api.github.com/repos/clojure-emacs/cider-nrepl/pulls/303/comments","review_comment_url":"https://api.github.com/repos/clojure-emacs/cider-nrepl/pulls/comments{/number}","comments_url":"https://api.github.com/repos/clojure-emacs/cider-nrepl/issues/303/comments","statuses_url":"https://api.github.com/repos/clojure-emacs/cider-nrepl/statuses/e9e00a30664fe6efbfdf6711275a30f533bd34fd","head":{"label":"grammati:conditional-break-squashed","ref":"conditional-break-squashed","sha":"e9e00a30664fe6efbfdf6711275a30f533bd34fd","user":{"login":"grammati","id":94716,"avatar_url":"https://avatars.githubusercontent.com/u/94716?v=3","gravatar_id":"","url":"https://api.github.com/users/grammati","html_url":"https://github.com/grammati","followers_url":"https://api.github.com/users/grammati/followers","following_url":"https://api.github.com/users/grammati/following{/other_user}","gists_url":"https://api.github.com/users/grammati/gists{/gist_id}","starred_url":"https://api.github.com/users/grammati/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/grammati/subscriptions","organizations_url":"https://api.github.com/users/grammati/orgs","repos_url":"https://api.github.com/users/grammati/repos","events_url":"https://api.github.com/users/grammati/events{/privacy}","received_events_url":"https://api.github.com/users/grammati/received_events","type":"User","site_admin":false},"repo":{"id":40772765,"name":"cider-nrepl","full_name":"grammati/cider-nrepl","owner":{"login":"grammati","id":94716,"avatar_url":"https://avatars.githubusercontent.com/u/94716?v=3","gravatar_id":"","url":"https://api.github.com/users/grammati","html_url":"https://github.com/grammati","followers_url":"https://api.github.com/users/grammati/followers","following_url":"https://api.github.com/users/grammati/following{/other_user}","gists_url":"https://api.github.com/users/grammati/gists{/gist_id}","starred_url":"https://api.github.com/users/grammati/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/grammati/subscriptions","organizations_url":"https://api.github.com/users/grammati/orgs","repos_url":"https://api.github.com/users/grammati/repos","events_url":"https://api.github.com/users/grammati/events{/privacy}","received_events_url":"https://api.github.com/users/grammati/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/grammati/cider-nrepl","description":"nREPL middleware for CIDER","fork":true,"url":"https://api.github.com/repos/grammati/cider-nrepl","forks_url":"https://api.github.com/repos/grammati/cider-nrepl/forks","keys_url":"https://api.github.com/repos/grammati/cider-nrepl/keys{/key_id}","collaborators_url":"https://api.github.com/repos/grammati/cider-nrepl/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/grammati/cider-nrepl/teams","hooks_url":"https://api.github.com/repos/grammati/cider-nrepl/hooks","issue_events_url":"https://api.github.com/repos/grammati/cider-nrepl/issues/events{/number}","events_url":"https://api.github.com/repos/grammati/cider-nrepl/events","assignees_url":"https://api.github.com/repos/grammati/cider-nrepl/assignees{/user}","branches_url":"https://api.github.com/repos/grammati/cider-nrepl/branches{/branch}","tags_url":"https://api.github.com/repos/grammati/cider-nrepl/tags","blobs_url":"https://api.github.com/repos/grammati/cider-nrepl/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/grammati/cider-nrepl/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/grammati/cider-nrepl/git/refs{/sha}","trees_url":"https://api.github.com/repos/grammati/cider-nrepl/git/trees{/sha}","statuses_url":"https://api.github.com/repos/grammati/cider-nrepl/statuses/{sha}","languages_url":"https://api.github.com/repos/grammati/cider-nrepl/languages","stargazers_url":"https://api.github.com/repos/grammati/cider-nrepl/stargazers","contributors_url":"https://api.github.com/repos/grammati/cider-nrepl/contributors","subscribers_url":"https://api.github.com/repos/grammati/cider-nrepl/subscribers","subscription_url":"https://api.github.com/repos/grammati/cider-nrepl/subscription","commits_url":"https://api.github.com/repos/grammati/cider-nrepl/commits{/sha}","git_commits_url":"https://api.github.com/repos/grammati/cider-nrepl/git/commits{/sha}","comments_url":"https://api.github.com/repos/grammati/cider-nrepl/comments{/number}","issue_comment_url":"https://api.github.com/repos/grammati/cider-nrepl/issues/comments{/number}","contents_url":"https://api.github.com/repos/grammati/cider-nrepl/contents/{+path}","compare_url":"https://api.github.com/repos/grammati/cider-nrepl/compare/{base}...{head}","merges_url":"https://api.github.com/repos/grammati/cider-nrepl/merges","archive_url":"https://api.github.com/repos/grammati/cider-nrepl/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/grammati/cider-nrepl/downloads","issues_url":"https://api.github.com/repos/grammati/cider-nrepl/issues{/number}","pulls_url":"https://api.github.com/repos/grammati/cider-nrepl/pulls{/number}","milestones_url":"https://api.github.com/repos/grammati/cider-nrepl/milestones{/number}","notifications_url":"https://api.github.com/repos/grammati/cider-nrepl/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/grammati/cider-nrepl/labels{/name}","releases_url":"https://api.github.com/repos/grammati/cider-nrepl/releases{/id}","deployments_url":"https://api.github.com/repos/grammati/cider-nrepl/deployments","created_at":"2015-08-15T17:03:00Z","updated_at":"2016-01-23T11:10:24Z","pushed_at":"2016-02-26T13:54:57Z","git_url":"git://github.com/grammati/cider-nrepl.git","ssh_url":"git@github.com:grammati/cider-nrepl.git","clone_url":"https://github.com/grammati/cider-nrepl.git","svn_url":"https://github.com/grammati/cider-nrepl","homepage":null,"size":789,"stargazers_count":0,"watchers_count":0,"language":"Clojure","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"clojure-emacs:master","ref":"master","sha":"e2b25b2c4b6871943943f7c1569f61b756cc9ac1","user":{"login":"clojure-emacs","id":5080083,"avatar_url":"https://avatars.githubusercontent.com/u/5080083?v=3","gravatar_id":"","url":"https://api.github.com/users/clojure-emacs","html_url":"https://github.com/clojure-emacs","followers_url":"https://api.github.com/users/clojure-emacs/followers","following_url":"https://api.github.com/users/clojure-emacs/following{/other_user}","gists_url":"https://api.github.com/users/clojure-emacs/gists{/gist_id}","starred_url":"https://api.github.com/users/clojure-emacs/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/clojure-emacs/subscriptions","organizations_url":"https://api.github.com/users/clojure-emacs/orgs","repos_url":"https://api.github.com/users/clojure-emacs/repos","events_url":"https://api.github.com/users/clojure-emacs/events{/privacy}","received_events_url":"https://api.github.com/users/clojure-emacs/received_events","type":"Organization","site_admin":false},"repo":{"id":15360927,"name":"cider-nrepl","full_name":"clojure-emacs/cider-nrepl","owner":{"login":"clojure-emacs","id":5080083,"avatar_url":"https://avatars.githubusercontent.com/u/5080083?v=3","gravatar_id":"","url":"https://api.github.com/users/clojure-emacs","html_url":"https://github.com/clojure-emacs","followers_url":"https://api.github.com/users/clojure-emacs/followers","following_url":"https://api.github.com/users/clojure-emacs/following{/other_user}","gists_url":"https://api.github.com/users/clojure-emacs/gists{/gist_id}","starred_url":"https://api.github.com/users/clojure-emacs/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/clojure-emacs/subscriptions","organizations_url":"https://api.github.com/users/clojure-emacs/orgs","repos_url":"https://api.github.com/users/clojure-emacs/repos","events_url":"https://api.github.com/users/clojure-emacs/events{/privacy}","received_events_url":"https://api.github.com/users/clojure-emacs/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/clojure-emacs/cider-nrepl","description":"nREPL middleware for CIDER","fork":false,"url":"https://api.github.com/repos/clojure-emacs/cider-nrepl","forks_url":"https://api.github.com/repos/clojure-emacs/cider-nrepl/forks","keys_url":"https://api.github.com/repos/clojure-emacs/cider-nrepl/keys{/key_id}","collaborators_url":"https://api.github.com/repos/clojure-emacs/cider-nrepl/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/clojure-emacs/cider-nrepl/teams","hooks_url":"https://api.github.com/repos/clojure-emacs/cider-nrepl/hooks","issue_events_url":"https://api.github.com/repos/clojure-emacs/cider-nrepl/issues/events{/number}","events_url":"https://api.github.com/repos/clojure-emacs/cider-nrepl/events","assignees_url":"https://api.github.com/repos/clojure-emacs/cider-nrepl/assignees{/user}","branches_url":"https://api.github.com/repos/clojure-emacs/cider-nrepl/branches{/branch}","tags_url":"https://api.github.com/repos/clojure-emacs/cider-nrepl/tags","blobs_url":"https://api.github.com/repos/clojure-emacs/cider-nrepl/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/clojure-emacs/cider-nrepl/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/clojure-emacs/cider-nrepl/git/refs{/sha}","trees_url":"https://api.github.com/repos/clojure-emacs/cider-nrepl/git/trees{/sha}","statuses_url":"https://api.github.com/repos/clojure-emacs/cider-nrepl/statuses/{sha}","languages_url":"https://api.github.com/repos/clojure-emacs/cider-nrepl/languages","stargazers_url":"https://api.github.com/repos/clojure-emacs/cider-nrepl/stargazers","contributors_url":"https://api.github.com/repos/clojure-emacs/cider-nrepl/contributors","subscribers_url":"https://api.github.com/repos/clojure-emacs/cider-nrepl/subscribers","subscription_url":"https://api.github.com/repos/clojure-emacs/cider-nrepl/subscription","commits_url":"https://api.github.com/repos/clojure-emacs/cider-nrepl/commits{/sha}","git_commits_url":"https://api.github.com/repos/clojure-emacs/cider-nrepl/git/commits{/sha}","comments_url":"https://api.github.com/repos/clojure-emacs/cider-nrepl/comments{/number}","issue_comment_url":"https://api.github.com/repos/clojure-emacs/cider-nrepl/issues/comments{/number}","contents_url":"https://api.github.com/repos/clojure-emacs/cider-nrepl/contents/{+path}","compare_url":"https://api.github.com/repos/clojure-emacs/cider-nrepl/compare/{base}...{head}","merges_url":"https://api.github.com/repos/clojure-emacs/cider-nrepl/merges","archive_url":"https://api.github.com/repos/clojure-emacs/cider-nrepl/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/clojure-emacs/cider-nrepl/downloads","issues_url":"https://api.github.com/repos/clojure-emacs/cider-nrepl/issues{/number}","pulls_url":"https://api.github.com/repos/clojure-emacs/cider-nrepl/pulls{/number}","milestones_url":"https://api.github.com/repos/clojure-emacs/cider-nrepl/milestones{/number}","notifications_url":"https://api.github.com/repos/clojure-emacs/cider-nrepl/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/clojure-emacs/cider-nrepl/labels{/name}","releases_url":"https://api.github.com/repos/clojure-emacs/cider-nrepl/releases{/id}","deployments_url":"https://api.github.com/repos/clojure-emacs/cider-nrepl/deployments","created_at":"2013-12-21T15:27:38Z","updated_at":"2016-02-25T09:41:58Z","pushed_at":"2016-02-26T14:16:21Z","git_url":"git://github.com/clojure-emacs/cider-nrepl.git","ssh_url":"git@github.com:clojure-emacs/cider-nrepl.git","clone_url":"https://github.com/clojure-emacs/cider-nrepl.git","svn_url":"https://github.com/clojure-emacs/cider-nrepl","homepage":null,"size":860,"stargazers_count":225,"watchers_count":225,"language":"Clojure","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":67,"mirror_url":null,"open_issues_count":12,"forks":67,"open_issues":12,"watchers":225,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/clojure-emacs/cider-nrepl/pulls/303"},"html":{"href":"https://github.com/clojure-emacs/cider-nrepl/pull/303"},"issue":{"href":"https://api.github.com/repos/clojure-emacs/cider-nrepl/issues/303"},"comments":{"href":"https://api.github.com/repos/clojure-emacs/cider-nrepl/issues/303/comments"},"review_comments":{"href":"https://api.github.com/repos/clojure-emacs/cider-nrepl/pulls/303/comments"},"review_comment":{"href":"https://api.github.com/repos/clojure-emacs/cider-nrepl/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/clojure-emacs/cider-nrepl/pulls/303/commits"},"statuses":{"href":"https://api.github.com/repos/clojure-emacs/cider-nrepl/statuses/e9e00a30664fe6efbfdf6711275a30f533bd34fd"}}}}