正在设计一种新的轻量级标记语言:InkMark

2021年5月27日 // InkMark Markdown

缘起

凡是编程开发领域的人,想必都熟悉 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

可以通过 .# 为各种元素添加 classid 属性,这时元素内容两侧的方括号是不可省略的,如:

.[[段落内容]][.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。目前我准备先把这个语言的规范给写出来,然后看看有没有志同道合的人来为其生态做贡献,如针对这个语言为常见的编辑器添加语法高亮功能,编写其解析器,甚至编写专用的编辑器。

这些不是我的主业,我向来又懒散,干这些事情也总是慢悠悠的。其中的好处是经过长时间的思考,我对这门语言的构思越来越成熟。至于坏处吗,最坏的可能就是胎死腹中。