1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-12-22 23:34:47 -05:00

feat(repl): support autocomplete on declarations containing a primitive (#11325)

This commit is contained in:
David Sherret 2021-07-08 12:58:18 -04:00 committed by GitHub
parent 27e1b4cb5a
commit d9c43f7f43
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 121 additions and 103 deletions

View file

@ -6,10 +6,7 @@ use test_util as util;
#[test]
fn pty_multiline() {
use std::io::{Read, Write};
use util::pty::fork::*;
let deno_exe = util::deno_exe_path();
let fork = Fork::from_ptmx().unwrap();
if let Ok(mut master) = fork.is_parent() {
run_pty_test(|master| {
master.write_all(b"(\n1 + 2\n)\n").unwrap();
master.write_all(b"{\nfoo: \"foo\"\n}\n").unwrap();
master.write_all(b"`\nfoo\n`\n").unwrap();
@ -37,24 +34,14 @@ fn pty_multiline() {
assert!(output.contains("/(/"));
assert!(output.contains("/{/"));
assert!(output.contains("[ \"{test1}\", \"test1\" ]"));
fork.wait().unwrap();
} else {
std::env::set_var("NO_COLOR", "1");
let err = exec::Command::new(deno_exe).arg("repl").exec();
println!("err {}", err);
unreachable!()
}
});
}
#[cfg(unix)]
#[test]
fn pty_unpaired_braces() {
use std::io::{Read, Write};
use util::pty::fork::*;
let deno_exe = util::deno_exe_path();
let fork = Fork::from_ptmx().unwrap();
if let Ok(mut master) = fork.is_parent() {
run_pty_test(|master| {
master.write_all(b")\n").unwrap();
master.write_all(b"]\n").unwrap();
master.write_all(b"}\n").unwrap();
@ -66,24 +53,14 @@ fn pty_unpaired_braces() {
assert!(output.contains("Unexpected token `)`"));
assert!(output.contains("Unexpected token `]`"));
assert!(output.contains("Unexpected token `}`"));
fork.wait().unwrap();
} else {
std::env::set_var("NO_COLOR", "1");
let err = exec::Command::new(deno_exe).arg("repl").exec();
println!("err {}", err);
unreachable!()
}
});
}
#[cfg(unix)]
#[test]
fn pty_bad_input() {
use std::io::{Read, Write};
use util::pty::fork::*;
let deno_exe = util::deno_exe_path();
let fork = Fork::from_ptmx().unwrap();
if let Ok(mut master) = fork.is_parent() {
run_pty_test(|master| {
master.write_all(b"'\\u{1f3b5}'[0]\n").unwrap();
master.write_all(b"close();\n").unwrap();
@ -91,24 +68,14 @@ fn pty_bad_input() {
master.read_to_string(&mut output).unwrap();
assert!(output.contains("Unterminated string literal"));
fork.wait().unwrap();
} else {
std::env::set_var("NO_COLOR", "1");
let err = exec::Command::new(deno_exe).arg("repl").exec();
println!("err {}", err);
unreachable!()
}
});
}
#[cfg(unix)]
#[test]
fn pty_complete_symbol() {
use std::io::{Read, Write};
use util::pty::fork::*;
let deno_exe = util::deno_exe_path();
let fork = Fork::from_ptmx().unwrap();
if let Ok(mut master) = fork.is_parent() {
run_pty_test(|master| {
master.write_all(b"Symbol.it\t\n").unwrap();
master.write_all(b"close();\n").unwrap();
@ -116,24 +83,14 @@ fn pty_complete_symbol() {
master.read_to_string(&mut output).unwrap();
assert!(output.contains("Symbol(Symbol.iterator)"));
fork.wait().unwrap();
} else {
std::env::set_var("NO_COLOR", "1");
let err = exec::Command::new(deno_exe).arg("repl").exec();
println!("err {}", err);
unreachable!()
}
});
}
#[cfg(unix)]
#[test]
fn pty_complete_declarations() {
use std::io::{Read, Write};
use util::pty::fork::*;
let deno_exe = util::deno_exe_path();
let fork = Fork::from_ptmx().unwrap();
if let Ok(mut master) = fork.is_parent() {
run_pty_test(|master| {
master.write_all(b"class MyClass {}\n").unwrap();
master.write_all(b"My\t\n").unwrap();
master.write_all(b"let myVar;\n").unwrap();
@ -145,24 +102,40 @@ fn pty_complete_declarations() {
assert!(output.contains("> MyClass"));
assert!(output.contains("> myVar"));
fork.wait().unwrap();
} else {
std::env::set_var("NO_COLOR", "1");
let err = exec::Command::new(deno_exe).arg("repl").exec();
println!("err {}", err);
unreachable!()
});
}
#[cfg(unix)]
#[test]
fn pty_complete_primitives() {
use std::io::{Read, Write};
run_pty_test(|master| {
master.write_all(b"let func = function test(){}\n").unwrap();
master.write_all(b"func.appl\t\n").unwrap();
master.write_all(b"let str = ''\n").unwrap();
master.write_all(b"str.leng\t\n").unwrap();
master.write_all(b"false.valueO\t\n").unwrap();
master.write_all(b"5n.valueO\t\n").unwrap();
master.write_all(b"let num = 5\n").unwrap();
master.write_all(b"num.toStrin\t\n").unwrap();
master.write_all(b"close();\n").unwrap();
let mut output = String::new();
master.read_to_string(&mut output).unwrap();
assert!(output.contains("> func.apply"));
assert!(output.contains("> str.length"));
assert!(output.contains("> 5n.valueOf"));
assert!(output.contains("> false.valueOf"));
assert!(output.contains("> num.toString"));
});
}
#[cfg(unix)]
#[test]
fn pty_ignore_symbols() {
use std::io::{Read, Write};
use util::pty::fork::*;
let deno_exe = util::deno_exe_path();
let fork = Fork::from_ptmx().unwrap();
if let Ok(mut master) = fork.is_parent() {
run_pty_test(|master| {
master.write_all(b"Array.Symbol\t\n").unwrap();
master.write_all(b"close();\n").unwrap();
@ -173,7 +146,16 @@ fn pty_ignore_symbols() {
assert!(
!output.contains("Uncaught TypeError: Array.Symbol is not a function")
);
});
}
#[cfg(unix)]
fn run_pty_test(mut run: impl FnMut(&mut util::pty::fork::Master)) {
use util::pty::fork::*;
let deno_exe = util::deno_exe_path();
let fork = Fork::from_ptmx().unwrap();
if let Ok(mut master) = fork.is_parent() {
run(&mut master);
fork.wait().unwrap();
} else {
std::env::set_var("NO_COLOR", "1");

View file

@ -47,18 +47,7 @@ struct EditorHelper {
}
impl EditorHelper {
fn post_message(
&self,
method: &str,
params: Option<Value>,
) -> Result<Value, AnyError> {
self
.message_tx
.blocking_send((method.to_string(), params))?;
self.response_rx.borrow_mut().blocking_recv().unwrap()
}
fn get_global_lexical_scope_names(&self) -> Vec<String> {
pub fn get_global_lexical_scope_names(&self) -> Vec<String> {
let evaluate_response = self
.post_message(
"Runtime.globalLexicalScopeNames",
@ -78,7 +67,67 @@ impl EditorHelper {
.collect()
}
fn get_expression_property_names(&self, expr: &str) -> Vec<String> {
pub fn get_expression_property_names(&self, expr: &str) -> Vec<String> {
// try to get the properties from the expression
if let Some(properties) = self.get_object_expr_properties(expr) {
return properties;
}
// otherwise fall back to the prototype
let expr_type = self.get_expression_type(expr);
let object_expr = match expr_type.as_deref() {
// possibilities: https://chromedevtools.github.io/devtools-protocol/v8/Runtime/#type-RemoteObject
Some("object") => "Object.prototype",
Some("function") => "Function.prototype",
Some("string") => "String.prototype",
Some("boolean") => "Boolean.prototype",
Some("bigint") => "BigInt.prototype",
Some("number") => "Number.prototype",
_ => return Vec::new(), // undefined, symbol, and unhandled
};
self
.get_object_expr_properties(object_expr)
.unwrap_or_else(Vec::new)
}
fn get_expression_type(&self, expr: &str) -> Option<String> {
self
.evaluate_expression(expr)?
.get("result")?
.get("type")?
.as_str()
.map(|s| s.to_string())
}
fn get_object_expr_properties(
&self,
object_expr: &str,
) -> Option<Vec<String>> {
let evaluate_result = self.evaluate_expression(object_expr)?;
let object_id = evaluate_result.get("result")?.get("objectId")?;
let get_properties_response = self
.post_message(
"Runtime.getProperties",
Some(json!({
"objectId": object_id,
})),
)
.ok()?;
Some(
get_properties_response
.get("result")?
.as_array()
.unwrap()
.iter()
.map(|r| r.get("name").unwrap().as_str().unwrap().to_string())
.collect(),
)
}
fn evaluate_expression(&self, expr: &str) -> Option<Value> {
let evaluate_response = self
.post_message(
"Runtime.evaluate",
@ -89,37 +138,24 @@ impl EditorHelper {
"timeout": 200,
})),
)
.unwrap();
.ok()?;
if evaluate_response.get("exceptionDetails").is_some() {
return Vec::new();
}
if let Some(result) = evaluate_response.get("result") {
if let Some(object_id) = result.get("objectId") {
let get_properties_response = self.post_message(
"Runtime.getProperties",
Some(json!({
"objectId": object_id,
})),
);
if let Ok(get_properties_response) = get_properties_response {
if let Some(result) = get_properties_response.get("result") {
let property_names = result
.as_array()
.unwrap()
.iter()
.map(|r| r.get("name").unwrap().as_str().unwrap().to_string())
.collect();
return property_names;
}
}
None
} else {
Some(evaluate_response)
}
}
Vec::new()
fn post_message(
&self,
method: &str,
params: Option<Value>,
) -> Result<Value, AnyError> {
self
.message_tx
.blocking_send((method.to_string(), params))?;
self.response_rx.borrow_mut().blocking_recv().unwrap()
}
}