@@ -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.
561595If the cursor is not at a head of a for-statement, keeps cursor position as is
562596and 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