Skip to content

Commit 58520c3

Browse files
feat: restore cursor on ctrl c
1 parent 24a501d commit 58520c3

3 files changed

Lines changed: 29 additions & 1 deletion

File tree

Cargo.lock

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ serde = { workspace = true }
3030
serde_json = { workspace = true, features = ["preserve_order"] }
3131
url = "2.4.1"
3232
sha256 = "1.4.0"
33-
tokio = { version = "1", features = ["macros", "rt"] }
33+
tokio = { version = "1", features = ["macros", "rt", "signal"] }
3434
tokio-tar = { package = "astral-tokio-tar", version = "0.6.0" }
3535
tokio-util = "0.7.16"
3636
md5 = "0.7.0"

src/cli/mod.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,23 @@ pub async fn run() -> Result<()> {
123123
let cli = Cli::parse();
124124
// Important: keep this after the Cli::parse() because the function can exit the process by itself, skipping the drop of the CursorGuard
125125
let _cursor_guard = CursorGuard::new();
126+
if *IS_TTY {
127+
// Ctrl+C terminates the process before `CursorGuard::drop` runs,
128+
// so we restore the cursor explicitly, then re-raise SIGINT with
129+
// the default disposition so the parent shell sees the expected
130+
// signal-terminated status.
131+
tokio::spawn(async {
132+
if tokio::signal::ctrl_c().await.is_ok() {
133+
drop(_cursor_guard); // explicitly drop to restore cursor before re-raising
134+
}
135+
// Safety: resetting SIGINT to SIG_DFL and raising it are
136+
// async-signal-safe and have no Rust-level invariants to break.
137+
unsafe {
138+
libc::signal(libc::SIGINT, libc::SIG_DFL);
139+
libc::raise(libc::SIGINT);
140+
}
141+
});
142+
}
126143

127144
let mut api_client = build_api_client(&cli)?;
128145

0 commit comments

Comments
 (0)