Madoko-简洁而强大的学术写作工具

Markdown和Latex代表了写作语言的两极:Markdown追求极致的简洁,只有最少的格式控制;而Latex追求极致的可控,可以实现无线复杂的格式,也对语法有着严格的限制。而这两极之间一直遗留着广阔的空白地带,是否有这样一种写作语言,在实现精美排版的同时,保持着足够的简洁和易用呢?Madoko的便是为了这一目的而生。

为论文写作而生的工具

The main design goal of Madoko is to enable light-weight creation of high-quality scholarly and industrial documents for the web and print, while maintaining simplicity and focus on plain text readability.

写作的意涵有两个方面,一是表达,二是传达。表达的载体除了文字之外,也可以是图像、表格、视频,理想的表达工具应该在尽可能不影响思考过程的情况下记录思考的结果。传达即对内容的包装与展示,对于不同的受众,展现方式对内容的传达起到了至关重要的作用。就像同样是传达学术知识,教科书和学术论文给人的阅读感受是很不一样的。

从这两个角度出发,我们就能解释Markdown的成功。它将表达与传达的过程和二为一,而不是相互干扰。它基于HTML的输出形式,顺应了互联网时代的阅读潮流。但是Markdown的轻量化设计决定了它无法满足更为重型的写作任务,包括书籍和学术论文。在这些领域,除了专门的排版软件之外,仍然是Latex的天下。

Latex虽然提供了几乎无限的灵活性,但是仍然有一些不可忽视的缺点。一,作为一个数十年历史的老工具,Latex的语法逻辑、使用方式,与现在流行的语言和工具有一定的差别,增大了学习的难度;二,Latex能够提供高质量的PDF输出,但是,智能手机普及带来的移动阅读需求使得PDF并非手机阅读的首选格式,类似于Markdown的HTML格式输出更为合适。

为了解决上面的问题,Madoko诞生了。它提供了一些非常重要的特性:

  • 标签和文档内交叉引用
  • 相比Markdown,具有更强自定义特性的表格
  • 支持Bibtex格式的引用文献,支持自定义引文格式
  • 更完善的数学公式支持
  • 支持TikZ、PSTricks绘图程序包和SVG矢量图
  • 支持任意的原生Latex样式和宏包
  • 支持变成语言的语法高亮
  • 自动编号
  • 自动生成标题页和目录页
  • 支持自定义模块
  • 支持使用CSS样式直接定义HTML和Latex输出样式
  • 强大的文本替换支持
  • 直接生成演示文稿,支持Web演示或者打印输出
  • 与常见Markdown扩展兼容

总结起来,Madoko的优点在于三个方面:一,兼容几乎全部Markdown和Latex功能;二,简洁而强大的自定义语法;三,同时支持PDF和Web格式输出,同时支持文档和演示文稿渲染。

Madoko使用手册

行内格式语法

// 以下代码均成对出现在要设置格式的内容两侧
- 倾斜:_ or *
- 加粗:__ or **
- 代码:`
- 下标:~
- 上标:^
- 删除线:~~

// 引用格式
- 链接:
    - 引用链接:[Change the text][Google],[Google]: http://www.google.com
    - 行内链接:[Google](http://www.google.com)
    - 直接链接:<http://www.google.com>
- 图片:![bfly],[bfly]: images/butterfly-200.png "A Monarch" { width: 100px }
- 脚注:[^fn],[^fn]: 通过缩进使用多行脚注

// 特殊格式
- \/:用于单词内的加粗或倾斜,本身无意义。
- \:用于强制换行。

块格式语法

// 常用
- 标题:和Markdown一样,使用#个数指示标题层级

// 标签-#Label
- 标题:### A named heading { #myheading }
- 公式:In Equation [#euler],~ Equation { #euler; caption:"Euler's formula" } ~
  (对公式的引用会自动编号)
- 自定义编号顺序:下面的代码使用 - 清除了默认属性
  ### An unnumbered heading { - }
  ### A labeled heading     { -; id: myheading1; label: "my label" }
  Let's refer to Section [#myheading1].
- 图片:
  Figure [#fig-monarch] shows how to put an image in a figure.
  ~ Figure { #fig-monarch; caption: "A Monarch butterfly." }
    The ![monarch] image.
  ~
  
 // 列表
 - 无序列表:使用*,+,-作为标记均可,标记对应不同的符号。但是列表开头需要空一行,标记后需要空一格。
 - 有序列表:使用数字+点或者空格的形式。数字的顺序不重要,都是从第一个数字开始依次加一。
 - 名称列表:下面两种格式均可
   * Abstract syntax
    : The conceptual structure (illustrated by the pictures) is called 
      the abstract syntax of the language.
   Abstract syntax
     ~ The conceptual structure (illustrated by the pictures) is called 
      the abstract syntax of the language.
 
  // 块引用
  - 和Markdown一样,使用 > 插入块引用。

表格

表格是一个Markdown和Latex都不尽如人意的地方。Markdown的表格过于简洁,而Latex的表格语法繁琐。Madoko发展了Markdown的表格标记,力求以简单的方式来实现复杂的表格。其主要语法格式如下:

  • 每一行的开头和结尾以及每一列之间都必须以(|)或者(+)分隔。
  • 横跨多列的单元格可以使用多个(|)分隔。
  • 表格可以有一个或多个标题行。
  • 表格必须有一个列分隔行,在这个分隔行内,单元格中的内容使用(-)或者(~)。
// 一个表格的例子
|  id  |    name    |      description           |  price  |
|:-----|:----------:|----------------------------|--------:|
| 1    |   gizmo    | Takes care of doohickies   |   1.99  |
| 2    |   doodad   |     Collects *gizmos*      |  23.80  |
| 10   |  dojigger  |            Foo             |  102.98 |
| 1024 | Self-explanatory, no?                  ||    0.99 |

列分隔行的格式说明:

  • (:)的位置用来指定对应列的对齐方式,左右分别对应左对齐和右对齐,两侧均有对应居中对齐。
  • 如果列之间用(+)号分隔,列之间会出现竖线分隔。(+)后面不能有空格。
  • 如果单元格内使用(-),则出现横线,(~)不出现线条。(=)则出现双横线。
// 一个包含各种横竖分割线的复杂表格
| ------ | ----------------- | ------------------- | ------ |
|   id   |        name       |    description      |  price |
+--------+-------------------+:-------------------:+~~~~~~~:+
| 1      | gizmo                                          |||
|        | -----------------------------------------------|||
| 2      | doodad            | Collect *gizmos*    | 23.80  |
| ====== | ----------------- | =================== |--------|
| 1024   | thingamabob       | Self-explanatory    | 0.99   |
| ------ | ----------------- |                     | ------ |

对于可能横跨多页的长表格,我们需要在表格后设置breakable属性为true。

// 我们可以通过添加属性标签直接指定列的宽度等属性。
+:----:|---{width:2cm}--+:-----{width:60%}--------:+-------:+
| centered gizmos      || Take care of doo hickies |  1.99  |
|   2  |    doodad      |     Collects *gizmos*    | 23.80  |
|  10  |   dojigger     |            Foo           | 102.98 |
| 1024 | thingabob      |  Self-explanatory, no?   |  0.99  |
|------|----------------|--------------------------|--------|
    
// 我们可以使用类似的方式为单元格着色
// 除此之外,我们也可以在表格后加上复杂的样式控制
// 前缀:tr-,行;col-,列;tbody-,表格体;thead,表格头;
//      even-,偶数行;odd-,奇数行;last-,最后一行;n-,第n行;
| ---- | -------------- | ------------------------ | ------ |
|   id |     name       |    description           |  price |
+:----:+--{background-color:Silver}--+:-----------:|-------:+
| centered gizmos      || Take care of doo hickies |  1.99  |
|   2  |    doodad      |     Collects *gizmos*    | 23.80  |
|  10  |   dojigger     |            Foo           | 102.98 |
| 1024 | thingabob      |  Self-explanatory, no?   |  0.99  |
|------|----------------|--------------------------|--------|
{ tbody-tr-odd-background-color:Gainsboro; \
  tr-even-background-color:Floralwhite }

// 为了方面的画出样式美观的表格,我们可以直接使用预定义的booktable样式
| --------------- | ----------- | --------------- |
|             Item             ||                 |
| \/------------- | ----------- |                 |
| Animal          | Description | &ensp;Price ($) |
| :-------------- | ----------- | --------------: |
| Gnat            | per gram    |           13.65 |
|                 | each        |            0.01 |
| Gnu             | stuffed     |           92.50 |
| Emu             | stuffed     |           33.33 |
| Armadillo&ensp; | frozen      |            8.99 |
| --------------- | ----------- | --------------- |
{ .booktable }
// 关于上面代码的一些说明:\/符号不会产生实际作用,它的目的是防止这一行被识别为列分隔行。

代码

插入代码块最简单的方式是直接将代码缩进四个空格。或者使用和Markdown类似的方式:

``` html 
<a href="foo.com">a link in html</a>
```

使用上面的方式,Madoko会自动进行语法高亮,使用Latex输出的PDF也会保留高亮样式。

对于代码块来说,非等宽字体会显得更美观,但是对齐会出错,Madoko提供了一个(.pretty)属性使得代码在美观的同时,保持对齐。

``` Haskell { .pretty }
data Exp   =  Number    Int
           |  Add       Exp Exp
           |  Subtract  Exp Exp
           |  Multiply  Exp Exp
           |  Divide    Exp Exp
           |  Variable  String        -- added
           deriving (Eq)
``` 

Madoko也支持对语法高亮的自定义设置:

.token.identifier    { font-style: italic }
.token.string.escape { color: gray }

// 对于pretty环境中的代码,可以结合下述代码使用:
@if tex {
  .ptoken.keyword    { font-family: sans-serif }
}

// 我们还可以扩展现有的高亮语法,添加新的需要高亮的关键字,详见Madoko参考手册。

矢量图

Madoko可以整合任意的Latex代码和宏包,自然也包括Latex中常用的绘图宏包Tikz和PSTricks。

// 先导入宏包
Package: pstricks
Package: pst-plot

// 使用Snippet环境插入代码
~ Center  {padding:1ex} 
~~ Snippet
\psset{unit=2cm} 
\begin{pspicture*}(-0.5,-1.5)(4,2) 
  \psgrid[subgriddiv=5,gridcolor=black!20% 
         ,gridlabels=0pt](1,0)(3,1.2)
  \psaxes{->}(0,0)(0,-1)(3.2,1.5)
  \uput[0](3.2,0){$x$}\uput[90](0,1.5){$f(x)$} 
  \pscircle*[linecolor=red](! Euler 1){3pt}
  \psline[linecolor=red,linestyle=dashed]%
         (! Euler 0)(! Euler 1)
  \psline[linecolor=red,linewidth=0.2pt,arrowscale=2]%
         {->}(! Euler 1)(0, 1)
  \uput[-90](! Euler 0){\color{red}$e$}
  \pscircle*[linecolor=blue](1,0){3pt} 
  \psplot[linewidth=1pt]{0.2}{3}{ x ln } 
  \rput(1.6,-0.5){\color{blue}\fbox{$f(x)=\ln(x)$}} 
\end{pspicture*}
~~
~ 

// 使用Tikz宏包时,使用下面的代码
Package     : tikz
Tex Header  : \usetikzlibrary{decorations.pathreplacing%
                             ,decorations.pathmorphing}

Madoko渲染Latex代码时默认使用xelatex,但是有的时候xelatex对图片的渲染会出错,我们可以使用命令:Math Latex Full: pdflatex,指定使用pdflatex来渲染。

公式

Madoko中的公式继承了Latex的语法,同时做了一些修改,以保持和其他Madoko语法的一致性。

Madoko在将文档渲染成HTML时,对公式有两种渲染方式:

  • 静态,static:Madoko使用Latex将公式渲染成图片。好处是加载速度快,坏处是本地使用时需要先安装Texlive。
  • 动态,dynamic:Madoko使用Mathjax实时渲染,好处是不需要预先安装Latex,坏处是公式很多的时候速度慢,并且有些命令不支持。可以在文档开头添加:Math Mode: mathjax 来开启这一命令。
A famous equation is $E = mc^2$, but another famous one is:
~ Equation  {#eq-gaussian; caption:"The Gaussian equation" }
 \int_{-\infty}^\infty e^{-a x^2} d x = \sqrt{\frac{\pi}{a}} 
~

// 行内公式如果太长,可以使用Latex注释换行
A long $E = %continue on next line
   mc^2$ formula.

// 如果不想给公式自动编号,需要使用Math而不是Equation
~ Math
P\left(A=2\;\middle|\frac{A^2}{B}>4\right)
~

// 对齐公式
~ Equation { #eq-alignment; caption:"Alignment example" }
\begin{aligned} 
 f(x)  &= a x^2+b x +c   &   g(x)  &= d x^3 \\
 f'(x) &= 2 a x +b       &   g'(x) &= 3 d x^2
\end{aligned}
~

// 排列公式也可以通过自定义规则来简化语法
Aligned { replace:"~Math&nl;\begin{aligned}&nl;&source;&nl;\end{aligned}&nl;~" }
~ Aligned
f(x) &= (x+a)(x+b) \\
&= x^2 + (a+b)x + ab
~

// 如果公式用到了其他宏包,我们只需要提前将其导入即可
Package: amscd
~ Equation { #eq-commuting; caption:"A commuting diagram" }
\begin{CD}
S^{{\mathcal{W}}_\Lambda}\otimes T @>j>> T\\
@VVV @VV{P}V\\
(S\otimes T)/I @= (Z \otimes T)/J
\end{CD}
~

// 对于数学公式非常多的文档,我们可以预定义一些简化命令
~ MathDefs
\newcommand{\infer}[3]{#1 \vdash #2\,:#3}
~ 
We infer $\infer{\Gamma}{e}{\tau}$ for such expression $e$.

// 通常我们把这些预定义命令放到单独的tex文件中,再导入进来
~ MathDefs
[INCLUDE="mathdefs.tex"]
~

预定义样式的公式:Latex的数学公式环境会赋予数学公式统一的样式,但是某些情况下我们需要对不同的部分赋予不同的样式,比如:计算机科学书籍中描述算法时常出现的代码和公式混杂的情况。Madoko提供了MathPre代码块来解决这一问题。它具有如下特点:

  • 保留了空格,间距、缩进和换行均使用数学样式;
  • 由字母和数字组成的名称看起来会更紧凑;
  • 名称后面带的数字自动变成下标;
  • @开头的名称变成了mathkw格式;
  • #开头的名称样式不变;
  • 可以使用&来对齐文本;
~ MathPre
@function sqr_\pi( num :int ) \{ 
  @return (num {\times} num \times{} \pi)
\} 
~

// 下面的代码可以将所有数学公式样式替换为MathPre样式
.math-inline,.math-display {
  input: mathpre;
}

目录

生成目录非常简单,除了生成标题目录之外,我们还可以生成图片、公式、表格等其它内容的目录。也可以自定义目录深度和样式。

// 一般目录,Toc Depth属性指定深度
[TOC]
// 图片目录
[TOC=figures]

引用文献

Madoko使用 BibTeX 和 Citation Style Language](http://citationstyles.org/) 来处理参考文献。

// 首先导入参考文献所在的bib文件
Bib:  ../mybib1

// Bib文件中的参考条目有一个关键字
@BOOK{ Knuth:TeX,
  author   = "Knuth, Donald E.",
  title    = "The {\TeX} book",
  publisher= "Addison-Wesley",
  year     = 1984
}

// 通过关键字我们可以施加引用
Read more [The book @Knuth:TeX;\ @Lamport:LaTeX (chapter 4)]. 

// 在需要放置引用文献章节的地方使用下面代码, 可以通过设定name-references属性指定该章节标题 
[BIB]

设置参考文献样式时,Madoko可以同时使用bst格式和csl格式文件。csl格式的好处在于,网络上有很多现成的文件提供。bst格式的参考文献样式可以在这里找到。

// 使用下面的代码导入csl文件
Csl Style: Taylor-and-Francis-Chicago-Author-Date

// 使用bst文件的方式
Bib Style: plainnat

// 正文中的引用样式一般有引用样式文件定义,我们也可以自己指定。
Cite Style: natural
// 可选的样式包括:natural, sqnatural, textual, super, and numeric

除了基本的展示功能之外,Madoko对参考文献还提供了一些有用的辅助功能。一是在HTML中参考文献的引用位置显示一个提示功能,二是在具体参考文献条目后面加一个搜索按钮,如果要在生成的PDF中也显示上述两个功能,需要加额外的命令:

~a: .tex-tooltip

自定义代码块


Madoko预定义了一些有用的代码块,除了之前涉及到的一些之外,还有:

  • Bibitem, Bibliography :单独输入参考文献条目
  • Note, Remark, Proof
  • Abstract :定义摘要
  • Framed :带有实线边框的块
  • Center :使内容居中
  • Columns, Column :column放置在columns中,使页面内容分几列放置
  • TexRaw :直接传递给Tex引擎的代码
  • HtmlRaw :直接传递给HTML引擎的代码
  • TexOnly :只会传递给Tex引擎的代码
  • HtmlOnly :只会传递给HTML引擎的代码
  • Section:主要使用在演示文稿模式中
  • Article, Aside, Nav :变成对应的HTML5标签
  • Theorem, Lemma, Proposition, Corollary, Example, Definition :均单独编号,带有对应的加粗名称,可以使用caption属性指定标题

另外还有一些特殊的块元素:

  • [TITLE] :生成标题
  • [TOC], [TOC=name] :生成目录
  • [FOOTNOTES] :生成脚注
  • [INCLUDE=file] :直接展开成对应文件内容,在其它内容处理之前最先被处理。
  • [BIB] :导入bib文件

导入其它文件

// 语法格式
[INCLUDE(=file)?(:range)?] 

// 指定文件名和行的范围
[INCLUDE=foo.hs:10-18]
[INCLUDE=foo.hs:20] // 导入20行之后的所有行

// 通过片段名导入
// 对于下面的文件
-- BEGIN:Var
-- BEGIN:Syntax
-- END:Syntax
-- END:Var                     
--BEGIN:Eval
--END:Eval

// 我们可以使用下面的代码导入指定片段
[INCLUDE=foo.hs:Var]
[INCLUDE=foo.hs:Eval]

// 为了省略文件名,我们可以先导入文件,而后可以直接输入片段名
[INCLUDE=foo.hs:0]
[INCLUDE:Syntax]

元数据和样式设置

元数据

元数据必须出现在文档的最一开始,用来指定标题、作者等基本信息和设置格式。

Title       : An overview of Madoko
Author      : Daan Leijen
Affiliation : Microsoft Research
Email       : daan@microsoft.com
Logo        : False
Embed       : False

完整的Madoko预定义关键字列表参见官网参考文档。

主要语法特性:

// 条件格式
@if html {
  Logo: True
}

@if not tex {
  h2 { color: blue }
}

// Entity实体
The title of this document is "&title;".\
And this section has label &sec-entity;.\
Standard entities are looked up last &Delta;&hArr;&delta;.

样式设置

Madoko使用css的语法来进行样式设置,并提供了一些简化语法。

{ key: value; key: value }

id:name可以简化为#id;
class:classnames可以简化为.class;

This is a paragraph in small-caps.
{ font-variant: small-caps} 

* {color: navy} This is a 'mylist' 
* in italics
{ .mylist; font-style: italic }

Madoko支持直接导入css文件,在输出为pdf时,后台会将很多常见css命令转化为对应的Latex命令,以保持PDF和HTML的格式一致性,其它的会被忽略。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,117评论 4 360
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,963评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 107,897评论 0 240
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,805评论 0 203
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,208评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,535评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,797评论 2 311
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,493评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,215评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,477评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,988评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,325评论 2 252
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,971评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,055评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,807评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,544评论 2 271
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,455评论 2 266

推荐阅读更多精彩内容