lipgloss-list

Crates.iolipgloss-list
lib.rslipgloss-list
version0.1.1
created_at2025-08-07 14:33:55.72221+00
updated_at2025-11-22 13:34:38.497167+00
descriptionA list component for terminal user interfaces, styled with Lip Gloss.
homepagehttps://github.com/whit3rabbit/lipgloss-rs
repositoryhttps://github.com/whit3rabbit/lipgloss-rs
max_upload_size
id1785384
size56,129
whit3rabbit (whit3rabbit)

documentation

README

lipgloss-list

A list component for Terminal UIs, styled with Lip Gloss. This crate is part of the lipgloss-rs ecosystem and aims for 1:1 API and rendering parity with Charm's Go implementation.

  • Simple and nested lists (sublists)
  • Predefined enumerators: alphabet, arabic, roman, bullet, dash, asterisk
  • Custom enumerators and custom indenter support
  • Per-item styling and enumerator styling via style functions
  • Multiline items with correct alignment

Installation

Use the batteries-included facade (recommended):

[dependencies]
lipgloss-extras = { version = "0.1.0", features = ["lists"] }

Or depend directly on the component (add lipgloss for styling):

[dependencies]
lipgloss-list = "0.1.0"
lipgloss = "0.1.0"

Quick start

use lipgloss_list::List;

let l = List::new()
    .items(vec!["A", "B", "C"]);

println!("{}", l);

Output:

• A
• B
• C

Enumerators

Pick from built-ins or define your own.

use lipgloss_list::{List, roman, arabic, alphabet, bullet, dash, asterisk};

let a = List::new().items(vec!["Foo", "Bar", "Baz"]).enumerator(arabic);
let r = List::new().items(vec!["Foo", "Bar", "Baz"]).enumerator(roman);
let ab = List::new().items(vec!["Foo", "Bar", "Baz"]).enumerator(alphabet);
let b = List::new().items(vec!["Foo", "Bar", "Baz"]).enumerator(bullet);
let d = List::new().items(vec!["Foo", "Bar", "Baz"]).enumerator(dash);
let s = List::new().items(vec!["Foo", "Bar", "Baz"]).enumerator(asterisk);

println!("{}\n\n{}\n\n{}\n\n{}\n\n{}\n\n{}", a, r, ab, b, d, s);

Define a custom enumerator:

use lipgloss_tree::Children;
use lipgloss_list::List;

fn bracketed(_items: &dyn Children, i: usize) -> String {
    format!("[{}]", i + 1)
}

let l = List::new().items(vec!["X", "Y", "Z"]).enumerator(bracketed);
println!("{}", l);

Sublists (nested lists)

Sublists are just lists as items.

use lipgloss_list::{List, roman};

let l = List::new()
    .item("A")
    .item("B")
    .item_list(List::new().items(vec!["C1", "C2", "C3"]).enumerator(roman))
    .item("D");

println!("{}", l);

Which renders like:

• A
• B
    I. C1
   II. C2
  III. C3
• D

Styling items and enumerators

Use style functions to style items and/or enumerators based on index or context.

use lipgloss::{Color, Style};
use lipgloss_list::List;
use lipgloss_tree::Children;

let l = List::new()
    .items(vec!["First", "Second", "Third", "Fourth"]) 
    .item_style_func(|_items: &dyn Children, i| {
        if i % 2 == 0 { Style::new().foreground(Color::from("86")) }
        else { Style::new().foreground(Color::from("219")) }
    })
    .enumerator_style_func(|items: &dyn Children, i| {
        if i == items.length() - 1 { Style::new().bold(true) } else { Style::new() }
    });

println!("{}", l);

Apply a base style to all items or all enumerators:

use lipgloss::{Color, Style};
use lipgloss_list::List;

let l = List::new()
    .items(vec!["Alpha", "Beta", "Gamma"]) 
    .item_style(Style::new().foreground(Color::from("201")))
    .enumerator_style(Style::new().foreground(Color::from("238")).padding_right(1));

println!("{}", l);

Custom indentation

Change indentation for nested content via indenter.

use lipgloss_list::List;
use lipgloss_tree::Children;

fn arrow_indenter(_items: &dyn Children, _i: usize) -> String { "→ ".into() }

let l = List::new()
    .items(vec!["Foo", "Bar", "Baz"]) 
    .indenter(arrow_indenter);

println!("{}", l);

Note: lists default to a two-space indenter for sublists, matching golden output.

Offsets and hiding

  • offset(start, end) shows only a subset of items, useful for paging.
  • hide(true) hides the entire list.
use lipgloss_list::List;

let visible_slice = List::new().items(vec!["A", "B", "C", "D"]).offset(1, 1);
let hidden = List::new().items(vec!["X", "Y"]).hide(true);

println!("{}", visible_slice);
assert_eq!(format!("{}", hidden), "");

Multiline items

Items can contain newlines; continuation lines are indented correctly.

use lipgloss_list::List;

let l = List::new().items(vec![
    "Item1 \nline 2\nline 3",
    "Item2 \nline 2\nline 3",
    "3",
]);

println!("{}", l);

Demos

Run from the repository root:

cargo run --package simple-list-demo
cargo run --package list-demo-duckduckgoose
cargo run --package list-demo-roman
cargo run --package list-demo-glow
cargo run --package list-demo-grocery

Notes

  • Lists are built on top of lipgloss-tree and benefit from its Unicode-aware layout rules.
  • Roman numerals alignment is handled to match Go’s output.
  • Nesting trees and tables inside lists is supported; deep complex nestings match golden coverage (with one known spacing discrepancy documented in docs/TREE_IN_LIST_SPACING_ISSUE.md).

Documentation

  • API docs: https://docs.rs/lipgloss-list
  • Project: https://github.com/whit3rabbit/lipgloss-rs

License

MIT

Commit count: 0

cargo fmt