查看源代码 prettypr (syntax_tools v3.2.1)
一个通用的美化打印库。
此模块使用 John Hughes 算法的严格样式上下文传递实现,该算法在“美化打印库的设计”中进行了描述。段落样式格式化、空文档、浮动文档和空字符串是我对该算法的补充。
要开始使用,您应该阅读有关 document()
数据类型的信息;主要构造函数:text/1
,above/2
,beside/2
,nest/2
,sep/1
和 par/2
;以及主要布局函数 format/3
。
如果您只是想格式化一段纯文本,您可能需要使用 text_par/2
函数,如下例所示
prettypr:format(prettypr:text_par("Lorem ipsum dolor sit amet"), 20)
摘要
函数
垂直连接文档。
水平连接文档。
为文档选择“最佳”布局,创建相应的固定布局文档。
强制在给定文档末尾换行。
产生空文档,该文档既没有高度也没有宽度。
创建一个“浮动”文档。
用单个空格或换行符和缩进分隔两个文档。
等效于 format(D, 80)
。
计算文档的布局并返回相应的文本。
将文档向右缩进多个字符位置。
类似于 text/1
,但结果被视为具有零宽度。
等效于 par(Ds, 0)
。
以段落式布局排列文档。
水平或垂直排列文档,用空格分隔。
产生一个表示固定、不可破坏的字符序列的文档。
产生一个表示段落格式纯文本的文档。
类型
-type deep_string() :: [char() | deep_string()].
-type document() :: null | #text{s :: deep_string()} | #nest{n :: integer(), d :: document()} | #beside{d1 :: document(), d2 :: document()} | #above{d1 :: document(), d2 :: document()} | #sep{ds :: [document()], i :: integer(), p :: boolean()} | #float{d :: document(), h :: integer(), v :: integer()} | #union{d1 :: document(), d2 :: document()} | #fit{d :: document()}.
一个抽象的基于字符的“文档”,表示许多可能的布局,可以对其进行处理以生成单个具体的布局。
然后可以将具体的布局呈现为包含换行符的字符序列,该序列可以传递给使用固定宽度字体的打印机或终端。
例如,文档 sep([text("foo"), text("bar")])
表示两种布局
foo bar
和
foo
bar
选择哪个布局取决于可用的水平空间。处理文档时,主要参数是纸张宽度和行宽(也称为“带状宽度”)。在生成的布局中,只要可以避免,就不应在纸张宽度(默认情况下为 80 个字符)之外打印任何文本,并且每行文本(不计其缩进,因此称为“带状”)的宽度最好不超过指定的行宽(默认情况下为 65)。
可以使用此模块的构造函数将文档连接成单个新文档。请注意,新文档通常表示比组件的总和更多可能的布局。
函数
垂直连接文档。
返回一个文档,表示文档 D1
和 D2
的串联,使得 D2
的第一行直接位于 D1
的最后一行下方,并且在所有可能的布局中,D2
的第一个字符与 D1
的第一个字符位于同一水平列中。
示例
ab cd => ab
cd
abc
abc fgh => de
de ij fgh
ij
水平连接文档。
返回一个文档,表示文档 D1
和 D2
的串联,使得在所有可能的布局中,D1
的最后一个字符与 D2
的第一个字符在水平方向上相邻。(注意:D2
的任何缩进都会丢失。)
示例
ab cd => abcd
ab ef ab
cd gh => cdef
gh
为文档选择“最佳”布局,创建相应的固定布局文档。
如果无法生成布局,则返回原子 empty
。有关 PaperWidth
和 LineWidth
的详细信息,请参见 format/3
。该函数是幂等的。
此函数的一个可能用途是计算文档的固定布局,然后可以将其作为较大文档的一部分包含在内。例如
above(text("Example:"), nest(8, best(D, W - 12, L - 6)))
将 D
格式化为缩进 8 的显示文本示例,其右边距相对于周围文档的纸张宽度 W
缩进 4,并且其最大单行长度比周围文档的行长度 L
短 6。
此函数由 format/3
函数使用,以在将文档布局为文本之前对其进行准备。
强制在给定文档末尾换行。
这是一个实用函数;有关详细信息,请参见 empty/0
。
-spec empty() -> null.
产生空文档,该文档既没有高度也没有宽度。
(因此,empty
与空的 text
字符串不同,后者具有零宽度但高度为 1。)
空文档有时很有用;特别是,它们具有以下属性:above(X, empty())
将强制在 X
之后换行,而不在其下方留下空行;由于这是一种常见的习惯用法,因此实用函数 break/1
会将给定文档置于这种上下文中。
另请参阅: text/1
。
等效于 floating(D, 0, 0)
。
-spec floating(document(), integer(), integer()) -> #float{d :: document(), h :: integer(), v :: integer()}.
创建一个“浮动”文档。
结果表示与 D
相同的布局集;但是,可以根据浮动文档的相对水平和垂直优先级,相对于紧邻其旁或上方的其他浮动文档移动浮动文档。这些优先级通过 Hp
和 Vp
参数设置;如果省略,则两者都默认为零。
注意
浮动文档似乎运行良好,但目前不如您希望的那么通用,在嵌入某些上下文时会失去效果。可以嵌套浮动运算符(即使具有不同的优先级),但效果可能难以预测。在任何情况下,请注意,该算法重新排序浮动文档的方式相当于“冒泡排序”,因此不要期望它能够快速排序大量浮动文档序列。
等效于 follow(D1, D2, 0)
。
用单个空格或换行符和缩进分隔两个文档。
换句话说,将生成以下布局之一
abc def
或
abc
def
在后一种情况下使用可选的偏移量。这对于排版编程语言结构通常很有用。
这是一个实用函数;有关更多详细信息,请参见 par/2
。
另请参阅: follow/2
。
等效于 format(D, 80)
。
计算文档的布局并返回相应的文本。
有关更多信息,请参见 document()
。如果无法选择布局,则会抛出 no_layout
。
PaperWidth
指定要布局文本的字段的总宽度(以字符位置为单位)。LineWidth
指定在任何单行上打印的文本的所需最大宽度(以字符数为单位),忽略前导和尾随空格。为了产生良好的布局,这些参数需要正确平衡。默认情况下,PaperWidth
为 80,LineWidth
为 65。
另请参阅: best/3
。
将文档向右缩进多个字符位置。
请注意,N
可以为负数,将文本向左移动,也可以为零,在这种情况下,D
将保持不变返回。
-spec null_text(string()) -> #text{s :: deep_string()}.
类似于 text/1
,但结果被视为具有零宽度。
这与字符串的实际长度无关。空文本通常用于标记,该标记应该对实际布局没有影响。
标准示例是将源代码格式化为 HTML,以便放置在 <pre>...</pre>
标记内,并使用诸如 <i>
和 <b>
之类的元素来突出显示源代码的某些部分。在这种情况下,当在 HTML 浏览器中查看时,标记不会增加文本的宽度,因此布局引擎应简单地假装标记的宽度为零。
等效于 par(Ds, 0)
。
以段落式布局排列文档。
返回一个文档,表示文档(非空)序列 Docs
的所有可能的左对齐段落式布局。Docs
中的元素在水平方向上以单个空格字符分隔,在垂直方向上以单个换行符分隔。所有后续行(如果有)都缩进到相同的左列,其缩进由可选的 Offset
参数相对于 Docs
中第一个元素的位置指定。例如,当偏移量为 -4 时,可以生成以下布局,用于表示数字 0 到 15 的文档列表
0 1 2 3
4 5 6 7 8 9
10 11 12 13
14 15
或者偏移量为 +2
0 1 2 3 4 5 6
7 8 9 10 11
12 13 14 15
实用函数 text_par/2
可以通过将文本字符串拆分成单词,轻松地将其转换为 par
表示形式。
请注意,每当 Docs
中的文档包含换行符时,它都会被放置在单独的行上。因此,既不会生成类似
ab cd
ef
也不会生成
ab
cd ef
但是,使前一种变体成为可能(在需要时)的一个有用习惯用法是 beside(par([D1, text("")], N), D2)
,其中 D1
和 D2
是两个文档。如果 D1
包含换行符(或者在其他必要情况下),这将会在 D1
和 D2
之间断行,并且可以选择将 D2
进一步缩进 N
个字符位置。实用函数 follow/3
为两个文档 D1
和 D2
以及可选整数 N
创建此上下文。
另请参阅:par/1
、text_par/2
。
水平或垂直排列文档,用空格分隔。
返回一个文档,表示文档(非空)序列 Docs
的两种备选布局,使得要么 Docs
中的所有元素水平连接,并以空格字符分隔,要么所有元素垂直连接(不额外分隔)。
注意
如果
Docs
中的某个文档包含换行符,则始终会选择垂直布局。
示例
ab
ab cd ef => ab cd ef | cd
ef
ab ab
cd ef => cd
ef
另请参阅:par/2
。
-spec text(string()) -> #text{s :: deep_string()}.
产生一个表示固定、不可破坏的字符序列的文档。
该字符串应仅包含可打印字符(允许制表符但不建议使用),并且不包含换行符、换行、垂直制表符等。制表符 (\t
) 被解释为在字符串内填充 1-8 个空格字符到下一个 8 个字符的列。
另请参阅:empty/0
、null_text/1
、text_par/2
。
等效于 text_par(Text, 0)
。
产生一个表示段落格式纯文本的文档。
Indentation
参数指定段落第一行的额外缩进。例如,text_par("Lorem ipsum dolor sit amet", N)
可能表示
Lorem ipsum dolor
sit amet
如果 N = 0,或者
Lorem ipsum
dolor sit amet
如果 N
= 2,或者
Lorem ipsum dolor
sit amet
如果 N
= -2。
(与 par/2
函数相比,缩进的符号因此被反转,并且行为会根据符号略有不同,以便与文本段落的预期布局匹配。)
请注意,这只是一个实用函数,它完成了将给定字符串拆分为以空格分隔的单词的所有工作,并使用适当的缩进设置 par
,其中包含 text
元素的列表。
另请参阅:par/2
、text/1
、text_par/1
。