org.nvim

Source blocks (Babel) in depth

1. How to use this file

Babel runs the code in #+begin_src blocks and writes what the code returns or prints back into the file, under a #+RESULTS: line. Blocks can take arguments (:var), call each other, include each other (noweb), share a live interpreter (:session) and be written out to source files (tangling). This file walks through all of it, from the first <C-c><C-c> to tangling a small program.

  • The file starts folded. <Tab> on a heading opens it, <S-Tab> cycles the whole buffer.
  • Nothing breaks if you make a mess: u undoes, and git checkout examples/17-babel.org restores the file.
  • <prefix> means <leader>o (the default mappings.prefix). g? lists every key of the buffer, <prefix>bh only the Babel ones.
  • The Emacs keys work too: C-c C-v e, C-c C-v t … (:h org-emacs-keys).
  • Lines starting with Try: are exercises, Expect: says what you should see afterwards. Lines starting with =# = are Org comments that annotate the examples; they are never exported.
  • Most blocks already show a #+RESULTS:, produced by org.nvim itself. Running them again replaces the result with the same text (unless the block prints the time or a random number). Remove a result with <prefix>bk to watch it come back.

Start Neovim from the repo root with the bundled init file, so your own config is not involved:

nvim -u examples/minimal_init.lua examples/17-babel.org

Tangling writes files into examples/17-babel-out/, a directory next to this file. Delete it when you are done: rm -r examples/17-babel-out.

1.1. Which interpreters you need

Lua blocks run inside Neovim: they always work, need nothing installed, and can use the whole vim API. sh needs a POSIX shell, which every Unix-like system has. All the exercises use one of these two. A few examples show other languages; they only run when the interpreter is on your $PATH:

Language Interpreter Notes
lua none (inside Neovim) print goes to the output
sh bash sh / bash also zsh, fish
python python3 :python picks another binary
js node :cmd picks another binary
ruby ruby (irb for sessions)  
sqlite sqlite3 :db names the database
awk perl awk / perl  
C cpp gcc / g++ compiled, then run
emacs-lisp emacs --batch runs in a separate Emacs

:checkhealth org reports which of them it found.

1.2. Keys in this file

Key Emacs What it does
<C-c><C-c> / <prefix>be C-c C-v e run the block / #+CALL / inline src
<prefix>bb C-c C-v b run every block of the buffer
<prefix>bs C-c C-v s run every block of the subtree
<prefix>bk C-c C-v k remove the result
<prefix>bn / <prefix>bp C-c C-v n/p next / previous block
<prefix>bu C-c C-v u go to the #+begin_src line
<prefix>bg / <prefix>br C-c C-v g/r go to a named block / result
<prefix>' C-c ' edit the block in its own buffer
<prefix>bv C-c C-v v show the expanded body
<prefix>bI C-c C-v I show the merged header arguments
<prefix>bc C-c C-v c check for misspelt header args
<prefix>bj C-c C-v j insert a header argument
<prefix>bd C-c C-v d split / wrap / insert a block
<prefix>ba C-c C-v a show the block's hash
<prefix>bo C-c C-v o open the result
<prefix>bm C-c C-v C-M-h select the block body
<prefix>bt / <prefix>bf C-c C-v t/f tangle this file / another file
<prefix>bi C-c C-v i add blocks to the Library of Babel
<prefix>bz / <prefix>bZ C-c C-v C-z / z show the session
<prefix>bl C-c C-v l run in the session and show it
<prefix>bK   kill the session
<Tab> on #+RESULTS:   fold / unfold the result

2. Running a block

A source block starts with #+begin_src LANG followed by optional header arguments, and ends with #+end_src. Put the cursor anywhere in it (on the #+begin_src line, in the body, or on #+end_src) and press <C-c><C-c> (or <prefix>be). The block runs in the background; while it runs, ⏳ executing… is shown at the end of the #+end_src line.

The simplest block: a Lua expression. Its value is the result.

1 + 2
3

A Lua block can also return a value, and use the vim API:

return "Neovim " .. vim.version().major .. "." .. vim.version().minor
Neovim 0.13

Try: put the cursor on the 1 + 2 line above and press <C-c><C-c>. Answer y to the question "Evaluate this lua code block on your system?".

Expect: the block below it now reads #+RESULTS: followed by : 3. The =: = prefix marks a one-line fixed-width result.

Try: change 1 + 2 to 6 * 7 and run it again.

Expect: the old result is replaced by : 42; it does not pile up.

2.1. The confirmation prompt

By default you are asked before every evaluation (Emacs org-confirm-babel-evaluate). This is the option babel.confirm_evaluate:

require("org").setup({
  babel = {
    -- never ask:
    confirm_evaluate = false,
    -- or: ask for everything except Lua
    -- confirm_evaluate = function(lang, body) return lang ~= "lua" end,
  },
})

Try: to stop the prompts for this session only, run this command: :lua require("org.config").opts.babel.confirm_evaluate = false

Expect: <C-c><C-c> on a block runs it at once, without a question. Restart Neovim to get the prompt back.

The :eval header argument controls one block:

:eval Effect
(none) / yes ask if confirm_evaluate says so, then run
query always ask, even when prompts are off
no / never never run (also :noeval)
never-export run by hand, but not when exporting
query-export ask when exporting
return "you will never see me"

Try: press <C-c><C-c> in the :eval no block above.

Expect: nothing is inserted; a message says evaluation is disabled.

2.2. Removing and folding results

  • <prefix>bk in a block deletes its result. With a count (1<prefix>bk, Emacs C-u C-c C-v k) it deletes every result in the buffer.
  • <Tab> on a #+RESULTS: line folds the result; :Org babel_hide_all_results folds all of them.
return { "alpha", "beta", "gamma", "delta" }
alpha beta gamma delta

Try: put the cursor in the block above and press <prefix>bk.

Expect: the #+RESULTS: line and the four-column table under it are gone. Press <C-c><C-c> to bring them back, then <Tab> on the #+RESULTS: line to fold and unfold them.

2.3. Running many blocks at once

  • <prefix>bb runs every block (and #+CALL: line and inline block) of the buffer, from top to bottom.
  • <prefix>bs runs every block of the current subtree.

Each one is confirmed unless prompts are off. Blocks with :eval no are skipped. Don't use <prefix>bb on this whole file before the "Library of Babel" exercise: its #+CALL: lines stop the run with an error until the library is loaded, and the session blocks start shells.

Try: on the "Running a block" heading press <prefix>bs.

Expect: every block of this section runs once (answer y each time); the :eval no blocks are skipped and keep having no result.

2.4. Moving between blocks

Key Moves to
<prefix>bn the next #+begin_src line
<prefix>bp the previous #+begin_src line
<prefix>bu the head of the block the cursor is in
<prefix>bg a named block (asks for the name)
<prefix>br a named result (asks for the name)
<prefix>bm selects the block body in Visual mode

Try: on this line press <prefix>bp twice, then <prefix>bn.

Expect: the cursor jumps from #+begin_src line to #+begin_src line. <prefix>bg then square jumps to the square block in "Named blocks".

3. Languages

The language after #+begin_src picks the interpreter. The plugin enables shells, python, lua, js/ts, ruby, perl, php, R, go, rust, sqlite, sql, C, C++, D, awk and emacs-lisp out of the box (babel.languages).

3.1. Lua: runs inside Neovim

Lua needs nothing installed. A block that is a single expression returns its value; otherwise use return. print goes to the output (see "Results").

local words = vim.split("the quick brown fox", " ")
return #words .. " words, longest: " .. vim.iter(words):fold("", function(a, w)
  return #w > #a and w or a
end)
4 words, longest: quick

Several return values are joined with , =; =nil gives nil:

return "a", 2, true
a, 2, true
return nil
nil

A Lua table that is a list becomes an Org list-table (one row); a list of lists becomes a table; a table with keys becomes a two-column table sorted by key:

return { { "x", "x²" }, { 1, 1 }, { 2, 4 }, { 3, 9 } }
x x²
1 1
2 4
3 9
return { lang = "lua", version = 5.1, jit = jit ~= nil }
jit true
lang lua
version 5.1

Try: in the key/value block above add , os = jit.os before the closing brace and press <C-c><C-c>.

Expect: a fourth row appears, sorted between lang and version, with your OS name (OSX, Linux or Windows).

Because the code runs in the editor, a block can act on the editor. This one counts the headings of this very file:

local n = 0
for _, l in ipairs(vim.api.nvim_buf_get_lines(0, 0, -1, false)) do
  if l:match("^%*+ ") then n = n + 1 end
end
return n .. " headings in this file"
50 headings in this file

(os.exit() or an endless loop would affect Neovim itself, and babel.timeout cannot stop Lua code.)

3.2. Shell

Shell blocks run sh (or bash, zsh, fish). By default their output is the result, and it is read like data: one line stays text, several lines become a table split at tabs, commas or runs of spaces.

echo "hello from sh"
hello from sh
printf 'apples 3\nbananas 12\ncherries 7\n'
apples 3
bananas 12
cherries 7

Add :results output to keep the text as it is (see "Results"):

printf 'apples 3\nbananas 12\ncherries 7\n'
apples 3
bananas 12
cherries 7

Try: in the block above, change :results output to :results value and run it.

Expect: the result becomes : 0: for shells, the "value" is the exit status. Put back output.

Errors: what a program writes to stderr (and a non-zero exit code) goes to the *Org-Babel Error Output* buffer in a split; the result keeps only the standard output.

echo "this goes to the result"
echo "this goes to the error buffer" >&2
exit 3

Try: run the block above.

Expect: : this goes to the result under #+RESULTS:, and a split named *Org-Babel Error Output* that shows the stderr line and the exit code 3.

3.3. Other languages (need their interpreter)

These show the same idea in other languages. They only run when the interpreter is installed; the results here were produced by org.nvim.

return [[n, n**2] for n in range(1, 4)]
1 1
2 4
3 9
console.log(["a", "b", "c"].map((s) => s.toUpperCase()).join("-"))
A-B-C
[1, 2, 3].sum * 10
60
select 'Mon' as day, 3 as tasks union all select 'Tue', 5;
day tasks
Mon 3
Tue 5
BEGIN { for (i = 1; i <= 3; i++) printf "%d%s", i * i, (i < 3 ? " " : "\n") }
1 4 9

Emacs-lisp blocks run in a separate emacs --batch (not in the editor), and fall back to the formula interpreter of tables when Emacs is missing.

4. Results

The :results header argument decides four things, which can be combined in one value (:results output table replace):

Group Values
collection value (default), output
type table (vector), list, verbatim, scalar, file
format raw, org, drawer, html, latex, code, pp, link
handling replace (default), append, prepend, silent, none

4.1. value versus output

value is what the code returns, output what it prints.

print("printed")
return "returned"
returned
print("printed")
return "returned"
printed

4.2. Types: table, list, verbatim, scalar

A list-like value becomes a table unless you ask otherwise.

return { "red", "green", "blue" }
red green blue
return { "red", "green", "blue" }
  • red
  • green
  • blue
printf 'a b\nc d\n'
a b
c d
echo "one two three"
one two three
return { 1, 2, 3 }
(1 2 3)

Long text (babel.min_lines_for_block_output, 10 lines by default) goes into an example block instead of =: = lines:

for i = 1, 12 do print("line " .. i) end
line 1
line 2
line 3
line 4
line 5
line 6
line 7
line 8
line 9
line 10
line 11
line 12

4.3. Formats: raw, org, drawer, html, code

By default text is quoted with =: =. Other formats insert it differently:

return "This is *bold* and /italic/."

This is bold and italic.

return "- item one\n- item two"
  • item one
  • item two
return "| a | b |\n| 1 | 2 |"
| a | b |
| 1 | 2 |
return "<b>bold</b>"
bold
return "print('generated code')"
print('generated code')

Try: run the raw block above twice.

Expect: the text appears twice: a raw result has no end marker, so it cannot be found and replaced. That is what drawer is for: run the drawer block twice and it stays single.

4.4. :wrap

:wrap wraps the result in any block: :wrap alone uses #+begin_results, :wrap src json a JSON src block, :wrap example an example block, :wrap export html an export block. Avoid :wrap quote or :wrap center: like in Emacs, those blocks are not recognised as a result, so every run adds another one instead of replacing it.

return vim.json.encode({ answer = 42 })
{"answer":42}
echo "an example block"
an example block
return "Wrapped in a results block."

Wrapped in a results block.

4.5. Handling: replace, append, prepend, silent, none

  • replace (the default) replaces the old result.
  • append / prepend add the new result after / before the old one.
  • silent shows the value as a message and writes nothing.
  • none neither shows nor writes (useful for side effects).
return os.date("%H:%M:%S")
15:07:56

Try: press <C-c><C-c> three times in the block above, a few seconds apart.

Expect: three more times appear under #+RESULTS:, each below the previous one. Change append to prepend and the newest goes on top.

return "shown in the message area only"

Try: run the silent block.

Expect: the message "shown in the message area only" (quoted, like Emacs' %S) and no #+RESULTS: line.

4.6. :cache

With :cache yes the result is stored with a hash of the body and header arguments: #+RESULTS[hash]:. Running the block again does nothing while the hash matches. Change the body and it runs again.

return "computed at " .. os.date("%Y-%m-%d")
computed at 2026-09-28

Try: press <C-c><C-c> in the block above.

Expect: nothing changes in the buffer: the hash still matches and the cached value is reused. <prefix>ba shows the same hash as in #+RESULTS[...]:. Now add a space at the end of the return line and run it again: the hash changes and the date is today's. A count forces a run: 1<prefix>be (Emacs C-u C-c C-c).

4.7. :file results

With :results file and :file NAME the result is written to a file and a link to it is inserted. :output-dir says where (and is created). <prefix>bo opens the file.

echo "Written by babel on a Monday"

Try: run the block above, then press <prefix>bo in it.

Expect: #+RESULTS: followed by [[file:17-babel-out/hello.txt]], and <prefix>bo opens that file with the text "Written by babel on a Monday".

5. Variables: :var

:var name=value defines a variable in the block. Values can be literals, tables, lists, or the results of other blocks.

5.1. Literals

Numbers stay numbers, quoted text is a string. Several :var can be given on one line or in separate :var arguments.

return x * y
42
return greeting .. ", " .. name .. "!"
Hello, Ada!

In a shell, variables are shell variables:

i=0
while [ "$i" -lt "$n" ]; do echo "hello $who"; i=$((i + 1)); done
hello world
hello world
hello world

Try: change n=3 to n=5 in the #+begin_src line above and run it.

Expect: five hello world rows.

A value that looks like an Emacs Lisp list is a list; a form like (+ 1 2) is evaluated:

return "#xs = " .. #xs .. ", total = " .. total
#xs = 3, total = 6

5.2. Tables and lists as input

A #+NAME: makes a table (or a list) available by name. A table arrives as a list of rows. The header row above the first hline is removed from the data by default.

name qty price
apples 12 0.50
bananas 6 0.25
cherry 100 0.05
local total = 0
for _, r in ipairs(rows) do total = total + r[2] * r[3] end
return string.format("%d rows, total %.2f", #rows, total)
3 rows, total 12.50

A named plain list arrives as a list of strings:

  • milk
  • eggs
  • bread
return table.concat(items, " + ")
milk + eggs + bread

Try: add a line - butter to the shopping list and run the block again.

Expect: : milk + eggs + bread + butter.

In a shell, a one-column value is a string with one item per line, a table is lines of tab-separated cells:

echo "$items" | sort
bread
eggs
milk

5.3. Slices and indexes

name[i] picks row i, name[i,j] one cell, name[i:j] a range of rows (both ends included), name[,j] a column and name[i:j,k:l] a rectangle. Indexes are 0-based; negative ones count from the end.

These examples use a table without a header, so row 0 is the first line:

11 12 13
21 22 23
31 32 33
return r
21 22 23
return c
13
return col
12 22 32
return rows
21 22 23
31 32 33
return box
12 13
22 23
return last
31 32 33

Try: change grid[-1] to grid[0:1] and run it.

Expect: a two-row table: | 11 | 12 | 13 | and | 21 | 22 | 23 |.

In a table with a header, like fruit, the header row is row 0 and the hline is row 1 (as in Emacs), so the first data row is row 2:

return first
apples 12 0.5
return names
apples bananas cherry
return p
0.05

5.4. :colnames, :rownames and :hlines

  • :colnames yes takes the first row as column names and puts them back on a table result of the same width. :colnames no keeps the header as a data row.
  • :rownames yes does the same for the first column.
  • :hlines yes keeps the hlines of the input (in Lua they are the string "hline").
for _, r in ipairs(t) do r[3] = r[3] * 2 end
return t
name qty price
apples 12 1
bananas 6 0.5
cherry 100 0.1
return t
apples 12 0.5
bananas 6 0.25
cherry 100 0.05
return #t .. " rows, first cell: " .. t[1][1]
4 rows, first cell: name
for _, r in ipairs(t) do r[1] = r[1] * 10 end
return t
name qty price
apples 120 0.5
bananas 60 0.25
cherry 1000 0.05
a 1
b 2
c 3
return t
a 1
b 2
c 3

5.5. Results of other blocks

A :var that names a block runs that block and uses its result. The block does not need a #+RESULTS:; arguments can be passed like a call.

return n * n
4
return a + b
29

A block can produce a table that another block consumes:

local t = {}
for i = 1, 4 do t[#t + 1] = { i, i * i, i * i * i } end
return t
1 1 1
2 4 8
3 9 27
4 16 64
local s = 0
for _, v in ipairs(cubes) do s = s + v end
return s
100

name[] gives the body text of a block instead of its result:

return vim.trim(code)
return n * n

Try: change the body of square to return n * n * n and run the a + b block again (without running square).

Expect: : 133 (8 + 125): the referenced block is always evaluated.

6. Named blocks and #+CALL

#+NAME: x above a block names it. #+CALL: x(args) runs it with other arguments and writes the result under the #+CALL: line.

return "Hello, " .. who .. punct
Hello, world!
Hello, Ada!
Hello, Linus?

Hello, Grace!

Try: put the cursor on #+CALL: greet(who"Ada")= and press <C-c><C-c>. Then change "Ada" to "Margaret" and run it again.

Expect: the line under its #+RESULTS: changes to : Hello, Margaret!.

A #+NAME: above a #+CALL: names its result, so the call itself can be used as a :var value:

Hello, Ada!
return s:upper()
HELLO, ADA!

Try: <prefix>br then ada.

Expect: the cursor jumps to the #+RESULTS: ada line.

6.1. Inline source blocks and calls

Inside a paragraph, a small block is written src_ followed by the language and the code in braces, and a call is written call_ followed by the block name and its arguments in parentheses. Header arguments go in square brackets after the language. <C-c><C-c> on one of them inserts the result right after it, wrapped in a {{{results(...)}}} macro (which exports as the bare value).

Two times three is return 2 * 3 and the square of nine is . Header arguments go in brackets: echo "hi from sh" .

Try: in the paragraph above, delete the first {{{results(...)}}} (the one with the 6), put the cursor on the inline lua block before it and press <C-c><C-c>.

Expect: the same {{{results(...)}}} with 6 comes back. Running it again replaces it rather than adding a second one.

Raw: return 6 * 7

Try: press <C-c><C-c> on the raw block in the line above.

Expect: the line reads Raw: then the block, then a space and a bare 42. A table or list result cannot be inlined: changing the code to return {1, 2} gives the message "Inline error: list result cannot be used".

7. Noweb: blocks inside blocks

With :noweb yes, a line containing <<name>> is replaced by the body of the block named name (before running and when tangling). This is "literate programming": write the parts where they are explained, and assemble them elsewhere.

local function shout(s) return s:upper() .. "!" end
<<helper-functions>>
return shout("noweb works")
NOWEB WORKS!

Try: in the second block press <prefix>bv.

Expect: a split with the expanded body: the local function shout line in place of <<helper-functions>>. Close it with :q.

The text before a reference is repeated on every inserted line (handy for comments or indentation):

echo one
echo two
<<two-lines>>
# prefix: <<two-lines>>
one
two

7.1. Inserting a result:

With parentheses, the reference is replaced by the result of running the block, not its body:

return "square(7) = <<square(n=7)>>"
square(7) = 49

7.2. :noweb-ref: collecting blocks

Several blocks can share a :noweb-ref instead of a name; a reference then inserts all of them, joined with a newline (:noweb-sep changes it).

echo "step 1: fetch"
echo "step 2: build"
<<steps>>
echo "done"
step 1: fetch
step 2: build
done

Try: copy one of the two :noweb-ref steps blocks, change its text to "step 3: test" and run the last block.

Expect: four lines of output: step 1, step 2, step 3, done.

7.3. When noweb applies

:noweb Expanded when… On export
no (default) never <<ref>> kept
yes running, tangling, exporting expanded
tangle tangling only <<ref>> kept
eval running only kept
no-export running and tangling <<ref>> kept
strip-export running and tangling the reference removed
strip-tangle running and exporting removed on tangle
tangle-eval running and tangling <<ref>> kept
echo "before"
<<two-lines>>

Try: run the :noweb tangle block above.

Expect: the result is : before, and the *Org-Babel Error Output* split shows a syntax error about <<two-lines>> (it is not valid shell) and "exited with code 2". Change tangle to yes and it prints before, one and two.

8. Sessions

Without a session every run starts a fresh interpreter. With :session [name] blocks of the same language and name share a live interpreter (a REPL), so variables and functions persist between blocks.

8.1. Lua sessions

A Lua session keeps its globals inside Neovim (nothing to install):

counter = (counter or 0) + 1
return "counter is " .. counter
counter is 1
return "the other block sees counter = " .. counter
the other block sees counter = 1

Try: run the first block three times, then the second one.

Expect: the first block shows counter is 1, then 2, then 3 (each Neovim starts with a fresh session). The second block then shows the other block sees counter = 3: they share counter. Without :session the second block would fail (counter would be nil).

8.2. Shell sessions

A shell session keeps the working directory, variables and functions. It runs in a terminal buffer named *name* (*shell* for the default session).

cd /tmp
greeting="set in the first block"
pwd
echo "$greeting"

Try: run the two blocks above in order.

Expect: the first one gets an empty #+RESULTS: (it prints nothing); the second one prints /tmp and set in the first block. Without the session it would print the directory of this file and an empty line.

Try: in the second block press <prefix>bz.

Expect: a split with the *work* terminal buffer. Enter Insert mode, type echo $greeting and <CR>: the REPL answers "set in the first block". Define x=5 there; a block with :session work running echo $x now prints 5.

Other session keys:

  • <prefix>bZ shows the session and also opens the edit buffer.
  • <prefix>bl sends the block to its session and shows the session.
  • <prefix>bK kills the session (the next run starts a fresh one).

8.3. :async

Every evaluation already runs in the background, so Neovim never freezes. With :async yes (or just :async) on a session block, a placeholder id is written into #+RESULTS: at once and replaced by the result when it arrives, even if you keep editing in between (Lua sessions finish at once and ignore it).

sleep 3
echo "finished after 3 seconds"

Try: run the block above and keep typing elsewhere in the file.

Expect: first a #+RESULTS: line with a long random id under it, then after three seconds that id becomes : finished after 3 seconds.

9. Header arguments at every level

Header arguments can be set in many places. From weakest to strongest:

  1. the defaults (babel.default_header_args, per language in babel.languages.LANG.default_header_args),
  2. #+PROPERTY: header-args[:LANG] ... at the top of the file,
  3. a header-args[:LANG] property of a heading (the nearest heading that sets one wins; header-args+ adds to the inherited value),
  4. the #+begin_src line,
  5. #+HEADER: lines above the block (the last one wins).

This file starts with #+PROPERTY: header-args:lua :exports both, so every Lua block of the file is exported with its code and its results.

Try: in any Lua block of this file (outside the next subtree, which sets its own) press <prefix>bI.

Expect: a message listing the merged header arguments. Under "Properties" a line reads :header-args:lua followed by :exports both, and under "Header Arguments" there is :exports both (with :cache no, :results replace, :session none and the other defaults). In a sh block the :header-args:sh line says nil and :exports is code.

9.1. A subtree with its own header arguments

Every Lua block below this heading gets base and :results verbatim. The heading's header-args:lua replaces the file's #+PROPERTY: header-args:lua :exports both (the nearest one wins), so <prefix>bI here shows :exports code. Writing the property as :header-args:lua+: would add to the inherited value instead.

return base + 1
101
return base + 1
6
return base + extra
1100

Try: change :var base=100 in the :PROPERTIES: drawer to :var base=200 and run the first block of this subtree.

Expect: : 201.

9.2. Checking and inserting header arguments

  • <prefix>bj inserts a header argument on the #+begin_src line, with completion of names and values.
  • <prefix>bc reports a header argument that looks like a misspelt one.
print("typo")

Try: press <prefix>bc in the block above.

Expect: the error Supplied header "resluts" is suspiciously close to "results". Fix the typo and press it again: "No suspicious header arguments found."

Try: in the same block press <prefix>bj, pick results, then silent.

Expect: = :results silent= is appended to the #+begin_src line.

9.3. :dir, :prologue, :epilogue, :cmdline

  • :dir PATH runs the block in that directory (:mkdirp yes creates it).
  • :prologue / :epilogue add code before / after the body.
  • :cmdline passes arguments to the interpreter.
pwd
/tmp
echo middle
start
middle
end
echo "$# arguments: $1 and $2"
2 arguments: alpha and beta

10. Editing blocks

10.1. Edit in a special buffer: <prefix>'

<prefix>' (Emacs C-c ') opens the body of the block in a separate buffer whose filetype matches the language, so you get that language's indentation, completion and LSP. Save with :w, or press <prefix>' / <C-c>' again to save and close.

local function add(a, b)
return a + b
end
return add(20, 22)
42

Try: in the block above press <prefix>', then gg=G to reindent, then <prefix>'.

Expect: you are back in this file. The body is now indented by two spaces (edit_src_content_indentation, 2 like Emacs) and the return a + b line one level more than the other lines. The same key edits example blocks, =: = fixed-width lines, LaTeX fragments and footnote definitions.

<prefix>bx does the same without opening a window: it asks for Normal mode keys, runs them in the edit buffer and writes the result back (gg=G reindents the block in one go).

10.2. Split, wrap and insert blocks: <prefix>bd

<prefix>bd (org-babel-demarcate-block):

  • inside a block: split it in two at the cursor line,
  • on a Visual selection outside blocks: wrap the lines in a new block,
  • elsewhere: insert an empty block (it asks for the language).
print("first half")
print("second half")

Try: put the cursor on print("second half") and press <prefix>bd.

Expect: two blocks, both #+begin_src lua :results output, with one print each.

Try: select the next two lines with V and j, then press <prefix>bd. At the Lang: prompt (it proposes the language of the block above), type sh and press <CR>.

echo "wrap me" echo "me too"

Expect: the two lines are now inside #+begin_src sh … #+end_src.

10.3. Show the expanded block: <prefix>bv

<prefix>bv shows what would actually run: noweb references expanded, :var assignments, :prologue and :epilogue added.

<<two-lines>>

Try: press <prefix>bv in the block above.

Expect: a split with n=3, set -e, echo one and echo two.

11. Tangling

Tangling writes blocks out to source files. :tangle FILE says where (relative to this Org file); :tangle yes uses this file's name with the language's extension (it would create examples/17-babel.lua, so it is not used here); :tangle no (the default) skips the block.

Key Tangles
<prefix>bt every block of this file (:Org tangle)
1<prefix>bt only the block at the cursor (Emacs C-u C-c C-v t)
2<prefix>bt the blocks with the same :tangle file as the cursor
<prefix>bf another Org file (asks for its name)

The blocks below write into examples/17-babel-out/. :mkdirp yes creates the directory. Delete it afterwards with rm -r examples/17-babel-out.

11.1. A small shell script

echo "Hello from a tangled script"
echo "Second block, same file"

Try: press <prefix>bt, then in a shell run sh examples/17-babel-out/hello.sh (or :!sh %:h/17-babel-out/hello.sh).

Expect: the message says the files were tangled; the script prints both lines. :e examples/17-babel-out/hello.sh shows #!/bin/sh on line 1, then the two echo lines separated by a blank line (:padline no removes it).

11.2. A Lua module with link comments and noweb

:comments link wraps each block in comments that link back here, so :Org tangle_jump in the tangled file jumps to the Org block and :Org detangle copies edits back. :comments org also writes the Org text before the block as comments.

local function double(x) return 2 * x end
local M = {}
<<mod-helpers>>
function M.quadruple(x) return double(double(x)) end
return M

Try: with the cursor in the block above press 1<prefix>bt (tangle only this block). Open examples/17-babel-out/mymod.lua.

Expect: the file starts with -- [[file:../17-babel.org::*A Lua module with link comments and noweb][A Lua module with link comments and noweb:2]] (:2 because it is the second block of that heading), has local function double where <<mod-helpers>> was, and ends with a -- A Lua module with link comments and noweb:2 ends here line. In that file, put the cursor inside the code and run :Org tangle_jump: you land back on this block.

Try: now load the module from a Lua block:

local path = vim.fn.expand("%:p:h") .. "/17-babel-out/mymod.lua"
if vim.fn.filereadable(path) == 0 then return "tangle it first" end
return dofile(path).quadruple(10)

Expect: : 40 once tangled, : tangle it first before.

12. Library of Babel

Named blocks of other files can be added to the Library of Babel with <prefix>bi (C-c C-v i). Then #+CALL:, :var and noweb find them from any file, for the rest of the session.

This block tangles a small library file (an Org file with two named Lua blocks). The commas in front of #+ lines inside an org block are escapes; tangling removes them.

#+NAME: lib-add
#+begin_src lua :var a=1 b=2
return a + b
#+end_src

#+NAME: lib-shout
#+begin_src lua :var s="hi"
return s:upper() .. "!"
#+end_src

Try:

  1. In the org block press 1<prefix>bt (writes examples/17-babel-out/library.org).
  2. Press <prefix>bi and answer examples/17-babel-out/library.org (the path is relative to the directory Neovim was started in).
  3. Put the cursor on each #+CALL: line and press <C-c><C-c>.

Expect: step 2 says "2 src blocks added to Library of Babel"; step 3 writes : 42 and : LIBRARY! under the calls. <prefix>bi with an empty answer ingests the current buffer.

13. Exporting code and results

:exports says what the export shows: code (the default), results, both or none. When exporting, blocks with :exports results or both are evaluated first (babel.evaluate_on_export, asked like any evaluation). This file sets :exports both for Lua (see "Header arguments at every level").

echo "only this line appears in the export"
only this line appears in the export

Try: turn off the prompts first (export evaluates every Lua block of this file, which has :exports both): :lua require("org.config").opts.babel.confirm_evaluate = false. Then export to plain text with <prefix>e then t then A (ASCII to a buffer) and search for "only this line" with /only this line.

Expect: the output shows the line in a box, but not the echo command. With babel.evaluate_on_export = false nothing is evaluated and :exports is ignored (as in Emacs with org-export-use-babel nil): the code and the existing #+RESULTS: are both exported. See 19-export.org for the exporters.

14. Further reading

  • :h org-babel (running, results, sessions, languages, header arguments)
  • :h org-babel-edit-special (<prefix>')
  • :h org-keymaps (the Babel keys), :h org-emacs-keys (C-c C-v keys)
  • :h org-table-calc (Lisp forms in header arguments, org-sbe)
  • 15-tables.org, 16-spreadsheet.org (tables that blocks read)
  • 18-dynamic-blocks.org (other generated content)