\chapter{一字不差}

在现在这个时代，文档出现一些计算机程序代码片段，是很常见的事。通常建议用等宽字体呈现这些代码且原样显示，像是过去打字机的输出结果，这种排版元素在西文里称为 Verbatim text，我将其译为「抄录」。

\section{抄录}

抄录有两种形式，一种是位于一行文字之内，用 \type{\type{...}} 排版\index[type]{\tex{type}}，另一种是位于段落之间的 \type{typing} 环境\index[typing]{\type{typing} 环境}。例如

\startexample
\startframedtext[width=broad]
用 C 语言写一个程序，让它在屏幕上显示「\type{Hello world!}」，代码如下
\starttyping
#include <stdio.h>
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 <stdio.h>
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

\noindent 不幸的是，目前 \CONTEXT\ 仅实现了 \TEX，\METAPOST，Lua，XML 等代码的着色。

\section{逃逸区}

利用 \type{\type} 和 \type{typing} 环境的逃逸（Escape）机制，也能实现代码着色。例如

\startTEX[escape=no]
\starttyping[escape=yes]
/BTEX\darkgreen \#include/ETEX <stdio.h>
/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 <stdio.h>
/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\ 预定义了一些标准颜色，可直接使用这些颜色的名字对文字进行着色，例如「\type{{\magenta 紫色}}」，结果为「{\magenta 紫色}」，也可以使用 \type{\color} 命令，例如「\type{\color[lightmagenta]{浅紫色}}」，结果为「\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} 环境未开启空格显示的效果。

\startTEX
\starttyping
本/BTEX\,/ETEX行/BTEX\,/ETEX每/BTEX\,/ETEX个/BTEX\,/ETEX汉/BTEX\,/ETEX字/BTEX\,/ETEX之/BTEX\,/ETEX后/BTEX\,/ETEX都/BTEX\,/ETEX有/BTEX\,/ETEX空/BTEX\,/ETEX格，/BTEX\,/ETEX但/BTEX\,/ETEX是/BTEX\,/ETEX你/BTEX\,/ETEX看/BTEX\,/ETEX不/BTEX\,/ETEX见/BTEX\,/ETEX它，/BTEX\,/ETEX除/BTEX\,/ETEX非/BTEX\,/ETEXspace=on！
\stoptyping
\stopTEX
\starttyping
本 行 每 个 汉 字 之 后 都 有 空 格， 但 是 你 看 不 见 它， 除 非 space=on！
\stoptyping

\noindent 作为比较，下例是开启了空格显示的效果。

\startTEX
\starttyping[space=on]
本/BTEX\,/ETEX行/BTEX\,/ETEX每/BTEX\,/ETEX个/BTEX\,/ETEX汉/BTEX\,/ETEX字/BTEX\,/ETEX之/BTEX\,/ETEX后/BTEX\,/ETEX都/BTEX\,/ETEX有/BTEX\,/ETEX空/BTEX\,/ETEX格，/BTEX\,/ETEX你/BTEX\,/ETEX能/BTEX\,/ETEX看/BTEX\,/ETEX见/BTEX\,/ETEX它/BTEX\,/ETEX。
\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]。
