1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2025-01-11 08:33:43 -05:00

fix(web): use rustyline for prompt (#21893)

Workaround until https://github.com/kkawakam/rustyline/pull/759
This commit is contained in:
Divy Srivastava 2024-01-12 02:35:55 +05:30 committed by GitHub
parent d8f86c8b9c
commit 9268df5f34
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 56 additions and 24 deletions

2
Cargo.lock generated
View file

@ -1655,6 +1655,7 @@ dependencies = [
"once_cell", "once_cell",
"regex", "regex",
"ring", "ring",
"rustyline",
"serde", "serde",
"signal-hook-registry", "signal-hook-registry",
"termcolor", "termcolor",
@ -5035,6 +5036,7 @@ dependencies = [
"cfg-if", "cfg-if",
"clipboard-win", "clipboard-win",
"fd-lock", "fd-lock",
"home",
"libc", "libc",
"log", "log",
"memchr", "memchr",

View file

@ -138,6 +138,7 @@ rustls = "0.21.8"
rustls-pemfile = "1.0.0" rustls-pemfile = "1.0.0"
rustls-tokio-stream = "=0.2.17" rustls-tokio-stream = "=0.2.17"
rustls-webpki = "0.101.4" rustls-webpki = "0.101.4"
rustyline = "=13.0.0"
webpki-roots = "0.25.2" webpki-roots = "0.25.2"
scopeguard = "1.2.0" scopeguard = "1.2.0"
saffron = "=0.1.0" saffron = "=0.1.0"

View file

@ -117,7 +117,7 @@ quick-junit = "^0.3.5"
rand = { workspace = true, features = ["small_rng"] } rand = { workspace = true, features = ["small_rng"] }
regex.workspace = true regex.workspace = true
ring.workspace = true ring.workspace = true
rustyline = { version = "=13.0.0", default-features = false, features = ["custom-bindings", "with-file-history"] } rustyline.workspace = true
rustyline-derive = "=0.7.0" rustyline-derive = "=0.7.0"
serde.workspace = true serde.workspace = true
serde_repr.workspace = true serde_repr.workspace = true

View file

@ -2823,12 +2823,10 @@ mod permissions {
.new_command() .new_command()
.args_vec(["run", "--quiet", "--unstable", "run/066_prompt.ts"]) .args_vec(["run", "--quiet", "--unstable", "run/066_prompt.ts"])
.with_pty(|mut console| { .with_pty(|mut console| {
console.expect("What is your name? [Jane Doe] "); console.expect("What is your name? Jane Doe");
console.write_line_raw("John Doe");
console.expect("Your name is John Doe.");
console.expect("What is your name? [Jane Doe] ");
console.write_line_raw(""); console.write_line_raw("");
console.expect("Your name is Jane Doe."); console.expect("Your name is Jane Doe.");
console.expect("Prompt "); console.expect("Prompt ");
console.write_line_raw("foo"); console.write_line_raw("foo");
console.expect("Your input is foo."); console.expect("Your input is foo.");
@ -2852,9 +2850,6 @@ mod permissions {
console.expect("Alert [Enter] "); console.expect("Alert [Enter] ");
console.write_line(""); console.write_line("");
console.expect("The end of test"); console.expect("The end of test");
console.expect("What is EOF? ");
console.write_line("");
console.expect("Your answer is null");
}); });
} }

View file

@ -1,5 +1,3 @@
const name0 = prompt("What is your name?", "Jane Doe"); // Answer John Doe
console.log(`Your name is ${name0}.`);
const name1 = prompt("What is your name?", "Jane Doe"); // Answer with default const name1 = prompt("What is your name?", "Jane Doe"); // Answer with default
console.log(`Your name is ${name1}.`); console.log(`Your name is ${name1}.`);
const input = prompt(); // Answer foo const input = prompt(); // Answer foo
@ -17,5 +15,3 @@ console.log(`Your answer is ${JSON.stringify(windows)}`);
alert("Hi"); alert("Hi");
alert(); alert();
console.log("The end of test"); console.log("The end of test");
const eof = prompt("What is EOF?");
console.log(`Your answer is ${JSON.stringify(eof)}`);

View file

@ -112,6 +112,7 @@ notify.workspace = true
once_cell.workspace = true once_cell.workspace = true
regex.workspace = true regex.workspace = true
ring.workspace = true ring.workspace = true
rustyline = { workspace = true, features = ["custom-bindings"] }
serde.workspace = true serde.workspace = true
signal-hook-registry = "1.4.0" signal-hook-registry = "1.4.0"
termcolor = "1.1.3" termcolor = "1.1.3"

View file

@ -9,6 +9,8 @@ const {
import { isatty } from "ext:runtime/40_tty.js"; import { isatty } from "ext:runtime/40_tty.js";
import { stdin } from "ext:deno_io/12_io.js"; import { stdin } from "ext:deno_io/12_io.js";
const ops = core.ops;
const LF = StringPrototypeCharCodeAt("\n", 0); const LF = StringPrototypeCharCodeAt("\n", 0);
const CR = StringPrototypeCharCodeAt("\r", 0); const CR = StringPrototypeCharCodeAt("\r", 0);
@ -35,22 +37,16 @@ function confirm(message = "Confirm") {
} }
function prompt(message = "Prompt", defaultValue) { function prompt(message = "Prompt", defaultValue) {
defaultValue ??= null; defaultValue ??= "";
if (!isatty(stdin.rid)) { if (!isatty(stdin.rid)) {
return null; return null;
} }
if (defaultValue) { return ops.op_read_line_prompt(
message += ` [${defaultValue}]`; `${message} `,
} `${defaultValue}`,
);
message += " ";
// output in one shot to make the tests more reliable
core.print(message, false);
return readLineFromStdinSync() || defaultValue;
} }
function readLineFromStdinSync() { function readLineFromStdinSync() {

View file

@ -5,6 +5,13 @@ use std::io::Error;
use deno_core::error::AnyError; use deno_core::error::AnyError;
use deno_core::op2; use deno_core::op2;
use deno_core::OpState; 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)] #[cfg(unix)]
use deno_core::ResourceId; use deno_core::ResourceId;
@ -43,7 +50,12 @@ use winapi::um::wincon;
deno_core::extension!( deno_core::extension!(
deno_tty, 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| { state = |state| {
#[cfg(unix)] #[cfg(unix)]
state.put(TtyModeStore::default()); 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()),
}
}