Fork me on GitHub

@ssanders Yes, you can do this. I don’t have much documentation for this yet, but I spoke a couple of years ago about the debugger, and I demo exactly what you’re asking about:


@U0567Q30W thanks for this. I actually watched this video (most of it) a few weeks ago and have been loving the use of the debugger in cursive. My particular use case though, hasn't been seeming to work.. if I set up a super simple ring web server and place a linebreak in the editor, then use a curl to hit the server, I can see the response in the terminal where I issued the curl command, but I don't see the linebreaks stopping the code execution. Think I may be missing something super obvious but can't put my finger on it


Do you see the breakpoint being active in the gutter? If IntelliJ can’t find the corresponding bytecode to the line, it’ll be like a grey crossed out circle.


It does look like it's getting greyed out once I start the debugger


Is there a way to help intellij find the bytecode?


One thing to try is setting the breakpoint, then starting your app and then re-loading the file containing the breakpoint.


That will cause Clojure to re-compile the file exactly matching what’s in your editor.


Re-loading the file is also required if you’ve just switched locals clearing off.


It's weird. The second I send the file to the repl I see a red message in the repl window and then the line break goes away.

Loading src/clj_ring/core.clj... 2019-10-31 22:00:13.209:INFO::nRepl-session-99305752-ae04-43f3-bf11-5b9398ba6c43: Logging initialized @17709ms to org.eclipse.jetty.util.log.StdErrLog


Hmm, that’s very strange.


Debugging can be very strange, and I can’t always explain what I see either, but that sounds stranger than usual.


I'm actually just trying it with a simple hello world -

(ns clj_ring.core
  (:use ring.adapter.jetty))

(defn handler [request]
  {:status 200}
  :headers {"Content-Type" "text/plain"}
  :body "Hello World")

(run-jetty handler {:port 8080})


Where are you putting the breakpoint? On the map inside the handler?


yeah, or .. on the defn handler line


Try doing something like:

(let [result {your map here...}]


And then putting the breakpoint on the let line. I’m actually not sure what executable bytecode Clojure generates when just returning a constant map like that.


There may not be enough for the debugger to hang off.


IIRC constant maps are generated just as constants in the class pool, and the code to return that may not be generated with line info.


blerg. no luck there


Would you mind uploading your hello world project to GH or somewhere so I can try it out?


sure thing


Thanks, give me a moment to wrap up what I’m doing.


Absolutely. Thanks for your help


You’re right, I cannot for the life of me get that to stop in the handler.


I made a few changes, I put your run-jetty in a comment block like this:

  (jetty/run-jetty handler {:port 3000 :join? false}))


That then means that it won’t run Jetty and block until it finishes when you load the file.


So you can then reload the file, and just use “Run top form” to start the Jetty server. It won’t block when you execute that because of the :join? false so you can then continue to use the REPL.


I see the problem


Your namespace is called clj_ring.core - it should be called clj-ring.core.


So when Clojure compiles, it can’t use - in package names because Java. So it maps them to _. But that’s a lossy transformation, so Cursive (and a lot of other tooling) assumes that when it sees a compiled class with an underscore in the name, that it comes from a namespace/function with a dash in the original name.


There’s no way to tell which of the two the original was named.


I need an inspection to warn about that, clearly.


You can just change the name in the ns form, and then everything works. The name of the directory on the filesystem should remain the same (with _)


no no, that's something I should have seen, I'm just extreme noob. But I've just changed that and still seeing the line break getting greyed out, is that not happening for you?


Did you re-load the file after changing the name?


Wait a minute, I’m now not seeing it work either.


I swear that worked a minute ago.


Ok, if I completely shut down and then re-start the REPL, it works for me.


There must have been something a bit funky in the debugger state.


There’s still something weird going on, though. It now makes my breakpoint into a circle with a tick, which means that it’s found the bytecode corresponding to the line information. But when I hit the server it doesn’t stop.


Ok, here’s what’s going on. When the server is started, it must be getting the actual function instance of the handler function rather than the var, and caches that. So then when I re-load the namespace, that function object is not updated.


If I re-start the server, it then stops correctly.


It's weird I still haven't been able to make it stop


And yes, I think I should have been more descriptive, I think that's the same circle logo I'm seeing - with a tick


This is what the breakpoint should look like.


So I have seen it stop, but I can’t make it do it again.


There’s something strange going on, but I don’t know what.


I thought that by passing the var (`#'handler`) to run-jetty that it would then re-load since it will then look up the function every time it’s invoked.


Similarly with what I’m doing there delegating through handler-fn.


But neither of those work reliably.


Ok, it’s something to do with the let block, for some reason.


Here’s what works for me. Make sure you pass the var itself to run-jetty like this:

  (def server (jetty/run-jetty #'handler {:port 3000 :join? false})))


That will cause the function stored in the handler var to be looked up each time it’s called, which will allow you to re-load the code without restarting the server.


Then, if I make my handler look like this:

(defn handler [request]
  (println "Hello")
  (let [result {:status  200
                :headers {"Content-Type" "text/plain"}
                :body    "Hello World"}]


Then it will break reliably on the println line.


oh snap, I see it now.


I guess the code generated for the let returning a constant map doesn’t generate any line numbers in the bytecode or something.


But weird that the let isn't working... yeah


Let me know if that works for you.


but yeah this works for me, I can totally use it in my project. Just need a way to step in.


Thanks a mil!


No problem! That was a combination of weird things. Once you have some actual code in your handler, everything should hopefully work.


the debugger is wonderful 🙂


@sogaiu Thanks, I also like it 🙂


I use it all the time.


it's really great for learning about clojure internals too! it's a gem of the clojure tooling world, imho.


I have a maybe slighty annoying request. Whenever you paste text that has some html tags, Cursive shows a popup asking to convert it to Hiccup. This seemed like a nice unexpected feature, but I paste HTML multiple times a day, but don’t use hiccup at all, so I have to click away the alert every time. It would be nice to have the option to not show it again or something…


I'm guessing, that is a so called Intention which you can disable in preferences, although when I search for hiccup in preferences, nothing turns up 😕


No, it’s not an intention. I’ll add the ability to disable that.


@U05469DKJ Would you prefer the ability to convert to something other than hiccup? Why are you pasting HTML into Clojure code?


We are storing user created content, which is rich formatted text. This is stored as simple HTML (just some <p>,<b>,<i>,etc tags). I often copy and paste an example input in the REPL.


I don’t need to convert it. An option to disable it would be great


instead of converting html into hiccup automatically (and having an option to enable/disable it), it would be great if cursive offered a context menu item such as "Paste HTML as Hiccup", something like this:


I could do that, but I think it would affect the discoverability. I could perhaps have both, where the explicit “Paste as Hiccup” option wouldn’t prompt, and the prompt for the standard paste could have a “Don’t ask me this again” option.

👍 4
Ben Hammond14:11:59

is there a way to interrupt the repl from displaying the last form I pressed 'Interrupt Current Evaluation` button and now I'm waiting for e n o r m o u s form to be written to the repl a 'don't bother writing the rest of tthis to the repl` button would be extremely helpful


Well, rather, no, there isn’t a way to do it, but it’s something I’m going to add 🙂

Ben Hammond14:11:33

(I'm going to kill that repl java process now)

Adrian Smith22:11:57

How do I get cursive to start understanding some of these symbols?

Adrian Smith22:11:42

oh the pom file from running shadow-cljs pom and then the mavern plugin has helped somewhat

Adrian Smith22:11:49

oh and I think from the sounds of it I need a fake project.clj for cursive to understand what a phaser is?


I also use shadow-cljs, and I find it much easier to work with Cursive when I use deps.edn and add :deps true to shadow-cljs.edn.