Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Revert "fix(runtime): Make native modal keyboard interaction consistent with browsers" #21739

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,6 @@ rustls = "0.21.8"
rustls-pemfile = "1.0.0"
rustls-tokio-stream = "=0.2.16"
rustls-webpki = "0.101.4"
rustyline = "=13.0.0"
webpki-roots = "0.25.2"
scopeguard = "1.2.0"
saffron = "=0.1.0"
Expand Down
2 changes: 1 addition & 1 deletion cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ quick-junit = "^0.3.5"
rand = { workspace = true, features = ["small_rng"] }
regex.workspace = true
ring.workspace = true
rustyline.workspace = true
rustyline = { version = "=13.0.0", default-features = false, features = ["custom-bindings", "with-file-history"] }
rustyline-derive = "=0.7.0"
serde.workspace = true
serde_repr.workspace = true
Expand Down
179 changes: 32 additions & 147 deletions cli/tests/integration/run_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2807,155 +2807,40 @@ mod permissions {
fn _066_prompt() {
TestContext::default()
.new_command()
.args_vec(["repl"])
.args_vec(["run", "--quiet", "--unstable", "run/066_prompt.ts"])
.with_pty(|mut console| {
// alert with no message displays default "Alert"
// alert displays "[Press any key to continue]"
// alert can be closed with Enter key
console.write_line_raw("alert()");
console.expect("Alert [Press any key to continue]");
console.write_raw("\r"); // Enter
console.expect("undefined");

// alert can be closed with Escape key
console.write_line_raw("alert()");
console.expect("Alert [Press any key to continue]");
console.write_raw("\x1b"); // Escape
console.expect("undefined");

// alert can display custom text
// alert can be closed with arbitrary keyboard key (x)
if !cfg!(windows) {
// it seems to work on windows, just not in the tests
console.write_line_raw("alert('foo')");
console.expect("foo [Press any key to continue]");
console.write_raw("x");
console.expect("undefined");
}

// confirm with no message displays default "Confirm"
// confirm returns true by immediately pressing Enter
console.write_line_raw("confirm()");
console.expect("Confirm [Y/n]");
console.write_raw("\r"); // Enter
console.expect("true");

// tese seem to work on windows, just not in the tests
if !cfg!(windows) {
// confirm returns false by pressing Escape
console.write_line_raw("confirm()");
console.expect("Confirm [Y/n]");
console.write_raw("\x1b"); // Escape
console.expect("false");

// confirm can display custom text
// confirm returns true by pressing y
console.write_line_raw("confirm('continue?')");
console.expect("continue? [Y/n]");
console.write_raw("y");
console.expect("true");

// confirm returns false by pressing n
console.write_line_raw("confirm('continue?')");
console.expect("continue? [Y/n]");
console.write_raw("n");
console.expect("false");

// confirm can display custom text
// confirm returns true by pressing Y
console.write_line_raw("confirm('continue?')");
console.expect("continue? [Y/n]");
console.write_raw("Y");
console.expect("true");

// confirm returns false by pressing N
console.write_line_raw("confirm('continue?')");
console.expect("continue? [Y/n]");
console.write_raw("N");
console.expect("false");
}

// prompt with no message displays default "Prompt"
// prompt returns user-inserted text
console.write_line_raw("prompt()");
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.expect("Your name is Jane Doe.");
console.expect("Prompt ");
console.write_line_raw("abc");
console.expect("\"abc\"");

// prompt can display custom text
// prompt with no default value returns empty string when immediately pressing Enter
console.write_line_raw("prompt('foo')");
console.expect("foo ");
console.write_raw("\r"); // Enter
console.expect("\"\"");

// prompt with non-string default value converts it to string
console.write_line_raw("prompt('foo', 1)");
console.expect("foo 1");
console.write_raw("\r"); // Enter
console.expect("\"1\"");

// prompt with non-string default value that can't be converted throws an error
console.write_line_raw("prompt('foo', Symbol())");
console.expect(
"Uncaught TypeError: Cannot convert a Symbol value to a string",
);

// prompt with empty-string default value returns empty string when immediately pressing Enter
console.write_line_raw("prompt('foo', '')");
console.expect("foo ");
console.write_raw("\r"); // Enter
console.expect("\"\"");

// prompt with contentful default value returns default value when immediately pressing Enter
console.write_line_raw("prompt('foo', 'bar')");
console.expect("foo bar");
console.write_raw("\r"); // Enter
console.expect("\"bar\"");

// prompt with contentful default value allows editing of default value
console.write_line_raw("prompt('foo', 'bar')");
console.expect("foo bar");
console.write_raw("\x1b[D"); // Left arrow
console.write_raw("\x1b[D"); // Left arrow
console.write_raw("\x7f"); // Backspace
console.write_raw("c");
console.expect("foo car");
console.write_raw("\r"); // Enter
console.expect("\"car\"");

// prompt returns null by pressing Escape
console.write_line_raw("prompt()");
console.expect("Prompt ");
console.write_raw("\x1b"); // Escape
console.expect("null");

#[cfg(not(any(target_os = "macos", target_os = "windows")))]
{
// confirm returns false by pressing Ctrl+C
console.write_line_raw("confirm()");
console.expect("Confirm [Y/n] ");
console.write_raw("\x03"); // Ctrl+C
console.expect("false");

// confirm returns false by pressing Ctrl+D
console.write_line_raw("confirm()");
console.expect("Confirm [Y/n] ");
console.write_raw("\x04"); // Ctrl+D
console.expect("false");

// prompt returns null by pressing Ctrl+C
console.write_line_raw("prompt()");
console.expect("Prompt ");
console.write_raw("\x03"); // Ctrl+C
console.expect("null");

// prompt returns null by pressing Ctrl+D
console.write_line_raw("prompt()");
console.expect("Prompt ");
console.write_raw("\x04"); // Ctrl+D
console.expect("null");
}
console.write_line_raw("foo");
console.expect("Your input is foo.");
console.expect("Question 0 [y/N] ");
console.write_line_raw("Y");
console.expect("Your answer is true");
console.expect("Question 1 [y/N] ");
console.write_line_raw("N");
console.expect("Your answer is false");
console.expect("Question 2 [y/N] ");
console.write_line_raw("yes");
console.expect("Your answer is false");
console.expect("Confirm [y/N] ");
console.write_line("");
console.expect("Your answer is false");
console.expect("What is Windows EOL? ");
console.write_line("windows");
console.expect("Your answer is \"windows\"");
console.expect("Hi [Enter] ");
console.write_line("");
console.expect("Alert [Enter] ");
console.write_line("");
console.expect("The end of test");
console.expect("What is EOF? ");
console.write_line("");
console.expect("Your answer is null");
});
}

Expand Down
21 changes: 21 additions & 0 deletions cli/tests/testdata/run/066_prompt.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
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
console.log(`Your name is ${name1}.`);
const input = prompt(); // Answer foo
console.log(`Your input is ${input}.`);
const answer0 = confirm("Question 0"); // Answer y
console.log(`Your answer is ${answer0}`);
const answer1 = confirm("Question 1"); // Answer n
console.log(`Your answer is ${answer1}`);
const answer2 = confirm("Question 2"); // Answer with yes (returns false)
console.log(`Your answer is ${answer2}`);
const answer3 = confirm(); // Answer with default
console.log(`Your answer is ${answer3}`);
const windows = prompt("What is Windows EOL?");
console.log(`Your answer is ${JSON.stringify(windows)}`);
alert("Hi");
alert();
console.log("The end of test");
const eof = prompt("What is EOF?");
console.log(`Your answer is ${JSON.stringify(eof)}`);
1 change: 0 additions & 1 deletion runtime/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,6 @@ 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"
Expand Down
107 changes: 45 additions & 62 deletions runtime/js/41_prompt.js
Original file line number Diff line number Diff line change
@@ -1,95 +1,78 @@
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
import { core, primordials } from "ext:core/mod.js";
const ops = core.ops;
import { isatty } from "ext:runtime/40_tty.js";
import { stdin } from "ext:deno_io/12_io.js";
import { getNoColor } from "ext:deno_console/01_console.js";
const { Uint8Array, StringFromCodePoint } = primordials;

const ESC = "\x1b";
const CTRL_C = "\x03";
const CTRL_D = "\x04";

const bold = ansi(1, 22);
const italic = ansi(3, 23);
const yellow = ansi(33, 0);
function ansi(start, end) {
return (str) => getNoColor() ? str : `\x1b[${start}m${str}\x1b[${end}m`;
}
const { ArrayPrototypePush, StringPrototypeCharCodeAt, Uint8Array } =
primordials;
const LF = StringPrototypeCharCodeAt("\n", 0);
const CR = StringPrototypeCharCodeAt("\r", 0);

function alert(message = "Alert") {
if (!isatty(stdin.rid)) {
return;
}

core.print(
`${yellow(bold(`${message}`))} [${italic("Press any key to continue")}] `,
);

try {
stdin.setRaw(true);
stdin.readSync(new Uint8Array(1024));
} finally {
stdin.setRaw(false);
}
core.print(`${message} [Enter] `, false);

core.print("\n");
readLineFromStdinSync();
}

function prompt(message = "Prompt", defaultValue = "") {
function confirm(message = "Confirm") {
if (!isatty(stdin.rid)) {
return null;
return false;
}

return ops.op_read_line_prompt(
`${message} `,
`${defaultValue}`,
);
core.print(`${message} [y/N] `, false);

const answer = readLineFromStdinSync();

return answer === "Y" || answer === "y";
}

const inputMap = new primordials.Map([
["Y", true],
["y", true],
["\r", true],
["\n", true],
["\r\n", true],
["N", false],
["n", false],
[ESC, false],
[CTRL_C, false],
[CTRL_D, false],
]);
function prompt(message = "Prompt", defaultValue) {
defaultValue ??= null;

function confirm(message = "Confirm") {
if (!isatty(stdin.rid)) {
return false;
return null;
}

core.print(`${yellow(bold(`${message}`))} [${italic("Y/n")}] `);
if (defaultValue) {
message += ` [${defaultValue}]`;
}

let val = false;
try {
stdin.setRaw(true);
message += " ";

while (true) {
const b = new Uint8Array(1024);
stdin.readSync(b);
let byteString = "";
// output in one shot to make the tests more reliable
core.print(message, false);

let i = 0;
while (b[i]) byteString += StringFromCodePoint(b[i++]);
return readLineFromStdinSync() || defaultValue;
}

if (inputMap.has(byteString)) {
val = inputMap.get(byteString);
function readLineFromStdinSync() {
const c = new Uint8Array(1);
const buf = [];

while (true) {
const n = stdin.readSync(c);
if (n === null || n === 0) {
break;
}
if (c[0] === CR) {
const n = stdin.readSync(c);
if (c[0] === LF) {
break;
}
ArrayPrototypePush(buf, CR);
if (n === null || n === 0) {
break;
}
}
} finally {
stdin.setRaw(false);
if (c[0] === LF) {
break;
}
ArrayPrototypePush(buf, c[0]);
}

core.print(`${val ? "y" : "n"}\n`);
return val;
return core.decode(new Uint8Array(buf));
}

export { alert, confirm, prompt };
Loading