Skip to content

Commit 5abfa5b

Browse files
committed
Add :max-column-alignment-width option
Add a new :max-column-alignment-width option for column alignment that selects the anchor by cascade demotion: the largest key for which every shorter key fits within N spaces. Keys longer than the chosen anchor are not padded.
1 parent 609d570 commit 5abfa5b

3 files changed

Lines changed: 88 additions & 14 deletions

File tree

README.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,29 @@ In order to load the standard configuration file from Leiningen, add the
316316
:as everything} ;; 27 spaces, falls back to 1 space
317317
```
318318

319+
* `:max-column-alignment-width` -
320+
a positive integer that limits which keys participate in column
321+
alignment. Keys whose end column is at or within N are aligned
322+
together; keys that end past column N are not padded and receive a
323+
single space before their value. Defaults to nil (no limit).
324+
**Experimental.**
325+
326+
```clojure
327+
;; Input:
328+
{:a 1
329+
:abcde 2
330+
:abcdefg 3
331+
:long-name 4}
332+
333+
;; With :align-map-columns? true and :max-column-alignment-width 7:
334+
;; :a and :abcde end at or within column 7 and align together;
335+
;; :abcdefg and :long-name end past column 7 and are not padded
336+
{:a 1 ;; ends within column 7, padded to value column
337+
:abcde 2 ;; ends at column 7, sets the value column
338+
:abcdefg 3 ;; ends past column 7, 1 space
339+
:long-name 4} ;; ends past column 7, 1 space
340+
```
341+
319342
* `:blank-lines-separate-alignment?` -
320343
true if cljfmt should treat blank lines as separators when aligning
321344
columns. When enabled, alignment groups are separated by blank lines,

cljfmt/src/cljfmt/core.cljc

Lines changed: 24 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -383,6 +383,7 @@
383383
:align-single-column-lines? false
384384
:aligned-forms default-aligned-forms
385385
:max-column-alignment-gap nil
386+
:max-column-alignment-width nil
386387
:blank-line-forms blank-line-forms
387388
:blank-lines-separate-alignment? false
388389
:extra-aligned-forms {}
@@ -670,13 +671,16 @@
670671
(defn- count-spaces [zloc]
671672
(if (space? zloc) (node-str-length zloc) 0))
672673

673-
(defn- pad-to-position [zloc start-position {max-gap :max-column-alignment-gap}]
674-
{:pre [(or (nil? max-gap) (pos-int? max-gap))]}
675-
(let [delta (- start-position (margin zloc))]
676-
(if max-gap
677-
(let [old-gap (count-spaces (z/left* zloc))
678-
new-gap (+ old-gap delta)]
679-
(pad-node zloc (if (> new-gap max-gap) (- 1 old-gap) delta)))
674+
(defn- pad-to-position [zloc start-position {max-gap :max-column-alignment-gap
675+
align-width :max-column-alignment-width}]
676+
{:pre [(or (nil? max-gap) (pos-int? max-gap))
677+
(or (nil? align-width) (pos-int? align-width))]}
678+
(let [old-gap (count-spaces (z/left* zloc))
679+
delta (- start-position (margin zloc))
680+
new-gap (+ old-gap delta)]
681+
(if (or (< new-gap 1)
682+
(and max-gap (> new-gap max-gap)))
683+
(pad-node zloc (- 1 old-gap))
680684
(pad-node zloc delta))))
681685

682686
(defn- edit-column [zloc column f]
@@ -707,17 +711,23 @@
707711
(recur (z/right* zloc) 0 acc)
708712
(recur (z/right* zloc) (inc col) (f zloc col acc)))))))
709713

710-
(defn- column-start-position [zloc col opts]
711-
(let [reduce-fn (if (:blank-lines-separate-alignment? opts)
714+
(defn- column-start-position
715+
[zloc col {align-width :max-column-alignment-width
716+
align-singles? :align-single-column-lines?
717+
separate? :blank-lines-separate-alignment?}]
718+
(let [reduce-fn (if separate?
712719
reduce-column-group
713720
reduce-columns)
714-
maximizer (fn [zloc c max-pos]
721+
collector (fn [zloc c positions]
715722
(if (and (= c (dec col))
716-
(or (:align-single-column-lines? opts)
723+
(or align-singles?
717724
(not (single-column-line? zloc))))
718-
(max max-pos (node-end-position zloc))
719-
max-pos))]
720-
(inc (reduce-fn zloc maximizer 0))))
725+
(conj positions (node-end-position zloc))
726+
positions))
727+
positions (reduce-fn zloc collector [])]
728+
(inc (apply max 0 (if align-width
729+
(filter #(<= % (+ (apply min 0 positions) align-width)) positions)
730+
positions)))))
721731

722732
(defn- align-one-column
723733
[zloc col {:keys [blank-lines-separate-alignment?] :as opts}]

cljfmt/test/cljfmt/core_test.cljc

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3193,6 +3193,47 @@
31933193
{:align-map-columns? true
31943194
:max-column-alignment-gap 5}))))
31953195

3196+
(deftest test-max-column-alignment-width
3197+
(testing "form: anchor demoted until all keys fit within gap"
3198+
(is (reformats-to?
3199+
["(let [a 1"
3200+
" abcde 2"
3201+
" abcdefg 3"
3202+
" long-name 4]"
3203+
" [a abcde abcdefg long-name])"]
3204+
["(let [a 1"
3205+
" abcde 2"
3206+
" abcdefg 3"
3207+
" long-name 4]"
3208+
" [a abcde abcdefg long-name])"]
3209+
{:align-form-columns? true
3210+
:max-column-alignment-width 11})))
3211+
(testing "map: anchor demoted until all keys fit within gap"
3212+
(is (reformats-to?
3213+
["{:a \"x\""
3214+
" :abcde \"y\""
3215+
" :abcdefg \"z\""
3216+
" :long-key \"w\"}"]
3217+
["{:a \"x\""
3218+
" :abcde \"y\""
3219+
" :abcdefg \"z\""
3220+
" :long-key \"w\"}"]
3221+
{:align-map-columns? true
3222+
:max-column-alignment-width 7})))
3223+
(testing "composing both flags refines alignment further"
3224+
(is (reformats-to?
3225+
["{:x \"a\""
3226+
" :abc \"b\""
3227+
" :abcde \"c\""
3228+
" :long-key \"d\"}"]
3229+
["{:x \"a\""
3230+
" :abc \"b\""
3231+
" :abcde \"c\""
3232+
" :long-key \"d\"}"]
3233+
{:align-map-columns? true
3234+
:max-column-alignment-width 7
3235+
:max-column-alignment-gap 3}))))
3236+
31963237
(deftest test-realign-form
31973238
(is (= "
31983239
{:x 1

0 commit comments

Comments
 (0)