forsooth!

By necessity, by proclivity, and by delight, we all quote.

No indentation in org-mode


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 {} \;
#+TITLE: No indentation in org-mode
#+DATE: <2017-10-07 Sat>
#+AUTHOR: @or
#+CATEGORY: tech
#+SUMMARY: Persuade org-mode not to indent after headings
#+SLUG: orgmode-no-indentation
#+TAGS: org, spacemacs

** Problem
By default org-mode indents the body after every heading based on its depth,
this includes drawers and metadata like status changes.
#+begin_src org
,* First heading
  CLOSED: [2017-10-07 Sat 13:22]
  :PROPERTIES:
  :CUSTOM_ID: foobar
  :END:
  Arbitrary text...

,** Another heading
   Arbitrary text...
#+end_src

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.

#+begin_src emacs-lisp
(setq org-adapt-indentation nil)
#+end_src

This makes above example look like:
#+begin_src org
,* First heading
CLOSED: [2017-10-07 Sat 13:22]
:PROPERTIES:
:CUSTOM_ID: foobar
:END:
Arbitrary text...
- bullet points
  - and another

,** Another heading
Arbitrary text...
#+end_src

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:

#+NAME: remove-org-indentation.py
#+begin_src python
#!/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)
#+end_src

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.
#+begin_src sh
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 {} \;
#+end_src