Comments (17)
I just released zprint 0.4.5 and lein-zprint 0.3.6 which contains the rum mixin support that we have been discussing in this issue. I believe that it matches what we all agreed to. Please let me know if this isn't what you thought you were getting and/or anything doesn't work as you expect. Thanks for the input!
@tonsky, I formatted your examples from the rum project, and they all look pretty good, with the exception of the [:dt ...]
vectors, which are hard to format algorithmically. I'm still thinking on how to perhaps preserve line breaks in some vectors but not others, but I haven't figured that out yet.
Generally, I used {:style :justified}
to match what you seem to do, and in most cases it comes out looking good. Exceptions tend to be in let
bindings with significant destructuring, or anywhere the thing in the local position is just large enough (but not too large).
Anyway, at least the rum components now look good, with and without doc-strings.
from zprint.
Yet another question for you both...
If the component has a doc-string (which none of the examples I can find do), how about this:
(rum/defcs component2
"This is a component with a doc-string! How unusual..."
< rum/static
rum/reactive
(rum/local 0 ::count)
(rum/local "" ::text)
[state label]
(let [count-atom (::count state) text-atom (::text state)] [:div]))
which kind of makes this attractive if they don't fit out to the right (instead of the previous version, with the <
by itself at the end of the first line):
(rum/defcs component
< rum/static
rum/reactive
(rum/local 0 ::count)
(rum/local "" ::text)
[state label]
(let [count-atom (::count state) text-atom (::text state)] [:div]))
Opinions?
from zprint.
@kkinnear I like the second approach! Having worked with this a lot, first one (without additional indentation) is a little bit hard to read (hard to find where argument list and component code start)
from zprint.
I think it’s even better. Should this be the default style (even without docstring)? I like that you can copy/paste the whole lines to cut out/paste back mixins.
from zprint.
If you want that to be the default, doc-string or not, I'm fine with that. You set the standard by creating the library and the examples that show how to use it. I was just looking at dynadoc, and it uses rum and formats the defc
and defcs
the way that you do in your examples.
But if you would like zprint to do it like:
; Example 1
(rum/defcs component
"This is a component with a doc-string! How unusual..."
< rum/static
rum/reactive
(rum/local 0 ::count)
(rum/local "" ::text)
[state label]
(let [count-atom (::count state) text-atom (::text state)] [:div]))
and this:
; Example 2
(rum/defcs component
< rum/static
rum/reactive
(rum/local 0 ::count)
(rum/local "" ::text)
[state label]
(let [count-atom (::count state) text-atom (::text state)] [:div]))
that would be great. The advantage to both of these formats is that having the component name end the line (as most people do with defn
as well) is that it makes it easier to find the component when scanning through a file. As I'm scanning the dynadoc common.cljc file on github with rum macros in it, even though the component names are in blue, it is still hard to pick them out all that easily because of the mixins or even the argument vector being at the end of the line.
Which leaves me also thinking that this would be the "no mixin" approach:
; Example 3
(rum/defcs component
[state label]
(let [count-atom (::count state) text-atom (::text state)] [:div]))
which is surely different from your standard style in rum:
; Example 4
(rum/defcs component [state label]
(let [count-atom (::count state) text-atom (::text state)] [:div]))
This is your macro and I'll do whatever you want, but I found this approach troubling. It is so close to defn
, but different. And just about everybody does defn
with the function name ending the line. Probably because it is simply easier to find it in a file when looking at it. At present zprint doesn't even have an option to do defn
like example 4.
So, if you like example 1 and think example 2 is the way to go, I would say example 3 follows along, and that's what I'll do. I think all of those are good myself, but it is your macro, and ultimately the way that you are going to write it is going to be what people would want zprint to do. So if you really like example 4 over example 3, and/or really want mixins on the first line if there is no doc-string, let me know -- and I'll figure out how to do that. I just want zprint to format it the way that you are going to format it, since the world will follow your lead here (or at least they already have, and I would expect that to continue).
And thanks very much for your input! I really appreciate it!
from zprint.
Here's my full configuration:
{:agent {:object? false}
:binding {:force-nl? true}
:extend {:flow? true}
:fn-map {"->" :hang
"->>" :hang
":gen-class" :flow
":import" :flow
":refer-clojure" :hang
":require" :flow
"cond->" :hang
"defn" :arg1-force-nl
"defrecord" :fn
"deftype" :fn
"filter" :hang
"map" :hang
"remove" :hang
"rum/defc" :flow
"rum/defcs" :flow
"s/fdef" :fn
"some->" :hang}
:list {:constant-pair? true :indent 2 :indent-arg 1}
:map {:comma? false
:key-order [:keys :as :or]
:lift-ns-in-code? false
:lift-ns? true
:sort-in-code? true
:sort? true}
:pair {:justify? false}
:pair-fn {:hang? false}
:set {:sort-in-code? true :sort? true}
:vector {:wrap-after-multi? false}
:width 80}
And this is the little playground I'm working on:
Looks like my most recent changes to indentation rules has broken formatting ns forms the way I want.
Update: I've gone back to my previous configuration of this:
{:agent {:object? false}
:binding {:force-nl? true}
:extend {:flow? true :indent 0}
:fn-map {"->" :hang
"->>" :hang
":gen-class" :flow
":import" :flow
":refer-clojure" :hang
":require" :flow
"cond->" :hang
"defn" :arg1-force-nl
"some->" :hang}
:list {:constant-pair? true :indent 2}
:map {:comma? false
:key-order [:keys :as :or]
:lift-ns-in-code? false
:lift-ns? true
:sort-in-code? true
:sort? true}
:pair {:justify? false}
:pair-fn {:hang? false}
:set {:sort-in-code? true :sort? true}
:vector {:wrap-after-multi? false}
:width 80}
I can't get that single space in the ns form, which makes sense because :require
isn't a function so the following lines shouldn't be indented as arguments - they're merely items in a list.
from zprint.
I'll try to see what I can do with your rum expressions. It would help me if you showed me how you would like them to look. No guarantees I can get them to look that way, but at least I would know what you would like them to look like.
The right-hand window is, presumably, the output. That (ns ...)
form looks good to me (which I suppose isn't a surprise). Do you wish it looked differently?
I'm very interested in what you are doing, though I can't say that I totally understand it at this point.
from zprint.
So, I went off to look at rum. Interesting work, might find a use for it myself. Presumably you want the rum stuff formatted like @tonsky does it. He tends to put the argument vectors of his defn
s on the same line as the name, which is unusual. But ignoring that, this one is going to be a challenge:
(rum/defcs component < rum/static
rum/reactive
(rum/local 0 ::count)
(rum/local "" ::text)
[state label]
(let [count-atom (::count state)
text-atom (::text state)]
[:div])
I'm looking at his examples here, and I will see what I can come up with.
from zprint.
Given the current capabilities, {:fn-map {"defc" :arg2 "defcc" :arg2 "defcs" :arg2} :vector {:wrap-after-multi? false}}
seems like about the best zprint can do. I've formatted all of the examples, and the results aren't bad, though of course not identical to the originals. For example:
(czprint r8 {:fn-map {"defcs" :arg2} :vector {:wrap? true :wrap-after-multi? false}})
(rum/defcs component <
rum/static
rum/reactive
(rum/local 0 :zprint.repl/count)
(rum/local "" :zprint.repl/text)
[state label]
(let [count-atom (:zprint.repl/count state)
text-atom (:zprint.repl/text state)]
[:div]))
This puts the mixins inline, not at the end of the first line. It also will put the argument vector on the first line if there isn't a mixin, but that's about the best I can see to do now.
Were I to implement some function type to do this kind of thing, I think I'd look for some symbol (e.g., <
) and then put everything between that symbol and the argument vector at the end of the first line or hanging below that. Of course, if one of the mixins is contained in a vector, that would not be particularly lovely. I don't know if a mixin can be a vector, do you?
If I implemented a function type like that, the example above would come out like it did in the rum readme, and I think most of what I saw in the examples would be pretty much like they were there. Does that sound like it would be useful? I'm open to another algorithm to print these things, if you would like to suggest one.
from zprint.
Wow @kkinnear! I didn't expect such a thoroughly detailed and helpful response. Thank you.
I'm very interested in what you are doing, though I can't say that I totally understand it at this point.
At this point I've done little more than take an input string and format it using a configuration I have in (browser) memory. As you change the code on the left the formatted result updates as soon as we can parse the input (incomplete S-expressions throw an exception which delays any update to the formatted result).
I'm planning on building some kind of configuration editor (or at least making it editable from the UI instead of live reloading the config via Figwheel) in the short to medium term. Longer term I'm undecided but have a few ideas I'm toying with.
Presumably you want the rum stuff formatted like @tonsky does it.
I'd consider Nikita's style somewhat canonical, but I do like your example using the current capabilities. It's certainly favourable than where I got to.
Were I to implement some function type to do this kind of thing, I think I'd look for some symbol (e.g., <) and then put everything between that symbol and the argument vector at the end of the first line or hanging below that.
Of course, if one of the mixins is contained in a vector, that would not be particularly lovely. I don't know if a mixin can be a vector, do you?
To my knowledge all of the mixins expand to maps and are merged allowing the composition of various lifecycle events (will mount. did mount etc.). I'm relatively new to Rum however so take that for what it's worth.
Does that sound like it would be useful? I'm open to another algorithm to print these things, if you would like to suggest one.
I think what you've suggested sounds perfect.
from zprint.
Oh!
The right-hand window is, presumably, the output. That (ns ...) form looks good to me (which I suppose isn't a surprise). Do you wish it looked differently?
Yes. I want zprint to match clojure-code from Emacs and treat the :require
list in the namespace as any old list and indent with a single space like so:
(ns foo
(:require
[foo.bar :as bar]))
;; Like any old list:
'(1
2
3)
;; Rather than as if `:require` is a function.
'(1
2
3)
from zprint.
What you are building looks great! Figuring out the zprint configuration to get what you want is non-trivial, and your application could help a lot! I'm looking forward to seeing where you take it. If there is anything I can do to help, let me know.
Now, let's deal with :require
. You can get what I think you want if you do: {:style :community :fn-map {"ns" :arg1}}
. That will give you the single space, and if you want that, you probably wanted :style :community
anyway for the rest of what you were doing. If you also don't want the hangs inside the :require
, you could do {:style :community :fn-map {"ns" :arg1} :list {:hang? false}}
. I only mention turning off the hangs because of your example above -- I can't believe you wouldn't want to have hangs for general formatting of functions. If you really don't like hangs for ns
statements but want hangs elsewhere, you can always use ;!zprint
formatting in your source file. I'm assuming that this is about formatting your own source files, and not dealing the live-reloading application's operation.
Over time, if you get interested in the ;!zprint capability for your application, I can show you how to
get that to be recognized and processed in your input strings if you haven't already seen how to do it. It is not obvious.
A bit of a tangent: There is a way to get the intermediate format zprint produces out, which contains the color information. I use it for testing, but it might be that you would want to feed it to rum and have it generate colored html, if that is interesting to you. The intermediate format is dirt simple:
(czprint-str "(a b c)" {:parse-string? true})
"(a b c)"
(czprint-str "(a b c)" {:parse-string? true :return-cvec? true})
[["(" :green :left] ["a" :black :element] [" " :none :whitespace] ["b" :black :element] [" " :none :whitespace] ["c" :black :element] [")" :green :right]]
(czprint-str '(a b c) {:return-cvec? true})
[["(" :green :left] ["a" :black :element] [" " :none :whitespace] ["b" :black :element] [" " :none :whitespace] ["c" :black :element] [")" :green :right]]
I can make that clearer if you are interested.
I have thought of adding a capability to zprint to produce colored and formatted html output, or perhaps creating a different library which would do that using the output from zprint. I haven't taken the time to do it, though the actual coding would not be all that difficult. The challenge for me would be figuring out what the html should look like, since I think there are multiple ways to get the same visual output, some of which are "better" than others. If you created a way to generate html from the zprint intermediate format for your application, you could also make that a separate (or additional) capability which might interesting to others as well. We can talk more about this if any of it is interesting to you. End of tangent.
from zprint.
I wanted to see how hard the mixin thing would be to do, and while I'm sure I missed some things, the basics seem like they are coming together. But I could use an opinion. When the mixins fit, they look like this:
(czprint r8 60 {:fn-map {"defcs" :arg2-mixin}})
(rum/defcs component < rum/static
rum/reactive
(rum/local 0 :zprint.repl/count)
(rum/local "" :zprint.repl/text)
[state label]
(let [count-atom (:zprint.repl/count state)
text-atom (:zprint.repl/text state)]
[:div]))
and as of now, when they don't fit, they look like this:
(czprint r8 50 {:fn-map {"defcs" :arg2-mixin}})
(rum/defcs component <
rum/static
rum/reactive
(rum/local 0 :zprint.repl/count)
(rum/local "" :zprint.repl/text)
[state label]
(let [count-atom (:zprint.repl/count state)
text-atom (:zprint.repl/text state)]
[:div]))
which is ok, I suppose. I was thinking of making them look like this when they don't fit:
(rum/defcs component <
rum/static
rum/reactive
(rum/local 0 :zprint.repl/count)
(rum/local "" :zprint.repl/text)
[state label]
(let [count-atom (:zprint.repl/count state)
text-atom (:zprint.repl/text state)]
[:div]))
I kind of like the second version (i.e., additional two space indent for the mixins) for when they don't fit well in the hang off of the first line. What do you think?
Thanks!
from zprint.
A bit of a tangent: There is a way to get the intermediate format zprint produces out, which contains the color information. I use it for testing, but it might be that you would want to feed it to rum and have it generate colored html, if that is interesting to you.
@kkinnear that's awesome. I was thinking about adding colour to the output; I think a set of issues with a milestone or two might be in order. I'll look into open sourcing what I have sooner than I'd planned.
from zprint.
Thanks for the feedback Nikita! I'll push forward in that direction.
from zprint.
Example 1, 2, and 3 match up to how I typically format my code so I'm onboard. But as you say, it's @tonsky's macro.
from zprint.
Thing is, I actually write defn
the way you wrote defcs
in Example 4. It might be not the common practice though—I just don’t know. I think what makes sense is to match defn
and defc*
formatting inside the same formatting tool, so I agree Example 3 would be best for zprint.
As for 1 and 2, I actually never thought about how best to format mixins. I use variations of styles depending on my mood/luck/what I think I did the last time. I’d love to standardize it and happy to do that with the syntax proposed in 1 and 2.
from zprint.
Related Issues (20)
- How to force-nl on -> only when exceeds the width HOT 3
- Wired justify in bindings with map on the left HOT 14
- Indentation inside namespaced maps is wrong HOT 2
- `;!zprint {:format :off}` deletes the outer key from namespaced maps HOT 3
- Aliasing a function to another in :fn-map does not work on namespaced function calls HOT 3
- Empty maps are removed when using `;!zprint {:format :off}` HOT 2
- :map :key-order request: HOT 2
- Option for `:rod` to not add newline after arglist when whole defn can fit into single line HOT 15
- How to force blank lines between vector elements? HOT 20
- `;!zprint {:format :skip}` removes arglist when there's zero arg HOT 1
- 1.2.5 format changes: `dissoc` HOT 3
- Slowness when pairing smaller width with long strings HOT 4
- Search for .zprintrc in XDG_CONFIG_HOME HOT 1
- Request or help if exists already - `#js` reader syntax in cljs interop HOT 9
- how do I to check or write all files recurisvely in a folder? HOT 1
- Custom Syntax Formatting: Hiccup HOT 10
- "Smart" comment changes feedback HOT 15
- Parinfer compatability HOT 2
- Vertical alignment HOT 6
- Adding Better Clojure Formatting from Tonsky HOT 8
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from zprint.