Comments (4)
Hey! Thanks for your suggestion, I'll first try to give you a solution and then later we can discuss if it is indeed a good one and think about possible changes!
When implementing the generalization of selectable prompts, I had planned to solve this problem via the new-type pattern. As a personal example, I have a struct which maps a db entity:
#[derive(AsChangeset, Identifiable, Insertable, Queryable, Serialize, PartialEq, Eq)]
#[table_name = "tag"]
#[changeset_options(treat_none_as_null = "true")]
pub struct Tag {
pub id: Ulid,
pub title: String,
pub description: Option<String>,
}
Then, by using the new type pattern I was able to implement a nice implementation that has one single clear purpose: formatting tags for being selected in a prompt:
struct TagSelectView(Tag);
impl Display for TagSelectView {
fn fmt(&self, f: &mut Formatter<'_>) -> std::result::Result<(), Error> {
write!(f, "{}", self.0.title)?;
if let Some(desc) = &self.0.description {
write!(f, " ({:.40})", desc)?;
}
Ok(())
}
}
On a first glance it looks like too much boilerplate code, but from my experience when trying different ways, it was basically the same amount of code used for a formatter, except for the struct
and impl
lines. But on the other hand I felt it did improve readability.
Finally, just as an example, I select tags with this static method:
pub struct TagSelector;
impl TagSelector {
pub fn select_skippable_from(
msg: &str,
tags: Vec1<Tag>,
help_msg: &str,
) -> Result<Option<Tag>> {
let tags = tags.into_iter().map(TagSelectView).collect();
let tag = inquire::Select::new(msg, tags)
.with_help_message(help_msg)
.prompt_skippable()?
.map(|t| t.0);
Ok(tag)
}
}
In your personal example, it could be solved similarly:
struct CustomStructView(String, CustomStruct);
impl CustomStructView {
fn filter(input: &str, obj: &CustomStructView, str_value: &str, idx: usize) -> bool {
input.contains(&obj.0)
}
}
impl Display for CustomStructView {
fn fmt(&self, f: &mut Formatter<'_>) -> std::result::Result<(), Error> {
write!(f, "{} ({})", self.0, self.1.description)
}
}
pub fn select(objs: Vec1<CustomStruct>) -> Result<CustomStruct> {
let objs = tags.into_iter()
.map(|cs| CustomStructView("something".to_string(), cs))
.collect();
inquire::Select::new("Select one please:", objs)
.with_help_message("Help message")
.with_filter(&CustomStructView::filter)
.prompt()
.map(|t| t.1)
}
Also, I just noticed that the way filters are implemented could be more ergonomic, probably a trait instead of a static function in this use-case, but we would lost the ability to define filters in closures. But that's something to be discussed in another issue.
from inquire.
Such a simple solution that I couldn't think off yesterday! That does indeed work perfectly fine. I'll close this. I do think that the above is better solution!
from inquire.
I fully agree on that, selecting over Strings is kinda bad
from inquire.
what about a solution like this?
pub struct Formatted<'a, T: ?Sized> {
fmt: &'a dyn Fn(&T) -> String,
value: T,
}
impl<'a, T> Formatted<'a, T> {
pub fn new(value: T, fmt: &'a impl Fn(&T) -> String) -> Self {
Self { fmt, value }
}
}
impl<T: ?Sized> Display for Formatted<'_, T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
(self.fmt)(&self.value).fmt(f)
}
}
impl<T> Deref for Formatted<'_, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.value
}
}
so that in their case it can be
fn select(objs: Vec<(String, CustomStruct)>) {
let objs = objs
.into_iter()
.map(|o| Formatted::new(o, &|o| format!("{}: {}", o.0, o.1.desc)))
.collect();
let select = Select::new("Select an object", objs).prompt().unwrap();
// use select as if it were (String, CustomStruct)
println!("{}", select.0);
}
It's not perfect though, because you can't manually deref select
as a box, because apparently box is kinda special.
from inquire.
Related Issues (20)
- Release HOT 1
- Use tty instead of stdin HOT 1
- with_starting_cursor does not apply HOT 2
- Fully support piped inputs in parallel with interactive inputs.
- Prompt crashes if program is run with crossterm+piped input+macos
- Add code coverage metrics to get a better idea of test coverage
- inquire derive and attribute macro HOT 3
- Show proper error message for CustomType prompt HOT 1
- Alt+{left, right, backspace} support HOT 3
- DateSelect default help message incorrect ? HOT 2
- Support for up-arrow previous prompt history, and control-keys HOT 2
- Inquire leaves the terminal in a broken state HOT 3
- Render issue using the `console` backend HOT 2
- Inquire forgets to add newlines in 0.7.1 HOT 5
- "external_print" Functionality
- Make Scrolling More Obvious (Customizable maybe?) HOT 1
- MultiSelect list doesn't show after filter is cleared on selection HOT 1
- Suppressing static lifetimes from Text (and other modules ?) HOT 1
- typo in README for termion link
- Password prompt with redirected `stdout`
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from inquire.