summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatt Mastracci <matthew@mastracci.com>2024-02-18 21:51:06 -0700
committerGitHub <noreply@github.com>2024-02-19 04:51:06 +0000
commit7e6b94231290020b55f1d08fb03ea8132781abc5 (patch)
tree3767f12db7180b13175c5a7f33c731b192f891a5
parent9a43a2b4959be288034ef0c43f638542de2028b8 (diff)
feat(core): highlight unprintable chars in permission prompts (#22468)
If we strip out unprintable chars, we don't see the full filename being requested by permission prompts. Instead, we highlight and escape them to make them visible.
-rw-r--r--runtime/permissions/prompter.rs30
-rw-r--r--tests/integration/run_tests.rs20
2 files changed, 29 insertions, 21 deletions
diff --git a/runtime/permissions/prompter.rs b/runtime/permissions/prompter.rs
index f054b31f3..da5979f0a 100644
--- a/runtime/permissions/prompter.rs
+++ b/runtime/permissions/prompter.rs
@@ -11,12 +11,24 @@ use std::io::StderrLock;
use std::io::StdinLock;
use std::io::Write as IoWrite;
-/// Helper function to strip ansi codes and ASCII control characters.
-fn strip_ansi_codes_and_ascii_control(s: &str) -> std::borrow::Cow<str> {
- console_static_text::ansi::strip_ansi_codes(s)
- .chars()
- .filter(|c| !c.is_ascii_control())
- .collect()
+/// Helper function to make control characters visible so users can see the underlying filename.
+fn escape_control_characters(s: &str) -> std::borrow::Cow<str> {
+ if !s.contains(|c: char| c.is_ascii_control() || c.is_control()) {
+ return std::borrow::Cow::Borrowed(s);
+ }
+ let mut output = String::with_capacity(s.len() * 2);
+ for c in s.chars() {
+ match c {
+ c if c.is_ascii_control() => output.push_str(
+ &colors::white_bold_on_red(c.escape_debug().to_string()).to_string(),
+ ),
+ c if c.is_control() => output.push_str(
+ &colors::white_bold_on_red(c.escape_debug().to_string()).to_string(),
+ ),
+ c => output.push(c),
+ }
+ }
+ output.into()
}
pub const PERMISSION_EMOJI: &str = "⚠️";
@@ -249,9 +261,9 @@ impl PermissionPrompter for TtyPrompter {
return PromptResponse::Deny; // don't grant permission if this fails
}
- let message = strip_ansi_codes_and_ascii_control(message);
- let name = strip_ansi_codes_and_ascii_control(name);
- let api_name = api_name.map(strip_ansi_codes_and_ascii_control);
+ let message = escape_control_characters(message);
+ let name = escape_control_characters(name);
+ let api_name = api_name.map(escape_control_characters);
// print to stderr so that if stdout is piped this is still displayed.
let opts: String = if is_unary {
diff --git a/tests/integration/run_tests.rs b/tests/integration/run_tests.rs
index 02fb915b5..a4bfc6345 100644
--- a/tests/integration/run_tests.rs
+++ b/tests/integration/run_tests.rs
@@ -4725,19 +4725,19 @@ fn stdio_streams_are_locked_in_permission_prompt() {
}
#[test]
-fn permission_prompt_strips_ansi_codes_and_control_chars() {
+fn permission_prompt_escapes_ansi_codes_and_control_chars() {
util::with_pty(&["repl"], |mut console| {
console.write_line(
r#"Deno.permissions.request({ name: "env", variable: "\rDo you like ice cream? y/n" });"#
);
// will be uppercase on windows
let env_name = if cfg!(windows) {
- "DO YOU LIKE ICE CREAM? Y/N"
+ "\\rDO YOU LIKE ICE CREAM? Y/N"
} else {
- "Do you like ice cream? y/n"
+ "\\rDo you like ice cream? y/n"
};
console.expect(format!(
- "┌ ⚠️ Deno requests env access to \"{}\".",
+ "\u{250c} \u{26a0}\u{fe0f} Deno requests env access to \"{}\".",
env_name
))
});
@@ -4747,14 +4747,10 @@ fn permission_prompt_strips_ansi_codes_and_control_chars() {
console.expect("undefined");
console.write_line_raw(r#"const unboldANSI = "\u001b[22m";"#);
console.expect("undefined");
- console.write_line_raw(r#"const prompt = `┌ ⚠️ ${boldANSI}Deno requests run access to "echo"${unboldANSI}\n ├ Requested by \`Deno.Command().output()`"#);
- console.expect("undefined");
- console.write_line_raw(r#"const moveANSIUp = "\u001b[1A";"#);
- console.expect("undefined");
- console.write_line_raw(r#"const clearANSI = "\u001b[2K";"#);
- console.expect("undefined");
- console.write_line_raw(r#"const moveANSIStart = "\u001b[1000D";"#);
- console.expect("undefined");
+ console.write_line_raw(
+ r#"new Deno.Command(`${boldANSI}cat${unboldANSI}`).spawn();"#,
+ );
+ console.expect("\u{250c} \u{26a0}\u{fe0f} Deno requests run access to \"\\u{1b}[1mcat\\u{1b}[22m\".");
});
}