Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

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.

Sauva demo

Sequence and normalization demo

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

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 systemArchitectureTarget
macOSApple Siliconaarch64-apple-darwin
macOSIntelx86_64-apple-darwin
LinuxARM64aarch64-unknown-linux-gnu or aarch64-unknown-linux-musl
Linuxx86-64x86_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.

  1. Use j / k or Down / Up to select a code point.
  2. Press Enter to open it in the Inspector, then Backspace to return.
  3. Press n in Sequence to compare normalization forms.

Sequence and normalization demo

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:

  1. A single character opens that character in the Inspector.
  2. U+ or 0x followed by one to six hexadecimal digits selects a code point. The prefixes are case-insensitive.
  3. An argument made entirely of hexadecimal digits is interpreted as a code point. It must contain two to six digits.
  4. Other nonempty text opens Sequence mode if it contains multiple code points.

Code point values must be between U+0000 and U+10FFFF.

ExampleInterpretation
sauva あInspect U+3042
sauva AInspect the letter A (U+0041)
sauva U+AInspect U+000A
sauva 41Inspect U+0041
sauva 1F600Inspect 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>

ModeBehavior
autoUse the Kitty graphics protocol in detected kitty and Ghostty terminals; otherwise omit glyph images
forceUse the Kitty graphics protocol without terminal detection
iterm2Use the iTerm2 inline image protocol; never selected automatically
offDisable 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.

TerminalGraphics modeSupport
kittyautoSupported
GhosttyautoSupported
Other terminals supporting Kitty graphics and Unicode placeholdersforceCan be tried; compatibility is not guaranteed
Terminals supporting the iTerm2 inline image protocoliterm2Explicit opt-in; compatibility and future support are not guaranteed
Other terminalsoff or autoText 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:

  1. $SAUVA_CONFIG_FILE, if set.
  2. $XDG_CONFIG_HOME/sauva/config.toml, if XDG_CONFIG_HOME is nonempty.
  3. $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 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:

SettingDefaultUse
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, or white.
  • 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

SettingTypeDefault
font_familiesArray of font family names[]
emoji_font_familiesArray of font family names[]
fgRGB or RGBA color string"#f5f7fa"
bgRGB 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:

  1. Configured normal fonts in font_families, in order.
  2. The system default text font.
  3. Configured emoji fonts in emoji_font_families, in order.
  4. 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

  • fg is the glyph foreground color; the default is "#f5f7fa".
  • bg is 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:

MessageMeaning
No visible pixelsThe resolved glyph is blank, as can happen with a space or invisible character
Glyph unavailableNo usable glyph was found in the available fonts
Not a Unicode scalar valueThe selected code point is a surrogate and cannot be rendered
Graphics disabledImages were disabled with --graphics off
Graphics unavailableAutomatic 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.

CommandKeysAction
quitCtrl-CQuit Sauva
helpF1Open or close help

Inspector

Context: inspector.

CommandKeysAction
quitq, EscQuit
previous_code_pointh, LeftInspect the previous code point
next_code_pointl, RightInspect the next code point
move_upk, UpSelect the previous property
move_downj, DownSelect the next property
page_upCtrl-UMove properties up one page
page_downCtrl-DMove properties down one page
firstgSelect the first property
lastGSelect the last property
copy_valueyCopy the selected property value
search/Open search
browse_planespBrowse planes
browse_rangesrBrowse ranges in the current plane
browse_blocksbBrowse blocks
browse_code_pointscBrowse code points in the current range
backBackspaceReturn to the sequence, when one is open

Context: search.

CommandKeysAction
previous_resultUp, Ctrl-PSelect the previous result
next_resultDown, Ctrl-NSelect the next result
inspect_resultEnterOpen the selected result in the Inspector
closeEscClose 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.

CommandKeysAction
quitq, EscQuit
move_upk, UpSelect the previous code point
move_downj, DownSelect the next code point
firstgSelect the first code point
lastGSelect the last code point
activateEnterInspect the selected code point
normalizenCompare normalization forms

Normalization

Context: normalization.

CommandKeysAction
quitqQuit
closeEscReturn to the original sequence
backBackspaceReturn to the original sequence
move_upk, UpSelect the previous normalization form
move_downj, DownSelect the next normalization form
firstgSelect NFC
lastGSelect NFKD
activateEnterInspect the selected normalization result
copy_valueyCopy the exact normalized text

Normalization Result

Context: normalization_result.

CommandKeysAction
quitqQuit
closeEscReturn to normalization comparison
backBackspaceReturn to normalization comparison
move_upk, UpSelect the previous code point
move_downj, DownSelect the next code point
firstgSelect the first code point
lastGSelect the last code point
activateEnterInspect the selected code point

Use Backspace in the Inspector to return to this result.

Browse Lists

Contexts: browse_plane, browse_range, and browse_block.

CommandKeysAction
quitqQuit
closeEscCancel browsing and return to the Inspector
backBackspaceReturn to the previous browse level, or to the Inspector at the top
move_upk, UpSelect the previous item
move_downj, DownSelect the next item
firstgSelect the first item
lastGSelect the last item
activateEnterOpen ranges in a plane, or code points in a range or block

browse_range and browse_block additionally support:

CommandKeysAction
page_upCtrl-UMove backward by a large step
page_downCtrl-DMove forward by a large step

Browse Code Points

Context: browse_code_points.

CommandKeysAction
quitqQuit
closeEscCancel browsing and return to the Inspector
backBackspaceReturn to the previous browse level
move_lefth, LeftMove left
move_rightl, RightMove right
move_upk, UpMove up one row
move_downj, DownMove down one row
page_upCtrl-UMove backward by a large step
page_downCtrl-DMove forward by a large step
firstgSelect the first code point in the range or block
lastGSelect the last code point in the range or block
activateEnterInspect the selected code point

Help

Context: help. The underlying screen's commands are inactive while help is open; global bindings remain active.

CommandKeysAction
closeEscClose help
move_upk, UpScroll up one line
move_downj, DownScroll down one line
page_upCtrl-UScroll up one page
page_downCtrl-DScroll down one page
firstgGo to the beginning
lastGGo 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

ContextApplies to
globalEvery screen; supports quit and help
inspectorCode point properties
searchSearch results
sequenceThe original input sequence
normalizationNormalization form comparison
normalization_resultA normalized sequence
browse_planePlane list
browse_rangeRange list
browse_blockBlock list
browse_code_pointsCode point grid
helpContextual 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

NameKey
spaceSpace
enterEnter
escEscape
tabTab
backspaceBackspace
deleteDelete
left, right, up, downLeft, Right, Up, Down
home, endHome and End
pageup, pagedownPage Up and Page Down
f1 through f12F1 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 G and shift-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

Inspector

Properties

SectionFields
IdentityCharacter, Code Point, Primary Name, Aliases, Plane, Block
ClassificationGeneral Category, Script, Age, East Asian Width, Canonical Combining Class, Bidi Class, Default Ignorable
EncodingUTF-8, UTF-16, HTML Decimal, HTML Hex, Rust char, Unicode Escape
NormalizationDecomposition Type, Decomposition
DataUnicode 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

KeysAction
h / l, Left / RightInspect the previous / next code point
j / k, Down / UpSelect a property
Ctrl-U / Ctrl-DMove through properties by page
g / GSelect the first / last property
yCopy the selected value
/Open Search
p, r, b, cOpen Browse at the corresponding level
BackspaceReturn to the original or normalized sequence, when one is open
q, EscQuit

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.

Search results

Queries

QueryBehavior
あFind the literal character
AFind the letter A
U+2192Find that code point
U+AFind U+000A
2192Find that code point and matching names or aliases
arrowMatch Unicode names and formal aliases containing the query
LFFind 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

KeysAction
Up / Down, Ctrl-P / Ctrl-NSelect the previous / next result
EnterOpen the selected result in the Inspector
EscClose Search
F1Open contextual help
Ctrl-CQuit

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:

KeyStarting view
pPlanes
rRanges in the current plane
bBlocks
cCode 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.

Plane browser

Range browser

Code point browser

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.

Block browser

Block code point browser

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.

Sequence and normalization demo

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:

ClusterCode 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

Sequence

  • 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 CP and GC in 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

KeysAction
j / k, Down / UpSelect a code point
g / GSelect the first / last code point
EnterOpen the selected code point in the Inspector
nCompare normalization forms
q, EscQuit

Sequence Inspector

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'

Normalization comparison

Forms

FormTransformation
NFCCanonical decomposition followed by canonical composition
NFDCanonical decomposition
NFKCCompatibility decomposition followed by canonical composition
NFKDCompatibility 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:

InputFormResult
A + U+0301NFCÁ (U+00C1)
Á (U+00C1)NFDA + U+0301
① (U+2460)NFKC1 (U+0031)
ffi (U+FB03)NFKDffi

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.

Normalization result

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

KeysIn form comparisonIn a result list
j / k, Down / UpSelect a formSelect a code point
g / GSelect NFC / NFKDSelect the first / last code point
EnterOpen the selected resultInspect the selected code point
yCopy the exact normalized text—
Backspace, EscReturn to the original sequenceReturn to form comparison
qQuitQuit

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_FILE or 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.