Introduction
Sauva is a terminal application for searching and browsing Unicode code points. It shows Unicode properties and a glyph preview in a responsive TUI.


Key Features
- Inspect Unicode names, properties, encodings, and decomposition mappings.
- Search by character, code point, Unicode name, or formal name alias.
- Browse Unicode planes, ranges, blocks, and code points.
- Analyze text as code points and grapheme clusters in Sequence mode.
- Compare NFC, NFD, NFKC, and NFKD normalization forms.
- Preview glyphs using installed fonts and a terminal graphics protocol.
- Customize colors, fonts, and keybindings.
For example, use Sauva to identify an invisible character, find a symbol by name, or examine how an emoji or accented letter is represented in a string.
Unicode Data
Sauva bundles data based on Unicode 17.0.0. Browsing and property lookup work offline, and the bundled data version is shown in the Inspector.
Glyphs depend on the fonts installed on your system. A character can have Unicode data even when no installed font can display it.
Built with Rust and Ratatui. Sauva is available on GitHub under the MIT License.
The generated Unicode data is distributed under the Unicode License v3. See the third-party notices for details.
Getting Started
- Requirements: supported systems and terminal requirements.
- Installation: install with Cargo, Homebrew, or a release binary.
- Basic Usage: inspect a character or analyze a string.
- Command Line Options: input formats and startup options.
- Compatibility: terminal graphics and system fonts.
Requirements
Operating Systems
Sauva supports macOS and Linux. Windows is not currently supported.
Terminal
An interactive terminal is required, including when the input is read from a pipe or file. Sauva reads the supplied input first, then accepts keyboard input from the terminal.
The minimum terminal size is 60 columns by 16 rows. A larger terminal, such as 100 columns by 30 rows, provides room for additional preview panels.
Glyph Images
Glyph images require a compatible terminal and fonts installed on your system. Sauva does not bundle fonts.
kitty and Ghostty are supported for automatic graphics detection. See Compatibility for the available protocols and modes.
Unicode properties, browsing, searching, and text analysis remain available when glyph images are disabled or unavailable.
Building from Source
Installing with Cargo requires Rust 1.88.0 or later. A release binary does not require Rust to be installed.
Installation
Cargo
Install from crates.io:
cargo install --locked sauva
See Requirements for the minimum Rust version.
Homebrew (macOS)
brew install lusingander/tap/sauva
The formula is available in lusingander/homebrew-tap.
Release Binaries
Download an archive for your operating system and architecture from the releases page.
| Operating system | Architecture | Target |
|---|---|---|
| macOS | Apple Silicon | aarch64-apple-darwin |
| macOS | Intel | x86_64-apple-darwin |
| Linux | ARM64 | aarch64-unknown-linux-gnu or aarch64-unknown-linux-musl |
| Linux | x86-64 | x86_64-unknown-linux-gnu or x86_64-unknown-linux-musl |
Extract the archive and put the sauva executable in a directory on your PATH.
Verify the Installation
sauva --version
Continue with Basic Usage.
Basic Usage
Inspect a Code Point
Run Sauva without arguments to open the default code point:
sauva
You can also specify a character or code point:
sauva あ
sauva U+2192
sauva 0x1F600
The Inspector shows the selected code point's properties and glyph preview.
- Use h / l or Left / Right to inspect adjacent code points.
- Use j / k or Down / Up to select a property, then y to copy its value.
- Press / to search, or p, r, b, or c to browse.
- Press F1 for help with the current screen.
- Press q or Esc to quit from the Inspector. Ctrl-C quits from any screen.
Analyze a String
Pass a string containing multiple code points to open Sequence mode:
sauva 'Á👩💻'
The list preserves the input order and groups code points into grapheme clusters.
- Use j / k or Down / Up to select a code point.
- Press Enter to open it in the Inspector, then Backspace to return.
- Press n in Sequence to compare normalization forms.

Use --text when a string would otherwise be interpreted as code point notation:
sauva --text 41
sauva --text U+2192
A single code point opens the Inspector, even with --text.
Read from a Pipe or File
Specify - to read UTF-8 input from stdin:
printf 'Á👩💻' | sauva -
printf 'U+2192' | sauva -
sauva --text - < input.txt
Sauva waits for EOF before opening the TUI. Whitespace and trailing newlines are preserved. For code point notation, use printf without a trailing newline; use --text - to inspect text exactly as supplied.
For all input rules and options, see Command Line Options. The complete controls are listed in Keybindings.
Command Line Options
Sauva - Terminal Unicode Explorer 🪄
Usage: sauva [OPTIONS] [INPUT]
Arguments:
[INPUT] Text or code point to inspect, or - to read stdin
Options:
-t, --text <TEXT> Treat the input as literal text, without code point notation parsing; - reads stdin
-g, --graphics <MODE> Control glyph preview graphics [default: auto] [possible values: auto, force, iterm2, off]
--print-default-config Print the complete default configuration to standard output
-h, --help Print help
-V, --version Print version
INPUT
Input is interpreted in this order:
- A single character opens that character in the Inspector.
U+or0xfollowed by one to six hexadecimal digits selects a code point. The prefixes are case-insensitive.- An argument made entirely of hexadecimal digits is interpreted as a code point. It must contain two to six digits.
- Other nonempty text opens Sequence mode if it contains multiple code points.
Code point values must be between U+0000 and U+10FFFF.
| Example | Interpretation |
|---|---|
sauva あ | Inspect U+3042 |
sauva A | Inspect the letter A (U+0041) |
sauva U+A | Inspect U+000A |
sauva 41 | Inspect U+0041 |
sauva 1F600 | Inspect U+1F600 |
sauva 'Á👩💻' | Analyze a sequence of code points |
A hexadecimal-only argument that fails notation parsing is rejected; it does not fall back to literal text. For example, use --text for a string of seven hexadecimal digits.
-t, --text <TEXT>
Treat the input as literal text without parsing code point notation:
sauva --text 41
sauva -t U+2192
These inputs open Sequence with the characters 4, 1, or U, +, 2, 1, 9, 2, respectively. A single character still opens the Inspector. Empty text is rejected.
INPUT and --text cannot be supplied together.
Reading from Stdin
Use - as INPUT to read stdin using the same interpretation rules. Use --text - to read literal text instead.
printf 'U+2192' | sauva -
printf 'Á👩💻' | sauva -
printf '41' | sauva --text -
printf 'A\nB\n' | sauva -
sauva --text - < input.txt
Sauva reads UTF-8 input until EOF before starting the TUI. All whitespace, including trailing LF and CRLF, is preserved. Empty input and invalid UTF-8 are rejected.
In particular, echo U+2192 | sauva - is rejected because the newline is part of the code point notation. Use printf 'U+2192' | sauva - for notation, or echo U+2192 | sauva --text - to inspect the literal text including its newline.
Stdin is read only when - is explicitly supplied. An interactive terminal is still required for keyboard input.
Since - selects stdin, use sauva U+002D to inspect the hyphen character itself.
-g, --graphics <MODE>
| Mode | Behavior |
|---|---|
auto | Use the Kitty graphics protocol in detected kitty and Ghostty terminals; otherwise omit glyph images |
force | Use the Kitty graphics protocol without terminal detection |
iterm2 | Use the iTerm2 inline image protocol; never selected automatically |
off | Disable glyph images |
See Compatibility for support details.
--print-default-config
Print the complete built-in configuration, including default keybindings, and exit:
sauva --print-default-config
sauva --print-default-config > config.toml
This option does not start the TUI or load your local configuration. It must be used on its own.
See Configurations for where to put the file.
-h, --help and -V, --version
Print command line help or the installed application version and exit.
Compatibility
Operating Systems
macOS and Linux are supported. Windows is not currently supported.
Terminal Graphics
Sauva uses the Kitty graphics protocol with Unicode placeholders for glyph images.
| Terminal | Graphics mode | Support |
|---|---|---|
| kitty | auto | Supported |
| Ghostty | auto | Supported |
| Other terminals supporting Kitty graphics and Unicode placeholders | force | Can be tried; compatibility is not guaranteed |
| Terminals supporting the iTerm2 inline image protocol | iterm2 | Explicit opt-in; compatibility and future support are not guaranteed |
| Other terminals | off or auto | Text information remains available without glyph images |
Automatic detection recognizes TERM=xterm-kitty and TERM=xterm-ghostty.
If a compatible terminal is not detected, try:
sauva --graphics force
This skips detection; it does not add graphics support to the terminal. A terminal multiplexer or a changed TERM value may affect detection and image display.
The iTerm2 inline image protocol is available only when selected explicitly:
sauva --graphics iterm2
Sixel is not implemented. To disable images, use:
sauva --graphics off
Fonts
Sauva does not bundle fonts. The available glyphs and their appearance depend on the fonts installed on the system.
- macOS uses Core Text to find system fonts.
- Linux uses Fontconfig when available. If Fontconfig cannot be loaded, Sauva uses a best-effort font database lookup.
Preferred text and emoji fonts can be configured separately. See Glyph Preview for the selection order and settings.
The font used for a glyph image can differ from the terminal's own text font. Terminal-rendered characters and the image preview can therefore look different.
Layout
The TUI adapts to the terminal size. Some preview panels are hidden at smaller widths, while the main text view remains available. See Requirements for the minimum size.
Configurations
Sauva uses a TOML configuration file to customize colors, glyph preview fonts, presentation, and keybindings.
Configuration File Location
The configuration path is selected in this order:
$SAUVA_CONFIG_FILE, if set.$XDG_CONFIG_HOME/sauva/config.toml, ifXDG_CONFIG_HOMEis nonempty.$HOME/.config/sauva/config.toml.
Only the selected file is loaded. For example, when XDG_CONFIG_HOME is set, Sauva does not look in $HOME/.config if that file is missing.
If the default file does not exist, all built-in settings are used. An empty SAUVA_CONFIG_FILE, a missing file explicitly selected with it, or an invalid configuration causes startup to fail.
All settings are optional. Unspecified settings keep their built-in defaults. Unknown fields are rejected, so misspelled setting names cause an error instead of being ignored.
Create a Configuration
Print the complete default configuration:
sauva --print-default-config
To create a file at the default location when XDG_CONFIG_HOME is unset:
mkdir -p ~/.config/sauva
sauva --print-default-config > ~/.config/sauva/config.toml
This writes to the specified file; use a new file path if you already have a configuration you want to keep.
You can also use a custom path:
sauva --print-default-config > ./config.toml
SAUVA_CONFIG_FILE=./config.toml sauva
Printing defaults does not load the local configuration or start the TUI, so it also works when an existing configuration is invalid.
- Config File Format: all configuration sections, values, and defaults.
- Glyph Preview: font selection and image colors.
- Custom Keybindings: command bindings for each screen.
Config File Format
All configuration settings are optional. The following example contains the default colors, glyph preview settings, and UI settings:
[color]
fg = "reset"
bg = "reset"
muted = "darkgray"
accent = "cyan"
heading = "blue"
border = "darkgray"
match = "yellow"
key = "yellow"
link = "blue"
[color.selection]
fg = "black"
bg = "cyan"
[color.difference]
fg = "black"
bg = "yellow"
[color.status]
info = "green"
warning = "yellow"
[glyph_preview]
font_families = []
emoji_font_families = []
fg = "#f5f7fa"
bg = "#00000000"
[ui]
selection_cursor = ""
input_cursor = "native"
Use sauva --print-default-config to print the full configuration, including every default keybinding.
The configuration structure is also described by config.schema.json. Sauva validates the configuration at startup, including terminal cell widths and keybinding conflicts.
color
These settings control the TUI's colors:
| Setting | Default | Use |
|---|---|---|
fg | "reset" | Main text |
bg | "reset" | Main background |
muted | "darkgray" | Secondary text and labels |
accent | "cyan" | Accented text and grapheme markers |
heading | "blue" | Section headings |
border | "darkgray" | Borders and scrollbars |
match | "yellow" | Search matches |
key | "yellow" | Key labels in help and the footer |
link | "blue" | Link text |
selection.fg | "black" | Selected item text |
selection.bg | "cyan" | Selected item background |
difference.fg | "black" | Text in changed normalization spans |
difference.bg | "yellow" | Background of changed normalization spans |
status.info | "green" | Informational status messages |
status.warning | "yellow" | Warning status messages |
Changed normalization spans are also underlined. Their colors are configured separately from the selection colors.
UI color values are strings in one of these formats:
- ANSI names:
reset,black,red,green,yellow,blue,magenta,cyan,gray,darkgray,light-red,light-green,light-yellow,light-blue,light-magenta,light-cyan, orwhite. - RGB hexadecimal:
"#RRGGBB". - Indexed color: a quoted number from
"0"to"255".
reset uses the terminal's default color. UI colors do not accept an alpha channel.
For example:
[color]
heading = "#89b4fa"
muted = "245"
[color.selection]
fg = "black"
bg = "light-blue"
glyph_preview
| Setting | Type | Default |
|---|---|---|
font_families | Array of font family names | [] |
emoji_font_families | Array of font family names | [] |
fg | RGB or RGBA color string | "#f5f7fa" |
bg | RGB or RGBA color string | "#00000000" |
Font lists are tried in the order given. Empty or whitespace-only family names are rejected. Image colors accept #RRGGBB or #RRGGBBAA, including an alpha channel.
See Glyph Preview for examples and the complete font selection order.
ui
selection_cursor
The marker shown before a selected Inspector property, list entry, or code point.
- Type: string.
- Default:
""(no visible marker). - Must be empty or occupy exactly one terminal cell, without control characters.
[ui]
selection_cursor = "▸"
input_cursor
The cursor shown in the search input.
- Default:
"native", using the terminal's native cursor. - Use
{ text = "..." }for a text cursor. Its text must occupy exactly one terminal cell, without control characters.
[ui]
input_cursor = { text = "|" }
keybindings
Bindings are grouped by screen context. Each command accepts an array of key strings that replaces its built-in binding. An empty array disables the command in that context.
[keybindings.global]
help = ["f2"]
[keybindings.inspector]
next_code_point = ["l", "right", "n"]
browse_planes = []
See Custom Keybindings for contexts, command names, key formats, and validation rules.
Glyph Preview
The glyph preview renders the selected code point as an image using a font installed on your system. When space is available, the preview panel also shows the font family, style, and version.
The image font is selected independently of the terminal's text font. Configure it in the [glyph_preview] section:
[glyph_preview]
font_families = ["Iosevka", "Noto Sans"]
emoji_font_families = ["Noto Color Emoji"]
fg = "#f5f7fa"
bg = "#00000000"
Font Selection
For each code point, Sauva tries:
- Configured normal fonts in
font_families, in order. - The system default text font.
- Configured emoji fonts in
emoji_font_families, in order. - System fallback fonts.
Missing families and fonts without a usable glyph are skipped. Both lists default to [], so system fonts are used without any configuration.
Sauva does not install fonts. Specify family names for fonts already installed on the machine. The chosen font can vary between code points and between operating systems.
For OS-specific font lookup and terminal support, see Compatibility.
Image Colors
fgis the glyph foreground color; the default is"#f5f7fa".bgis the image background color; the default is"#00000000", fully transparent.
Values accept #RRGGBB or #RRGGBBAA. For example, use an opaque background on a light terminal:
[glyph_preview]
fg = "#202020"
bg = "#ffffff"
Color font glyphs, such as emoji, can use their own palette.
Special Characters
Combining marks can be shown with a dotted circle to make their position visible. The dotted circle is a preview aid; it is not part of the character's value or the text copied from the Inspector.
Some code points cannot produce a visible image:
| Message | Meaning |
|---|---|
No visible pixels | The resolved glyph is blank, as can happen with a space or invisible character |
Glyph unavailable | No usable glyph was found in the available fonts |
Not a Unicode scalar value | The selected code point is a surrogate and cannot be rendered |
Graphics disabled | Images were disabled with --graphics off |
Graphics unavailable | Automatic detection did not select a graphics protocol |
Unicode details remain available in these cases. See FAQ for troubleshooting.
Keybindings
Press F1 to open or close contextual help. Help and the footer show the active bindings, including your custom settings.
The tables below list the built-in bindings and the command names used in Custom Keybindings.
Global
These bindings apply in every screen, including help.
| Command | Keys | Action |
|---|---|---|
quit | Ctrl-C | Quit Sauva |
help | F1 | Open or close help |
Inspector
Context: inspector.
| Command | Keys | Action |
|---|---|---|
quit | q, Esc | Quit |
previous_code_point | h, Left | Inspect the previous code point |
next_code_point | l, Right | Inspect the next code point |
move_up | k, Up | Select the previous property |
move_down | j, Down | Select the next property |
page_up | Ctrl-U | Move properties up one page |
page_down | Ctrl-D | Move properties down one page |
first | g | Select the first property |
last | G | Select the last property |
copy_value | y | Copy the selected property value |
search | / | Open search |
browse_planes | p | Browse planes |
browse_ranges | r | Browse ranges in the current plane |
browse_blocks | b | Browse blocks |
browse_code_points | c | Browse code points in the current range |
back | Backspace | Return to the sequence, when one is open |
Search
Context: search.
| Command | Keys | Action |
|---|---|---|
previous_result | Up, Ctrl-P | Select the previous result |
next_result | Down, Ctrl-N | Select the next result |
inspect_result | Enter | Open the selected result in the Inspector |
close | Esc | Close search |
Character keys edit the query, including j, k, and q. Use the arrow keys or Ctrl-P / Ctrl-N to select results. Search input editing keys are reserved and cannot be assigned to commands.
Sequence
Context: sequence.
| Command | Keys | Action |
|---|---|---|
quit | q, Esc | Quit |
move_up | k, Up | Select the previous code point |
move_down | j, Down | Select the next code point |
first | g | Select the first code point |
last | G | Select the last code point |
activate | Enter | Inspect the selected code point |
normalize | n | Compare normalization forms |
Normalization
Context: normalization.
| Command | Keys | Action |
|---|---|---|
quit | q | Quit |
close | Esc | Return to the original sequence |
back | Backspace | Return to the original sequence |
move_up | k, Up | Select the previous normalization form |
move_down | j, Down | Select the next normalization form |
first | g | Select NFC |
last | G | Select NFKD |
activate | Enter | Inspect the selected normalization result |
copy_value | y | Copy the exact normalized text |
Normalization Result
Context: normalization_result.
| Command | Keys | Action |
|---|---|---|
quit | q | Quit |
close | Esc | Return to normalization comparison |
back | Backspace | Return to normalization comparison |
move_up | k, Up | Select the previous code point |
move_down | j, Down | Select the next code point |
first | g | Select the first code point |
last | G | Select the last code point |
activate | Enter | Inspect the selected code point |
Use Backspace in the Inspector to return to this result.
Browse Lists
Contexts: browse_plane, browse_range, and browse_block.
| Command | Keys | Action |
|---|---|---|
quit | q | Quit |
close | Esc | Cancel browsing and return to the Inspector |
back | Backspace | Return to the previous browse level, or to the Inspector at the top |
move_up | k, Up | Select the previous item |
move_down | j, Down | Select the next item |
first | g | Select the first item |
last | G | Select the last item |
activate | Enter | Open ranges in a plane, or code points in a range or block |
browse_range and browse_block additionally support:
| Command | Keys | Action |
|---|---|---|
page_up | Ctrl-U | Move backward by a large step |
page_down | Ctrl-D | Move forward by a large step |
Browse Code Points
Context: browse_code_points.
| Command | Keys | Action |
|---|---|---|
quit | q | Quit |
close | Esc | Cancel browsing and return to the Inspector |
back | Backspace | Return to the previous browse level |
move_left | h, Left | Move left |
move_right | l, Right | Move right |
move_up | k, Up | Move up one row |
move_down | j, Down | Move down one row |
page_up | Ctrl-U | Move backward by a large step |
page_down | Ctrl-D | Move forward by a large step |
first | g | Select the first code point in the range or block |
last | G | Select the last code point in the range or block |
activate | Enter | Inspect the selected code point |
Help
Context: help. The underlying screen's commands are inactive while help is open; global bindings remain active.
| Command | Keys | Action |
|---|---|---|
close | Esc | Close help |
move_up | k, Up | Scroll up one line |
move_down | j, Down | Scroll down one line |
page_up | Ctrl-U | Scroll up one page |
page_down | Ctrl-D | Scroll down one page |
first | g | Go to the beginning |
last | G | Go to the end |
Custom Keybindings
Customize bindings in the [keybindings.<context>] sections of the configuration file.
[keybindings.global]
help = ["f2"]
[keybindings.inspector]
next_code_point = ["l", "right", "n"]
back = ["backspace"]
browse_planes = []
- Each array replaces the keys for one command in one context.
- Omitted commands keep their built-in bindings.
- Multiple keys can be assigned to one command.
- An empty array disables that command in that context.
- Help and the footer display the resulting bindings.
Use sauva --print-default-config to see every context, command, and default binding. The command names are also listed in Keybindings.
Contexts
| Context | Applies to |
|---|---|
global | Every screen; supports quit and help |
inspector | Code point properties |
search | Search results |
sequence | The original input sequence |
normalization | Normalization form comparison |
normalization_result | A normalized sequence |
browse_plane | Plane list |
browse_range | Range list |
browse_block | Block list |
browse_code_points | Code point grid |
help | Contextual help |
Global bindings remain active in all contexts. When help is open, only its own bindings and the global bindings are active.
Disabling a local command does not disable the global binding for the same action. For example, disabling keybindings.inspector.quit leaves the default global Ctrl-C binding available.
Key Formats
Characters
Use a single non-whitespace character, such as a, 1, /, or -.
Uppercase ASCII letters represent Shift plus that letter. For example, G and shift-g both describe Shift-G.
Named Keys
| Name | Key |
|---|---|
space | Space |
enter | Enter |
esc | Escape |
tab | Tab |
backspace | Backspace |
delete | Delete |
left, right, up, down | Left, Right, Up, Down |
home, end | Home and End |
pageup, pagedown | Page Up and Page Down |
f1 through f12 | F1 through F12 |
Names and modifier prefixes are lowercase.
Modifiers
Use ctrl-, alt-, or shift- followed by a single character. Modifiers can be combined, without repeating the same modifier:
[keybindings.inspector]
next_code_point = ["ctrl-n", "alt-l"]
last = ["shift-g"]
Modifiers apply only to character keys. Forms such as ctrl-left, shift-tab, or alt-f1 are not supported. Use a lowercase ASCII letter after a modifier; ctrl-G is invalid.
The terminal must deliver the chosen key combination to Sauva. Some combinations are handled by the terminal itself.
Conflicts and Validation
Sauva rejects invalid bindings at startup, including:
- Unknown contexts, command names, or key names.
- Duplicate keys for a command, including equivalent forms such as
Gandshift-g. - A key assigned to two different commands in the same context.
- A local binding that uses a global key for a different command.
- Global or search bindings that would intercept search input editing.
For example, binding j to search.next_result is rejected because j is needed for typing the query. Use an arrow key or another combination that is not an input editing key.
When moving a key from one command to another, also remove it from the original command's binding. For example:
[keybindings.inspector]
next_code_point = ["right"]
copy_value = ["y", "l"]
Features
- Inspector: inspect one code point and copy its properties.
- Search: find a character by value, name, or formal alias.
- Browse: explore planes, ranges, blocks, and code points.
- Sequence: examine a string's code points and grapheme clusters.
- Normalization: compare and inspect normalized text.
Press F1 in any screen for contextual help. See Keybindings for the complete controls.
Inspector
The Inspector shows the properties of one Unicode code point. Open it at startup with a character or code point argument, or select a code point from Search, Browse, or Sequence.
sauva あ
sauva U+2192

Properties
| Section | Fields |
|---|---|
| Identity | Character, Code Point, Primary Name, Aliases, Plane, Block |
| Classification | General Category, Script, Age, East Asian Width, Canonical Combining Class, Bidi Class, Default Ignorable |
| Encoding | UTF-8, UTF-16, HTML Decimal, HTML Hex, Rust char, Unicode Escape |
| Normalization | Decomposition Type, Decomposition |
| Data | Unicode Version |
Some useful distinctions:
- Age is the Unicode version in which the character was introduced. Unicode Version is the version of Sauva's bundled data.
- Aliases lists formal Unicode name aliases and their types. These aliases can also be searched.
- East Asian Width is a Unicode property. Actual terminal cell width also depends on the terminal and its rendering rules.
- Decomposition shows the character's Unicode decomposition mapping. To compare the normalized forms of a string, use Normalization from Sequence.
The glyph panel renders the selected code point and shows the font used, when space is available. See Glyph Preview for font settings and special cases.
Operations
| Keys | Action |
|---|---|
| h / l, Left / Right | Inspect the previous / next code point |
| j / k, Down / Up | Select a property |
| Ctrl-U / Ctrl-D | Move through properties by page |
| g / G | Select the first / last property |
| y | Copy the selected value |
| / | Open Search |
| p, r, b, c | Open Browse at the corresponding level |
| Backspace | Return to the original or normalized sequence, when one is open |
| q, Esc | Quit |
Adjacent navigation follows code point values, even when the Inspector was opened from a sequence. Backspace returns to the sequence's existing selection.
Copying Values
Select a property and press y to copy it to the system clipboard. Selecting Character copies the actual character, including invisible characters and combining marks. Display aids such as a dotted circle or a <SPACE> label are not included in that value.
Unavailable values, such as an encoding for a surrogate, cannot be copied. A status message reports whether copying succeeded or why it failed.
Special Code Points
Sauva can inspect the full code point range, including unassigned code points, private-use characters, and surrogates.
Surrogates are not Unicode scalar values, so UTF-8 / UTF-16 encodings and character images are unavailable for them. Empty or invisible characters may have property data without visible pixels in the preview.
Search
Press / in the Inspector to search by character, code point, Unicode name, or formal name alias.

Queries
| Query | Behavior |
|---|---|
あ | Find the literal character |
A | Find the letter A |
U+2192 | Find that code point |
U+A | Find U+000A |
2192 | Find that code point and matching names or aliases |
arrow | Match Unicode names and formal aliases containing the query |
LF | Find matching formal aliases and names |
Surrounding ASCII whitespace is removed from a search query. Name and alias matching ignores ASCII case and normalizes runs of ASCII whitespace to a single space.
A U+ prefix explicitly selects code point notation and accepts one to six hexadecimal digits. A bare hexadecimal query is interpreted as notation only when it contains four to six digits; its name and alias matches are included as well.
Search notation differs from command line input: the search field does not recognize the 0x prefix, and a query such as 41 searches names and aliases. Use U+0041 for an unambiguous code point query.
Invalid U+ notation and out-of-range code points display an error. A valid query with no matching results displays an empty result list.
Result Order
Direct character or code point matches appear first. Name and alias matches follow, ordered by exact match, prefix match, and substring match. For equal match types, primary name matches precede alias matches, and code point order breaks remaining ties.
A code point appears only once even if both its name and an alias match. Matching text is highlighted.
Operations
| Keys | Action |
|---|---|
| Up / Down, Ctrl-P / Ctrl-N | Select the previous / next result |
| Enter | Open the selected result in the Inspector |
| Esc | Close Search |
| F1 | Open contextual help |
| Ctrl-C | Quit |
Character keys edit the query, so j, k, and q are entered as text. Search results update as the query changes. Reopening Search keeps the previous query and selection.
Browse
Browse Unicode by numeric location or by a named block. From the Inspector, use these shortcuts:
| Key | Starting view |
|---|---|
| p | Planes |
| r | Ranges in the current plane |
| b | Blocks |
| c | Code points in the current range |
Planes and Ranges
This path explores Unicode by code point value:
Plane → Range → Code Point → Inspector
A plane contains 65,536 code points. Sauva divides each plane into ranges of 256 code points for browsing. These ranges are numeric subdivisions, independent of named Unicode blocks.



Blocks
This path explores named blocks from the Unicode Character Database:
Block → Code Point → Inspector
Blocks have different sizes and may leave gaps between them. When opening the block list from a code point in a gap, Sauva selects the next block.


Operations
- Use j / k or Down / Up in lists.
- Use h, j, k, l or the arrow keys in a code point grid.
- Press Enter to open the next level or inspect the selected code point.
- Press g / G to jump to the first / last item. In a grid, this is the first / last code point in the range or block.
- Use Ctrl-U / Ctrl-D for larger steps in ranges, blocks, and code point grids.
Backspace returns to the previous browse level. At the level where browsing was opened, it returns to the Inspector. Esc cancels browsing immediately and returns to the Inspector without changing its selected code point. Press q to quit.
Code point grids include unassigned and special code points, so an entry may have no visible glyph. The Inspector provides the available property details for each entry.
Sequence
Sequence mode analyzes a string as an ordered list of code points, grouped into grapheme clusters. It is useful for examining combining marks, emoji sequences, and invisible characters.
Start in Sequence Mode
Pass text containing multiple code points:
sauva 'Á👩💻'
Use --text to prevent code point notation parsing:
sauva --text 41
sauva --text U+2192
Read text from a pipe or file:
printf 'Á👩💻' | sauva --text -
sauva --text - < input.txt
A single code point opens the Inspector. Sequence opens for multiple code points, even when they form a single visible character. Empty input is rejected.
See Command Line Options for the complete input rules.

Code Points and Grapheme Clusters
A code point is one Unicode value, such as U+0041. A grapheme cluster groups code points into a unit that often corresponds to a user-perceived character. Sauva uses extended grapheme cluster boundaries as described in Unicode Text Segmentation.
For example, the string Á👩💻 contains five code points and two grapheme clusters:
| Cluster | Code points |
|---|---|
Á | U+0041 LATIN CAPITAL LETTER A + U+0301 COMBINING ACUTE ACCENT |
👩💻 | U+1F469 WOMAN + U+200D ZERO WIDTH JOINER + U+1F4BB PERSONAL COMPUTER |
The accented A in the command above is U+0041 followed by U+0301.
Reading the Screen

- Each row shows the input position, code point, display representation, and Unicode name.
- The left gutter numbers grapheme clusters and connects their member code points. A dot marks a cluster containing one code point.
- The selected cluster is emphasized in the gutter.
- The heading shows code point and grapheme counts, abbreviated as
CPandGCin compact layouts. - When space is available, the selection panel shows the selected code point's properties and position within its cluster. The glyph image renders that individual code point.
Input order, repeated characters, spaces, and newlines are preserved. Labels and dotted circles make otherwise hard-to-see characters visible in the list.
Operations
| Keys | Action |
|---|---|
| j / k, Down / Up | Select a code point |
| g / G | Select the first / last code point |
| Enter | Open the selected code point in the Inspector |
| n | Compare normalization forms |
| q, Esc | Quit |

Backspace in the Inspector returns to the sequence. From Sequence, press n to open Normalization.
Normalization
From Sequence, press n to compare the input with its NFC, NFD, NFKC, and NFKD normalized forms.
sauva 'Á①ffi'

Forms
| Form | Transformation |
|---|---|
| NFC | Canonical decomposition followed by canonical composition |
| NFD | Canonical decomposition |
| NFKC | Compatibility decomposition followed by canonical composition |
| NFKD | Compatibility decomposition |
Canonical normalization handles equivalent representations, such as a precomposed accented letter and a letter followed by a combining mark. Compatibility normalization also converts characters such as circled digits and ligatures, and can remove distinctions in their original presentation. See Unicode Normalization Forms for the specification.
Examples of individual transformations:
| Input | Form | Result |
|---|---|---|
A + U+0301 | NFC | Á (U+00C1) |
Á (U+00C1) | NFD | A + U+0301 |
① (U+2460) | NFKC | 1 (U+0031) |
ffi (U+FB03) | NFKD | ffi |
Comparison
The comparison screen shows:
- The original text and its code point sequence.
- Whether each form changes the input.
- Code point (
CP), UTF-8 byte (Bytes), and grapheme cluster (GC) counts for each form. - The selected form's result, code point sequence, and number of changed regions.
Changed regions use the configured difference colors and underlining. Spaces and invisible characters are represented with display aids; the copied result contains the actual normalized text.
Inspect a Result
Select a form and press Enter to open its code point list.

The result is shown alongside the original code point list. As you select a result code point, the corresponding region in the original is highlighted and brought into view. This makes compositions and expansions easier to follow.
Press Enter again to inspect a result code point. Backspace in the Inspector returns to the result list; Backspace or Esc in the result list returns to the form comparison.
The original input is preserved throughout these operations.
Operations
| Keys | In form comparison | In a result list |
|---|---|---|
| j / k, Down / Up | Select a form | Select a code point |
| g / G | Select NFC / NFKD | Select the first / last code point |
| Enter | Open the selected result | Inspect the selected code point |
| y | Copy the exact normalized text | — |
| Backspace, Esc | Return to the original sequence | Return to form comparison |
| q | Quit | Quit |
Copying includes whitespace and newlines in the normalized result. Select a form and press y in the comparison screen to copy the whole result.
FAQ
Why is the glyph preview missing?
First, check Compatibility. Automatic graphics detection enables images for kitty and Ghostty. If a compatible terminal is not detected, try sauva --graphics force. For the iTerm2 inline image protocol, explicitly use sauva --graphics iterm2.
Also check the preview's message:
- Graphics disabled: start without
--graphics off. - Graphics unavailable: automatic detection did not select a protocol.
- Glyph unavailable: install a font with a usable glyph, or adjust the preferred fonts.
- No visible pixels: the resolved glyph is blank. Spaces and invisible characters can have this result.
- Not a Unicode scalar value: surrogates cannot be rendered.
- Preview area unavailable: resize the terminal and try again.
Some preview panels are hidden at smaller terminal widths. Enlarge the terminal to make room for them. Text information remains available without images.
Why does the glyph use a different font from my terminal?
Sauva selects fonts independently for glyph images. It tries configured normal fonts, the system default text font, configured emoji fonts, and system fallback fonts, in that order.
Set glyph_preview.font_families and glyph_preview.emoji_font_families to installed family names. The preview's Font and Version fields identify the font used. See Glyph Preview.
Why does sauva 41 open one character?
An input containing only hexadecimal digits is interpreted as code point notation. 41 selects U+0041, the letter A.
Use sauva --text 41 to open the two literal characters in Sequence mode. A single-character argument is always treated as that character; use sauva U+A to inspect code point U+000A.
The search field has its own input rules. See Command Line Options and Search.
Why does echo U+2192 | sauva - fail?
echo adds a newline, and Sauva preserves that newline as part of stdin. It therefore cannot parse the input as code point notation.
Use:
printf 'U+2192' | sauva -
To examine the literal text and its newline, use:
echo U+2192 | sauva --text -
Stdin must contain nonempty, valid UTF-8. It is read only when - is explicitly supplied, and Sauva waits for EOF before starting. Keyboard input still requires an interactive terminal.
Why does an emoji appear as several rows?
Sequence has one row per code point. An emoji such as 👩💻 contains multiple code points grouped into one grapheme cluster. The gutter connects those rows and shows their shared cluster number.
The glyph image previews the selected code point. See Sequence for an example.
Why does copying fail?
Sauva uses the system clipboard. The footer reports when it is unavailable, busy, or unable to accept the text. Check that a system clipboard is available in the current desktop session; an SSH or headless session may not provide one.
A field marked unavailable, such as the encoding of a surrogate, has no copyable value. In Normalization, press y in the form comparison screen to copy the whole normalized result.
Why does my configuration prevent startup?
The startup error identifies the configuration file and the problem. Check for:
- An empty
SAUVA_CONFIG_FILEor a nonexistent file selected by it. - Invalid TOML or unknown field names.
- Unsupported color formats or cursor text wider than one terminal cell.
- Invalid, duplicate, conflicting, or input-reserved keybindings.
sauva --print-default-config works without loading the local file and provides a valid starting point. See Configurations and Custom Keybindings.
Can I use Sauva without glyph images?
Yes. Run sauva --graphics off to use properties, Search, Browse, Sequence, and Normalization without image previews.
Which Unicode version does Sauva use?
The bundled data is based on Unicode 17.0.0. The Inspector's Unicode Version field shows this data version, while Age shows the version in which the selected character was introduced. An installed font may cover a different set of characters.