pub struct DefaultDelegate {
pub show_description: bool,
pub styles: DefaultItemStyles,
/* private fields */
}Expand description
A delegate for rendering DefaultItem instances in list components.
This delegate provides the standard rendering logic for DefaultItem objects,
handling different visual states, filtering highlights, and layout options.
It implements the ItemDelegate trait to integrate seamlessly with the list
component system.
§Features
- Adaptive styling: Automatically adjusts colors for light/dark terminals
- State rendering: Handles normal, selected, and dimmed visual states
- Filter highlighting: Character-level highlighting of search matches
- Flexible layout: Configurable description display and item spacing
- Responsive design: Adjusts rendering based on available width
§Configuration
The delegate can be customized through its public fields:
show_description: Controls whether descriptions are rendered below titlesstyles: Complete styling configuration for all visual states
§Usage with List
The delegate is designed to work with the Model<DefaultItem> list component
and handles all the rendering complexity automatically.
§Examples
use bubbletea_widgets::list::{DefaultDelegate, DefaultItem, Model};
// Create a delegate with default settings
let delegate = DefaultDelegate::new();
// Customize the delegate
let mut custom_delegate = DefaultDelegate::new();
custom_delegate.show_description = false; // Hide descriptions
// Use with a list
let items = vec![
DefaultItem::new("Task 1", "First task description"),
DefaultItem::new("Task 2", "Second task description"),
];
let list = Model::new(items, delegate, 80, 24);Fields§
§show_description: boolWhether to show the description beneath the title.
styles: DefaultItemStylesStyling used for different visual states.
Implementations§
Source§impl DefaultDelegate
impl DefaultDelegate
Sourcepub fn new() -> Self
pub fn new() -> Self
Creates a new delegate with default styles and layout.
This is equivalent to DefaultDelegate::default() and provides a convenient
constructor for creating a new delegate with standard settings.
§Returns
A new DefaultDelegate configured with default settings suitable for
most list use cases.
§Examples
use bubbletea_widgets::list::{DefaultDelegate, DefaultItem, Model};
let delegate = DefaultDelegate::new();
let items = vec![DefaultItem::new("Item 1", "Description 1")];
let list = Model::new(items, delegate, 80, 24);Trait Implementations§
Source§impl Clone for DefaultDelegate
impl Clone for DefaultDelegate
Source§fn clone(&self) -> DefaultDelegate
fn clone(&self) -> DefaultDelegate
1.0.0 · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreSource§impl Debug for DefaultDelegate
impl Debug for DefaultDelegate
Source§impl Default for DefaultDelegate
impl Default for DefaultDelegate
Source§fn default() -> Self
fn default() -> Self
Creates a new delegate with default configuration.
The default delegate is configured with:
- Description display enabled
- Standard adaptive styling
- Height of 2 lines (title + description)
- 1 line spacing between items
This configuration provides a standard list appearance that matches the Go bubbles library defaults.
§Examples
use bubbletea_widgets::list::DefaultDelegate;
let delegate = DefaultDelegate::default();
assert_eq!(delegate.show_description, true);Source§impl<I: Item + 'static> ItemDelegate<I> for DefaultDelegate
impl<I: Item + 'static> ItemDelegate<I> for DefaultDelegate
Source§fn render(&self, m: &Model<I>, index: usize, item: &I) -> String
fn render(&self, m: &Model<I>, index: usize, item: &I) -> String
Renders an item as a styled string for display in the list.
This method implements the complete rendering pipeline for list items, with special handling for filter highlighting that avoids common ANSI spacing issues.
§Rendering Pipeline
- State Detection: Determine if item is selected, dimmed, or has filter matches
- Filter Highlighting: Apply character-level highlighting using segment-based approach
- Style Application: Apply colors, borders, and padding based on item state
- Layout Formatting: Combine title and description if enabled
§Filter Highlighting Implementation
The filter highlighting system is complex due to lipgloss rendering behavior:
§Problem
Lipgloss styles with padding add spaces when applied to individual text segments.
If we pass styles with padding directly to apply_character_highlighting, we get:
- Input: “Nutella” with matches [0] (highlighting ‘N’)
- Expected: “│ Nutella”
- Actual: “│ N utella” (extra space between ‘N’ and ‘utella’)
§Solution
- Create “base” styles WITHOUT padding/borders for segment highlighting
- Apply highlighting using these clean styles via
apply_character_highlighting - Manually apply border and padding AFTER highlighting is complete
§Selected vs Unselected Items
- Selected: Left border (│) + 1 space padding + colored text
- Unselected: No border + 2 spaces padding + normal text color
This approach ensures seamless text rendering while preserving visual hierarchy.
§Arguments
m- The list model containing state and filter informationindex- The index of this item in the current list viewitem- The item to render
§Returns
A formatted string with ANSI styling codes. Returns empty string if list width is 0.
§Visual States
- Normal: Standard appearance with left padding
- Selected: Highlighted with left border and accent colors
- Dimmed: Faded appearance when filter input is empty
- Filtered: Normal or selected appearance with character-level match highlighting
§CRITICAL DEVELOPER NOTES - List Component Bug Fixes
This render method is part of comprehensive fixes for list component issues. READ THIS before modifying anything related to index handling!
§Index Parameter Semantics (VERY IMPORTANT!)
The index parameter represents the original item index in the full items list,
NOT a viewport-relative or filtered-relative position. This design is crucial for:
- Cursor Highlighting:
index == m.cursorcomparison works correctly - Filter Highlighting: We can find matches by searching filtered_items
- Viewport Scrolling: Highlighting persists across viewport changes
§Fixed Bug Context
Previous issues that were resolved:
- Cursor highlighting loss: Caused by passing viewport-relative indices
- Filter input accumulation: Fixed by proper textinput event forwarding
- Viewport page jumping: Fixed by smooth scrolling implementation
§System Integration
This method works with other fixes in mod.rs:
sync_viewport_with_cursor(): Provides smooth viewport scrollingview_items(): Passes original indices instead of viewport-relative ones- Filter input handlers: Ensure proper character accumulation
⚠️ WARNING: If you modify index handling here, ensure consistency with view_items()!
Source§fn height(&self) -> usize
fn height(&self) -> usize
Returns the height in lines that each item occupies.
The height depends on whether descriptions are enabled:
- With descriptions: Returns the configured height (default 2 lines)
- Without descriptions: Always returns 1 line
This height is used by the list component for layout calculations, viewport sizing, and scroll positioning.
§Returns
The number of terminal lines each item will occupy when rendered.
Source§fn spacing(&self) -> usize
fn spacing(&self) -> usize
Returns the number of blank lines between items.
This spacing is added between each item in the list to improve readability and visual separation. The default spacing is 1 line.
§Returns
The number of blank lines to insert between rendered items.
Source§fn update(&self, _msg: &Msg, _m: &mut Model<I>) -> Option<Cmd>
fn update(&self, _msg: &Msg, _m: &mut Model<I>) -> Option<Cmd>
Handles update messages for the delegate.
The default delegate implementation does not require any message handling,
so this method always returns None. Override this method in custom
delegates that need to respond to keyboard input, timer events, or
other application messages.
§Arguments
_msg- The message to handle (unused in default implementation)_m- Mutable reference to the list model (unused in default implementation)
§Returns
Always returns None as the default delegate requires no update commands.
Source§fn full_help(&self) -> Vec<Vec<Binding>>
fn full_help(&self) -> Vec<Vec<Binding>>
Source§fn on_select(&self, _index: usize, _item: &I) -> Option<Cmd>
fn on_select(&self, _index: usize, _item: &I) -> Option<Cmd>
Auto Trait Implementations§
impl Freeze for DefaultDelegate
impl !RefUnwindSafe for DefaultDelegate
impl Send for DefaultDelegate
impl Sync for DefaultDelegate
impl Unpin for DefaultDelegate
impl !UnwindSafe for DefaultDelegate
Blanket Implementations§
Source§impl<S, D, Swp, Dwp, T> AdaptInto<D, Swp, Dwp, T> for Swhere
T: Real + Zero + Arithmetics + Clone,
Swp: WhitePoint<T>,
Dwp: WhitePoint<T>,
D: AdaptFrom<S, Swp, Dwp, T>,
impl<S, D, Swp, Dwp, T> AdaptInto<D, Swp, Dwp, T> for Swhere
T: Real + Zero + Arithmetics + Clone,
Swp: WhitePoint<T>,
Dwp: WhitePoint<T>,
D: AdaptFrom<S, Swp, Dwp, T>,
Source§fn adapt_into_using<M>(self, method: M) -> Dwhere
M: TransformMatrix<T>,
fn adapt_into_using<M>(self, method: M) -> Dwhere
M: TransformMatrix<T>,
Source§fn adapt_into(self) -> D
fn adapt_into(self) -> D
Source§impl<T, C> ArraysFrom<C> for Twhere
C: IntoArrays<T>,
impl<T, C> ArraysFrom<C> for Twhere
C: IntoArrays<T>,
Source§fn arrays_from(colors: C) -> T
fn arrays_from(colors: C) -> T
Source§impl<T, C> ArraysInto<C> for Twhere
C: FromArrays<T>,
impl<T, C> ArraysInto<C> for Twhere
C: FromArrays<T>,
Source§fn arrays_into(self) -> C
fn arrays_into(self) -> C
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<WpParam, T, U> Cam16IntoUnclamped<WpParam, T> for Uwhere
T: FromCam16Unclamped<WpParam, U>,
impl<WpParam, T, U> Cam16IntoUnclamped<WpParam, T> for Uwhere
T: FromCam16Unclamped<WpParam, U>,
Source§type Scalar = <T as FromCam16Unclamped<WpParam, U>>::Scalar
type Scalar = <T as FromCam16Unclamped<WpParam, U>>::Scalar
parameters when converting.Source§fn cam16_into_unclamped(
self,
parameters: BakedParameters<WpParam, <U as Cam16IntoUnclamped<WpParam, T>>::Scalar>,
) -> T
fn cam16_into_unclamped( self, parameters: BakedParameters<WpParam, <U as Cam16IntoUnclamped<WpParam, T>>::Scalar>, ) -> T
self into C, using the provided parameters.Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T, C> ComponentsFrom<C> for Twhere
C: IntoComponents<T>,
impl<T, C> ComponentsFrom<C> for Twhere
C: IntoComponents<T>,
Source§fn components_from(colors: C) -> T
fn components_from(colors: C) -> T
Source§impl<T> FromAngle<T> for T
impl<T> FromAngle<T> for T
Source§fn from_angle(angle: T) -> T
fn from_angle(angle: T) -> T
angle.Source§impl<T, U> FromStimulus<U> for Twhere
U: IntoStimulus<T>,
impl<T, U> FromStimulus<U> for Twhere
U: IntoStimulus<T>,
Source§fn from_stimulus(other: U) -> T
fn from_stimulus(other: U) -> T
other into Self, while performing the appropriate scaling,
rounding and clamping.Source§impl<T, U> IntoAngle<U> for Twhere
U: FromAngle<T>,
impl<T, U> IntoAngle<U> for Twhere
U: FromAngle<T>,
Source§fn into_angle(self) -> U
fn into_angle(self) -> U
T.Source§impl<WpParam, T, U> IntoCam16Unclamped<WpParam, T> for Uwhere
T: Cam16FromUnclamped<WpParam, U>,
impl<WpParam, T, U> IntoCam16Unclamped<WpParam, T> for Uwhere
T: Cam16FromUnclamped<WpParam, U>,
Source§type Scalar = <T as Cam16FromUnclamped<WpParam, U>>::Scalar
type Scalar = <T as Cam16FromUnclamped<WpParam, U>>::Scalar
parameters when converting.Source§fn into_cam16_unclamped(
self,
parameters: BakedParameters<WpParam, <U as IntoCam16Unclamped<WpParam, T>>::Scalar>,
) -> T
fn into_cam16_unclamped( self, parameters: BakedParameters<WpParam, <U as IntoCam16Unclamped<WpParam, T>>::Scalar>, ) -> T
self into C, using the provided parameters.Source§impl<T, U> IntoColor<U> for Twhere
U: FromColor<T>,
impl<T, U> IntoColor<U> for Twhere
U: FromColor<T>,
Source§fn into_color(self) -> U
fn into_color(self) -> U
Source§impl<T, U> IntoColorUnclamped<U> for Twhere
U: FromColorUnclamped<T>,
impl<T, U> IntoColorUnclamped<U> for Twhere
U: FromColorUnclamped<T>,
Source§fn into_color_unclamped(self) -> U
fn into_color_unclamped(self) -> U
Source§impl<T> IntoStimulus<T> for T
impl<T> IntoStimulus<T> for T
Source§fn into_stimulus(self) -> T
fn into_stimulus(self) -> T
self into T, while performing the appropriate scaling,
rounding and clamping.Source§impl<T, C> TryComponentsInto<C> for Twhere
C: TryFromComponents<T>,
impl<T, C> TryComponentsInto<C> for Twhere
C: TryFromComponents<T>,
Source§type Error = <C as TryFromComponents<T>>::Error
type Error = <C as TryFromComponents<T>>::Error
try_into_colors fails to cast.Source§fn try_components_into(self) -> Result<C, <T as TryComponentsInto<C>>::Error>
fn try_components_into(self) -> Result<C, <T as TryComponentsInto<C>>::Error>
Source§impl<T, U> TryIntoColor<U> for Twhere
U: TryFromColor<T>,
impl<T, U> TryIntoColor<U> for Twhere
U: TryFromColor<T>,
Source§fn try_into_color(self) -> Result<U, OutOfBounds<U>>
fn try_into_color(self) -> Result<U, OutOfBounds<U>>
OutOfBounds error is returned which contains
the unclamped color. Read more