#user-input #input #read #prompt #stdin #parse-input #cli-input

nightly smart-read

复杂但简单易用的用户输入读取方法

20 个版本 (6 个重大更改)

0.7.0 2024 年 8 月 21 日
0.6.2 2024 年 6 月 10 日
0.4.1 2024 年 3 月 29 日

#376命令行界面

Download history 2/week @ 2024-05-04 1/week @ 2024-05-25 408/week @ 2024-06-01 179/week @ 2024-06-08 21/week @ 2024-06-15 8/week @ 2024-06-29 24/week @ 2024-07-06 32/week @ 2024-07-27 304/week @ 2024-08-17

每月 336 次下载

MIT 许可证

40KB
691

Smart Read

Crates.io Crates.io license

复杂但简单易用的用户输入读取方法

任何实现了 TryRead 的东西都可以与 readprompt 宏一起使用,通过创建该特征的新的实现来添加功能。要查看默认实现的列表,请访问主 文档 页面。


特点

  • 高度可定制,基本上可以实现任何功能
  • 极其简单,无论是使用还是扩展
  • 极其人体工程学,尽可能无负担

基本用法

use smart_read::prelude::*;

// read a line of text
let input = read!();

// prompt a line of text
let input = prompt!("Enter a string: ");

// read specific types
let input = read!(UsizeInput);
let input = read!(BoolInput);
let input = read!(NonWhitespaceInput);
let input = read!(I32Input);

// read a number within a range
let input = read!(0. ..= 100.);


// read a bool
let input = prompt!("Confirm input: "; YesNoInput);

// set a default value
let input = prompt!("Confirm input: "; [true] YesNoInput);


// choose from a list of options
let (index, input) = read!(["red", "green", "blue"]);
// some input types have special syntax
let (index, input) = read!(= "red", "green", "blue");

// give options bulletins, alternate matching strings, and extra data
let (index, input) = read!([
	InputOption::new("1", "red", vec!("r", "the first color"), ()), // displayed as "1: red", and so on
	InputOption::new("2", "green", vec!("g", "the second color"), ()),
	InputOption::new("3", "blue", vec!("b", "the third color"), ()),
]);

// same as above, but using special syntax
let (index, input) = read!(=
	["1", "red", "r", "the first color"], (),
	["2", "green", "g", "the second color"], (),
	["3", "blue", "b", "the third color"], (),
);


// one-time custom logic
let input = prompt!("Enter an even int: "; TransformValidate (|x: String| -> Result<isize, String> { // explicit types here are optional, only added for demonstration
	// validate input as an integer
	let Ok(x) = x.parse::<isize>() else {return Err(String::from("Could not parse input"));};
	// validate input as even
	if x % 2 != 0 {return Err(String::from("Input is not even."));}
	Ok(x)
}));


// combine any features
let (index, input) = prompt!("Enter an int: "; [1usize] = 1, 2, 3, 4, 5); // uses prompt message, default value, and special list_constraint syntax

示例 stdout(来自 read_lines 示例)

==== `read!(0. ..= 100.)` ====
Enter a number within the range [0.0, 100.0]: 100.0001

Invalid input, not within bounds
Enter a number within the range [0.0, 100.0]: aa 

Could not parse input (error: invalid float literal)
Enter a number within the range [0.0, 100.0]: 1.
You entered: "1"

扩展现有功能

use smart_read::prelude::*;

#[derive(Clone, PartialEq)]
pub struct Car {
	pub name: String,
	pub color: String,
}

// choose from a list of cars
fn main() {
	let (index, input) = read!(= new_car("Red", "Toyota"), new_car("Silver", "Ram"));
	println!("You chose: {input} (index {index})");
}

pub fn new_car(color: impl Into<String>, name: impl Into<String>) -> Car {
	Car {name: name.into(), color: color.into()}
}

impl std::fmt::Display for Car {
	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
		write!(f, "{} {}", self.color, self.name)
	}
}

添加新功能

use smart_read::*;

struct PasswordInput {
	pub min_len: usize,
	pub min_digits: usize,
}

// take in a password input
fn main() {
	let input = read!(PasswordInput {min_len: 10, min_digits: 1});
	println!("You entered: \"{input}\"");
}

impl<'a> TryRead<'a> for PasswordInput {
	type Output = String;
	type Default = (); // ensure no default can be given
	fn try_read_line(&self, prompt: Option<String>, default: Option<Self::Default>) -> smart_read::BoxResult<Self::Output> {
		if default.is_some() {return DefaultNotAllowedError::new_box_result();}
		let prompt = prompt.unwrap_or_else(
			|| format!("Enter a password (must have {}+ characters and have {}+ digits): ", self.min_len, self.min_digits)
		);
		loop {
			
			print!("{prompt}");
			let password = read_stdin()?;
			
			if password.len() < 10 {
				println!("Password must have at least 10 characters");
				continue;
			}
			if password.chars().filter(|c| c.is_digit(10)).count() < 1 {
				println!("Password must have at least 1 digit");
				continue;
			}
			
			return Ok(password)
			
		}
	}
}

无运行时依赖项