2

Occasionally I would like to poke a result in the repl in other software. Is there a convenient way to copy the outcome of a function run in a repl to system clipboard? I know I can spit the result out to a file. I'm using mac os x.

sumek
  • 26,495
  • 13
  • 56
  • 75

1 Answers1

8

you can always rebind *out* special variable, to point to a new location. For example you could collect all your output to string:

user> (def result (java.io.StringWriter.))
#'user/result

user> (binding [*out* result]
        (println :aaa)
        (println :bbb))
nil

user> (str result)
":aaa\n:bbb\n"

this is a temporary binding, beaning that *out* would be intact outside the binding block:

user> (println :aaa)
:aaa
nil

also you could reset the out on a thread level using set!:

user> (def result (java.io.StringWriter.))
#'user/result

user> (set! *out* result)
#object[java.io.StringWriter 0x66c129d9 ""]

user> (println :aaa)
nil

user> (println :bbb)
nil

user> (str result)
":aaa\n:bbb\n"

then, you can put this string into clipboard using java.awt classes:

user> (import 'java.awt.Toolkit)
java.awt.Toolkit

user> (import 'java.awt.datatransfer.StringSelection)
java.awt.datatransfer.StringSelection

user> (.. Toolkit
          (getDefaultToolkit)
          (getSystemClipboard)
          (setContents (StringSelection. (str result)) nil))
nil

That's it. Now just paste it. Should work properly on mac.

Then you can just generalize it with a macro:

(defmacro with-clipboard [& body]
  `(binding [*out* (java.io.StringWriter.)]
     (let [result# (do ~@body)]
       (.. Toolkit
           (getDefaultToolkit)
           (getSystemClipboard)
           (setContents (StringSelection. (str *out*)) nil))
       result#)))

and use it like this:

user> (with-clipboard
        (println :hello)
        (println :clipboard)
        (+ 10 20))
;; => 30

and clipboard will contain:

:hello
:clipboard
leetwinski
  • 17,408
  • 2
  • 18
  • 42