summaryrefslogtreecommitdiff
path: root/runtime
diff options
context:
space:
mode:
Diffstat (limited to 'runtime')
-rw-r--r--runtime/Cargo.toml1
-rw-r--r--runtime/js/41_prompt.js18
-rw-r--r--runtime/ops/tty.rs43
3 files changed, 50 insertions, 12 deletions
diff --git a/runtime/Cargo.toml b/runtime/Cargo.toml
index 223c42ffb..52149357f 100644
--- a/runtime/Cargo.toml
+++ b/runtime/Cargo.toml
@@ -112,6 +112,7 @@ notify.workspace = true
once_cell.workspace = true
regex.workspace = true
ring.workspace = true
+rustyline = { workspace = true, features = ["custom-bindings"] }
serde.workspace = true
signal-hook-registry = "1.4.0"
termcolor = "1.1.3"
diff --git a/runtime/js/41_prompt.js b/runtime/js/41_prompt.js
index 4e2f0fffc..e9f10e244 100644
--- a/runtime/js/41_prompt.js
+++ b/runtime/js/41_prompt.js
@@ -9,6 +9,8 @@ const {
import { isatty } from "ext:runtime/40_tty.js";
import { stdin } from "ext:deno_io/12_io.js";
+const ops = core.ops;
+
const LF = StringPrototypeCharCodeAt("\n", 0);
const CR = StringPrototypeCharCodeAt("\r", 0);
@@ -35,22 +37,16 @@ function confirm(message = "Confirm") {
}
function prompt(message = "Prompt", defaultValue) {
- defaultValue ??= null;
+ defaultValue ??= "";
if (!isatty(stdin.rid)) {
return null;
}
- if (defaultValue) {
- message += ` [${defaultValue}]`;
- }
-
- message += " ";
-
- // output in one shot to make the tests more reliable
- core.print(message, false);
-
- return readLineFromStdinSync() || defaultValue;
+ return ops.op_read_line_prompt(
+ `${message} `,
+ `${defaultValue}`,
+ );
}
function readLineFromStdinSync() {
diff --git a/runtime/ops/tty.rs b/runtime/ops/tty.rs
index 3227ee562..6cc129883 100644
--- a/runtime/ops/tty.rs
+++ b/runtime/ops/tty.rs
@@ -5,6 +5,13 @@ use std::io::Error;
use deno_core::error::AnyError;
use deno_core::op2;
use deno_core::OpState;
+use rustyline::config::Configurer;
+use rustyline::error::ReadlineError;
+use rustyline::Cmd;
+use rustyline::Editor;
+use rustyline::KeyCode;
+use rustyline::KeyEvent;
+use rustyline::Modifiers;
#[cfg(unix)]
use deno_core::ResourceId;
@@ -43,7 +50,12 @@ use winapi::um::wincon;
deno_core::extension!(
deno_tty,
- ops = [op_stdin_set_raw, op_isatty, op_console_size],
+ ops = [
+ op_stdin_set_raw,
+ op_isatty,
+ op_console_size,
+ op_read_line_prompt
+ ],
state = |state| {
#[cfg(unix)]
state.put(TtyModeStore::default());
@@ -320,3 +332,32 @@ mod tests {
);
}
}
+
+#[op2]
+#[string]
+pub fn op_read_line_prompt(
+ #[string] prompt_text: &str,
+ #[string] default_value: &str,
+) -> Result<Option<String>, AnyError> {
+ let mut editor = Editor::<(), rustyline::history::DefaultHistory>::new()
+ .expect("Failed to create editor.");
+
+ editor.set_keyseq_timeout(1);
+ editor
+ .bind_sequence(KeyEvent(KeyCode::Esc, Modifiers::empty()), Cmd::Interrupt);
+
+ let read_result =
+ editor.readline_with_initial(prompt_text, (default_value, ""));
+ match read_result {
+ Ok(line) => Ok(Some(line)),
+ Err(ReadlineError::Interrupted) => {
+ // SAFETY: Disable raw mode and raise SIGINT.
+ unsafe {
+ libc::raise(libc::SIGINT);
+ }
+ Ok(None)
+ }
+ Err(ReadlineError::Eof) => Ok(None),
+ Err(err) => Err(err.into()),
+ }
+}