\chapter{一字不差}

在这个信息时代,文档出现一些计算机程序源码片段,是很常见的事。这些代码需要以等宽字体原样显示,像是过去的打字机的输出,故而名曰文本抄录(Verbatim text)。为了让代码更为易读,通常需要根据相应语法对其进行着色渲染。有时,还需要在代码中插入一些其他排版元素。

\section{抄录}

抄录有两种形式,一种是位于一行文字之内,用 \type{\type{...}} 排版,另一种是位于段落之间,用 \type{\starttyping ... \stoptyping} 排版。例如

\startsample
\startframedtext[width=\textwidth]
用 C 语言写一个程序,让它在屏幕上显示「\type{Hello world!}」,代码如下
\starttyping
#include <stdio.h>
int main(void)
{
   printf("Hello world!\n");
   return 0;
}
\stoptyping
\stopframedtext
\stopsample
\typesample

\noindent 结果为

\start
\setuptyping[before={\blank[line]},after={\blank[line]}]
\getsample
\stop

上述示例,不仅演示了抄录命令的基本用法,你应该也学会了如何使用 \type{framedtext} 环境给一些内容添加朴素的边框。

\section{外框}

也许你也想要一个像本文档中有着巨大的淡蓝色方括号的 \type{typing} 环境,但是需要事先对第 \in[metapost] 章中介绍的 \METAPOST\ 语言的基本用法有所了解方可。给 \type{typing} 环境添加朴素的外框很容易做到,而且它也是实现巨大淡蓝色方括号的基础,方法是

\startsample
\setuptyping
 [before={\startframedtext[width=\textwidth]},
  after={\stopframedtext}]

\starttyping
带外框的 \starttyping ... \stoptyping
\stoptyping
\stopsample
\typesample
\start
\getsample
\stop

在 \type{\setuptyping} 的 \type{before} 和 \type{after} 参数中,也可以根据自己的需求,添加其他排版命令或你自己定义的宏。\CONTEXT\ 很多命令带有 \type{before} 和 \type{after} 参数。

\section{行号}

\type{\setuptyping} 的 \type{line} 参数可用于设定代码行号。通过 \type{\setuplinenumbering} 可调整行号样式。以下示例开启代码行号,并将行号到 \type{typing} 环境的距离设为 0.5 em:

\startsample
\setuplinenumbering[typing][distance=.5em]
\setuptyping
 [numbering=line,
  before={\startframedtext[width=\textwidth]},
  after={\stopframedtext}]

\starttyping
#include <stdio.h>
int main(void)
{
   printf("Hello world!\n");
   return 0;
}
\stoptyping
\stopsample
\typesample
\start
\getsample
\stop

\section{着色}

\CONTEXT\ 提供了代码语法着色功能,例如对 \TEX\ 代码进行着色,

\startsample
\starttyping[option=TEX]
\starttext
Hello \CONTEXT!
\stoptext
\stoptyping
\stopsample
\typesample
\start
\setuplinenumbering[typing][distance=.5em]
\setuptyping
 [numbering=line,
  before={\startframedtext[width=\textwidth]},
  after={\stopframedtext}]
\getsample
\stop

不幸的是,目前 \CONTEXT\ 仅实现了 \TEX,\METAPOST,Lua,XML 等代码的着色。不过,对于 \CONTEXT\ 尚不支持的语言,\CONTEXT\ 提供了扩展机制,若你对 Lua 语言及其 Lpeg 库有所了解,可自己动手,丰衣足食\cite[code-render]。

\section{逃逸}

即使不懂  Lua 和 Lpeg,倘若你不嫌麻烦,利用 \type{\type} 和 \type{typing} 环境的逃逸(Escape)机制,也能实现代码着色。例如

\starttyping[escape=no,option=TEX]
\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
\stoptyping

\noindent 结果为

\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

我应该一直都没有告诉你,\CONTEXT\ 该如何给文字着色。\CONTEXT\ 预定义了一些标准颜色,可直接使用这些颜色的名字对文字进行着色,例如「\type{{\magenta 紫色}}」,结果为「{\magenta 紫色}」,也可以使用 \type{\color} 命令,例如「\type{\color[lightmagenta]{浅紫色}}」,结果为「\color[lightmagenta]{浅紫色}」。以下代码可用于查看 \CONTEXT\ 预定义颜色,

\starttyping[option=TEX]
\startTEXpage[offset=4pt]
\showcolor[rgb]
\stopTEXpage
\stoptyping

使用 \type{\definecolor} 可以通过设定红(r)、绿(g)、蓝(b)分量定义颜色。例如

\startsample
\definecolor[myred][r=.8,g=.2,b=.2]
\framed{\myred 给你点 color see see!}
\stopsample
\simplesample[option=TEX]{\getsample}

\noindent 上述代码中可以让你你顺便又学会了另一种给文字增加外框的方法。

亦可使用 \type{\colored} 直接设定 rgb 颜色对文字着色,以下代码与上例等效:

\startsample
\framed{\colored[r=.8,g=.2,b=.2]{给你点 color see see!}}
\stopsample
\typesample[option=TEX]

\section{显示空格}

\starttyping[escape=no,option=TEX]
\starttyping[space=on]
H E  L   L    L     O
\stoptyping
\stoptyping
\start
\setuptyping
 [before={\startframedtext[width=\textwidth]},
  after={\stopframedtext}]
\starttyping[space=on]
H E  L   L    L     O
\stoptyping
\stop

注意,\CONTEXT\ 中文断行需要 \type{\setscript[hanzi]},但该命令会吞噬汉字之间的空白字符,从而导致一个问题,在 \type{\type} 和 \type{typing} 环境中,汉字之间若存在空白字符,它们不会被输出到排版结果,此时,只有 \type{space=on} 可以救急。

例如,以下 \type{typing} 环境未开启空格显示:

\starttyping
本 行 每 个 汉 字 之 后 都 有 空 格, 但 是 你 看 不 见 它, 除 非 space=on !
\stoptyping
\noindent 以下 \type{typing} 环境开启了空格显示:
\starttyping[space=on]
本 行 每 个 汉 字 之 后 都 有 空 格, 但 是 你 看 不 见 它, 除 非 space=on !
\stoptyping

\section{定义}

使用 \type{\definetype} 和 \type{\definetyping} 可定义专用的抄录环境。例如

\starttyping[option=TEX]
\starttyping[escape=yes,space=on,option=TEX]
Hello /BTEX\darkred\CONTEXT/ETEX!
\stoptyping
\stoptyping

\noindent 倘若每次使用该 \type{typing} 环境,可能会让你觉得繁琐,且增加了输入出错的风险,采用以下方法可予以简化:

\starttyping[option=TEX]
\definetyping[foo][escape=yes,space=on,option=TEX]
\startfoo
Hello /BTEX\darkred\CONTEXT/ETEX!
\stopfoo
\stoptyping


\section{小结}

五色使人目盲。即使 \CONTEXT\ 的代码着色功能未能支持你的程序代码,也许并不值得遗憾。也许真正值得遗憾的是,它未能激发你对 Lua 语言和 Lpeg 库的兴趣,而这正是 \CONTEXT\ 的代码着色功能支持的编程语言过少最重要的原因。