8

Q: how can I format/fill poorly-formatted items in an org-mode bulleted list?

I'm trying to figure out how to make fill-paragraph work on poorly formatted bulleted items in an org-mode list. By "poorly formatted," I mean long-ish bullets that use multiple lines but need to be cleaned up to make them readable. The difficulty is that org-mode does not seem to recognize subsequent lines as part of the same bullet when the first non-whitespace character is in the same column as the bullet itself.

Hence, in the example below, bullet (1) does not need filling, bullets (2) and (3) need filling and respond as expected to fill-paragraph, but bullets (4) and (5) do not fill as expected:

* a header

  1) a simple bullet
  2) a bullet that responds nicely
     to
     fill-paragraph
     (try it!)
  3) another bullet that also responds nicely
    to
     fill-paragraph
    even though the "t" in "to" and the
     "e" in "even" line up with the space
         in between the "4)" and the start of the bullet
  4) a bullet that does
  NOT respond to fill-paragraph
  because the "N" in "NOT" is in the same column
  as the start of the bullet
  5) a similar problem:
the text is flush entirely to the left

First of all, why does this happen? Second, and more to the point, how can I convince org-mode to treat all of the lines up to the next bullet as part of the same bullet for fill-paragraph purposes?

9

It happens because Org uses indentation to define text as belonging to an item.

(info "(org)Plain lists")

Items belonging to the same list must have the same indentation on
the first line.

To convince Org to do what you want, you need to get the text indented to the level of the item. You can use C-x r t (string-rectangle) or C-x C-i (indent-rigidly) to do this and then filling will work like in #2 and #3.

If you are on the item line and you want to enter text below it, you can use C-j (org-return-indent) to move to the same indentation on the next line. That way, you can avoid formatting like in #4 and #5.

2

As @KyleMeyer explains in his answer, org-mode does not consider text to be part of a list item if it is not indented past the level of the corresponding bullet. So essentially, we need a way to absorb paragraphs into list items.

With point positioned inside a list item, the following command lets you do that without having to take care of indentation manually:

(defun org-back-to-item ()
  (re-search-backward "^ *[-+*]\\|^ *[1-9]+[)\.] " nil nil 1))

(defun org-fill-paragraph-handle-lists (&optional num-paragraphs)
  (interactive "p")
  (save-excursion
    (let ((bound (if mark-active
                     (- (region-end) 2)
                   (progn
                     (org-back-to-item)
                     (while (>= num-paragraphs 0)
                       (call-interactively 'org-mark-element)
                       (setq num-paragraphs (1- num-paragraphs)))
                     (- (region-end) 2)))))
      (while (search-forward "\n" bound t)
        (replace-match " ")))
    (org-fill-paragraph)))

(define-key org-mode-map (kbd "C-M-q") 'org-fill-paragraph-handle-lists)

The main idea is to replace occurrences of \n with SPC in the list item to fill before calling org-fill-paragraph on it.

Note that if you have more than one paragraph inside a list item:

  ...
  4) a bullet that does
  NOT respond to fill-paragraph
  because the "N" in "NOT" is in the same column
  as the start of the bullet

  Some more text
  5) ...

you can make Some more text (the second paragraph) become part of the list item by calling the command like this:

M-2 C-M-q

More specifically, org-fill-paragraph-handle-lists will absorb a single paragraph below a list item by default, but can be instructed to absorb any number of paragraphs by calling it with a numeric prefix arg.

  • Clever! There's one point that's not quite working yet. If point is in the text that org would, by default, not consider part of the item (e.g., if we're on the "NOT..." line in the example), it does not fill as intended -- that is, it fills as a separate paragraph and slurps up item 5) as well. The issue seems to be in how org-mark-element chooses the element. Will give it some more thought. – Dan Dec 11 '14 at 13:11
  • @Dan This issue can be addressed by defining a function that moves point back to the previous list item, and calling it before marking paragraphs. See the updated code in my answer. – itsjeyd Dec 11 '14 at 14:22

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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