Skip to content

Commit 62cf880

Browse files
committed
Update electric indent inside multiline comments
More consistent behavior between `swift-mode:indent-new-comment-line`, `swift-mode:post-self-insert`, and `swift-mode:indent-line`. Automatically insert a line break before the closing delimiter of multiline comment.
1 parent ddc7ae6 commit 62cf880

File tree

1 file changed

+201
-79
lines changed

1 file changed

+201
-79
lines changed

swift-mode-indent.el

Lines changed: 201 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,12 @@
8484
:group 'swift
8585
:safe 'booleanp)
8686

87+
(defcustom swift-mode:break-line-before-comment-close t
88+
"If non-nil, break line before the closing delimiter of multiline comments."
89+
:type 'boolean
90+
:group 'swift
91+
:safe 'booleanp)
92+
8793
(defcustom swift-mode:highlight-anchor nil
8894
"Highlight anchor point for indentation if non-nil.
8995
@@ -172,22 +178,55 @@ declaration and its offset is `swift-mode:basic-offset'."
172178
(defun swift-mode:calculate-indent-of-multiline-comment ()
173179
"Return the indentation of the current line inside a multiline comment."
174180
(back-to-indentation)
175-
(let ((comment-beginning-position (nth 8 (syntax-ppss))))
181+
(let ((comment-beginning-position (nth 8 (syntax-ppss)))
182+
(starts-with-asterisk (eq (char-after) ?*)))
176183
(forward-line -1)
177184
(back-to-indentation)
178-
(if (<= (point) comment-beginning-position)
179-
;; The cursor was on the 2nd line of the comment, so aligns with
180-
;; the asterisk of the comment starter.
181-
(progn
182-
(goto-char comment-beginning-position)
183-
(forward-char)
184-
(swift-mode:indentation (point) 0))
185-
;; The cursor was on the 3rd or following lines of the comment, so aligns
186-
;; with a non-empty preceding line.
187-
(if (eolp)
188-
;; The cursor is on an empty line, so seeks a non-empty-line.
189-
(swift-mode:calculate-indent-of-multiline-comment)
190-
(swift-mode:indentation (point) 0)))))
185+
(cond
186+
((<= (point) comment-beginning-position)
187+
;; The cursor was on the 2nd line of the comment.
188+
(goto-char comment-beginning-position)
189+
(forward-char)
190+
;; If there are extra characters or spaces after asterisks, aligns with
191+
;; the first non-space character or end of line. Otherwise, aligns with
192+
;; the first asterisk.
193+
(when (and
194+
(looking-at "\\**[^*\n]+")
195+
(not (and swift-mode:prepend-asterisk-to-comment-line
196+
starts-with-asterisk)))
197+
(skip-chars-forward "*")
198+
(skip-syntax-forward " "))
199+
(swift-mode:indentation (point) 0))
200+
201+
;; The cursor was on the 3rd or following lines of the comment.
202+
203+
((= (save-excursion
204+
(forward-line)
205+
(back-to-indentation)
206+
(point))
207+
(save-excursion
208+
(goto-char comment-beginning-position)
209+
(if (forward-comment 1)
210+
(progn
211+
(backward-char)
212+
(skip-chars-backward "*")
213+
(point))
214+
-1)))
215+
;; Before the closing delimiter. Aligns with the first asterisk of the
216+
;; opening delimiter.
217+
(goto-char comment-beginning-position)
218+
(forward-char)
219+
(swift-mode:indentation (point) 0))
220+
221+
;; Otherwise, aligns with a non-empty preceding line.
222+
223+
((and (bolp) (eolp))
224+
;; The previous line is empty, so seeks a non-empty-line.
225+
(swift-mode:calculate-indent-of-multiline-comment))
226+
227+
(t
228+
;; The previous line is not empty, so aligns to this line.
229+
(swift-mode:indentation (point) 0)))))
191230

192231
(defun swift-mode:calculate-indent-of-multiline-string ()
193232
"Return the indentation of the current line inside a multiline string."
@@ -213,7 +252,7 @@ declaration and its offset is `swift-mode:basic-offset'."
213252
swift-mode:multiline-statement-offset))
214253
;; The cursor was on the 3rd or following lines of the comment, so
215254
;; aligns with a non-empty preceding line.
216-
(if (eolp)
255+
(if (and (bolp) (eolp))
217256
;; The cursor is on an empty line, so seeks a non-empty-line.
218257
(swift-mode:calculate-indent-of-multiline-string)
219258
(swift-mode:indentation (point) 0))))))
@@ -1527,15 +1566,14 @@ Return nil otherwise."
15271566
"Skips forward whitespaces and newlines."
15281567
(skip-syntax-forward " >"))
15291568

1530-
(defun swift-mode:incomplete-comment-p ()
1531-
"Return t if the point is inside an incomplete comment.
1569+
(defun swift-mode:incomplete-comment-p (chunk)
1570+
"Return t if the CHUNK is incomplete comment.
15321571
15331572
Return nil otherwise."
1534-
(let ((chunk (swift-mode:chunk-after)))
1535-
(and (swift-mode:chunk:comment-p chunk)
1536-
(save-excursion
1537-
(goto-char (swift-mode:chunk:start chunk))
1538-
(not (forward-comment 1))))))
1573+
(and (swift-mode:chunk:comment-p chunk)
1574+
(save-excursion
1575+
(goto-char (swift-mode:chunk:start chunk))
1576+
(not (forward-comment 1)))))
15391577

15401578
(defun swift-mode:indent-new-comment-line (&optional soft)
15411579
"Break the line at the point and indent the new line.
@@ -1550,20 +1588,21 @@ See `indent-new-comment-line' for SOFT."
15501588
(if soft (insert-and-inherit ?\n) (newline 1))
15511589
(delete-horizontal-space)
15521590

1591+
;; Inserts a prefix and indents the line.
15531592
(cond
15541593
((not (swift-mode:chunk:comment-p chunk))
15551594
(indent-according-to-mode))
15561595

15571596
((swift-mode:chunk:single-line-comment-p chunk)
1558-
(insert-before-markers-and-inherit
1597+
(insert-and-inherit
15591598
(save-excursion
15601599
(goto-char comment-beginning-position)
15611600
(looking-at "/+\\s *")
15621601
(match-string-no-properties 0)))
15631602
(indent-according-to-mode))
15641603

15651604
((not comment-multi-line)
1566-
(insert-before-markers-and-inherit
1605+
(insert-and-inherit
15671606
(save-excursion
15681607
(goto-char comment-beginning-position)
15691608
(looking-at "/\\*+\\s *")
@@ -1573,33 +1612,98 @@ See `indent-new-comment-line' for SOFT."
15731612
(forward-line 0)
15741613
(backward-char)
15751614
(delete-horizontal-space)
1576-
(insert-before-markers-and-inherit " */"))
1615+
(insert-and-inherit " */"))
15771616
(indent-according-to-mode))
15781617

1618+
(t
1619+
(swift-mode:format-multiline-comment-line-after-newline chunk soft)))
1620+
1621+
;; Cleans up the previous line.
1622+
(save-excursion
1623+
(forward-line 0)
1624+
(backward-char)
1625+
(delete-horizontal-space))))
1626+
1627+
(defun swift-mode:format-multiline-comment-line-after-newline (chunk soft)
1628+
"Insert prefix and indent current line in multiline comment.
1629+
1630+
The point is assumed inside multiline comment and just after newline.
1631+
1632+
The closing delimiter is also inserted and/or formatted depending on custom
1633+
variables `swift-mode:auto-close-multiline-comment' and
1634+
`swift-mode:break-line-before-comment-close'.
1635+
1636+
CHUNK is the comment chunk.
1637+
1638+
See `indent-new-comment-line' for SOFT."
1639+
(let ((comment-beginning-position (swift-mode:chunk:start chunk)))
1640+
(cond
15791641
((save-excursion
15801642
(forward-line -1)
15811643
(<= (point) comment-beginning-position))
15821644
;; The cursor was on the 2nd line of the comment.
1583-
;; Uses default prefix.
1584-
(when swift-mode:prepend-asterisk-to-comment-line
1585-
(insert-before-markers-and-inherit "*")
1586-
(when swift-mode:insert-space-after-asterisk-in-comment
1587-
(insert-before-markers-and-inherit " ")))
1645+
1646+
;; If the comment have only one line, delete a space after asterisk.
1647+
;;
1648+
;; Example:
1649+
;; /** aaa */
1650+
;; ↓
1651+
;; /**
1652+
;; aaa
1653+
;; */
1654+
;;
1655+
;; /** aaa
1656+
;; */
1657+
;; ↓
1658+
;; /**
1659+
;; aaa
1660+
;; */
1661+
(when (= (line-beginning-position)
1662+
(save-excursion
1663+
(goto-char comment-beginning-position)
1664+
(forward-comment 1)
1665+
(line-beginning-position)))
1666+
(save-excursion
1667+
(goto-char comment-beginning-position)
1668+
(forward-char)
1669+
(skip-chars-forward "*")
1670+
(when (looking-at " [ \t]*$")
1671+
(delete-char 1))))
1672+
1673+
;; If the point is just before the closing delimiter, breaks the line.
1674+
(when (and swift-mode:break-line-before-comment-close
1675+
(= (point)
1676+
(save-excursion
1677+
(goto-char comment-beginning-position)
1678+
(if (forward-comment 1)
1679+
(progn
1680+
(backward-char)
1681+
(skip-chars-backward "*")
1682+
(point))
1683+
-1))))
1684+
(save-excursion
1685+
(if soft (insert-and-inherit ?\n) (newline 1))
1686+
(indent-according-to-mode)))
1687+
1688+
;; Invokes `swift-mode:indent-line`
15881689
(indent-according-to-mode)
1589-
(insert-before-markers-and-inherit
1590-
(save-excursion
1591-
(goto-char comment-beginning-position)
1592-
(forward-char 1)
1593-
(looking-at "\\**\\(\\s *\\)")
1594-
(let ((prefix (match-string-no-properties 0)))
1595-
(if (= (length (match-string-no-properties 1)) 0)
1596-
""
1597-
(substring
1598-
(replace-regexp-in-string "\\*" " " prefix)
1599-
(if swift-mode:prepend-asterisk-to-comment-line
1600-
(if swift-mode:insert-space-after-asterisk-in-comment 2 1)
1601-
0)
1602-
(length prefix)))))))
1690+
1691+
;; Inserts or replaces a space to an asterisk.
1692+
(when swift-mode:prepend-asterisk-to-comment-line
1693+
(let ((columns-from-end (- (line-end-position) (point))))
1694+
(move-to-column
1695+
(save-excursion
1696+
(goto-char comment-beginning-position)
1697+
(forward-char)
1698+
(current-column)))
1699+
(insert-and-inherit "*")
1700+
(when (eq (char-after) ?\s)
1701+
(delete-char 1))
1702+
(when (and
1703+
swift-mode:insert-space-after-asterisk-in-comment
1704+
(not (eq (char-after) ?\s)))
1705+
(insert-and-inherit " "))
1706+
(goto-char (- (line-end-position) columns-from-end)))))
16031707

16041708
;; The cursor was on the 3nd or following lines of
16051709
;; the comment.
@@ -1611,39 +1715,34 @@ See `indent-new-comment-line' for SOFT."
16111715
(forward-line -1)
16121716
(looking-at "\\s *\\(\\*+\\s *\\)")))
16131717
;; The previous line has a prefix. Uses it.
1614-
(insert-before-markers-and-inherit (match-string-no-properties 1))
1615-
(indent-according-to-mode))
1616-
1617-
((save-excursion
1618-
(forward-line -1)
1619-
(looking-at "$"))
1620-
;; The previous line is empty. Uses the default indentation.
1718+
(insert-and-inherit (match-string-no-properties 1))
16211719
(indent-according-to-mode))
16221720

16231721
(t
1624-
;; Uses the prefix of the previous line.
1625-
(insert-before-markers-and-inherit
1626-
(save-excursion
1627-
(forward-line -1)
1628-
(looking-at "\\s *")
1629-
(match-string-no-properties 0)))))
1630-
1631-
;; Cleans up the previous line.
1632-
(save-excursion
1633-
(forward-line 0)
1634-
(backward-char)
1635-
(delete-horizontal-space))
1722+
;; Uses the default indentation.
1723+
(indent-according-to-mode)))
16361724

16371725
;; Closes incomplete multiline comment.
16381726
(when (and swift-mode:auto-close-multiline-comment
1639-
(swift-mode:chunk:multiline-comment-p chunk)
1640-
(swift-mode:incomplete-comment-p))
1727+
(swift-mode:incomplete-comment-p chunk))
16411728
(save-excursion
16421729
(end-of-line)
16431730
(when comment-multi-line
16441731
(if soft (insert-and-inherit ?\n) (newline 1)))
16451732
(insert-and-inherit "*/")
1646-
(indent-according-to-mode)))))
1733+
(indent-according-to-mode)))
1734+
1735+
;; Make sure the closing delimiter is on its own line.
1736+
(when swift-mode:break-line-before-comment-close
1737+
(save-excursion
1738+
(goto-char comment-beginning-position)
1739+
(when (forward-comment 1)
1740+
(backward-char)
1741+
(skip-chars-backward "*")
1742+
(skip-syntax-backward " ")
1743+
(when (not (bolp))
1744+
(if soft (insert-and-inherit ?\n) (newline 1))
1745+
(indent-according-to-mode)))))))
16471746

16481747
(defun swift-mode:post-self-insert ()
16491748
"Miscellaneous logic for electric indentation."
@@ -1656,31 +1755,54 @@ See `indent-new-comment-line' for SOFT."
16561755
(swift-mode:chunk:comment-p (swift-mode:chunk-after))
16571756
(save-excursion (backward-char) (skip-syntax-backward " ") (bolp)))
16581757
(when swift-mode:insert-space-after-asterisk-in-comment
1659-
(insert-before-markers-and-inherit " "))
1660-
(indent-according-to-mode))
1758+
(insert-and-inherit " "))
1759+
(when electric-indent-mode
1760+
(indent-according-to-mode)))
16611761

16621762
;; Fixes "* /" at the end of a multiline comment to "*/".
16631763
((and
1664-
(= last-command-event ?/)
16651764
swift-mode:fix-comment-close
1666-
(swift-mode:chunk:comment-p (swift-mode:chunk-after))
1667-
(save-excursion
1668-
(let ((pos (point)))
1669-
(forward-line 0)
1670-
(and
1671-
(looking-at "^\\s *\\*\\s +/")
1672-
(eq (match-end 0) pos)
1673-
(swift-mode:incomplete-comment-p)))))
1765+
(= last-command-event ?/)
1766+
(let ((chunk (swift-mode:chunk-after))
1767+
(pos (point)))
1768+
(and
1769+
(swift-mode:chunk:comment-p chunk)
1770+
(save-excursion
1771+
(forward-line 0)
1772+
(and
1773+
(looking-at "^\\s *\\*\\s +/")
1774+
(eq (match-end 0) pos)
1775+
(swift-mode:incomplete-comment-p chunk))))))
16741776
(backward-char)
16751777
(delete-horizontal-space)
16761778
(forward-char))
16771779

16781780
;; Indents electrically when ")" is inserted at bol as the end of a string
16791781
;; interpolation.
16801782
((and
1783+
electric-indent-mode
16811784
(= last-command-event ?\))
1682-
(save-excursion (backward-char) (skip-syntax-backward " ") (bolp)))
1683-
(indent-according-to-mode))))
1785+
(save-excursion (backward-char) (skip-syntax-backward " ") (bolp))
1786+
(= (swift-mode:chunk:start (swift-mode:chunk-after)) (1- (point))))
1787+
(indent-according-to-mode))
1788+
1789+
;; Indents electrically after newline inside strings and comments.
1790+
;; Unlike `electric-indent-mode', the previous line is not indented.
1791+
((and
1792+
electric-indent-mode
1793+
(= last-command-event ?\n))
1794+
(let ((chunk (swift-mode:chunk-after)))
1795+
(if (swift-mode:chunk:multiline-comment-p chunk)
1796+
(progn
1797+
(delete-horizontal-space)
1798+
(swift-mode:format-multiline-comment-line-after-newline
1799+
chunk
1800+
(not use-hard-newlines)))
1801+
(indent-according-to-mode)))
1802+
(save-excursion
1803+
(forward-line 0)
1804+
(backward-char)
1805+
(delete-horizontal-space)))))
16841806

16851807
(defun swift-mode:highlight-anchor (indentation)
16861808
"Highlight the anchor point of the INDENTATION."

0 commit comments

Comments
 (0)