| Crates.io | promkit |
| lib.rs | promkit |
| version | 0.10.1 |
| created_at | 2022-05-04 07:10:38.343528+00 |
| updated_at | 2025-07-24 13:03:25.903305+00 |
| description | A toolkit for building your own interactive command-line tools |
| homepage | |
| repository | https://github.com/ynqa/promkit |
| max_upload_size | |
| id | 580246 |
| size | 148,473 |
A toolkit for building your own interactive prompt in Rust.
Put the package in your Cargo.toml.
[dependencies]
promkit = "0.10.1"
See here.
promkit provides presets so that users can try prompts immediately without having to build complex components for specific use cases.
Show you commands, code, and actual demo screens for examples that can be executed immediately below.
cargo run --bin readline --manifest-path examples/readline/Cargo.toml
use promkit::{preset::readline::Readline, suggest::Suggest};
fn main() -> anyhow::Result<()> {
let mut p = Readline::default()
.title("Hi!")
.enable_suggest(Suggest::from_iter([
"apple",
"applet",
"application",
"banana",
]))
.validator(
|text| text.len() > 10,
|text| format!("Length must be over 10 but got {}", text.len()),
)
.prompt()?;
println!("result: {:?}", p.run()?);
Ok(())
}
cargo run --manifest-path examples/confirm/Cargo.toml
use promkit::preset::confirm::Confirm;
fn main() -> anyhow::Result<()> {
let mut p = Confirm::new("Do you have a pet?").prompt()?;
println!("result: {:?}", p.run()?);
Ok(())
}
cargo run --manifest-path examples/password/Cargo.toml
use promkit::preset::password::Password;
fn main() -> anyhow::Result<()> {
let mut p = Password::default()
.title("Put your password")
.validator(
|text| 4 < text.len() && text.len() < 10,
|text| format!("Length must be over 4 and within 10 but got {}", text.len()),
)
.prompt()?;
println!("result: {:?}", p.run()?);
Ok(())
}
cargo run --manifest-path examples/form/Cargo.toml
use promkit::{
crossterm::style::{Color, ContentStyle},
preset::form::Form,
promkit_widgets::text_editor,
};
fn main() -> anyhow::Result<()> {
let mut p = Form::new([
text_editor::State {
prefix: String::from("❯❯ "),
prefix_style: ContentStyle {
foreground_color: Some(Color::DarkRed),
..Default::default()
},
active_char_style: ContentStyle {
background_color: Some(Color::DarkCyan),
..Default::default()
},
..Default::default()
},
text_editor::State {
prefix: String::from("❯❯ "),
prefix_style: ContentStyle {
foreground_color: Some(Color::DarkGreen),
..Default::default()
},
active_char_style: ContentStyle {
background_color: Some(Color::DarkCyan),
..Default::default()
},
..Default::default()
},
text_editor::State {
prefix: String::from("❯❯ "),
prefix_style: ContentStyle {
foreground_color: Some(Color::DarkBlue),
..Default::default()
},
active_char_style: ContentStyle {
background_color: Some(Color::DarkCyan),
..Default::default()
},
..Default::default()
},
])
.prompt()?;
println!("result: {:?}", p.run()?);
Ok(())
}
cargo run --manifest-path examples/listbox/Cargo.toml
use promkit::preset::listbox::Listbox;
fn main() -> anyhow::Result<()> {
let mut p = Listbox::new(0..100)
.title("What number do you like?")
.prompt()?;
println!("result: {:?}", p.run()?);
Ok(())
}
cargo run --manifest-path examples/query_selector/Cargo.toml
use promkit::preset::query_selector::QuerySelector;
fn main() -> anyhow::Result<()> {
let mut p = QuerySelector::new(0..100, |text, items| -> Vec<String> {
text.parse::<usize>()
.map(|query| {
items
.iter()
.filter(|num| query <= num.parse::<usize>().unwrap_or_default())
.map(|num| num.to_string())
.collect::<Vec<String>>()
})
.unwrap_or(items.clone())
})
.title("What number do you like?")
.listbox_lines(5)
.prompt()?;
println!("result: {:?}", p.run()?);
Ok(())
}
cargo run --manifest-path examples/checkbox/Cargo.toml
use promkit::preset::checkbox::Checkbox;
fn main() -> anyhow::Result<()> {
let mut p = Checkbox::new(vec![
"Apple",
"Banana",
"Orange",
"Mango",
"Strawberry",
"Pineapple",
"Grape",
"Watermelon",
"Kiwi",
"Pear",
])
.title("What are your favorite fruits?")
.checkbox_lines(5)
.prompt()?;
println!("result: {:?}", p.run()?);
Ok(())
}
cargo run --manifest-path examples/tree/Cargo.toml
use promkit::{preset::tree::Tree, promkit_widgets::tree::node::Node};
fn main() -> anyhow::Result<()> {
let mut p = Tree::new(Node::try_from(&std::env::current_dir()?.join("src"))?)
.title("Select a directory or file")
.tree_lines(10)
.prompt()?;
println!("result: {:?}", p.run()?);
Ok(())
}
cargo run --manifest-path examples/json/Cargo.toml
use promkit::{
preset::json::Json,
promkit_widgets::{
jsonstream::JsonStream,
serde_json::{self, Deserializer},
},
};
fn main() -> anyhow::Result<()> {
let stream = JsonStream::new(
Deserializer::from_str(
r#"
{
"apiVersion": "v1",
"kind": "Pod",
"metadata": {
"annotations": {
"kubeadm.kubernetes.io/etcd.advertise-client-urls": "https://172.18.0.2:2379",
"kubernetes.io/config.hash": "9c4c3ba79af7ad68d939c568f053bfff",
"kubernetes.io/config.mirror": "9c4c3ba79af7ad68d939c568f053bfff",
"kubernetes.io/config.seen": "2024-10-12T12:53:27.751706220Z",
"kubernetes.io/config.source": "file"
},
"creationTimestamp": "2024-10-12T12:53:31Z",
"labels": {
"component": "etcd",
"tier": "control-plane"
},
"name": "etcd-kind-control-plane",
"namespace": "kube-system",
"ownerReferences": [
{
"apiVersion": "v1",
"controller": true,
"kind": "Node",
"name": "kind-control-plane",
"uid": "6cb2c3e5-1a73-4932-9cc5-6d69b80a9932"
}
],
"resourceVersion": "192988",
"uid": "77465839-5a58-43b1-b754-55deed66d5ca"
},
"spec": {
"containers": [
{
"command": [
"etcd",
"--advertise-client-urls=https://172.18.0.2:2379",
"--cert-file=/etc/kubernetes/pki/etcd/server.crt",
"--client-cert-auth=true",
"--data-dir=/var/lib/etcd",
"--experimental-initial-corrupt-check=true",
"--experimental-watch-progress-notify-interval=5s",
"--initial-advertise-peer-urls=https://172.18.0.2:2380",
"--initial-cluster=kind-control-plane=https://172.18.0.2:2380",
"--key-file=/etc/kubernetes/pki/etcd/server.key",
"--listen-client-urls=https://127.0.0.1:2379,https://172.18.0.2:2379",
"--listen-metrics-urls=http://127.0.0.1:2381",
"--listen-peer-urls=https://172.18.0.2:2380",
"--name=kind-control-plane",
"--peer-cert-file=/etc/kubernetes/pki/etcd/peer.crt",
"--peer-client-cert-auth=true",
"--peer-key-file=/etc/kubernetes/pki/etcd/peer.key",
"--peer-trusted-ca-file=/etc/kubernetes/pki/etcd/ca.crt",
"--snapshot-count=10000",
"--trusted-ca-file=/etc/kubernetes/pki/etcd/ca.crt"
],
"image": "registry.k8s.io/etcd:3.5.15-0",
"imagePullPolicy": "IfNotPresent",
"livenessProbe": {
"failureThreshold": 8,
"httpGet": {
"host": "127.0.0.1",
"path": "/livez",
"port": 2381,
"scheme": "HTTP"
},
"initialDelaySeconds": 10,
"periodSeconds": 10,
"successThreshold": 1,
"timeoutSeconds": 15
},
"name": "etcd",
"readinessProbe": {
"failureThreshold": 3,
"httpGet": {
"host": "127.0.0.1",
"path": "/readyz",
"port": 2381,
"scheme": "HTTP"
},
"periodSeconds": 1,
"successThreshold": 1,
"timeoutSeconds": 15
},
"resources": {
"requests": {
"cpu": "100m",
"memory": "100Mi"
}
},
"startupProbe": {
"failureThreshold": 24,
"httpGet": {
"host": "127.0.0.1",
"path": "/readyz",
"port": 2381,
"scheme": "HTTP"
},
"initialDelaySeconds": 10,
"periodSeconds": 10,
"successThreshold": 1,
"timeoutSeconds": 15
},
"terminationMessagePath": "/dev/termination-log",
"terminationMessagePolicy": "File",
"volumeMounts": [
{
"mountPath": "/var/lib/etcd",
"name": "etcd-data"
},
{
"mountPath": "/etc/kubernetes/pki/etcd",
"name": "etcd-certs"
}
]
}
],
"dnsPolicy": "ClusterFirst",
"enableServiceLinks": true,
"hostNetwork": true,
"nodeName": "kind-control-plane",
"preemptionPolicy": "PreemptLowerPriority",
"priority": 2000001000,
"priorityClassName": "system-node-critical",
"restartPolicy": "Always",
"schedulerName": "default-scheduler",
"securityContext": {
"seccompProfile": {
"type": "RuntimeDefault"
}
},
"terminationGracePeriodSeconds": 30,
"tolerations": [
{
"effect": "NoExecute",
"operator": "Exists"
}
],
"volumes": [
{
"hostPath": {
"path": "/etc/kubernetes/pki/etcd",
"type": "DirectoryOrCreate"
},
"name": "etcd-certs"
},
{
"hostPath": {
"path": "/var/lib/etcd",
"type": "DirectoryOrCreate"
},
"name": "etcd-data"
}
]
},
"status": {
"conditions": [
{
"lastProbeTime": null,
"lastTransitionTime": "2024-12-06T13:28:35Z",
"status": "True",
"type": "PodReadyToStartContainers"
},
{
"lastProbeTime": null,
"lastTransitionTime": "2024-12-06T13:28:34Z",
"status": "True",
"type": "Initialized"
},
{
"lastProbeTime": null,
"lastTransitionTime": "2024-12-06T13:28:50Z",
"status": "True",
"type": "Ready"
},
{
"lastProbeTime": null,
"lastTransitionTime": "2024-12-06T13:28:50Z",
"status": "True",
"type": "ContainersReady"
},
{
"lastProbeTime": null,
"lastTransitionTime": "2024-12-06T13:28:34Z",
"status": "True",
"type": "PodScheduled"
}
],
"containerStatuses": [
{
"containerID": "containerd://de0d57479a3ac10e213df6ea4fc1d648ad4d70d4ddf1b95a7999d0050171a41e",
"image": "registry.k8s.io/etcd:3.5.15-0",
"imageID": "sha256:27e3830e1402783674d8b594038967deea9d51f0d91b34c93c8f39d2f68af7da",
"lastState": {
"terminated": {
"containerID": "containerd://28d1a65bd9cfa40624a0c17979208f66a5cc7f496a57fa9a879907bb936f57b3",
"exitCode": 255,
"finishedAt": "2024-12-06T13:28:31Z",
"reason": "Unknown",
"startedAt": "2024-11-04T15:14:19Z"
}
},
"name": "etcd",
"ready": true,
"restartCount": 2,
"started": true,
"state": {
"running": {
"startedAt": "2024-12-06T13:28:35Z"
}
}
}
],
"hostIP": "172.18.0.2",
"hostIPs": [
{
"ip": "172.18.0.2"
}
],
"phase": "Running",
"podIP": "172.18.0.2",
"podIPs": [
{
"ip": "172.18.0.2"
}
],
"qosClass": "Burstable",
"startTime": "2024-12-06T13:28:34Z"
}
}
"#,
)
.into_iter::<serde_json::Value>()
.filter_map(serde_json::Result::ok)
.collect::<Vec<_>>()
.iter(),
);
let mut p = Json::new(stream).title("JSON viewer").prompt()?;
println!("result: {:?}", p.run()?);
Ok(())
}
This project is licensed under the MIT License. See the LICENSE file for details.