Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Indentation of clojure.test/are #548

Open
joncol opened this issue Nov 27, 2019 · 8 comments
Open

Indentation of clojure.test/are #548

joncol opened this issue Nov 27, 2019 · 8 comments

Comments

@joncol
Copy link

joncol commented Nov 27, 2019

Expected behavior

I was expecting clojure-mode's indentation to behave similar to cider-format and lein cljfmt. Is there some way to configure clojure-mode to indent the same way as cider-format?

Actual behavior

The macro clojure.test/are is indented one way with M-x cider-format (and lein cljfmt), but another way when using clojure-mode's indentation rules (with aggressive-indent-mode). The latter uses one space less than the former for the second argument to are (when it is on a new line).

Steps to reproduce the problem

The code is formatted as following using clojure-mode indentation:

(deftest are-test
  (are [x y]
      (= x y)
    1 1
    2 2))

And as following when using cider-format indentation (note the extra space on line 3):

((deftest are-test
  (are [x y]
       (= x y)
    1 1
    2 2))

Environment & Version information

clojure-mode version information

clojure-mode (version 5.11.0)

Emacs version

GNU Emacs 27.0.50 (build 1, x86_64-pc-linux-gnu, GTK+ Version 3.24.12, cairo version 1.17.3) of 2019-11-26

Operating system

Arch Linux

@svantevonerichsen6906
Copy link

I'd actually expect the clojure-mode result (not alignment, but two levels of indentation to separate it from the body).

@joncol
Copy link
Author

joncol commented Nov 27, 2019

I'd actually expect the clojure-mode result (not alignment, but two levels of indentation to separate it from the body).

I'm not sure I understand what you mean. But it would be best if there was some way to configure this...

@j-cr
Copy link
Contributor

j-cr commented Dec 25, 2019

Seems like it's not specific to are, all n-arg indent specs are broken(?):

;; in emacs:
(define-clojure-indent
  (foo 3))

;; in clojure:
(foo 1
    2
    3
  4
  5)

;; in emacs:
(define-clojure-indent
  (foo nil))

;; in clojure:
(foo 1
     2
     3
     4
     5)

@j-cr
Copy link
Contributor

j-cr commented Dec 25, 2019

This change to clojure-indent-function does the trick:

modified   clojure-mode.el
@@ -1511,7 +1511,8 @@ This function also returns nil meaning don't specify the indentation."
              (clojure--normal-indent last-sexp 'always-align))
             ;; Special arg. Rigidly indent with a large indentation.
             (t
-             (+ (* 2 lisp-body-indent) containing-form-column)))))
+             (+ 1 (* 2 lisp-body-indent) containing-form-column)
+             ))))
         (`:defn
          (+ lisp-body-indent containing-form-column))
         ((pred functionp)

Though I suspect a proper fix should take into account the value of clojure-indent-style var. Docstring for clojure-indent-function states:

- an integer N, meaning indent the first N arguments specially
  like ordinary function arguments and then indent any further
  arguments like a body;

...and how 'ordinary function arguments' are indented is controlled by clojure-indent-style: if it's always-align or align-arguments, then the first N arguments should be on the same column; if it's always-indent however, then logically according to the spec ("All args are indented like a macro body") the first N arguments should be indented the same as all the other ones, i.e. it should be a no-op.

I'm not sure if clojure-indent-function is supposed to be used that way though; chances are I'm overthinking this?

In any case, with the provided patch:

;; in emacs:
(define-clojure-indent
  (foo 3))

;; in clojure: 
(foo 1
     2
     3
  4
  5) 

@nfedyashev
Copy link

hi @j-cr

Thanks for posting this diff!
I was to apply it to my (spac)emacs installation and it failed. Can you please explain how to apply this diff?

I've tried the following process:

  1. found that file( ~/.emacs.d/elpa/develop/clojure-mode-20200813.639/clojure-mode.el )
  2. applied the fix
  3. executed (spacemacs/recompile-elpa) which results in several warnings.
  4. After emacs restart, regular modes stopped working - e.g. clj files are opened in fundamental(plain text) mode.

I've rolled back that diff and recompiled elpa. Everything seems to be working again but I was trying to fix this issue with clojure.test/are form weird formatting.

Seems like it's not specific to are, all n-arg indent specs are broken(?):
From what I see, the biggest(only?) issue is with are form because If I rename it to any other 3-character form(e.g. foo) formatting suddenly works again.

@j-cr
Copy link
Contributor

j-cr commented Sep 14, 2020

I don't use spacemacs so I don't know. Simply finding that function, changing it and evaluating it should work.

@nfedyashev
Copy link

@j-cr thanks!

@andreyorst
Copy link
Contributor

I'd actually expect the clojure-mode result (not alignment, but two levels of indentation to separate it from the body).

I'm not sure I understand what you mean.

@joncol, svantevonerichsen6906 meant that this is correct formatting.

Clojure mode indents special arguments by fixed amount of spaces, which is twice as large as indentation of ordinary macro parameter.
Which means that when you say (define-clojure-indent (foo 3)) you mean that first 3 arguments to foo should be considered special. These arguments are not aligned to the first one, but use 4 space indentation to indicate that these are indeed special args.

Similarly, if you put let binding vector onto a separate line, you'll see that it is indented by four spaces, where the body is indented by 2:

(let
    [a 10]
  a)

It may actually look that vector is aligned with where the first argument should go, but it's just a coincidence. If you use a longer macros like (define-clojure-indent (foo-bar-baz 2)) you'll see this:

(foo-bar-baz a
    b
  c)

Which helps seeing that a, and b are special args, and c is body form.


patch in #548 (comment) introduces incorrect formatting, by making all special args indented by 5 spaces instead of 4, thus making those align with forms that have 3 letter long names, but it will still not work with foo-bar-baz macros, which I assume is what you want

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

No branches or pull requests

5 participants