Attaching visualization creates a channel for passing the updata data. (https://github.com/enso-org/ide/pull/460)

Original commit: 23286ad8c9
This commit is contained in:
Michał Wawrzyniec Urbańczyk 2020-05-26 14:41:03 +02:00 committed by GitHub
parent 8629d72fbd
commit e58c16735a
2 changed files with 101 additions and 15 deletions

View File

@ -11,6 +11,55 @@ use std::collections::HashMap;
use uuid::Uuid;
// ===============
// === Aliases ===
// ===============
/// An identifier of called definition in module.
pub type DefinitionId = crate::double_representation::definition::Id;
/// An identifier of expression.
pub type ExpressionId = ast::Id;
// ===============================
// === VisualizationUpdateData ===
// ===============================
/// An update data that notification receives from the interpreter. Owns the binary data generated
/// for visualization by the Language Server.
///
/// Binary data can be accessed through `Deref` or `AsRef` implementations.
///
/// The inner storage is private and users should not make any assumptions about it.
#[derive(Clone,Debug)]
pub struct VisualizationUpdateData(Vec<u8>);
impl VisualizationUpdateData {
/// Wraps given vector with binary data into a visualization update data.
pub fn new(data:Vec<u8>) -> VisualizationUpdateData {
VisualizationUpdateData(data)
}
}
impl AsRef<[u8]> for VisualizationUpdateData {
fn as_ref(&self) -> &[u8] {
self.0.as_ref()
}
}
impl Deref for VisualizationUpdateData {
type Target = [u8];
fn deref(&self) -> &Self::Target {
self.as_ref()
}
}
// ==============
// === Errors ===
// ==============
@ -31,11 +80,6 @@ pub struct InvalidVisualizationId();
// === StackItem ===
// =================
/// An identifier of called definition in module.
pub type DefinitionId = crate::double_representation::definition::Id;
/// An identifier of expression.
pub type ExpressionId = ast::Id;
/// A specific function call occurring within another function's definition body.
///
/// This is a single item in ExecutionContext stack.
@ -47,6 +91,12 @@ pub struct LocalCall {
pub definition : DefinitionId,
}
// =====================
// === Visualization ===
// =====================
/// Unique Id for visualization.
pub type VisualizationId = Uuid;
@ -57,7 +107,7 @@ pub struct Visualization {
pub id: VisualizationId,
/// Node that is to be visualized.
pub ast_id: ExpressionId,
/// An enso lambda that will transform the data into expected format, i.e. `a -> a.json`.
/// An enso lambda that will transform the data into expected format, e.g. `a -> a.json`.
pub expression: String,
}
@ -75,6 +125,20 @@ pub type Id = language_server::ContextId;
// =============================
// === AttachedVisualization ===
// =============================
/// The information about active visualization. Includes the channel endpoint allowing sending
/// the visualization update's data to the visualization's attacher (presumably the view).
#[derive(Clone,Debug)]
pub struct AttachedVisualization {
visualization : Visualization,
update_sender : futures::channel::mpsc::UnboundedSender<VisualizationUpdateData>,
}
// =============
// === Model ===
// =============
@ -90,11 +154,11 @@ pub type Id = language_server::ContextId;
#[derive(Debug)]
pub struct ExecutionContext {
/// A name of definition which is a root call of this context.
pub entry_point: DefinitionName,
pub entry_point:DefinitionName,
/// Local call stack.
stack: RefCell<Vec<LocalCall>>,
stack:RefCell<Vec<LocalCall>>,
/// Set of active visualizations.
visualizations: RefCell<HashMap<VisualizationId, Visualization>>,
visualizations: RefCell<HashMap<VisualizationId,AttachedVisualization>>,
}
impl ExecutionContext {
@ -118,13 +182,21 @@ impl ExecutionContext {
}
/// Attaches a new visualization for current execution context.
pub fn attach_visualization(&self, vis: Visualization) {
self.visualizations.borrow_mut().insert(vis.id,vis);
///
/// Returns a stream of visualization update data received from the server.
pub fn attach_visualization
(&self, visualization:Visualization) -> impl Stream<Item=VisualizationUpdateData> {
let id = visualization.id;
let (update_sender,receiver) = futures::channel::mpsc::unbounded();
let visualization = AttachedVisualization {visualization,update_sender};
self.visualizations.borrow_mut().insert(id,visualization);
receiver
}
/// Detaches visualization from current execution context.
pub fn detach_visualization(&self, id:&VisualizationId) -> FallibleResult<Visualization> {
Ok(self.visualizations.borrow_mut().remove(id).ok_or_else(InvalidVisualizationId)?)
let err = InvalidVisualizationId;
Ok(self.visualizations.borrow_mut().remove(id).ok_or_else(err)?.visualization)
}
/// Get an iterator over stack items.
@ -135,4 +207,14 @@ impl ExecutionContext {
let stack_size = self.stack.borrow().len();
(0..stack_size).filter_map(move |i| self.stack.borrow().get(i).cloned())
}
/// Dispatches the visualization update data (typically received from as LS binary notification)
/// to the respective's visualization update channel.
pub fn dispatch_update(&self, visualization_id:VisualizationId, data:VisualizationUpdateData) {
if let Some(visualization) = self.visualizations.borrow_mut().get(&visualization_id) {
// TODO [mwu] Should we consider detaching the visualization if the view has dropped the
// channel's receiver? Or we need to provide a way to re-establish the channel.
let _ = visualization.update_sender.unbounded_send(data);
}
}
}

View File

@ -5,6 +5,7 @@ use crate::prelude::*;
use crate::double_representation::definition::DefinitionName;
use crate::model::execution_context::LocalCall;
use crate::model::execution_context::Visualization;
use crate::model::execution_context::VisualizationUpdateData;
use crate::model::execution_context::VisualizationId;
use enso_protocol::language_server;
@ -81,11 +82,14 @@ impl ExecutionContext {
}
/// Attaches a new visualization for current execution context.
pub async fn attach_visualization(&self, vis: Visualization) -> FallibleResult<()> {
///
/// Returns a stream of visualization update data received from the server.
pub async fn attach_visualization
(&self, vis: Visualization) -> FallibleResult<impl Stream<Item=VisualizationUpdateData>> {
let config = vis.config(self.id,self.module_path.module_name().to_string());
self.language_server.attach_visualisation(&vis.id, &vis.ast_id, &config).await?;
self.model.attach_visualization(vis);
Ok(())
let stream = self.model.attach_visualization(vis);
Ok(stream)
}
/// Detaches visualization from current execution context.