From dda05419bd26a84cee33eb924e172d8fa52cbeec Mon Sep 17 00:00:00 2001 From: Kyosuke Fujimoto Date: Mon, 5 Oct 2026 08:40:45 +0900 Subject: [PATCH 01/23] docs: add mdBook setup and introduction --- docs/.gitignore | 1 + docs/book.toml | 11 +++++++++ docs/src/SUMMARY.md | 3 +++ docs/src/introduction/index.md | 42 ++++++++++++++++++++++++++++++++++ 4 files changed, 57 insertions(+) create mode 100644 docs/.gitignore create mode 100644 docs/book.toml create mode 100644 docs/src/SUMMARY.md create mode 100644 docs/src/introduction/index.md diff --git a/docs/.gitignore b/docs/.gitignore new file mode 100644 index 0000000..7585238 --- /dev/null +++ b/docs/.gitignore @@ -0,0 +1 @@ +book diff --git a/docs/book.toml b/docs/book.toml new file mode 100644 index 0000000..19ea61e --- /dev/null +++ b/docs/book.toml @@ -0,0 +1,11 @@ +[book] +authors = ["Kyosuke Fujimoto"] +language = "en" +src = "src" +title = "Sauva" +description = "Sauva Documentation" + +[output.html] +git-repository-url = "https://github.com/lusingander/sauva" +site-url = "/sauva/" +default-theme = "rust" diff --git a/docs/src/SUMMARY.md b/docs/src/SUMMARY.md new file mode 100644 index 0000000..7d92940 --- /dev/null +++ b/docs/src/SUMMARY.md @@ -0,0 +1,3 @@ +# Summary + +- [Introduction](./introduction/index.md) diff --git a/docs/src/introduction/index.md b/docs/src/introduction/index.md new file mode 100644 index 0000000..ff7d938 --- /dev/null +++ b/docs/src/introduction/index.md @@ -0,0 +1,42 @@ +# 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](https://raw.githubusercontent.com/lusingander/sauva/refs/heads/master/img/demo.gif) + +## 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. + +## Text Analysis + +Pass a string to open Sequence mode: + +```sh +sauva 'Á👩‍💻' +``` + +The sequence can be inspected one code point at a time or compared with its NFC, NFD, NFKC, and NFKD normalized forms. + +![Sequence and normalization demo](https://raw.githubusercontent.com/lusingander/sauva/refs/heads/master/img/demo-sequence.gif) + +## 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](https://github.com/ratatui/ratatui). +Sauva is available on [GitHub](https://github.com/lusingander/sauva) under the [MIT License](https://github.com/lusingander/sauva/blob/master/LICENSE). + +The generated Unicode data is distributed under the [Unicode License v3](https://github.com/lusingander/sauva/blob/master/UNICODE-LICENSE.txt). See the [third-party notices](https://github.com/lusingander/sauva/blob/master/THIRD_PARTY_NOTICES.md) for details. From 378d620454c864257ed8b5bc6217f81f944b89e7 Mon Sep 17 00:00:00 2001 From: Kyosuke Fujimoto Date: Mon, 5 Oct 2026 08:41:26 +0900 Subject: [PATCH 02/23] docs: add getting started overview --- docs/src/SUMMARY.md | 1 + docs/src/getting-started/index.md | 7 +++++++ 2 files changed, 8 insertions(+) create mode 100644 docs/src/getting-started/index.md diff --git a/docs/src/SUMMARY.md b/docs/src/SUMMARY.md index 7d92940..307e320 100644 --- a/docs/src/SUMMARY.md +++ b/docs/src/SUMMARY.md @@ -1,3 +1,4 @@ # Summary - [Introduction](./introduction/index.md) +- [Getting Started](./getting-started/index.md) diff --git a/docs/src/getting-started/index.md b/docs/src/getting-started/index.md new file mode 100644 index 0000000..80bbca1 --- /dev/null +++ b/docs/src/getting-started/index.md @@ -0,0 +1,7 @@ +# Getting Started + +- [Requirements](./requirements.md): supported systems and terminal requirements. +- [Installation](./installation.md): install with Cargo, Homebrew, or a release binary. +- [Basic Usage](./basic-usage.md): inspect a character or analyze a string. +- [Command Line Options](./command-line-options.md): input formats and startup options. +- [Compatibility](./compatibility.md): terminal graphics and system fonts. From 77e63fd3bded7e541ea5a92faf68f46cc2e150c4 Mon Sep 17 00:00:00 2001 From: Kyosuke Fujimoto Date: Mon, 5 Oct 2026 08:41:26 +0900 Subject: [PATCH 03/23] docs: add requirements page --- docs/src/SUMMARY.md | 1 + docs/src/getting-started/requirements.md | 23 +++++++++++++++++++++++ 2 files changed, 24 insertions(+) create mode 100644 docs/src/getting-started/requirements.md diff --git a/docs/src/SUMMARY.md b/docs/src/SUMMARY.md index 307e320..94f133f 100644 --- a/docs/src/SUMMARY.md +++ b/docs/src/SUMMARY.md @@ -2,3 +2,4 @@ - [Introduction](./introduction/index.md) - [Getting Started](./getting-started/index.md) + - [Requirements](./getting-started/requirements.md) diff --git a/docs/src/getting-started/requirements.md b/docs/src/getting-started/requirements.md new file mode 100644 index 0000000..c4ab906 --- /dev/null +++ b/docs/src/getting-started/requirements.md @@ -0,0 +1,23 @@ +# 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](./compatibility.md) 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. From a43a82089a8b717e5bc6f4a08910c89002328bdd Mon Sep 17 00:00:00 2001 From: Kyosuke Fujimoto Date: Mon, 5 Oct 2026 08:41:26 +0900 Subject: [PATCH 04/23] docs: add installation page --- docs/src/SUMMARY.md | 1 + docs/src/getting-started/installation.md | 40 ++++++++++++++++++++++++ 2 files changed, 41 insertions(+) create mode 100644 docs/src/getting-started/installation.md diff --git a/docs/src/SUMMARY.md b/docs/src/SUMMARY.md index 94f133f..d5a1c59 100644 --- a/docs/src/SUMMARY.md +++ b/docs/src/SUMMARY.md @@ -3,3 +3,4 @@ - [Introduction](./introduction/index.md) - [Getting Started](./getting-started/index.md) - [Requirements](./getting-started/requirements.md) + - [Installation](./getting-started/installation.md) diff --git a/docs/src/getting-started/installation.md b/docs/src/getting-started/installation.md new file mode 100644 index 0000000..34afda8 --- /dev/null +++ b/docs/src/getting-started/installation.md @@ -0,0 +1,40 @@ +# Installation + +## Cargo + +Install from [crates.io](https://crates.io/crates/sauva): + +```sh +cargo install --locked sauva +``` + +See [Requirements](./requirements.md) for the minimum Rust version. + +## Homebrew (macOS) + +```sh +brew install lusingander/tap/sauva +``` + +The formula is available in [lusingander/homebrew-tap](https://github.com/lusingander/homebrew-tap/blob/master/sauva.rb). + +## Release Binaries + +Download an archive for your operating system and architecture from the [releases page](https://github.com/lusingander/sauva/releases). + +| 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 + +```sh +sauva --version +``` + +Continue with [Basic Usage](./basic-usage.md). From d55199e83b8fe5193d846858191ee5b9f6b1c8f2 Mon Sep 17 00:00:00 2001 From: Kyosuke Fujimoto Date: Mon, 5 Oct 2026 08:41:26 +0900 Subject: [PATCH 05/23] docs: add basic usage page --- docs/src/SUMMARY.md | 1 + docs/src/getting-started/basic-usage.md | 64 +++++++++++++++++++++++++ 2 files changed, 65 insertions(+) create mode 100644 docs/src/getting-started/basic-usage.md diff --git a/docs/src/SUMMARY.md b/docs/src/SUMMARY.md index d5a1c59..fd3942b 100644 --- a/docs/src/SUMMARY.md +++ b/docs/src/SUMMARY.md @@ -4,3 +4,4 @@ - [Getting Started](./getting-started/index.md) - [Requirements](./getting-started/requirements.md) - [Installation](./getting-started/installation.md) + - [Basic Usage](./getting-started/basic-usage.md) diff --git a/docs/src/getting-started/basic-usage.md b/docs/src/getting-started/basic-usage.md new file mode 100644 index 0000000..2be9455 --- /dev/null +++ b/docs/src/getting-started/basic-usage.md @@ -0,0 +1,64 @@ +# Basic Usage + +## Inspect a Code Point + +Run Sauva without arguments to open the default code point: + +```sh +sauva +``` + +You can also specify a character or code point: + +```sh +sauva あ +sauva U+2192 +sauva 0x1F600 +``` + +The [Inspector](../features/inspector.md) 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](../features/search.md), or `p`, `r`, `b`, or `c` to [browse](../features/browse.md). +- 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](../features/sequence.md) mode: + +```sh +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](../features/normalization.md). + +![Sequence and normalization demo](https://raw.githubusercontent.com/lusingander/sauva/refs/heads/master/img/demo-sequence.gif) + +Use `--text` when a string would otherwise be interpreted as code point notation: + +```sh +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: + +```sh +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](./command-line-options.md). The complete controls are listed in [Keybindings](../keybindings/index.md). From 6eb473aedc06b0704860ce6dcc44766b216d38b2 Mon Sep 17 00:00:00 2001 From: Kyosuke Fujimoto Date: Mon, 5 Oct 2026 08:41:26 +0900 Subject: [PATCH 06/23] docs: add command line reference --- docs/src/SUMMARY.md | 1 + .../getting-started/command-line-options.md | 100 ++++++++++++++++++ 2 files changed, 101 insertions(+) create mode 100644 docs/src/getting-started/command-line-options.md diff --git a/docs/src/SUMMARY.md b/docs/src/SUMMARY.md index fd3942b..241b36f 100644 --- a/docs/src/SUMMARY.md +++ b/docs/src/SUMMARY.md @@ -5,3 +5,4 @@ - [Requirements](./getting-started/requirements.md) - [Installation](./getting-started/installation.md) - [Basic Usage](./getting-started/basic-usage.md) + - [Command Line Options](./getting-started/command-line-options.md) diff --git a/docs/src/getting-started/command-line-options.md b/docs/src/getting-started/command-line-options.md new file mode 100644 index 0000000..a9ad766 --- /dev/null +++ b/docs/src/getting-started/command-line-options.md @@ -0,0 +1,100 @@ +# Command Line Options + +```text +Sauva - Terminal Unicode Explorer 🪄 + +Usage: sauva [OPTIONS] [INPUT] + +Arguments: + [INPUT] Text or code point to inspect, or - to read stdin + +Options: + -t, --text Treat the input as literal text, without code point notation parsing; - reads stdin + -g, --graphics 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`. + +| 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 ` + +Treat the input as literal text without parsing code point notation: + +```sh +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. + +```sh +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 | 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](./compatibility.md) for support details. + +## `--print-default-config` + +Print the complete built-in configuration, including default keybindings, and exit: + +```sh +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](../configurations/index.md) for where to put the file. + +## `-h, --help` and `-V, --version` + +Print command line help or the installed application version and exit. From 8440805058b80f88092a26a04f4537d43283806d Mon Sep 17 00:00:00 2001 From: Kyosuke Fujimoto Date: Mon, 5 Oct 2026 08:41:27 +0900 Subject: [PATCH 07/23] docs: add compatibility page --- docs/src/SUMMARY.md | 1 + docs/src/getting-started/compatibility.md | 54 +++++++++++++++++++++++ 2 files changed, 55 insertions(+) create mode 100644 docs/src/getting-started/compatibility.md diff --git a/docs/src/SUMMARY.md b/docs/src/SUMMARY.md index 241b36f..c249551 100644 --- a/docs/src/SUMMARY.md +++ b/docs/src/SUMMARY.md @@ -6,3 +6,4 @@ - [Installation](./getting-started/installation.md) - [Basic Usage](./getting-started/basic-usage.md) - [Command Line Options](./getting-started/command-line-options.md) + - [Compatibility](./getting-started/compatibility.md) diff --git a/docs/src/getting-started/compatibility.md b/docs/src/getting-started/compatibility.md new file mode 100644 index 0000000..f0101ee --- /dev/null +++ b/docs/src/getting-started/compatibility.md @@ -0,0 +1,54 @@ +# Compatibility + +## Operating Systems + +macOS and Linux are supported. Windows is not currently supported. + +## Terminal Graphics + +Sauva uses the [Kitty graphics protocol](https://sw.kovidgoyal.net/kitty/graphics-protocol/) with [Unicode placeholders](https://sw.kovidgoyal.net/kitty/graphics-protocol/#unicode-placeholders) for glyph images. + +| Terminal | Graphics mode | Support | +| --- | --- | --- | +| [kitty](https://sw.kovidgoyal.net/kitty/) | `auto` | Supported | +| [Ghostty](https://ghostty.org) | `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: + +```sh +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](https://iterm2.com/documentation-images.html) is available only when selected explicitly: + +```sh +sauva --graphics iterm2 +``` + +Sixel is not implemented. To disable images, use: + +```sh +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](../configurations/glyph-preview.md) 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](./requirements.md) for the minimum size. From 557ac74cbfb954130dd66de9915bc36896955fee Mon Sep 17 00:00:00 2001 From: Kyosuke Fujimoto Date: Mon, 5 Oct 2026 08:41:27 +0900 Subject: [PATCH 08/23] docs: add configuration overview --- docs/src/SUMMARY.md | 1 + docs/src/configurations/index.md | 49 ++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+) create mode 100644 docs/src/configurations/index.md diff --git a/docs/src/SUMMARY.md b/docs/src/SUMMARY.md index c249551..dd2c54f 100644 --- a/docs/src/SUMMARY.md +++ b/docs/src/SUMMARY.md @@ -7,3 +7,4 @@ - [Basic Usage](./getting-started/basic-usage.md) - [Command Line Options](./getting-started/command-line-options.md) - [Compatibility](./getting-started/compatibility.md) +- [Configurations](./configurations/index.md) diff --git a/docs/src/configurations/index.md b/docs/src/configurations/index.md new file mode 100644 index 0000000..34ad82a --- /dev/null +++ b/docs/src/configurations/index.md @@ -0,0 +1,49 @@ +# 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: + +```sh +sauva --print-default-config +``` + +To create a file at the default location when `XDG_CONFIG_HOME` is unset: + +```sh +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: + +```sh +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](./config-file-format.md): all configuration sections, values, and defaults. +- [Glyph Preview](./glyph-preview.md): font selection and image colors. +- [Custom Keybindings](../keybindings/custom-keybindings.md): command bindings for each screen. From 67e36545200c273bc1ce8c3a2113ab8454551503 Mon Sep 17 00:00:00 2001 From: Kyosuke Fujimoto Date: Mon, 5 Oct 2026 08:41:27 +0900 Subject: [PATCH 09/23] docs: add configuration reference --- docs/src/SUMMARY.md | 1 + docs/src/configurations/config-file-format.md | 141 ++++++++++++++++++ 2 files changed, 142 insertions(+) create mode 100644 docs/src/configurations/config-file-format.md diff --git a/docs/src/SUMMARY.md b/docs/src/SUMMARY.md index dd2c54f..efe9ce5 100644 --- a/docs/src/SUMMARY.md +++ b/docs/src/SUMMARY.md @@ -8,3 +8,4 @@ - [Command Line Options](./getting-started/command-line-options.md) - [Compatibility](./getting-started/compatibility.md) - [Configurations](./configurations/index.md) + - [Config File Format](./configurations/config-file-format.md) diff --git a/docs/src/configurations/config-file-format.md b/docs/src/configurations/config-file-format.md new file mode 100644 index 0000000..7b2275c --- /dev/null +++ b/docs/src/configurations/config-file-format.md @@ -0,0 +1,141 @@ +# Config File Format + +All configuration settings are optional. The following example contains the default colors, glyph preview settings, and UI settings: + +```toml +[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](https://github.com/lusingander/sauva/blob/master/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`, 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: + +```toml +[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](./glyph-preview.md) 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. + +```toml +[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. + +```toml +[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. + +```toml +[keybindings.global] +help = ["f2"] + +[keybindings.inspector] +next_code_point = ["l", "right", "n"] +browse_planes = [] +``` + +See [Custom Keybindings](../keybindings/custom-keybindings.md) for contexts, command names, key formats, and validation rules. From abb3ed7c27a300448e73f83b96f859e7a9478ce4 Mon Sep 17 00:00:00 2001 From: Kyosuke Fujimoto Date: Mon, 5 Oct 2026 08:41:27 +0900 Subject: [PATCH 10/23] docs: add glyph preview configuration guide --- docs/src/SUMMARY.md | 1 + docs/src/configurations/glyph-preview.md | 59 ++++++++++++++++++++++++ 2 files changed, 60 insertions(+) create mode 100644 docs/src/configurations/glyph-preview.md diff --git a/docs/src/SUMMARY.md b/docs/src/SUMMARY.md index efe9ce5..d054af7 100644 --- a/docs/src/SUMMARY.md +++ b/docs/src/SUMMARY.md @@ -9,3 +9,4 @@ - [Compatibility](./getting-started/compatibility.md) - [Configurations](./configurations/index.md) - [Config File Format](./configurations/config-file-format.md) + - [Glyph Preview](./configurations/glyph-preview.md) diff --git a/docs/src/configurations/glyph-preview.md b/docs/src/configurations/glyph-preview.md new file mode 100644 index 0000000..38a48d1 --- /dev/null +++ b/docs/src/configurations/glyph-preview.md @@ -0,0 +1,59 @@ +# 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: + +```toml +[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](../getting-started/compatibility.md). + +## 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: + +```toml +[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](../faq/index.md) for troubleshooting. From 4d780790672c5342a59e9cca2405b79971f8da79 Mon Sep 17 00:00:00 2001 From: Kyosuke Fujimoto Date: Mon, 5 Oct 2026 08:41:27 +0900 Subject: [PATCH 11/23] docs: add default keybindings reference --- docs/src/SUMMARY.md | 1 + docs/src/keybindings/index.md | 152 ++++++++++++++++++++++++++++++++++ 2 files changed, 153 insertions(+) create mode 100644 docs/src/keybindings/index.md diff --git a/docs/src/SUMMARY.md b/docs/src/SUMMARY.md index d054af7..697530e 100644 --- a/docs/src/SUMMARY.md +++ b/docs/src/SUMMARY.md @@ -10,3 +10,4 @@ - [Configurations](./configurations/index.md) - [Config File Format](./configurations/config-file-format.md) - [Glyph Preview](./configurations/glyph-preview.md) +- [Keybindings](./keybindings/index.md) diff --git a/docs/src/keybindings/index.md b/docs/src/keybindings/index.md new file mode 100644 index 0000000..921733a --- /dev/null +++ b/docs/src/keybindings/index.md @@ -0,0 +1,152 @@ +# 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](./custom-keybindings.md). + +## 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 | From 177ea922c74cc3c54554e1aeda90e1e77047c95a Mon Sep 17 00:00:00 2001 From: Kyosuke Fujimoto Date: Mon, 5 Oct 2026 08:41:27 +0900 Subject: [PATCH 12/23] docs: add custom keybindings guide --- docs/src/SUMMARY.md | 1 + docs/src/keybindings/custom-keybindings.md | 100 +++++++++++++++++++++ 2 files changed, 101 insertions(+) create mode 100644 docs/src/keybindings/custom-keybindings.md diff --git a/docs/src/SUMMARY.md b/docs/src/SUMMARY.md index 697530e..c4dcd64 100644 --- a/docs/src/SUMMARY.md +++ b/docs/src/SUMMARY.md @@ -11,3 +11,4 @@ - [Config File Format](./configurations/config-file-format.md) - [Glyph Preview](./configurations/glyph-preview.md) - [Keybindings](./keybindings/index.md) + - [Custom Keybindings](./keybindings/custom-keybindings.md) diff --git a/docs/src/keybindings/custom-keybindings.md b/docs/src/keybindings/custom-keybindings.md new file mode 100644 index 0000000..3df4d96 --- /dev/null +++ b/docs/src/keybindings/custom-keybindings.md @@ -0,0 +1,100 @@ +# Custom Keybindings + +Customize bindings in the `[keybindings.]` sections of [the configuration file](../configurations/index.md). + +```toml +[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](./index.md). + +## 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` describe the same key. + +### Named Keys + +| Name | Key | +| --- | --- | +| `space` | Space | +| `enter` | Enter | +| `esc` | Escape | +| `tab` | Tab | +| `backspace` | Backspace | +| `delete` | Delete | +| `left`, `right`, `up`, `down` | Arrow keys | +| `home`, `end` | Home and End | +| `pageup`, `pagedown` | Page Up and Page Down | +| `f1` through `f12` | Function keys | + +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: + +```toml +[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: + +```toml +[keybindings.inspector] +next_code_point = ["right"] +copy_value = ["y", "l"] +``` From 5c51e2cd64f013af5fcedd9f57481b4ca536add4 Mon Sep 17 00:00:00 2001 From: Kyosuke Fujimoto Date: Mon, 5 Oct 2026 08:41:27 +0900 Subject: [PATCH 13/23] docs: add features overview --- docs/src/SUMMARY.md | 1 + docs/src/features/index.md | 9 +++++++++ 2 files changed, 10 insertions(+) create mode 100644 docs/src/features/index.md diff --git a/docs/src/SUMMARY.md b/docs/src/SUMMARY.md index c4dcd64..8c01f58 100644 --- a/docs/src/SUMMARY.md +++ b/docs/src/SUMMARY.md @@ -12,3 +12,4 @@ - [Glyph Preview](./configurations/glyph-preview.md) - [Keybindings](./keybindings/index.md) - [Custom Keybindings](./keybindings/custom-keybindings.md) +- [Features](./features/index.md) diff --git a/docs/src/features/index.md b/docs/src/features/index.md new file mode 100644 index 0000000..109c04e --- /dev/null +++ b/docs/src/features/index.md @@ -0,0 +1,9 @@ +# Features + +- [Inspector](./inspector.md): inspect one code point and copy its properties. +- [Search](./search.md): find a character by value, name, or formal alias. +- [Browse](./browse.md): explore planes, ranges, blocks, and code points. +- [Sequence](./sequence.md): examine a string's code points and grapheme clusters. +- [Normalization](./normalization.md): compare and inspect normalized text. + +Press `F1` in any screen for contextual help. See [Keybindings](../keybindings/index.md) for the complete controls. From a084d00844be1d62c14166109025c8cb7a6be298 Mon Sep 17 00:00:00 2001 From: Kyosuke Fujimoto Date: Mon, 5 Oct 2026 08:41:27 +0900 Subject: [PATCH 14/23] docs: add inspector guide --- docs/src/SUMMARY.md | 1 + docs/src/features/inspector.md | 57 ++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+) create mode 100644 docs/src/features/inspector.md diff --git a/docs/src/SUMMARY.md b/docs/src/SUMMARY.md index 8c01f58..e99172d 100644 --- a/docs/src/SUMMARY.md +++ b/docs/src/SUMMARY.md @@ -13,3 +13,4 @@ - [Keybindings](./keybindings/index.md) - [Custom Keybindings](./keybindings/custom-keybindings.md) - [Features](./features/index.md) + - [Inspector](./features/inspector.md) diff --git a/docs/src/features/inspector.md b/docs/src/features/inspector.md new file mode 100644 index 0000000..0c45678 --- /dev/null +++ b/docs/src/features/inspector.md @@ -0,0 +1,57 @@ +# 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. + +```sh +sauva あ +sauva U+2192 +``` + +![Inspector](https://raw.githubusercontent.com/lusingander/sauva/refs/heads/master/img/inspector.png) + +## 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](./normalization.md) from Sequence. + +The glyph panel renders the selected code point and shows the font used, when space is available. See [Glyph Preview](../configurations/glyph-preview.md) 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 `` 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. From 5c3d21191ccaee44791650353898997afb0c6f75 Mon Sep 17 00:00:00 2001 From: Kyosuke Fujimoto Date: Mon, 5 Oct 2026 08:41:28 +0900 Subject: [PATCH 15/23] docs: add search guide --- docs/src/SUMMARY.md | 1 + docs/src/features/search.md | 43 +++++++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+) create mode 100644 docs/src/features/search.md diff --git a/docs/src/SUMMARY.md b/docs/src/SUMMARY.md index e99172d..e78c448 100644 --- a/docs/src/SUMMARY.md +++ b/docs/src/SUMMARY.md @@ -14,3 +14,4 @@ - [Custom Keybindings](./keybindings/custom-keybindings.md) - [Features](./features/index.md) - [Inspector](./features/inspector.md) + - [Search](./features/search.md) diff --git a/docs/src/features/search.md b/docs/src/features/search.md new file mode 100644 index 0000000..8459e46 --- /dev/null +++ b/docs/src/features/search.md @@ -0,0 +1,43 @@ +# Search + +Press `/` in the Inspector to search by character, code point, Unicode name, or formal name alias. + +![Search results](https://raw.githubusercontent.com/lusingander/sauva/refs/heads/master/img/filter.png) + +## 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](../getting-started/command-line-options.md): 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. From ac05c413d73a95a021207470b2484dec9ae7d85a Mon Sep 17 00:00:00 2001 From: Kyosuke Fujimoto Date: Mon, 5 Oct 2026 08:41:28 +0900 Subject: [PATCH 16/23] docs: add browse guide --- docs/src/SUMMARY.md | 1 + docs/src/features/browse.md | 52 +++++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+) create mode 100644 docs/src/features/browse.md diff --git a/docs/src/SUMMARY.md b/docs/src/SUMMARY.md index e78c448..4bf4894 100644 --- a/docs/src/SUMMARY.md +++ b/docs/src/SUMMARY.md @@ -15,3 +15,4 @@ - [Features](./features/index.md) - [Inspector](./features/inspector.md) - [Search](./features/search.md) + - [Browse](./features/browse.md) diff --git a/docs/src/features/browse.md b/docs/src/features/browse.md new file mode 100644 index 0000000..3938782 --- /dev/null +++ b/docs/src/features/browse.md @@ -0,0 +1,52 @@ +# 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: + +```text +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](https://raw.githubusercontent.com/lusingander/sauva/refs/heads/master/img/plane.png) + +![Range browser](https://raw.githubusercontent.com/lusingander/sauva/refs/heads/master/img/range.png) + +![Code point browser](https://raw.githubusercontent.com/lusingander/sauva/refs/heads/master/img/code-points.png) + +## Blocks + +This path explores named blocks from the Unicode Character Database: + +```text +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](https://raw.githubusercontent.com/lusingander/sauva/refs/heads/master/img/block.png) + +![Block code point browser](https://raw.githubusercontent.com/lusingander/sauva/refs/heads/master/img/block-code-points.png) + +## 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. From 5aaf76d89bae7c99c8716993d501d01e22bd53b8 Mon Sep 17 00:00:00 2001 From: Kyosuke Fujimoto Date: Mon, 5 Oct 2026 08:41:28 +0900 Subject: [PATCH 17/23] docs: add sequence guide --- docs/src/SUMMARY.md | 1 + docs/src/features/sequence.md | 70 +++++++++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+) create mode 100644 docs/src/features/sequence.md diff --git a/docs/src/SUMMARY.md b/docs/src/SUMMARY.md index 4bf4894..837118c 100644 --- a/docs/src/SUMMARY.md +++ b/docs/src/SUMMARY.md @@ -16,3 +16,4 @@ - [Inspector](./features/inspector.md) - [Search](./features/search.md) - [Browse](./features/browse.md) + - [Sequence](./features/sequence.md) diff --git a/docs/src/features/sequence.md b/docs/src/features/sequence.md new file mode 100644 index 0000000..09f11f8 --- /dev/null +++ b/docs/src/features/sequence.md @@ -0,0 +1,70 @@ +# 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: + +```sh +sauva 'Á👩‍💻' +``` + +Use `--text` to prevent code point notation parsing: + +```sh +sauva --text 41 +sauva --text U+2192 +``` + +Read text from a pipe or file: + +```sh +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](../getting-started/command-line-options.md) for the complete input rules. + +![Sequence and normalization demo](https://raw.githubusercontent.com/lusingander/sauva/refs/heads/master/img/demo-sequence.gif) + +## 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](https://www.unicode.org/reports/tr29/). + +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 + +![Sequence](https://raw.githubusercontent.com/lusingander/sauva/refs/heads/master/img/sequence.png) + +- 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 + +| 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 | + +![Sequence Inspector](https://raw.githubusercontent.com/lusingander/sauva/refs/heads/master/img/sequence-inspector.png) + +Backspace in the Inspector returns to the sequence. From Sequence, press `n` to open [Normalization](./normalization.md). From 737159aa6b8b2b76948babf2965eeb421744caa2 Mon Sep 17 00:00:00 2001 From: Kyosuke Fujimoto Date: Mon, 5 Oct 2026 08:41:28 +0900 Subject: [PATCH 18/23] docs: add normalization guide --- docs/src/SUMMARY.md | 1 + docs/src/features/normalization.md | 65 ++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+) create mode 100644 docs/src/features/normalization.md diff --git a/docs/src/SUMMARY.md b/docs/src/SUMMARY.md index 837118c..5e5baab 100644 --- a/docs/src/SUMMARY.md +++ b/docs/src/SUMMARY.md @@ -17,3 +17,4 @@ - [Search](./features/search.md) - [Browse](./features/browse.md) - [Sequence](./features/sequence.md) + - [Normalization](./features/normalization.md) diff --git a/docs/src/features/normalization.md b/docs/src/features/normalization.md new file mode 100644 index 0000000..1dc7fcf --- /dev/null +++ b/docs/src/features/normalization.md @@ -0,0 +1,65 @@ +# Normalization + +From [Sequence](./sequence.md), press `n` to compare the input with its NFC, NFD, NFKC, and NFKD normalized forms. + +```sh +sauva 'Á①ffi' +``` + +![Normalization comparison](https://raw.githubusercontent.com/lusingander/sauva/refs/heads/master/img/sequence-normalization.png) + +## 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](https://www.unicode.org/reports/tr15/) 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. + +![Normalization result](https://raw.githubusercontent.com/lusingander/sauva/refs/heads/master/img/sequence-normalization-result.png) + +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. From d80412a483f5248829a9789cfc9c4da8215c6a4e Mon Sep 17 00:00:00 2001 From: Kyosuke Fujimoto Date: Mon, 5 Oct 2026 08:41:28 +0900 Subject: [PATCH 19/23] docs: add frequently asked questions --- docs/src/SUMMARY.md | 1 + docs/src/faq/index.md | 79 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 80 insertions(+) create mode 100644 docs/src/faq/index.md diff --git a/docs/src/SUMMARY.md b/docs/src/SUMMARY.md index 5e5baab..3e05f04 100644 --- a/docs/src/SUMMARY.md +++ b/docs/src/SUMMARY.md @@ -18,3 +18,4 @@ - [Browse](./features/browse.md) - [Sequence](./features/sequence.md) - [Normalization](./features/normalization.md) +- [FAQ](./faq/index.md) diff --git a/docs/src/faq/index.md b/docs/src/faq/index.md new file mode 100644 index 0000000..f72c549 --- /dev/null +++ b/docs/src/faq/index.md @@ -0,0 +1,79 @@ +# FAQ + +## Why is the glyph preview missing? + +First, check [Compatibility](../getting-started/compatibility.md). 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](../configurations/glyph-preview.md). +- **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](../configurations/glyph-preview.md). + +## 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](../getting-started/command-line-options.md) and [Search](../features/search.md). + +## 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: + +```sh +printf 'U+2192' | sauva - +``` + +To examine the literal text and its newline, use: + +```sh +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](../features/sequence.md) 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](../configurations/index.md) and [Custom Keybindings](../keybindings/custom-keybindings.md). + +## 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. From ba3587cf39e2d347b53fbb56bd5125261d957bbe Mon Sep 17 00:00:00 2001 From: Kyosuke Fujimoto Date: Mon, 5 Oct 2026 08:41:49 +0900 Subject: [PATCH 20/23] ci: deploy documentation to GitHub Pages --- .github/workflows/gh-pages.yml | 52 ++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 .github/workflows/gh-pages.yml diff --git a/.github/workflows/gh-pages.yml b/.github/workflows/gh-pages.yml new file mode 100644 index 0000000..a26351a --- /dev/null +++ b/.github/workflows/gh-pages.yml @@ -0,0 +1,52 @@ +name: Deploy GitHub Pages + +on: + push: + branches: + - master + paths: + - docs/** + - .github/workflows/gh-pages.yml + workflow_dispatch: + +permissions: + contents: read + pages: write + id-token: write + +concurrency: + group: pages + cancel-in-progress: false + +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + - name: Setup Pages + uses: actions/configure-pages@45bfe0192ca1faeb007ade9deae92b16b8254a0d # v6.0.0 + - name: Install mdbook + run: | + curl --fail --location --silent --show-error \ + https://github.com/rust-lang/mdBook/releases/download/v0.4.52/mdbook-v0.4.52-x86_64-unknown-linux-gnu.tar.gz \ + --output "${RUNNER_TEMP}/mdbook.tar.gz" + tar -xzf "${RUNNER_TEMP}/mdbook.tar.gz" -C "${RUNNER_TEMP}" + echo "${RUNNER_TEMP}" >> "${GITHUB_PATH}" + - name: Build with mdbook + run: mdbook build docs + - name: Upload artifact + uses: actions/upload-pages-artifact@fc324d3547104276b827a68afc52ff2a11cc49c9 # v5.0.0 + with: + path: docs/book + + deploy: + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + runs-on: ubuntu-latest + needs: build + steps: + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@368f82528645a54fb793d4d04e342629a3f51346 # v5.0.1 From 2cb10d18e65a9e52306b98912076455a7910d551 Mon Sep 17 00:00:00 2001 From: Kyosuke Fujimoto Date: Mon, 5 Oct 2026 08:41:49 +0900 Subject: [PATCH 21/23] docs: link README to documentation and showcase Sequence --- Cargo.toml | 4 +- README.md | 265 +++++++++++++---------------------------------------- 2 files changed, 64 insertions(+), 205 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 3062da0..4fd5e19 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,7 @@ name = "sauva" version = "0.3.0" description = "Terminal Unicode Explorer" authors = ["Kyosuke Fujimoto "] -homepage = "https://github.com/lusingander/sauva" +homepage = "https://lusingander.github.io/sauva/" repository = "https://github.com/lusingander/sauva" readme = "README.md" license = "MIT" @@ -12,7 +12,7 @@ categories = ["command-line-utilities"] edition = "2024" rust-version = "1.88.0" -exclude = ["/.github", "/img", "/data", "/tools"] +exclude = ["/.github", "/docs", "/img", "/data", "/tools"] [dependencies] arboard = { version = "3.6.1", default-features = false, features = ["wayland-data-control"] } diff --git a/README.md b/README.md index 8d02c5d..45cc921 100644 --- a/README.md +++ b/README.md @@ -5,45 +5,71 @@ Terminal Unicode Explorer 🪄 - +Sauva browsing and search demo ## About Sauva is a terminal application for searching and browsing Unicode code points. It shows Unicode properties and a glyph preview in a responsive TUI. -The bundled data is based on Unicode 17.0.0. +- Inspect Unicode properties, encodings, and decomposition mappings. +- Search by character, code point, Unicode name, or formal name alias. +- Browse planes, ranges, blocks, and code points. +- Analyze strings by code point and grapheme cluster in Sequence mode. +- Compare NFC, NFD, NFKC, and NFKD normalization forms. +- Customize colors, glyph preview fonts, and keybindings. + +The bundled data is based on Unicode 17.0.0. See [Features](https://lusingander.github.io/sauva/features/) for details and screenshots. + +## Documentation + +For detailed usage, configuration, and terminal support, see the [full documentation](https://lusingander.github.io/sauva/). ## Installation -### [Cargo](https://crates.io/crates/sauva) +If you're using Cargo: -``` +```sh cargo install --locked sauva ``` -### [Homebrew (macOS)](https://github.com/lusingander/homebrew-tap/blob/master/sauva.rb) +Homebrew and pre-built binaries are also available. See [Installation](https://lusingander.github.io/sauva/getting-started/installation.html) for all options. -``` -brew install lusingander/tap/sauva -``` +## Usage -### Downloading a binary +### Inspect a code point -Pre-built binaries are available from the [releases page](https://github.com/lusingander/sauva/releases). +Run `sauva` without arguments, or specify a character or code point: -## Usage +```sh +sauva +sauva あ +sauva U+2192 +``` -### Basic +### Analyze text in Sequence mode -Run sauva without arguments to open the default code point: +Pass a string to inspect its code points and grapheme clusters: +```sh +sauva 'Á👩‍💻' ``` -sauva + +Press `Enter` to inspect a selected code point, or `n` to compare normalization forms. + +Sauva Sequence and normalization demo + +Use `--text` when the input would otherwise be interpreted as code point notation, or `--text -` to read literal UTF-8 text from stdin: + +```sh +sauva --text 41 +printf 'Á👩‍💻' | sauva --text - ``` +See [Sequence](https://lusingander.github.io/sauva/features/sequence.html), [Normalization](https://lusingander.github.io/sauva/features/normalization.html), and [Basic Usage](https://lusingander.github.io/sauva/getting-started/basic-usage.html) for more examples. + ### Options -``` +```text Sauva - Terminal Unicode Explorer 🪄 Usage: sauva [OPTIONS] [INPUT] @@ -59,208 +85,41 @@ Options: -V, --version Print version ``` -#### Specifying `INPUT` - -A single character can be inspected directly. Text sequences can be analyzed by code point and grapheme cluster, and compared with their NFC, NFD, NFKC, and NFKD normalized forms. - -``` -sauva あ -sauva 'Á👩‍💻' -``` - -Code points can also be given in `U+` notation, `0x` notation, or as two to six hexadecimal digits. - -``` -sauva U+2192 -sauva 0x1F600 -sauva 1F600 -``` - -A one-character argument is treated as the character itself. Use a prefix for a one-digit hexadecimal value, such as `U+A` or `0xA`. - -An input made entirely of hexadecimal digits keeps the code point interpretation. Use `--text` to force literal text when the input would otherwise be interpreted as notation: - -``` -sauva -t 41 -sauva --text U+2192 -``` - -Empty text is rejected. - -#### Reading from stdin - -Pass `-` to read the input from stdin. It accepts the same text and code point formats as `INPUT`. Use `--text -` (or `-t -`) to treat stdin as literal text without code point notation parsing. - -``` -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 opening the TUI. All whitespace, including trailing LF and CRLF, is preserved. For code point notation, use `printf` without a trailing newline: `echo U+2192 | sauva -` is rejected because the newline is part of the notation. Use `--text -` to inspect that input as literal text, including its newline. Empty input and invalid UTF-8 are rejected. - -Stdin is read only when `-` is explicitly specified. Keyboard input continues to come from the terminal, so an interactive terminal is still required. Since `-` selects stdin, use `sauva U+002D` to inspect the hyphen character itself. - -#### `-g, --graphics ` +For input interpretation, stdin handling, and graphics modes, see [Command Line Options](https://lusingander.github.io/sauva/getting-started/command-line-options.html). -- `auto` enables the Kitty graphics protocol for detected kitty and Ghostty terminals. -- `force` uses the Kitty graphics protocol without terminal detection. -- `iterm2` uses the iTerm2 inline image protocol. -- `off` disables glyph images. +### Keybindings -See [Compatibility](#compatibility) for terminal support. +| Key | Description | +| --- | --- | +| `F1` | Open or close contextual help | +| `Ctrl-C` | Quit from any view | +| `j` / `k` or arrow keys | Move the selection; use Up / Down in Search | +| `/` | Open Search from the Inspector | +| `p`, `r`, `b`, `c` | Open Browse from the Inspector | +| `Enter` | Open the selected item or inspect a code point | +| `Backspace` | Go back in Browse or return from the Inspector to its Sequence | +| `y` | Copy the selected Inspector value or normalization result | +| `n` | Compare normalization forms from Sequence | + +See [Keybindings](https://lusingander.github.io/sauva/keybindings/) for all controls and [Custom Keybindings](https://lusingander.github.io/sauva/keybindings/custom-keybindings.html) to customize them. ### Config -sauva loads the first applicable configuration path in this order: +Sauva loads the configuration selected by `SAUVA_CONFIG_FILE`, or `$XDG_CONFIG_HOME/sauva/config.toml` (using `~/.config` when `XDG_CONFIG_HOME` is unset or empty). -1. The path specified by `SAUVA_CONFIG_FILE` -2. `$XDG_CONFIG_HOME/sauva/config.toml` -3. `$HOME/.config/sauva/config.toml` +Print the complete built-in configuration with: -If the default file does not exist, built-in settings are used. A missing file specified by `SAUVA_CONFIG_FILE`, or an invalid configuration file, causes startup to fail. - -The complete built-in configuration can be printed without starting the TUI or loading a local configuration file: - -``` +```sh sauva --print-default-config -sauva --print-default-config > config.toml -``` - -All settings are optional. The following example shows the main configuration areas: - -
-Configuration example - -```toml -[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 = ["Iosevka", "Noto Sans"] -emoji_font_families = ["Noto Color Emoji"] -fg = "#f5f7fa" -bg = "#00000000" - -[ui] -selection_cursor = "▸" -input_cursor = { text = "|" } -``` - -UI colors accept ANSI color names, `#RRGGBB`, or an indexed color from `0` to `255`. Glyph image colors accept `#RRGGBB` and `#RRGGBBAA`. - -
- -The complete configuration structure and defaults are defined in [config.schema.json](config.schema.json). - -### Keybindings - -These are the main built-in controls. The available controls depend on the current view. - -| Key | Description | -| --- | --- | -| F1 | Open or close contextual help | -| Ctrl+c | Quit from any view | -| q | Quit from the Inspector, Sequence, or Browse view | -| Esc | Cancel or go back; quit from the Inspector or input Sequence | -| h j k l or arrow keys | Move the selection | -| / | Search by character, code point, Unicode name, or formal name alias | -| p r b c | Browse planes, ranges, blocks, or code points | -| Enter | Open the selected item; inspect a code point from Sequence or Browse | -| Backspace | Go back in Browse; return from Inspector to its Sequence | -| y | Copy the selected Inspector value | - -Press F1 to view all controls for the current screen. - -#### Custom keybindings - -Keybindings can be replaced per command and context. A command can have multiple keys, and an empty array disables it in that context. - -
-Keybinding example and syntax - -```toml -[keybindings.global] -help = ["f2"] - -[keybindings.inspector] -next_code_point = ["l", "right", "n"] -back = ["backspace"] -browse_planes = [] ``` -Keys may be a single character, a named key such as `enter`, `esc`, `left`, or `f1`, or a modifier followed by one character, such as `ctrl-n`, `alt-j`, or `shift-g`. Conflicting and invalid bindings are rejected at startup. - -See [config.schema.json](config.schema.json) for all contexts and command names. - -
+See [Configurations](https://lusingander.github.io/sauva/configurations/) and [Config File Format](https://lusingander.github.io/sauva/configurations/config-file-format.html) for settings and defaults. ## Compatibility -### Operating systems - -macOS and Linux are supported. macOS uses Core Text for system font lookup. Linux uses Fontconfig when available and falls back to a best-effort font database lookup if Fontconfig cannot be loaded. - -### Terminal emulators - -Glyph previews use the [Kitty graphics protocol](https://sw.kovidgoyal.net/kitty/graphics-protocol/) and its [Unicode placeholder](https://sw.kovidgoyal.net/kitty/graphics-protocol/#unicode-placeholders) feature. The supported terminals are: - -- [kitty](https://sw.kovidgoyal.net/kitty/) -- [Ghostty](https://ghostty.org) - -Use `--graphics force` to try the Kitty protocol in another compatible terminal or when automatic detection does not enable it. - -The [iTerm2 inline image protocol](https://iterm2.com/documentation-images.html) is available through `--graphics iterm2`, but compatibility and future support are not guaranteed. It is never selected automatically. - -### Glyph preview fonts - -Sauva does not bundle fonts. Available glyphs and the selected font therefore depend on the fonts installed on the system. - -For each code point, sauva tries configured normal fonts, the system default text font, configured emoji fonts, and then system fallback fonts. Preferred fonts can be set with `glyph_preview.font_families` and `glyph_preview.emoji_font_families`. - -## Screenshots - -### Inspector - -Inspector view - -### Browse Plane / Range / Code point - -Plane browser Range browser Code point browser - -### Browse Block - -Block browser Block code point browser - -### Search - -Search results - -### Sequence +macOS and Linux are supported. Glyph images are automatically enabled in kitty and Ghostty, using the Kitty graphics protocol. The iTerm2 inline image protocol is available through `--graphics iterm2` with no guarantee of compatibility or future support. -Sequence Sequence inspector view Sequence normalization Sequence normalization result +Text information and analysis remain available without glyph images. Sauva uses installed system fonts and does not bundle fonts. See [Compatibility](https://lusingander.github.io/sauva/getting-started/compatibility.html) for details. ## License From afe788631d39fc02affb110d1ae3e516cb62b24f Mon Sep 17 00:00:00 2001 From: Kyosuke Fujimoto Date: Mon, 5 Oct 2026 09:33:06 +0900 Subject: [PATCH 22/23] docs: use kbd tags for keyboard controls --- README.md | 20 +-- docs/src/faq/index.md | 2 +- docs/src/features/browse.md | 20 +-- docs/src/features/index.md | 2 +- docs/src/features/inspector.md | 24 ++-- docs/src/features/normalization.md | 22 +-- docs/src/features/search.md | 14 +- docs/src/features/sequence.md | 12 +- docs/src/getting-started/basic-usage.md | 16 +-- docs/src/keybindings/custom-keybindings.md | 28 ++-- docs/src/keybindings/index.md | 156 ++++++++++----------- 11 files changed, 158 insertions(+), 158 deletions(-) diff --git a/README.md b/README.md index 45cc921..3a754bb 100644 --- a/README.md +++ b/README.md @@ -54,7 +54,7 @@ Pass a string to inspect its code points and grapheme clusters: sauva 'Á👩‍💻' ``` -Press `Enter` to inspect a selected code point, or `n` to compare normalization forms. +Press Enter to inspect a selected code point, or n to compare normalization forms. Sauva Sequence and normalization demo @@ -91,15 +91,15 @@ For input interpretation, stdin handling, and graphics modes, see [Command Line | Key | Description | | --- | --- | -| `F1` | Open or close contextual help | -| `Ctrl-C` | Quit from any view | -| `j` / `k` or arrow keys | Move the selection; use Up / Down in Search | -| `/` | Open Search from the Inspector | -| `p`, `r`, `b`, `c` | Open Browse from the Inspector | -| `Enter` | Open the selected item or inspect a code point | -| `Backspace` | Go back in Browse or return from the Inspector to its Sequence | -| `y` | Copy the selected Inspector value or normalization result | -| `n` | Compare normalization forms from Sequence | +| F1 | Open or close contextual help | +| Ctrl-C | Quit from any view | +| j / k or arrow keys | Move the selection; use Up / Down in Search | +| / | Open Search from the Inspector | +| p, r, b, c | Open Browse from the Inspector | +| Enter | Open the selected item or inspect a code point | +| Backspace | Go back in Browse or return from the Inspector to its Sequence | +| y | Copy the selected Inspector value or normalization result | +| n | Compare normalization forms from Sequence | See [Keybindings](https://lusingander.github.io/sauva/keybindings/) for all controls and [Custom Keybindings](https://lusingander.github.io/sauva/keybindings/custom-keybindings.html) to customize them. diff --git a/docs/src/faq/index.md b/docs/src/faq/index.md index f72c549..8aa2906 100644 --- a/docs/src/faq/index.md +++ b/docs/src/faq/index.md @@ -57,7 +57,7 @@ The glyph image previews the selected code point. See [Sequence](../features/seq 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. +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? diff --git a/docs/src/features/browse.md b/docs/src/features/browse.md index 3938782..ec05e3c 100644 --- a/docs/src/features/browse.md +++ b/docs/src/features/browse.md @@ -4,10 +4,10 @@ Browse Unicode by numeric location or by a named block. From the Inspector, use | Key | Starting view | | --- | --- | -| `p` | Planes | -| `r` | Ranges in the current plane | -| `b` | Blocks | -| `c` | Code points in the current range | +| p | Planes | +| r | Ranges in the current plane | +| b | Blocks | +| c | Code points in the current range | ## Planes and Ranges @@ -41,12 +41,12 @@ Blocks have different sizes and may leave gaps between them. When opening the bl ## 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. +- 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. +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. diff --git a/docs/src/features/index.md b/docs/src/features/index.md index 109c04e..1e61a50 100644 --- a/docs/src/features/index.md +++ b/docs/src/features/index.md @@ -6,4 +6,4 @@ - [Sequence](./sequence.md): examine a string's code points and grapheme clusters. - [Normalization](./normalization.md): compare and inspect normalized text. -Press `F1` in any screen for contextual help. See [Keybindings](../keybindings/index.md) for the complete controls. +Press F1 in any screen for contextual help. See [Keybindings](../keybindings/index.md) for the complete controls. diff --git a/docs/src/features/inspector.md b/docs/src/features/inspector.md index 0c45678..33e497c 100644 --- a/docs/src/features/inspector.md +++ b/docs/src/features/inspector.md @@ -32,21 +32,21 @@ The glyph panel renders the selected code point and shows the font used, when sp | 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. +| 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 `` label are not included in that value. +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 `` 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. diff --git a/docs/src/features/normalization.md b/docs/src/features/normalization.md index 1dc7fcf..56ac060 100644 --- a/docs/src/features/normalization.md +++ b/docs/src/features/normalization.md @@ -1,6 +1,6 @@ # Normalization -From [Sequence](./sequence.md), press `n` to compare the input with its NFC, NFD, NFKC, and NFKD normalized forms. +From [Sequence](./sequence.md), press n to compare the input with its NFC, NFD, NFKC, and NFKD normalized forms. ```sh sauva 'Á①ffi' @@ -41,13 +41,13 @@ Changed regions use the configured difference colors and underlining. Spaces and ## Inspect a Result -Select a form and press Enter to open its code point list. +Select a form and press Enter to open its code point list. ![Normalization result](https://raw.githubusercontent.com/lusingander/sauva/refs/heads/master/img/sequence-normalization-result.png) 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. +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. @@ -55,11 +55,11 @@ The original input is preserved throughout these 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. +| 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. diff --git a/docs/src/features/search.md b/docs/src/features/search.md index 8459e46..d121299 100644 --- a/docs/src/features/search.md +++ b/docs/src/features/search.md @@ -1,6 +1,6 @@ # Search -Press `/` in the Inspector to search by character, code point, Unicode name, or formal name alias. +Press / in the Inspector to search by character, code point, Unicode name, or formal name alias. ![Search results](https://raw.githubusercontent.com/lusingander/sauva/refs/heads/master/img/filter.png) @@ -34,10 +34,10 @@ A code point appears only once even if both its name and an alias match. Matchin | 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 | +| 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. +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. diff --git a/docs/src/features/sequence.md b/docs/src/features/sequence.md index 09f11f8..735b4dc 100644 --- a/docs/src/features/sequence.md +++ b/docs/src/features/sequence.md @@ -59,12 +59,12 @@ Input order, repeated characters, spaces, and newlines are preserved. Labels and | 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 | +| 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 | ![Sequence Inspector](https://raw.githubusercontent.com/lusingander/sauva/refs/heads/master/img/sequence-inspector.png) -Backspace in the Inspector returns to the sequence. From Sequence, press `n` to open [Normalization](./normalization.md). +Backspace in the Inspector returns to the sequence. From Sequence, press n to open [Normalization](./normalization.md). diff --git a/docs/src/getting-started/basic-usage.md b/docs/src/getting-started/basic-usage.md index 2be9455..ea3892e 100644 --- a/docs/src/getting-started/basic-usage.md +++ b/docs/src/getting-started/basic-usage.md @@ -18,11 +18,11 @@ sauva 0x1F600 The [Inspector](../features/inspector.md) 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](../features/search.md), or `p`, `r`, `b`, or `c` to [browse](../features/browse.md). -- Press `F1` for help with the current screen. -- Press `q` or `Esc` to quit from the Inspector. `Ctrl-C` quits from any screen. +- 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](../features/search.md), or p, r, b, or c to [browse](../features/browse.md). +- 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 @@ -34,9 +34,9 @@ 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](../features/normalization.md). +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](../features/normalization.md). ![Sequence and normalization demo](https://raw.githubusercontent.com/lusingander/sauva/refs/heads/master/img/demo-sequence.gif) diff --git a/docs/src/keybindings/custom-keybindings.md b/docs/src/keybindings/custom-keybindings.md index 3df4d96..be704af 100644 --- a/docs/src/keybindings/custom-keybindings.md +++ b/docs/src/keybindings/custom-keybindings.md @@ -38,30 +38,30 @@ Use `sauva --print-default-config` to see every context, command, and default bi 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. +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 `-`. +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` describe the same key. +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` | Arrow keys | -| `home`, `end` | Home and End | -| `pageup`, `pagedown` | Page Up and Page Down | -| `f1` through `f12` | Function keys | +| `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. @@ -89,7 +89,7 @@ Sauva rejects invalid bindings at startup, including: - 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. +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: diff --git a/docs/src/keybindings/index.md b/docs/src/keybindings/index.md index 921733a..c372140 100644 --- a/docs/src/keybindings/index.md +++ b/docs/src/keybindings/index.md @@ -1,6 +1,6 @@ # Keybindings -Press `F1` to open or close contextual help. Help and the footer show the active bindings, including your custom settings. +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](./custom-keybindings.md). @@ -10,8 +10,8 @@ These bindings apply in every screen, including help. | Command | Keys | Action | | --- | --- | --- | -| `quit` | `Ctrl-C` | Quit Sauva | -| `help` | `F1` | Open or close help | +| `quit` | Ctrl-C | Quit Sauva | +| `help` | F1 | Open or close help | ## Inspector @@ -19,22 +19,22 @@ 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 | +| `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 @@ -42,12 +42,12 @@ 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 | +| `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. +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 @@ -55,13 +55,13 @@ 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 | +| `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 @@ -69,15 +69,15 @@ 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 | +| `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 @@ -85,16 +85,16 @@ 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 | +| `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. +Use Backspace in the Inspector to return to this result. ## Browse Lists @@ -102,21 +102,21 @@ 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 | +| `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 | +| `page_up` | Ctrl-U | Move backward by a large step | +| `page_down` | Ctrl-D | Move forward by a large step | ## Browse Code Points @@ -124,18 +124,18 @@ 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 | +| `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 @@ -143,10 +143,10 @@ Context: `help`. The underlying screen's commands are inactive while help is ope | 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 | +| `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 | From 5daf9e9ad02bb6397810b21b688fcab3e3784ea4 Mon Sep 17 00:00:00 2001 From: Kyosuke Fujimoto Date: Mon, 5 Oct 2026 09:33:42 +0900 Subject: [PATCH 23/23] docs: simplify introduction and group demos --- docs/src/introduction/index.md | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/docs/src/introduction/index.md b/docs/src/introduction/index.md index ff7d938..831849d 100644 --- a/docs/src/introduction/index.md +++ b/docs/src/introduction/index.md @@ -4,6 +4,8 @@ Sauva is a terminal application for searching and browsing Unicode code points. ![Sauva demo](https://raw.githubusercontent.com/lusingander/sauva/refs/heads/master/img/demo.gif) +![Sequence and normalization demo](https://raw.githubusercontent.com/lusingander/sauva/refs/heads/master/img/demo-sequence.gif) + ## Key Features - Inspect Unicode names, properties, encodings, and decomposition mappings. @@ -16,18 +18,6 @@ Sauva is a terminal application for searching and browsing Unicode code points. 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. -## Text Analysis - -Pass a string to open Sequence mode: - -```sh -sauva 'Á👩‍💻' -``` - -The sequence can be inspected one code point at a time or compared with its NFC, NFD, NFKC, and NFKD normalized forms. - -![Sequence and normalization demo](https://raw.githubusercontent.com/lusingander/sauva/refs/heads/master/img/demo-sequence.gif) - ## 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.