Coder Social home page Coder Social logo

Formatting Rum macros about zprint HOT 17 CLOSED

kkinnear avatar kkinnear commented on July 18, 2024
Formatting Rum macros

from zprint.

Comments (17)

kkinnear avatar kkinnear commented on July 18, 2024 3

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.

kkinnear avatar kkinnear commented on July 18, 2024 2

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.

tonsky avatar tonsky commented on July 18, 2024 1

@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.

tonsky avatar tonsky commented on July 18, 2024 1

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.

kkinnear avatar kkinnear commented on July 18, 2024 1

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.

jcf avatar jcf commented on July 18, 2024

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:

2017-12-02-00 17 18-1ed10a792e20

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.

kkinnear avatar kkinnear commented on July 18, 2024

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.

kkinnear avatar kkinnear commented on July 18, 2024

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 defns 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.

kkinnear avatar kkinnear commented on July 18, 2024

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.

jcf avatar jcf commented on July 18, 2024

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.

jcf avatar jcf commented on July 18, 2024

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.

kkinnear avatar kkinnear commented on July 18, 2024

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.

kkinnear avatar kkinnear commented on July 18, 2024

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.

jcf avatar jcf commented on July 18, 2024

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.

kkinnear avatar kkinnear commented on July 18, 2024

Thanks for the feedback Nikita! I'll push forward in that direction.

from zprint.

jcf avatar jcf commented on July 18, 2024

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.

tonsky avatar tonsky commented on July 18, 2024

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)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo 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.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.