aboutsummaryrefslogtreecommitdiffstats

selectui

A terminal UI for selecting and searching through items with a clean, split-pane interface.

Features

  • Search Bar: Filter items in real-time as you type
  • Split View:
  • Left pane: List of items showing title and subtitle
  • Right pane: Detailed view of selected item (all keys/values)
  • Fuzzy Search: Toggle with f key for flexible matching
  • Case Sensitivity: Toggle with i key for exact case matching
  • Readline Controls: Support for common shortcuts (^A, ^E, ^W, ^U)
  • Status Bar: Shows total entries, matched entries, and active flags
  • Help: Press ? to see keybindings
  • Oneshot Mode: Use -o flag to exit after first selection

Installation

This project uses uv for dependency management.

cd selectui
uv sync

Or install as a library:

pip install -e .

Usage

As a CLI Tool

The script reads JSON objects line-by-line from stdin (JSONL format). Each line should be a valid JSON object with at least a title key (and optionally a subtitle key). Items are loaded asynchronously, so the UI updates as new objects arrive.

Basic usage:

cat example.jsonl | uv run selectui

Oneshot mode (exit after selection):

cat example.jsonl | uv run selectui --oneshot

or

cat example.jsonl | uv run selectui -o

Example with jq:

# Select from a list of files (convert to JSONL)
find . -type f | while read f; do echo "{\"title\": \"$f\"}"; done | uv run selectui

# Or using jq to output JSONL (one object per line)
cat data.json | jq -c '.[]' | uv run selectui

Streaming example:

# Simulate streaming data - items appear one by one
for i in 1 2 3 4 5; do echo "{\"title\": \"Item $i\", \"subtitle\": \"Description $i\"}"; sleep 0.5; done | uv run selectui

Custom title/subtitle keys:

# Use 'name' as title and 'description' as subtitle
cat data.jsonl | uv run selectui -t name -s description

# Use 'filename' as title, no subtitle
cat files.jsonl | uv run selectui --title filename

As a Library

SelectUI can be used as a library in your Python applications:

from selectui import SelectUI

items = [
    {"title": "Python", "subtitle": "High-level language"},
    {"title": "Rust", "subtitle": "Systems language"},
    {"title": "Go", "subtitle": "Concurrent language"},
]

app = SelectUI(items=items, oneshot=True)
app.run()

if app.selected_item:
    print(f"You selected: {app.selected_item['title']}")

With Pydantic Models (Type Safety)

from selectui import SelectUI, SelectItem

# Type-safe items with validation
items = [
    SelectItem(title="Python", subtitle="High-level language", info="1991"),
    SelectItem(title="Rust", subtitle="Systems language", info="2010"),
]

app = SelectUI(items=items, oneshot=True)
app.run()

Converting from JSON with Custom Keys

from selectui import SelectItem

# Convert JSON/dict with custom field mappings
data = {"name": "Alice", "role": "Engineer", "team": "Backend"}
item = SelectItem.from_dict(data, title_key="name", subtitle_key="role", info_key="team")

See the examples/ directory for more library usage examples: - examples/minimal.py - Simplest possible usage - examples/simple_library_example.py - Common patterns - examples/library_usage.py - Comprehensive feature demonstrations - examples/pydantic_example.py - Pydantic models with type safety - examples/json_conversion.py - JSON conversion with custom keys

For detailed library documentation, see examples/README.md.

Keybindings

  • ↑/↓ - Move selection up/down (works from search bar!)
  • PgUp/PgDn - Page up/down (works from search bar!)
  • j/k - Vim-style navigation (when list is focused)
  • Enter - Select item and output to stdout
  • Esc, q, or ^C - Quit
  • Type to filter items
  • ^A - Move cursor to start of line
  • ^E - Move cursor to end of line
  • ^W - Delete word backward
  • ^U - Clear search line
  • Backspace - Delete character
  • ←/→ - Move cursor left/right in search box

Toggles

  • f - Toggle fuzzy search (shows "F" in status bar when active)
  • i - Toggle case-sensitive search (shows "I" in status bar when active)

Input Format

The input should be JSONL (JSON Lines) - one JSON value per line. Each line can be either: - A single JSON object - A JSON array of objects (all items will be added to the list)

{"title": "Item 1", "subtitle": "Description of item 1"}
{"title": "Item 2", "subtitle": "Description of item 2"}
[{"title": "Item 3"}, {"title": "Item 4"}]
  • title: Displayed as the main text (configurable with -t/--title)
  • subtitle: Displayed below the title (configurable with -s/--subtitle)
  • Other keys: All keys and values are shown in the detail pane

The UI loads items asynchronously as they arrive, showing a "..." indicator in the status bar while streaming is in progress.

Command Line Options

Option Description
-o, --oneshot Exit after first selection
-t, --title KEY Key to use for item title (default: title)
-s, --subtitle KEY Key to use for item subtitle (default: subtitle)
-i, --info KEY Key to display as right-aligned info in each entry
-e, --events Enable events mode (see below)

Events Mode

When --events is enabled, pressing CTRL+key combinations will emit a JSONL event to stdout containing the pressed key and the currently selected item:

cat items.jsonl | selectui --events

Output format when CTRL+x is pressed:

{"key":"ctrl+x","item":{"title":"Selected Item","subtitle":"..."}}

This allows building interactive workflows where different CTRL keys trigger different actions on the selected item. Reserved keys (like CTRL+C for quit) are not emitted.

Output

When an item is selected (by pressing Enter), the complete JSON object is output to stdout. In non-oneshot mode, the UI continues running after output. In oneshot mode, the program exits after the first selection.

Example

See example.jsonl for a sample data file with job listings.

cat example.jsonl | uv run selectui

Dependencies

  • Python 3.8+
  • textual (for the TUI framework)
  • thefuzz (for fuzzy searching)

License

MIT