Skip to content

fix max-column-alignment-gap to demote anchor when gap limit exceeded#425

Open
sirmspencer wants to merge 1 commit into
weavejester:masterfrom
sirmspencer:ms-fix-gap-anchor-demotion
Open

fix max-column-alignment-gap to demote anchor when gap limit exceeded#425
sirmspencer wants to merge 1 commit into
weavejester:masterfrom
sirmspencer:ms-fix-gap-anchor-demotion

Conversation

@sirmspencer

@sirmspencer sirmspencer commented Jul 24, 2026

Copy link
Copy Markdown

@weavejester I can't remember if you want an issue per PR, so I included the details here. I can make it an issue if you prefer.

LLM notice

I have reviewed all of what is being submitted. The PR description was partially generated with llm to show the current and expected.

Problem

Here, I am not sure if this is a bug or a differene in expected behavior so I went with a new flag.

When :max-column-alignment-gap is set, the alignment anchor is still the longest key in the form. Individual rows whose gap would exceed the limit fall back to a single space, but rows with medium-length keys are still extended all the way to the inflated anchor column. This produces inconsistent alignment: the shortest key falls back, medium keys over-extend, and the longest key (which caused the problem) sets the column for all of them.

Current behavior

Config: {:align-form-columns? true, :max-column-alignment-gap 5}

Input:

(let [a 1
      abcde 2
      abcdefg 3
      long-name 4]
  [a abcde abcdefg long-name])

Output — long-name stays as anchor; a falls back (gap 9 > 5); abcde and
abcdefg extend unnecessarily to the long-name column:

(let [a 1
      abcde     2
      abcdefg   3
      long-name 4]
  [a abcde abcdefg long-name])

The same behavior affects maps with :align-map-columns?.

Solution

This PR does not change the behavior of :max-column-alignment-gap. Instead it introduces a new flag, :max-column-anchor-gap, which applies the limit at anchor selection time rather than per row.

When :max-column-anchor-gap N is set, cljfmt selects the largest key for which every shorter key would need at most N spaces to align. Keys longer than the chosen anchor are not padded.

Expected behavior

Config: {:align-form-columns? true, :max-column-anchor-gap 5}

;; long-name (gap 8 from a) and abcdefg (gap 6 from a) exceed limit;
;; anchor demotes to abcde (gap for a = 4 ≤ 5)
(let [a     1
      abcde 2
      abcdefg 3
      long-name 4]
  [a abcde abcdefg long-name])

Composing both flags

The two flags are orthogonal and can be combined. :max-column-anchor-gap runs
first to select a conservative anchor; :max-column-alignment-gap then applies
per-row fallback to the result.

;; Config: {:align-map-columns? true
;;          :max-column-anchor-gap 5       ; long-key excluded; anchor = :abcde
;;          :max-column-alignment-gap 3}   ; further trims rows with gap > 3
;;
;; :x falls back (gap 4 > 3); :abc aligns (gap 3 = limit); :abcde is anchor
{:x "a"
 :abc   "b"
 :abcde "c"
 :long-key "d"}

Changes

  • New option :max-column-anchor-gap added to default-options (nil by default)
  • column-start-position applies cascade demotion when :max-column-anchor-gap is set
  • pad-to-position gains a guard for keys wider than the demoted anchor, preventing
    their spacing from collapsing to zero
  • README documents the new option and its relationship to :max-column-alignment-gap
  • New test-max-column-anchor-gap deftest with form, map, and compose cases

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant