summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Sherret <dsherret@users.noreply.github.com>2021-11-25 14:05:12 -0500
committerGitHub <noreply@github.com>2021-11-25 14:05:12 -0500
commit6a780543a43d4d370c42b557955200c59bcb21e8 (patch)
treefc53d1b825a162b0d101803b5be25ec4458889e2
parentf3c0f0565bbf43b4cc31979b05e729d4f4a1538f (diff)
refactor(repl): move rustyline sync channel communication into struct (#12900)
-rw-r--r--cli/tools/repl/channel.rs74
-rw-r--r--cli/tools/repl/mod.rs (renamed from cli/tools/repl.rs)49
2 files changed, 92 insertions, 31 deletions
diff --git a/cli/tools/repl/channel.rs b/cli/tools/repl/channel.rs
new file mode 100644
index 000000000..54ec6869d
--- /dev/null
+++ b/cli/tools/repl/channel.rs
@@ -0,0 +1,74 @@
+// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
+
+use deno_core::anyhow::anyhow;
+use deno_core::error::AnyError;
+use deno_core::serde_json::Value;
+use std::cell::RefCell;
+use tokio::sync::mpsc::channel;
+use tokio::sync::mpsc::unbounded_channel;
+use tokio::sync::mpsc::Receiver;
+use tokio::sync::mpsc::Sender;
+use tokio::sync::mpsc::UnboundedReceiver;
+use tokio::sync::mpsc::UnboundedSender;
+
+/// Rustyline uses synchronous methods in its interfaces, but we need to call
+/// async methods. To get around this, we communicate with async code by using
+/// a channel and blocking on the result.
+pub fn rustyline_channel(
+) -> (RustylineSyncMessageSender, RustylineSyncMessageHandler) {
+ let (message_tx, message_rx) = channel(1);
+ let (response_tx, response_rx) = unbounded_channel();
+
+ (
+ RustylineSyncMessageSender {
+ message_tx,
+ response_rx: RefCell::new(response_rx),
+ },
+ RustylineSyncMessageHandler {
+ response_tx,
+ message_rx,
+ },
+ )
+}
+
+pub type RustylineSyncMessage = (String, Option<Value>);
+pub type RustylineSyncResponse = Result<Value, AnyError>;
+
+pub struct RustylineSyncMessageSender {
+ message_tx: Sender<RustylineSyncMessage>,
+ response_rx: RefCell<UnboundedReceiver<RustylineSyncResponse>>,
+}
+
+impl RustylineSyncMessageSender {
+ pub fn post_message(
+ &self,
+ method: &str,
+ params: Option<Value>,
+ ) -> Result<Value, AnyError> {
+ if let Err(err) =
+ self.message_tx.blocking_send((method.to_string(), params))
+ {
+ Err(anyhow!("{}", err))
+ } else {
+ self.response_rx.borrow_mut().blocking_recv().unwrap()
+ }
+ }
+}
+
+pub struct RustylineSyncMessageHandler {
+ message_rx: Receiver<RustylineSyncMessage>,
+ response_tx: UnboundedSender<RustylineSyncResponse>,
+}
+
+impl RustylineSyncMessageHandler {
+ pub async fn recv(&mut self) -> Option<RustylineSyncMessage> {
+ self.message_rx.recv().await
+ }
+
+ pub fn send(&self, response: RustylineSyncResponse) -> Result<(), AnyError> {
+ self
+ .response_tx
+ .send(response)
+ .map_err(|err| anyhow!("{}", err))
+ }
+}
diff --git a/cli/tools/repl.rs b/cli/tools/repl/mod.rs
index b6874f574..925ede654 100644
--- a/cli/tools/repl.rs
+++ b/cli/tools/repl/mod.rs
@@ -5,7 +5,8 @@ use crate::ast::ImportsNotUsedAsValues;
use crate::colors;
use crate::proc_state::ProcState;
use deno_ast::swc::parser::error::SyntaxError;
-use deno_ast::swc::parser::token::{Token, Word};
+use deno_ast::swc::parser::token::Token;
+use deno_ast::swc::parser::token::Word;
use deno_core::error::AnyError;
use deno_core::futures::FutureExt;
use deno_core::parking_lot::Mutex;
@@ -25,28 +26,27 @@ use rustyline::Context;
use rustyline::Editor;
use rustyline_derive::{Helper, Hinter};
use std::borrow::Cow;
-use std::cell::RefCell;
use std::path::PathBuf;
use std::sync::Arc;
-use tokio::sync::mpsc::channel;
-use tokio::sync::mpsc::unbounded_channel;
-use tokio::sync::mpsc::Receiver;
-use tokio::sync::mpsc::Sender;
-use tokio::sync::mpsc::UnboundedReceiver;
-use tokio::sync::mpsc::UnboundedSender;
+
+mod channel;
+
+use channel::rustyline_channel;
+use channel::RustylineSyncMessageHandler;
+use channel::RustylineSyncMessageSender;
// Provides helpers to the editor like validation for multi-line edits, completion candidates for
// tab completion.
#[derive(Helper, Hinter)]
struct EditorHelper {
context_id: u64,
- message_tx: Sender<(String, Option<Value>)>,
- response_rx: RefCell<UnboundedReceiver<Result<Value, AnyError>>>,
+ sync_sender: RustylineSyncMessageSender,
}
impl EditorHelper {
pub fn get_global_lexical_scope_names(&self) -> Vec<String> {
let evaluate_response = self
+ .sync_sender
.post_message(
"Runtime.globalLexicalScopeNames",
Some(json!({
@@ -106,6 +106,7 @@ impl EditorHelper {
let object_id = evaluate_result.get("result")?.get("objectId")?;
let get_properties_response = self
+ .sync_sender
.post_message(
"Runtime.getProperties",
Some(json!({
@@ -127,6 +128,7 @@ impl EditorHelper {
fn evaluate_expression(&self, expr: &str) -> Option<Value> {
let evaluate_response = self
+ .sync_sender
.post_message(
"Runtime.evaluate",
Some(json!({
@@ -144,17 +146,6 @@ impl EditorHelper {
Some(evaluate_response)
}
}
-
- 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 is_word_boundary(c: char) -> bool {
@@ -705,8 +696,7 @@ impl ReplSession {
async fn read_line_and_poll(
repl_session: &mut ReplSession,
- message_rx: &mut Receiver<(String, Option<Value>)>,
- response_tx: &UnboundedSender<Result<Value, AnyError>>,
+ message_handler: &mut RustylineSyncMessageHandler,
editor: ReplEditor,
) -> Result<String, ReadlineError> {
let mut line_fut = tokio::task::spawn_blocking(move || editor.readline());
@@ -717,12 +707,12 @@ async fn read_line_and_poll(
result = &mut line_fut => {
return result.unwrap();
}
- result = message_rx.recv() => {
+ result = message_handler.recv() => {
if let Some((method, params)) = result {
let result = repl_session
.post_message_with_event_loop(&method, params)
.await;
- response_tx.send(result).unwrap();
+ message_handler.send(result).unwrap();
}
poll_worker = true;
@@ -740,13 +730,11 @@ pub async fn run(
maybe_eval: Option<String>,
) -> Result<(), AnyError> {
let mut repl_session = ReplSession::initialize(worker).await?;
- let (message_tx, mut message_rx) = channel(1);
- let (response_tx, response_rx) = unbounded_channel();
+ let mut rustyline_channel = rustyline_channel();
let helper = EditorHelper {
context_id: repl_session.context_id,
- message_tx,
- response_rx: RefCell::new(response_rx),
+ sync_sender: rustyline_channel.0,
};
let history_file_path = ps.dir.root.join("deno_history.txt");
@@ -766,8 +754,7 @@ pub async fn run(
loop {
let line = read_line_and_poll(
&mut repl_session,
- &mut message_rx,
- &response_tx,
+ &mut rustyline_channel.1,
editor.clone(),
)
.await;