Beautiful go to line modal

Conrad Irwin , Julia , and Marshall created

Co-authored-by: Julia <julia@zed.dev>
Co-authored-by: Marshall <marshall@zed.dev>

Change summary

crates/editor2/src/editor.rs         |  68 ++++++++++++------
crates/go_to_line2/src/go_to_line.rs | 110 +++++++++++++++++++----------
crates/theme2/src/theme2.rs          |   8 +
crates/workspace2/src/modal_layer.rs |  23 -----
4 files changed, 126 insertions(+), 83 deletions(-)

Detailed changes

crates/editor2/src/editor.rs 🔗

@@ -36,10 +36,10 @@ pub use element::{
 use futures::FutureExt;
 use fuzzy::{StringMatch, StringMatchCandidate};
 use gpui::{
-    actions, div, px, relative, AnyElement, AppContext, BackgroundExecutor, Context,
-    DispatchContext, Div, Element, Entity, EventEmitter, FocusHandle, FontStyle, FontWeight, Hsla,
-    Model, Pixels, Render, Styled, Subscription, Task, TextStyle, View, ViewContext, VisualContext,
-    WeakView, WindowContext,
+    actions, div, hsla, px, relative, rems, AnyElement, AppContext, BackgroundExecutor, Context,
+    DispatchContext, Div, Element, Entity, EventEmitter, FocusHandle, FontFeatures, FontStyle,
+    FontWeight, Hsla, Model, Pixels, Render, Styled, Subscription, Task, TextStyle, View,
+    ViewContext, VisualContext, WeakView, WindowContext,
 };
 use highlight_matching_bracket::refresh_matching_bracket_highlights;
 use hover_popover::{hide_hover, HoverState};
@@ -2162,14 +2162,14 @@ impl Editor {
     //         self.collaboration_hub = Some(hub);
     //     }
 
-    //     pub fn set_placeholder_text(
-    //         &mut self,
-    //         placeholder_text: impl Into<Arc<str>>,
-    //         cx: &mut ViewContext<Self>,
-    //     ) {
-    //         self.placeholder_text = Some(placeholder_text.into());
-    //         cx.notify();
-    //     }
+    pub fn set_placeholder_text(
+        &mut self,
+        placeholder_text: impl Into<Arc<str>>,
+        cx: &mut ViewContext<Self>,
+    ) {
+        self.placeholder_text = Some(placeholder_text.into());
+        cx.notify();
+    }
 
     //     pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut ViewContext<Self>) {
     //         self.cursor_shape = cursor_shape;
@@ -9365,18 +9365,42 @@ impl Render for Editor {
 
     fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
         let settings = ThemeSettings::get_global(cx);
-        let text_style = TextStyle {
-            color: cx.theme().colors().text,
-            font_family: settings.buffer_font.family.clone(),
-            font_features: settings.buffer_font.features,
-            font_size: settings.buffer_font_size.into(),
-            font_weight: FontWeight::NORMAL,
-            font_style: FontStyle::Normal,
-            line_height: relative(settings.buffer_line_height.value()),
-            underline: None,
+        let text_style = match self.mode {
+            EditorMode::SingleLine => {
+                TextStyle {
+                    color: cx.theme().colors().text,
+                    font_family: "Zed Sans".into(), // todo!()
+                    font_features: FontFeatures::default(),
+                    font_size: rems(1.0).into(),
+                    font_weight: FontWeight::NORMAL,
+                    font_style: FontStyle::Normal,
+                    line_height: relative(1.3).into(), // TODO relative(settings.buffer_line_height.value()),
+                    underline: None,
+                }
+            }
+
+            EditorMode::AutoHeight { max_lines } => todo!(),
+
+            EditorMode::Full => TextStyle {
+                color: cx.theme().colors().text,
+                font_family: settings.buffer_font.family.clone(),
+                font_features: settings.buffer_font.features,
+                font_size: settings.buffer_font_size.into(),
+                font_weight: FontWeight::NORMAL,
+                font_style: FontStyle::Normal,
+                line_height: relative(settings.buffer_line_height.value()),
+                underline: None,
+            },
+        };
+
+        let background = match self.mode {
+            EditorMode::SingleLine => cx.theme().system().transparent,
+            EditorMode::AutoHeight { max_lines } => cx.theme().system().transparent,
+            EditorMode::Full => cx.theme().colors().editor_background,
         };
+
         EditorElement::new(EditorStyle {
-            background: cx.theme().colors().editor_background,
+            background,
             local_player: cx.theme().players().local(),
             text: text_style,
             scrollbar_width: px(12.),

crates/go_to_line2/src/go_to_line.rs 🔗

@@ -1,15 +1,11 @@
+use editor::Editor;
 use gpui::{
-    actions, div, px, red, AppContext, Div, ParentElement, Render, Styled, ViewContext,
-    VisualContext,
-};
-use ui::modal;
-use editor::{scroll::autoscroll::Autoscroll, Editor};
-use gpui::{
-    actions, div, px, red, AppContext, Div, EventEmitter, ParentElement, Render, Styled, View,
+    actions, div, AppContext, Div, EventEmitter, ParentElement, Render, SharedString, Styled, View,
     ViewContext, VisualContext,
 };
-use text::{Bias, Point};
-use ui::modal;
+use text::Point;
+use theme::ActiveTheme;
+use ui::{h_stack, modal, v_stack, Label, LabelColor};
 use util::paths::FILE_ROW_COLUMN_DELIMITER;
 use workspace::ModalRegistry;
 
@@ -33,6 +29,7 @@ pub fn init(cx: &mut AppContext) {
 
 pub struct GoToLine {
     line_editor: View<Editor>,
+    #[allow(unused)] // todo!()
     active_editor: View<Editor>,
 }
 
@@ -46,7 +43,11 @@ impl EventEmitter for GoToLine {
 
 impl GoToLine {
     pub fn new(active_editor: View<Editor>, cx: &mut ViewContext<Self>) -> Self {
-        let line_editor = cx.build_view(|cx| Editor::single_line(cx));
+        let line_editor = cx.build_view(|cx| {
+            let mut editor = Editor::single_line(cx);
+            editor.set_placeholder_text("Find something", cx);
+            editor
+        });
         cx.subscribe(&line_editor, Self::on_line_editor_event)
             .detach();
 
@@ -65,26 +66,27 @@ impl GoToLine {
         match event {
             editor::Event::Blurred => cx.emit(Event::Dismissed),
             editor::Event::BufferEdited { .. } => {
-                if let Some(point) = self.point_from_query(cx) {
-                    // todo!()
-                    // self.active_editor.update(cx, |active_editor, cx| {
-                    //     let snapshot = active_editor.snapshot(cx).display_snapshot;
-                    //     let point = snapshot.buffer_snapshot.clip_point(point, Bias::Left);
-                    //     let display_point = point.to_display_point(&snapshot);
-                    //     let row = display_point.row();
-                    //     active_editor.highlight_rows(Some(row..row + 1));
-                    //     active_editor.request_autoscroll(Autoscroll::center(), cx);
-                    // });
-                    cx.notify();
-                }
+                //  if let Some(point) = self.point_from_query(cx) {
+                // todo!()
+                // self.active_editor.update(cx, |active_editor, cx| {
+                //     let snapshot = active_editor.snapshot(cx).display_snapshot;
+                //     let point = snapshot.buffer_snapshot.clip_point(point, Bias::Left);
+                //     let display_point = point.to_display_point(&snapshot);
+                //     let row = display_point.row();
+                //     active_editor.highlight_rows(Some(row..row + 1));
+                //     active_editor.request_autoscroll(Autoscroll::center(), cx);
+                // });
+                //       cx.notify();
+                //  }
             }
             _ => {}
         }
     }
 
+    #[allow(unused)]
     fn point_from_query(&self, cx: &ViewContext<Self>) -> Option<Point> {
         // todo!()
-        let line_editor = "2:2"; //self.line_editor.read(cx).text(cx);
+        let line_editor = self.line_editor.read(cx).text(cx);
         let mut components = line_editor
             .splitn(2, FILE_ROW_COLUMN_DELIMITER)
             .map(str::trim)
@@ -97,22 +99,26 @@ impl GoToLine {
         ))
     }
 
-    fn cancel(&mut self, _: &Cancel, cx: &mut ViewContext<Self>) {
-        cx.emit(Event::Dismissed);
-    }
-
-    fn confirm(&mut self, _: &Confirm, cx: &mut ViewContext<Self>) {
-        if let Some(point) = self.point_from_query(cx) {
-            self.active_editor.update(cx, |active_editor, cx| {
-                let snapshot = active_editor.snapshot(cx).display_snapshot;
-                let point = snapshot.buffer_snapshot.clip_point(point, Bias::Left);
-                active_editor.change_selections(Some(Autoscroll::center()), cx, |s| {
-                    s.select_ranges([point..point])
-                });
-            });
-        }
-
-        cx.emit(Event::Dismissed);
+    // fn cancel(&mut self, _: &Cancel, cx: &mut ViewContext<Self>) {
+    //     cx.emit(Event::Dismissed);
+    // }
+
+    // fn confirm(&mut self, _: &Confirm, cx: &mut ViewContext<Self>) {
+    //     if let Some(point) = self.point_from_query(cx) {
+    //         self.active_editor.update(cx, |active_editor, cx| {
+    //             let snapshot = active_editor.snapshot(cx).display_snapshot;
+    //             let point = snapshot.buffer_snapshot.clip_point(point, Bias::Left);
+    //             active_editor.change_selections(Some(Autoscroll::center()), cx, |s| {
+    //                 s.select_ranges([point..point])
+    //             });
+    //         });
+    //     }
+
+    //     cx.emit(Event::Dismissed);
+    // }
+
+    fn status_text(&self) -> SharedString {
+        "Default text".into()
     }
 }
 
@@ -120,7 +126,31 @@ impl Render for GoToLine {
     type Element = Div<Self>;
 
     fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
-        modal(cx).child(self.line_editor.clone()).child("blah blah")
+        modal(cx).w_96().child(
+            v_stack()
+                .px_1()
+                .pt_0p5()
+                .gap_px()
+                .child(
+                    v_stack()
+                        .py_0p5()
+                        .px_1()
+                        .child(div().px_1().py_0p5().child(self.line_editor.clone())),
+                )
+                .child(
+                    div()
+                        .h_px()
+                        .w_full()
+                        .bg(cx.theme().colors().element_background),
+                )
+                .child(
+                    h_stack()
+                        .justify_between()
+                        .px_2()
+                        .py_1()
+                        .child(Label::new(self.status_text()).color(LabelColor::Muted)),
+                ),
+        )
     }
 }
 

crates/theme2/src/theme2.rs 🔗

@@ -63,7 +63,13 @@ pub struct Theme {
 }
 
 impl Theme {
-    /// Returns the [`ThemeColors`] for the theme.
+    /// Returns the [`SystemColors`] for the theme.
+    #[inline(always)]
+    pub fn system(&self) -> &SystemColors {
+        &self.styles.system
+    }
+
+    /// Returns the [`PlayerColors`] for the theme.
     #[inline(always)]
     pub fn players(&self) -> &PlayerColors {
         &self.styles.player

crates/workspace2/src/modal_layer.rs 🔗

@@ -1,7 +1,7 @@
 use std::{any::TypeId, sync::Arc};
 
 use gpui::{
-    div, hsla, px, red, AnyView, AppContext, Component, DispatchPhase, Div, ParentElement, Render,
+    div, px, AnyView, AppContext, Component, DispatchPhase, Div, ParentElement, Render,
     StatelessInteractive, Styled, View, ViewContext,
 };
 use ui::v_stack;
@@ -72,21 +72,8 @@ impl ModalLayer {
         Self { open_modal: None }
     }
 
-    // Workspace
-    // - ModalLayer parent
-    // - - container
-    // - - - modal
-    // - - - content of the modal
-    // - - content of the workspace
-
-    // app
-    // workspace
-    // container some layer that contains all modals and is 100% wide and high
-    // modal (this has a shadow, some witdht)
-    // whatever
-
     pub fn render(&self, workspace: &Workspace, cx: &ViewContext<Workspace>) -> Div<Workspace> {
-        let mut parent = div().relative().bg(red()).size_full();
+        let mut parent = div().relative().size_full();
 
         for (_, action) in cx.global::<ModalRegistry>().registered_modals.iter() {
             parent = (action)(parent);
@@ -104,11 +91,7 @@ impl ModalLayer {
                 .z_index(400);
 
             // transparent layer
-            let container2 = v_stack()
-                .bg(hsla(0.5, 0.5, 0.5, 0.5))
-                .h(px(0.0))
-                .relative()
-                .top_20();
+            let container2 = v_stack().h(px(0.0)).relative().top_20();
 
             parent.child(container1.child(container2.child(open_modal.clone())))
         })