cljs-devtools icon indicating copy to clipboard operation
cljs-devtools copied to clipboard

Feature: String with metadata mode

Open olivergeorge opened this issue 5 years ago • 4 comments

This is a feature idea.

I'm looking for a way to make my js/console.log display cleanly with and without cljs-devtools installed.

Motivating example

Today's job is a react native app. It's not always convenient to turn cljs-devtools on (e.g. two simulators) and it's helpful to look in the simulator logs sometimes (no cljs-devtool rendering).

Problems

  • js/console.log with regular clojure data types produces verbose/unreadable strings.
  • logging (serializing) large data structures can cause UX lag

Idea

Perhaps cljs-devtools could be adapted to look for metadata associated with a string (or string like) object.

Vaguely something like this could be used to prepare a "console.log friendly string" with some other protocol which cljs-devtools could detect...

(defn data-str [data]
  (binding [*print-level* 3 *print-length* 5]
    (specify! (pr-str data) IMeta (-meta [_] data)))))

(js/console.log (data-str {:a 1 :b (range 1000)}))

NOTE: this code doesn't work

Goal is to cover two cases

  • String form will work in all situations and not take too long to serialize.
  • If cljs-devtools is installed you can drill into metadata.

olivergeorge avatar Aug 27 '20 00:08 olivergeorge

Perhaps this could result in a better enable-console-print!

olivergeorge avatar Aug 28 '20 01:08 olivergeorge

I had no time to look into this yet. I believe you could achieve something similar with String object instead of using just plain js strings. The String object should be able to hold cljs metadata and should be presented as string in standard consoles.

Try something like this (from top of my head):

(specify! (js/String. (pr-str data)) IMeta (-meta [_] data)))))

darwin avatar Aug 28 '20 11:08 darwin

That partially solves the "string with metadata" issue.

cljs.user=> 
(defn data-str [data]
  (binding [*print-level* 3 *print-length* 5]
    (specify! (js/String. (pr-str data)) IMeta (-meta [_] data))))

cljs.user=> (data-str {:a (range 10)})
#object[String {:a (0 1 2 3 4 ...)}]

cljs.user=> (meta (data-str {:a (range 10)}))
{:a (0 1 2 3 4 5 6 7 8 9)}

But the console output associated with String objects isn't what we were hoping for...

Test: Just console.log(new String("I am a string")) in Chrome console (no cljs devtools)

image

Test: Just (js/console.log (js/String. "I am a string")) in metro bundler log

image

Test: Just (js/console.log (data-str {:a (range 10)})) in metro bundler log

image

Test: Just (js/console.log (data-str {:a (range 10)})) in chrome console with cljs devtools

image

olivergeorge avatar Aug 29 '20 03:08 olivergeorge

This is the best I've come up with

(defn log-data [& data]
  (binding [*print-level* 3 *print-length* 5]
    (let [s (apply pr-str data)
          d (specify! #js [] IMeta (-meta [_] data))]
      (js/console.log s d))))

(log-data :this {:is "a" :test (range 100)})

It looks fine from a metro bundler terminal.

LOG :this {:is "a", :test (0 1 2 3 4 ...)} []

I suspect cljs-devtools could be made to handle the "array with meta" better.

image

Still a bit ugly from console without devtools...

image

olivergeorge avatar Aug 29 '20 23:08 olivergeorge