Skip to content

Commit

Permalink
Merge pull request #209 from Garbaz/master
Browse files Browse the repository at this point in the history
Provide a basic default implementation of `History`
  • Loading branch information
pksunkara committed Sep 1, 2023
2 parents 418dcef + 57cb025 commit c4c00f4
Show file tree
Hide file tree
Showing 5 changed files with 128 additions and 32 deletions.
35 changes: 4 additions & 31 deletions examples/history.rs
@@ -1,13 +1,13 @@
use dialoguer::{theme::ColorfulTheme, History, Input};
use std::{collections::VecDeque, process};
use dialoguer::{theme::ColorfulTheme, BasicHistory, Input};
use std::process;

fn main() {
println!("Use 'exit' to quit the prompt");
println!("In this example, history is limited to 4 entries");
println!("In this example, history is limited to 8 entries and contains no duplicates");
println!("Use the Up/Down arrows to scroll through history");
println!();

let mut history = MyHistory::default();
let mut history = BasicHistory::new().max_entries(8).no_duplicates(true);

loop {
if let Ok(cmd) = Input::<String>::with_theme(&ColorfulTheme::default())
Expand All @@ -22,30 +22,3 @@ fn main() {
}
}
}

struct MyHistory {
max: usize,
history: VecDeque<String>,
}

impl Default for MyHistory {
fn default() -> Self {
MyHistory {
max: 4,
history: VecDeque::new(),
}
}
}

impl<T: ToString> History<T> for MyHistory {
fn read(&self, pos: usize) -> Option<String> {
self.history.get(pos).cloned()
}

fn write(&mut self, val: &T) {
if self.history.len() == self.max {
self.history.pop_back();
}
self.history.push_front(val.to_string());
}
}
51 changes: 51 additions & 0 deletions examples/history_custom.rs
@@ -0,0 +1,51 @@
use dialoguer::{theme::ColorfulTheme, History, Input};
use std::{collections::VecDeque, process};

fn main() {
println!("Use 'exit' to quit the prompt");
println!("In this example, history is limited to 4 entries");
println!("Use the Up/Down arrows to scroll through history");
println!();

let mut history = MyHistory::default();

loop {
if let Ok(cmd) = Input::<String>::with_theme(&ColorfulTheme::default())
.with_prompt("dialoguer")
.history_with(&mut history)
.interact_text()
{
if cmd == "exit" {
process::exit(0);
}
println!("Entered {}", cmd);
}
}
}

struct MyHistory {
max: usize,
history: VecDeque<String>,
}

impl Default for MyHistory {
fn default() -> Self {
MyHistory {
max: 4,
history: VecDeque::new(),
}
}
}

impl<T: ToString> History<T> for MyHistory {
fn read(&self, pos: usize) -> Option<String> {
self.history.get(pos).cloned()
}

fn write(&mut self, val: &T) {
if self.history.len() == self.max {
self.history.pop_back();
}
self.history.push_front(val.to_string());
}
}
71 changes: 71 additions & 0 deletions src/history.rs
@@ -1,3 +1,5 @@
use std::collections::VecDeque;

/// Trait for history handling.
pub trait History<T> {
/// This is called with the current position that should
Expand All @@ -13,3 +15,72 @@ pub trait History<T> {
/// is implemented as a FIFO queue.
fn write(&mut self, val: &T);
}

pub struct BasicHistory {
max_entries: Option<usize>,
deque: VecDeque<String>,
no_duplicates: bool,
}

impl BasicHistory {
/// Creates a new basic history value which has no limit on the number of
/// entries and allows for duplicates.
///
/// # Example
///
/// A history with at most 8 entries and no duplicates:
///
/// ```rs
/// let mut history = BasicHistory::new().max_entries(8).no_duplicates(true);
/// ```
pub fn new() -> Self {
Self {
max_entries: None,
deque: VecDeque::new(),
no_duplicates: false,
}
}

/// Limit the number of entries stored in the history.
pub fn max_entries(self, max_entries: usize) -> Self {
Self {
max_entries: Some(max_entries),
..self
}
}

/// Prevent duplicates in the history. This means that any previous entries
/// that are equal to a new entry are removed before the new entry is added.
pub fn no_duplicates(self, no_duplicates: bool) -> Self {
Self {
no_duplicates,
..self
}
}
}

impl<T: ToString> History<T> for BasicHistory {
fn read(&self, pos: usize) -> Option<String> {
self.deque.get(pos).cloned()
}

fn write(&mut self, val: &T) {
let val = val.to_string();

if self.no_duplicates {
self.deque.retain(|v| v != &val);
}

self.deque.push_front(val);

if let Some(max_entries) = self.max_entries {
self.deque.truncate(max_entries);
}
}
}

impl Default for BasicHistory {
fn default() -> Self {
Self::new()
}
}
2 changes: 1 addition & 1 deletion src/lib.rs
Expand Up @@ -39,7 +39,7 @@ pub use completion::Completion;
pub use edit::Editor;
pub use error::{Error, Result};
#[cfg(feature = "history")]
pub use history::History;
pub use history::{History, BasicHistory};
use paging::Paging;
pub use validate::Validator;

Expand Down
1 change: 1 addition & 0 deletions src/prompts/input.rs
Expand Up @@ -14,6 +14,7 @@ use crate::{

type ValidatorCallback<'a, T> = Box<dyn FnMut(&T) -> Option<String> + 'a>;


/// Renders an input prompt.
///
/// ## Example
Expand Down

0 comments on commit c4c00f4

Please sign in to comment.