kkinnear / zprint

Executables, uberjar, and library to beautifully format Clojure and Clojurescript source code and s-expressions.
MIT License
547 stars 46 forks source link

Different output of tagged literals in library vs shell #318

Open albertzak opened 1 month ago

albertzak commented 1 month ago
(zp/zprint-str 
  [{:a :b :c :d} (tagged-literal 'x {:e :f :g :h})]
  {:map {:comma? false}})
"[{:a :b :c :d} #x {:e :f, :g :h}]"

Expected the comma between :e :f, :g :h to not be there. Reproduced in cljs and babashka with zprint v1.2.9. Interestingly it prints as expected via bb zprint

echo "[{:a :b :c :d} #x {:e :f :g :h}]" | bb zprint "{:map {:comma? false}}"
[{:a :b :c :d} #x {:e :f :g :h}]
kkinnear commented 1 month ago

I'm sorry that you ran into this. I can reproduce it. I'm not sure yet what is going on, but I have some suspicions. I'll get back to you with more information as soon a I can.

kkinnear commented 1 month ago

Thanks for noticing this. The problem is both subtle and glaring.

zprint handles tagged-literals when formatting source, as the parser for source sees them as a reader-macro and there is code to handle some minor variations of them there.

However, when formatting actual Clojure structures, zprint doesn't recognize tagged literals. At all. So it just includes the pr-str of the element it doesn't recognize as special, which for your tagged literal includes a map. But pr-str of a map includes commas in that map. So you get commas, and all of the configuration changes you make to zprint will have no affect on them because zprint isn't actually rendering that map into a string.

The obvious fix is for zprint to recognize a tagged literal and do the right thing with it. Which is a fix I will make, but until it is released, there is nothing you can do to get rid of the commas.

I'll let you know when it is released in this issue.

albertzak commented 1 month ago

I see, thank you for looking into it. Meanwhile, if performance is of no concern, a hacky workaround is to pr-str before zprint with {:parse-string? true} to switch to source-formatting behavior:

(zp/zprint-str (pr-str [{:a :b :c :d} (tagged-literal 'x {:a :b :c :d})])
  {:map {:comma? false} :parse-string? true})
"[{:a :b :c :d} #x {:a :b :c :d}]"
kkinnear commented 1 month ago

Good thought, that didn't occur to me. I have fixed it (though yet to finish the tests), it will be in the next release, 1.3.0. I don't know when I will release next, as there are a number of things yet to complete before I do.