19

I'm looking for a minor mode to keep paragraphs filled at all times while typing (similar to what aggressive-indent-mode does for indentation). It also needs to be smart enough to only fill comments (and maybe strings depending on the language).

Some things that I've tried are:

  • auto-fill-mode automatically fills while you are typing new paragraphs but doesn't refill when you edit paragraphs.

  • refill-mode does constantly refill paragraphs but it tries to wrap code into paragraphs as well as comments.

  • I tried adding fill-paragraph to the after-change-functions hook but it screws up undo and plenty of other things (this is probably all fixable but would take some effort).

Any better ideas?

Malabarba
  • 22,878
  • 6
  • 78
  • 163
dshepherd
  • 1,281
  • 6
  • 18
  • 6
    Aside: chapter 7 of [Glickstein's *Writing GNU Emacs Extensions*](http://shop.oreilly.com/product/9781565922617.do) walks through how you might implement the functionality you're after. Might be a great opportunity to learn/practice with elisp. – Dan Nov 20 '14 at 12:41
  • I'm looking the auto-fill-paragraph(with auto-fill enabled) in `org-mode`, but you may try [rebox2](https://github.com/lewang/rebox2) – CodyChan Jan 08 '15 at 13:19

2 Answers2

4

I came up with a minimal way of implementing this functionality: just bind space bar to also call (fill-paragraph)!

(defun fill-then-insert-space ()
  (interactive)
  (fill-paragraph)
  (insert " "))
(global-set-key (kbd "SPC") #'fill-then-insert-space)

There are a couple of caveat's that I've stumbled across so far:

  1. elisp-mode (possibly others) does some fancy code filling when you call fill-paragraph, this may or may not be what you want. Can probably be fixed with by testing if point is in a comment or docstring but I'm not sure how to do that.

  2. You sometimes can't easily enter multiple spaces (because the fill-paragraph kills any trailing spaces). Since the space-bar now acts like just-one-space it's probably ok to replace that binding with (insert " ").

I made a minor-mode containing this functionality, it's available on github or in the melpa package aggressive-fill-paragraph.

dshepherd
  • 1,281
  • 6
  • 18
  • I find it ironic that `aggressive-fill-paragraph` is far less aggressive than `refill-mode`, which is aggressive up to being pretty useless *(as you can't even quote someone with `> ` without refill-mode rearranging stuff: even if you use regexps for replacement)*. – Hi-Angel Jul 27 '19 at 19:53
1

If you like how refill-mode behaves (I don't :p) but not when it behaves, it should be relatively easy to fix by inhibiting it whenever you're not in the right conditions

For example

(defvar plop/refill-enabler-function nil)

(defun plop/region-in-comment (beg end)
  ;; should really be comment-only-p, but that seems really broken for me
  (not
   (loop for c from beg to end
      if (not (eq 'font-lock-comment-face (get-char-property c 'face)))
      return t)))

(defun plop/refill-after-change-function (beg end len)
  (unless undo-in-progress
    (when (and plop/refill-enabler-function
               (funcall plop/refill-enabler-function beg end))
      (setq refill-doit end))))

(defun plop/install-refill-hack ()
  (if refill-mode
      (progn
        (add-hook 'after-change-functions 'plop/refill-after-change-function nil t)
        (remove-hook 'after-change-functions 'refill-after-change-function t))
    (progn
      (remove-hook 'after-change-functions 'plop/refill-after-change-function t))))

(defun plop/refill-hook ()
  (set (make-local-variable 'plop/refill-enabler-function)
       #'plop/region-in-comment)
  (add-hook 'refill-mode-hook 'plop/install-refill-hack t t)
  (refill-mode))

(add-hook 'some-hook 'plop/refill-hook)

Basically it removes the function that triggers the refill from after-change-functions and replaces it with one that will in addition check that we're in a comment before doing exactly the same thing.

Sigma
  • 4,510
  • 21
  • 27
  • Looks like a good start, but still not quite right: if a refill is triggered while editing a comment, it refills the whole paragraph, including the surrounding code. This may be the fault of the surrounding mode for not defining paragraph limits properly, but I doubt it: I tried in Emacs Lisp mode, which I presume does things by the book. – Gilles 'SO- stop being evil' Jan 01 '15 at 00:20
  • well, that's why I said I don't like `refill-mode` :) The problem is that `refill-mode` uses `fill-region` instead of `fill-paragraph`, thus losing the ability to honor `fill-paragraph-function` and making things potentially messy – Sigma Jan 01 '15 at 02:31