3

In literate programming, I often like to write my code in small snippets and then export them all at once via org-babel-tangle. This works great for non-indentation sensitive code (especially with post-processing), but doesn't work quite well with languages like Haskell or Python as org-babel-tangle removes the initial whitespace:

This is a completely self-contained example of the problem.
Copy it into an org-mode buffer and try both 
=M-x org-export-dispatch= and =M-x org-babel-tangle=.

* A simple Python function
:PROPERTIES:
:header-args:python: :tangle example.py :padline no
:END:

Here's a small example function in Python:

#+begin_src python  :shebang "#!/usr/bin/env python"
def foo():
#+end_src

According to org-mode's documentation[fn:1], we can use `-i' 
to keep the indentation, so let's do that on the continuation 
of the aforementioned example:

#+begin_src python -i
    """Says hello!"""
    print("Hello, world!")
#+end_src

If we (org-export-dispatch) the file, then everything seems 
nice. However, if we (org-babel-tangle) the file, then the 
indentation is gone and thus our Python file invalid.

* Footnotes

[fn:1] See [[info:org#Literal Examples][info:org#Literal Examples]].

The -i switch doesn't seem to work for org-babel-tangle at all. While I could use <<noweb>> to glue the code together in a hidden, non-exported source block, I would rather like to have org-babel-tangle behave correctly.

Is there some hidden option I'm missing? How can I keep the indentation when I tangle files via org-babel-tangle similarly to the -i switch for exporting?

NickD
  • 27,023
  • 3
  • 23
  • 42
Zeta
  • 1,045
  • 9
  • 18

1 Answers1

4

You can use the variable org-src-preserve-indentation. If you set it to t before tangling like this:

#+begin_src emacs-lisp
(setq org-src-preserve-indentation t)
#+end_src

then the tangle will work as you expect.

The variable is defined with a defcustom so it is meant to be customized as you wish. You can either set it in your init file as above or customize it by hitting the customize link in its docstring, which you get with C-h v org-src-preserve-indentation.

EDIT: As a couple of comments point out, Emacs provides a very general mechanism (it can be used in any file, not just Org mode files) for setting the value of a variable as a local, per-file variable. As the documentation of file local variables points out, you can add a section at the very end of the file, like this:

...

* File local variables                                     :noexport:

# Local Variables:
# org-src-preserve-indentation: t
# End:

Tagging the section as noexport prevents it from cluttering up any exported material.

Alternatively, you can add a single line (as a comment, so that Org mode will ignore it) at the top of the file like this:

# -*- org-src-preserve-indentation: t -*-

...

Local variables are activated when the file is opened, so after adding the local variable, you either have to save and kill the buffer and then reopen the file, or perhaps more conveniently do M-x normal-mode. If you get a question about safe local variables, you might want to add this variable to the list of safe local variables by pressing !.

NickD
  • 27,023
  • 3
  • 23
  • 42
  • Hm. It's unfortunate that a global variable is necessary. I usually like to keep `#+OPTIONS` or `PROPERTIES` local. I'll guess I'll use `add-file-local-variable` and add `(org-src-preserver-indentation . t)` to the safe values/variables. – Zeta Jan 06 '21 at 11:04
  • You might want to suggest that as an RFE on the Org mode mailing list. The thinking goes, I'm guessing, that users prefer it one way or the other and that does not depend on the block or file. Making everything local to a file does have an overhead I imagine. I'm a bit surprised that the default value is nil though. – NickD Jan 06 '21 at 14:46
  • Great answer. I had the same problem. It seems that the author of the document should determine how the code is tangled... but I'm sure there is wisdom in the current setup. – Schmudde Feb 09 '21 at 17:18
  • Actually variables can be set per-document with a header `# -*- org-src-preserve-indentation: t; -*- ` https://stackoverflow.com/a/20033865/1013628 – ibizaman Feb 23 '22 at 07:16