aboutsummaryrefslogtreecommitdiffstats
path: root/README.md
blob: f8418e787ceaffc7628ba575e651b9a6658c5faf (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
# 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](https://github.com/astral-sh/uv) for dependency management.

```bash
cd selectui
uv sync
```

Or install as a library:

```bash
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:

```bash
cat example.jsonl | uv run selectui
```

### Oneshot mode (exit after selection):

```bash
cat example.jsonl | uv run selectui --oneshot
```

or

```bash
cat example.jsonl | uv run selectui -o
```

### Example with jq:

```bash
# 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:

```bash
# 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:

```bash
# 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:

```python
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)

```python
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

```python
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/](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](examples/README.md).

## Keybindings

### Navigation
- `↑/↓` - 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

### Search
- 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)

```jsonl
{"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:

```bash
cat items.jsonl | selectui --events
```

Output format when CTRL+x is pressed:
```json
{"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.

```bash
cat example.jsonl | uv run selectui
```

## Dependencies

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

## License

MIT