Org-mode 语法汇总

用作 ox-w3ctr 的测试文件

More details about this document
Create Date:
Publish Date:
Update Date:
2024-12-14 13:10
Creator:
Emacs 31.0.50 (Org mode 9.7.11)
License:
This work is licensed under CC BY-SA 4.0

本文档是对 ox-w3ctr 这一 Org-mode 导出后端的测试,内容基本覆盖了所有 Org-mode 语法,并对每种语法给出了一些文档中有说明的使用方式。严格来说,想要测试 ox-w3ctr 是否可用,我应该编写一些测试样例,但是 Org-mode 的导出框架已经足够鲁棒,使用中碰到问题也很容易进行修正,一些不常用功能中的 bug 如果不使用根本不会发现。使用一个能够覆盖绝大多数语法的文件来测试应该足够了。

如果您在学习 Org-mode 的用法,本文可能并不适合作为学习材料,不过如果在学习如何如何为 Org-mode 编写导出代码,本文可以作为一个测试用例。读者可以参考以下资料了解 Org-mode 的语法以及导出框架:

本文所使用的 CSS 文件来自 W3C TR 2021,即 TR/2021base.css。最新的 base.css 可从该 CSS 的 github repo 获取。以下 W3C TR 可以作为简单用例:

这一节属于 zeroth section,在 ox-w3ctr 中时我采用了不同于 ox-html 的生成方法。

生成本 HTML 文档使用的是 Emacs 31.0.50 和 Org 9.7.11。

1. Org-mode 语法总览

在 Org-mode 语法文档的开头,它将 Org-mode 文本格式称为一种简单,但用途广泛的纯文本格式,既易于使用又能够表示复杂的文档。与 Markdown 破碎的生态相比,Org-mode 的语法非常统一。这大概是由于它内置的功能强于 Markdown 从而足以用于大多数目的,而不用像 Markdown 一样使用 HTML 标签或发明新东西。

首先,Org-mode 语法的组成可以分为对象(object)和元素(element)两类,如果以段落(paragraph)为基准,那么 元素 就是层次大于等于 段落 的组件,也就是不能被段落容纳; 对象 则是比 段落 层次小的东西,可以被段落容纳。这里的段落会在 ox-html 后端中被导出为 <p> 标签。

更进一步,元素可以从大到小分为 heading, section, greater elementlesser element 。元素确定了特定的语法环境,在所有元素中只有 heading, section, property drawerplanning line 是上下文无关的,其他的语法成分只能存在于特定的环境中。

1.svg
https://elilif.github.io/articles/2024-03-12-org-syntax-and-word-count.html

在所有这些元素中, lesser element 不能容纳其他的元素。比如,段落可被认为是一个小元素,它的里面就不能包含另一个段落。 greater element 可以包含它们自己,以及其他的 greater elementlesser elementsection 可以包含 greater elementlesser elementheading 可以包含 section 和其他的 heading

1.1. Org-mode 语法中的元素

变量 org-element-all-elements 提供了完整的元素列表:

( babel-call center-block clock comment comment-block diary-sexp drawer
  dynamic-block example-block export-block fixed-width footnote-definition
  headline horizontal-rule inlinetask item keyword latex-environment node-property
  paragraph plain-list planning property-drawer quote-block section
  special-block src-block table table-row verse-block)
(length org-element-all-elements) => 30

按照语法文档的分类,上面这些元素可以分为:

  • 最大的 headlinesection ,共 2 个
  • greater element ,包括 center-block, quote-block, special-block, drawer, property-drawer, dynamic-block, footnote-definition, inlinetask, item, plain-list, table ,共 11 个
  • lesser element ,包括 comment-block, example-block, export-block, src-block, verse-block, clock, diary-sexp, planning, comment, fixed-width, horizontal-rule, keyword, babel-call, latex-environment, node-property, paragraph, table-row ,共 17 个

1.2. Org-mode 语法中的对象

变量 org-element-all-objects 提供了完整的对象列表:

( bold citation citation-reference code entity export-snippet footnote-reference
  inline-babel-call inline-src-block italic line-break latex-fragment link macro
  radio-target statistics-cookie strike-through subscript superscript table-cell
  target timestamp underline verbatim)
(length org-element-all-objects) => 24

在 Org-mode 语法中,对象的分类不如元素那样细致,不过文档中给出了所谓的最小对象集合和标准对象集合,分别是:

  • minimal set of objects: plain-text, text-markup, entity, latex-fragment, subscript, superscript. 其中 text-markup 包括 bold, italic, underline, verbatim, codestrike-through. 共 11 个
  • standard set of objects: 除了 citationtable-cell 外的所有对象,共 22 个

2. headline 和 section

Org-mode 本身最高支持无限级别的 headline ,在导出时最高的 headline 导出级别取决于 org-export-headline-levels ,它的默认值为 3 。在 ox-w3ctr 中我使用 org-w3ctr-headline-levels 覆盖了该选项,且将默认值设置为 5 ,这是因为在 ox-html#+TITLE 会被导出为 <H1> 标题,一级 headline 到五级 headline 分别被导出为 <H2><H6> ,这就是 HTML 支持的所有标题级别了。实际使用中我们很少会用到 3 级以上的 headline

以下是不同级别的 headline 例子:

2.1. 我是二级标题

2.1.1. 我是三级标题

2.1.1.1. 我是四级标题
2.1.1.1.1. 我是五级标题
  1. 我是六级标题,因为没有 <H7> 所以是列表
    1. 我是七级
      1. 8
        1. 9
          1. 10
            1. 11
              1. 12
                1. 13

2.2. headline

在 Org-mode 中, headline 是一个无缩进的如下结构,Org-mode 语法文档中对 headline 的描述如下:

STARS KEYWORD PRIORITY COMMENT TITLE TAGS

headline 由级数 STARS ,GTD 关键字 KEYWORDS ,优先级 PRIORITY ,注释标志 COMMENT ,标题内容 TITLE 和标签 TAGS 组成,除 STARS 外其他都是可选项。其中:

  • STARS 包含一个或多个星号 * ,并带有空格字符 SPC 后缀。星号的数量决定了 headline 的级别。

    因为 headline 要求以 * 开头且与行首之间不能有空格,我们也就不能直接在段落的开头使用 * 。要解决在一行的开头使用 * 这个问题,直接的方法是添加空格或零宽空格,不过正确做法是使用 , 转义,即 ,*

    如果用户加载了 org-inlinetask* 的数量大于等于 org-inlinetask-min-level (默认值为 15),那么它会成为一个 inlinetask 而不是 headline

  • KEYWORDorg-todo-keywords-1 中的一个字符串,它被叫做“todo keyword”

    标准的 org-todo-keywords-1("TODO" "DONE") ,即默认可用的 KEYWORD"TODO""DONE" 。读者可以参考 Org-mode 文档的 TODO Extensions 一节来扩展关键字。

  • PRIORITY 为以 # 为前缀的带中括号单字符(比如 [#A][#1] ),它被叫做“priority cookie”

    PRIORITY 可以用来记录 headline 的优先级,默认情况下 Org-mode 支持 [#A], [#B][#C] ,不写 PRIORITY 则默认为 [#B] 优先级。优先级的使用可以参考 Priorities

  • COMMENT 是字符串 "COMMENT" ,表示 headline 被注释了,导出时该 headline 会被忽略
  • TITLE 为来自标准对象集合的对象,且不为断行对象
  • TAGS 为一系列由 : 分隔的 token,token 可包含 [a-z-A-Z0-9_@#%]

    TAGS 没什么好说的,需要注意的是 tag 名不能包含 - 字符。 TAGS 的用法可以参考 Tags

以下是一些和 headline 操作相关的命令:

  • TAB(org-cycle) ,切换 headline 的显示 Global and local cycling
  • headline 间的移动命令 Motion
    • C-c C-n(org-next-visible-heading)
    • C-c C-p(org-previous-visible-heading)
    • C-c C-f(org-forward-heading-same-level)
    • C-c C-b(org-backward-heading-same-level)
    • C-c C-u(outline-up-heading)
    • C-c C-j(org-goto)
  • 作用于 headline 的编辑命令 Structure Editing
    • M-LEFT(org-do-promote), M-RIGHT(org-do-demote)
    • M-S-LEFT(org-promote-subtree), M-S-RIGHT(org-demote-subtree)
    • M-UP(org-move-subtree-up), M-DOWN(org-move-subtree-down)
  • 设置 headlineTAGS C-c C-c(org-set-tags-command) Setting Tags
  • 切换 headlineCOMMENT 状态 C-;(org-toggle-comment)
  • 切换 headlineARCHIVE 标签状态 C-c C-x a(org-toggle-archive-tag)

2.3. section

section 包含一个或多个非 heading 元素。粗略来说, section 就是位于 headline 之间的内容。文档中给出的例子如下:

An introduction.
* A Heading
Some text.
** Sub-Topic 1
** Sub-Topic 2
*** Additional entry

上面内容对应的 AST 为:

(document
 (section)
 (heading
  (section)
  (heading)
  (heading
   (heading))))

在第一个 headline 之前的内容构成的 section 被叫做 zeroth section ,它与普通 section 的区别在于可以直接包含 property drawer 元素,但不能含有 planning 元素,也就是说它允许如下结构:

BEGINNING-OF-FILE
BLANK-LINES
COMMENT
PROPERTYDRAWER

其中 BLANK-LINESCOMMENT 不是必须的。

3. 对其余各元素的介绍

在这一节中我们会介绍所有二十八个元素,加上上面的 headlinesection 一共三十个。

3.1. greater blocks

greater blocks 之所以 greater 自然是要与 lesser blocks 相对,它们允许包含其他的 greater element 。所有的(就 3 种) greater block 都具有如下结构(其中的 BEGIN 也可为小写):

#+BEGIN_NAME PARAMETERS
CONTENTS
#+END_NAME

其中, NAME 是不含空格的字符串,可以为任意不属于 lesser block 的名字; PARAMETERS 是可选的参数,是不含换行的字符串; CONTENTS 为不含 #+END_NAME 行的任意内容。最后一条规则也就注定了它们不能自我嵌套(不过可以相互嵌套)。这些块结构用的最多的时候也许是导出时根据不同后端生成具有相同语义的产物。

在编写 Org-mode 导出后端时,也许我们可以考虑利用这些 block (特别是 special block )以及它们的 PARAMETERS 参数来实现更加丰富的语义。

3.1.1. center block

center-block 就是让其中内容居中的 block,不过在 Org-mode buffer 中并不会居中显示。以下是一个 center block 例子(来自 Paragraphs):

#+BEGIN_CENTER
Everything should be made as simple as possible, \\
but not any simpler
#+END_CENTER

其中 \\ 表示段落内换行,它的效果如下:

Everything should be made as simple as possible,
but not any simpler

3.1.2. quote block

类似地, quote block 具有语义上的引用义:

#+BEGIN_QUOTE
你说的对,但是《原神》是由米哈游自主研发的一款全新开放世界冒险游戏。游戏发生在一个被称作「提瓦特」的幻想世界,在这里,被神选中的人将被授予「神之眼」,导引元素之力。你将扮演一位名为「旅行者」的神秘角色,在自由的旅行中邂逅性格各异、能力独特的同伴们,和他们一起击败强敌,找回失散的亲人——同时,逐步发掘「原神」的真相。

你说得对,但是这就是奎桑提,HP 4700,护甲 329,魔抗 201 的英雄。有不可阻挡,有护盾,还能过墙。有控制,甚至冷却时间只有 1 秒,只要 15 点蓝。转换姿态时甚至可以刷新 W 的 cd,还有真实伤害。然后,护甲和魔抗提升后还能获得技能加速,缩短 Q 的 cd,还缩短释放时间,然后还有攻击力。W 就啊啊啊啊啊啊!!!
#+END_QUOTE

你说的对,但是《原神》是由米哈游自主研发的一款全新开放世界冒险游戏。游戏发生在一个被称作「提瓦特」的幻想世界,在这里,被神选中的人将被授予「神之眼」,导引元素之力。你将扮演一位名为「旅行者」的神秘角色,在自由的旅行中邂逅性格各异、能力独特的同伴们,和他们一起击败强敌,找回失散的亲人——同时,逐步发掘「原神」的真相。

你说得对,但是这就是奎桑提,HP 4700,护甲 329,魔抗 201 的英雄。有不可阻挡,有护盾,还能过墙。有控制,甚至冷却时间只有 1 秒,只要 15 点蓝。转换姿态时甚至可以刷新 W 的 cd,还有真实伤害。然后,护甲和魔抗提升后还能获得技能加速,缩短 Q 的 cd,还缩短释放时间,然后还有攻击力。W 就啊啊啊啊啊啊!!!

3.1.3. special block

special block 相对特殊一些,它的 NAME 可以为任意非 lesser block 以及 quotecenter 的名字,比如 #+begin_aside 。它的意义取决于导出后端想要赋予它什么意义:

#+begin_hello
hello world
#+end_hello

3.2. drawers

drawer 具有如下结构:

:NAME:
CONTENTS
:end:

在 Org-mode Manual 的 Drawers 一节是这样描述它的:

Sometimes you want to keep information associated with an entry, but you normally do not want to see it. For this, Org mode has drawers. They can contain anything but a headline and another drawer.

简单来说, drawer 提供了一种非 headline 的折叠展开内容方法。我们可以通过 C-c C-x d(org-inser-drawer) 插入 drawer 。当某个 region 被选中时,调用该命令会将当前 region 中的内容插入到 drawer 中;当带有前缀参时,该命令会调用 org-insert-property-drawer 来在当前 headline 插入 PROPERTIES drawer

如果使用 #+caption: 作为 <details> 中的 <summary> 的话, drawer 将会非常适合作为 details 的对应物,就像这样:

#+caption: This is a details
:everything-here-is-ok:
Contents are hidden
:end:
#+end_example
This is a details

Contents are hidden

#include <stdio.h>
int main(void)
{
	  print("hello world\n");
	  return 0;
}

3.2.1. property drawer

property drawer 必须紧接着 headlineinlinetask ,作用是为它们提供属性信息:

HEADLINE
PROPERTYDRAWER

HEADLINE
PLANNING
PROPERTYDRAWER

相比一般 drawerproperty drawer 的要求更严格一些,它的 NAME 必须为 PROPERTIES ,而且 CONTENTS 中不能含空行,只能是 node property 。以下是一个例子:

* Heading
:PROPERTIES:
:CUSTOM_ID: someid
:END:

本节的标题 property drawer 就具有一个 CUSTOM_ID 属性,读者可以查看本 HTML 页面的源代码找到它的 ID。

3.3. dynamic block

dynamic block 结构如下:

#+begin: NAME PARAMETERS
CONTENTS
#+end:

其中 NAME 是不含空格的字符串; PARAMETERS 是可选的参数字符串,不含换行符; CONTENTS 是除 dynamic block 外的零个或多个其他元素。

dynamic block 的文档 Dyanmci Block 中对参数结构有更精细的描述,它应为 :parameter1 value1 :parameter2 value2 ... ,不过也不是非得这样,使用 (org-element-property :arguments dynamic-block) 获取到的参数就是一整个字符串。

根据文档的说法, dynamic block 可以根据用户函数对块中的内容进行自动更新。我们可以通过 C-c C-x x(org-dynamic-block-insert-dblock) 来在当前位置插入 dynamic block ,并通过 C-c C-x u(org-dblock-update) 来更新块的内容。我们可以添加 org-update-all-dblocks 到某些 hook 中来在必要时触发所有 dynamic block 的更新。读者可以阅读文档以及 org-dblock-write:clocktable 来学习如何编写生成和更新 dynamic block 的函数。

3.4. footnote definition

footnote definition 是脚注的定义部分,它和 headline 一样必须顶格,它的结构如下:

[fn:LABEL] CONTENTS

其中 LABEL 是数字或由 [[:word:]-_] 组成的字符串,用来标识对应的脚注, CONTENTS 为脚注的内容,它在下一个 footnote definition 之前结束,或者是下一个 headline 、两个连续的换行、或 buffer 的末尾。这是一些例子,注意在第二个脚注中,隔了一行的字符串仍属于该脚注:

[fn:1] A short footnote.

[fn:2] This is a longer footnote.

It even contains a single blank line.

Org-mode 支持三种形式的脚注,具体的用法可以参考 Creating Footnotes

下面是一段来自维基百科的内容,我改成了 Org-mode 格式:

Wikipe-tan (Japanese[fn:Japanese]: ウィキペたん) is a personification of Wikipedia[fn:Wikipedia] created in January 2006 by Japanese editor Kasuga[fn:Kasuga] She is an unofficial mascot of Wikipedia and is used at several WikiProjects. The -tan in "Wikipe-tan" is an affectionate suffix, in the form of a Japanese honorific. Like the OS-tans, she is a product of moe anthropomorphism.

[fn:Japanese] Janapanese 的 wiki 链接:https://en.wikipedia.org/wiki/Japanese_language
[fn:Wikipedia] Wikipedia 的链接:https://en.wikipedia.org/wiki/Wikipedia
[fn:Kasuga] In the aftermath of the unified login finalization, the user now going by Kasuga on Commons and on English Wikipedia is a different person. The accounts of the creator of Wikipe-tan were renamed Kasuga~enwiki, Kasuga~jawiki and Kasuga~commonswiki.

Wikipe-tan (Japanese[Japanese]: ウィキペたん) is a personification of Wikipedia[Wikipedia] created in January 2006 by Japanese editor Kasuga[Kasuga] She is an unofficial mascot of Wikipedia and is used at several WikiProjects. The -tan in "Wikipe-tan" is an affectionate suffix, in the form of a Japanese honorific. Like the OS-tans, she is a product of moe anthropomorphism.

请点击脚注链接跳转到定义部分。

除了上述标准脚注外,Org-mode 还支持匿名脚注和内联脚注,它们的导出效果如下:

来个匿名脚注[fn:: 芝士匿名脚注,以标号作为脚注名],来个内联脚注[fn:芝士内联脚注: 以 :xxx: 作为脚注名,后面接脚注定义部分]

来个匿名脚注[4],来个内联脚注[芝士内联脚注]

3.5. inlinetask

headline 的星号数量大于等于 org-inlinetask-min-level 时,它就成了 inlinetask ,不过仅在 org-inlinetask 加载后才会有 inlinetask 。这个功能我从来没用使用过。下面是一个例子:

*************** TODO some tiny task
This is a paragraph, it lies outside the inlinetask above.
*************** TODO some small task
                 DEADLINE: <2009-03-30 Mon>
                 :PROPERTIES:
                   :SOMETHING: or other
                 :END:
                 And here is some extra text
*************** END

我在 Org-mode Manual 中居然没有找到 inlinetask 的章节。

3.6. item

item 是单个列表项,它在内部可以嵌套 item ,结构如下:

BULLET COUNTER-SET CHECK-BOX TAG CONTENTS

其中:

  • BULLET 是表头符号,对无序列表可以是 *, -+

    注意顶格的 * 不能作为 item 开头,因为它会被识别为 headline ;对有序列表需要是一个数字或单个 a-z 的字符加上 .) ,比如 1.a)

  • COUNTER-SET 指定有序列表的序号值,格式为 [@COUNTER]
  • CHECK-BOX 选择框,可以为 [ ], [X][-]
  • TAG 格式为 TAG-TEXT :: ,其中 TAG-TEXT 会作为标准集合对象解析
  • CONTENTS 为零个或多个元素,并在遇到以下情况时结束
    • 下一个 item
    • 相比起始行具有更浅或相同缩进的行,这不计算其他非段落元素或 inlinetask 边界内的行
    • 两个连续的换行

下面是文档中给出的例子:

- item
3. [@3] set to three
+ [-] tag :: item contents
 * item, note whitespace in front
* not an item, but heading - heading takes precedence

Org-mode Manual 的 Plain Lists 一节对列表进行了更为细致的描述。上面提到的 TAG 用于生成所谓的 description list ,在 HTML 导出后端中,它会使用不同于 olul 的标签。

这是一个无序列表例子:

- 第一项
- 第二项
- 第三项
  • 第一项
  • 第二项
  • 第三项

这是一个有序列表的例子:

1. いいよ,こいよ
1. [@1] 伊已逝,吾亦逝
4. [@4] 意易失,吾亦逝
5. [@5] 逸一时,误一世
1. [@1] 疑一时,误一世
4. [@4] こめいじ こいし
  1. いいよ,こいよ
  2. 伊已逝,吾亦逝
  3. 意易失,吾亦逝
  4. 逸一时,误一世
  5. 疑一时,误一世
  6. こめいじ こいし

这是一个描述性列表的例子:

- 你好 :: 今日は
- 再见 :: また明日
你好
今日は
再见
また明日

3.7. plain list

plain list 就是一系列具有相同缩进的连续 item 。文档中给出了一个 plain list 对应的 AST:

1. item 1
2. [X] item 2
   - some tag :: item 2.1
(ordered-plain-list
 (item
   (paragraph))
 (item
  (paragraph)
  (descriptive-plain-list
   (item
     (paragraph)))))

Org-mode Manual 在 Plain Lists 一节给出了一些方便的命令,这里简单列出部分:

  • S-UP S-DOWN ,移动到当前列表的下一个/上一个 item
  • M-UP M-DOWN ,将当前 item 上移/下移一位
  • M-LEFT M-RIGHT ,减少/增加当前 item 的缩进,不处理子 item
  • C-c C-c ,切换 Checkbox 的状态

3.8. table

Org-mode 支持两种表格,一种来自 Org-mode 自己,另一种来自 Emacs 的 table.el,这两种表格的性状略有不同。Org-mode 表格以 | 开头而 tabel.el 以 +- 开头。以下代码展示了两者的不同之处:

|   |   |   |    +---+---+---+
|   |   |   |	 |   |   |   |
		 +---+---+---+
		 |   |   |   |
		 +---+---+---+

表格由一行行的 lesser element table row 组成,我们会在后文介绍它。以下是一个表格例子:

| Name  | Phone | Age |
|-------+-------+-----|
| Peter |  1234 |  24 |
| Anna  |  4321 |  25 |
Name Phone Age
Peter 1234 24
Anna 4321 25

Org-mode 的表格功能非常强大,支持一定程度的运算功能,可以看作是“穷人的 Excel”。 table 的具体用法可以参考 Org-mode Manual 的 Tables 一章。

3.9. blocks

(从 block 开始就是 lesser block 了,因此我加粗了标题)

lesser block 具有与 greater block 相似的结构:

#+BEGIN_NAME DATA
CONTENTS
#+END_NAME

其中, NAME 只能为以下各小节标题其中之一, DATA 同样是一个不含断行的字符串, CONTENTS 不含 #+END_NAME 。关于各 lesser block 的文档如下列表所示:

3.9.1. comment block

comment block 即注释块。在导出时它们不会被导出。

#+BEGIN_COMMENT
I'll not be exported
#+END_COMMENT

3.9.2. example block

example block 通常用于显示代码或文字的样例,它会保留原始样式,包括空格和换行,以便准确显示内容。

#+BEGIN_EXAMPLE
  Some example from a text file.
#+END_EXAMPLE

3.9.3. export block

我们可以通过 export block 指定一段内容针对特定导出后端的内容,这允许在同一文档中为不同的导出格式定制内容。对 HTML 后端来说,我们可以有如下做法:

#+BEGIN_EXPORT html
<div><p>123<br>456</p></div>
#+END_EXPORT

以下代码可以导出颜色为红色的 hello world

#+begin_export html
<span style="color:red;">hello world</span>
#+end_export
hello world

3.9.4. src block

src block 算是 Org-mode 的重量级特性,在 Org-mode Manual 中专门有一章介绍它的用法。在 src block 中, DATA 的格式如下:

LANGUAGE SWITCHES ARGUMENTS

其中 LANGUAGE 是源代码块的语言,为一无空格字符串; SWITCHES 是由空格分隔的任意数量 SWITCH 模式;最后的 ARGUMENTS 为无折行字符串。其中 SWITCH 的写法可以参考上面给出的 Literal Examples 文档,而 ARGUMENTS 参数可以参考 Using Header Arguments

和导出相关的 ARGUMENTS:exports ,可以指定 code, results, bothnone 四种选项。其中 code 为默认选项,即导出代码, results 为导出代码的执行结果, both 为导出两者, none 则不导出代码块。

以下是一个 src block 例子:

#+begin_src emacs-lisp
"This string
* has "*" escaped.
Otherwise, '* has "*" escaped.' would be treated as a heading (which
is context-free)."

"#+ lines may or may not need to be escaped:
#+end_src if not escaped, would be this source block.
However,
#+keyword: does not interfere with code block end and may be left as is.
#+keyword may be escaped as well, optionally - parser removes all the
commas in ,* and ,#+ lines."
#+end_src

我们可以使用 org-export-use-babel 来控制代码导出时是否使用 babel 处理代码,我发现设置它为 nil 能缩短不少的时间,因此我用 org-w3ctr-use-babel 覆盖了这个选项,并设置其默认值为 nil

3.9.5. verse block

verse block 的功能非常简单,就是保持文本的结构,但它没有 example block 那么强,除了换行和缩进外它不会改变其他对象的格式。在以下例子中,若代码块环境为 example ,那么 = 内容在 HTML 导出中会直接显示等于号,而不是生成 <code> 标签:

#+BEGIN_VERSE
 Great clouds overhead
 Tiny black birds rise and fall
 Snow covers Emacs

    ---AlexSchroeder, =hello=
#+END_VERSE

Great clouds overhead
Tiny black birds rise and fall
Snow covers Emacs

   —AlexSchroeder, hello

3.10. clock

clock 元素的形状如下:

clock: INACTIVE-TIMESTAMP
clock: INACTIVE-TIMESTAMP-RANGE DURATION
clock: DURATION

其中的 INACTIVE-TIMESTAMPINACTIVE-TIMESTAMP-RANGE 都是 timestamp 对象(下文会介绍)。 DURATION 的格式为 HH:MM 。一个简单的例子如下:

clock: [2024-10-12]

3.11. diary sexp

diary sexp 是一个无缩进的如下结构:

%%SEXP

例子如下:

%%(org-calendar-holiday)

diary-sexp 的具体用法可以参考 Sexp Entries and the Fancy Diary Display

3.12. planning

planning 元素具有如下结构:

HEADING
PLANNING

其中 PALNNING 一行包含一个或多个 KEYWORD: TIMESTAMP 模式, KEYWORD 可为 DEADLINE, SCHEDULEDCLOSEDTIMESTAMP 为一个 timestamp 对象。 planning 必须紧随 heading ,两者之间不能有空行。

文档给出的例子如下:

*** TODO watch "The Matrix"
    SCHEDULED: <1999-03-31 Wed>
#+END_SRC

3.13. comment

除了上面提到的 comment block ,Org-mode 也支持单行注释,只需要一个顶格 # 加上空格即可:

# This is a line comment.

自然,注释是不会导出的。

3.14. fixed width

: 加空格开头的行将成为单行 example block ,不过在 ox-html 中我们无法通过 attr_html 为其添加其他 HTML 属性。

: This is a fixed width.
This is a fixed width.

3.15. horizontal rule

如果一行以 - 开头且至少有 5 个连续的 - 符号,那么它会成为一个 horizontal rule ,在 ox-html 中它导出为 <hr> 标签,在 ox-w3ctr 中同样也是。

-----

3.16. keywords

keywords 的形式如下:

#+KEY: VALUE

其中:

KEY
一个除 call 外含无空格字符的字符串
VALUE
不含换行符的任意字符串

KEYorg-element-parsed-keywords 中的任一成员时, VALUE 可以包含除 footnote reference 的任意标准对象(第一节提到的标准对象集合)。 org-element-parsed-keywords 的值如下所示:

org-element-parsed-keywords => ("CAPTION")

ox-html 中, org-html-keyword 实现为可以导出 HTMLTOC 关键字,前者用于导出 HTML 代码片段,后者用于导出局部目录。

3.16.1. babel call

如果 KEYcall 那么 keywords 就是 babel call ,它具有以下几种可能的形式:

#+call: NAME(ARGUMENTS)
#+call: NAME[HEADER1](ARGUMENTS)
#+call: NAME(ARGUMENTS)[HEADER2]
#+call: NAME[HEADER1](ARGUMENTS)[HEADER2]

其中, NAME 是不含换行符和 []() 的任意字符串; ARGUMENTS 是可选的参数,包含任意非换行符字符,不过开括号和回括号必须配平; HEADER1HEADER2 是可选的参数,同样它们由非换行符组成,且要求括号配平。

我几乎没有使用过 Org-mode 的 babel 功能,此处不详细展开。

3.16.2. affiliated keywords

所谓的 affiliated keyword (关联关键字)可以依附于某个元素来提供一些额外的信息,比如 #+attr_html 可以为某个元素提供一些 HTML 属性。 affiliated keywords 具有如下结构:

#+KEY: VALUE
#+KEY[OPTVAL]: VALUE
#+attr_BACKEND: VALUE

其中, KEY 是一个位于 org-element-affiliated-keywords 中的成员; BACKEND 是一个由 [a-zA-Z0-9-_] 组成的字符串,对 HTML 后端就是 htmlOPTVAL 是不含换行符的字符串,且括号必须配平,它仅在 KEY 属于 org-element-dual-keywords 时有效; VALUE 是不含换行符的字符串,不过当 KEY 属于 org-element-parsed-keywords 时有例外可以换行。

org-element-affiliated-keyword 给出了可用的 affiliated 关键字:

(defconst org-element-affiliated-keywords
  '("CAPTION" "DATA" "HEADER" "HEADERS" "LABEL" "NAME" "PLOT" "RESNAME" "RESULT"
    "RESULTS" "SOURCE" "SRCNAME" "TBLNAME"))

(defconst org-element-dual-keywords '("CAPTION" "RESULTS")
  "List of affiliated keywords which can have a secondary value.

In Org syntax, they can be written with optional square brackets
before the colons.  For example, RESULTS keyword can be
associated to a hash value with the following:

  #+RESULTS[hash-string]: some-source

This list is checked after translations have been applied.  See
`org-element-keyword-translation-alist'.")

需要注意的是,某些关键字已经过时了:

(defconst org-element-keyword-translation-alist
  '(("DATA" . "NAME")  ("LABEL" . "NAME") ("RESNAME" . "NAME")
    ("SOURCE" . "NAME") ("SRCNAME" . "NAME") ("TBLNAME" . "NAME")
    ("RESULT" . "RESULTS") ("HEADERS" . "HEADER")))

根据翻译表,现在推荐使用的 affiliated 关键字有:

  • CAPTION (dual)
  • NAME
  • HEADER
  • PLOT
  • RESULTS (dual)

除了 comments, clocks, headings, inlinetasks, items, node properties, planning, property drawers, sectionstable rows 外,其他的元素都可以被赋予 affiliated keyword

在一个元素上重复使用某个 affiliated keyword 将会导致先前的值被最后一个值覆盖。唯一的例外是 header

The sole exception to this is #+header: keywords, where in the case of multiple :opt val declarations the last declaration on the first line it occurs on has priority.

唯一的例外是 #+header: 关键字,在存在多个 :opt val 声明的情况下,优先考虑首次出现的行上的最后一个声明。

此外,如果 KEY 属于 org-element-dual-keywordsKEY#+attr_BACKEND ,那么多个 VALUE 会被连接起来得到最终的 VALUE 。文档给出了这样的例子:

#+name: image-name
#+caption: This is a caption for
#+caption: the image linked below
[[file:some/image.png]]

3.17. latex environment

latex environment 具有以下结构:

\begin{NAME}EXTRA
CONTENTS
\end{NAME}

其中, NAME 是一个包含字母数字或 * 的字符串, EXTRA 是不含 \end{NAME} 内容的字符串, CONTENTS 是不含 \end{NAME} 的字符串。以下是一个简单的例子:

\begin{align*}
2x - 5y &= 8 \\
3x + 9y &= -12
\end{align*}
\begin{align*} 2x - 5y &= 8 \\ 3x + 9y &= -12 \end{align*}

3.18. node property

node property 只能存在于 property drawer 中,它具有如下结构:

:NAME: VALUE
:NAME:
:NAME+: VALUE
:NAME+:

其中, NAME 是不含空白字符且不以 + 结尾的字符串, VALUE 是不含换行符的字符串。

和 babel call 一样,我基本上没有用过。

3.19. paragraph

paragraph 是默认的元素,空行和其他元素会终止段落。

3.20. table row

table row| 跟着以下情况组成:

  • 任意数量的 table cell
  • 一个 - ,表示这是一行“规则”行

table row 只能存在于 table 中。

4. 对各对象的详细介绍

对象可以出现在以下元素中:

4.1. entity

在 Org-mode 中, entity 具有如下结构:

\NAME POST
\NAME{}
\_SPACES

其中, NAME 是一个存在于 org-entitiesorg-entities-user alist 中的键; POST 是一个非字母(non-alphabetic)字符, SPACES 是一个或多个空格。以下是文档给出的例子:

1\cent.
1.5em space:\_   here, all three spaces in =\_   = constitute the entity name.

1¢. 1.5em space:   here, all three spaces in =  = constitute the entity name.

org-entitiesorg-entities-user 的值分别如下:

org-entities =>
("* Letters" "** Latin" ("Agrave" "\\`{A}" nil "&Agrave;" "A" "À" "À")
 ("agrave" "\\`{a}" nil "&agrave;" "a" "à" "à") ("Aacute" "\\'{A}" nil "&Aacute;" "A" "Á" "Á")
 ("aacute" "\\'{a}" nil "&aacute;" "a" "á" "á") ("Acirc" "\\^{A}" nil "&Acirc;" "A" "Â" "Â")
 ("acirc" "\\^{a}" nil "&acirc;" "a" "â" "â") ("Amacr" "\\={A}" nil "&Amacr;" "A" "Ã" "Ã")
 ("amacr" "\\={a}" nil "&amacr;" "a" "ã" "ã") ("Atilde" "\\~{A}" nil "&Atilde;" "A" "Ã" "Ã")
 ("atilde" "\\~{a}" nil "&atilde;" "a" "ã" "ã") ...)
(length org-entities) => 435

org-entities-user => nil

在 Org-mode 语法文档的附录给出了完整的 entry 列表,这里用几个可能比较常用的作为示例:

\alpha \beta \gamma \delta \epsion \eta \theta \lambda \pi \phi \omega \dots \laquo \raquo \lsaquo \rsaquo \vert \S \copy \trade \pm \times \div \frac12

\larr \lArr \uarr \uArr \rarr \rArr \darr \dArr \harr \hArr \crarr \oplus \otimes \check

α β γ δ \epsion η θ λ π φ ω … « » ‹ › | § © ™ ± × ÷ ½

← ⇐ ↑ ⇑ → ⇒ ↓ ⇓ ↔ ⇔ ↵ ⊕ ⊗ ✓

我们也可以直接使用 C-x 8 RET 来选择并输入 Unicode 字符。

4.2. LaTeX fragment

LaTex fragment 具有如下结构:

\NAME BRACKETS
\(CONTENTS\)
\[CONTENTS\]

其中, NAME 是不存在于 org-entitesorg-entites-user alist 的字符串, BRACKETS 是以下结构,它与 NAME 间不能存在空格:

[CONTENTS1]
{CONTENTS1}

CONTENTS1 不能包含 {}[] 和换行符, CONTENTS2 不能包含 {} 和换行符。以下是一些例子:

\enlargethispage{2\baselineskip}
\caption{Emacs development timeline}

但是,这种 LaTeX fragment 似乎在 LaTeX 后端会更加有用,在 HTML 后端中它们保持了原样。

对于第二种和第三种 LaTeX fragmentCONTENTS 是可以包含任意字符的字符串,不过第二种不能包含 \) ,第三种不能包含 \] ,以下是两个简单的例子:

\[\left(\begin{matrix}y_0\\y_1\\y_2\\\vdots\\y_{N-1}\end{matrix}\right) = \left(\begin{matrix}1&1&1&\dots&1\\1&W_N^1&W_N^2&\dots&W_N^{N-1}\\1&W_N^2&W_N^4&\dots&W_N^{2(N-1)}\\\vdots&\vdots&\vdots&\cdots&\vdots\\1&W_N^{N-1}&W_N^{2(N-1)}&\dots&W_N^{(N-1)^2}\end{matrix}\right) \left(\begin{matrix}x_0\\x_1\\x_2\\\vdots\\x_{N-1}\end{matrix}\right)\]

\(x_n = \frac1N \sum\limits_{k=0}^{N-1}e^{2\pi ik\frac nN}y_k \quad (n=0, 1, 2, \dots, N-1)\)

\[\left(\begin{matrix}y_0\\y_1\\y_2\\\vdots\\y_{N-1}\end{matrix}\right) = \left(\begin{matrix}1&1&1&\dots&1\\1&W_N^1&W_N^2&\dots&W_N^{N-1}\\1&W_N^2&W_N^4&\dots&W_N^{2(N-1)}\\\vdots&\vdots&\vdots&\cdots&\vdots\\1&W_N^{N-1}&W_N^{2(N-1)}&\dots&W_N^{(N-1)^2}\end{matrix}\right) \left(\begin{matrix}x_0\\x_1\\x_2\\\vdots\\x_{N-1}\end{matrix}\right)\]

\(x_n = \frac1N \sum\limits_{k=0}^{N-1}e^{2\pi ik\frac nN}y_k \quad (n=0, 1, 2, \dots, N-1)\)

除了上面几种形式,Org-mode 也支持 TeX 风格的 LaTeX fragment

$$CONTENTS$$
PRE$CHAR$POST
PRE$BORDER1 BODY BORDER2$POST

其中:

PRE
一行的开头或任意非 $ 符号的字符
CHAR
不是 .,?;" 的非空白字符
POST
任何标点符号(包括括号和引号)、空格字符或行尾
BORDER1
不是 .,;$ 的非空白字符
BODY
不含 $ 的任意字符串
BORDER2
不是 .,;$ 的非空白字符

4.3. export snippet

export snippet 具有如下结构:

@@BACKEND:VALUE@@

其中 BACKEND 是某导出后端的名字, VALUE 是不含 @@ 的任意字符串。简单的例子如下:

@@html:<ins>我是插入标签</ins>@@ @@html:<del>我是删除标签</del>@@

我是插入标签 我是删除标签

4.4. footnote reference

footnote reference 具有如下结构:

[fn:LABEL]
[fn:LABEL:DEFINITION]
[fn::DEFINITION]

其中, LABEL 是一个不含空格的字符串,可包含 -_DEFINITION 是标准对象,我们已经在 footnote definition 对这种对象进行了简单的举例,此处不再赘述。

4.5. citation

citation 具有如下结构:

[cite CITESTYLE: REFERENCES]
[cite CITESTYLE: GLOBALPREFIX;REFERENCES]
[cite CITESTYLE: REFERENCES;GLOBALSUFFIX]
[cite CITESTYLE: GLOBALPREFIX;REFERENCES;GLOBALSUFFIX]

文档中给出了如下例子:

[cite:@key]
[cite/t: see;@source1;@source2;by Smith /et al./]

ox-html 没有导出 citation

4.6. citation reference

citation reference 只能存在于 citation 中,且具有如下结构:

KEYPREFIX @KEY KEYSUFFIX

文档给出了如下例子:

[cite:@key]
[cite/t:see;@foo p. 7;@bar pp. 4;by foo]
[cite/a/f:c.f.;the very important @@atkey @ once;the crucial @baz vol. 3]

同样, ox-html 不导出 citation reference

4.7. inline babel call

inline babel call 具有如下结构:

call_NAME(ARGUMENTS)
call_NAME[HEADER1](ARGUMENTS)
call_NAME(ARGUMENTS)[HEADER2]
call_NAME[HEADER1](ARGUMENTS)[HEADER2]

其中, NAME 是包含除 []() 字符外任意字符的字符串, ARGUMENTS, HEADER1HEADER2 是不含换行符的字符串,且括号必须配平。

4.8. inline source block

inline source block 具有如下结构:

src_LANG{BODY}
src_LANG[HEADERS]{BODY}

其中, LANG 是不含空格和 [{ 的字符串,表示块中的语言; HEADERSBODY 是不含换行符的字符串, HEADER 中的方括号要求配平, BODY 中的大括号要求配平。

以下是一段简单的 C 代码例子:

src_c{int a = 114514; printf("%d\n", a);}

int a = 114514; printf("%d\n", a);

4.9. line break

line break 即换行符,它具有以下结构:

PRE\\SPACE

其中, PRE 是除 \ 外的任意东西, SPACE 是 0 个或多个 TABSPACE 字符。以下是一个简单的例子:

1 \\
2 \\
3

1
2
3

ox-html 中, line break 实现为 <br> 标签。

4.10. link

在 Org-mode 中 link 的种类很多,包括 radio, angle, plainregular

4.10.1. radio link

radio link 具有如下结构:

PRE RADIO POST

其中 PRE 是非字母字符, RADIO 是一个或多个由 radio target 匹配的对象,它只能是最小对象(见第一节对最小对象的描述), POST 是非字母字符。下面是一个简单的例子:

This is some <<<*important* information>>> which we refer to lots.
Make sure you remember the *important* information.

This is some important information which we refer to lots. Make sure you remember the important information. 读者可打开 HTML 源代码查看链接及标签的 id 属性。

ox-html 中,若 :html-prefer-user-labels 在导出过程中的值非 nil ,那么 radio target 的 id 会使用它的字符串内容,但是标准 HTML id 要求满足 [a-zA-Z][a-zA-Z0-9-_]* 正则匹配,生成的 id 可能不合规范。

4.10.2. plain link

plain link 具有如下结构:

PRE LINKTYPE:PATHPLAIN POST

其中, PRE 是一个不组成 word 的字符, LINKTYPEorg-link-parameters 中的一种链接类型, PATHPLAIN 是链接, POSTPRE 同理。以下是一个简单的例子:

Be sure to look at https://orgmode.org.

Be sure to look at https://orgmode.org.

4.10.3. angle link

angle link 可以用来消除 plain link 与周围文本的歧义,具有如下结构:

<LINKTYPE:PATHANGLE>

其中的 LINKTYPEPATHANGLEplain link 具有相同含义。我几乎从来没有使用过它。

4.10.4. regular link

regular link 具有以下两种形式:

[[PATHREG]]
[[PATHREG][DESCRIPTION]]

其中, PATHREG 可以是以下形式:

FILENAME               ("file" type)
LINKTYPE:PATHINNER     ("LINKTYPE" type)
LINKTYPE://PATHINNER   ("LINKTYPE" type)
id:ID                  ("id" type)
#CUSTOM-ID             ("custom-id" type)
(CODEREF)              ("coderef" type)
FUZZY                  ("fuzzy" type)

以下是一些例子:

[[https://orgmode.org][The Org project homepage]]
[[file:orgmanual.org]]
[[Regular links]]

4.11. macro

macro 调用具有以下两种形式:

{{{NAME}}}
{{{NAME(ARGUMENTS)}}}

其中, NAME 是宏的名字,满足正则 [a-zA-Z0-9-_]ARGUMENTS 是宏参数。以下是一些例子:

{{{title}}}
{{{one_arg_macro(1)}}}
{{{two_arg_macro(1, 2)}}}
{{{two_arg_macro(1\,a, 2)}}}

4.12. target and radio target

target 具有如下形式:

<<TARGET>>

其中 TARGET 不能包含 <> 和换行符,且不能以空白字符起始或结尾。

radio target 具有以下形式:

<<<CONTENTS>>>

其中的 CONTENTS 必须来自最小对象集合,且不含 <> 和换行符。

以下是 targetradio target 的两个简单例子,读者可以打开 HTML 源代码查看其 id 以及标签:

<<hello>>, <<<world>>> <<this is a target>>, <<<me too>>>

, world , me too

4.13. statistics cookie

statistics cookie 具有如下结构:

[PERCENT%]
[NUM1/NUM2]

它可以用来统计完成情况,比如如下列表:

- Hello [2/3] [66%]
  - [X] one
  - [X] two
  - [ ] three
  • Hello [2/3] [66%]
    • ☑ one
    • ☑ two
    • ☐ three

ox-html 中它实现为 <code> 标签包围的文本。

4.14. subscript and superscript

subscriptsuperscript 的结构如下:

CHAR_SCRIPT
CHAR^SCRIPT

其中 CHAR 为任意非空格字符, SCRIPT 可以是如下情况:

  • 单个 *
  • 使用大括号包围的表达式,表达式本身应该是大括号配平的,且属于标准对象集合
  • 如下形式:

    SIGN CHARS FINAL

    其中 SIGN 可以是 +- 或空字符串, CHARS 由任意数量的 [a-zA-Z0-9], ,, \. 组成, FINAL 是一个 [a-zA-Z0-9] 字符

4.15. table cell

table cell 为如下形式:

CONTENTS SPACES|
CONTENTS SPACES END-OF-LINE

其中 CONTENTS 不能包含 | 字符,且必须只能包含最小对象集合内的对象加上 citation, export snippet, footnote reference, link, macro, radio target, targettimestamp

4.16. timestamp

timestamp 可以是如下形式:

<%%(SEXP)>                                                     (diary)
<DATE TIME REPEATER-OR-DELAY>                                  (active)
[DATE TIME REPEATER-OR-DELAY]                                  (inactive)
<DATE TIME REPEATER-OR-DELAY>--<DATE TIME REPEATER-OR-DELAY>   (active range)
<DATE TIME-TIME REPEATER-OR-DELAY>                             (active range)
[DATE TIME REPEATER-OR-DELAY]--[DATE TIME REPEATER-OR-DELAY]   (inactive range)
[DATE TIME-TIME REPEATER-OR-DELAY]                             (inactive range)

4.17. text markup

PRE MARKER CONTENTS MARKER POST
  • *, a bold object, 粗体
  • /, an italic object, 斜体
  • _, an underline object, 下划线
  • =, a verbatim object, 引述
  • ~, a code object, 代码
  • +, a strike-through object. 删除线

4.17.1. plain text

什么对象也不是的对象就是 plain text

5. 后记

本文差不多就是把 Org-mode 的语法文档翻译了一下,想要查看更加严谨描述的同学可以看看原文去。我在今年 4 月份写完了 ox-w3ctr 这个 Org-mode 的导出后端以及这篇测试文档,现在总算是有时间改改之前的代码,顺便加加文档了。

References

[Japanese]

Janapanese 的 wiki 链接:https://en.wikipedia.org/wiki/Japanese_language

[Wikipedia]

Wikipedia 的链接:https://en.wikipedia.org/wiki/Wikipedia

[Kasuga]

In the aftermath of the unified login finalization, the user now going by Kasuga on Commons and on English Wikipedia is a different person. The accounts of the creator of Wikipe-tan were renamed Kasuga~enwiki, Kasuga~jawiki and Kasuga~commonswiki.

[4]
芝士匿名脚注,以标号作为脚注名
[芝士内联脚注]
以 :xxx: 作为脚注名,后面接脚注定义部分