Skip to content

Commit f30fa7b

Browse files
committed
Merge pull request #231 from elixir-lang/correct-block-match-indentation
correct indentation for block with multiple matches
2 parents e9d8cea + 0330d49 commit f30fa7b

File tree

2 files changed

+134
-6
lines changed

2 files changed

+134
-6
lines changed

elixir-smie.el

Lines changed: 88 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,19 @@
173173
(not (or (memq (char-before) '(?\{ ?\[))
174174
(looking-back elixir-smie--operator-regexp (- (point) 3) t))))
175175

176+
(defun elixir-smie-last-line-end-with-block-operator-p ()
177+
"Return non-nil if the previous line ends with a `->' operator."
178+
(save-excursion
179+
(forward-line -1)
180+
(move-end-of-line 1)
181+
(looking-back elixir-smie--block-operator-regexp (- (point) 3) t)))
182+
183+
(defun elixir-smie-last-line-start-with-block-operator-p ()
184+
(save-excursion
185+
(forward-line -1)
186+
(beginning-of-line)
187+
(looking-at "^\s+->.+$")))
188+
176189
(defun elixir-smie--semi-ends-match ()
177190
"Return non-nil if the current line concludes a match block."
178191
(when (not (eobp))
@@ -292,7 +305,8 @@
292305
(t (smie-rule-parent))))
293306
(`(:before . "MATCH-STATEMENT-DELIMITER")
294307
(cond
295-
((smie-rule-parent-p "MATCH-STATEMENT-DELIMITER")
308+
((and (smie-rule-parent-p "do")
309+
(smie-rule-hanging-p))
296310
(smie-rule-parent))
297311
((and (not (smie-rule-sibling-p))
298312
(nth 2 smie--parent)
@@ -302,12 +316,29 @@
302316
(not (nth 2 smie--parent))
303317
(smie-rule-hanging-p))
304318
(smie-rule-parent))))
319+
(`(:after . "MATCH-STATEMENT-DELIMITER")
320+
(cond
321+
((and (smie-rule-parent-p "MATCH-STATEMENT-DELIMITER")
322+
(smie-rule-hanging-p)
323+
(smie-rule-sibling-p))
324+
(if (elixir-smie-last-line-end-with-block-operator-p)
325+
(smie-rule-parent)
326+
0))
327+
(t
328+
(smie-rule-parent))))
305329
(`(:before . "fn")
306330
(smie-rule-parent))
307331
(`(:before . "do:")
308332
(cond
309333
((smie-rule-parent-p "def" "if")
310334
(smie-rule-parent))))
335+
(`(:before . "do")
336+
(cond
337+
((and (smie-rule-parent-p "case")
338+
(smie-rule-hanging-p))
339+
(smie-rule-parent 2))
340+
(t
341+
elixir-smie-indent-basic)))
311342
(`(:before . "end")
312343
(smie-rule-parent))
313344
;; Closing paren on the other line
@@ -323,12 +354,30 @@
323354
;; ()
324355
;; .....
325356
((smie-rule-parent-p "do")
326-
(smie-rule-parent elixir-smie-indent-basic))
357+
(smie-rule-parent))
327358
(t (smie-rule-parent))))
328359
(`(:before . "[")
329360
(cond
330361
((smie-rule-hanging-p)
331362
(smie-rule-parent))))
363+
(`(:before . "{")
364+
(cond
365+
;; Example
366+
;;
367+
;; case parse do
368+
;; { [ help: true ], _, _ }
369+
;; -> :help
370+
;; { _, [ user, project, count ], _ }
371+
((and (not (smie-rule-hanging-p))
372+
(smie-rule-parent-p "do"))
373+
(smie-rule-parent))
374+
((and (smie-rule-parent-p "MATCH-STATEMENT-DELIMITER")
375+
(not (smie-rule-hanging-p)))
376+
(if (elixir-smie-last-line-end-with-block-operator-p)
377+
(smie-rule-parent elixir-smie-indent-basic)
378+
(if (elixir-smie-last-line-start-with-block-operator-p)
379+
(smie-rule-parent -2)
380+
(smie-rule-parent))))))
332381
(`(:after . "{")
333382
(cond
334383
((smie-rule-hanging-p)
@@ -346,7 +395,21 @@
346395
(`(:before . "->")
347396
(cond
348397
((smie-rule-hanging-p)
349-
(smie-rule-parent elixir-smie-indent-basic))))
398+
(smie-rule-parent elixir-smie-indent-basic))
399+
;; Example
400+
;;
401+
;; case parse do
402+
;; { [ help: true ], _, _ }
403+
;; -> :help
404+
;; ...
405+
((and (not (smie-rule-hanging-p))
406+
(smie-rule-parent-p "do"))
407+
elixir-smie-indent-basic)
408+
((and (not (smie-rule-hanging-p))
409+
(smie-rule-parent-p "MATCH-STATEMENT-DELIMITER"))
410+
(smie-rule-parent)
411+
)
412+
))
350413
(`(:after . "->")
351414
(cond
352415
;; This first condition is kind of complicated so I'll try to make this
@@ -372,8 +435,11 @@
372435
;; Otherwise, if just indent by two.
373436
((smie-rule-hanging-p)
374437
(cond
375-
((smie-rule-parent-p "after" "catch" "do" "rescue" "try")
376-
elixir-smie-indent-basic)
438+
((smie-rule-parent-p "catch" "rescue")
439+
(smie-rule-parent (+ elixir-smie-indent-basic
440+
elixir-smie-indent-basic)))
441+
((smie-rule-parent-p "after" "do" "try")
442+
(smie-rule-parent elixir-smie-indent-basic))
377443
(t (smie-rule-parent elixir-smie-indent-basic))))))
378444
(`(:before . ";")
379445
(cond
@@ -390,16 +456,32 @@
390456
((and (smie-rule-parent-p "if")
391457
(smie-rule-hanging-p))
392458
(smie-rule-parent))
459+
((and (smie-rule-parent-p "else")
460+
(smie-rule-hanging-p))
461+
(smie-rule-parent elixir-smie-indent-basic))
393462
((smie-rule-parent-p "after" "catch" "def" "defmodule" "defp" "do" "else"
394463
"fn" "if" "rescue" "try" "unless")
395-
(smie-rule-parent elixir-smie-indent-basic))
464+
(smie-rule-parent))
465+
;; Example
466+
;;
467+
;; case parse do
468+
;; { [ help: true ], _, _ }
469+
;; -> :help
470+
;; { _, [ user, project, count ], _ }
471+
;; -> { user, project, count }
472+
;; ...
473+
((and (smie-rule-parent-p "->")
474+
(smie-rule-hanging-p))
475+
(smie-rule-parent))
396476
))
397477
(`(:after . ";")
398478
(cond
399479
((smie-rule-parent-p "def")
400480
(smie-rule-parent))
401481
((smie-rule-parent-p "if")
402482
(smie-rule-parent))
483+
((smie-rule-parent-p "after")
484+
(smie-rule-parent elixir-smie-indent-basic))
403485
((and (smie-rule-parent-p "(")
404486
(boundp 'smie--parent)
405487
(save-excursion

test/elixir-mode-indentation-test.el

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1184,6 +1184,52 @@ defmodule Foo do
11841184
end
11851185
")
11861186

1187+
(elixir-def-indentation-test complex-case-with-matches (:tags '(indentation))
1188+
"
1189+
case parse do
1190+
{ [ help: true ], _, _ }
1191+
-> :help
1192+
{ _, [ user, project, count ], _ } ->
1193+
{ user, project, count }
1194+
{ _, [ user, project ], _ } -> { user, project, @default_count }
1195+
{ _, [ _, project ], _ } -> { _, project, @default_count }
1196+
_ -> :help
1197+
end"
1198+
"
1199+
case parse do
1200+
{ [ help: true ], _, _ }
1201+
-> :help
1202+
{ _, [ user, project, count ], _ } ->
1203+
{ user, project, count }
1204+
{ _, [ user, project ], _ } -> { user, project, @default_count }
1205+
{ _, [ _, project ], _ } -> { _, project, @default_count }
1206+
_ -> :help
1207+
end")
1208+
1209+
1210+
(elixir-def-indentation-test complex-case-with-matches/2 (:tags '(indentation))
1211+
"
1212+
case parse do
1213+
{ [ help: true ], _, _ }
1214+
-> :help
1215+
{ _, [ user, project, count ], _ }
1216+
-> { user, project, count }
1217+
{ _, [ user, project ], _ }
1218+
-> { user, project, @default_count }
1219+
_ -> :help
1220+
end"
1221+
"
1222+
case parse do
1223+
{ [ help: true ], _, _ }
1224+
-> :help
1225+
{ _, [ user, project, count ], _ }
1226+
-> { user, project, count }
1227+
{ _, [ user, project ], _ }
1228+
-> { user, project, @default_count }
1229+
_ -> :help
1230+
end")
1231+
1232+
11871233
;; We don't want automatic whitespace cleanup here because of the significant
11881234
;; whitespace after `Record' above. By setting `whitespace-action' to nil,
11891235
;; `whitespace-mode' won't automatically clean up trailing whitespace (in my

0 commit comments

Comments
 (0)