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:
parent
27e1b4cb5a
commit
d9c43f7f43
2 changed files with 121 additions and 103 deletions
|
@ -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");
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue