lotabout.skim/src/skim_item.rs
2026-06-17 13:58:44 +02:00

103 lines
3.3 KiB
Rust

use ratatui::text::Line;
use std::borrow::Cow;
use std::fmt::{Debug, Display};
use crate::{AsAny, DisplayContext, ItemPreview, PreviewContext};
/// A `SkimItem` defines what's been processed(fetched, matched, previewed and returned) by skim
///
/// # Downcast Example
/// Skim will return the item back, but in `Arc<dyn SkimItem>` form. We might want a reference
/// to the concrete type instead of trait object. Skim provide a somehow "complicated" way to
/// `downcast` it back to the reference of the original concrete type.
///
/// ```rust
/// use skim::prelude::*;
///
/// struct MyItem {}
/// impl SkimItem for MyItem {
/// fn text(&self) -> Cow<str> {
/// unimplemented!()
/// }
/// }
///
/// impl MyItem {
/// pub fn mutable(&mut self) -> i32 {
/// 1
/// }
///
/// pub fn immutable(&self) -> i32 {
/// 0
/// }
/// }
///
/// let mut ret: Arc<dyn SkimItem> = Arc::new(MyItem{});
/// let mutable: &mut MyItem = Arc::get_mut(&mut ret)
/// .expect("item is referenced by others")
/// .as_any_mut() // cast to Any
/// .downcast_mut::<MyItem>() // downcast to (mut) concrete type
/// .expect("something wrong with downcast");
/// assert_eq!(mutable.mutable(), 1);
///
/// let immutable: &MyItem = (*ret).as_any() // cast to Any
/// .downcast_ref::<MyItem>() // downcast to concrete type
/// .expect("something wrong with downcast");
/// assert_eq!(immutable.immutable(), 0)
/// ```
pub trait SkimItem: AsAny + Send + Sync + 'static {
/// The string to be used for matching (without color)
fn text(&self) -> Cow<'_, str>;
/// The content to be displayed on the item list, could contain ANSI properties
fn display(&self, context: DisplayContext) -> Line<'_> {
context.to_line(self.text())
}
/// Custom preview content, default to `ItemPreview::Global` which will use global preview
/// setting(i.e. the command set by `preview` option)
fn preview(&self, _context: PreviewContext) -> ItemPreview {
ItemPreview::Global
}
/// Get output text(after accept), default to `text()`
///
/// Note that this function is intended to be used by the caller of skim and will not be used by
/// skim. And since skim will return the item back in `SkimOutput`, if string is not what you
/// want, you could still use `downcast` to retain the pointer to the original struct.
fn output(&self) -> Cow<'_, str> {
self.text()
}
/// Limit the matching ranges of the `get_text` of the item.
/// providing (`start_byte`, `end_byte`) of the range
fn get_matching_ranges(&self) -> Option<&[(usize, usize)]> {
None
}
/// Returns true if the item should be disabled
/// Disabled items cannot be selected
fn disabled(&self) -> bool {
false
}
}
//------------------------------------------------------------------------------
// Implement SkimItem for raw strings
impl<T: AsRef<str> + Send + Sync + 'static> SkimItem for T {
fn text(&self) -> Cow<'_, str> {
Cow::Borrowed(self.as_ref())
}
}
impl Display for dyn SkimItem {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(&self.text())
}
}
impl Debug for dyn SkimItem {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_fmt(format_args!("SkimItem {{ text: {} }}", self.text()))
}
}