Skip to content

Instantly share code, notes, and snippets.

@weavejester
Last active June 3, 2022 13:24
Show Gist options
  • Save weavejester/4251a563ab25ee76bbf37212119db5f0 to your computer and use it in GitHub Desktop.
Save weavejester/4251a563ab25ee76bbf37212119db5f0 to your computer and use it in GitHub Desktop.
(def ^:private ns-reference-symbols
#{:import :require :require-macros :use})
(defn- ns-reference? [zloc]
(and (z/list? zloc)
(some-> zloc z/up ns-form?)
(-> zloc z/sexpr first ns-reference-symbols)))
(defn- re-seq-matcher [re charmap coll]
{:pre (every? charmap coll)}
(let [s (apply str (map charmap coll))
v (vec coll)
m (re-matcher re s)]
(letfn [(next-match []
(when (.find m)
{:value (subvec v (.start m) (.end m))
:start (.start m)
:end (.end m)}))]
(take-while some? (repeatedly next-match)))))
(defn- find-elements-with-comments [nodes]
(re-seq-matcher #"(CNS*)*ES*C?"
#(case (n/tag %)
(:whitespace :comma) \S
:comment \C
:newline \N
\E)
nodes))
(defn- splice-into [coll splices]
(letfn [(splice [v i splices]
(when-let [[{:keys [value start end]} & splices] (seq splices)]
(lazy-cat (subvec v i start) value (splice v end splices))))]
(splice (vec coll) 0 splices)))
(defn- add-newlines-after-comments [nodes]
(mapcat #(if (n/comment? %) [% (n/newlines 1)] [%]) nodes))
(defn- remove-newlines-after-comments [nodes]
(mapcat #(when-not (and %1 (n/comment? %1) (n/linebreak? %2)) [%2])
(cons nil nodes)
nodes))
(defn- sort-node-arguments-by [f nodes]
(let [nodes (add-newlines-after-comments nodes)
args (rest (find-elements-with-comments nodes))
sorted (sort-by f (map :value args))]
(->> sorted
(map #(assoc %1 :value %2) args)
(splice-into nodes)
(remove-newlines-after-comments))))
(defn- update-children [zloc f]
(let [node (z/node zloc)]
(z/replace zloc (n/replace-children node (f (n/children node))))))
(defn- nodes-string [nodes]
(apply str (map n/string nodes)))
(defn- flatten-nodes [nodes]
(mapcat #(if (n/inner? %) (flatten-nodes (n/children %)) [%]) nodes))
(defn- node-sort-string [nodes]
(->> (flatten-nodes nodes)
(remove (some-fn n/comment? n/whitespace?))
(nodes-string)))
(defn sort-arguments [zloc]
(update-children zloc #(sort-node-arguments-by node-sort-string %)))
(defn sort-ns-references [form]
(transform form edit-all ns-reference? sort-arguments))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment