Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion promkit-widgets/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "promkit-widgets"
version = "0.2.0"
version = "0.3.0"
edition = "2024"
authors = ["ynqa <[email protected]>"]
description = "Widgets for promkit"
Expand Down
4 changes: 2 additions & 2 deletions promkit-widgets/src/checkbox/checkbox.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ impl Checkbox {
/// Creates a new `Checkbox` from a vector of `fmt::Display`.
pub fn from_displayable<E: fmt::Display, I: IntoIterator<Item = E>>(items: I) -> Self {
Self {
listbox: Listbox::from_displayable(items),
listbox: Listbox::from(items),
picked: HashSet::new(),
}
}
Expand Down Expand Up @@ -59,7 +59,7 @@ impl Checkbox {
.collect::<HashSet<usize>>();

Self {
listbox: Listbox::from_displayable(listbox_items),
listbox: Listbox::from(listbox_items),
picked: picked_indices,
}
}
Expand Down
8 changes: 8 additions & 0 deletions promkit-widgets/src/cursor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,14 @@ impl<C: Len> Cursor<C> {
&mut self.contents
}

/// Replaces the contents with new contents and adjusts the position if necessary.
pub fn replace_contents(&mut self, contents: C) {
self.contents = contents;
if self.position >= self.contents.len() {
self.position = self.contents.len().saturating_sub(1);
}
}

/// Returns the current position of the cursor.
pub fn position(&self) -> usize {
self.position
Expand Down
7 changes: 4 additions & 3 deletions promkit-widgets/src/listbox/listbox.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,8 @@
}
}

impl Listbox {
/// Creates a new `Listbox` from a vector of `fmt::Display`.
pub fn from_displayable<E: fmt::Display, I: IntoIterator<Item = E>>(items: I) -> Self {
impl<E: fmt::Display, I: IntoIterator<Item = E>> From<I> for Listbox {
fn from(items: I) -> Self {
Self(Cursor::new(
items
.into_iter()
Expand All @@ -31,8 +30,10 @@
false,
))
}
}

impl Listbox {
pub fn len(&self) -> usize {

Check warning on line 36 in promkit-widgets/src/listbox/listbox.rs

View workflow job for this annotation

GitHub Actions / test

struct `Listbox` has a public `len` method, but no `is_empty` method
self.0.contents().len()
}

Expand Down
20 changes: 15 additions & 5 deletions promkit-widgets/src/text.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use promkit_core::{Pane, PaneFactory, crossterm::style::ContentStyle};
use promkit_core::{Pane, PaneFactory, crossterm::style::ContentStyle, grapheme::StyledGraphemes};

mod text;

Check warning on line 3 in promkit-widgets/src/text.rs

View workflow job for this annotation

GitHub Actions / test

module has the same name as its containing module
pub use text::Text;

/// Represents the state of a text-based component within the application.
Expand All @@ -13,15 +13,19 @@
pub text: Text,

/// Style for the text string.
pub style: ContentStyle,
pub style: Option<ContentStyle>,

/// Maximum number of lines to display.
pub lines: Option<usize>,
}

impl State {
pub fn replace(&mut self, renderer: Self) {
*self = renderer;
pub fn replace(&mut self, state: Self) {
*self = state;
}

pub fn replace_text(&mut self, text: Vec<StyledGraphemes>) {
self.text.replace_contents(text);
}
}

Expand All @@ -38,7 +42,13 @@
.iter()
.enumerate()
.filter(|(i, _)| *i >= self.text.position() && *i < self.text.position() + height)
.map(|(_, item)| item.clone().apply_style(self.style))
.map(|(_, item)| {
if let Some(style) = &self.style {
item.clone().apply_style(style.clone())

Check warning on line 47 in promkit-widgets/src/text.rs

View workflow job for this annotation

GitHub Actions / test

using `clone` on type `ContentStyle` which implements the `Copy` trait
} else {
item.clone()
}
})
.fold((vec![], 0), |(mut acc, pos), item| {
let rows = item.matrixify(width as usize, height, 0).0;
if pos < self.text.position() + height {
Expand Down
11 changes: 11 additions & 0 deletions promkit-widgets/src/text/text.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,17 @@ impl<T: AsRef<str>> From<T> for Text {
}

impl Text {
/// Creates a new `Text` from styled graphemes without parsing a string.
/// Useful when the caller already has styled content prepared.
pub fn from_styled_graphemes(lines: Vec<StyledGraphemes>) -> Self {
Self(Cursor::new(lines, 0, false))
}

/// Replaces the contents with new contents and adjusts the position if necessary.
pub fn replace_contents(&mut self, text: Vec<StyledGraphemes>) {
self.0.replace_contents(text);
}

/// Returns a reference to the vector of items in the listbox.
pub fn items(&self) -> &Vec<StyledGraphemes> {
self.0.contents()
Expand Down
2 changes: 1 addition & 1 deletion promkit/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ tree = ["promkit-widgets/text", "promkit-widgets/tree"]
anyhow = { workspace = true }
async-trait = { workspace = true }
futures = { workspace = true }
promkit-widgets = { path = "../promkit-widgets", version = "=0.2.0" }
promkit-widgets = { path = "../promkit-widgets", version = "=0.3.0" }
radix_trie = { workspace = true }
scopeguard = { workspace = true }
tokio = { workspace = true }
Expand Down
6 changes: 3 additions & 3 deletions promkit/src/preset/checkbox.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,10 +85,10 @@ impl Checkbox {
renderer: None,
evaluator: |event, ctx| Box::pin(evaluate::default(event, ctx)),
title: text::State {
style: ContentStyle {
style: Some(ContentStyle {
attributes: Attributes::from(Attribute::Bold),
..Default::default()
},
}),
..Default::default()
},
checkbox: checkbox::State {
Expand Down Expand Up @@ -124,7 +124,7 @@ impl Checkbox {

/// Sets the style for the title text.
pub fn title_style(mut self, style: ContentStyle) -> Self {
self.title.style = style;
self.title.style = Some(style);
self
}

Expand Down
6 changes: 3 additions & 3 deletions promkit/src/preset/json.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,10 +77,10 @@ impl Json {
renderer: None,
evaluator: |event, ctx| Box::pin(evaluate::default(event, ctx)),
title: text::State {
style: ContentStyle {
style: Some(ContentStyle {
attributes: Attributes::from(Attribute::Bold),
..Default::default()
},
}),
..Default::default()
},
json: jsonstream::State {
Expand Down Expand Up @@ -125,7 +125,7 @@ impl Json {

/// Sets the style for the title text.
pub fn title_style(mut self, style: ContentStyle) -> Self {
self.title.style = style;
self.title.style = Some(style);
self
}

Expand Down
8 changes: 4 additions & 4 deletions promkit/src/preset/listbox.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,14 +85,14 @@ impl Listbox {
renderer: None,
evaluator: |event, ctx| Box::pin(evaluate::default(event, ctx)),
title: text::State {
style: ContentStyle {
style: Some(ContentStyle {
attributes: Attributes::from(Attribute::Bold),
..Default::default()
},
}),
..Default::default()
},
listbox: listbox::State {
listbox: listbox::Listbox::from_displayable(items),
listbox: listbox::Listbox::from(items),
cursor: String::from("❯ "),
active_item_style: Some(ContentStyle {
foreground_color: Some(Color::DarkCyan),
Expand All @@ -112,7 +112,7 @@ impl Listbox {

/// Sets the style for the title text.
pub fn title_style(mut self, style: ContentStyle) -> Self {
self.title.style = style;
self.title.style = Some(style);
self
}

Expand Down
10 changes: 5 additions & 5 deletions promkit/src/preset/query_selector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ impl crate::Prompt for QuerySelector {
.map(|s| s.to_string())
.collect(),
);
self.list.listbox = Listbox::from_displayable(list);
self.list.listbox = Listbox::from(list);
}

// Update the renderer with the new state of the components.
Expand Down Expand Up @@ -126,15 +126,15 @@ impl QuerySelector {
T: Display,
I: IntoIterator<Item = T>,
{
let listbox = Listbox::from_displayable(items);
let listbox = Listbox::from(items);
Self {
renderer: None,
evaluator: |event, ctx| Box::pin(evaluate::default(event, ctx)),
title: text::State {
style: ContentStyle {
style: Some(ContentStyle {
attributes: Attributes::from(Attribute::Bold),
..Default::default()
},
}),
..Default::default()
},
readline: text_editor::State {
Expand Down Expand Up @@ -178,7 +178,7 @@ impl QuerySelector {

/// Sets the style for the title text.
pub fn title_style(mut self, style: ContentStyle) -> Self {
self.title.style = style;
self.title.style = Some(style);
self
}

Expand Down
12 changes: 6 additions & 6 deletions promkit/src/preset/readline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,10 +73,10 @@ impl Default for Readline {
evaluator: |event, ctx| Box::pin(evaluate::default(event, ctx)),
focus: Focus::Readline,
title: text::State {
style: ContentStyle {
style: Some(ContentStyle {
attributes: Attributes::from(Attribute::Bold),
..Default::default()
},
}),
..Default::default()
},
readline: text_editor::State {
Expand All @@ -99,7 +99,7 @@ impl Default for Readline {
},
suggest: Default::default(),
suggestions: listbox::State {
listbox: Listbox::from_displayable(Vec::<String>::new()),
listbox: Listbox::from(Vec::<String>::new()),
cursor: String::from("❯ "),
active_item_style: Some(ContentStyle {
foreground_color: Some(Color::DarkGrey),
Expand All @@ -115,11 +115,11 @@ impl Default for Readline {
validator: Default::default(),
error_message: text::State {
text: Default::default(),
style: ContentStyle {
style: Some(ContentStyle {
foreground_color: Some(Color::DarkRed),
attributes: Attributes::from(Attribute::Bold),
..Default::default()
},
}),
lines: None,
},
}
Expand Down Expand Up @@ -179,7 +179,7 @@ impl Readline {

/// Sets the style for the title text.
pub fn title_style(mut self, style: ContentStyle) -> Self {
self.title.style = style;
self.title.style = Some(style);
self
}

Expand Down
4 changes: 2 additions & 2 deletions promkit/src/preset/readline/evaluate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ pub async fn readline(event: &Event, ctx: &mut Readline) -> anyhow::Result<Signa
if let Some(suggest) = &ctx.suggest {
let text = ctx.readline.texteditor.text_without_cursor().to_string();
if let Some(candidates) = suggest.prefix_search(text) {
ctx.suggestions.listbox = Listbox::from_displayable(candidates);
ctx.suggestions.listbox = Listbox::from(candidates);
ctx.readline
.texteditor
.replace(&ctx.suggestions.listbox.get().to_string());
Expand Down Expand Up @@ -288,7 +288,7 @@ pub async fn suggestion(event: &Event, ctx: &mut Readline) -> anyhow::Result<Sig

// Switch back to the readline input.
_ => {
ctx.suggestions.listbox = Listbox::from_displayable(Vec::<String>::new());
ctx.suggestions.listbox = Listbox::from(Vec::<String>::new());

ctx.focus = Focus::Readline;
}
Expand Down
2 changes: 1 addition & 1 deletion promkit/src/preset/text.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ impl Text {

/// Sets the style for the text component.
pub fn style(mut self, style: ContentStyle) -> Self {
self.text.style = style;
self.text.style = Some(style);
self
}

Expand Down
6 changes: 3 additions & 3 deletions promkit/src/preset/tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,10 +78,10 @@ impl Tree {
renderer: None,
evaluator: |event, ctx| Box::pin(evaluate::default(event, ctx)),
title: text::State {
style: ContentStyle {
style: Some(ContentStyle {
attributes: Attributes::from(Attribute::Bold),
..Default::default()
},
}),
..Default::default()
},
tree: tree::State {
Expand All @@ -107,7 +107,7 @@ impl Tree {

/// Sets the style for the title text.
pub fn title_style(mut self, style: ContentStyle) -> Self {
self.title.style = style;
self.title.style = Some(style);
self
}

Expand Down
Loading