knit

Start knitting with the new/from functions!

For complexity reasons, formatters are not aware of linebreaks! See split for an example on how to handle multiline Strings.

Except where otherwise noted; for formatters that take a width, the total length of the resulting String will never exceed width.

Types

Internal type for processing Strings more efficiently.

pub opaque type Yarn

Values

pub fn crop_centre(this: Yarn, to width: Int) -> Yarn

Drop characters equally from both sides of a String if it exceeds width.

  • If width is less than 0, it will be clamped to 0.

Examples:

knit.new(knit.crop_centre(_, 5))("hello world") // "lo wo"
pub fn crop_left(this: Yarn, to width: Int) -> Yarn

Drop characters from the left side of a String if it exceeds width.

  • If width is less than 0, it will be clamped to 0.

Examples:

knit.new(knit.crop_left(_, 5))("hello world") // "hello"
pub fn crop_right(this: Yarn, to width: Int) -> Yarn

Drop characters from the right side of a String if it exceeds width.

  • If width is less than 0, it will be clamped to 0.

Examples:

knit.new(knit.crop_right(_, 5))("hello world") // "world"
pub fn digit_separator(
  this: Yarn,
  every interval: Int,
  with separator: String,
) -> Yarn

Add a separator every interval integer digits in a String representing a number.

  • If interval is less than 1, it will default to 3.
  • separator is truncated to the first character.
  • If separator is "", it will default to ",".
  • This function does not check that what it’s processing actually represents a number; this may lead to amusing behavior if used on other Strings.

Examples:

knit.from(int.to_string, knit.digit_separator(_, 3, ","))(1_000_000) // "1,000,000"
knit.from(float.to_string, knit.digit_separator(_, 3, "_"))(1_000.0001) // "1_000.0001"
knit.from(int.to_string, knit.digit_separator(_, 3, "."))(-100_001) // "-100.001"
pub fn ellipsize(
  this: Yarn,
  to width: Int,
  with ellipses: String,
) -> Yarn

Ellipsize the right side of a String with ellipses if the total length exceeds width.

  • If width is less than 0, it will be clamped to 0.
  • If ellipses is "", it will default to "...".
  • ellipses is truncated to width.

Examples:

knit.new(knit.ellipsize(_, 10, "..."))("hello world") // "hello w..."
knit.new(knit.ellipsize(_, 11, "..."))("hello world") // "hello world"
pub fn from(
  from: fn(a) -> String,
  formatter: fn(Yarn) -> Yarn,
) -> fn(a) -> String

Create a new formatter that accepts any type you can convert to a String.

Examples:

let fmt = knit.from(int.to_string, knit.digit_separator(_, 3, " "))
fmt(3_141_592) // "3 141 592"
let normalise = {
  use yarn <- knit.from(fn(a) { a |> float.to_precision(2) |> float.to_string })
  yarn |> knit.pad_right(8, "0")
}

normalise(3.1415926) // "3.140000"
normalise(1000.1) // "1000.100"
pub fn from_string(this: String) -> Yarn

Convert a String into a Yarn.

  • This requires a call to string.length.
pub fn join(this: List(Yarn), with separator: String) -> Yarn

Join Strings by separator.

  • separator is truncated to the first character.
  • If separator is "", it will default to "\n".

Examples:

pub fn length(this: Yarn) -> Int

Get the length of a Yarn.

  • This is a “free” operation, as the length is already tracked.
pub fn margin_centre(
  this: Yarn,
  by amount: Int,
  with fill: String,
) -> Yarn

Pad both sides of a String with fill, adding amount characters total.

  • If amount is less than 0, it will be clamped to 0.
  • fill is truncated to the first character.
  • If fill is "", it will default to " ".

Examples:

knit.new(knit.margin_centre(_, 4, " "))("hello world") // "  hello world  "
pub fn margin_left(
  this: Yarn,
  by amount: Int,
  with fill: String,
) -> Yarn

Pad the left side of a String with fill, amount times.

  • If amount is less than 0, it will be clamped to 0.
  • fill is truncated to the first character.
  • If fill is "", it will default to " ".

Examples:

knit.new(knit.margin_left(_, 4, " "))("hello world") // "    hello world"
pub fn margin_right(
  this: Yarn,
  by amount: Int,
  with fill: String,
) -> Yarn

Pad the right side of a String with fill, amount times.

  • If amount is less than 0, it will be clamped to 0.
  • fill is truncated to the first character.
  • If fill is "", it will default to " ".

Examples:

knit.new(knit.margin_right(_, 4, " "))("hello world") // "hello world    "
pub fn new(formatter: fn(Yarn) -> Yarn) -> fn(String) -> String

Create a new formatter that accepts Strings.

Examples:

let pad = knit.new(knit.pad_centre(_, 15, " "))
pad("hello world") // "  hello world  "
let fmt = {
  use yarn <- knit.new
  yarn |> knit.crop_centre(9) |> knit.pad_centre(9, " ")
}

fmt("hello world") // "ello worl"
fmt("hello") // "  hello  "
pub fn pad_centre(
  this: Yarn,
  to width: Int,
  with fill: String,
) -> Yarn

Pad both sides of a String with fill if it is less than width.

  • The resulting String will be allowed to exceed width.
  • If width is less than 0, it will be clamped to 0.
  • fill is truncated to the first character.
  • If fill is "", it will default to " ".

Examples:

knit.new(knit.pad_centre(_, 15, " "))("hello world") // "  hello world  "
pub fn pad_left(
  this: Yarn,
  to width: Int,
  with fill: String,
) -> Yarn

Pad the left side of a String with fill if it is less than width.

  • The resulting String will be allowed to exceed width.
  • If width is less than 0, it will be clamped to 0.
  • fill is truncated to the first character.
  • If fill is "", it will default to " ".

Examples:

knit.new(knit.pad_left(_, 15, " "))("hello world") // "    hello world"
pub fn pad_right(
  this: Yarn,
  to width: Int,
  with fill: String,
) -> Yarn

Pad the right side of a String with fill if it is less than width.

  • The resulting String will be allowed to exceed width.
  • If width is less than 0, it will be clamped to 0.
  • fill is truncated to the first character.
  • If fill is "", it will default to " ".

Examples:

knit.new(knit.pad_right(_, 15, " "))("hello world") // "hello world    "
pub fn simple_wrap(this: Yarn, to width: Int) -> List(Yarn)

Simply wrap a String onto multiple lines at width.

  • This function is very simplistic and does not wrap at word boundaries or hyphenate. If you’re looking for something fancier, consider the string_width package!

Examples:

knit.new(fn(yarn) { knit.simple_wrap(yarn, 16) |> knit.from_lines })(
  "this is a long sentence that maybe doesn't look so great",
)
this is a long s
entence that may
be doesn't look
so great
pub fn split(this: Yarn, by separator: String) -> List(Yarn)

Split a String by separator.

This function is useful for formatting multiline Strings correctly!

  • separator is truncated to the first character.
  • If separator is "", it will default to "\n".

Examples:

let fmt = {
  use yarn <- knit.new
  yarn
  |> knit.split("\n")
  |> list.map(fn(yarn) {
    knit.pad_centre(yarn, 14, " ") |> knit.margin_centre(2, "|")
  })
  |> knit.join("\n")
}

fmt("line 1\nline 2\nline 3")
|    line 1    |
|    line 2    |
|    line 3    |
pub fn to_string(this: Yarn) -> String

Convert a String into a Yarn.

pub fn with(this: fn(String) -> String) -> fn(Yarn) -> Yarn

Convert any fn(String) -> String into a composable formatter.

  • The formatter returned by this function will always call string.length, take care when calling repeatedly on large inputs.

Examples:

let header = {
  use yarn <- knit.new
  yarn |> knit.with(string.uppercase) |> knit.pad_centre(32, "-")
}

echo header("section header") // "---------SECTION HEADER---------"
let header = {
  let title_case = {
    use string <- knit.with
    string.split(string, " ") |> list.map(string.capitalise) |> string.join(" ")
  }
  use yarn <- knit.new
  title_case(yarn) |> knit.pad_centre(32, " ")
}

echo header("section 2: electric boogaloo") // "  Section 2: Electric Boogaloo  "
pub fn with_arg(
  this: fn(String, a) -> String,
) -> fn(Yarn, a) -> Yarn

Convert any fn(String, a) -> String into a composable formatter.

  • The formatter returned by this function will always call string.length, take care when calling repeatedly on large inputs.
  • If you need to pass more than one argument, try using a tuple!

Examples:

// todo
Search Document