缘起
凡是编程开发领域的人,想必都熟悉 Markdown,它是一种轻量级的标记语言而非编程语言,广泛被用于文档的撰写。从第一次接触 Markdown 开始,我就非常喜欢它。然而,当我尝试用 Markdown 写一些学术性的东西时,却发现它完全无法满足需求。因为它连基本的上下标都不支持,更别说能很好地表达学术文档中常用的图像、表格、公式和参考文献,以及这些内容的自动编号和引用。期间我还大量使用 MediaWiki,配合 HTML,MediaWiki 标记语法确实能表达一些学术性的内容,比如英文维基百科上调和矩阵这样一篇包含大量公式的条目。然而 MediaWiki 标记语法相对较为繁琐,且在表达复杂内容时,需要配合 HTML 使用,多数情况下并不讨人喜爱。另外还有很多其他形式的轻量级标记语言,如 reStructuredText,其功能相对更为强大,但语法繁琐,我还是不喜欢。至于 LaTeX 这种专业的学术论文排版系统,其功能十分强大,但也非常复杂难用,实践证明,我等凡人是学不会的。因此,我就在有意无意中思考着该怎样简单地标记学术内容。起初只是随便想想,后来发现我确实能对 Markdown 做出很多改进,再到后来,我又把这些改进统一成一致的表述规则,于是一种新的轻量级标记语言就呼之欲出了,就让我们称之为 InkMark 吧。
InkMark 是一种轻量级标记语言,它的语法规定了如何利用简单的标记,为文本添加结构、语义和格式。通过特定的 InkMark 编译器,可以将这些纯文本转换为规范的 HTML 或其他格式的文档。InkMark 尤其适用于学术内容的网络书写与展示。
特性
相对于其他各种轻量级标记语言,InkMark 具有以下特性:
- 具有几乎与 HTML 相匹配的文档内容描述能力。理论上来说,InkMark 可以表示 HTM5 中的所有类型的元素,且可以像 HTML 那样为元素添加任意属性。
- 很好地在简单和功能强大之间取得平衡。InkMark 的元素标记法包括完整模式和简写模式,其完整模式像 HTML 一样功能强大,而简写模式则像 Markdown 一样简单,且可以按统一的规则由完整模式过渡到简写模式。
- 简写模式使用独特的“标记符号加方括号对接龙”形式的语法。例如,在其他轻量级标记语言中,常用
**着重强调**
表示要 着重强调 的文本,Inkmark 中却使用*[着重强调]
达到同样的效果。其他轻量级标记语言的用户在刚开始可能会不太习惯,但一旦适应,他们多数会喜欢上这种标记方式。 - 能够用于科学技术报告、学术论文、书籍的书写。通常这些学术文档篇幅巨大,结构复杂,含有大量的图像、表格、公式和参考文献,需要对这些内容标注题注、自动编号,并在文档其他位置进行交叉引用和索引。
- 具有灵活的文档组织能力。各个文档可独立编写和呈现,之后不必改变就可以合并在一起形成更长的主文档。无论是论坛帖子、博客文章、期刊论文、报告或书籍,其书写体验基本是一致的。
- 更注重语义的表述,尽量不直接指定显示格式。如该语言关心你文本中的一行文字是普通段落、标题还是引文,但却不关心你的段落对齐方式,以及首行是否缩进等。
- 尽可能保持语法的一致性和对称性,使用户能根据一定的规则来理解和学习其语法,降低语法学习和编译器实现的难度。
- 良好的中文支持。其语法在元素标签和属性名称,换行、空格、标点处理,东西方文字混排等方面都更符合中文用户的使用习惯。
- 更加复杂。功能强大必然带来复杂性的提升,因此其学习及编译器的实现也更加困难。
- 当使用相对高级的功能时,所生成 HTML 文本的正确显示需要依赖特定的层叠样式表(CSS)甚至 JavaScript 代码。如可能要借助 MathJax 这类 JavaScript 数学显示引擎才能正确地显示文本中的公式,带编号公式的合理显示布局(通常公式和编号显示在同一行内,公式居中对齐,编号右对齐)也需要借助额外的 CSS 实现,而一些自定义类独有的显示方式也需要借助 CSS 实现。
相对于 LaTeX 这种专业的学术论文排版系统,InkMark 主要专注于为文本添加常用的结构和语义,而其他更多的功能,如文本和页面样式,则大多交给其他程序(如和网页关联的层叠样式表,CSS) 来完成。因此,其功能要远远少于 LaTeX,但也简单得多。
示例
和 HTML 元素一样,InkMark 的元素类型也分为行内元素和块级元素,两种元素的标记法稍有不同。InkMark 标记语法包括完整模式和简写模式,多数情况下我们只是使用简写模式。以下只通过示例介绍简写模式。
InkMark 的简写模式使用一种“标记符号 + 方括号包括的被标记内容 + 方括号包括的属性值 + 另一个方括号包括的属性值”的形式。其中的“方括号包括的属性值”可以有多个,形成接龙。对于行内元素,只需要用单一一对方括号包括被标记的内容;对于块级元素,其内容两侧的方括号应各自至少重写两次,且两侧重写的次数必须相等。
简单的行内元素示例:
- 着重强调:
*[着重强调]
- 强调:
/[强调]
- 插入:
+[显示带下划线的文字]
- 删除:
-[显示带删除线的文字]
- 上标:
^[上标]
- 上标:
_[下标]
- 链接:
@[链接文字][https://example.com/]
- 行内 LaTeX 公式:
$[\sqrt{a^2+b^2}]
对于简单的单行书写的块级元素,可以省略元素内容两侧的重复书写的方括号,但标记符号前方不能有非空白字符,标记符号和被标记内容之间必须由空格或水平制表符分割:
" 块级引用文字
? 注释文字
= 一级标标题
== 二级标题
=== 三级标题
* 无序列表项
# 有序列表项
段落标记和 Markdown 标记一样,即上下是空行就行。但 InkMark 其实有一个段落标记符号,就是英文句号 .
,只不过这个符号常被省略而已。有时候段落标记可以放在其他块级标记符号后面,起到复合标记的效果,如以下列表项的内容将同时被加上段落标记:
*. 带段落标记的列表项内容 1
*. 带段落标记的列表项内容 2
可以通过 .
和 #
为各种元素添加 class
和 id
属性,这时元素内容两侧的方括号是不可省略的,如:
.[[段落内容]][.class-name-1.class-name-2#id-name]
表格(其中的 |
表示一般单元格,!
表示标题行单元格):
+++[[
-! 第1行第1列 ! 第1行第2列 ! 第1行第3列
-| 第2行第1列 | 第2行第2列 | 第2行第3列
-| 第3行第1列 | 第3行第2列 | 第3行第3列
]][表格的标题]
常规图像:
&[https://example.com/path/to/picture.png][alt=替换文字][宽度=600px]
带边框、标题和描述的图像(对应 HTML 中的 figure
元素):
&[[https://example.com/path/to/picture.png]][标题=图像标题][描述=图像描述]
带边框、标题和描述的图像,且图像标题中带“图 1”这样的标签和自动编号:
&[[https://example.com/path/to/picture.png]][标题=#[.图][图像标题]][描述=图像描述]
自动编号:#[.表][表的标题]
引用自动编号的方式和链接详细的,但不必加链接项:@[.表#表的标题]
。
同时支持其他自定义形式的标记。如行内的 span
标记:[=span][被标记的行内元素内容]
。块级的 div
标记:
[=div][[
被标记的块级内容。
]]
整行显示的(英文中常说的 display 样式)LaTeX 公式,右侧带编号标签:
$$$[[
\left[ \begin{matrix}
\sigma _{xx}& \tau _{xy}& \tau _{xz}\\
\tau _{yx}& \sigma _{yy}& \tau _{yz}\\
\tau _{zx}& \tau _{zy}& \sigma _{zz}\\
\end{matrix} \right]
]][标签=(1)]
为了保证语法的一致性,预格式化代码块的表示相对 Markdown 要繁琐一点。如:
```[[
package main
import "fmt"
func main() {
fmt.Printf("Hello, 世界!\n")
}
]][lang=Go]
借用自动编号的功能,参考文献和正文放在一起,而不用另列单放,以此保证文档各部分相对独立。如下为正文中以上标的 [1]
形式插入的参考文献:
#[.参考文献#参考文献名称][参考文献具体内容][^[ [#1] ]]
生成图、表、参考文献的引用列表的方式也是一致的,如:
@[[.参考文献]]
真正的规范将包含居多的内容,这里就不一一介绍了。
其他
相对 Markdown 来说,InkMark 的形式没有那么优雅,但格式更统一,易记易学。当然,其表达能力在所有的轻量级标记语言中都是顶尖的。我自己平时用这种格式记大量笔记,总体用起来感觉很好,其文档看起来几乎和 Markdown 一样美观,反正我自己是能接受的。
Markdown 是有巨大生态的,我这个东西只是用来玩,从来不希望替代 Markdown。目前我准备先把这个语言的规范给写出来,然后看看有没有志同道合的人来为其生态做贡献,如针对这个语言为常见的编辑器添加语法高亮功能,编写其解析器,甚至编写专用的编辑器。
这些不是我的主业,我向来又懒散,干这些事情也总是慢悠悠的。其中的好处是经过长时间的思考,我对这门语言的构思越来越成熟。至于坏处吗,最坏的可能就是胎死腹中。