在『先写作,后排版』浮光掠影的给出了一些用于写作的 ConTeXt 宏,它们大致与 Markdown、reStructuredTeXt 之类的标记语言是等价的,即仅关注写作内容而不考虑排版。然而 ConTeXt 除了对内容的写作予以支持,它还要考虑内容的排版问题,因此它必须提供内容与版式的分界。例如规划一块区域放置内容,另一区域放置我们所设定的版式,因此这两个区域之间就存在着界限。我们将这些区域及其分界称为 ConTeXt 文稿的物理结构 ,它就像容纳着我们所要排版的文档内容及其版式的容器。所谓的『ConTeXt 文稿』,意即 context
命令所接受的输入文件—— .tex
文件。
无论是 ConTeXt 还是 LaTeX,其源头是 TeX,而 TeX 文稿是没有什么物理结构的。整篇 TeX 文稿就是 TeX 宏的堆积,只需要在文档的末尾加个 /bye
告诉 TeX 引擎:『文稿到此结束』。这种方式,对于那些有着整齐有序的好习惯的 TeX 用户而言没什么不好,但是对于那些比较随意的 TeX 用户,则很容易写出控制序列漫天飞从而很难看懂的 TeX 文稿。
LaTeX 与 ConTeXt 定义了一些控制序列,对 TeX 文稿进行概念上的分割,从而形成了各自的物理结构。
LaTeX 文稿的物理结构为:
% 设定文稿类型 /documentclass{article} % 导言区 ... ... % 正文区 /begin{document} ... 正文 ... /end{document}
ConTeXt 的等价结构为:
% 导言区 ... ... % 文档内容 /starttext ... ... /stoptext
之所以说 LaTeX 与 ConTeXt 对 TeX 文稿进行了概念上的分割,是因为它们并没有对文稿进行真正的区域划分。例如,LaTeX 与 ConTeXt 都建议用户尽量在导言区进行一些全局性的排版参数设定,但是用户也完全可以不遵守这个建议。
好了,我不再提 LaTeX,下面只关心 ConTeXt。
上面所展示的是最基本的 ConTeXt 文稿物理结构。下面使用该结构写一篇文章:
/usemodule[zhfonts] /starttext /title{庄子和惠子游于濠梁} 庄子与惠子游于濠梁之上。 庄子曰:“鯈鱼出游从容,是鱼之乐也。” 惠子曰:“子非鱼,安知鱼之乐?” 庄子曰:“子非我,安知我不知鱼之乐?” 惠子曰:“我非子,固不知子矣;子固非鱼也,子之不知鱼之乐全矣!” 庄子曰:“请循其本。子曰‘汝安知鱼乐’云者,既已知吾知之而问我。我知之濠上也。” /stoptext
这份文稿很简单,而且未考虑任何排版问题,是个不错的只专注于写作的示例。对于这份文稿,结合 ConTeXt 文稿的基本物理结构,可以理解为:
在导言区( /starttext
之前的区域)加载 zhfonts 模块。
在正文区域(即 /starttext
与 /stoptext
所包含的区域),使用 /title
控制序列设定文档标题,其后就是文档内容。
这份文稿经 context
编译后输出结果如下图所示:
因为在写作过程中不关注排版,导致排版结果很难看,例如存在标题不够醒目,段落首行没有缩进以及文本行距过紧等问题。现在,假定该文档的写作过程已经结束,现在我们可以向导言区添加一些排版参数的设定语句改善一下版式,即:
/usemodule[zhfonts] /setuphead[title][style=/bfb, indentnext=yes] /setupindenting[always, first, 2em] /setupinterlinespace[line=1.6em] /starttext /title{庄子和惠子游于濠梁} 庄子与惠子游于濠梁之上。 庄子曰:“鯈鱼出游从容,是鱼之乐也。” 惠子曰:“子非鱼,安知鱼之乐?” 庄子曰:“子非我,安知我不知鱼之乐?” 惠子曰:“我非子,固不知子矣;子固非鱼也,子之不知鱼之乐全矣!” 庄子曰:“请循其本。子曰‘汝安知鱼乐’云者,既已知吾知之而问我。我知之濠上也。” /stoptext
排版结果如下:
显然,我们在导言区所添加的 3 行代码是用于设定排版样式的,即使现在你对 ConTeXt 排版非常陌生,应该也能轻易的看出:
setuphead[title][style=/bfb, indentnext=yes]
是设定标题文本呈粗体并且标题之后的段落首行具有缩进。
/setupindenting[always, first, 2em]
是设定段落首行缩进尺寸为 2 个字宽。
/setupinterlinespace[line=1.6em]
是设定文本行距为 1.6 倍的字高。
但是对于本文的意图而言,上述解释并不重要。真正重要的是,我们在导言区添加的这 3 行代码并未对正文区( /starttext
与 /stoptext
之间的区域)有任何改动。这意味着,我们总是能够在导言区进行版式的设定而不会破坏正文区域的可读性。
虽然在导言区放置版式设定代码不会破坏正文区域的可读性,但是如果版式设定代码过多,也会让导言区乱象环生,并且正文区域也会被向下推移动,而无法在打开文稿时第一眼被看到。可将导言区中的代码存放到环境 (Environment) 文件中。
假设有这样一份 ConTeXt 文稿,文件名为 plain-sty.tex,内容如下:
/startenvironment plain-sty /usemodule[zhfonts] /setuphead[title][style=/bfb, indentnext=yes] /setupindenting[always, first, 2em] /setupinterlinespace[line=1.6em] /stopenvironment
这样的文稿即为 ConTeXt 环境文件 。
上面的环境文件示例中的主要内容我们并不陌生,这些语句置于 /startenvironment ... /stopenvironment
区域。尾随 /startenvironment
控制序列之后的是环境的名字,它必须与环境文件名相同。ConTeXt 建议用户将文档所有的全局排版设定均置于环境文件中。
对于像 plain-sty.tex 这样一份定义好的环境文件,在 ConTeXt 文稿中的使用方式可参考下面的示例:
/environment plain-sty /starttext /title{庄子和惠子游于濠梁} 庄子与惠子游于濠梁之上。 庄子曰:“鯈鱼出游从容,是鱼之乐也。” 惠子曰:“子非鱼,安知鱼之乐?” 庄子曰:“子非我,安知我不知鱼之乐?” 惠子曰:“我非子,固不知子矣;子固非鱼也,子之不知鱼之乐全矣!” 庄子曰:“请循其本。子曰‘汝安知鱼乐’云者,既已知吾知之而问我。我知之濠上也。” /stoptext
只需使用 /environment
控制序列,并向其提供环境文件名,便可以将环境文件的内容载入包含正文区域的 ConTeXt 文稿中。
如果你是个程序猿,我相信 ConTeXt 的环境文件对你而言是非常容易理解的,它有些类似 C 语言的头文件,也类似于网页的 CSS 文件。可将 ConTeXt 环境文件等同于衣服,而将包含正文区域的 ConTeXt 文稿视身体。我们可以为同样的身体提供各种各样的衣服。
如果你了解一些 Plain TeX 或 LaTeX 的知识,可能会认为 /input
也能起到类似 /environment
的作用,但二者的区别是 ConTeXt 可以保证环境文件仅被加载一次。
环境文件仅被加载一次,这有什么优势?无论是 Plain TeX、LaTeX 还是 ConTeXt,在处理交叉引用方面的内容时,通常要对文稿重复编译多次。在 ConTeXt 中,在对文稿的多次编译过程中只需对环境文件加载一次,可以提高输出排版结果的效率。
采用 /starttext ... /stoptext
结构的文稿,尽管有环境文件的辅助,但是它依然不足以构建规模较大一些的文档,譬如一本页数较多的书籍。因此,ConTeXt 提供了作品(Product)与组件(Component)的文稿结构。
下面示例建立了一份文件名为 prd.tex 的作品文稿,现在它还是一个空壳。
/startproduct prd % ... 暂且无内容 ... /stopproduct
组件是对作品结构的进一步分割,也就是说一份作品由一些组件构成。下面的示例建立了一份文件名为 c-1.tex 的组件文稿,其定义方式类似作品文稿。
/startcomponent c-1 /product prd % 表示该组件隶属于作品 prd % 暂且无内容 /stopcomponent
现在假设我们建立了多个组件,例如 c-1.tex, c-2.tex 等,可以它们插入作品文稿:
/startproduct prd /component c-1 /component c-2 ... ... /stopproduct
亦可向作品文稿中插入环境文件:
/startproduct prd /environment plain-sty /component c-1 /component c-2 ... ... /stopproduct
作品、组件与环境文件的逻辑关系如下图所示:
ConTeXt 还提供了比作品更大的文稿结构,即项目(Project)。项目主要是面向排版风格相同的一系列的书籍或期刊的排版的,本质上就是一系列 product 的组合,在此就不涉及了。有欲观瞻者,可阅: http://wiki.contextgarden.net/Project_structure