///|
pub using @align {type Alignment}
///|
pub using @wrap {
type Line,
type BreakKind,
type WrapAlgorithm,
type BreakPolicy,
type OptimalOptions,
}
///|
/// Logical paragraph layout configuration. Optional integrations live in their own package.
pub(all) struct LayoutStyle {
max_width : Int
alignment : Alignment
ambiguous_wide : Bool
wrap_algorithm : WrapAlgorithm
break_policy : BreakPolicy
tab_width : Int
optimal : OptimalOptions
} derive(Eq, Debug)
///|
pub extend LayoutStyle with Eq::{not_equal, equal}
///|
pub extend LayoutStyle with Debug::{to_repr}
///|
/// Construct a layout style (greedy by default). Nonpositive widths normalize to one column.
pub fn LayoutStyle::new(
max_width : Int,
alignment? : Alignment = Left,
ambiguous_wide? : Bool = false,
wrap_algorithm? : WrapAlgorithm = Greedy,
break_policy? : BreakPolicy = Unicode,
tab_width? : Int = 4,
optimal? : OptimalOptions = OptimalOptions::new(),
) -> LayoutStyle {
{
max_width,
alignment,
ambiguous_wide,
wrap_algorithm,
break_policy,
tab_width,
optimal,
}
}
///|
/// Layout a logical paragraph into lines with source ranges and aligned text.
pub fn layout(text : String, style : LayoutStyle) -> Array[Line] {
let opts = @wrap.WrapOptions::new(
ambiguous_wide=style.ambiguous_wide,
break_policy=style.break_policy,
tab_width=style.tab_width,
)
let lines = match style.wrap_algorithm {
Greedy => @wrap.wrap(text, style.max_width, opts~)
Optimal =>
@wrap.optimal_wrap(text, style.max_width, opts~, optimal=style.optimal)
}
finish(lines, style)
}
///|
fn finish(lines : Array[Line], style : LayoutStyle) -> Array[Line] {
let width = if style.max_width > 0 { style.max_width } else { 1 }
let aligned = @align.align_lines(lines, width, style.alignment)
lines.mapi(fn(i, line) {
{
..line,
aligned_text: aligned[i],
width: @wrap.display_width(
aligned[i],
ambiguous_wide=style.ambiguous_wide,
),
}
})
}
///|
/// Layout with a caller-owned hyphenator. Reuse a compiled Liang trie between calls.
pub fn[H : @hyphen.Hyphenator] layout_hyphenated(
text : String,
style : LayoutStyle,
hyphenator : H,
) -> Array[Line] {
let opts = @wrap.WrapOptions::new(
ambiguous_wide=style.ambiguous_wide,
break_policy=style.break_policy,
tab_width=style.tab_width,
)
finish(
@wrap.wrap_hyphenated(
text,
style.max_width,
hyphenator,
algorithm=style.wrap_algorithm,
opts~,
optimal=style.optimal,
),
style,
)
}