How can one enable org-indent-mode
(or otherwise indent content to Org headings) while still maintaining a consistent visual fill column?
-
Does this still happen? I tried replicating this in 2022 with org-mode + org-indent-mode + visual-fill-column-mode, and I didn't see the undesired overflow.– g-gundamCommented Oct 15, 2022 at 16:17
-
@g-gundam This happens for me in Org 9.5.5 on Emacs 28.1.– Matthew PiziakCommented Oct 15, 2022 at 23:56
3 Answers
I've finally figured out the solution to this.
Basically, the problem is that when org-indent does its fancy visual indentation it changes the visual position of columns on the screen. So for fill to be consistent between indentation levels current-fill-column needs to be adjusted by the current level of indentation.
The way org-indent accomplishes its visual indentation is by setting the line-prefix text property. You can reproduce this for yourself by putting some text in a Fundamental Mode buffer and running (set-text-properties (point-min) (point-max) '(line-prefix " "))
. You'll see the text shifted over by two columns, just like how org-indent does it, and if you look at the (current-column)
you'll see that those are also shifted over.
So this can be fixed by some return advice on current-fill column that adjusts it by the length of the line-prefix at point:
(defun my-org-indent-fill-column-advice (res)
(cond
((and (boundp 'org-indent-mode) org-indent-mode)
(- res
(length (plist-get (text-properties-at (point))
'line-prefix))))
(t res)))
(advice-add 'current-fill-column :filter-return #'my-org-indent-fill-column-advice)
-
Welcome to Emacs Stack Exchange! An excellent solution to a four year problem. I've tested it out and it works perfectly. Commented Aug 31 at 16:21
One way of achieving this behavior is to disable org-indent-mode
and set org-adapt-indentation
to t
. The side effect of this configuration is that spaces will be added to Org file, where org-indent-mode
only acts at render time.
The only way I found to do this is by overriding the function that returns the fill column.
(defun current-fill-column ()
"Return the fill-column to use for this line.
Subtracts right margin and org indentation level from fill-column"
(let ((indent-level (if (bound-and-true-p org-indent-mode)
(* org-indent-indentation-per-level
(org-current-level))
0))
(margin (or (get-text-property (point) 'right-margin) 0)))
(- fill-column indent-level margin)))
This probably misses some edge cases, since the original function is more complex, but this is working for my purposes so far.