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

Add ClojureScript support to the debugger #1416

Open
Malabarba opened this Issue Nov 13, 2015 · 11 comments

Comments

Projects
None yet
8 participants
@Malabarba
Member

Malabarba commented Nov 13, 2015

The debugger simply fails if used in ClojureScript code, it would be nice for it to work.

Here's a list of things to achieve that. If anyone can help with any of these items, it will likely save me a lot of researching down the road. So please don't be shy.

  • (trivial) Change the debug middleware from cljs/expects-piggieback to cljs/requires-piggieback.
  • Ensure that the #dbg and #break reader tags are active when the cljs code is read. This is done in Clojure via our data_readers.clj file at the classpath root, is there a similar file for ClojureScript?
  • Currently instrumentation is done by ensuring that tools.nrepl uses our instrument-and-eval function instead of the plain eval (see debug.clj). I'm not sure how to do this in piggieback.
  • instrument.clj should work as is. It parses the code (which is still Clojure data even with cljs code), and it wraps parts of it in some code of our own.
  • The debugger then works by running some CIDER code inside the user's code. This code therefore needs to be defined in the cljs environment.

The last item is hardest. The code in question is just one macro and a few functions in debug.clj. These needs to be defined in the cljs environment, which probably means they'll have to be moved to a cljc file (or duplicated in a cljs file).

The problem is that this code interacts with tools.nrepl, which (IIUC) is impossible to do from the cljs environment. So it'll likely involved a deep rethinking of how the debugger works.
Reimplementing the first version of the debugger in cljs might be the solution (it prompted the user directly instead of using the nrepl).

@divs1210

This comment has been minimized.

Show comment
Hide comment
@divs1210

divs1210 Feb 21, 2016

Hey, @Malabarba ! Thanks for the list of things to start off from. I'm new to Emacs and CIDER, but would like to give this a shot.

divs1210 commented Feb 21, 2016

Hey, @Malabarba ! Thanks for the list of things to start off from. I'm new to Emacs and CIDER, but would like to give this a shot.

@sfrdmn

This comment has been minimized.

Show comment
Hide comment
@sfrdmn

sfrdmn Aug 4, 2016

Any thoughts on a setting for simply ignoring the fact you're in a CLJS file and just interpreting the forms as plain Clojure? I guess it'll work fine in a lot of cases and if it's documented + opt-in, shouldn't be too problematic?

sfrdmn commented Aug 4, 2016

Any thoughts on a setting for simply ignoring the fact you're in a CLJS file and just interpreting the forms as plain Clojure? I guess it'll work fine in a lot of cases and if it's documented + opt-in, shouldn't be too problematic?

@Malabarba

This comment has been minimized.

Show comment
Hide comment
@Malabarba

Malabarba Aug 4, 2016

Member

I think M-x clojure-mode might work.

Member

Malabarba commented Aug 4, 2016

I think M-x clojure-mode might work.

@sfrdmn

This comment has been minimized.

Show comment
Hide comment
@sfrdmn

sfrdmn Aug 4, 2016

So it does! Thanks 👍

sfrdmn commented Aug 4, 2016

So it does! Thanks 👍

zlrth added a commit to getsparket/first-fly that referenced this issue May 21, 2017

integration test in finance-test ns.
made the finance.clj a cljc
because cljs files can't be debugged with
cider's debugger.
clojure-emacs/cider#1416
it will probably be used exclusively on the cljs side
as we have no clj backend or anything now.
@doubleagent

This comment has been minimized.

Show comment
Hide comment
@doubleagent

doubleagent Mar 1, 2018

2nd time this week Cider has prompted me to visit this page.

doubleagent commented Mar 1, 2018

2nd time this week Cider has prompted me to visit this page.

@NightMachinary

This comment has been minimized.

Show comment
Hide comment
@NightMachinary

NightMachinary May 8, 2018

How does Cursive manage this?

NightMachinary commented May 8, 2018

How does Cursive manage this?

@bbatsov

This comment has been minimized.

Show comment
Hide comment
@bbatsov

bbatsov May 8, 2018

Member

No idea. It's not open-source so we can't easily check.

Member

bbatsov commented May 8, 2018

No idea. It's not open-source so we can't easily check.

@cursive-ide

This comment has been minimized.

Show comment
Hide comment
@cursive-ide

cursive-ide May 8, 2018

@NightMachinary @bbatsov Very simple - it doesn't :-). Cursive can only debug JVM clojure right now.

cursive-ide commented May 8, 2018

@NightMachinary @bbatsov Very simple - it doesn't :-). Cursive can only debug JVM clojure right now.

@bendlas

This comment has been minimized.

Show comment
Hide comment
@bendlas

bendlas Jun 12, 2018

So, the biggest problem with having a debugger based on instrumented code in JavaScript, is, that unlike the JVM, you can't block your thread to wait for input from the debugging frontend. This leaves two likely approaches: Debugging via the runtime's debugger interface (e.g. via debugger.html) and relying on source maps to recover the cider experience, or, doing a CPS transformation on the source.

I honestly can't decide, what feels to be more work, but ultimately, CPS feels more in-line with the spirit in the existing debugger, of instrumenting the source. A remote-control debugger would totally be worth doing, though, and I'm sure that an RDP-based debugger, targetting Clojure and ClojureScript could be a great success as well.

That said, let me try to sell you on an even crazier idea, than doing CPS on ClojureScript code: Doing CPS on JavaScript code. That would (theoretically) enable debugging callbacks coming from javascript frameworks.

I decided to explore existing CPS solutions for JavaScript, and there are some, most of them seem to focus on providing some syntax for explicit passing, but jwacs stood out, not just because it takes its job of doing the heavy lifting for providing true continuations, seriously, but also because it's written in CommonLisp, so working with it reminded me of how Clojure with Emacs should feel ;-)

Initial results on some snippets and even a 2.4M advanced minified JS seemed promising, after fixing some minor issues

I so far found three features missing:

  • finally clauses are documented as missing chumsley/jwacs#4
  • geters, seters, necessary to deal with in some way, because they can't be transpiled away chumsley/jwacs#5
  • breaks from labelled-statement-blocks, a rather obscure language feature, used by gclosure advanced

After implementing labelled statement blocks to get acquainted with the code base, I'm pretty confident, that I (and you too) can make it work for everything we need, including the above issues.

If you're interested in helping with this, I'm currently in the process of getting acquainted with cider-debug-middleware's internals. In particular, I'd like to figure out, how to run some hand-crafted code in a clojurescript runtime, to contact cider-debug-middleware with a break-point.

TLDR;
A jwacs-based cps-transformer could be run in a separate server, processing JavaScript, instrumented with breakpoints based on function_continuation, suspend and resume, as per jwacs-doc.

bendlas commented Jun 12, 2018

So, the biggest problem with having a debugger based on instrumented code in JavaScript, is, that unlike the JVM, you can't block your thread to wait for input from the debugging frontend. This leaves two likely approaches: Debugging via the runtime's debugger interface (e.g. via debugger.html) and relying on source maps to recover the cider experience, or, doing a CPS transformation on the source.

I honestly can't decide, what feels to be more work, but ultimately, CPS feels more in-line with the spirit in the existing debugger, of instrumenting the source. A remote-control debugger would totally be worth doing, though, and I'm sure that an RDP-based debugger, targetting Clojure and ClojureScript could be a great success as well.

That said, let me try to sell you on an even crazier idea, than doing CPS on ClojureScript code: Doing CPS on JavaScript code. That would (theoretically) enable debugging callbacks coming from javascript frameworks.

I decided to explore existing CPS solutions for JavaScript, and there are some, most of them seem to focus on providing some syntax for explicit passing, but jwacs stood out, not just because it takes its job of doing the heavy lifting for providing true continuations, seriously, but also because it's written in CommonLisp, so working with it reminded me of how Clojure with Emacs should feel ;-)

Initial results on some snippets and even a 2.4M advanced minified JS seemed promising, after fixing some minor issues

I so far found three features missing:

  • finally clauses are documented as missing chumsley/jwacs#4
  • geters, seters, necessary to deal with in some way, because they can't be transpiled away chumsley/jwacs#5
  • breaks from labelled-statement-blocks, a rather obscure language feature, used by gclosure advanced

After implementing labelled statement blocks to get acquainted with the code base, I'm pretty confident, that I (and you too) can make it work for everything we need, including the above issues.

If you're interested in helping with this, I'm currently in the process of getting acquainted with cider-debug-middleware's internals. In particular, I'd like to figure out, how to run some hand-crafted code in a clojurescript runtime, to contact cider-debug-middleware with a break-point.

TLDR;
A jwacs-based cps-transformer could be run in a separate server, processing JavaScript, instrumented with breakpoints based on function_continuation, suspend and resume, as per jwacs-doc.

@bbatsov

This comment has been minimized.

Show comment
Hide comment
@bbatsov

bbatsov Jun 17, 2018

Member

@bendlas It's nice to see someone interested in fixing this! Let me know if you need any assistance from me!

I don't know almost anything about ClojureScript, but I know a thing or two about CIDER. :-)

Member

bbatsov commented Jun 17, 2018

@bendlas It's nice to see someone interested in fixing this! Let me know if you need any assistance from me!

I don't know almost anything about ClojureScript, but I know a thing or two about CIDER. :-)

@bendlas

This comment has been minimized.

Show comment
Hide comment
@bendlas

bendlas Jun 17, 2018

@bbatsov theat's great, thanks for offering!
I'm currently trying to understand how piggieback communicates with the rest of nrepl. For some reason, on a piggieback-ed cljs connection, I don't see any more messages coming through the debug middleware ... we can discuss more interactively on the #cider slack ...

bendlas commented Jun 17, 2018

@bbatsov theat's great, thanks for offering!
I'm currently trying to understand how piggieback communicates with the rest of nrepl. For some reason, on a piggieback-ed cljs connection, I don't see any more messages coming through the debug middleware ... we can discuss more interactively on the #cider slack ...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment