Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support source maps for JS-based visualizations #3208

Merged
merged 14 commits into from
Jan 11, 2022
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions app/gui/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#### Visual Environment

- [Added support of source maps for JS-based visualizations.][3208]
- [Fixed histograms coloring and added a color legend.][3153]
- [Fixed broken node whose expression contains non-ASCII characters.][3166]
- [Fixed developer console warnings about views being created but not
Expand All @@ -17,6 +18,7 @@
[3181]: https://github.com/enso-org/enso/pull/3181
[3186]: https://github.com/enso-org/enso/pull/3186
[3193]: https://github.com/enso-org/enso/pull/3193
[3208]: https://github.com/enso-org/enso/pull/3208

# Enso 2.0.0-alpha.18 (2021-10-12)

Expand Down
27 changes: 22 additions & 5 deletions app/gui/src/controller/visualization.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use crate::constants::VISUALIZATION_DIRECTORY;
use engine_protocol::language_server;
use ide_view::graph_editor::component::visualization;
use ide_view::graph_editor::component::visualization::definition;
use ide_view::graph_editor::component::visualization::java_script::Sources;
use std::rc::Rc;


Expand Down Expand Up @@ -89,16 +90,19 @@ pub struct EmbeddedVisualizations {
pub struct Handle {
language_server_rpc: Rc<language_server::Connection>,
embedded_visualizations: Rc<RefCell<EmbeddedVisualizations>>,
logger: Logger,
}

impl Handle {
/// Creates a new visualization controller.
pub fn new(
language_server_rpc: Rc<language_server::Connection>,
embedded_visualizations: EmbeddedVisualizations,
logger: &Logger,
) -> Self {
let logger = logger.sub("VisualizationController");
let embedded_visualizations = Rc::new(RefCell::new(embedded_visualizations));
Self { language_server_rpc, embedded_visualizations }
Self { language_server_rpc, embedded_visualizations, logger }
}

async fn list_project_specific_visualizations(&self) -> FallibleResult<Vec<VisualizationPath>> {
Expand Down Expand Up @@ -155,7 +159,17 @@ impl Handle {
let js_code = self.language_server_rpc.read_file(path).await?.contents;
let wrap_error =
|err| Error::js_preparation_error(visualization.clone(), err).into();
visualization::java_script::Definition::new(project, &js_code)
let sources = if let Some(file_name) = path.file_name() {
let sources: &[(&str, &str)] = &[(file_name, &js_code)];
Sources::from_files(sources)
} else {
warning!(
self.logger,
"Unable to get a file name from {path}. Visualization source map will not be provided."
);
Sources::empty()
};
visualization::java_script::Definition::new(project, sources)
.map(Into::into)
.map_err(wrap_error)
}
Expand Down Expand Up @@ -233,7 +247,8 @@ mod tests {
let embedded_visualization = builtin::visualization::native::BubbleChart::definition();
embedded_visualizations
.insert("[Demo] Bubble Visualization".to_string(), embedded_visualization.clone());
let vis_controller = Handle::new(language_server, embedded_visualizations);
let logger = Logger::new("Mock logger");
let vis_controller = Handle::new(language_server, embedded_visualizations, &logger);

let visualizations = vis_controller.list_visualizations().await;
let visualizations = visualizations.expect("Couldn't list visualizations.");
Expand All @@ -247,8 +262,10 @@ mod tests {
assert_eq!(visualizations.len(), 3);

let owner = visualization::Project::CurrentProject;
let javascript_vis0 = js_vis::Definition::new(owner.clone_ref(), &file_content0);
let javascript_vis1 = js_vis::Definition::new(owner, &file_content1);
let sources_vis0 = Sources::from_files(&[("file0.js", &file_content0)]);
let javascript_vis0 = js_vis::Definition::new(owner.clone_ref(), sources_vis0);
let sources_vis1 = Sources::from_files(&[("file0.js", &file_content1)]);
let javascript_vis1 = js_vis::Definition::new(owner, sources_vis1);
let javascript_vis0 = javascript_vis0.expect("Couldn't create visualization class.");
let javascript_vis1 = javascript_vis1.expect("Couldn't create visualization class.");
let javascript_vis0: visualization::Definition = javascript_vis0.into();
Expand Down
2 changes: 1 addition & 1 deletion app/gui/src/model/project/synchronized.rs
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,7 @@ impl Project {
let module_registry = default();
let execution_contexts = default();
let visualization =
controller::Visualization::new(language_server, embedded_visualizations);
controller::Visualization::new(language_server, embedded_visualizations, &logger);
let parser = Parser::new_or_panic();
let language_server = &*language_server_rpc;
let suggestion_db = SuggestionDatabase::create_synchronized(language_server);
Expand Down
4 changes: 3 additions & 1 deletion app/gui/view/debug_scene/visualization/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,9 @@ fn constructor_graph() -> visualization::java_script::Definition {

return Graph
"#;
visualization::java_script::Definition::new_builtin(source).unwrap()
let mut sources = visualization::java_script::Sources::empty();
sources.add_file("demo.js", source);
visualization::java_script::Definition::new_builtin(sources).unwrap()
}

#[wasm_bindgen]
Expand Down
2 changes: 2 additions & 0 deletions app/gui/view/graph-editor/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ crate-type = ["cdylib", "rlib"]
[dependencies]
analytics = { version = "0.1.0", path = "../../analytics" }
ast = { version = "0.1.0", path = "../../language/ast/impl" }
base64 = "0.13"
bimap = { version = "0.4.0" }
enso-config = { version = "0.1.0", path = "../../config" }
enso-frp = { version = "0.1.0", path = "../../../../lib/rust/frp" }
Expand All @@ -30,6 +31,7 @@ js-sys = { version = "0.3.28" }
nalgebra = { version = "0.26.1", features = ["serde-serialize"] }
serde_json = { version = "1.0" }
serde = { version = "1.0", features = ["derive"] }
sourcemap = "6.0"
uuid = { version = "0.8", features = ["serde", "v4", "wasm-bindgen"] }
wasm-bindgen = { version = "=0.2.58", features = ["nightly", "serde-serialize"] }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// These implementations are neither efficient nor pretty, but get the idea across.

use crate::component::visualization;
use crate::component::visualization::java_script::source::from_files;



Expand All @@ -12,77 +13,81 @@ use crate::component::visualization;

/// Return a `JavaScript` Table visualization.
pub fn table_visualization() -> visualization::java_script::FallibleDefinition {
let loading_scripts = include_str!("java_script/helpers/loading.js");
let scrollable = include_str!("java_script/helpers/scrollable.js");
let source = include_str!("java_script/table.js");
let source = format!("{}{}{}", loading_scripts, scrollable, source);
let source = from_files!(
"java_script/helpers/loading.js",
"java_script/helpers/scrollable.js",
"java_script/table.js"
);

visualization::java_script::Definition::new_builtin(source)
}

/// Return a `JavaScript` SQL visualization.
pub fn sql_visualization() -> visualization::java_script::FallibleDefinition {
let loading_scripts = include_str!("java_script/helpers/loading.js");
let scrollable = include_str!("java_script/helpers/scrollable.js");
let source = include_str!("java_script/sql.js");
let source = format!("{}{}{}", loading_scripts, scrollable, source);
let source = from_files!(
"java_script/helpers/loading.js",
"java_script/helpers/scrollable.js",
"java_script/sql.js"
);

visualization::java_script::Definition::new_builtin(source)
}

/// Return a `JavaScript` Scatter plot visualization.
pub fn scatter_plot_visualization() -> visualization::java_script::FallibleDefinition {
let loading_scripts = include_str!("java_script/helpers/loading.js");
let number = include_str!("java_script/helpers/number.js");
let source = include_str!("java_script/scatterPlot.js");
let source = format!("{}{}{}", loading_scripts, number, source);
let source = from_files!(
"java_script/helpers/loading.js",
"java_script/helpers/number.js",
"java_script/scatterPlot.js"
);

visualization::java_script::Definition::new_builtin(source)
}

/// Return a `JavaScript` Histogram visualization.
pub fn histogram_visualization() -> visualization::java_script::FallibleDefinition {
let loading_scripts = include_str!("java_script/helpers/loading.js");
let number = include_str!("java_script/helpers/number.js");
let source = include_str!("java_script/histogram.js");
let source = format!("{}{}{}", loading_scripts, number, source);
let source = from_files!(
"java_script/helpers/loading.js",
"java_script/helpers/number.js",
"java_script/histogram.js"
);

visualization::java_script::Definition::new_builtin(source)
}

/// Return a `JavaScript` Heatmap visualization.
pub fn heatmap_visualization() -> visualization::java_script::FallibleDefinition {
let loading_scripts = include_str!("java_script/helpers/loading.js");
let number = include_str!("java_script/helpers/number.js");
let source = include_str!("java_script/heatmap.js");
let source = format!("{}{}{}", loading_scripts, number, source);
let source = from_files!(
"java_script/helpers/loading.js",
"java_script/helpers/number.js",
"java_script/heatmap.js"
);

visualization::java_script::Definition::new_builtin(source)
}

/// Return a `JavaScript` Map visualization.
pub fn geo_map_visualization() -> visualization::java_script::FallibleDefinition {
let loading_scripts = include_str!("java_script/helpers/loading.js");
let number = include_str!("java_script/helpers/number.js");
let source = include_str!("java_script/geoMap.js");
let source = format!("{}{}{}", loading_scripts, number, source);
let source = from_files!(
"java_script/helpers/loading.js",
"java_script/helpers/number.js",
"java_script/geoMap.js"
);

visualization::java_script::Definition::new_builtin(source)
}

/// Return a `JavaScript` Bubble visualization. This should not be used as it is a demo
/// visualization.
pub fn bubble_visualization() -> visualization::java_script::FallibleDefinition {
let source = include_str!("java_script/bubbleVisualization.js");
let source = from_files!("java_script/bubbleVisualization.js");

visualization::java_script::Definition::new_builtin(source)
}

/// Return a `JavaScript` Image visualization.
pub fn image_base64_visualization() -> visualization::java_script::FallibleDefinition {
let loading_scripts = include_str!("java_script/helpers/loading.js");
let source = include_str!("java_script/imageBase64.js");
let source = format!("{}{}", loading_scripts, source);
let source = from_files!("java_script/helpers/loading.js", "java_script/imageBase64.js");

visualization::java_script::Definition::new_builtin(source)
}
Expand All @@ -93,6 +98,8 @@ pub fn empty_visualization() -> visualization::java_script::FallibleDefinition {
class EmptyVisualization extends Visualization {}
return EmptyVisualization;
"#;
let files = [("java_script/empty.js", source)];
let source = visualization::java_script::Sources::from_files(&files);

visualization::java_script::Definition::new_builtin(source)
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
pub mod binding;
pub mod definition;
pub mod instance;
pub mod source;

pub use definition::*;
pub use instance::*;
pub use source::Sources;
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ use super::instance::Instance;
use crate::component::visualization;
use crate::component::visualization::InstantiationError;
use crate::component::visualization::InstantiationResult;
use crate::visualization::foreign::java_script::Sources;

use ensogl::display::Scene;
use ensogl::system::web::JsValue;
Expand Down Expand Up @@ -59,14 +60,10 @@ pub struct Definition {

impl Definition {
/// Create a visualization source from piece of JS source code. Signature needs to be inferred.
pub fn new(
project: visualization::path::Project,
source: impl AsRef<str>,
) -> Result<Self, Error> {
let source = source.as_ref();
let source = source;
pub fn new(project: visualization::path::Project, sources: Sources) -> Result<Self, Error> {
let source = sources.to_string(&project);
let context = JsValue::NULL;
let function = Function::new_with_args(binding::JS_CLASS_NAME, source)
let function = Function::new_with_args(binding::JS_CLASS_NAME, &source)
.map_err(Error::InvalidFunction)?;
let js_class = binding::js_class();
let class = function.call1(&context, &js_class).map_err(Error::InvalidFunction)?;
Expand All @@ -84,8 +81,8 @@ impl Definition {
}

/// Create a definition of visualization that is built into the IDE.
pub fn new_builtin(source: impl AsRef<str>) -> Result<Self, Error> {
Self::new(visualization::path::Project::Builtin, source)
pub fn new_builtin(sources: Sources) -> Result<Self, Error> {
Self::new(visualization::path::Project::Builtin, sources)
}

fn new_instance(&self, scene: &Scene) -> InstantiationResult {
Expand Down
Loading