查看源代码 prettypr (syntax_tools v3.2.1)

一个通用的美化打印库。

此模块使用 John Hughes 算法的严格样式上下文传递实现,该算法在“美化打印库的设计”中进行了描述。段落样式格式化、空文档、浮动文档和空字符串是我对该算法的补充。

要开始使用,您应该阅读有关 document() 数据类型的信息;主要构造函数:text/1above/2beside/2nest/2sep/1par/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)

以段落式布局排列文档。

水平或垂直排列文档,用空格分隔。

产生一个表示固定、不可破坏的字符序列的文档。

产生一个表示段落格式纯文本的文档。

类型

链接到此类型

deep_string()

查看源代码 (未导出)
-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)。

可以使用此模块的构造函数将文档连接成单个新文档。请注意,新文档通常表示比组件的总和更多可能的布局。

函数

-spec above(document(), document()) -> #above{d1 :: document(), d2 :: document()}.

垂直连接文档。

返回一个文档,表示文档 D1D2 的串联,使得 D2 的第一行直接位于 D1 的最后一行下方,并且在所有可能的布局中,D2 的第一个字符与 D1 的第一个字符位于同一水平列中。

示例

ab  cd  =>  ab
            cd

               abc
abc   fgh  =>   de
 de    ij      fgh
                ij
-spec beside(document(), document()) -> #beside{d1 :: document(), d2 :: document()}.

水平连接文档。

返回一个文档,表示文档 D1D2 的串联,使得在所有可能的布局中,D1 的最后一个字符与 D2 的第一个字符在水平方向上相邻。(注意:D2 的任何缩进都会丢失。)

示例

ab  cd  =>  abcd

ab  ef      ab
cd  gh  =>  cdef
              gh
-spec best(document(), integer(), integer()) -> empty | document().

为文档选择“最佳”布局,创建相应的固定布局文档。

如果无法生成布局,则返回原子 empty。有关 PaperWidthLineWidth 的详细信息,请参见 format/3。该函数是幂等的。

此函数的一个可能用途是计算文档的固定布局,然后可以将其作为较大文档的一部分包含在内。例如

     above(text("Example:"), nest(8, best(D, W - 12, L - 6)))

D 格式化为缩进 8 的显示文本示例,其右边距相对于周围文档的纸张宽度 W 缩进 4,并且其最大单行长度比周围文档的行长度 L 短 6。

此函数由 format/3 函数使用,以在将文档布局为文本之前对其进行准备。

-spec break(document()) -> #above{d1 :: document(), d2 :: document()}.

强制在给定文档末尾换行。

这是一个实用函数;有关详细信息,请参见 empty/0

-spec empty() -> null.

产生空文档,该文档既没有高度也没有宽度。

(因此,empty 与空的 text 字符串不同,后者具有零宽度但高度为 1。)

空文档有时很有用;特别是,它们具有以下属性:above(X, empty()) 将强制在 X 之后换行,而不在其下方留下空行;由于这是一种常见的习惯用法,因此实用函数 break/1 会将给定文档置于这种上下文中。

另请参阅: text/1

-spec floating(document()) -> #float{d :: document(), h :: integer(), v :: integer()}.

等效于 floating(D, 0, 0)

-spec floating(document(), integer(), integer()) ->
                  #float{d :: document(), h :: integer(), v :: integer()}.

创建一个“浮动”文档。

结果表示与 D 相同的布局集;但是,可以根据浮动文档的相对水平和垂直优先级,相对于紧邻其旁或上方的其他浮动文档移动浮动文档。这些优先级通过 HpVp 参数设置;如果省略,则两者都默认为零。

注意

浮动文档似乎运行良好,但目前不如您希望的那么通用,在嵌入某些上下文时会失去效果。可以嵌套浮动运算符(即使具有不同的优先级),但效果可能难以预测。在任何情况下,请注意,该算法重新排序浮动文档的方式相当于“冒泡排序”,因此不要期望它能够快速排序大量浮动文档序列。

-spec follow(document(), document()) -> #beside{d1 :: document(), d2 :: document()}.

等效于 follow(D1, D2, 0)

-spec follow(document(), document(), integer()) -> #beside{d1 :: document(), d2 :: document()}.

用单个空格或换行符和缩进分隔两个文档。

换句话说,将生成以下布局之一

abc def

abc
 def

在后一种情况下使用可选的偏移量。这对于排版编程语言结构通常很有用。

这是一个实用函数;有关更多详细信息,请参见 par/2

另请参阅: follow/2

-spec format(document()) -> string().

等效于 format(D, 80)

-spec format(document(), integer()) -> string().

等效于 format(D, PaperWidth, 65)

-spec format(document(), integer(), integer()) -> string().

计算文档的布局并返回相应的文本。

有关更多信息,请参见 document()。如果无法选择布局,则会抛出 no_layout

PaperWidth 指定要布局文本的字段的总宽度(以字符位置为单位)。LineWidth 指定在任何单行上打印的文本的所需最大宽度(以字符数为单位),忽略前导和尾随空格。为了产生良好的布局,这些参数需要正确平衡。默认情况下,PaperWidth 为 80,LineWidth 为 65。

另请参阅: best/3

-spec nest(integer(), document()) -> document().

将文档向右缩进多个字符位置。

请注意,N 可以为负数,将文本向左移动,也可以为零,在这种情况下,D 将保持不变返回。

-spec null_text(string()) -> #text{s :: deep_string()}.

类似于 text/1,但结果被视为具有零宽度。

这与字符串的实际长度无关。空文本通常用于标记,该标记应该对实际布局没有影响。

标准示例是将源代码格式化为 HTML,以便放置在 <pre>...</pre> 标记内,并使用诸如 <i><b> 之类的元素来突出显示源代码的某些部分。在这种情况下,当在 HTML 浏览器中查看时,标记不会增加文本的宽度,因此布局引擎应简单地假装标记的宽度为零。

另请参阅: empty/0text/1

-spec par([document()]) -> #sep{ds :: [document()], i :: integer(), p :: boolean()}.

等效于 par(Ds, 0)

-spec par([document()], integer()) -> #sep{ds :: [document()], i :: integer(), p :: boolean()}.

以段落式布局排列文档。

返回一个文档,表示文档(非空)序列 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),其中 D1D2 是两个文档。如果 D1 包含换行符(或者在其他必要情况下),这将会在 D1D2 之间断行,并且可以选择将 D2 进一步缩进 N 个字符位置。实用函数 follow/3 为两个文档 D1D2 以及可选整数 N 创建此上下文。

另请参阅:par/1text_par/2

-spec sep([document()]) -> #sep{ds :: [document()], i :: integer(), p :: boolean()}.

水平或垂直排列文档,用空格分隔。

返回一个文档,表示文档(非空)序列 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/0null_text/1text_par/2

-spec text_par(string()) -> document().

等效于 text_par(Text, 0)

链接到此函数

text_par(Text, Indentation)

查看源代码
-spec text_par(string(), integer()) -> document().

产生一个表示段落格式纯文本的文档。

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/2text/1text_par/1