clj-commons / formatter

Building blocks and discussion for building a common Clojure code formatter
36 stars 1 forks source link

Removing extra whitespace? #2

Open danielcompton opened 5 years ago

danielcompton commented 5 years ago

There are a few places where Clojure programs can accumulate trailing whitespace. In the listings below | denotes the end of the line.

At the ends of lines after source code

(def v nil)       |

Between lines of source code within a form

(defn best-allowed-language [accepts-header available]
  (let [accepts (->> (string/split accepts-header #"[\s\r\n]*,[\s\r\n]*")
                     (map split-qval)
                     (into {}))
                     |
        score (fn [langtag]
                (or
                 ;; "A language-range matches a language-tag if it exactly equals the tag"
...

At the end of a source code file

(def v nil)

|

Different programmers and editors have different behaviour for how they treat extra whitespace. This can lead to churn in source control diffs when different programmers work on the same file. I think it would be beneficial for this spec to define a policy for handling extra whitespace. I'm personally in favour of removing all three kinds of whitespace, but would like to open this up for discussion.

PEZ commented 5 years ago

Two of those cases should be easy to solve without controversy. Just remove all trailing whitespace on non-empty lines and decide on wether to have zero or one trailing empty line at the end of the files.

As for the empty lines within a form, I personally think they can always be removed.

Of course, an editor might, and probably will, relax these rules while code is being entered and enforce them more strictly on save and on command.

Let me add what I think might be a trickier one to agree on:

Between top level forms Some people suggest to use two lines. Having tried that, I have kind of started to like it. But I am not using it for all forms.

(def foo :foo)
(def bar :bar)

(defn re-pos-first
  "Find position of first match of `re` in `s`"
  [re s]
  (if-let [m (.match s re)]
    (.-index m)
    -1))

(defn split-into-lines
  [s]
  (clojure.string/split s #"\r?\n" -1))

(defn enclosing? [text]
  (let [ast (cljify (paredit/parse text))
        children (:children ast)]
    (and (= 1 (count children))
         (= "list" (:type (first children))))))

I think the pattern I follow might be that forms that are often one-liners get zero lines between them and otherwise I opt for two. Maybe the formatter could use these rules: