Skip to content

Commit 293d739

Browse files
committed
Support alignment for reader conditionals
Fixes #483
1 parent e6bd584 commit 293d739

File tree

3 files changed

+77
-31
lines changed

3 files changed

+77
-31
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
## master (unreleased)
44

5+
### New features
6+
7+
* [#483](https://github.com/clojure-emacs/clojure-mode/issues/483): Support alignment for reader conditionals, with the new `clojure-align-reader-conditionals` user option.
8+
59
## 5.9.0 (2018-08-18)
610

711
### Changes

clojure-mode.el

Lines changed: 49 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1090,6 +1090,12 @@ will align the values like this:
10901090
:safe #'booleanp
10911091
:type 'boolean)
10921092

1093+
(defcustom clojure-align-reader-conditionals nil
1094+
"Whether to align reader conditionals, as if they were maps."
1095+
:package-version '(clojure-mode . "5.10")
1096+
:safe #'booleanp
1097+
:type 'boolean)
1098+
10931099
(defcustom clojure-align-binding-forms
10941100
'("let" "when-let" "when-some" "if-let" "if-some" "binding" "loop"
10951101
"doseq" "for" "with-open" "with-local-vars" "with-redefs")
@@ -1118,32 +1124,42 @@ For instance, in a map literal point is left immediately before
11181124
the first key; while, in a let-binding, point is left inside the
11191125
binding vector and immediately before the first binding
11201126
construct."
1121-
;; Are we in a map?
1122-
(or (and (eq (char-before) ?{)
1123-
(not (eq (char-before (1- (point))) ?\#)))
1124-
;; Are we in a cond form?
1125-
(let* ((fun (car (member (thing-at-point 'symbol) clojure-align-cond-forms)))
1126-
(method (and fun (clojure--get-indent-method fun)))
1127-
;; The number of special arguments in the cond form is
1128-
;; the number of sexps we skip before aligning.
1129-
(skip (cond ((numberp method) method)
1130-
((null method) 0)
1131-
((sequencep method) (elt method 0)))))
1132-
(when (and fun (numberp skip))
1133-
(clojure-forward-logical-sexp skip)
1134-
(comment-forward (point-max))
1135-
fun)) ; Return non-nil (the var name).
1136-
;; Are we in a let-like form?
1137-
(when (member (thing-at-point 'symbol)
1138-
clojure-align-binding-forms)
1139-
;; Position inside the binding vector.
1140-
(clojure-forward-logical-sexp)
1141-
(backward-sexp)
1142-
(when (eq (char-after) ?\[)
1143-
(forward-char 1)
1144-
(comment-forward (point-max))
1145-
;; Return non-nil.
1146-
t))))
1127+
(let ((point (point)))
1128+
;; Are we in a map?
1129+
(or (and (eq (char-before) ?{)
1130+
(not (eq (char-before (1- point)) ?\#)))
1131+
;; Are we in a reader conditional?
1132+
(and clojure-align-reader-conditionals
1133+
(or (and (eq (char-before (- point 2)) ?\#)
1134+
(eq (char-before (- point 1)) ??)
1135+
(eq (char-before) ?\())
1136+
(and (eq (char-before (- point 3)) ?\#)
1137+
(eq (char-before (- point 2)) ??)
1138+
(eq (char-before (- point 1)) ?@)
1139+
(eq (char-before) ?\())))
1140+
;; Are we in a cond form?
1141+
(let* ((fun (car (member (thing-at-point 'symbol) clojure-align-cond-forms)))
1142+
(method (and fun (clojure--get-indent-method fun)))
1143+
;; The number of special arguments in the cond form is
1144+
;; the number of sexps we skip before aligning.
1145+
(skip (cond ((numberp method) method)
1146+
((null method) 0)
1147+
((sequencep method) (elt method 0)))))
1148+
(when (and fun (numberp skip))
1149+
(clojure-forward-logical-sexp skip)
1150+
(comment-forward (point-max))
1151+
fun)) ; Return non-nil (the var name).
1152+
;; Are we in a let-like form?
1153+
(when (member (thing-at-point 'symbol)
1154+
clojure-align-binding-forms)
1155+
;; Position inside the binding vector.
1156+
(clojure-forward-logical-sexp)
1157+
(backward-sexp)
1158+
(when (eq (char-after) ?\[)
1159+
(forward-char 1)
1160+
(comment-forward (point-max))
1161+
;; Return non-nil.
1162+
t)))))
11471163

11481164
(defun clojure--find-sexp-to-align (end)
11491165
"Non-nil if there's a sexp ahead to be aligned before END.
@@ -1152,10 +1168,13 @@ Place point as in `clojure--position-for-alignment'."
11521168
(let ((found))
11531169
(while (and (not found)
11541170
(search-forward-regexp
1155-
(concat "{\\|(" (regexp-opt
1156-
(append clojure-align-binding-forms
1157-
clojure-align-cond-forms)
1158-
'symbols))
1171+
(concat (when clojure-align-reader-conditionals
1172+
"#\\?@(\\|#\\?(\\|")
1173+
"{\\|("
1174+
(regexp-opt
1175+
(append clojure-align-binding-forms
1176+
clojure-align-cond-forms)
1177+
'symbols))
11591178
end 'noerror))
11601179

11611180
(let ((ppss (syntax-ppss)))

test/clojure-mode-indentation-test.el

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -485,7 +485,8 @@ x
485485
"Verify that all FORMs correspond to a properly indented sexps."
486486
(declare (indent defun))
487487
`(ert-deftest ,(intern (format "test-align-%s" name)) ()
488-
(let ((clojure-align-forms-automatically t))
488+
(let ((clojure-align-forms-automatically t)
489+
(clojure-align-reader-conditionals t))
489490
,@(mapcar (lambda (form)
490491
`(with-temp-buffer
491492
(clojure-mode)
@@ -596,6 +597,28 @@ x
596597
:b {:a :a,
597598
:aa :a}}")
598599

600+
(def-full-align-test reader-conditional
601+
"#?(:clj 2
602+
:cljs 2)")
603+
604+
(def-full-align-test reader-conditional-splicing
605+
"#?@(:clj [2]
606+
:cljs [2])")
607+
608+
(ert-deftest reader-conditional-alignment-disabled-by-default ()
609+
(let ((content "#?(:clj 2\n :cljs 2)"))
610+
(with-temp-buffer
611+
(clojure-mode)
612+
(insert content)
613+
(call-interactively #'clojure-align)
614+
(should (string= (buffer-string) content)))
615+
(with-temp-buffer
616+
(clojure-mode)
617+
(setq-local clojure-align-reader-conditionals t)
618+
(insert content)
619+
(call-interactively #'clojure-align)
620+
(should-not (string= (buffer-string) content)))))
621+
599622
(ert-deftest clojure-align-remove-extra-commas ()
600623
(with-temp-buffer
601624
(clojure-mode)

0 commit comments

Comments
 (0)