Skip to content

Commit e8e0e3d

Browse files
vemvbbatsov
authored andcommitted
[Fix #483] Support alignment for reader conditionals (#486)
1 parent e8d6414 commit e8e0e3d

File tree

3 files changed

+76
-31
lines changed

3 files changed

+76
-31
lines changed

CHANGELOG.md

+4
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.1 (2018-08-27)
610

711
* [#485](https://github.com/clojure-emacs/clojure-mode/issues/485): Fix a regression in `end-f-defun`.

clojure-mode.el

+48-30
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")
@@ -1104,6 +1110,10 @@ will align the values like this:
11041110
:safe #'listp
11051111
:type '(repeat string))
11061112

1113+
(defvar clojure--beginning-of-reader-conditional-regexp
1114+
"#\\?@(\\|#\\?("
1115+
"Regexp denoting the beginning of a reader conditional.")
1116+
11071117
(defun clojure--position-for-alignment ()
11081118
"Non-nil if the sexp around point should be automatically aligned.
11091119
This function expects to be called immediately after an
@@ -1118,32 +1128,36 @@ For instance, in a map literal point is left immediately before
11181128
the first key; while, in a let-binding, point is left inside the
11191129
binding vector and immediately before the first binding
11201130
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))))
1131+
(let ((point (point)))
1132+
;; Are we in a map?
1133+
(or (and (eq (char-before) ?{)
1134+
(not (eq (char-before (1- point)) ?\#)))
1135+
;; Are we in a reader conditional?
1136+
(and clojure-align-reader-conditionals
1137+
(looking-back clojure--beginning-of-reader-conditional-regexp (- (point) 4)))
1138+
;; Are we in a cond form?
1139+
(let* ((fun (car (member (thing-at-point 'symbol) clojure-align-cond-forms)))
1140+
(method (and fun (clojure--get-indent-method fun)))
1141+
;; The number of special arguments in the cond form is
1142+
;; the number of sexps we skip before aligning.
1143+
(skip (cond ((numberp method) method)
1144+
((null method) 0)
1145+
((sequencep method) (elt method 0)))))
1146+
(when (and fun (numberp skip))
1147+
(clojure-forward-logical-sexp skip)
1148+
(comment-forward (point-max))
1149+
fun)) ; Return non-nil (the var name).
1150+
;; Are we in a let-like form?
1151+
(when (member (thing-at-point 'symbol)
1152+
clojure-align-binding-forms)
1153+
;; Position inside the binding vector.
1154+
(clojure-forward-logical-sexp)
1155+
(backward-sexp)
1156+
(when (eq (char-after) ?\[)
1157+
(forward-char 1)
1158+
(comment-forward (point-max))
1159+
;; Return non-nil.
1160+
t)))))
11471161

11481162
(defun clojure--find-sexp-to-align (end)
11491163
"Non-nil if there's a sexp ahead to be aligned before END.
@@ -1152,10 +1166,14 @@ Place point as in `clojure--position-for-alignment'."
11521166
(let ((found))
11531167
(while (and (not found)
11541168
(search-forward-regexp
1155-
(concat "{\\|(" (regexp-opt
1156-
(append clojure-align-binding-forms
1157-
clojure-align-cond-forms)
1158-
'symbols))
1169+
(concat (when clojure-align-reader-conditionals
1170+
(concat clojure--beginning-of-reader-conditional-regexp
1171+
"\\|"))
1172+
"{\\|("
1173+
(regexp-opt
1174+
(append clojure-align-binding-forms
1175+
clojure-align-cond-forms)
1176+
'symbols))
11591177
end 'noerror))
11601178

11611179
(let ((ppss (syntax-ppss)))

test/clojure-mode-indentation-test.el

+24-1
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)