Problem
By default org-mode indents the body after every heading based on its depth, this includes drawers and metadata like status changes.
* First heading
CLOSED: [2017-10-07 Sat 13:22]
:PROPERTIES:
:CUSTOM_ID: foobar
:END:
Arbitrary text...
** Another heading
Arbitrary text...
I started to dislike this, because for some reason it became a bit of a hassle to maintain proper indentation, especially with source/example/quote blocks, which also started at that indentation, but then it was inconsistent to drop the indentation for their content. I also struggled with finding a good indentation for bullet points: do they start with an extra space at that indentation level or not?
So I found org-indent-mode
, which magically displays everything with indentation, without having the actual spaces in the file. That doesn’t work well for me, as it hides the actual structure of the file and things like the fill-column
marker and tags are all over the place.
Solution
I gave up for it for a while, but recently found org-adapt-indentation
, which simply turns off the indentation altogether, if set to nil
. The only drawback is that drawers and metadata also isn’t indented. I kinda liked it for them, but I can live with that compromise.
(setq org-adapt-indentation nil)
This makes above example look like:
* First heading
CLOSED: [2017-10-07 Sat 13:22]
:PROPERTIES:
:CUSTOM_ID: foobar
:END:
Arbitrary text...
- bullet points
- and another
** Another heading
Arbitrary text...
So that’s great. I start bullet points at column 0, without a leading space, and all is well.
Migrate existing files
The next problem was fixing my existing org files. The following script does just that:
#!/usr/bin/env python3
import sys
filename = sys.argv[1]
def get_indentation(line):
i = 0
while i < len(line) and line[i] == " ":
i += 1
return i
output = ""
indentation_to_remove = 0
first_line = False
for line in open(filename):
line = line.rstrip()
if line.startswith("*"):
first_line = True
indentation_to_remove = 0
output += line + "\n"
continue
if not line:
output += "\n"
continue
if first_line:
first_line = False
indentation_to_remove = get_indentation(line)
if not line.startswith(" " * indentation_to_remove):
indentation_to_remove = get_indentation(line)
line = line[indentation_to_remove:]
output += line + "\n"
open(filename, "w").write(output)
And I ran it as seen below. This replaces the files, so best back them up or better yet use git, which also allows you to inspect the diff.
find . -iname '*.org' -exec remove-org-indentation.py {} \;
find . -iname '*.org_archive' -exec remove-org-indentation.py {} \;
find templates -iname '*.txt' -exec remove-org-indentation.py {} \;