(eval-when-compile (require 'cl))
(defgroup refill nil
"Refilling paragraphs on changes."
:group 'fill)
(defvar refill-ignorable-overlay nil
"Portion of the most recently filled paragraph not needing filling.
This is used to optimize refilling.")
(make-variable-buffer-local 'refill-ignorable-overlay)
(defun refill-adjust-ignorable-overlay (overlay afterp beg end &optional len)
"Adjust OVERLAY to not include the about-to-be-modified region."
(when (not afterp)
(save-excursion
(goto-char beg)
(forward-line -1)
(if (<= (point) (overlay-start overlay))
(move-overlay overlay (point-min) (point-min))
(move-overlay overlay (overlay-start overlay) (point))))))
(defun refill-fill-paragraph-at (pos &optional arg)
"Like `fill-paragraph' at POS, but don't delete whitespace at paragraph end."
(save-excursion
(goto-char pos)
(forward-paragraph)
(skip-syntax-backward "-")
(let ((end (point))
(beg (progn (backward-paragraph) (point)))
(obeg (overlay-start refill-ignorable-overlay))
(oend (overlay-end refill-ignorable-overlay)))
(unless (> beg pos) (goto-char pos)
(if (and (>= beg obeg) (< beg oend))
(let ( (fill-prefix
(if (and adaptive-fill-mode
(or (null fill-prefix) (string= fill-prefix "")))
(fill-context-prefix beg end)
fill-prefix))
(adaptive-fill-mode nil))
(save-restriction
(if use-hard-newlines
(fill-region oend end arg)
(fill-region-as-paragraph oend end arg)))
(move-overlay refill-ignorable-overlay obeg (point)))
(save-restriction
(if use-hard-newlines
(fill-region beg end arg)
(fill-region-as-paragraph beg end arg)))
(move-overlay refill-ignorable-overlay beg (point)))))))
(defun refill-fill-paragraph (arg)
"Like `fill-paragraph' but don't delete whitespace at paragraph end."
(refill-fill-paragraph-at (point) arg))
(defvar refill-doit nil
"Non-nil tells `refill-post-command-function' to do its processing.
Set by `refill-after-change-function' in `after-change-functions' and
unset by `refill-post-command-function' in `post-command-hook', and
sometimes `refill-pre-command-function' in `pre-command-hook'. This
ensures refilling is only done once per command that causes a change,
regardless of the number of after-change calls from commands doing
complex processing.")
(make-variable-buffer-local 'refill-doit)
(defun refill-after-change-function (beg end len)
"Function for `after-change-functions' which just sets `refill-doit'."
(unless undo-in-progress
(setq refill-doit end)))
(defun refill-post-command-function ()
"Post-command function to do refilling (conditionally)."
(when refill-doit (case this-command
(self-insert-command
(when (aref auto-fill-chars (char-before))
(refill-fill-paragraph-at refill-doit)
(setq refill-doit nil)))
((quoted-insert fill-paragraph fill-region) nil)
((newline newline-and-indent open-line indent-new-comment-line
reindent-then-newline-and-indent)
(save-excursion
(beginning-of-line) (skip-chars-backward "\n")
(save-restriction
(narrow-to-region (point-min) (point))
(refill-fill-paragraph-at refill-doit)))
(widen)
(save-excursion
(skip-chars-forward "\n")
(save-restriction
(narrow-to-region (line-beginning-position) (point-max))
(refill-fill-paragraph-at refill-doit))))
(t
(refill-fill-paragraph-at refill-doit)))
(setq refill-doit nil)))
(defun refill-pre-command-function ()
"Pre-command function to do refilling (conditionally)."
(when (and refill-doit (not (eq this-command 'self-insert-command)))
(refill-fill-paragraph-at refill-doit)
(setq refill-doit nil)))
(defvar refill-saved-state nil)
(define-minor-mode refill-mode
"Toggle Refill minor mode.
With prefix arg, turn Refill mode on iff arg is positive.
When Refill mode is on, the current paragraph will be formatted when
changes are made within it. Self-inserting characters only cause
refilling if they would cause auto-filling."
:group 'refill
:lighter " Refill"
:keymap '(("\177" . backward-delete-char-untabify))
(when refill-ignorable-overlay
(delete-overlay refill-ignorable-overlay)
(kill-local-variable 'refill-ignorable-overlay))
(when (local-variable-p 'refill-saved-state)
(dolist (x refill-saved-state)
(set (make-local-variable (car x)) (cdr x)))
(kill-local-variable 'refill-saved-state))
(if refill-mode
(progn
(add-hook 'after-change-functions 'refill-after-change-function nil t)
(add-hook 'post-command-hook 'refill-post-command-function nil t)
(add-hook 'pre-command-hook 'refill-pre-command-function nil t)
(set (make-local-variable 'refill-saved-state)
(mapcar (lambda (s) (cons s (symbol-value s)))
'(fill-paragraph-function auto-fill-function)))
(set (make-local-variable 'fill-paragraph-function)
'refill-fill-paragraph)
(set (make-local-variable 'backward-delete-char-untabify-method)
'hungry)
(setq refill-ignorable-overlay (make-overlay 1 1 nil nil t))
(overlay-put refill-ignorable-overlay 'modification-hooks
'(refill-adjust-ignorable-overlay))
(overlay-put refill-ignorable-overlay 'insert-behind-hooks
'(refill-adjust-ignorable-overlay))
(auto-fill-mode 0))
(remove-hook 'after-change-functions 'refill-after-change-function t)
(remove-hook 'post-command-hook 'refill-post-command-function t)
(kill-local-variable 'backward-delete-char-untabify-method)))
(provide 'refill)