# `Drafter.Draw.Segment`
[🔗](https://github.com/jaman/drafter/blob/main/lib/drafter/draw/segment.ex#L1)

The fundamental rendering unit: a string of text with a single style applied.

A `%Segment{}` stores the text content, a style map, and the pre-computed
display column width (accounting for double-width CJK and emoji codepoints).
Style keys: `:fg` and `:bg` (RGB 3-tuples or color strings normalised to
RGB), `:bold`, `:dim`, `:italic`, `:underline`, `:reverse` (booleans).
Multiple segments are assembled into a `Drafter.Draw.Strip` to form a
single terminal line.

    iex> Drafter.Draw.Segment.new("hi", %{bold: true})
    %Drafter.Draw.Segment{text: "hi", style: %{bold: true}, width: 2}

# `style`

```elixir
@type style() :: %{
  optional(:fg) =&gt; {0..255, 0..255, 0..255},
  optional(:bg) =&gt; {0..255, 0..255, 0..255},
  optional(:fg_alpha) =&gt; float(),
  optional(:bg_alpha) =&gt; float(),
  optional(:bold) =&gt; boolean(),
  optional(:dim) =&gt; boolean(),
  optional(:italic) =&gt; boolean(),
  optional(:underline) =&gt; boolean(),
  optional(:reverse) =&gt; boolean()
}
```

# `t`

```elixir
@type t() :: %Drafter.Draw.Segment{
  style: style(),
  text: String.t(),
  width: non_neg_integer()
}
```

# `alpha_key`

```elixir
@spec alpha_key(:fg | :bg) :: :fg_alpha | :bg_alpha
```

The style key holding the alpha channel for `:fg` or `:bg`.

A translucent colour is stored as two style keys: the RGB triple under `:fg` or
`:bg`, and its alpha, a float in `0.0..1.0`, under the key this returns. A style
with no such key is fully opaque.

Only the compositor reads these keys. It blends the colour against the cell
beneath and removes the alpha key, so a style reaching the ANSI encoders never
carries one.

## Examples

    iex> Drafter.Draw.Segment.alpha_key(:fg)
    :fg_alpha

    iex> Drafter.Draw.Segment.alpha_key(:bg)
    :bg_alpha

# `apply_style`

```elixir
@spec apply_style(t(), style()) :: t()
```

Merge `style` into the segment's own style, `style` winning on shared keys.

Colour values are not normalised; pass RGB triples.

## Examples

    iex> Drafter.Draw.Segment.plain("x") |> Drafter.Draw.Segment.apply_style(%{bold: true})
    %Drafter.Draw.Segment{text: "x", style: %{bold: true}, width: 1}

    iex> segment = Drafter.Draw.Segment.new("x", %{bold: true, italic: true})
    iex> Drafter.Draw.Segment.apply_style(segment, %{bold: false}).style
    %{bold: false, italic: true}

# `crop`

```elixir
@spec crop(t(), non_neg_integer()) :: t()
```

Cut the segment down to `crop_width` display columns.

A segment already that narrow is returned unchanged, and a `crop_width` of zero
or less gives an empty segment. A double-width grapheme that would straddle the
boundary is dropped whole, so the result can be one column narrower than asked.
ANSI SGR sequences in the text are preserved and cost no columns.

## Examples

    iex> Drafter.Draw.Segment.plain("hello") |> Drafter.Draw.Segment.crop(3)
    %Drafter.Draw.Segment{text: "hel", style: %{}, width: 3}

    iex> Drafter.Draw.Segment.plain("hello") |> Drafter.Draw.Segment.crop(9)
    %Drafter.Draw.Segment{text: "hello", style: %{}, width: 5}

    iex> Drafter.Draw.Segment.plain("hello") |> Drafter.Draw.Segment.crop(0)
    %Drafter.Draw.Segment{text: "", style: %{}, width: 0}

    iex> Drafter.Draw.Segment.plain("日本語") |> Drafter.Draw.Segment.crop(3)
    %Drafter.Draw.Segment{text: "日", style: %{}, width: 2}

# `empty?`

```elixir
@spec empty?(t()) :: boolean()
```

Whether the segment's text is the empty string.

## Examples

    iex> Drafter.Draw.Segment.plain("") |> Drafter.Draw.Segment.empty?()
    true

    iex> Drafter.Draw.Segment.plain(" ") |> Drafter.Draw.Segment.empty?()
    false

# `new`

```elixir
@spec new(String.t(), style()) :: t()
```

A segment of `text` carrying `style`.

The display width is measured on construction, with ANSI SGR sequences in `text`
excluded from the count. Colour values in `style` are normalised to RGB triples,
a translucent colour additionally storing its alpha under `alpha_key/1`.

`style` defaults to `%{}`.

## Examples

    iex> Drafter.Draw.Segment.new("abc")
    %Drafter.Draw.Segment{text: "abc", style: %{}, width: 3}

    iex> Drafter.Draw.Segment.new("日本")
    %Drafter.Draw.Segment{text: "日本", style: %{}, width: 4}

    iex> Drafter.Draw.Segment.new("x", %{fg: "#ff0000"})
    %Drafter.Draw.Segment{text: "x", style: %{fg: {255, 0, 0}}, width: 1}

    iex> Drafter.Draw.Segment.new("x", %{fg: "rgba(255, 0, 0, 0.5)"})
    %Drafter.Draw.Segment{text: "x", style: %{fg: {255, 0, 0}, fg_alpha: 0.5}, width: 1}

# `pad`

```elixir
@spec pad(t(), non_neg_integer()) :: t()
```

Append spaces until the segment is `target_width` columns wide, or return it
unchanged if it already is.

## Examples

    iex> Drafter.Draw.Segment.plain("ab") |> Drafter.Draw.Segment.pad(5)
    %Drafter.Draw.Segment{text: "ab   ", style: %{}, width: 5}

    iex> Drafter.Draw.Segment.plain("abcde") |> Drafter.Draw.Segment.pad(2)
    %Drafter.Draw.Segment{text: "abcde", style: %{}, width: 5}

# `plain`

```elixir
@spec plain(String.t()) :: t()
```

A segment of `text` with an empty style.

## Examples

    iex> Drafter.Draw.Segment.plain("héllo")
    %Drafter.Draw.Segment{text: "héllo", style: %{}, width: 5}

# `style_codes`

```elixir
@spec style_codes(style()) :: String.t()
```

The SGR sequence that turns on `style`.

Returns the empty string for an empty style, or one that sets nothing. Colours
are emitted as 24-bit `38;2` and `48;2` codes. Alpha keys emit nothing.

## Examples

    iex> Drafter.Draw.Segment.style_codes(%{})
    ""

    iex> Drafter.Draw.Segment.style_codes(%{bold: true})
    "\e[1m"

    iex> Drafter.Draw.Segment.style_codes(%{fg: {255, 0, 0}})
    "\e[38;2;255;0;0m"

    iex> Drafter.Draw.Segment.style_codes(%{bold: false})
    ""

# `style_flags`

```elixir
@spec style_flags() :: [atom()]
```

The style keys that are attribute flags rather than colours.

## Examples

    iex> Drafter.Draw.Segment.style_flags()
    [:bold, :dim, :italic, :underline, :reverse]

# `to_ansi`

```elixir
@spec to_ansi(t()) :: String.t()
```

The segment as SGR codes, its text, and a reset.

A segment with an empty style returns its text alone, with no codes and no reset.

## Examples

    iex> Drafter.Draw.Segment.new("x", %{bold: true}) |> Drafter.Draw.Segment.to_ansi()
    "\e[1mx\e[0m"

    iex> Drafter.Draw.Segment.plain("x") |> Drafter.Draw.Segment.to_ansi()
    "x"

# `width`

```elixir
@spec width(t()) :: non_neg_integer()
```

The segment's width in display columns, measured when it was built.

## Examples

    iex> Drafter.Draw.Segment.plain("日本") |> Drafter.Draw.Segment.width()
    4

---

*Consult [api-reference.md](api-reference.md) for complete listing*
