Companion to
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.
Every public identifier falls into one category. The category drives the shape.
Methods that perform a side effect or trigger a state transition.
Shape: <verb> or <verb>_<object>.
Examples:
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.
ui.text("hi") // grandfathered: immediate-mode tradition; "text" treated as a verb here
ui.button("ok") // grandfathered for the same reasonNew actions should use real verbs.
Methods that return a value without side effects.
Shape: <noun> or <noun>_<modifier>.
Examples:
ui.theme();
ui.spacing();
ui.width();
ui.focused_name();
ui.events();
state.cursor;Anti-pattern: get_X prefix.
fn get_theme(&self) -> Theme { /* ... */ } // bad — Rust convention drops `get_`
fn theme(&self) -> Theme { /* ... */ } // goodMethods on ContainerBuilder (Layer 2) that configure the container.
Shape: short adjective or terse phrase.
Examples:
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.
.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 okFunctions that create instances.
Shape:
Type::default()— whenDefaultis implementable.Type::new(args)— minimal required config.Type::with_X(arg)— narrow construction variant.
Examples:
TextInputState::default();
TextInputState::with_placeholder("Search...");
SplitPaneState::new(0.5);
TabsState::new(["Files", "Settings"]);| Suffix | Meaning | Example |
|---|---|---|
_named |
name-keyed variant | register_focusable_named |
_keyed |
runtime-key variant | use_state_keyed |
_colored |
color-customized variant (canonical color-override for immediate widgets returning Response; blessed in API_DESIGN.md Rule 1) |
text_input_colored |
_lang |
language-aware variant | code_block_lang |
_styled |
explicit-Style/Color override variant |
sparkline_styled |
_hd |
high-density / braille-cell rendering variant | candlestick_hd |
_halfblock |
half-block (▀ / ▄) pixel-doubling render variant | heatmap_halfblock |
_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 | 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 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.
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)
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.
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 callbackUse single-letter names only when the role is unambiguous from the function context.
idx(preferred) ori(in tight loops).- Never
index_of_thingunless disambiguation is needed.
n— count, genericlen— length of a collectionw,h— width, height in cells (SLT uses cells, not pixels)cap— capacitycnt— forbidden; usecountorn
- Always
uiin public closures (|ui| { ui.text("hi") }). ctxallowed only in private internals.selfwhen defining a method onContext.
// good — public closure
ui.col(|ui| {
ui.text("hello");
});
// good — private impl
fn helper(ctx: &mut Context) { /* ... */ }When defining impl Type, order methods to maximize rustdoc readability:
- Constructors —
new,default(viaimpl Default),with_X. - Getters — nouns, return values without side effects.
- Builder modifiers — adjectives, return
Selfor&mut Self. - Actions — verbs, perform side effects.
- Trait impls — separate
impl Trait for Typeblocks.
Generated rustdoc pages then read top-to-bottom: "how to construct, how to read, how to configure, how to act."
<Widget>State. Always pub struct.
pub struct TextInputState { /* ... */ }
pub struct SplitPaneState { /* ... */ }
pub struct TableState { /* ... */ }<Widget>Response. Compound responses must Deref<Target = Response>.
pub struct BreadcrumbResponse {
pub response: Response,
pub clicked_segment: Option<usize>,
}
impl Deref for BreadcrumbResponse {
type Target = Response;
fn deref(&self) -> &Response { &self.response }
}<Widget>Opts. Used when ≥ 4 optional fields would otherwise inflate
the function signature.
pub struct GutterOpts<G> {
pub width: u32,
pub bg: Color,
pub label_fn: G,
pub highlights: Vec<HighlightRange>,
}Full words for variants, no abbreviations:
pub enum BarDirection {
Horizontal, // good
Vertical,
}
pub enum Border {
None, Single, Double, Rounded, Thick, // good
}
// bad
pub enum BD { H, V }Builder structs use <Widget><Lifetime> shape:
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.
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 |
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
...
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.
Unlike the v0.20 renames above, these names still exist as
#[deprecated(since = "0.21.0")] forwarding aliases for the whole v0.21.x
line. Prefer the new form; the old names compile (with a warning) and are
scheduled for removal in the next major.
| Deprecated | New | Reason |
|---|---|---|
code_block_lang(c, l) |
code_block(c).lang(l) |
Builder consolidation — _lang × _numbered cross-product folded into one CodeBlock builder |
code_block_numbered(c) |
code_block(c).numbered() |
Builder consolidation |
code_block_numbered_lang(c, l) |
code_block(c).lang(l).numbered() |
Builder consolidation |
Note:
code_block(code)now returns aCodeBlock<'_>builder instead ofResponse. It still renders onDrop, so the commonui.code_block(code);/let _ = ui.code_block(code);forms are unaffected; callers that bound the oldResponseshould add.show().
The _colored suffix is not deprecated: it is the blessed canonical
color-override variant for immediate widgets (see the suffix table and
API_DESIGN.md Rule 1).
// 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);// rejected in review
ui.container().apply_border(Border::Single).p_padding_value(2)
// correct
ui.container().border(Border::Single).p(2)// rejected
fn dbg_print_state(...)
// correct
fn debug_print_state(...) // or, better: slt_debug!(...)// rejected
pub struct TIState { /* TextInputState */ }
// correct
pub struct TextInputState { /* ... */ }- Find an existing analogous method/type in the same family.
- Match its shape — same prefix, same suffix, same length category.
- If no analog exists, document why this is a new pattern in the
PR description and update
DESIGN_PRINCIPLES.mdmatrix if the new shape changes a cell.