diff --git a/Cargo.toml b/Cargo.toml index 603cd65..3fa1c05 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,12 +1,12 @@ [package] -name = "tui-tree-widget" -description = "Tree Widget for ratatui" -version = "0.23.0" +name = "managarr-tree-widget" +description = "Tree Widget for Managarr" +version = "0.24.0" license = "MIT" -repository = "https://github.com/EdJoPaTo/tui-rs-tree-widget" -authors = ["EdJoPaTo "] +repository = "https://github.com/Dark-Alex-17/managarr-tree-widget" +authors = ["EdJoPaTo ", "Dark-Alex-17 "] edition = "2021" -keywords = ["tui", "terminal", "tree", "widget"] +keywords = ["tui", "terminal", "tree", "widget", "managarr"] categories = ["command-line-interface"] include = ["src/**/*", "examples/**/*", "benches/**/*", "README.md"] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html @@ -31,7 +31,7 @@ criterion = "0.5" ratatui = "0.29" [target.'cfg(target_family = "unix")'.dev-dependencies] -pprof = { version = "0.13", features = ["criterion", "flamegraph"] } +pprof = { version = "0.14.0", features = ["criterion", "flamegraph"] } [[bench]] name = "bench" diff --git a/README.md b/README.md index f875f1b..2f24103 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,10 @@ -# Ratatui Tree Widget +# Managarr Tree Widget [Ratatui](https://docs.rs/ratatui) Widget built to show Tree Data structures. ![Screenshot](media/screenshot.png) -Built for the specific use case of [`mqttui`](https://github.com/EdJoPaTo/mqttui). + +## Credit +The original project for this widget is the [Ratatui Tree Widget](https://github.com/EdJoPaTo/tui-rs-tree-widget), which was purppose built for the specific use +case of [`mqttui`](https://github.com/EdJoPaTo/mqttui). diff --git a/benches/bench.rs b/benches/bench.rs index b477777..a083bb3 100644 --- a/benches/bench.rs +++ b/benches/bench.rs @@ -4,67 +4,67 @@ use criterion::{criterion_group, criterion_main, BatchSize, Criterion, Throughpu use ratatui::buffer::Buffer; use ratatui::layout::Rect; use ratatui::widgets::StatefulWidget; -use tui_tree_widget::{Tree, TreeItem, TreeState}; +use managarr_tree_widget::{Tree, TreeItem, TreeState}; #[must_use] -fn example_items() -> Vec> { +fn example_items() -> Vec> { vec![ - TreeItem::new_leaf("a", "Alfa"), + TreeItem::new_leaf("a", "Alfa".to_owned()), TreeItem::new( "b", - "Bravo", + "Bravo".to_owned(), vec![ - TreeItem::new_leaf("c", "Charlie"), + TreeItem::new_leaf("c", "Charlie".to_owned()), TreeItem::new( "d", - "Delta", + "Delta".to_owned(), vec![ - TreeItem::new_leaf("e", "Echo"), - TreeItem::new_leaf("f", "Foxtrot"), + TreeItem::new_leaf("e", "Echo".to_owned()), + TreeItem::new_leaf("f", "Foxtrot".to_owned()), ], ) .expect("all item identifiers are unique"), - TreeItem::new_leaf("g", "Golf"), + TreeItem::new_leaf("g", "Golf".to_owned()), ], ) .expect("all item identifiers are unique"), - TreeItem::new_leaf("h", "Hotel"), + TreeItem::new_leaf("h", "Hotel".to_owned()), TreeItem::new( "i", - "India", + "India".to_owned(), vec![ - TreeItem::new_leaf("j", "Juliett"), - TreeItem::new_leaf("k", "Kilo"), - TreeItem::new_leaf("l", "Lima"), - TreeItem::new_leaf("m", "Mike"), - TreeItem::new_leaf("n", "November"), + TreeItem::new_leaf("j", "Juliett".to_owned()), + TreeItem::new_leaf("k", "Kilo".to_owned()), + TreeItem::new_leaf("l", "Lima".to_owned()), + TreeItem::new_leaf("m", "Mike".to_owned()), + TreeItem::new_leaf("n", "November".to_owned()), ], ) .expect("all item identifiers are unique"), - TreeItem::new_leaf("o", "Oscar"), + TreeItem::new_leaf("o", "Oscar".to_owned()), TreeItem::new( "p", - "Papa", + "Papa".to_owned(), vec![ - TreeItem::new_leaf("q", "Quebec"), - TreeItem::new_leaf("r", "Romeo"), - TreeItem::new_leaf("s", "Sierra"), - TreeItem::new_leaf("t", "Tango"), - TreeItem::new_leaf("u", "Uniform"), + TreeItem::new_leaf("q", "Quebec".to_owned()), + TreeItem::new_leaf("r", "Romeo".to_owned()), + TreeItem::new_leaf("s", "Sierra".to_owned()), + TreeItem::new_leaf("t", "Tango".to_owned()), + TreeItem::new_leaf("u", "Uniform".to_owned()), TreeItem::new( "v", - "Victor", + "Victor".to_owned(), vec![ - TreeItem::new_leaf("w", "Whiskey"), - TreeItem::new_leaf("x", "Xray"), - TreeItem::new_leaf("y", "Yankee"), + TreeItem::new_leaf("w", "Whiskey".to_owned()), + TreeItem::new_leaf("x", "Xray".to_owned()), + TreeItem::new_leaf("y", "Yankee".to_owned()), ], ) .expect("all item identifiers are unique"), ], ) .expect("all item identifiers are unique"), - TreeItem::new_leaf("z", "Zulu"), + TreeItem::new_leaf("z", "Zulu".to_owned()), ] } @@ -75,14 +75,14 @@ fn init(criterion: &mut Criterion) { group.bench_function("empty", |bencher| { bencher.iter(|| { let items = vec![]; - let _: Tree = black_box(Tree::new(black_box(&items))).unwrap(); + let _ = black_box(Tree::new(black_box(&items))).unwrap(); }); }); group.bench_function("example-items", |bencher| { bencher.iter(|| { let items = example_items(); - let _: Tree<_> = black_box(Tree::new(black_box(&items))).unwrap(); + let _ = black_box(Tree::new(black_box(&items))).unwrap(); }); }); @@ -96,7 +96,7 @@ fn renders(criterion: &mut Criterion) { let buffer_size = Rect::new(0, 0, 100, 100); group.bench_function("empty", |bencher| { - let items: Vec> = vec![]; + let items: Vec> = vec![]; let tree = Tree::new(&items).unwrap(); let mut state = TreeState::default(); bencher.iter_batched( diff --git a/examples/example.rs b/examples/example.rs index 4d2a1a4..e934f20 100644 --- a/examples/example.rs +++ b/examples/example.rs @@ -7,7 +7,7 @@ use ratatui::style::{Color, Modifier, Style}; use ratatui::text::Span; use ratatui::widgets::{Block, Scrollbar, ScrollbarOrientation}; use ratatui::{crossterm, Frame, Terminal}; -use tui_tree_widget::{Tree, TreeItem, TreeState}; +use managarr_tree_widget::{Tree, TreeItem, TreeState}; #[must_use] struct App { @@ -82,24 +82,6 @@ impl App { fn draw(&mut self, frame: &mut Frame) { let area = frame.area(); - let selected = self.state.selected(); - let flatten = self.state.flatten(&self.items); - let current_selection = flatten - .iter() - .find(|i| self.state.selected() == i.identifier); - let is_selected = current_selection.is_some() - && current_selection.unwrap().item.content().to_string() == *"Echo"; - let style = if is_selected { - Style::new() - .fg(Color::Black) - .bg(Color::Cyan) - .add_modifier(Modifier::BOLD) - } else { - Style::new() - .fg(Color::Black) - .bg(Color::LightGreen) - .add_modifier(Modifier::BOLD) - }; let widget = Tree::new(&self.items) .expect("all item identifiers are unique") .block( @@ -113,7 +95,12 @@ impl App { .track_symbol(None) .end_symbol(None), )) - .highlight_style(style) + .highlight_style( + Style::new() + .fg(Color::Black) + .bg(Color::LightGreen) + .add_modifier(Modifier::BOLD), + ) .highlight_symbol(">> "); frame.render_stateful_widget(widget, area, &mut self.state); } diff --git a/src/flatten.rs b/src/flatten.rs index e623aeb..a4ce339 100644 --- a/src/flatten.rs +++ b/src/flatten.rs @@ -10,7 +10,8 @@ use crate::tree_item::TreeItem; #[must_use] pub struct Flattened<'a, Identifier, T> where - T: for<'b> Into> + Clone, + Identifier: Clone + PartialEq + Eq + core::hash::Hash, + T: for<'b> Into> + Clone + Default, { pub identifier: Vec, pub item: &'a TreeItem, @@ -18,7 +19,8 @@ where impl<'a, Identifier, T> Flattened<'a, Identifier, T> where - T: for<'b> Into> + Clone, + Identifier: Clone + PartialEq + Eq + core::hash::Hash, + T: for<'b> Into> + Clone + Default, { /// Zero based depth. Depth 0 means top level with 0 indentation. #[must_use] @@ -38,7 +40,7 @@ pub fn flatten<'a, Identifier, T>( ) -> Vec> where Identifier: Clone + PartialEq + Eq + core::hash::Hash, - T: for<'b> Into> + Clone, + T: for<'b> Into> + Clone + Default, { let mut result = Vec::new(); for item in items { diff --git a/src/lib.rs b/src/lib.rs index 989af33..ce8cc0a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -30,7 +30,7 @@ mod tree_state; /// # Example /// /// ``` -/// # use tui_tree_widget::{Tree, TreeItem, TreeState}; +/// # use managarr_tree_widget::{Tree, TreeItem, TreeState}; /// # use ratatui::backend::TestBackend; /// # use ratatui::Terminal; /// # use ratatui::widgets::Block; @@ -41,7 +41,7 @@ mod tree_state; /// let items = vec![item]; /// /// terminal.draw(|frame| { -/// let area = frame.size(); +/// let area = frame.area(); /// /// let tree_widget = Tree::new(&items) /// .expect("all item identifiers are unique") @@ -55,7 +55,8 @@ mod tree_state; #[derive(Debug, Clone)] pub struct Tree<'a, Identifier, T> where - T: for<'b> Into> + Clone, + Identifier: Clone + PartialEq + Eq + core::hash::Hash, + T: for<'b> Into> + Clone + Default, { items: &'a [TreeItem], @@ -80,7 +81,7 @@ where impl<'a, Identifier, T> Tree<'a, Identifier, T> where Identifier: Clone + PartialEq + Eq + core::hash::Hash, - T: for<'b> Into> + Clone, + T: for<'b> Into> + Clone + Default, { /// Create a new `Tree`. /// @@ -121,7 +122,7 @@ where /// Show the scrollbar when rendering this widget. /// /// Experimental: Can change on any release without any additional notice. - /// Its there to test and experiment with whats possible with scrolling widgets. + /// It's there to test and experiment with what's possible with scrolling widgets. /// Also see pub const fn experimental_scrollbar(mut self, scrollbar: Option>) -> Self { self.scrollbar = scrollbar; @@ -171,7 +172,7 @@ fn tree_new_errors_with_duplicate_identifiers() { impl<'a, Identifier, T> StatefulWidget for Tree<'a, Identifier, T> where Identifier: Clone + PartialEq + Eq + core::hash::Hash, - T: for<'b> Into> + Clone, + T: for<'b> Into> + Clone + Default, { type State = TreeState; @@ -341,7 +342,7 @@ where impl<'a, Identifier, T> Widget for Tree<'a, Identifier, T> where Identifier: Clone + Default + Eq + core::hash::Hash, - T: for<'b> Into> + Clone, + T: for<'b> Into> + Clone + Default, { fn render(self, area: Rect, buf: &mut Buffer) { let mut state = TreeState::default(); diff --git a/src/tree_item.rs b/src/tree_item.rs index 0daa115..ed8d469 100644 --- a/src/tree_item.rs +++ b/src/tree_item.rs @@ -15,7 +15,7 @@ use ratatui::text::Text; /// /// The `text` can be different from its `identifier`. /// To repeat the filename analogy: File browsers sometimes hide file extensions. -/// The filename `main.rs` is the identifier while its shown as `main`. +/// The filename `main.rs` is the identifier while it's shown as `main`. /// Two files `main.rs` and `main.toml` can exist in the same directory and can both be displayed as `main` but their identifier is different. /// /// Just like every file in a file system can be uniquely identified with its file and directory names each [`TreeItem`] in a [`Tree`](crate::Tree) can be with these identifiers. @@ -28,7 +28,7 @@ use ratatui::text::Text; /// # Example /// /// ``` -/// # use tui_tree_widget::TreeItem; +/// # use managarr_tree_widget::TreeItem; /// let a = TreeItem::new_leaf("l", "Leaf"); /// let b = TreeItem::new("r", "Root", vec![a])?; /// # Ok::<(), std::io::Error>(()) @@ -36,7 +36,8 @@ use ratatui::text::Text; #[derive(Debug, Clone)] pub struct TreeItem where - T: for<'a> Into> + Clone, + Identifier: Clone + PartialEq + Eq + core::hash::Hash, + T: for<'a> Into> + Clone + Default, { pub(super) identifier: Identifier, pub(super) content: T, @@ -46,11 +47,11 @@ where impl TreeItem where Identifier: Clone + PartialEq + Eq + core::hash::Hash, - T: for<'a> Into> + Clone, + T: for<'a> Into> + Clone + Default, { /// Create a new `TreeItem` without children. #[must_use] - pub fn new_leaf(identifier: Identifier, content: T) -> Self { + pub const fn new_leaf(identifier: Identifier, content: T) -> Self { Self { identifier, content, @@ -107,7 +108,7 @@ where /// Get a mutable reference to a child by index. /// - /// When you choose to change the `identifier` the [`TreeState`](crate::TreeState) might not work as expected afterwards. + /// When you choose to change the `identifier` the [`TreeState`](crate::TreeState) might not work as expected afterward. #[must_use] pub fn child_mut(&mut self, index: usize) -> Option<&mut Self> { self.children.get_mut(index) diff --git a/src/tree_state.rs b/src/tree_state.rs index 2be9c3e..a02dd51 100644 --- a/src/tree_state.rs +++ b/src/tree_state.rs @@ -14,7 +14,7 @@ use crate::tree_item::TreeItem; /// # Example /// /// ``` -/// # use tui_tree_widget::TreeState; +/// # use managarr_tree_widget::TreeState; /// type Identifier = usize; /// /// let mut state = TreeState::::default(); @@ -67,7 +67,7 @@ where items: &'a [TreeItem], ) -> Vec> where - T: for<'b> Into> + Clone, + T: for<'b> Into> + Clone + Default, { flatten(&self.opened, items, &[]) } @@ -79,7 +79,7 @@ where /// Clear the selection by passing an empty identifier vector: /// /// ```rust - /// # use tui_tree_widget::TreeState; + /// # use managarr_tree_widget::TreeState; /// # let mut state = TreeState::::default(); /// state.select(Vec::new()); /// ``` @@ -195,13 +195,13 @@ where /// # Example /// /// ``` - /// # use tui_tree_widget::TreeState; + /// # use managarr_tree_widget::TreeState; /// # type Identifier = usize; /// # let mut state = TreeState::::default(); /// // Move the selection one down - /// state.select_visible_relative(|current| { + /// state.select_relative(|current| { /// // When nothing is currently selected, select index 0 - /// // Otherwise select current + 1 (without panicing) + /// // Otherwise select current + 1 (without panicking) /// current.map_or(0, |current| current.saturating_add(1)) /// }); /// ``` @@ -230,13 +230,13 @@ where /// # Example /// /// ``` - /// # use tui_tree_widget::TreeState; + /// # use managarr_tree_widget::TreeState; /// # type Identifier = usize; /// # let mut state = TreeState::::default(); /// // Move the selection one down /// state.select_relative(|current| { /// // When nothing is currently selected, select index 0 - /// // Otherwise select current + 1 (without panicing) + /// // Otherwise select current + 1 (without panicking) /// current.map_or(0, |current| current.saturating_add(1)) /// }); /// ```