Fix filling in c-ts-mode (bug#72116)

The previous fix introduced a regression in the case when there's only a
single line in the block comment.  In that case we don't want to add a
start at the second line:

/* foo foo foo */ should => /* foo foo
                               foo */

rather than   /* foo foo
               * foo */

This commit fixes that.

* lisp/progmodes/c-ts-common.el:
(c-ts-common--fill-block-comment): Don't mask the /*.
(c-ts-common--adaptive-fill-prefix): New function.
(c-ts-common-comment-setup): Don't set adaptive-regexp, change
adaptive-fill-first-line-regexp to work with the new
adaptive-fill-function.
* test/lisp/progmodes/c-ts-mode-resources/filling.erts: New tests
This commit is contained in:
Yuan Fu 2024-07-27 14:50:19 -07:00
parent e4cd26defc
commit 74bb1e5897
No known key found for this signature in database
GPG key ID: 56E19BC57664A442
2 changed files with 110 additions and 45 deletions

View file

@ -153,16 +153,16 @@ comment."
(end-marker nil)
(end-len 0))
(move-marker start-marker start)
;; We mask "/*" and the space before "*/" like
;; `c-fill-paragraph' does.
;; If the first line is /* followed by non-text, exclude this line
;; from filling.
(atomic-change-group
;; Mask "/*".
(goto-char start)
(when (looking-at (rx (* (syntax whitespace))
(group "/") "*"))
(goto-char (match-beginning 1))
(move-marker start-marker (point))
(replace-match " " nil nil nil 1))
(group "/") "*"
(* (or "*" "=" "-" "/" (syntax whitespace)))
eol))
(forward-line)
(move-marker start-marker (point)))
;; Include whitespaces before /*.
(goto-char start)
@ -206,16 +206,63 @@ comment."
(fill-region (max start-marker para-start) (min end para-end) arg))
;; Unmask.
(when start-marker
(goto-char start-marker)
(delete-char 1)
(insert "/"))
(when end-marker
(goto-char end-marker)
(delete-region (point) (+ end-len (point)))
(insert (make-string end-len ?\s)))
(goto-char orig-point))))
(defun c-ts-common--adaptive-fill-prefix ()
"Returns the appropriate fill-prefix for this paragraph.
This function should be called at BOL. Used by
`adaptive-fill-function'."
(cond
;; (1)
;; If current line is /* and next line is * -> prefix is *.
;; Eg:
;; /* xxx => /* xxx
;; * xxx xxx * xxx
;; * xxx
;; If current line is /* and next line isn't * or doesn't exist ->
;; prefix is whitespace.
;; Eg:
;; /* xxx xxx */ => /* xxx
;; xxx */
((and (looking-at (rx (* (syntax whitespace))
"/*"
(* "*")
(* (syntax whitespace))))
(let ((whitespaces (make-string (length (match-string 0)) ?\s)))
(save-excursion
(if (and (eq (forward-line) 0)
(looking-at (rx (* (syntax whitespace))
"*"
(* (syntax whitespace)))))
(match-string 0)
whitespaces)))))
;; (2)
;; Current line: //, ///, ////...
;; Prefix: same.
((looking-at (rx (* (syntax whitespace))
"//"
(* "/")
(* (syntax whitespace))))
(match-string 0))
;; (3)
;; Current line: *, |, -
;; Prefix: same.
;; This branch must return the same prefix as branch (1), as the
;; second line in the paragraph; then the whole paragraph will use *
;; as the prefix.
((looking-at (rx (* (syntax whitespace))
(or "*" "|" "-")
(* (syntax whitespace))))
(match-string 0))
;; Other: let `adaptive-fill-regexp' and
;; `adaptive-fill-first-line-regexp' decide.
(t nil)))
(defun c-ts-common-comment-setup ()
"Set up local variables for C-like comment.
@ -241,43 +288,15 @@ Set up:
(group (or (syntax comment-end)
(seq (+ "*") "/")))))
(setq-local adaptive-fill-mode t)
;; This matches (1) empty spaces (the default), (2) "//", (3) "*",
;; but do not match "/*", because we don't want to use "/*" as
;; prefix when filling. (Actually, it doesn't matter, because
;; `comment-start-skip' matches "/*" which will cause
;; `fill-context-prefix' to use "/*" as a prefix for filling, that's
;; why we mask the "/*" in `c-ts-common--fill-paragraph'.)
(setq-local adaptive-fill-regexp
(concat (rx (* (syntax whitespace))
(group (or (seq "/" (+ "/")) (* "*"))))
adaptive-fill-regexp))
;; For (1): Note the missing * comparing to `adaptive-fill-regexp'.
;; The reason for its absence is a bit convoluted to explain. Suffice
;; to say that without it, filling a single line paragraph that starts
;; with /* doesn't insert * at the beginning of each following line,
;; and filling a multi-line paragraph whose first two lines start with
;; * does insert * at the beginning of each following line. If you
;; know how does adaptive filling work, you know what I mean.
;;
;; For (2): If we only have (1), filling a single line that starts
;; with a single * (and not /*) in a block comment doesn't work as
;; expected: the following lines won't be prefixed with *. So we add
;; another rule to cover this case too. (See bug#72116.) I
;; intentionally made the matching strict (it only matches if there
;; are only a single * at the BOL) because I want to minimize the
;; possibility of this new rule matching in unintended situations.
(setq-local adaptive-fill-function #'c-ts-common--adaptive-fill-prefix)
;; Always accept * or | as prefix, even if there's only one line in
;; the paragraph.
(setq-local adaptive-fill-first-line-regexp
(rx bos
;; (1)
(or (seq (* (syntax whitespace))
(group (seq "/" (+ "/")))
(* (syntax whitespace)))
;; (2)
(seq (* (syntax whitespace))
(group "*")
(* (syntax whitespace))))
(* (syntax whitespace))
(or "*" "|")
(* (syntax whitespace))
eos))
;; Same as `adaptive-fill-regexp'.
(setq-local paragraph-start
(rx (or (seq (* (syntax whitespace))
(group (or (seq "/" (+ "/")) (* "*")))

View file

@ -6,6 +6,52 @@ Code:
Point-Char: |
Name: Single line
=-=
/* woooomy woooomy woooomy woooomy woooomy woooomy woooomy woooomy woooomy */
=-=
/* woooomy woooomy woooomy woooomy woooomy woooomy woooomy woooomy
woooomy */
=-=-=
Name: Two lines
=-=
/* woooomy woooomy woooomy woooomy woooomy woooomy woooomy woooomy
woooomy woooomy woooomy woooomy woooomy woooomy woooomy woooomy woooomy */
=-=
/* woooomy woooomy woooomy woooomy woooomy woooomy woooomy woooomy
woooomy woooomy woooomy woooomy woooomy woooomy woooomy woooomy
woooomy */
=-=-=
Name: Two lines with star
=-=
/* woooomy woooomy woooomy woooomy woooomy woooomy woooomy woooomy
* woooomy woooomy woooomy woooomy woooomy woooomy woooomy woooomy woooomy
*/
=-=
/* woooomy woooomy woooomy woooomy woooomy woooomy woooomy woooomy
* woooomy woooomy woooomy woooomy woooomy woooomy woooomy woooomy
* woooomy
*/
=-=-=
Name: First line empty (bug#72116)
=-=
/**
* rsite nrsoti ernsto ierntires ntoritsen roitsenrsoit enrstoi ensrotie nrsit ensroit enrsoi ensrien
*/
=-=
/**
* rsite nrsoti ernsto ierntires ntoritsen roitsenrsoit enrstoi
* ensrotie nrsit ensroit enrsoi ensrien
*/
=-=-=
Name: Type 1
=-=