superlighttui 0.20.1

Super Light TUI - A lightweight, ergonomic terminal UI library
Documentation
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
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
# SLT Naming Conventions (Micro Tier)

> Companion to [`DESIGN_PRINCIPLES.md`]./DESIGN_PRINCIPLES.md. This doc
> is the **Micro tier**: how methods, types, parameters, and modules are
> named.

The principle is **shape-encoding**: a name's shape (verb / noun /
adjective, length, suffix, prefix) tells the reader its category. When a
new contributor or AI assistant sees a name they've never seen, they
should infer category and call shape from the name alone.

---

## Categories

Every public identifier falls into one category. The category drives the
shape.

### 1. Verbs — Actions

Methods that perform a side effect or trigger a state transition.

**Shape**: `<verb>` or `<verb>_<object>`.

**Examples**:
```rust
ui.quit();
ui.notify("saved", ToastLevel::Info);
ui.focus_by_name("search");
ui.register_focusable();
ui.consume_indices(vec![0, 2]);
state.set_ratio(0.5);
```

**Anti-pattern**: noun-as-verb for actions.

```rust
ui.text("hi")    // grandfathered: immediate-mode tradition; "text" treated as a verb here
ui.button("ok")  // grandfathered for the same reason
```

New actions should use real verbs.

### 2. Nouns — Getters

Methods that return a value without side effects.

**Shape**: `<noun>` or `<noun>_<modifier>`.

**Examples**:
```rust
ui.theme();
ui.spacing();
ui.width();
ui.focused_name();
ui.events();
state.cursor;
```

**Anti-pattern**: `get_X` prefix.

```rust
fn get_theme(&self) -> Theme { /* ... */ }    // bad — Rust convention drops `get_`
fn theme(&self) -> Theme { /* ... */ }         // good
```

### 3. Adjectives — Builder modifiers

Methods on `ContainerBuilder` (Layer 2) that configure the container.

**Shape**: short adjective or terse phrase.

**Examples**:
```rust
ui.container()
  .bordered(Border::Single)
  .p(2)
  .gap(1)
  .grow(1)
  .fill()
  .bold()
  .dim()
  .italic()
  .bg(theme.surface)
  .fg(Color::Cyan)
  .col(|ui| { /* ... */ });
```

**Anti-pattern**: verb form for builder modifiers.

```rust
.apply_padding(2)    // bad — too long, verb-shape
.with_padding(2)     // ok if `with_` prefix is the family convention
.p(2)                // good — terse, adjective-shape
.padding(2)          // also good — full word ok
```

### 4. Constructors

Functions that create instances.

**Shape**:
- `Type::default()` — when `Default` is implementable.
- `Type::new(args)` — minimal required config.
- `Type::with_X(arg)` — narrow construction variant.

**Examples**:
```rust
TextInputState::default();
TextInputState::with_placeholder("Search...");
SplitPaneState::new(0.5);
TabsState::new(["Files", "Settings"]);
```

---

## Suffix Patterns

| Suffix | Meaning | Example |
|--------|---------|---------|
| `_named` | name-keyed variant | `register_focusable_named` |
| `_keyed` | runtime-key variant | `use_state_keyed` |
| `_colored` | color-customized variant | `text_input_colored` |
| `_lang` | language-aware variant | `code_block_lang` |
| `_pct` | percent variant | `w_pct(50)` |
| `_ratio` | ratio variant | `w_ratio(1, 3)` |
| `_minmax` | min/max bounds variant | `w_minmax(10, 30)` |
| `_gap` | gap-supplied variant | `row_gap(g, ...)` |
| `_with` | callback-ish variant | `with_if(cond, f)` |
| `State` | Layer 4 state type | `TextInputState` |
| `Response` | Layer 5 response type | `BreadcrumbResponse` |
| `Opts` | options struct (4+ fields) | `GutterOpts` |
| `Builder` | builder type (rare; usually anon `<Widget><Lifetime>`) ||

---

## Prefix Patterns

| Prefix | Meaning | Example |
|--------|---------|---------|
| `with_` | builder-style override / conditional | `with_if`, `with_padding` |
| `use_` | hook (state-bound across frames) | `use_state`, `use_effect`, `use_state_keyed` |
| `register_` | frame-level registration | `register_focusable`, `register_focusable_named` |
| `consume_` | mark event/index as handled | `consume_indices` |
| `is_` | boolean getter | `is_quit_requested` |
| `has_` | possession boolean getter | `has_focus` (use sparingly — prefer noun like `focused`) |
| `slt_` | macro/function from SLT internals | `slt_warn!`, `slt_assert!` |

---

## Length Conventions

Length should match category:

- **Adjectives** (Layer 2 modifiers): ≤ 2 syllables typical.
  -`bg`, `fg`, `p`, `w`, `h`, `gap`, `grow`, `fill`, `border`, `bold`, `dim`
  -`bordered`, `padding`, `italic`, `inverted`
  -`with_padding_all_sides` — too long
- **Nouns** (Layer 1/2 getters): full word.
  -`theme`, `spacing`, `width`, `events`
  -`tm`, `sp`, `ev`
- **Verbs** (Layer 1 actions): full word + object.
  -`register_focusable`, `focus_by_name`, `consume_indices`
  -`reg_foc`, `foc_name`
- **Types**: full word.
  -`TextInputState`, `SplitPaneState`, `BreadcrumbResponse`
  -`TIState`, `SPState`, `BCResp`

**Cross-category mismatch is a yellow signal**: when one method in a
family is ≤ 6 chars and another is > 20, ask whether the categories are
correctly assigned.

---

## Abbreviation Policy

### Allowed (universal)

These are recognizable across languages and don't need expansion:

```
bg fg id idx len min max pos pct
w h x y r g b a (RGBA)
```

### Forbidden (domain-specific)

Even common-sounding domain abbreviations are forbidden because they
hide their family from new readers:

| Forbidden | Use instead |
|-----------|-------------|
| `ctx` | `context` (in private code only — public API uses `ui`) |
| `btn` | `button` |
| `lbl` | `label` |
| `dbg` | `debug` |
| `cfg` | `config` |
| `req` | `request` |
| `res` | `response` (or just don't shorten — `Response` is the type) |
| `srv` | `server` |
| `db` | `database` (universal-ish, but spell it out in public APIs) |

**Rationale**: AI assistants and new contributors can guess `bg` =
"background" because it's universal CSS/web vocabulary. They can't guess
`lbl` = "label" because it could be "label", "label-id", "labour", etc.
The cost of typing `label` over `lbl` is 2 characters; the cost of a
miscalled API is much higher.

---

## Parameter Naming

### Closures

```rust
fn use_effect<F, D>(&mut self, f: F, deps: &D)              // f for the callback
fn with_if<F>(self, cond: bool, f: F) -> Self               // f for the callback
```

Use single-letter names only when the role is unambiguous from the
function context.

### Indices

- `idx` (preferred) or `i` (in tight loops).
- Never `index_of_thing` unless disambiguation is needed.

### Lengths and sizes

- `n` — count, generic
- `len` — length of a collection
- `w`, `h` — width, height in cells (SLT uses cells, not pixels)
- `cap` — capacity
- `cnt` — forbidden; use `count` or `n`

### References to `Context` / `ui`

- **Always `ui`** in public closures (`|ui| { ui.text("hi") }`).
- **`ctx`** allowed only in private internals.
- **`self`** when defining a method on `Context`.

```rust
// good — public closure
ui.col(|ui| {
    ui.text("hello");
});

// good — private impl
fn helper(ctx: &mut Context) { /* ... */ }
```

---

## Method Ordering on `impl` blocks

When defining `impl Type`, order methods to maximize rustdoc readability:

1. **Constructors**`new`, `default` (via `impl Default`), `with_X`.
2. **Getters** — nouns, return values without side effects.
3. **Builder modifiers** — adjectives, return `Self` or `&mut Self`.
4. **Actions** — verbs, perform side effects.
5. **Trait impls** — separate `impl Trait for Type` blocks.

Generated rustdoc pages then read top-to-bottom: "how to construct, how
to read, how to configure, how to act."

---

## Type Naming

### State (Layer 4)

`<Widget>State`. Always `pub struct`.

```rust
pub struct TextInputState { /* ... */ }
pub struct SplitPaneState { /* ... */ }
pub struct TableState { /* ... */ }
```

### Response (Layer 5)

`<Widget>Response`. Compound responses must `Deref<Target = Response>`.

```rust
pub struct BreadcrumbResponse {
    pub response: Response,
    pub clicked_segment: Option<usize>,
}

impl Deref for BreadcrumbResponse {
    type Target = Response;
    fn deref(&self) -> &Response { &self.response }
}
```

### Options structs

`<Widget>Opts`. Used when ≥ 4 optional fields would otherwise inflate
the function signature.

```rust
pub struct GutterOpts<G> {
    pub width: u32,
    pub bg: Color,
    pub label_fn: G,
    pub highlights: Vec<HighlightRange>,
}
```

### Enums

Full words for variants, no abbreviations:

```rust
pub enum BarDirection {
    Horizontal,                                 // good
    Vertical,
}

pub enum Border {
    None, Single, Double, Rounded, Thick,       // good
}

// bad
pub enum BD { H, V }
```

### Builders (anonymous)

Builder structs use `<Widget><Lifetime>` shape:

```rust
pub struct Gauge<'a> { /* borrows &mut Context */ }
pub struct LineGauge<'a> { /* ... */ }
pub struct Breadcrumb<'a> { /* ... */ }
```

The lifetime parameter is required because builders borrow `&mut Context`.

---

## Module Naming

### Files

`snake_case.rs`. Group by family, not by widget count.

| Module | Family |
|--------|--------|
| `widgets_display/text.rs` | text & inline styling |
| `widgets_display/status.rs` | alerts, badges, code blocks |
| `widgets_input/text_input.rs` | text input variants |
| `widgets/responses.rs` | Layer 5 compound response types |

### Modules vs files

Rust 2018 style: `filename.rs` + `filename/` directory. Avoid `mod.rs`.

```
src/widgets.rs           # facade re-exports
src/widgets/
    input.rs             # state types in input family
    selection.rs
    ...
```

---

## Rename History

For AI assistants: do **not** search for these old names. They were
removed in v0.20.

| Old | New | Reason |
|-----|-----|--------|
| `gauge_w(r, w)` | `gauge(r).width(w)` | Builder consolidation |
| `gauge_colored(r, c)` | `gauge(r).color(c)` | Builder consolidation |
| `line_gauge_with(r, opts)` | `line_gauge(r).<chain>` | Builder consolidation |
| `breadcrumb_sep(b, s)` | `breadcrumb(b).separator(s)` | Builder consolidation |
| `LineGaugeOpts` | `LineGauge<'_>` builder | Builder consolidation |
| `HighlightRange::single(...)` | `HighlightRange::line(...)` | Single-line was the only use |
| `label_owned(s)` | `label(s)` | `impl Into<String>` accepts both |

These removals are **breaking changes**, but they were introduced *and*
removed in the same release (v0.20), so the pre-release window was the
only place they ever existed.

---

## Anti-patterns Observed in Review

### Mixed verbs in the same widget family

```rust
// historic — pre-v0.20 the gauge family had both
ui.gauge(0.6);                    // immediate
ui.gauge_w(0.6, 24);              // immediate-with-arg
LineGaugeOpts::new(...).render()  // builder

// resolved — v0.20 unified to:
ui.gauge(0.6).width(24).color(Color::Cyan);
ui.line_gauge(0.6).label("60%").width(24);
```

### Long form when a short adjective exists

```rust
// rejected in review
ui.container().apply_border(Border::Single).p_padding_value(2)

// correct
ui.container().border(Border::Single).p(2)
```

### Abbreviation creep

```rust
// rejected
fn dbg_print_state(...)

// correct
fn debug_print_state(...) // or, better: slt_debug!(...)
```

### Type abbreviation

```rust
// rejected
pub struct TIState { /* TextInputState */ }

// correct
pub struct TextInputState { /* ... */ }
```

---

## When in doubt

1. **Find an existing analogous method/type** in the same family.
2. **Match its shape** — same prefix, same suffix, same length category.
3. **If no analog exists**, document why this is a new pattern in the
   PR description and update [`DESIGN_PRINCIPLES.md`]./DESIGN_PRINCIPLES.md
   matrix if the new shape changes a cell.