16.8 Extracting Source Code

从代码块中提取源代码是文学编程的基础任务,Org 提供了便捷的实现方式。在文学编程术语中,文档在创作时将代码与文档 编织(woven) 在一起,导出时则将代码 缠绕(tangled) 分离以供计算机执行。Org 支持编织与缠绕操作,便于创建、维护、共享与导出文学编程文档,并提供丰富的自定义选项用于提取源代码。

Org 在缠绕代码块时会对其展开、合并与转换,再根据选项配置重新组合为一个或多个独立文件。在此缠绕过程中,Org 会展开源代码中的变量,并解析所有 noweb 风格引用(参见 Noweb Reference Syntax)。

Header arguments

tangle’ 头参数用于指定是否将代码块导出到源码文件。

yes

将代码块导出到源码文件。源码文件名由当前 Org 文件名派生,文件扩展名由代码语言标识符决定。 示例: ‘:tangle yes’ 。

no

默认值。不将代码提取到源码文件中。 示例: ‘:tangle no’ 。

FILENAME

将代码块导出到文件名由 ‘tangle’ 头参数值指定的源码文件。文件名路径相对于当前 Org 文件所在目录解析,若指定了 ‘tangle-directory’ ,则相对于该目录。

FILENAME 支持以下几种形式:

单个文件名(字符串)

示例: ‘:tangle script.py’ 。

文件名列表

将代码块导出到多个文件。示例: ‘:tangle '("src/main.py" "src/utils.py")’ 。

变量或函数调用

求值后得到目标文件名。示例: ‘:tangle 'tangle-targets’ 或 ‘:tangle (get-tangle-targets)’ 。

当同时指定 ‘:tangle-directory’ 和多个 ‘:tangle’ 文件时,代码块会导出到所有目录与文件的组合路径。

Example:

#+begin_src emacs-lisp :tangle '("config.el" "backup.el") :tangle-directory '("~/.config" "/backup")
(message "Tangling to multiple targets specified by :tangle and :tangle-directory")
#+end_src

该代码块会导出到四个文件:

  • ~/.config/config.el
  • ~/.config/backup.el
  • /backup/config.el
  • /backup/backup.el

tangle-directory’ 头参数用于指定一个或多个基础目录,作为 tangle 相对路径的根目录。用法与 ‘tangle’ 类似,支持相同类型的值。

此外,位于注释子树内的代码块(见 Comment Lines)永远不会被导出。

mkdirp’ 头参数用于在导出文件时自动创建不存在的父目录。 ‘yes’ 表示启用创建, ‘no’ 表示禁用。

comments’ 头参数用于控制在导出文件中插入额外注释,这些注释独立于代码块本身已有的注释。

no

默认值。导出时不插入任何额外注释。

link

用注释包裹代码块,并添加指向 Org 文件中对应代码位置的链接。

注意 Org 会使用 org-store-linkHandling Links)生成指向代码块的链接。如果父标题重复或在导出后被修改,该链接可能不唯一。建议将 org-id-link-to-org-use-id 设为 t,确保链接指向正确标题。

yes

为兼容旧版本保留,效果与 ‘link’ 相同。

org

将 Org 文件中最近的标题文本作为注释插入,具体文本取自代码块所在的上层上下文。

both

同时启用 ‘link’ 和 ‘org’ 两种注释。

noweb

启用 ‘link’ 功能,展开 noweb 引用(见 Noweb Reference Syntax),并在代码块内部用链接注释包裹展开内容。

padline’ 头参数用于控制是否在导出文件中为代码块前后添加空行。

yes

默认值。在导出文件中每个代码块前后各插入一个空行。

no

不为导出的代码块添加空行。

shebang’ 头参数可将导出结果转为可执行脚本文件。将其设为字符串,例如 ‘:shebang "#!/bin/bash"’ ,Org 会将该字符串作为导出文件的第一行,并自动为文件添加可执行权限。

tangle-mode’ 头参数通过 set-file-modes 指定导出文件的权限。权限使用八进制值表示,可通过对 Elisp 八进制值调用 identity 函数传入。例如,创建只读文件可写为 ‘:tangle-mode (identity #o444)’ 。为简化写法,支持八进制简写 ‘oXXX’ (o 代表 octal),因此只读示例可简写为 ‘:tangle-mode o444’ 。省略 ‘o’ 前缀会将数值当作整数解析,可能导致意外结果( ‘444’ 等价于 ‘o674’ )。 另外还支持两种简写格式:类似 ls 的权限字符串 ‘rw-r--r--’ ,以及类似 chmod 的权限写法 ‘g+w’ 。 注意 chmod 风格权限基于 org-babel-tangle-default-file-mode ,其默认值为 ‘#o644’ 。

当同时指定 ‘:tangle-mode’ 和 ‘:shebang’ 时, ‘:tangle-mode’ 指定的权限会覆盖 ‘:shebang’ 带来的权限。若多个代码块导出到同一文件且 ‘:tangle-mode’ 冲突,Org 的行为未定义。

默认情况下 Org 在导出时会展开代码块。 ‘no-expand’ 头参数可关闭该展开行为。注意 org-babel-expand-src-block 的展开副作用之一是会为变量赋值(见 Environment of a Code Block),展开也会替换 noweb 引用为目标内容(见 Noweb Reference Syntax)。部分展开可能导致提前赋值,因此提供该选项。该选项仅对导出生效,对导出无影响,因为执行用的代码块必须展开。

Functions

org-babel-tangle

导出当前文件。快捷键绑定为 C-c C-v t

带前缀参数时仅导出当前代码块。

org-babel-tangle-file

选择一个文件进行导出。快捷键绑定为 C-c C-v f

Tangle hooks

org-babel-pre-tangle-hook

该钩子在导出流程开始前运行,当前缓冲区即为待导出的缓冲区。

org-babel-tangle-body-hook

该钩子在临时缓冲区中运行,缓冲区内容为每个已展开的代码块。钩子可按需修改展开后的代码,修改后的内容将作为最终代码使用。

org-babel-post-tangle-hook

该钩子在由 org-babel-tangle 导出的代码文件内部运行,适用于对导出文件进行后处理、编译或执行。

org-babel-tangle-finished-hook

该钩子在 post-tangle 钩子之后运行,环境为原始 Org 缓冲区。

Jumping between code and Org

调试器通常会将错误信息关联到源码文件。但对导出文件,我们希望关联到 Org 文件而非导出后的源码文件。为实现这一跳转,Org 使用 org-babel-tangle-jump-to-org 函数,并依赖两个额外代码块头参数:

  1. 将 ‘padline’ 设为 true —这是默认设置。
  2. 将 ‘comments’ 设为 ‘link’ ,使 Org 插入指向 Org 文件的链接。