Get basic list of completions rendering without styling

Nathan Sobo and Max Brunsfeld created

Co-Authored-By: Max Brunsfeld <maxbrunsfeld@gmail.com>

Change summary

crates/editor/src/editor.rs  | 11 ++++++--
crates/editor/src/element.rs | 48 +++++++++++++++++++++++++++++++++++--
2 files changed, 53 insertions(+), 6 deletions(-)

Detailed changes

crates/editor/src/editor.rs 🔗

@@ -289,7 +289,7 @@ pub fn init(cx: &mut MutableAppContext, path_openers: &mut Vec<Box<dyn PathOpene
     cx.add_action(Editor::fold);
     cx.add_action(Editor::unfold);
     cx.add_action(Editor::fold_selected_ranges);
-    cx.add_action(Editor::show_autocomplete);
+    cx.add_action(Editor::show_completions);
 }
 
 trait SelectionExt {
@@ -1505,7 +1505,7 @@ impl Editor {
         }
     }
 
-    fn show_autocomplete(&mut self, _: &ShowAutocomplete, cx: &mut ViewContext<Self>) {
+    fn show_completions(&mut self, _: &ShowAutocomplete, cx: &mut ViewContext<Self>) {
         let position = self
             .newest_selection::<usize>(&self.buffer.read(cx).read(cx))
             .head();
@@ -1531,6 +1531,10 @@ impl Editor {
         .detach_and_log_err(cx);
     }
 
+    pub fn has_completions(&self) -> bool {
+        self.completion_state.is_some()
+    }
+
     pub fn render_completions(&self) -> Option<ElementBox> {
         self.completion_state.as_ref().map(|state| {
             let build_settings = self.build_settings.clone();
@@ -1542,7 +1546,8 @@ impl Editor {
                     let settings = build_settings(cx);
                     for completion in &completions[range] {
                         items.push(
-                            Label::new(completion.label().to_string(), settings.style.text.clone()).boxed(),
+                            Label::new(completion.label().to_string(), settings.style.text.clone())
+                                .boxed(),
                         );
                     }
                 },

crates/editor/src/element.rs 🔗

@@ -300,7 +300,7 @@ impl EditorElement {
         &mut self,
         bounds: RectF,
         visible_bounds: RectF,
-        layout: &LayoutState,
+        layout: &mut LayoutState,
         cx: &mut PaintContext,
     ) {
         let view = self.view(cx.app);
@@ -392,6 +392,28 @@ impl EditorElement {
         }
         cx.scene.pop_layer();
 
+        if let Some((position, completions_list)) = layout.completions.as_mut() {
+            cx.scene.push_stacking_context(None);
+
+            let cursor_row_layout = &layout.line_layouts[(position.row() - start_row) as usize];
+            let x = cursor_row_layout.x_for_index(position.column() as usize) - scroll_left;
+            let y = (position.row() + 1) as f32 * layout.line_height - scroll_top;
+            let mut list_origin = content_origin + vec2f(x, y);
+            let list_height = completions_list.size().y();
+
+            if list_origin.y() + list_height > bounds.lower_left().y() {
+                list_origin.set_y(list_origin.y() - layout.line_height - list_height);
+            }
+
+            completions_list.paint(
+                list_origin,
+                RectF::from_points(Vector2F::zero(), vec2f(f32::MAX, f32::MAX)), // Let content bleed outside of editor
+                cx,
+            );
+
+            cx.scene.pop_stacking_context();
+        }
+
         cx.scene.pop_layer();
     }
 
@@ -857,9 +879,29 @@ impl Element for EditorElement {
                 snapshot = view.snapshot(cx);
             }
 
-            completions = view.render_completions();
+            if view.has_completions() {
+                let newest_selection_head = view
+                    .newest_selection::<usize>(&snapshot.buffer_snapshot)
+                    .head()
+                    .to_display_point(&snapshot);
+
+                if (start_row..end_row).contains(&newest_selection_head.row()) {
+                    let list = view.render_completions().unwrap();
+                    completions = Some((newest_selection_head, list));
+                }
+            }
         });
 
+        if let Some((_, completions_list)) = completions.as_mut() {
+            completions_list.layout(
+                SizeConstraint {
+                    min: Vector2F::zero(),
+                    max: vec2f(800., (12. * line_height).min((size.y() - line_height) / 2.)),
+                },
+                cx,
+            );
+        }
+
         let blocks = self.layout_blocks(
             start_row..end_row,
             &snapshot,
@@ -1004,7 +1046,7 @@ pub struct LayoutState {
     highlighted_ranges: Vec<(Range<DisplayPoint>, Color)>,
     selections: HashMap<ReplicaId, Vec<text::Selection<DisplayPoint>>>,
     text_offset: Vector2F,
-    completions: Option<ElementBox>,
+    completions: Option<(DisplayPoint, ElementBox)>,
 }
 
 fn layout_line(