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

feat: add alert, confirm, and prompt #7507

Merged
merged 6 commits into from
Oct 13, 2020
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
29 changes: 29 additions & 0 deletions cli/dts/lib.deno.window.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ declare class Window extends EventTarget {
onunload: ((this: Window, ev: Event) => any) | null;
close: () => void;
readonly closed: boolean;
alert: (message?: string) => void;
confirm: (message?: string) => boolean;
prompt: (message?: string, defaultValue?: string) => string | null;
Deno: typeof Deno;
}

Expand All @@ -23,4 +26,30 @@ declare var self: Window & typeof globalThis;
declare var onload: ((this: Window, ev: Event) => any) | null;
declare var onunload: ((this: Window, ev: Event) => any) | null;

/**
* Shows the given message and waits for the enter key pressed.
* If the stdin is not interactive, it does nothing.
* @param message
*/
declare function alert(message?: string): void;

/**
* Shows the given message and waits for the answer. Returns the user's answer as boolean.
* Only `y` and `Y` are considered as true.
* If the stdin is not interactive, it returns false.
* @param message
*/
declare function confirm(message?: string): boolean;

/**
* Shows the given message and waits for the user's input. Returns the user's input as string.
* If the default value is given and the user inputs the empty string, then it returns the given
bartlomieju marked this conversation as resolved.
Show resolved Hide resolved
* default value.
* If the default value is not given and the user inputs the empty string, it returns null.
* If the stdin is not interactive, it returns null.
* @param message
* @param defaultValue
*/
declare function prompt(message?: string, defaultValue?: string): string | null;

/* eslint-enable @typescript-eslint/no-explicit-any */
66 changes: 66 additions & 0 deletions cli/rt/41_prompt.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
((window) => {
const { stdin, stdout } = window.__bootstrap.files;
const { isatty } = window.__bootstrap.tty;
const LF = "\n".charCodeAt(0);
const encoder = new TextEncoder();
const decoder = new TextDecoder();

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

stdout.writeSync(encoder.encode(`${message} [Enter] `));

readLineFromStdinSync();
}

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

stdout.writeSync(encoder.encode(`${message} [y/N] `));

const answer = readLineFromStdinSync();

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

function prompt(message = "Prompt", defaultValue) {
defaultValue ??= null;

if (!isatty(stdin.rid)) {
return null;
}

stdout.writeSync(encoder.encode(`${message} `));

if (defaultValue) {
stdout.writeSync(encoder.encode(`[${defaultValue}] `));
}

return readLineFromStdinSync() || defaultValue;
}

function readLineFromStdinSync() {
const c = new Uint8Array(1);
const buf = [];

while (true) {
const n = stdin.readSync(c);
if (n === 0 || c[0] === LF) {
break;
}
buf.push(c[0]);
}
return decoder.decode(new Uint8Array(buf));
}
bartlomieju marked this conversation as resolved.
Show resolved Hide resolved

window.__bootstrap.prompt = {
alert,
confirm,
prompt,
};
})(this);
4 changes: 4 additions & 0 deletions cli/rt/99_main.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ delete Object.prototype.__proto__;
const fileReader = window.__bootstrap.fileReader;
const webSocket = window.__bootstrap.webSocket;
const fetch = window.__bootstrap.fetch;
const prompt = window.__bootstrap.prompt;
const denoNs = window.__bootstrap.denoNs;
const denoNsUnstable = window.__bootstrap.denoNsUnstable;
const errors = window.__bootstrap.errors.errors;
Expand Down Expand Up @@ -285,6 +286,9 @@ delete Object.prototype.__proto__;
onunload: util.writable(null),
close: util.writable(windowClose),
closed: util.getterOnly(() => windowIsClosing),
alert: util.writable(prompt.alert),
confirm: util.writable(prompt.confirm),
prompt: util.writable(prompt.prompt),
};

const workerRuntimeGlobalProperties = {
Expand Down
17 changes: 17 additions & 0 deletions cli/tests/066_prompt.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
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}`);
alert("Hi");
alert();
console.log("The end of test");
8 changes: 8 additions & 0 deletions cli/tests/066_prompt.ts.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[WILDCARD]What is your name? [Jane Doe] Your name is John Doe.
What is your name? [Jane Doe] Your name is Jane Doe.
Prompt Your input is foo.
Question 0 [y/N] Your answer is true
Question 1 [y/N] Your answer is false
Question 2 [y/N] Your answer is false
Confirm [y/N] Your answer is false
Hi [Enter] Alert [Enter] The end of test
11 changes: 11 additions & 0 deletions cli/tests/integration_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1917,6 +1917,17 @@ itest!(_065_import_map_info {
output: "065_import_map_info.out",
});

#[cfg(unix)]
#[test]
fn _066_prompt() {
let args = "run --unstable 066_prompt.ts";
let output = "066_prompt.ts.out";
// These are answers to prompt, confirm, and alert calls.
let input = b"John Doe\n\nfoo\nY\nN\nyes\n\n\n\n";

util::test_pty(args, output, input);
}

itest!(js_import_detect {
args: "run --quiet --reload js_import_detect.ts",
output: "js_import_detect.ts.out",
Expand Down