檢視原始碼 Inspect.Algebra (Elixir v1.16.2)
用於建立和處理代數文件的一組函式。
此模組實作了 Christian Lindig 在 「Strictly Pretty」(2000) 中所描述的功能,並加入了一些小功能,例如支援二進位節點和最大化使用水平空間的斷行模式。
iex> Inspect.Algebra.empty()
:doc_nil
iex> "foo"
"foo"
使用此模組中的函式,我們可以將不同的元素串接在一起並呈現它們
iex> doc = Inspect.Algebra.concat(Inspect.Algebra.empty(), "foo")
iex> Inspect.Algebra.format(doc, 80)
["foo"]
函式 nest/2
、space/2
和 line/2
可協助您將文件組成一個嚴格的結構。不過,當使用 glue/3
和 group/1
等函式時,文件代數才會變得有趣。glue 會在兩個文件之間插入斷行。group 表示必須符合目前行數的文件,否則斷行會呈現為新行。讓我們將兩個文件用斷行黏合在一起,將其分組,然後呈現它
iex> doc = Inspect.Algebra.glue("a", " ", "b")
iex> doc = Inspect.Algebra.group(doc)
iex> Inspect.Algebra.format(doc, 80)
["a", " ", "b"]
請注意,斷行會如實呈現,因為我們尚未達到行數限制。一旦達到,它就會被換行符號取代
iex> doc = Inspect.Algebra.glue(String.duplicate("a", 20), " ", "b")
iex> doc = Inspect.Algebra.group(doc)
iex> Inspect.Algebra.format(doc, 10)
["aaaaaaaaaaaaaaaaaaaa", "\n", "b"]
此模組使用位元組大小來計算剩餘的空間。如果您的文件包含字串,則需要將它們包覆在 string/1
中,然後再依賴 String.length/1
來預先計算文件大小。
最後,此模組也包含與 Elixir 相關的函式,有點類似 Elixir 格式,例如 to_doc/2
。
實作詳細資料
實作 Inspect.Algebra
的基礎是 Lindig 的 Strictly Pretty 論文,該論文建立在先前的漂亮列印演算法之上,但針對嚴格語言(例如 Elixir)進行調整。論文中的核心概念是使用明確的文件群組,這些群組會呈現為平面(斷行為空白)或斷行(斷行為換行符號)。
此實作提供了兩種斷行::strict
和 :flex
。當群組不符合時,所有嚴格斷行都會視為換行符號。不過,彈性斷行會在每次出現時重新評估,且仍可能呈現為平面。請參閱 break/1
和 flex_break/1
以取得更多資訊。
此實作也新增了 force_unfit/1
和 next_break_fits/2
,它們提供了對文件調整的更多控制。
摘要
函數
根據給定的 string
,傳回一個斷行文件。
壓縮此節點之後的所有換行符號和空白,最多發出 max
個換行符號。
如果 color_key
在選項中具有顏色,則為文件上色。
串接文件清單,傳回新文件。
串接兩個文件實體,傳回新文件。
根據限制和內容,將 collection
包裝在 left
和 right
中。
傳回用於表示空值的文檔實體。
根據給定的 string
,傳回一個彈性斷行文件。
將兩個文件 (doc1
和 doc2
) 粘合在一起,在它們之間插入 break_string
給出的 flex_break/1
。
使用給定的資料夾函數,將文件清單折疊成文件。
強制目前的群組不適合。
根據給定的寬度,格式化給定的文件。
將兩個文件 (doc1
和 doc2
) 粘合在一起,在它們之間插入給定的斷行 break_string
。
傳回包含指定文件 doc
的群組。
強制換行。
在兩個文件之間插入強制換行。
在給定的 level
中,巢狀給定的文件。
將下一個斷行視為適合。
在兩個文件之間插入強制單一空格。
建立由字串表示的文件。
根據 Inspect
協定,將 Elixir 詞彙轉換為代數文件。
防護
類型
函數
@spec break(binary()) :: doc_break()
根據給定的 string
,傳回一個斷行文件。
此換行可以視為換行符號或給定的 字串
,具體視所選佈局的 模式
而定。
範例
讓我們透過串接兩個字串並在它們之間換行來建立文件
iex> doc = Inspect.Algebra.concat(["a", Inspect.Algebra.break("\t"), "b"])
iex> Inspect.Algebra.format(doc, 80)
["a", "\t", "b"]
請注意,換行以給定的字串表示,因為我們尚未達到換行限制。一旦達到換行限制,就會以新行取代
iex> break = Inspect.Algebra.break("\t")
iex> doc = Inspect.Algebra.concat([String.duplicate("a", 20), break, "b"])
iex> doc = Inspect.Algebra.group(doc)
iex> Inspect.Algebra.format(doc, 10)
["aaaaaaaaaaaaaaaaaaaa", "\n", "b"]
@spec collapse_lines(pos_integer()) :: doc_collapse()
壓縮此節點之後的所有換行符號和空白,最多發出 max
個換行符號。
@spec color(t(), Inspect.Opts.color_key(), Inspect.Opts.t()) :: t()
如果 color_key
在選項中具有顏色,則為文件上色。
串接文件清單,傳回新文件。
範例
iex> doc = Inspect.Algebra.concat(["a", "b", "c"])
iex> Inspect.Algebra.format(doc, 80)
["a", "b", "c"]
串接兩個文件實體,傳回新文件。
範例
iex> doc = Inspect.Algebra.concat("hello", "world")
iex> Inspect.Algebra.format(doc, 80)
["hello", "world"]
@spec container_doc( t(), [any()], t(), Inspect.Opts.t(), (term(), Inspect.Opts.t() -> t()), keyword() ) :: t()
根據限制和內容,將 collection
包裝在 left
和 right
中。
它使用給定的 left
和 right
文件作為外圍,並使用分隔文件 separator
來分隔 docs
中的項目。如果集合中的所有項目都是簡單文件(文字或字串),則此函數會嘗試盡可能將它們放在同一行上。如果它們不是簡單文件,則每行只會顯示一個項目(如果它們不符合)。
會遵循給定 inspect_opts
中的限制,並且在達到限制時,此函數會停止處理並輸出 "..."
。
選項
:separator
- 每一份文件之間使用的分隔符號:break
- 如果為:strict
,則在每個元素之間始終換行。如果為:flex
,則只在必要時換行。如果為:maybe
,則僅在所有元素都基於文字時選擇:flex
,否則為:strict
範例
iex> inspect_opts = %Inspect.Opts{limit: :infinity}
iex> fun = fn i, _opts -> to_string(i) end
iex> doc = Inspect.Algebra.container_doc("[", Enum.to_list(1..5), "]", inspect_opts, fun)
iex> Inspect.Algebra.format(doc, 5) |> IO.iodata_to_binary()
"[1,\n 2,\n 3,\n 4,\n 5]"
iex> inspect_opts = %Inspect.Opts{limit: 3}
iex> fun = fn i, _opts -> to_string(i) end
iex> doc = Inspect.Algebra.container_doc("[", Enum.to_list(1..5), "]", inspect_opts, fun)
iex> Inspect.Algebra.format(doc, 20) |> IO.iodata_to_binary()
"[1, 2, 3, ...]"
iex> inspect_opts = %Inspect.Opts{limit: 3}
iex> fun = fn i, _opts -> to_string(i) end
iex> opts = [separator: "!"]
iex> doc = Inspect.Algebra.container_doc("[", Enum.to_list(1..5), "]", inspect_opts, fun, opts)
iex> Inspect.Algebra.format(doc, 20) |> IO.iodata_to_binary()
"[1! 2! 3! ...]"
@spec empty() :: :doc_nil
傳回用於表示空值的文檔實體。
範例
iex> Inspect.Algebra.empty()
:doc_nil
@spec flex_break(binary()) :: doc_break()
根據給定的 string
,傳回一個彈性斷行文件。
彈性換行仍會導致群組換行,例如 break/1
,但會在文件呈現時重新評估。
例如,取一個群組文件,表示為 [1, 2, 3]
,其中每個逗號後的空格都是一個換行。當上述文件不適合單行時,所有換行都會啟用,導致文件呈現為
[1,
2,
3]
然而,如果使用彈性換行,則每一個換行在呈現時都會重新評估,因此文件可能會呈現為
[1, 2,
3]
因此得名「彈性」。它們在文件調整時更具彈性。另一方面,它們的成本更高,因為需要重新評估每個換行。
此函式由 container_doc/6
和朋友使用,以取得同一行上的最大項目數。
將兩個文件 (doc1
和 doc2
) 粘合在一起,在它們之間插入 break_string
給出的 flex_break/1
。
此函式由 container_doc/6
和朋友使用,以取得同一行上的最大項目數。
使用給定的資料夾函數,將文件清單折疊成文件。
文件清單「從右邊」折疊;在於此,此函式類似於 List.foldr/3
,但它不預期初始累加器,並使用 docs
的最後元素作為初始累加器。
範例
iex> docs = ["A", "B", "C"]
iex> docs =
...> Inspect.Algebra.fold_doc(docs, fn doc, acc ->
...> Inspect.Algebra.concat([doc, "!", acc])
...> end)
iex> Inspect.Algebra.format(docs, 80)
["A", "!", "B", "!", "C"]
@spec force_unfit(t()) :: doc_force()
強制目前的群組不適合。
@spec format(t(), non_neg_integer() | :infinity) :: iodata()
根據給定的寬度,格式化給定的文件。
取得最大寬度和文件以列印作為其引數,並傳回文件的最佳版面配置的 IO 資料表示法,以符合給定的寬度。
文件開始為平面(沒有換行),直到找到一個群組。
範例
iex> doc = Inspect.Algebra.glue("hello", " ", "world")
iex> doc = Inspect.Algebra.group(doc)
iex> doc |> Inspect.Algebra.format(30) |> IO.iodata_to_binary()
"hello world"
iex> doc |> Inspect.Algebra.format(10) |> IO.iodata_to_binary()
"hello\nworld"
將兩個文件 (doc1
和 doc2
) 粘合在一起,在它們之間插入給定的斷行 break_string
。
有關如何插入換行的更多資訊,請參閱 break/1
。
範例
iex> doc = Inspect.Algebra.glue("hello", "world")
iex> Inspect.Algebra.format(doc, 80)
["hello", " ", "world"]
iex> doc = Inspect.Algebra.glue("hello", "\t", "world")
iex> Inspect.Algebra.format(doc, 80)
["hello", "\t", "world"]
@spec group(t(), :self | :inherit) :: doc_group()
傳回包含指定文件 doc
的群組。
群組中的文件會盡可能地一起呈現,以發揮呈現器的最佳能力。
群組模式也可以設定為 :inherit
,這表示如果父群組也已換行,它會自動換行。
範例
iex> doc =
...> Inspect.Algebra.group(
...> Inspect.Algebra.concat(
...> Inspect.Algebra.group(
...> Inspect.Algebra.concat(
...> "Hello,",
...> Inspect.Algebra.concat(
...> Inspect.Algebra.break(),
...> "A"
...> )
...> )
...> ),
...> Inspect.Algebra.concat(
...> Inspect.Algebra.break(),
...> "B"
...> )
...> )
...> )
iex> Inspect.Algebra.format(doc, 80)
["Hello,", " ", "A", " ", "B"]
iex> Inspect.Algebra.format(doc, 6)
["Hello,", "\n", "A", "\n", "B"]
@spec line() :: t()
強制換行。
如果群組中的所有列都符合,則包含換行符號的群組將符合。
範例
iex> doc =
...> Inspect.Algebra.concat(
...> Inspect.Algebra.concat(
...> "Hughes",
...> Inspect.Algebra.line()
...> ),
...> "Wadler"
...> )
iex> Inspect.Algebra.format(doc, 80)
["Hughes", "\n", "Wadler"]
在兩個文件之間插入強制換行。
請參閱 line/0
。
範例
iex> doc = Inspect.Algebra.line("Hughes", "Wadler")
iex> Inspect.Algebra.format(doc, 80)
["Hughes", "\n", "Wadler"]
@spec nest(t(), non_neg_integer() | :cursor | :reset, :always | :break) :: doc_nest() | t()
在給定的 level
中,巢狀給定的文件。
如果 level
是整數,則為每當發生換行符號時附加的縮排。如果層級是 :cursor
,則文件中的「游標」目前位置會成為巢狀結構。如果層級是 :reset
,則會重設為 0。
mode
可以是 :always
,表示巢狀結構總是會發生,或 :break
,表示巢狀結構只會發生在已中斷的群組內。
範例
iex> doc = Inspect.Algebra.nest(Inspect.Algebra.glue("hello", "world"), 5)
iex> doc = Inspect.Algebra.group(doc)
iex> Inspect.Algebra.format(doc, 5)
["hello", "\n ", "world"]
@spec next_break_fits(t(), :enabled | :disabled) :: doc_fits()
將下一個斷行視為適合。
mode
可以是 :enabled
或 :disabled
。當為 :enabled
時,它會在找到下一個中斷後立即將文件視為符合,有效地取消中斷。它也會忽略在尋找下一個中斷時出現的任何 force_unfit/1
。
當停用時,它會像平常一樣運作,並且會忽略任何後續 next_break_fits/2
指令。
範例
Elixir 的程式碼格式化器會使用此功能,以避免在某些特定位置中斷程式碼。例如,考慮以下程式碼
some_function_call(%{..., key: value, ...})
現在假設這段程式碼不符合其列。程式碼格式化器會在 (
和 )
內以及在 %{
和 }
內加入中斷。因此,文件會中斷如下
some_function_call(
%{
...,
key: value,
...
}
)
格式化器會將表示映射的代數文件包裝在 next_break_fits/1
中,因此程式碼會格式化如下
some_function_call(%{
...,
key: value,
...
})
在兩個文件之間插入強制單一空格。
範例
iex> doc = Inspect.Algebra.space("Hughes", "Wadler")
iex> Inspect.Algebra.format(doc, 5)
["Hughes", " ", "Wadler"]
@spec string(String.t()) :: doc_string()
建立由字串表示的文件。
雖然 Inspect.Algebra
接受二進位資料作為文件,但會根據二進位資料大小進行計算。另一方面,string
文件會根據文件大小中的字元數進行衡量。
範例
以下文件有 10 個位元組,因此在沒有斷行的情況下,無法格式化為寬度 9
iex> doc = Inspect.Algebra.glue("olá", " ", "mundo")
iex> doc = Inspect.Algebra.group(doc)
iex> Inspect.Algebra.format(doc, 9)
["olá", "\n", "mundo"]
但是,如果我們使用 string
,則會使用字串長度,而不是位元組大小,正確地符合
iex> string = Inspect.Algebra.string("olá")
iex> doc = Inspect.Algebra.glue(string, " ", "mundo")
iex> doc = Inspect.Algebra.group(doc)
iex> Inspect.Algebra.format(doc, 9)
["olá", " ", "mundo"]
@spec to_doc(any(), Inspect.Opts.t()) :: t()
根據 Inspect
協定,將 Elixir 詞彙轉換為代數文件。