### Run Readline Example Source: https://github.com/ynqa/promkit/blob/main/README.md Execute the readline example to test text input with auto-completion. ```bash cargo run --bin readline ``` -------------------------------- ### Run Text Example Source: https://github.com/ynqa/promkit/blob/main/README.md Execute the text example to test static text display. ```bash cargo run --bin text ``` -------------------------------- ### Run QuerySelector Example Source: https://github.com/ynqa/promkit/blob/main/README.md Execute the query_selector example to test a searchable selection interface. ```bash cargo run --bin query_selector ``` -------------------------------- ### Run Confirm Example Source: https://github.com/ynqa/promkit/blob/main/README.md Execute the confirm example to test yes/no confirmation prompts. ```bash cargo run --bin confirm ``` -------------------------------- ### Run Form Example Source: https://github.com/ynqa/promkit/blob/main/README.md Execute the form example to test managing multiple text input fields. ```bash cargo run --bin form ``` -------------------------------- ### Run Listbox Example Source: https://github.com/ynqa/promkit/blob/main/README.md Execute the listbox example to test single selection from a list. ```bash cargo run --bin listbox ``` -------------------------------- ### Run Tree Example Source: https://github.com/ynqa/promkit/blob/main/README.md Execute the tree example to test displaying hierarchical data. ```bash cargo run --bin tree ``` -------------------------------- ### Run Checkbox Example Source: https://github.com/ynqa/promkit/blob/main/README.md Execute the checkbox example to test multiple selection checkbox interface. ```bash cargo run --bin checkbox ``` -------------------------------- ### Run JSON Example Source: https://github.com/ynqa/promkit/blob/main/README.md Execute the json example to parse and interactively display JSON data. Provide the path to a JSON file as an argument. ```bash cargo run --bin json ${PATH_TO_JSON_FILE} ``` -------------------------------- ### Run Password Example Source: https://github.com/ynqa/promkit/blob/main/README.md Execute the password example to test masked password input with validation. ```bash cargo run --bin password ``` -------------------------------- ### Implement Custom Prompt with SharedRenderer in Rust Source: https://context7.com/ynqa/promkit/llms.txt This example demonstrates the BYOP pattern by implementing the `Prompt` trait directly. It manages a `SharedRenderer` and handles user input for a text editor, allowing independent UI updates from async tasks. ```rust use std::sync::Arc; use promkit::{ async_trait, core::{grapheme::StyledGraphemes, render::{Renderer, SharedRenderer}, Widget}, widgets::text_editor, Prompt, Signal, }; use promkit::core::crossterm::event::{Event, KeyCode, KeyEvent, KeyEventKind, KeyEventState, KeyModifiers}; #[derive(Clone, PartialEq, Eq, PartialOrd, Ord)] enum Layer { Editor, Status } struct MyPrompt { renderer: SharedRenderer, editor: text_editor::State, } #[async_trait::async_trait] impl Prompt for MyPrompt { async fn initialize(&mut self) -> anyhow::Result<()> { Ok(()) } async fn evaluate(&mut self, event: &Event) -> anyhow::Result { match event { Event::Key(KeyEvent { code: KeyCode::Enter, modifiers: KeyModifiers::NONE, kind: KeyEventKind::Press, state: KeyEventState::NONE, }) => return Ok(Signal::Quit), Event::Key(KeyEvent { code: KeyCode::Char(ch), modifiers: KeyModifiers::NONE, kind: KeyEventKind::Press, state: KeyEventState::NONE, }) => self.editor.texteditor.insert(*ch), Event::Key(KeyEvent { code: KeyCode::Backspace, .. }) => self.editor.texteditor.erase(), _ => {} } let size = promkit::core::crossterm::terminal::size()?; self.renderer .update([(Layer::Editor, self.editor.create_graphemes(size.0, size.1))]) .render() .await?; Ok(Signal::Continue) } type Return = String; fn finalize(&mut self) -> anyhow::Result { Ok(self.editor.texteditor.text_without_cursor().to_string()) } } #[tokio::main] async fn main() -> anyhow::Result<()> { let editor = text_editor::State::default(); let size = promkit::core::crossterm::terminal::size()?; let renderer = Arc::new( Renderer::try_new_with_graphemes( [(Layer::Editor, editor.create_graphemes(size.0, size.1))], true, ) .await?, ); let result = MyPrompt { renderer, editor }.run().await?; println!("You typed: {result}"); Ok(()) } ``` -------------------------------- ### Configure Readline Preset with Custom Options Source: https://github.com/ynqa/promkit/blob/main/Concept.md Demonstrates how to configure the `Readline` preset in Promkit with various options like custom titles, styles, suggestions, history, masking, word breaking, and validation. This example requires `tokio` for async execution. ```rust use std::collections::HashSet; use promkit::{ Prompt, core::crossterm::style::{Color, ContentStyle}, preset::readline::Readline, suggest::Suggest, }; #[tokio::main] async fn main() -> anyhow::Result<()> { let result = Readline::default() .title("Custom Title") .prefix("$ ") .prefix_style(ContentStyle { foreground_color: Some(Color::DarkRed), ..Default::default() }) .active_char_style(ContentStyle { background_color: Some(Color::DarkCyan), ..Default::default() }) .inactive_char_style(ContentStyle::default()) .enable_suggest(Suggest::from_iter(["option1", "option2"])) .enable_history() .mask('*') .word_break_chars(HashSet::from([' ', '-'])) .text_editor_lines(3) .validator( |text| text.len() > 3, |text| format!("Please enter more than 3 characters (current: {})", text.len()), ) .run() .await?; println!("result: {result}"); Ok(()) } ``` -------------------------------- ### Derive Promkit for Structs Source: https://github.com/ynqa/promkit/blob/main/promkit-derive/README.md Apply the `#[derive(Promkit)]` attribute to a struct to automatically generate interactive form input fields. This example demonstrates setting a custom label and label style for a String field, using a default for an Option, and configuring a label for a usize field. ```rust use promkit::crossterm::style::{Color, ContentStyle}; use promkit_derive::Promkit; #[derive(Default, Debug, Promkit)] struct Profile { #[form( label = "What is your name?", label_style = ContentStyle { foreground_color: Some(Color::DarkCyan), ..Default::default() }, )] name: String, #[form(default)] hobby: Option, #[form(label = "How old are you?", ignore_invalid_attr = "nothing")] age: usize, } fn main() -> Result<(), Box> { let mut ret = Profile::default(); ret.build()?; dbg!(ret); Ok(()) } ``` -------------------------------- ### Initialize and Update Renderer with Layers Source: https://context7.com/ynqa/promkit/llms.txt Demonstrates initializing a `SharedRenderer` with styled graphemes for different layers and updating a specific layer. Ensure `tokio` is set up for async operations. ```rust use promkit::core::{ grapheme::StyledGraphemes, render::{Renderer, SharedRenderer}, crossterm::style::{Color, ContentStyle, Stylize}, }; #[derive(Clone, PartialEq, Eq, PartialOrd, Ord)] enum Layer { Header, Body, Footer } #[tokio::main] async fn main() -> anyhow::Result<()> { let renderer: SharedRenderer = std::sync::Arc::new( Renderer::try_new_with_graphemes( [ (Layer::Header, StyledGraphemes::from("=== My App ===\n")), (Layer::Body, StyledGraphemes::from("Loading...\n")), ], true, // draw immediately ) .await?, ); // Update only the body without re-drawing header/footer renderer .update([(Layer::Body, StyledGraphemes::from("Done!\n"))]) .render() .await?; // Remove footer layer renderer.remove([Layer::Footer]); Ok(()) } ``` -------------------------------- ### Use the Confirm Preset for Yes/No Prompts Source: https://context7.com/ynqa/promkit/llms.txt Utilize the `Confirm` preset for simple yes/no questions. It automatically applies a y/n validator and returns the answer as a string ('y', 'n', 'yes', or 'no'). ```rust use promkit::preset::confirm::Confirm; #[tokio::main] async fn main() -> anyhow::Result<()> { let answer = Confirm::new("Do you want to proceed?").run().await?; println!("result: {answer}"); // Expected output: "y" or "n" Ok(()) } ``` -------------------------------- ### Use the Readline Preset for Text Input Source: https://context7.com/ynqa/promkit/llms.txt Configure and run the `Readline` preset for single-line text input with features like suggestions, history, and validation. It returns the entered string. ```rust use std::collections::HashSet; use promkit::{ preset::readline::Readline, suggest::Suggest, Prompt, core::crossterm::style::{Color, ContentStyle}, }; #[tokio::main] async fn main() -> anyhow::Result<()> { let result = Readline::default() .title("Search packages") .prefix("$ ") .prefix_style(ContentStyle { foreground_color: Some(Color::DarkGreen), ..Default::default() }) .active_char_style(ContentStyle { background_color: Some(Color::DarkCyan), ..Default::default() }) .enable_suggest(Suggest::from_iter(["apple", "applet", "application", "banana"])) .enable_history() .word_break_chars(HashSet::from([' ', '-'])) .text_editor_lines(3) .validator( |text| text.len() > 2, |text| format!("Too short: {} chars (need > 2)", text.len()), ) .run() .await?; println!("result: {result}"); // Expected: the string the user typed, e.g. "application" Ok(()) } ``` -------------------------------- ### Suggest Utility for Trie-Based Autocompletion Source: https://context7.com/ynqa/promkit/llms.txt Suggest provides a prefix-search structure backed by a radix trie. It can be enabled with `Readline::enable_suggest` or queried directly. Returns None if no matches are found. ```Rust use promkit::suggest::Suggest; fn main() { let suggest = Suggest::from_iter(["apple", "applet", "application", "banana", "band"]); let results = suggest.prefix_search("app").unwrap(); println!("{:?}", results); // Expected: ["apple", "applet", "application"] assert!(suggest.prefix_search("xyz").is_none()); } ``` -------------------------------- ### Integrate Async Spinner Widget Source: https://context7.com/ynqa/promkit/llms.txt Shows how to integrate the `Spinner` widget to display an asynchronous progress indicator. The spinner runs in a separate task and updates the renderer until a condition is met. ```rust use std::{sync::Arc, time::Duration}; use promkit::widgets::spinner::{self, frame, Spinner}; use promkit::core::render::{Renderer, SharedRenderer}; #[derive(Clone, PartialEq, Eq, PartialOrd, Ord)] enum Layer { Spin } struct TaskState(Arc>); // true = idle impl spinner::State for TaskState { async fn is_idle(&self) -> bool { *self.0.read().await } } #[tokio::main] async fn main() -> anyhow::Result<()> { let idle = Arc::new(tokio::sync::RwLock::new(false)); let state = TaskState(idle.clone()); let renderer: SharedRenderer = Arc::new( Renderer::try_new_with_graphemes([], false).await? ); let sp = Arc::new( Spinner::default() .frames(frame::DOTS) .suffix(" Processing...") .duration(Duration::from_millis(80)), ); let r = renderer.clone(); let spinner_task = tokio::spawn(async move { spinner::run(sp.as_ref(), state, Layer::Spin, r).await }); // Simulate heavy work tokio::time::sleep(Duration::from_secs(2)).await; *idle.write().await = true; spinner_task.abort(); Ok(()) } ``` -------------------------------- ### Run Validation Commands Source: https://github.com/ynqa/promkit/blob/main/CLAUDE.md Recommended commands for running validation checks locally. These include code formatting, linting, and testing. ```bash cargo fmt --all -- --check ``` ```bash cargo clippy ``` ```bash cargo test -- --nocapture --format pretty ``` -------------------------------- ### Async Event Loop Implementation in Rust Source: https://github.com/ynqa/promkit/blob/main/CHANGELOG.md Demonstrates the async event loop structure for a prompt, including initialization, event evaluation, and finalization phases. This pattern is used for better performance and responsiveness in async operations. ```rust async fn run(&mut self) -> anyhow::Result { // 1. Initialize phase self.initialize().await?; // 2. Event evaluation loop while let Some(event) = EVENT_STREAM.lock().await.next().await { match event { Ok(event) => { if self.evaluate(&event).await? == Signal::Quit { break; // Exit loop when quit signal received } } ... /// Handle errors } } // 3. Finalize phase self.finalize() } ``` -------------------------------- ### Clone promkit Repository Source: https://github.com/ynqa/promkit/blob/main/CONTRIBUTING.md Clone the promkit repository to your local machine. Replace `` with your GitHub username. ```bash git clone https://github.com//promkit.git ``` -------------------------------- ### Add Promkit to Cargo.toml Source: https://context7.com/ynqa/promkit/llms.txt Specify Promkit and its features, along with Tokio, in your Cargo.toml file. Available feature flags include various prompt types and 'all'. ```toml [dependencies] promkit = { version = "0.12.1", features = ["readline", "confirm", "listbox"] } tokio = { version = "1", features = ["full"] } ``` -------------------------------- ### Promkit Event Loop Logic Source: https://github.com/ynqa/promkit/blob/main/Concept.md This Rust code snippet illustrates the core event loop within `Prompt::run`. It handles initialization, event observation, evaluation, and finalization, with a specific condition to skip resize events. ```rust self.initialize().await?; while let Some(event) = EVENT_STREAM.lock().await.next().await { match event { Ok(event) => { // Current behavior: skip resize events in run loop. if event.is_resize() { continue; } if self.evaluate(&event).await? == Signal::Quit { break; } } Err(_) => break, } } self.finalize() ``` -------------------------------- ### Create a New Branch Source: https://github.com/ynqa/promkit/blob/main/CONTRIBUTING.md Before making changes, create a new branch for your work to keep your contributions organized. ```bash git checkout -b your-branch-name ``` -------------------------------- ### Add Promkit Dependency to Cargo.toml Source: https://github.com/ynqa/promkit/blob/main/README.md Include the promkit package in your project's Cargo.toml file to add it as a dependency. ```toml [dependencies] promkit = "0.12.1" ``` -------------------------------- ### Implement the Prompt Trait in Rust Source: https://context7.com/ynqa/promkit/llms.txt Define a struct and implement the `Prompt` trait to create a custom interactive prompt. The `run` method handles the event loop and lifecycle phases. ```rust use promkit::{Prompt, Signal}; use promkit::core::crossterm::event::Event; struct MyPrompt { value: String, } #[async_trait::async_trait] impl Prompt for MyPrompt { async fn initialize(&mut self) -> anyhow::Result<()> { // Set up renderer, draw initial UI Ok(()) } async fn evaluate(&mut self, event: &Event) -> anyhow::Result { // React to keyboard / mouse events; return Signal::Quit to exit Ok(Signal::Continue) } type Return = String; fn finalize(&mut self) -> anyhow::Result { Ok(self.value.clone()) } } #[tokio::main] async fn main() -> anyhow::Result<()> { let result = MyPrompt { value: String::new() }.run().await?; println!("Got: {result}"); Ok(()) } ``` -------------------------------- ### Run Validation Commands Source: https://github.com/ynqa/promkit/blob/main/AGENTS.md Execute these commands to check code formatting, linting, and tests. Ensure tests are run with capture disabled for clear output. ```bash cargo fmt --all -- --check ``` ```bash cargo clippy ``` ```bash cargo test -- --nocapture --format pretty ``` -------------------------------- ### Json Preset for Interactive JSON Viewing Source: https://context7.com/ynqa/promkit/llms.txt The Json preset provides an interactive, scrollable, and navigable JSON explorer. It accepts a JsonStream built from serde_json::Value items and supports OverflowMode::Wrap and OverflowMode::Truncate. ```Rust use promkit::{ preset::json::Json, widgets::{ jsonstream::{config::OverflowMode, JsonStream}, serde_json::{self, Value}, }, Prompt, }; #[tokio::main] async fn main() -> anyhow::Result<()> { let data: Vec = serde_json::from_str( r#"[ {"name": "Alice", "age": 30, "active": true}, {"name": "Bob", "age": 25, "active": false} ]"# )?; let stream = JsonStream::new(data.iter()); Json::new(stream) .title("User Data") .overflow_mode(OverflowMode::Wrap) .run() .await?; Ok(()) // The user browses and collapses JSON nodes interactively. } ``` -------------------------------- ### Type-Safe Form Generation with promkit-derive Source: https://context7.com/ynqa/promkit/llms.txt The `promkit-derive` crate's `#[derive(Promkit)]` macro automatically generates a `build()` method for structs, creating type-safe interactive forms. This reduces boilerplate and ensures type correctness. ```toml [dependencies] promkit = { version = "0.12.1", features = ["form"] } promkit-derive = "0.12.1" tokio = { version = "1", features = ["full"] } ``` ```rust use promkit::core::crossterm::style::{Color, ContentStyle}; use promkit_derive::Promkit; #[derive(Default, Debug, Promkit)] struct UserProfile { #[form( label = "What is your name?", label_style = ContentStyle { foreground_color: Some(Color::DarkCyan), ..Default::default() } )] name: String, #[form(label = "How old are you?")] age: usize, // Optional field — becomes None if input cannot be parsed #[form(default)] nickname: Option, } #[tokio::main] async fn main() -> anyhow::Result<()> { let mut profile = UserProfile::default(); profile.build().await?; dbg!(&profile); // Expected: // profile = UserProfile { name: "Alice", age: 30, nickname: Some("ally") } Ok(()) } ``` -------------------------------- ### Tree Preset for Hierarchical Navigation Source: https://context7.com/ynqa/promkit/llms.txt The Tree preset renders a collapsible tree of Node items, useful for navigating hierarchical structures like file systems. `Node::try_from(&path)` builds the tree from a filesystem path. Returns the path string of the selected node. ```Rust use std::path::Path; use promkit::{preset::tree::Tree, widgets::tree::node::Node, Prompt}; #[tokio::main] async fn main() -> anyhow::Result<()> { let root = Path::new("/usr/local/lib"); let selection = Tree::new(Node::try_from(&root)?) .title("Browse files") .tree_lines(15) .run() .await?; println!("selected: {selection}"); // Expected: "/usr/local/lib/some/nested/file" Ok(()) } ``` -------------------------------- ### Multi-Field Form Input Source: https://context7.com/ynqa/promkit/llms.txt The Form preset allows managing multiple text input fields interactively. Users navigate between fields using Tab/Shift-Tab and confirm with Enter. It returns a vector of strings, one for each field. ```rust use promkit::{ preset::form::Form, widgets::text_editor, core::crossterm::style::{Color, ContentStyle}, Prompt, }; #[tokio::main] async fn main() -> anyhow::Result<()> { let fields = Form::new([ text_editor::State { config: text_editor::config::Config { prefix: String::from("Name ❯❯ "), prefix_style: ContentStyle { foreground_color: Some(Color::DarkCyan), ..Default::default() }, active_char_style: ContentStyle { background_color: Some(Color::DarkCyan), ..Default::default() }, ..Default::default() }, ..Default::default() }, text_editor::State { config: text_editor::config::Config { prefix: String::from("Email ❯❯ "), prefix_style: ContentStyle { foreground_color: Some(Color::DarkGreen), ..Default::default() }, active_char_style: ContentStyle { background_color: Some(Color::DarkCyan), ..Default::default() }, ..Default::default() }, ..Default::default() }, ]) .run() .await?; println!("name: {}, email: {}", fields[0], fields[1]); // Expected: ["Alice", "alice@example.com"] Ok(()) } ``` -------------------------------- ### Checkbox Preset for Multiple Selection Source: https://context7.com/ynqa/promkit/llms.txt The Checkbox preset displays a list with toggleable checkmarks, allowing users to select multiple items. Use `new_with_checked` to set initially pre-checked items. Returns a Vec of all checked items. ```Rust use promkit::{preset::checkbox::Checkbox, Prompt}; #[tokio::main] async fn main() -> anyhow::Result<()> { let selected = Checkbox::new_with_checked([ ("Apples", true), ("Bananas", false), ("Cherries", true), ("Dates", false), ]) .title("Select your favourite fruits") .checkbox_lines(4) .run() .await?; println!("result: {:?}", selected); // Expected: ["Apples", "Cherries"] (plus any toggled during interaction) Ok(()) } ``` -------------------------------- ### Single Selection Listbox Input Source: https://context7.com/ynqa/promkit/llms.txt The Listbox preset allows users to select a single item from an iterator. The selection is returned as a String. Configure the number of visible lines with `listbox_lines`. ```rust use promkit::{preset::listbox::Listbox, Prompt}; #[tokio::main] async fn main() -> anyhow::Result<()> { let choice = Listbox::new(["Rust", "Go", "TypeScript", "Python"]) .title("Pick a language") .listbox_lines(4) .run() .await?; println!("result: {choice}"); // Expected: "Rust" (or whichever item was highlighted) Ok(()) } ``` -------------------------------- ### Commit Changes Source: https://github.com/ynqa/promkit/blob/main/CONTRIBUTING.md Commit your changes with a clear and concise message explaining the purpose of your contribution. ```bash git commit -m "Your commit message here" ``` -------------------------------- ### Password Input with Validation Source: https://context7.com/ynqa/promkit/llms.txt Use the Password preset for masked input of sensitive information. A validator can be applied to enforce specific criteria. ```rust use promkit::preset::password::Password; #[tokio::main] async fn main() -> anyhow::Result<()> { let password = Password::default() .title("Enter your password") .validator( |text| 4 < text.len() && text.len() < 20, |text| format!("Length must be 5–19 chars (got {})", text.len()), ) .run() .await?; println!("password length: {}", password.len()); // Expected: length of the secret string typed by the user Ok(()) } ``` -------------------------------- ### Text Preset for Scrollable Static Text Source: https://context7.com/ynqa/promkit/llms.txt The Text preset displays a long string in a scrollable pane, suitable for piping file contents or long output into an interactive pager. Users can scroll through the text and exit using 'q' or Ctrl+C. ```Rust use promkit::{preset::text::Text, Prompt}; #[tokio::main] async fn main() -> anyhow::Result<()> { let contents = std::fs::read_to_string("README.md")?; Text::new(contents).run().await?; Ok(()) // User scrolls through the text and exits with q or Ctrl+C. } ``` -------------------------------- ### Push Changes to Fork Source: https://github.com/ynqa/promkit/blob/main/CONTRIBUTING.md Push your committed changes to your forked repository on GitHub. Replace `your-branch-name` with the name of your branch. ```bash git push origin your-branch-name ``` -------------------------------- ### QuerySelector Preset for Searchable Selection Source: https://context7.com/ynqa/promkit/llms.txt Use QuerySelector to combine a text editor with a filtered listbox. A user-supplied closure filters the item list based on the current query. Returns the selected item as a String. ```Rust use promkit::{preset::query_selector::QuerySelector, Prompt}; #[tokio::main] async fn main() -> anyhow::Result<()> { let languages = vec!["Rust", "Ruby", "Python", "PHP", "Go", "JavaScript"]; let choice = QuerySelector::new(languages, |query, items| { let q = query.to_lowercase(); items .iter() .filter(|item| item.to_lowercase().contains(&q)) .cloned() .collect() }) .title("Search a language") .listbox_lines(5) .run() .await?; println!("result: {choice}"); // Typing "ru" narrows the list to ["Rust", "Ruby"] Ok(()) } ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.