mirror of
https://github.com/denoland/deno.git
synced 2024-12-23 15:49:44 -05:00
refactor(repl): move rustyline sync channel communication into struct (#12900)
This commit is contained in:
parent
f3c0f0565b
commit
6a780543a4
2 changed files with 92 additions and 31 deletions
74
cli/tools/repl/channel.rs
Normal file
74
cli/tools/repl/channel.rs
Normal file
|
@ -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))
|
||||
}
|
||||
}
|
|
@ -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;
|
Loading…
Reference in a new issue