# `Drafter.CharacterWidth`
[🔗](https://github.com/jaman/drafter/blob/main/lib/drafter/character_width.ex#L1)

Terminal display width of text, in columns.

Widths are per grapheme cluster, not per codepoint. Every measurement Drafter
makes goes through here: strip widths, truncation, wrapping, cursor placement,
and the compositor's column arithmetic.

## Examples

    iex> Drafter.CharacterWidth.string("drafter")
    7

    iex> Drafter.CharacterWidth.grapheme("漢")
    2

    iex> Drafter.CharacterWidth.grapheme("e\u0301")
    1

## Choosing an implementation

`Drafter.CharacterWidth.Default` is used when nothing is configured. A host
that owns the grid Drafter draws into can supply its own tables instead:

    config :drafter, character_width: ETee.CharacterWidth

The setting is read with `Application.compile_env/3`, so these functions
compile to direct calls into the chosen module. Changing it takes effect on
recompiling Drafter:

    mix deps.compile drafter --force

## Conformance

An implementation must measure printable ASCII as one column, C0 controls and
combining marks as zero, and East Asian wide characters as two; `U+FE0F` and
`U+FE0E` override the base character's presentation; and `string/1` equals the
sum of its graphemes. `Drafter.CharacterWidthConformanceTest` asserts all of
this and can be run against a candidate module.

# `implementation`

```elixir
@type implementation() :: module()
```

A module implementing this behaviour.

# `codepoint`

```elixir
@callback codepoint(non_neg_integer()) :: non_neg_integer()
```

Columns a single codepoint occupies, ignoring any cluster it belongs to.

# `grapheme`

```elixir
@callback grapheme(String.t()) :: non_neg_integer()
```

Columns one grapheme cluster occupies. Zero for an empty string.

# `printable_ascii?`

```elixir
@callback printable_ascii?(binary()) :: boolean()
```

Whether a binary is entirely printable ASCII.

A `true` answer means the binary's byte size equals its column width, so
callers may skip grapheme segmentation.

# `string`

```elixir
@callback string(String.t()) :: non_neg_integer()
```

Columns a whole string occupies, summed over its grapheme clusters.

# `codepoint`

# `default?`

```elixir
@spec default?() :: boolean()
```

Whether Drafter is measuring with its own tables rather than a host's.

# `grapheme`

# `implementation`

```elixir
@spec implementation() :: implementation()
```

The implementation in use.

# `printable_ascii?`

# `string`

---

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