arichiardi / replumb

ClojureScript plumbing for your self-hosted REPLs.
http://clojurescript.io
Eclipse Public License 1.0
210 stars 16 forks source link

Provide method of capturing standard output from eval without changing result #160

Closed jasongilman closed 8 years ago

jasongilman commented 8 years ago

I'd like to be able to capture the output during an eval so I can display it in the REPL. Is there an existing way to do this with Replumb that I've missed.

I could change the evaluated code so that if a user executes (foo 5) I actually send this:

(let [result (atom nil)
      output (with-out-str (reset! result (foo 5)))]
  {:output output
   :result @result})

The problem with that approach is that it breaks *1 behavior. I'd like to be able to capture the output from printlns etc without changing the result that's returned.

Let me say thanks for an awesome library. I'm adding a self hosted REPL to Proto REPL using Replumb and so far it's been pretty easy. I was even able to integrate completion using apropos. (Mostly it's missing the doc strings) Being able to use something like Replumb with Proto REPL in Atom means I can build a fully functional Clojure development and data visualization environment with no leiningen or Java dependencies.

arichiardi commented 8 years ago

Oh I extend this thanks to all the people that I have worked with on this, past bootstrapped cljs and cljs.js contributors included :)

About the problem, I don't really get it (oops) :smile: The result map returned inside the read-eval-call cb contains the result of the evaluation. It looks like you want to get all the replumb output, but the only meaningful output is already redirected as string as :value of the result map (even doc and source output).

Is there something else I am missing? Am I misinterpreting? Probably so...

You know the library was born in my mind in order to have a Clojurescript leiningen (or boot now) that would be way faster to execute :wink:

arichiardi commented 8 years ago

By the way the doc string might be missing because you need to hook your own IO to replumb. If you have not done it already the node demo probably shows this better...feel free to ping me on Slack for further questions.

jasongilman commented 8 years ago

I wasn't specific enough in the original issue. Imagine that foo does this:

(defn foo
  [x]
  (println x)
  (* 2 x))

What I was asking for was a way to get the result of (foo 5) from Replumb but also any output that was triggered during the call. That's so in a REPL I could display the output "5" from the println and the result in the right locations.

After thinking about it some I'm not sure if Replumb is the right place to implement this. I really want to redirect all JavaScript console.log calls to the REPL, not just from within Clojure code that was executed. I can use something like this approach to do that so it might be outside the scope of what Replumb should provide.

I'm leaving this open though because I could still see it being useful for Replumb to do this. You should think about making the evaluation handler receive messages like the ones that nREPL sends. nREPL and Replumb both have similar purposes in their desire to be a common interface for building REPLs. It would be nice if they had similar APIs. nREPLs sends maps with :out that contain anything that was output within the session that was executed.

What did you mean by "You know the library was born in my mind in order to have a Clojurescript leiningen (or boot now) that would be way faster to execute"?

I'll investigate the doc strings stuff later. I just haven't hooked that part up yet and I'm sure it will work. Thanks for the offer to help in slack.

arichiardi commented 8 years ago

Ok now it's clear but yes I think it is more log redirecting than something to add to replumb (btw the code above prints fine in node).

However I have not put much thought in that kind of redirect...replumb's responsibility should just to eval forms in a bootstrapped way. But again, do we consider println side effects as part of the evaluation result? Some can say the result is just nil.

About nrepl, well I consider this a layer, definitely a layer on top of replumb that accepts the commands and understands the protocol and evaluates using it...but maybe there is no obvious advantage over a ClojureScript JVM Repl here...

So many cool things to ponder :)))

About leiningen, if we could port it to node using (bootstrapped) ClojureScript maybe we would get a faster building tool :)

jasongilman commented 8 years ago

A combination of Planck and boot might provide that fast build experience. Planck is fast and allows you to write scripts. Running boot (or variant) might work though I'm unsure how much of Java that boot uses. @mfikes might know more about using Planck to do builds.

arichiardi commented 8 years ago

Yeah we use boot for all our projects, except this one ;) About Planck, at the moment it does not work on Linux, but it will at some point, I am sure.

mfikes commented 8 years ago

@jasongilman It is not quite the same as building a boot-based project, but Planck is used to build its website. There is an anoying unsolved bug mfikes/planck#88 that I bet would arise if you used Planck's sh capability to drive boot. Otherwise, Planck is trying to use itself to build itself where it can.

arichiardi commented 8 years ago

Closing this for now, as not properly replumb-related but thanks a lot for using this library!