Skip to content

Commit a1830e4

Browse files
committed
Fixed indents of for-statements
1 parent 0bd26af commit a1830e4

File tree

2 files changed

+412
-48
lines changed

2 files changed

+412
-48
lines changed

swift-mode.el

Lines changed: 135 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ class Foo:
9494
(switch)
9595
(case)
9696
(default)
97+
(for)
9798
(insts ";" insts)
9899
(insts "IMP;" insts))
99100
;; expressions.
@@ -119,6 +120,8 @@ class Foo:
119120
;; case label.
120121
(case (id "case" id ":" id))
121122
(default (id "default" id ":" id))
123+
;; for statement.
124+
(for (id "for" expr ";" expr ";" expr) (id "for" expr "in" expr))
122125
;; block.
123126
(block ("{" insts "}"))
124127
;; types.
@@ -186,25 +189,27 @@ class Foo:
186189
;; let foo: Foo<A> ← not inserts ";" here
187190
;; = new Foo<A>()
188191
;;
189-
(and (looking-back "[[:upper:]][\])>]*>" (- (point) 32) nil) ; see comment for T> in swift-smie--forward-token
192+
(and (looking-back "[[:alnum:]_][\])>]*>" (- (point) 32) nil) ; see comment for T> in swift-smie--forward-token
190193
(save-excursion
191194
(forward-comment (point-max))
192195
(not (looking-at "[:(=]"))))
196+
;; sentinel
197+
(= (point) (point-min))
193198
(not (or
194199
;; supresses implicit semicolon on empty line
195200
(save-excursion
196201
(goto-char (line-beginning-position))
197202
(< (line-end-position) (progn (forward-comment (point-max)) (point))))
198203
;; supresses implicit semicolon after operator
199-
(looking-back "[-.({[,!#$%&=^~\\|@+:*<>?]" (- (point) 1) t)
204+
(looking-back "[-.({[,!#$%&=^~\\|@+:*<>?;]" (- (point) 1) t)
200205
;; supresses implicit semicolon after keyword
201206
;; Note that "as?" is already handled by preceeding conditions.
202207
(save-excursion
203-
(member (smie-default-backward-token) '("as" "is" "class" "deinit" "enum" "extension" "func" "import" "init" "internal" "let" "operator" "private" "protocol" "public" "static" "struct" "subscript" "typealias" "var" "case" "for" "if" "switch" "where" "while" "associativity" "convenience" "dynamic" "didSet" "final" "get" "infix" "inout" "lazy" "mutating" "nonmutating" "optional" "override" "postfix" "precedence" "prefix" "required" "set" "unowned" "weak" "willSet")))
208+
(member (smie-default-backward-token) '("as" "is" "class" "deinit" "enum" "extension" "func" "import" "init" "internal" "let" "operator" "private" "protocol" "public" "static" "struct" "subscript" "typealias" "var" "case" "for" "if" "return" "switch" "where" "while" "associativity" "convenience" "dynamic" "didSet" "final" "get" "infix" "inout" "lazy" "mutating" "nonmutating" "optional" "override" "postfix" "precedence" "prefix" "required" "set" "unowned" "weak" "willSet")))
204209
;; supresses implicit semicolon before operator
205210
(progn
206211
(forward-comment (point-max))
207-
(looking-at "[-.{,!#$%&=^~\\|+:*<>?]"))
212+
(looking-at "[-.,!#$%&=^~\\|+:*<>?]"))
208213
;; supresses implicit semicolon before keyword
209214
(save-excursion
210215
;; note that comments are already skipped by previous condition
@@ -240,7 +245,7 @@ class Foo:
240245

241246
;; close angle bracket for type parameters.
242247
((and (eq (char-after) ?>)
243-
(looking-back "[[:upper:]][\])>]*" (- (point) 32) nil))
248+
(looking-back "[[:alnum:]_][\])>]*" (- (point) 32) nil))
244249
(forward-char 1)
245250
"T>")
246251

@@ -297,7 +302,7 @@ class Foo:
297302

298303
;; close angle bracket for type parameters.
299304
((and (eq (char-before) ?>)
300-
(looking-back "[[:upper:]][\])>]*" (- (point) 32) nil))
305+
(looking-back "[[:alnum:]_][\])>]*" (- (point) 32) nil))
301306
(backward-char 1)
302307
"T>")
303308

@@ -502,31 +507,34 @@ OFFSET is a offset from parent tokens, or 0 if omitted."
502507
(+ (smie-indent-virtual) swift-indent-supertype-offset))
503508
(current-column)))))
504509

505-
(`(:before . ,(or "IMP;" ";"))
506-
;; aligns with the first statement or a preceeding sibling that is at the
507-
;; beginning of a line unless that is a case label.
508-
;;
509-
;; indents with `swift-indent-offset` after case label.
510-
(let
511-
((pos (point))
512-
(parent (swift-smie--backward-sexps-until
513-
'("{" "(" "[" ":")
514-
'("IMP;" ";"))))
515-
(cons 'column
516-
(cond
517-
((equal (nth 2 parent) ":")
518-
(setq parent (swift-smie--backward-sexps-until
519-
'("{" "(" "[" "case" "default")
520-
'("IMP;" ";")))
521-
(if (member (nth 2 parent) '("case" "default"))
522-
(progn
523-
(goto-char (nth 1 parent))
524-
(+ (current-column) swift-indent-offset))
525-
(current-column)))
526-
(t
527-
(current-column))))))
528-
529-
(`(:after . ,(or "class" "func" "enum" "switch" "case"))
510+
(`(:before . "IMP;")
511+
(or
512+
;; special handling for for-in statement:
513+
;;
514+
;; for x in
515+
;; xs
516+
(save-excursion
517+
(and
518+
(save-excursion (equal (swift-smie--backward-token) "in"))
519+
(progn (forward-char 1)
520+
(swift-smie--backward-for-head))
521+
(progn
522+
(swift-smie--forward-token)
523+
(swift-smie--forward-token)
524+
(swift-smie--backward-token)
525+
(cons 'column (current-column)))))
526+
(swift-smie--rule-before-semicolon t)))
527+
528+
(`(:before . ";")
529+
(swift-smie--rule-before-semicolon nil))
530+
531+
(`(:before . "in")
532+
(when (swift-smie--backward-for-head)
533+
(swift-smie--forward-token)
534+
(swift-smie--forward-token)
535+
(swift-smie--backward-token)
536+
(cons 'column (current-column))))
537+
(`(:after . ,(or "class" "func" "enum" "switch" "case" "for"))
530538
;; i.e.
531539
;;
532540
;; switch
@@ -555,27 +563,106 @@ OFFSET is a offset from parent tokens, or 0 if omitted."
555563
(t nil))))
556564
))
557565

566+
(defun swift-smie--rule-before-semicolon (implicit)
567+
;; aligns with the first statement or a preceeding sibling that is at the
568+
;; beginning of a line unless that is a case label.
569+
;;
570+
;; indents with `swift-indent-offset` after case label.
571+
(or
572+
(swift-smie--rule-for)
573+
(let
574+
((pos (point))
575+
(parent (swift-smie--backward-sexps-until
576+
(list "{" "(" "[" ":" (if implicit ":" "for"))
577+
'("IMP;" ";"))))
578+
(cons 'column
579+
(cond
580+
((equal (nth 2 parent) ":")
581+
(setq parent (swift-smie--backward-sexps-until
582+
'("{" "(" "[" "case" "default")
583+
'("IMP;" ";")))
584+
(if (member (nth 2 parent) '("case" "default"))
585+
(progn
586+
(goto-char (nth 1 parent))
587+
(+ (current-column) swift-indent-offset))
588+
(current-column)))
589+
(t
590+
(current-column)))))))
591+
558592
(defun swift-smie--backward-for-head ()
559-
"Backward the head of a for-statement (i.e. 'for foo; bar; buz') and
560-
returns the column of the \"for\" token.
593+
"Backward the head of a for-statement (i.e. 'for foo; bar; buz' or
594+
'for x in xs') and returns the column of the \"for\" token.
561595
If the cursor is not at a head of a for-statement, keeps cursor position as is
562596
and returns nil"
563-
(save-excursion
564-
(let*
565-
((parent (swift-smie--backward-sexps-until
566-
swift-smie--statement-parent-tokens))
567-
(token (nth 2 parent)))
568-
(when (equal token ";")
569-
(goto-char (nth 1 parent))
570-
(setq parent (swift-smie--backward-sexps-until
571-
swift-smie--statement-parent-tokens))
572-
(setq token (nth 2 parent))
573-
(when (equal token ";")
597+
(let*
598+
((pos (point))
599+
(parent (swift-smie--backward-sexps-until
600+
swift-smie--statement-parent-tokens))
601+
(token (nth 2 parent))
602+
(result-column
603+
(cond
604+
;; 'for foo; bar; |buz' where '|' represents the cursor
605+
((equal token ";")
574606
(goto-char (nth 1 parent))
575-
(swift-smie--backward-sexps-until swift-smie--statement-parent-tokens)
576-
(when (equal (swift-smie--forward-token) "for")
577-
(swift-smie--backward-token)
607+
(setq parent (swift-smie--backward-sexps-until
608+
swift-smie--statement-parent-tokens))
609+
(setq token (nth 2 parent))
610+
(when (equal token ";")
611+
(goto-char (nth 1 parent))
612+
(swift-smie--backward-sexps-until
613+
swift-smie--statement-parent-tokens)
614+
(when (equal (swift-smie--forward-token) "for")
615+
(swift-smie--backward-token)
616+
(current-column))))
617+
((equal token "IMP;")
618+
;; four cases:
619+
;;
620+
;; 1.
621+
;; for x
622+
;; in
623+
;; |xs
624+
;;
625+
;; 2.
626+
;; for x in
627+
;; |xs
628+
;;
629+
;; 3.
630+
;; for x
631+
;; |in xs
632+
;; 4.
633+
;; |for x in xs
634+
(cond
635+
;; case 1 or 2
636+
((save-excursion (swift-smie--backward-token)
637+
(equal (swift-smie--backward-token) "in"))
638+
(goto-char (nth 1 parent))
639+
(swift-smie--backward-token) ; "in"
640+
(swift-smie--backward-token) ; "IMP;" or "x"
641+
(swift-smie--backward-sexps-until
642+
swift-smie--statement-parent-tokens)
643+
(when (equal (swift-smie--forward-token) "for")
644+
(swift-smie--backward-token)
645+
(current-column)))
646+
;; case 3
647+
((save-excursion (equal (swift-smie--forward-token) "in"))
648+
(goto-char (nth 1 parent))
649+
(swift-smie--backward-sexps-until
650+
swift-smie--statement-parent-tokens)
651+
(when (equal (swift-smie--forward-token) "for")
652+
(swift-smie--backward-token)
653+
(current-column)))
654+
;; case 4
655+
((save-excursion
656+
(and (equal (swift-smie--forward-token) "for")
657+
(progn
658+
(goto-char pos)
659+
(equal
660+
(nth 2 (swift-smie--backward-sexps-until '("IMP;" "in")))
661+
"in"))))
578662
(current-column)))))))
663+
(when (not result-column)
664+
(goto-char pos))
665+
result-column))
579666

580667
(defun swift-smie--rule-for ()
581668
"Special rule for 'for' statement."
@@ -640,7 +727,7 @@ and returns nil"
640727
(swift-smie--op-offset (swift-smie--goto-op-parent) ignore-question offset))
641728

642729
(defun swift-smie--rule-before-op (&optional ignore-question offset)
643-
;; When the token is not at the beginning of the line (i.e. not called from
730+
;; When the token is at the beginning of the line (i.e. not called from
644731
;; smie-indent-virtual) and if the previous line is indented manually,
645732
;; aligns with it.
646733
;; When the token is not at the beginning of the line, and if the current

0 commit comments

Comments
 (0)