Skip to content

Commit 62112e5

Browse files
refactor(cli): replace promptly with dialoguer
1 parent 6b33766 commit 62112e5

File tree

4 files changed

+78
-165
lines changed

4 files changed

+78
-165
lines changed

Cargo.lock

+18-140
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

sqlx-cli/Cargo.toml

+2-2
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ path = "src/bin/cargo-sqlx.rs"
2626

2727
[dependencies]
2828
dotenvy = "0.15.0"
29-
tokio = { version = "1.15.0", features = ["macros", "rt", "rt-multi-thread"] }
29+
tokio = { version = "1.15.0", features = ["macros", "rt", "rt-multi-thread", "signal"] }
3030
sqlx = { workspace = true, default-features = false, features = [
3131
"runtime-tokio",
3232
"migrate",
@@ -39,7 +39,7 @@ chrono = { version = "0.4.19", default-features = false, features = ["clock"] }
3939
anyhow = "1.0.52"
4040
async-trait = "0.1.52"
4141
console = "0.15.0"
42-
promptly = "0.3.0"
42+
dialoguer = { version = "0.11", default-features = false }
4343
serde_json = "1.0.73"
4444
glob = "0.3.0"
4545
openssl = { version = "0.10.38", optional = true }

sqlx-cli/src/database.rs

+42-23
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
use crate::migrate;
22
use crate::opt::ConnectOpts;
3-
use console::style;
4-
use promptly::{prompt, ReadlineError};
3+
use console::{style, Term};
4+
use dialoguer::Confirm;
55
use sqlx::any::Any;
66
use sqlx::migrate::MigrateDatabase;
7+
use std::{io, mem};
8+
use tokio::task;
79

810
pub async fn create(connect_opts: &ConnectOpts) -> anyhow::Result<()> {
911
// NOTE: only retry the idempotent action.
@@ -24,7 +26,7 @@ pub async fn create(connect_opts: &ConnectOpts) -> anyhow::Result<()> {
2426
}
2527

2628
pub async fn drop(connect_opts: &ConnectOpts, confirm: bool, force: bool) -> anyhow::Result<()> {
27-
if confirm && !ask_to_continue_drop(connect_opts.required_db_url()?) {
29+
if confirm && !ask_to_continue_drop(connect_opts.required_db_url()?.to_owned()).await {
2830
return Ok(());
2931
}
3032

@@ -58,27 +60,44 @@ pub async fn setup(migration_source: &str, connect_opts: &ConnectOpts) -> anyhow
5860
migrate::run(migration_source, connect_opts, false, false, None).await
5961
}
6062

61-
fn ask_to_continue_drop(db_url: &str) -> bool {
62-
loop {
63-
let r: Result<String, ReadlineError> =
64-
prompt(format!("Drop database at {}? (y/n)", style(db_url).cyan()));
65-
match r {
66-
Ok(response) => {
67-
if response == "n" || response == "N" {
68-
return false;
69-
} else if response == "y" || response == "Y" {
70-
return true;
71-
} else {
72-
println!(
73-
"Response not recognized: {}\nPlease type 'y' or 'n' and press enter.",
74-
response
75-
);
76-
}
77-
}
78-
Err(e) => {
79-
println!("{e}");
80-
return false;
63+
async fn ask_to_continue_drop(db_url: String) -> bool {
64+
struct RestoreCursorGuard {
65+
disarmed: bool,
66+
}
67+
68+
impl Drop for RestoreCursorGuard {
69+
fn drop(&mut self) {
70+
if !self.disarmed {
71+
Term::stderr().show_cursor().unwrap()
8172
}
8273
}
8374
}
75+
76+
let mut guard = RestoreCursorGuard { disarmed: false };
77+
78+
let decision_result = task::spawn_blocking(move || {
79+
Confirm::new()
80+
.with_prompt(format!("Drop database at {}?", style(&db_url).cyan()))
81+
.wait_for_newline(true)
82+
.default(false)
83+
.show_default(true)
84+
.interact()
85+
})
86+
.await
87+
.expect("Confirm thread panicked");
88+
match decision_result {
89+
Ok(decision) => {
90+
guard.disarmed = true;
91+
decision
92+
}
93+
Err(dialoguer::Error::IO(err)) if err.kind() == io::ErrorKind::Interrupted => {
94+
// Sometimes CTRL + C causes this error to be returned
95+
mem::drop(guard);
96+
false
97+
}
98+
Err(err) => {
99+
mem::drop(guard);
100+
panic!("Confirm dialog failed with {err}")
101+
}
102+
}
84103
}

0 commit comments

Comments
 (0)