zprint icon indicating copy to clipboard operation
zprint copied to clipboard

:sort-require seemingly incompatible with "ns" in fn-map

Open samharad opened this issue 7 months ago • 1 comments

When I have an entry for "ns" in my :fn-map, it seems that :style :sort-require no longer takes effect:

 ➜  cat /tmp/foo.clj
(ns foo
  (:require
   [z :refer :all]
   [a :refer :all]))

 ➜  ../zprint/zprintm '{:style :sort-require}' < /tmp/foo.clj
(ns foo
  (:require [a :refer :all]
            [z :refer :all]))

 ➜  ../zprint/zprintm '{:style :sort-require :fn-map {"ns" [:arg1-body {:width 250}]}}' < /tmp/foo.clj
(ns foo
  (:require [z :refer :all]
            [a :refer :all]))

 ➜  ../zprint/zprintm '{:style :sort-require :fn-map {"ns" [:arg1-body {:width 250 :style :sort-require}]}}' < /tmp/foo.clj
(ns foo
  (:require [z :refer :all]
            [a :refer :all]))

samharad avatar May 28 '25 20:05 samharad

Good question, thanks for asking!

Here is the implementation of :sort-require:

      :sort-require
        {:doc "Sort requires & refers in ns macro, possibly with regexes.",
         :regex-vec [],
         :sort-refer? true,
         :style-fn (fn
                     ([] "sort-require-config")
                     ([existing-options new-options style-fn-map style-call]
                      {:fn-map {"ns" [:arg1-body
                                      {:list {:option-fn
                                                (partial
                                                  sort-reqs
                                                  (merge-deep
                                                    style-fn-map
                                                    style-call))}}]}}))}},

As you can see, it is implemented by adding an :option-fn to be executed when an ns is encountered -- by using the :fn-map. Thus, when you also change the :fn-map for ns, that essentially removes the :style :sort-require. I can see that perhaps you were thinking this might be the case from your examples. The reason your examples did what they did is because any :style is performed before any of the rest of an option-map is integrated into the current configuration. Thus, if a style does a lot of things and you want to change just one thing, then you can put the thing you want to change in the same option map as the :style invocation, and the style will always happen first (regardless of where it actually appears in the option map).

But that isn't the most important thing going on here. How to get what you want?

Presumably this isn't about making ns :arg1-body, since it already is. If this is about having ns statements have a width that is different from the rest of your formatting and still using :sort-require, then the only way that I can see to do that is for you to define your own style, say :sort-require-250 or something, which would look like this:

{:style-map
   {:sort-require-250
      {:doc "Sort requires & refers in ns macro, possibly with regexes.",
       :regex-vec [],
       :sort-refer? true,
       :style-fn (fn
                   ([] "sort-require-config-250")
                   ([existing-options new-options style-fn-map style-call]
                    {:fn-map {"ns" [:arg1-body
                                    {:width 250,
                                     :list {:option-fn
                                              (partial sort-reqs
                                                       (merge-deep
                                                         style-fn-map
                                                         style-call))}}]}}))}}}

I think that will give you what you want. In the event that you didn't really want it to be wide, the same approach will work for most things that you would want to do -- just add them to the option map where the :width 250 showed up.

In the event this doesn't work or doesn't make sense, please let me know and we will figure something out.

kkinnear avatar May 28 '25 22:05 kkinnear