\chapter{一字不差} 在现在这个时代,文档出现一些计算机程序代码片段,是很常见的事。通常建议用等宽字体呈现这些代码且原样显示,像是过去打字机的输出结果,故而 Verbatim text,我将其译为\boxquote{文本抄录}。 \section{抄录} 抄录有两种形式,一种是位于一行文字之内,用 \type{\type{...}} 排版\index[type]{\tex{type}},另一种是位于段落之间的 \type{typing} 环境\index[typing]{\type{typing} 环境}。例如 \startexample \startframedtext[width=broad] 用 C 语言写一个程序,让它在屏幕上显示「\type{Hello world!}」,代码如下 \starttyping #include int main(void) { printf("Hello world!\n"); return 0; } \stoptyping \stopframedtext \stopexample \simpleexample[option=TEX]{\null} \start \setuptyping[before={\blank[line]},after={\blank[line]}] \getexample \stop 上例不仅演示了抄录命令的基本用法,也演示了如何用 \type{framedtext} 环境构造边框。在 \type{\setuptyping} 命令的 \type{before} 和 \type{after} 参数允许你根据自己的需求,添加可被 \type{typing} 环境自动执行的排版命令。下例可以让 \type{typing} 环境自带边框。 \startexample \setuptyping[before={\startframedtext[width=broad]}, after={\stopframedtext}] \starttyping 带外框的 \starttyping ... \stoptyping \stoptyping \stopexample \simpleexample[option=TEX]{\null} \start\getexample\stop \type{\setuptyping} 的 \type{line} 参数可用于设定代码行号。通过 \type{\setuplinenumbering}\index[setuplinenumbering]{\tex{setuplinenumbering}} 可定制行号样式。下例开启代码行号,并将行号到 \type{typing} 环境的距离设为 0.5em: \startexample \setuptyping[numbering=line, before={\startframedtext[width=broad]}, after={\stopframedtext}] \setuplinenumbering[typing][distance=.5em] \starttyping #include int main(void) { printf("Hello world!\n"); return 0; } \stoptyping \stopexample \simpleexample[option=TEX]{\null} \start\getexample\stop \section{着色} \CONTEXT\ 提供了代码语法着色功能,例如对 \TEX\ 代码进行着色, \startexample \starttyping[option=TEX] \starttext Hello \CONTEXT! \stoptext \stoptyping \stopexample \simpleexample[option=TEX]{\null} \start \setuplinenumbering[typing][distance=.5em] \setuptyping [numbering=line, before={\startframedtext[width=\textwidth]}, after={\stopframedtext}] \getexample \stop 不幸的是,目前 \CONTEXT\ 仅实现了 \TEX,\METAPOST,Lua,XML 等代码的着色。 \section{逃逸区} 倘若你不嫌麻烦,利用 \type{\type} 和 \type{typing} 环境的逃逸(Escape)机制,即 \type{/BTEX.../ETEX}\index[BTEX]{\type{/BTEX ... /ETEX}},也能实现代码着色。例如 \startTEX[escape=no] \starttyping[escape=yes] /BTEX\darkgreen \#include/ETEX /BTEX\darkblue int/ETEX main(/BTEX\darkblue void/ETEX) { printf("/BTEX\darkred Hello world!\n/ETEX"); /BTEX\darkblue return/ETEX 0; } \stoptyping \stopTEX \setupinterlinespace[line=3.75ex] \start \setuptyping [before={\startframedtext[width=\textwidth]}, after={\stopframedtext}] \starttyping[escape=yes] /BTEX\darkgreen \#include/ETEX /BTEX\darkblue int/ETEX main(/BTEX\darkblue void/ETEX) { printf("/BTEX\darkred Hello world!\n/ETEX"); /BTEX\darkblue return/ETEX 0; } \stoptyping \stop \noindent \type{/BTEX.../ETEX} 能够在抄录区域构造局部的 \TEX\ 环境,从而允许你用一些 \CONTEXT\ 排版命令制作一些特殊效果,这些命令不会被当成源码显示。 上述示例基于 \TEX\ 逃逸区实现的代码着色胜在简单,失于繁琐,不过如果你熟悉某种编程语言,诸如 Python,Lua 或者 Awk 之类的脚本语言,你可以编写程序,自动生成这类着色代码,然后将其插入到文档里。 我应该一直都没有告诉你,如何给文字着色\index[yanse]{颜色}。\CONTEXT\ 预定义了一些标准颜色,可直接使用这些颜色的名字对文字进行着色,例如\boxquote{\type{{\magenta 紫色}}},结果为\boxquote{\magenta 紫色},也可以使用 \type{\color} 命令,例如\boxquote{\type{\color[lightmagenta]{浅紫色}}},结果为\boxquote{\color[lightmagenta]{浅紫色}}。以下代码可用于查看 \CONTEXT\ 预定义颜色, \starttyping[option=TEX] \startTEXpage[offset=4pt] \showcolor[rgb] \stopTEXpage \stoptyping \noindent 使用 \type{\definecolor}\index[definecolor]{\tex{definecolor}} 可以通过设定红(r)、绿(g)、蓝(b)分量定义颜色。例如 \startexample \definecolor[myred][r=.8,g=.2,b=.2] \framed{\myred 给你点 color see see!} \stopexample \simpleexample[option=TEX]{\getexample} \noindent 上例可以让你顺便学会另一种给文字增加外框的方法。也可以用 \type{\colored}\index[colored]{\tex{colored}} 直接设定 rgb 颜色对文字着色,以下代码与上例等效: \startTEX \framed{\colored[r=.8,g=.2,b=.2]{给你点 color see see!}} \stopTEX \section{显示空格} \CONTEXT\ 中文断行需要 \type{\setscript[hanzi]},但该命令会吞噬汉字之间的空白字符,从而导致一个问题,在 \type{\type} 和 \type{typing} 环境中,汉字之间若存在空白字符,它们不会被输出到排版结果,此时,只有 \type{space=on} 可以救急。 下例是 \type{typing} 环境未开启空格显示的效果。 \startexample \starttyping 本 行 每 个 汉 字 之 后 都 有 空 格, 但 是 你 看 不 见 它, 除 非 space=on ! \stoptyping \stopexample \simpleexample[option=TEX]{\null} \getexample \noindent 作为比较,下例是开启了空格显示的效果。 \startTEX \starttyping[space=on] 本 行 每 个 汉 字 之 后 都 有 空 格, 你 能 看 见 它 。 \stoptyping \stopTEX \starttyping[space=on] 本 行 每 个 汉 字 之 后 都 有 空 格, 你 能 看 见 它 。 \stoptyping \section{样式设定} \tex{setuptype}\index[setuptype]{\tex{setuptype}} 和 \tex{setuptyping}\index[setuptyping]{\tex{setuptyping}} 可分别用于设置行内和行间抄录环境的样式。例如将行内抄录的颜色设为深红色,并打开空格显示: \startTEX \setuptype[color=darkred,space=on] \stopTEX 下例可将行间抄录的字号设为比正文字号小一号,并且前后留白各半行距离,且开启 \TEX\ 逃逸。注意,\tex{tt} 是等宽字体切换命令,希望你还没有忘记 \in[fontfamily] 节所讲的那些字体切换命令。 \startTEX \setuptyping[style=\tfx\tt, before={\blank[halfline]}, after={\blank[halfline]} escape=yes] \stopTEX 使用 \type{\definetype}\index[definetype]{\tex{definetype}} 和 \type{\definetyping}\index[definetyping]{\tex{definetyping}} 可以定义专用的抄录环境,见下例。 \starttyping[option=TEX] \definetyping[foo][escape=yes,space=on,option=TEX] \startfoo Hello /BTEX\darkred\CONTEXT/ETEX! \stopfoo \stoptyping \tex{setuptype} 和 \tex{setuptyping} 也能用于设定自定义的抄录环境,但是需要提供环境名,例如: \starttyping[option=TEX] \setuptyping[foo][style=\tt\tfx] \stoptyping \subject{小结} 抄录环境还有许多功能,本文未予介绍,可以阅读文档 \cite[typing] 获得更全面的认识。 面向印刷行业的抄录环境本身并不复杂,只是若是排版面向屏幕阅读的电子文档,代码着色能够更为直观地呈现代码结构,而 \CONTEXT\ 在这方面存在很大欠缺。虽然它提供了扩展机制,但目前只能通过一些示例代码\cite[verb-luatex]去理解这该套机制。如果你要自行尝试为某种编程语言的代码编写着色器,不仅需要熟悉 Lua 语言,还需要熟悉 LPEG 库的用法。如果你对这个主题感兴趣,可以参考我所作的一些尝试\cite[lpeg,code-render]。