Subject: bug#20774: auto-fill doesn't work properly when first-line prefix differs in adaptive-fill-mode

From: Samuel Freilich <[email-masked]>
Date: Mon, 8 Jun 2015 19:39:03 -0400

The function do-auto-fill doesn't consider that in adaptive-fill-mode, the
first line's prefix might not match the fill-prefix for subsequent lines.

For example, markdown-mode configures adaptive-fill-mode so that when
filling list item paragraphs, there's a hanging indent:

*   List item...
    next line...

Currently, there's a bug where auto-fill-mode will break lines at the start
of a list item, even though the resulting line is just as long, e.g.:

*   [link](http://a-really-long-url.example.com/..
<http://a-really-long-url.example.com/>.)

When you hit enter at the end of the line in markdown-mode with autofill on
and the fill-column set to less than the length of that line, it becomes:

*
   [link](http://a-really-long-url.example.com/..
<http://a-really-long-url.example.com/>.)

That's incorrect behavior because the prefix added after breaking the line
is just as long as the line up to the point before the break.

The attached patch fixes this by ensuring that a line will be broken by
auto-fill only if the position is further along in the line than the length
of the fill prefix. It also ensures that the first-line fill prefix is
skipped when finding a point to break (that is, the line should not be
broken in the middle of the prefix), even if the first-line prefix differs
from the fill-prefix for subsequent lines.

*Detailed Reproduction Steps:*

Get markdown-mode from:
http://jblevins.org/projects/markdown-mode/markdown-mode.el

$ emacs -Q -l markdown-mode.el
M-x markdown-mode RET
M-x auto-fill-mode RET
M-x set-fill-column RET 5 RET

Type the following into the buffer and hit RET:
* Item

Actual result:
*
  Item
  [cursor]

Expected result:
* Item
  [cursor]

Peace,
-Sam
*** simple.el.old	2015-06-08 19:19:20.484397387 -0400
--- simple.el.new	2015-06-08 19:18:58.340305301 -0400
***************
*** 6559,6575 ****
  	       (setq fill-prefix prefix))))
  
        (while (and (not give-up) (> (current-column) fc))
! 	;; Determine where to split the line.
! 	(let* (after-prefix
  	       (fill-point
  		(save-excursion
  		  (beginning-of-line)
! 		  (setq after-prefix (point))
! 		  (and fill-prefix
! 		       (looking-at (regexp-quote fill-prefix))
! 		       (setq after-prefix (match-end 0)))
  		  (move-to-column (1+ fc))
! 		  (fill-move-to-break-point after-prefix)
  		  (point))))
  
  	  ;; See whether the place we found is any good.
--- 6559,6581 ----
  	       (setq fill-prefix prefix))))
  
        (while (and (not give-up) (> (current-column) fc))
!         ;; Determine where to split the line.
!         (let* (line-start
!                after-prefix
  	       (fill-point
  		(save-excursion
  		  (beginning-of-line)
! 		  (setq line-start (point))
!       ;; Skip the fill-prefix. Note that we might be on the first line of the
!       ;; paragraph, and the fist line can differ in adaptive-fill-mode.
!       (when (or (and adaptive-fill-mode
!                      adaptive-fill-first-line-regexp
!                      (looking-at adaptive-fill-first-line-regexp))
!                 (and fill-prefix
!                      (looking-at (regex-quote fill-prefix))))
!         (setq after-prefix (match-end 0)))
  		  (move-to-column (1+ fc))
! 		  (fill-move-to-break-point (or after-prefix line-start))
  		  (point))))
  
  	  ;; See whether the place we found is any good.
***************
*** 6578,6586 ****
  		(or (bolp)
  		    ;; There is no use breaking at end of line.
  		    (save-excursion (skip-chars-forward " ") (eolp))
! 		    ;; It is futile to split at the end of the prefix
! 		    ;; since we would just insert the prefix again.
! 		    (and after-prefix (<= (point) after-prefix))
  		    ;; Don't split right after a comment starter
  		    ;; since we would just make another comment starter.
  		    (and comment-start-skip
--- 6584,6592 ----
  		(or (bolp)
  		    ;; There is no use breaking at end of line.
  		    (save-excursion (skip-chars-forward " ") (eolp))
! 		    ;; It is futile to split earlier in the line than the length of the
! 		    ;; prefix, since we would just insert the prefix again.
! 		    (and fill-prefix (<= (point) (+ line-start (length fill-prefix))))
  		    ;; Don't split right after a comment starter
  		    ;; since we would just make another comment starter.
  		    (and comment-start-skip