Request or help if exists already - `#js` reader syntax in cljs interop
riotrah opened this issue · 9 comments
I write a lot of cljs, and thus a lot of js interop. This frequently involves use of #js {:my-key ""}
and #js [""]
I'm not sure what it is about my config, which is otherwise really great, but whenever a hang or flow are warranted (line too long, or explicitly configured, etc), the #js
ends up on its own line.
Is that expected behavior? Is there, or could there be, a config option to keep #js
always adjacent (left of) the subsequent form, whilst maintaining the rest of the hang/flow?
I think I'm going to need your config and an actual example to make progress on this. When I try it with the default config, it does exactly what you want:
(czprint i292 {:parse-string? true :width 50})
(defn i292
[x y]
(let [this-is (a-test this
is
only
a
test
#js {:my-key ""})]
(vector? this-is)))
I checked, and it has worked like this for a good long time in the past.
Something in your configuration must be triggering the problem, so if you give me an example and your config, I'll figure out what it is and see what I can to do to prevent it. Thanks!
Oh interesting. Thanks for the promptness and intense dedication as always, @kkinnear.
Apologies for the verbose configs (namely the fn-map
s, which I'm probably doing innefficiently and redundantly across my user & repo configs)
Here's my _user_ config:
{:fn-map {":require" [:flow {:list {:indent 2
:indent-arg 2}}]
"$" [:gt2-force-nl {:list {:hang? true}
:map {:force-nl? true}}]
"$r" [:gt2-force-nl {:list {:hang? true}
:map {:force-nl? true}}]
"->" [:arg1-force-nl {:list {:hang? true}}]
"->>" [:arg1-force-nl {:list {:hang? true}}]
".then" [:arg1-force-nl {:list {:hang? true}}]
"<>" [:arg1-force-nl {:list {:hang? true}
:map {:force-nl? true}}]
"cond" :pair-fn
;; "cond->" [:pair {:list {:hang? true}}]
"cond->>" [:arg1-force-nl {:list {:hang? true}}]
"css" :arg1-force-nl
"cx" :arg1-force-nl
"def" [:arg1-force-nl {:list {:hang? false}}]
"defn" [:arg1-force-nl {:list {:hang? false}}]
"defnc" :arg2
"fnc" :arg1
"defhook" :arg1-force-nl
"use-effect" :flow
"defstory" :arg1-force-nl
"deftest" [:arg1-force-nl {:list {:hang? false
:respect-bl? true}}]
"deftest-chain" [:arg1-force-nl {:list {:hang? false}}]
;; "fn" :gt2-force-nl
"fn*" [:replace-w-string {:list {:replacement-string "#"}}]
;; "if" :arg1-force-nl
"if" :hang
"into" :arg1-force-nl
;; "is" [:arg1 {:list {:hang? true}}]
"js-await" [:binding {:list {:hang? false}}]
"merge" :arg1-force-nl
"quote" [:replace-w-string {:list {:replacement-string "'"}}]
"reg-event-db" :flow
"reg-event-fx" :flow
"testing" [:arg1-force-nl {:list {:hang? false}}]
"use-*" :arg1
"when" :arg1-force-nl
"when-not" :arg1-force-nl}
:list {:indent-arg 2}
:map {:comma? false
:force-nl? true
:justify? true}
:pair {:hang? true
:justify? false}
:search-config? true
:style [:community :hiccup :how-to-ns]
:vector {:wrap-after-multi? true
:wrap? true}
:width 120}
Here's my _repo_ config:
{:binding {:flow? false
:force-nl? true
:hang-diff 10
:hang-expand 5000
:hang? true
:indent 2
:justify {:ignore-for-variance nil
;; :lhs-narrow 2.0
:max-variance 1000
:no-justify #{"_"}}
:justify? false
:nl-separator? true}
:comment {:inline-align-style :consecutive
:inline? true
:wrap? true}
:fn-map {"$" [:gt2-force-nl {:list {:hang? true}
:map {:force-nl? true}}]
"$r" [:gt2-force-nl {:list {:hang? true}
:map {:force-nl? true}}]
"->" :hang
;; "->" [:arg1-force-nl {:list {:hang? true
;; :indent 4
;; :indent-arg 4}}]
"->>" [:arg1-force-nl {:list {:hang? true}}]
".then" [:arg1-force-nl {:list {:hang? true}}]
;; :default :arg1
:default :hang
"concat" :hang
"gobj/set" [:arg1 {:list {:hang? true
:indent-arg 10}}]
":require" [:flow {:list {:indent 2
:indent-arg 2}}]
":require-macros" :force-nl
"<>" [:arg1-force-nl {:list {:hang? true}
:map {:force-nl? true}}]
"assoc" [:arg1-pair {:pair-fn {:hang? true}
:pair {:hang? true
:flow? false}}]
"cond" :pair-fn
"cond->>" [:arg1-> {:list {:hang? true}}]
"css" [:arg1-force-nl {:list {:hang? true}}]
"d/div" :flow
"def" [:arg1-force-nl {:list {:hang? false}}]
"defcss" [:arg1-force-nl {:list {:hang? false}}]
"defn" [:arg1-force-nl {:list {:hang? false}}]
"defnc" [:arg1-force-nl {:list {:hang? false}}]
"defnc-" [:arg1-force-nl {:list {:hang? false}}]
"defstory" [:arg1-force-nl {:list {:hang? true}}]
"deftest" [:arg1-force-nl {:list {:hang? false
:respect-bl? true}
:next-inner-restore [[:list :hang?] [:list :respect-bl?]]}]
"deftest-chain" [:arg1-force-nl {:list {:hang? false}
:next-inner-restore [[:list :hang?]
[:list :respect-bl?]]}]
"fn" :fn
"fn*" [:replace-w-string {:list {:replacement-string "#"}}]
"for-map" :binding
"if" [:hang {:list {:hang? true}}]
"into" [:arg1-force-nl {:list {:hang? true}}]
"is" [:arg1 {:list {:hang? true}}]
"js-await" [:binding {:list {:hang? false}}]
"let" :binding
"merge" :hang
"ns" [:arg1-force-nl {:list {:hang? false}}]
"quote" [:replace-w-string {:list {:replacement-string "'"}}]
"reg-event-db" :flow
"reg-event-fx" :flow
"testing" [:arg1-force-nl {:list {:hang? false}
:next-inner-restore [[:list :hang?] [:list :respect-bl?]]}]
"when" [:arg1-force-nl {:list {:hang? true}}]
"when-not" [:arg1-force-nl {:list {:hang? true}}]}
:list {:hang? true}
:map {:comma? false
:force-nl? true
:hang? true
:justify? false}
;; :pair {:hang? true}
;; :pair-fn {:hang? true}
:search-config? true
;; :width 80}
:width 100}
;; :width 120}
Thanks for the configurations. That didn't provoke the problem, interestingly enough. It seems like, using the default configuration, that you get the #js
on a line by itself when the map after it doesn't fit on the same line. Like this:
(defn i292
[x y]
(let [this-is (a-test this
#js
{:your-key "",
:a-very-long-key :and-a-very-long-value,
:a-second-key :and-a-second-value}
a
test
#js {:my-key ""}
not
the
end)]
(vector? this-is)))
Notice the two #js
elements above.
Questions:
- I think the first
#js
is what you don't like and the second is what you do like. Is this correct? - Is this the behavior that you see? That is, are the places where
#js
appears on its own line places where the thing following it would not fit on the same line as the#js
? - Do you ever see things like the second
#js
, where the next thing stays on the same line as the#js
?
Thanks!
- Yes, tho needs some upcoming context
- Yep
- Yep! I neglected to even notice that as all of my usages of that recently have been for somewhat larger/nested pojos/maps
Your first example comes close, tho it's a more "justifiable" (?) case for a separate line #js
, imo.
But here's a real-er case:
suppose there's a max width set somewhere near the end of the longest line
Before:
#js {:a "b"}
#js {:detail (or signature (str "[" (name (or category "")) "]"))
:documentation (when description
#js {:value description})
:insertText (if function? (str/upper-case insert-text) insert-text)
:insertTextRules (when snippet
insert-as-snippet-rule)
:kind kind
:label s
:filterText (str/upper-case s)
:sortText (str/lower-case (str sort-text-prefix " " s))}))
After zprint:
#js {:a "b"}
#js
{:detail (or signature (str "[" (name (or category "")) "]"))
:documentation (when description
#js {:value description})
:insertText (if function? (str/upper-case insert-text) insert-text)
:insertTextRules (when snippet
insert-as-snippet-rule)
:kind kind
:label s
:filterText (str/upper-case s)
:sortText (str/lower-case (str sort-text-prefix " " s))}))
I'm not sure how I'd configure zprint to do what my preferred output would look like:
Preferred:
#js {:a 'b}
#js {:detail (or signature
(str "[" (name (or category "")) "]"))
:documentation (when description
#js {:value description})
:insertText (if function?
(str/upper-case insert-text)
insert-text)
:insertTextRules (when snippet
insert-as-snippet-rule)
:kind kind
:label s
:filterText (str/upper-case s)
:sortText (str/lower-case (str sort-text-prefix
" " s))}
The specifics of where exactly all of the newlines should be or when to hang/flow/etc are less relevant (for this demo at least) than the main point being to start "breaking" the lines in the map before considering placing the #js
on its own line. Ie, I'd rather have a map with multiline rhs values before I'd have a map whose #js
is a line above it.
Does that make sense?
Yes, it makes a lot of sense.
It is worth knowing that you can't configure zprint to do it the way you want. At least I haven't found any way to do that. I am experimenting with a code change that will do it the way you want, which I think is probably what most people would want too. I'm currently looking at how to get it to go back to the not-great way it does it now in case someone really wants that.
Wow thanks so much for exploring this wow!!!!!!
In 1.2.6
the #js
will try to put the next thing on the same line, as you want it, by default. There will be a new configuration element in the option map: :tagged-literal
which will be configurable in such a way that if someone wants it the way it is today, they can configure it that way by setting{:tagged-literal {:hang? false}}
. I'll let you know when 1.2.6
is available.
wow thanks again dude!
I just released 1.2.6
. The changes I made to format tagged literals are the default, so you should see what you want without anything other than upgrading. Thanks for pointing this out!