diff --git a/ide/CHANGELOG.md b/ide/CHANGELOG.md
index 7a531fb7e08f..c2780e3af5d1 100644
--- a/ide/CHANGELOG.md
+++ b/ide/CHANGELOG.md
@@ -119,6 +119,8 @@
load.][1413]
- [Fixed a case where IDE could lose connection to the backend after some
time.][1428]
+- [Improved performance of the graph editor, particularly when opening a project
+ for a first time.][1445]
#### EnsoGL (rendering engine)
@@ -164,6 +166,7 @@ you can find their release notes
[1428]: https://github.com/enso-org/ide/pull/1428
[1438]: https://github.com/enso-org/ide/pull/1438
[1367]: https://github.com/enso-org/ide/pull/1367
+[1445]: https://github.com/enso-org/ide/pull/1445
diff --git a/ide/src/rust/ide/src/ide/integration.rs b/ide/src/rust/ide/src/ide/integration.rs
index b880aede27cf..1b262cbdc3db 100644
--- a/ide/src/rust/ide/src/ide/integration.rs
+++ b/ide/src/rust/ide/src/ide/integration.rs
@@ -182,6 +182,7 @@ struct Model {
node_views : RefCell>,
node_view_by_expression : RefCell>,
expression_views : RefCell>,
+ expression_types : SharedHashMap>,
connection_views : RefCell>,
code_view : CloneRefCell,
visualizations : SharedHashMap,
@@ -427,13 +428,15 @@ impl Model {
let node_view_by_expression = default();
let connection_views = default();
let expression_views = default();
+ let expression_types = default();
let code_view = default();
let visualizations = default();
let error_visualizations = default();
let searcher = default();
let this = Model
- {view,graph,text,searcher,node_views,expression_views,connection_views,code_view,logger
- ,visualization,visualizations,error_visualizations,project,node_view_by_expression};
+ {view,graph,text,searcher,node_views,expression_views,expression_types,connection_views
+ ,code_view,logger,visualization,visualizations,error_visualizations,project
+ ,node_view_by_expression};
this.init_project_name();
this.load_visualizations();
@@ -623,7 +626,9 @@ impl Model {
input_span_tree : trees.inputs,
output_span_tree : trees.outputs.unwrap_or_else(default)
};
- if !self.expression_views.borrow().get(&id).contains(&&code_and_trees) {
+ let expression_changed =
+ !self.expression_views.borrow().get(&id).contains(&&code_and_trees);
+ if expression_changed {
for sub_expression in node.info.ast().iter_recursive() {
if let Some(expr_id) = sub_expression.id {
self.node_view_by_expression.borrow_mut().insert(expr_id,id);
@@ -636,7 +641,7 @@ impl Model {
// Set initially available type information on ports (identifiable expression's sub-parts).
for expression_part in node.info.expression().iter_recursive() {
if let Some(id) = expression_part.id {
- self.refresh_computed_info(id);
+ self.refresh_computed_info(id,expression_changed);
}
}
}
@@ -645,7 +650,7 @@ impl Model {
fn refresh_computed_infos(&self, expressions_to_refresh:&[ExpressionId]) -> FallibleResult {
debug!(self.logger, "Refreshing type information for IDs: {expressions_to_refresh:?}.");
for id in expressions_to_refresh {
- self.refresh_computed_info(*id)
+ self.refresh_computed_info(*id,false)
}
Ok(())
}
@@ -654,12 +659,12 @@ impl Model {
/// graph editor view.
///
/// The computed value information includes the expression type and the target method pointer.
- fn refresh_computed_info(&self, id:ExpressionId) {
+ fn refresh_computed_info(&self, id:ExpressionId, force_type_info_refresh:bool) {
let info = self.lookup_computed_info(&id);
let info = info.as_ref();
let typename = info.and_then(|info| info.typename.clone().map(graph_editor::Type));
if let Some(node_id) = self.node_view_by_expression.borrow().get(&id).cloned() {
- self.set_type(node_id,id,typename);
+ self.set_type(node_id,id,typename, force_type_info_refresh);
let method_pointer = info.and_then(|info| {
info.method_call.and_then(|entry_id| {
let opt_method = self.project.suggestion_db().lookup_method_ptr(entry_id).ok();
@@ -677,9 +682,20 @@ impl Model {
}
/// Set given type (or lack of such) on the given sub-expression.
- fn set_type(&self, node_id:graph_editor::NodeId, id:ExpressionId, typename:Option) {
- let event = (node_id,id,typename);
- self.view.graph().frp.input.set_expression_usage_type.emit(&event);
+ fn set_type
+ ( &self
+ , node_id : graph_editor::NodeId
+ , id : ExpressionId
+ , typename : Option
+ , force_refresh : bool
+ ) {
+ // We suppress spurious type information updates here, as they were causing performance
+ // issues. See: https://github.com/enso-org/ide/issues/952
+ let previous_type_opt = self.expression_types.insert(id,typename.clone());
+ if force_refresh || previous_type_opt.as_ref() != Some(&typename) {
+ let event = (node_id,id,typename);
+ self.view.graph().frp.input.set_expression_usage_type.emit(&event);
+ }
}
/// Set given method pointer (or lack of such) on the given sub-expression.
@@ -851,7 +867,7 @@ impl Model {
use controller::graph::executed::Notification;
use controller::graph::Notification::*;
- debug!(self.logger, "Received notification {notification:?}");
+ debug!(self.logger, "Received graph notification {notification:?}");
let result = match notification {
Some(Notification::Graph(Invalidate)) => self.on_graph_invalidated(),
Some(Notification::Graph(PortsUpdate)) => self.on_graph_expression_update(),
@@ -874,7 +890,7 @@ impl Model {
pub fn handle_text_notification(&self, notification:Option) {
use controller::text::Notification;
- debug!(self.logger, "Received notification {notification:?}");
+ debug!(self.logger, "Received text notification {notification:?}");
let result = match notification {
Some(Notification::Invalidate) => self.on_text_invalidated(),
other => {
@@ -892,6 +908,7 @@ impl Model {
pub fn handle_searcher_notification(&self, notification:controller::searcher::Notification) {
use controller::searcher::Notification;
use controller::searcher::UserAction;
+ debug!(self.logger, "Received searcher notification {notification:?}");
match notification {
Notification::NewActionList => with(self.searcher.borrow(), |searcher| {
if let Some(searcher) = &*searcher {
diff --git a/ide/src/rust/ide/view/graph-editor/src/component/node/input/port.rs b/ide/src/rust/ide/view/graph-editor/src/component/node/input/port.rs
index 3ac163af6596..43f82f7efa73 100644
--- a/ide/src/rust/ide/view/graph-editor/src/component/node/input/port.rs
+++ b/ide/src/rust/ide/view/graph-editor/src/component/node/input/port.rs
@@ -132,7 +132,7 @@ ensogl::define_endpoints! {
set_hover (bool),
set_connected (bool,Option),
set_parent_connected (bool),
- set_definition_type (Option),
+ set_definition_type (Option),
set_usage_type (Option),
}
diff --git a/ide/src/rust/ide/view/graph-editor/src/component/type_coloring.rs b/ide/src/rust/ide/view/graph-editor/src/component/type_coloring.rs
index b913466a1d18..0e9382ae7714 100644
--- a/ide/src/rust/ide/view/graph-editor/src/component/type_coloring.rs
+++ b/ide/src/rust/ide/view/graph-editor/src/component/type_coloring.rs
@@ -42,12 +42,8 @@ use std::hash::Hasher;
/// parametrization, other mechanisms should be used. For example, `Point Float` and `Point Number`
/// should have similar colors, completely distinct from their parameter types.
pub fn compute(tp:&Type, styles:&StyleWatch) -> color::Lcha {
- // FIXME: Left for performance debug purposes. See: https://github.com/enso-org/ide/issues/952
- // println!("Type coloring for: '{}",tp.as_str());
let types_path = theme::code::types::overriden::HERE.path();
let type_path = types_path.into_subs(tp.as_str().split('.'));
- // FIXME: Left for performance debug purposes. See: https://github.com/enso-org/ide/issues/952
- // println!("Path: {:?}",type_path);
let hue = styles.get(type_path.sub("hue")).number_or_else(|| auto_hue(tp,styles));
let lightness = styles.get(type_path.sub("lightness")).number_or_else(||
styles.get_number_or(theme::code::types::lightness,0.85));
diff --git a/ide/src/rust/ide/view/graph-editor/src/lib.rs b/ide/src/rust/ide/view/graph-editor/src/lib.rs
index a260994480c4..aa02d5df6091 100644
--- a/ide/src/rust/ide/view/graph-editor/src/lib.rs
+++ b/ide/src/rust/ide/view/graph-editor/src/lib.rs
@@ -3043,5 +3043,3 @@ impl display::Object for GraphEditor {
self.model.display_object()
}
}
-
-