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

Optimize opening dropdown #5688

Merged
merged 2 commits into from
Feb 18, 2023
Merged
Show file tree
Hide file tree
Changes from all 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
2 changes: 2 additions & 0 deletions Cargo.lock

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

12 changes: 1 addition & 11 deletions app/gui/language/parser-scala/src/jsclient.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,6 @@ impl From<JsValue> for Error {

#[wasm_bindgen(module = "/pkg/scala-parser.js")]
extern "C" {
#[wasm_bindgen(catch)]
fn doc_parser_generate_html_source(content: String) -> std::result::Result<String, JsValue>;
#[wasm_bindgen(catch)]
fn doc_parser_generate_html_from_doc(content: String) -> std::result::Result<String, JsValue>;
}
Expand All @@ -56,16 +54,8 @@ impl Client {
Ok(Client {})
}

/// Calls JS doc parser to generate HTML from documented Enso code.
pub fn generate_html_docs(&self, program: String) -> api::Result<String> {
let html_code = || {
let html_code = doc_parser_generate_html_source(program)?;
Result::Ok(html_code)
};
Ok(html_code()?)
}

/// Calls JS doc parser to generate HTML from pure doc code without Enso's AST.
#[profile(Detail)]
pub fn generate_html_doc_pure(&self, code: String) -> api::Result<String> {
let html_code = || {
let html_code = doc_parser_generate_html_from_doc(code)?;
Expand Down
6 changes: 0 additions & 6 deletions app/gui/language/parser-scala/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,12 +82,6 @@ impl DocParser {
DocParser::new().unwrap_or_else(|e| panic!("Failed to create doc parser: {e:?}"))
}

/// Parses program with documentation and generates HTML code.
/// If the program does not have any documentation will return empty string.
pub fn generate_html_docs(&self, program: String) -> api::Result<String> {
self.borrow_mut().generate_html_docs(program)
}

/// Parses pure documentation code and generates HTML code.
/// Will return empty string for empty entry.
pub fn generate_html_doc_pure(&self, code: String) -> api::Result<String> {
Expand Down
12 changes: 1 addition & 11 deletions app/gui/language/parser-scala/src/wsclient.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,6 @@ impl From<serde_json::error::Error> for Error {
#[allow(clippy::enum_variant_names)]
#[derive(Debug, serde::Serialize, serde::Deserialize)]
pub enum Request {
DocParserGenerateHtmlSource { program: String },
DocParserGenerateHtmlFromDoc { code: String },
}

Expand Down Expand Up @@ -196,17 +195,8 @@ impl Client {
Ok(client)
}

/// Sends a request to parser service to generate HTML code from documented Enso code.
pub fn generate_html_docs(&mut self, program: String) -> api::Result<String> {
let request = Request::DocParserGenerateHtmlSource { program };
let response_doc = self.rpc_call_doc(request)?;
match response_doc {
ResponseDoc::SuccessDoc { code } => Ok(code),
ResponseDoc::Error { message } => Err(ParsingError(message)),
}
}

/// Sends a request to parser service to generate HTML code from pure documentation code.
#[profile(Detail)]
pub fn generate_html_doc_pure(&mut self, code: String) -> api::Result<String> {
let request = Request::DocParserGenerateHtmlFromDoc { code };
let response_doc = self.rpc_call_doc(request)?;
Expand Down
1 change: 1 addition & 0 deletions app/gui/suggestion-database/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ span-tree = { path = "../language/span-tree" }
ast = { path = "../language/ast/impl" }
parser = { path = "../language/parser" }
parser-scala = { path = "../language/parser-scala" }
enso-profiler = { path = "../../../lib/rust/profiler" }
enso-text = { path = "../../../lib/rust/text" }
double-representation = { path = "../controller/double-representation" }
engine-protocol = { path = "../controller/engine-protocol" }
Expand Down
3 changes: 3 additions & 0 deletions app/gui/suggestion-database/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ use engine_protocol::language_server;
use engine_protocol::language_server::SuggestionId;
use enso_data_structures::hash_map_tree::HashMapTree;
use enso_notification as notification;
use enso_profiler as profiler;
use enso_profiler::prelude::*;
use flo_stream::Subscriber;
use language_server::types::SuggestionDatabaseUpdatesEvent;
use language_server::types::SuggestionsDatabaseVersion;
Expand Down Expand Up @@ -412,6 +414,7 @@ impl SuggestionDatabase {
}

/// Apply the update event to the database.
#[profile(Detail)]
pub fn apply_update_event(&self, event: SuggestionDatabaseUpdatesEvent) {
for update in event.updates {
let mut entries = self.entries.borrow_mut();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ pub struct View {
impl View {
/// Create a new node widget. The widget is initialized to empty state, waiting for widget
/// metadata to be provided using `set_node_data` and `set_metadata` FRP endpoints.
#[profile(Task)]
pub fn new(app: &Application) -> Self {
let frp = Frp::new();
let model = Rc::new(Model::new(app));
Expand Down Expand Up @@ -160,6 +161,7 @@ impl Model {
Self { app, display_object, kind_model: kind }
}

#[profile(Task)]
fn set_widget_data(&self, frp: &SampledFrp, meta: &Option<Metadata>, node_data: &NodeData) {
trace!("Setting widget data: {:?} {:?}", meta, node_data);

Expand Down Expand Up @@ -426,6 +428,7 @@ impl LazyDropdown {
}
}

#[profile(Detail)]
fn initialize_on_open(&mut self) {
match self {
LazyDropdown::Initialized(..) => {}
Expand Down
1 change: 1 addition & 0 deletions app/gui/view/graph-editor/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2130,6 +2130,7 @@ impl GraphEditorModel {
}
}

#[profile(Debug)]
fn set_node_expression_usage_type(
&self,
node_id: impl Into<NodeId>,
Expand Down
49 changes: 36 additions & 13 deletions lib/rust/ensogl/component/drop-down/src/entry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,9 @@ pub struct EntryData {
display_object: display::object::Instance,
label_thin: text::Text,
label_bold: text::Text,
selected: Cell<bool>,
/// A text change to the currently-hidden label that has not yet been applied.
deferred_label: RefCell<Option<ImString>>,
}

impl EntryData {
Expand All @@ -101,16 +104,28 @@ impl EntryData {
label_thin.add_to_scene_layer(layer);
label_bold.add_to_scene_layer(layer);
}
Self { display_object, label_thin, label_bold }
let selected = default();
let deferred_label = default();
Self { display_object, label_thin, label_bold, selected, deferred_label }
}

fn update_selected(&self, selected: bool) {
if selected {
self.display_object.remove_child(&self.label_thin);
self.display_object.add_child(&self.label_bold);
} else {
self.display_object.remove_child(&self.label_bold);
self.display_object.add_child(&self.label_thin);
let was_selected = self.selected.replace(selected);
if selected != was_selected {
let new = self.selected_label();
if let Some(label) = self.deferred_label.take() {
new.set_content(label);
}
self.display_object.remove_all_children();
self.display_object.add_child(new);
}
}

/// Render the currently-enabled text control.
fn selected_label(&self) -> &text::Text {
match self.selected.get() {
true => &self.label_bold,
false => &self.label_thin,
}
}

Expand All @@ -119,6 +134,11 @@ impl EntryData {
self.label_thin.set_xy(label_pos);
self.label_bold.set_xy(label_pos);
}

fn set_content(&self, text: &ImString) {
self.selected_label().set_content(text.clone_ref());
self.deferred_label.set(text.clone_ref());
}
}


Expand All @@ -135,6 +155,7 @@ impl ensogl_grid_view::Entry for Entry {
type Model = EntryModel;
type Params = EntryParams;

#[profile(Debug)]
fn new(app: &Application, text_layer: Option<&Layer>) -> Self {
let data = Rc::new(EntryData::new(app, text_layer));
let frp = EntryFrp::<Self>::new();
Expand All @@ -160,8 +181,6 @@ impl ensogl_grid_view::Entry for Entry {
);
layout <- all(contour, text_size, text_offset);
eval layout ((&(c, ts, to)) data.update_layout(c, ts, to));
selected <- input.set_model.map(|m| *m.selected);
eval selected ((&s) data.update_selected(s));

text_size <- text_size.ref_into_some();
data.label_thin.set_property_default <+ text_size;
Expand All @@ -171,7 +190,10 @@ impl ensogl_grid_view::Entry for Entry {
data.label_thin.set_font <+ font;
data.label_bold.set_font <+ font;

desired_entry_width <- data.label_bold.width.map2(&text_offset, |w, offset| w + offset);
bold_width <- data.label_bold.width.map2(&text_offset, |w, offset| w + offset);
thin_width <- data.label_thin.width.map2(&text_offset, |w, offset| w + offset);
widths <- all(bold_width, thin_width);
desired_entry_width <- widths.map(|&(b, t)| b.max(t)).on_change();
limited_entry_width <- desired_entry_width.map2(&input.set_params, |width, params| {
// Using min/max to avoid a panic in clamp when min_width > max_width. In those
// cases, the max value is returned instead.
Expand All @@ -184,9 +206,10 @@ impl ensogl_grid_view::Entry for Entry {
data.label_thin.set_view_width <+ view_width;
data.label_bold.set_view_width <+ view_width;

content <- input.set_model.map(|m| m.text.clone_ref());;
data.label_thin.set_content <+ content;
data.label_bold.set_content <+ content;
eval input.set_model ((m) {
data.update_selected(*m.selected);
data.set_content(&m.text);
});

out.contour <+ contour;
out.highlight_contour <+ contour;
Expand Down
1 change: 1 addition & 0 deletions lib/rust/ensogl/component/drop-down/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ ensogl_core::define_endpoints_2! { <T: (DropdownValue)>
}

impl<T: DropdownValue> Frp<T> {
#[profile(Debug)]
fn init(network: &frp::Network, api: &api::Private<T>, model: &Model<T>) {
let input = &api.input;
let output = &api.output;
Expand Down
9 changes: 9 additions & 0 deletions lib/rust/ensogl/component/drop-down/src/model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ impl<T> component::Model for Model<T> {
"Dropdown"
}

#[profile(Debug)]
fn new(app: &Application) -> Self {
let display_object = display::object::Instance::new();

Expand All @@ -97,6 +98,7 @@ impl<T> component::Model for Model<T> {

impl<T: DropdownValue> Model<T> {
/// Set the minimum and maximum allowed inner width of an entry.
#[profile(Debug)]
pub fn set_outer_width_bounds(&self, min_outer_width: f32, max_outer_width: f32) {
let corners_radius = CORNER_RADIUS - CLIP_PADDING;
let max_width = max_outer_width - CLIP_PADDING * 2.0;
Expand All @@ -107,6 +109,7 @@ impl<T: DropdownValue> Model<T> {
}

/// Set the dimensions of all ui elements of the dropdown.
#[profile(Debug)]
pub fn set_dimensions(
&self,
num_entries: usize,
Expand Down Expand Up @@ -136,6 +139,7 @@ impl<T: DropdownValue> Model<T> {
self.grid.resize_grid(num_entries, 1);
}

#[profile(Debug)]
pub fn set_selection(&self, selected: &HashSet<T>, allow_multiselect: bool) {
let mut entries = self.selected_entries.borrow_mut();
entries.clear();
Expand All @@ -148,6 +152,7 @@ impl<T: DropdownValue> Model<T> {

/// Convert provided list of indices onto sets of index ranges. One set of ranges is for indices
/// that are already in cache, and the other set is for indices that need to be requested.
#[profile(Debug)]
pub fn get_ready_and_request_ranges(
&self,
requested_indices: &[usize],
Expand Down Expand Up @@ -180,6 +185,7 @@ impl<T: DropdownValue> Model<T> {
/// Accepts entry at given index, modifying selection. If entry is already selected, it will be
/// unselected, unless it is the last selected entry and `allow_empty` is false. For
/// single-select dropdowns, previously selected entry will be unselected.
#[profile(Debug)]
pub fn accept_entry_at_index(&self, index: usize, allow_multiselect: bool, allow_empty: bool) {
let cache = self.cache.borrow();
let Some(entry) = cache.get(index) else { return };
Expand All @@ -201,6 +207,7 @@ impl<T: DropdownValue> Model<T> {
///
/// Note: The iterator borrows cache and selection. Make sure to drop it before calling any
/// methods that need to borrow them mutably.
#[profile(Debug)]
pub fn entry_models_for_range(
&self,
range: Range<usize>,
Expand All @@ -216,6 +223,7 @@ impl<T: DropdownValue> Model<T> {
}

/// Update cache with new entries at given range. Returns range of indices that were updated.
#[profile(Debug)]
pub fn insert_entries_in_range(
&self,
updated_range: Range<usize>,
Expand All @@ -236,6 +244,7 @@ impl<T: DropdownValue> Model<T> {

/// Prune selection according to changed multiselect mode. Returns true if the selection was
/// changed.
#[profile(Debug)]
pub fn set_multiselect(&self, multiselect: bool) -> bool {
let mut entries = self.selected_entries.borrow_mut();
if !multiselect && entries.len() > 1 {
Expand Down
1 change: 1 addition & 0 deletions lib/rust/ensogl/component/grid-view/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,7 @@ impl<Entry: entry::Entry, EntryParams> Model<Entry, EntryParams> {
}

impl<E: Entry> Model<E, E::Params> {
#[profile(Debug)]
fn update_entry(
&self,
row: Row,
Expand Down
8 changes: 8 additions & 0 deletions lib/rust/ensogl/component/text/src/component/text.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1020,6 +1020,7 @@ impl TextModel {
}

/// Recompute the shape of the provided line index.
#[profile(Debug)]
pub fn shape_line(&self, line: Line) -> ShapedLine {
let line_range = self.line_range_snapped(line);
let glyph_sets = self.shape_range(line_range.clone());
Expand Down Expand Up @@ -1116,6 +1117,7 @@ impl TextModel {
/// and to the right of the insertion point. Unfortunately, the current Rustybuzz
/// implementation does not support such use cases:
/// https://github.com/RazrFalcon/rustybuzz/issues/54
#[profile(Debug)]
fn update_lines_after_change(&self, changes: Option<&[buffer::Change]>) {
debug_span!("update_lines_after_change").in_scope(|| {
self.detach_glyphs_from_cursors();
Expand Down Expand Up @@ -1193,6 +1195,7 @@ impl TextModel {
}

/// Replace selections with new ones.
#[profile(Debug)]
fn replace_selections(&self, do_edit: bool, buffer_selections: &buffer::selection::Group) {
let mut new_selection_map = SelectionMap::default();
for buffer_selection in buffer_selections {
Expand Down Expand Up @@ -1278,6 +1281,7 @@ impl TextModel {
}

/// Redraw the given line ranges.
#[profile(Debug)]
fn redraw_sorted_line_ranges(
&self,
sorted_line_ranges: impl Iterator<Item = RangeInclusive<ViewLine>>,
Expand All @@ -1293,6 +1297,7 @@ impl TextModel {
}

/// Redraw the line. This will re-position all line glyphs.
#[profile(Debug)]
fn redraw_line(&self, view_line: ViewLine) {
let line = &mut self.lines.borrow_mut()[view_line];
let default_divs = || NonEmptyVec::singleton(0.0);
Expand Down Expand Up @@ -1439,6 +1444,7 @@ impl TextModel {
}

/// Attach glyphs to cursors if cursors are in edit mode.
#[profile(Debug)]
pub fn attach_glyphs_to_cursors(&self) {
for line in ViewLine(0)..=self.buffer.last_view_line_index() {
self.attach_glyphs_to_cursors_for_line(line)
Expand Down Expand Up @@ -1486,6 +1492,7 @@ impl TextModel {
}

/// Detach all glyphs from cursors and place them back in lines.
#[profile(Debug)]
pub fn detach_glyphs_from_cursors(&self) {
let selection_map = self.selection_map.borrow();
for (&line, cursor_map) in &selection_map.location_map {
Expand Down Expand Up @@ -1754,6 +1761,7 @@ impl TextModel {
}

/// Position all lines in the provided line range. The range has to be sorted.
#[profile(Debug)]
fn position_sorted_line_ranges(
&self,
sorted_line_ranges: impl Iterator<Item = RangeInclusive<ViewLine>>,
Expand Down
Loading