12

Let's say I have the following buffer.

1. lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum

Hitting M-q here while in text-mode leads to the following.

1. lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem
ipsum lorem ipsum lorem ipsum lorem ipsum

On the other hand, if I activate markdown-mode, I get the following (Markdown is just an example, you see similar behavior in various modes).

1. lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem
   ipsum lorem ipsum lorem ipsum lorem ipsum

How do I configure text-mode to do that?

I imagine this can be achieved by writting a special fill-paragraph-function, but this variable is just set to nil in markdown-mode, so there's probably an easier way.

Malabarba
  • 22,878
  • 6
  • 78
  • 163

3 Answers3

6

I've been a happy user of filladapt-mode for a long time, which handles this sort of thing really nicely. For info, see

http://emacswiki.org/emacs/FillAdapt

From that page:

Filladapt by KyleJones enhances Emacs’ fill functions by guessing a fill prefix, such as a comment sequence in program code, and handling bullet points like “1.” or “*”.

For example, it could turn this

* Pretend I'm a really super long line.
* And the window's narrow.

into

* Pretend I'm a really super
  long line.
* And the window's narrow.
Chris
  • 261
  • 3
  • 5
  • Ok, edited to address that. – Chris Oct 01 '15 at 01:29
  • to enable this mode in conjunction w/ another mode, add something like `(add-hook 'org-mode-hook 'turn-on-filladapt-mode)` to your config file (this info isn't directly available on the linked wiki page). – Mark Feb 01 '16 at 18:14
  • Works beautifully to make `fill-paragraph` behave properly within blockquotes in `markdown-mode`. – Resigned June 2023 Mar 14 '17 at 17:55
  • 2 years has passed since the answer. Download link http://www.wonderworks.com/download/filladapt.el is no longer available. – Tankman六四 Jul 26 '17 at 12:01
  • The link works for me right now. Maybe there was a temporary problem with the site. – Chris Jul 28 '17 at 18:48
3
(fill-paragraph &optional JUSTIFY REGION)

[...]

If `fill-paragraph-function' is non-nil, we call it (passing our
argument to it), and if it returns non-nil, we simply return its value.

If `fill-paragraph-function' is nil, return the `fill-prefix' used for filling.

[...]

markdown-mode presumably sets fill-paragraph-function to nil so that the function uses fill-prefix to do the filling.

(let ((fill-prefix (make-string (length "1. ") ? ))
  (fill-paragraph))

Full example:

(let* ((num 15)
       (numstr (format "%d. " num))
       (fill-prefix (make-string (length numstr) ? )))
  (with-temp-buffer
    (loop for i from 1 to 15 do
          (insert (format "lorem ipsum (%d) doler sit amet " i)))
    (beginning-of-line)
    (insert numstr)
    (fill-paragraph)
    (buffer-string)))

;; =>

"\
15. lorem ipsum (1) doler sit amet lorem ipsum (2) doler sit amet
    lorem ipsum (3) doler sit amet lorem ipsum (4) doler sit amet
    lorem ipsum (5) doler sit amet lorem ipsum (6) doler sit amet
    lorem ipsum (7) doler sit amet lorem ipsum (8) doler sit amet
    lorem ipsum (9) doler sit amet lorem ipsum (10) doler sit amet
    lorem ipsum (11) doler sit amet lorem ipsum (12) doler sit amet
    lorem ipsum (13) doler sit amet lorem ipsum (14) doler sit amet
    lorem ipsum (15) doler sit amet "
Sean Allred
  • 6,861
  • 16
  • 85
  • 1
    _"markdown-mode presumably sets fill-paragraph-function to nil so that the function uses fill-prefix to do the filling."_ That can't be the whole story. When I hit `M-q`, `fill-paragraph` is invoked directly (there's no let-bind around it). While it's possible that `fill-prefix` is ultimately used for this purpose, there has to be some configuration variable that allows it to be auto-detected. – Malabarba Feb 14 '15 at 17:14
  • 1
    @Malabarba Looks like `markdown-mode` actually does this via paragraph definitions: https://gist.github.com/vermiculus/88759fd9f8368adbf663 – Sean Allred Feb 14 '15 at 17:24
  • Yes, that looks more like it. – Malabarba Feb 14 '15 at 17:42
3

Sean's gist pointed me in the right direction, and here's the snippet that solved it.

(defun my-adaptive-fill-function ()
  "Return prefix for filling paragraph or nil if not determined."
  (cond
   ;; List item inside blockquote
   ((looking-at "^[ \t]*>[ \t]*\\([0-9]+\\.\\|[*+-]\\)[ \t]+")
    (replace-regexp-in-string
     "[0-9\\.*+-]" " " (match-string-no-properties 0)))
   ;; Blockquote
   ((looking-at "^[ \t]*>[ \t]*")
    (match-string-no-properties 0))
   ;; List items
   ((looking-at "^\\([ \t]*\\)\\([0-9]+\\.\\|[\\*\\+-]\\)\\([ \t]+\\)")
    (match-string-no-properties 0))
   ;; No match
   (t nil)))

;; Paragraph filling in text-mode.
(add-hook 'text-mode-hook
  (lambda ()
    (set (make-local-variable 'paragraph-start)
         "\f\\|[ \t]*$\\|[ \t]*[*+-] \\|[ \t]*[0-9]+\\.[ \t]\\|[ \t]*: ")
    (set (make-local-variable 'paragraph-separate)
         "\\(?:[ \t\f]*\\|.*  \\)$")
    (set (make-local-variable 'adaptive-fill-first-line-regexp)
         "\\`[ \t]*>[ \t]*?\\'")
    (set (make-local-variable 'adaptive-fill-function)
         'my-adaptive-fill-function)))
Malabarba
  • 22,878
  • 6
  • 78
  • 163
  • If I have have empty line as bullet like only start `*`, when I do `M-q` it is removes. Is it possible to prevent to delete empty lines that only have `*`? – alper Jun 01 '20 at 23:25
  • Instead of `*` could I also accomplish this approach for `* @param` as a different pattern ? – alper Jun 02 '20 at 11:57