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.

0

3 Answers 3

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.
5
  • Ok, edited to address that.
    – Chris
    Oct 1, 2015 at 1: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 1, 2016 at 18:14
  • Works beautifully to make fill-paragraph behave properly within blockquotes in markdown-mode. Mar 14, 2017 at 17:55
  • 2 years has passed since the answer. Download link wonderworks.com/download/filladapt.el is no longer available. Jul 26, 2017 at 12:01
  • The link works for me right now. Maybe there was a temporary problem with the site.
    – Chris
    Jul 28, 2017 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 "
3
  • 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, 2015 at 17:14
  • 1
    @Malabarba Looks like markdown-mode actually does this via paragraph definitions: gist.github.com/vermiculus/88759fd9f8368adbf663 Feb 14, 2015 at 17:24
  • Yes, that looks more like it.
    – Malabarba
    Feb 14, 2015 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)))
2
  • 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 1, 2020 at 23:25
  • Instead of * could I also accomplish this approach for * @param as a different pattern ?
    – alper
    Jun 2, 2020 at 11:57

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.