An open API service indexing awesome lists of open source software.

https://github.com/uutils/ansi-width

Calculate the width of a string when printed to the terminal
https://github.com/uutils/ansi-width

Last synced: about 1 year ago
JSON representation

Calculate the width of a string when printed to the terminal

Awesome Lists containing this project

README

          

[![Crates.io](https://img.shields.io/crates/v/ansi-width.svg)](https://crates.io/crates/ansi-width)
[![Discord](https://img.shields.io/badge/discord-join-7289DA.svg?logo=discord&longCache=true&style=flat)](https://discord.gg/wQVJbvJ)
[![License](http://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/uutils/ansi-width/blob/main/LICENSE)
[![dependency status](https://deps.rs/repo/github/uutils/ansi-width/status.svg)](https://deps.rs/repo/github/uutils/ansi-width)

[![CodeCov](https://codecov.io/gh/uutils/ansi-width/branch/main/graph/badge.svg)](https://codecov.io/gh/uutils/ansi-width)

# ANSI width

Measure the width of a string when printed to the terminal

For ASCII, this is identical to the length of the string in bytes. However,
there are 2 special cases:

- Many unicode characters (CJK, emoji, etc.) span multiple columns.
- ANSI escape codes should be ignored.

The first case is handled by the `unicode-width` crate. This function extends
that crate by ignoring ANSI escape codes.

## Limitations

- We cannot know the width of a `TAB` character in the terminal emulator.
- Backspace is also treated as zero width.

## A Primer on ANSI escape codes (and how this crate works)

ANSI codes are created using special character sequences in a string. These
sequences start with the ESC character: `'\x1b'`, followed by some other
character to determine the type of the escape code. That second character
determines how long the sequence continues:

- `ESC [`: until a character in the range `'\x40'..='\x7E'` is found.
- `ESC ]`: until an `ST` is found.

An `ST` is a String Terminator and is given by the sequence `ESC \` (or in Rust
syntax `'\x1b\x5c'`).

This is the subset of sequences that this library supports, since these are used
by most applications that need this functionality. If you have a use case for
other codes, please open an issue on the
[GitHub repository](https://github.com/uutils/ansi-width).

`ansi-width` does not parse the actual ANSI codes to improve performance, it can
only skip the ANSI codes.

## Examples

```rust
use ansi_width::ansi_width;

// ASCII string
assert_eq!(ansi_width("123456"), 6);

// Accents
assert_eq!(ansi_width("café"), 4);

// Emoji (2 crab emoji)
assert_eq!(ansi_width("🦀🦀"), 4);

// CJK characters (“Nǐ hǎo” or “Hello” in Chinese)
assert_eq!(ansi_width("你好"), 4);

// ANSI colors
assert_eq!(ansi_width("\u{1b}[31mRed\u{1b}[0m"), 3);

// ANSI hyperlink
assert_eq!(
ansi_width("\x1b]8;;http://example.com\x1b\\This is a link\x1b]8;;\x1b\\"),
14
);
```

## Alternatives

- [`str::len`](https://doc.rust-lang.org/std/primitive.str.html#method.len): Returns only the length in bytes and therefore only works for
ASCII characters.
- [`unicode-width`](https://crates.io/crates/unicode-width): Does not take ANSI
characters into account by design (see
[this issue](https://github.com/unicode-rs/unicode-width/issues/24)). This
might be what you want if you don't care about ANSI codes. `unicode-width` is
used internally by this crate as well.
- [`textwrap::core::display_width`](https://docs.rs/textwrap/latest/textwrap/core/fn.display_width.html):
Very similar functionality to this crate and it also supports hyperlinks since version 0.16.1. The
advantage of this crate is that it does not require pulling in the rest of `textwrap`'s functionality
(even though that functionality is excellent if you need it).
- [`console::measure_text_width`](https://docs.rs/console/latest/console/fn.measure_text_width.html):
Similar to `textwrap` and very well-tested. However, it constructs a new
string internally without ANSI codes first and then measures the width of
that. The parsing is more robust than this crate though.

## References

The information above is based on:

-
-