When renaming, fade out the old name and select all

Nathan Sobo created

Change summary

crates/editor/src/editor.rs         | 14 +++-------
crates/editor/src/element.rs        | 40 +++++++++++++++++-------------
crates/gpui/src/color.rs            | 12 ++++----
crates/gpui/src/elements/text.rs    | 38 ++++++++++++++++++++---------
crates/gpui/src/fonts.rs            | 12 +++++++-
crates/theme/src/theme.rs           |  1 
crates/zed/assets/themes/_base.toml |  1 
7 files changed, 70 insertions(+), 48 deletions(-)

Detailed changes

crates/editor/src/editor.rs 🔗

@@ -4393,20 +4393,14 @@ impl Editor {
                         editor
                             .buffer
                             .update(cx, |buffer, cx| buffer.edit([0..0], &old_name, cx));
-                        editor.select_ranges(
-                            [tail_offset_in_rename_range..cursor_offset_in_rename_range],
-                            None,
-                            cx,
-                        );
+                        editor.select_all(&SelectAll, cx);
                         editor
                     });
                     this.highlight_text::<Rename>(
                         vec![range.clone()],
                         HighlightStyle {
-                            color: Color::transparent_black(),
-                            font_properties: todo!(),
-                            underline: todo!(),
-                            fade_out: todo!(),
+                            fade_out: Some(style.rename_fade),
+                            ..Default::default()
                         },
                         cx,
                     );
@@ -4500,7 +4494,7 @@ impl Editor {
     fn take_rename(&mut self, cx: &mut ViewContext<Self>) -> Option<RenameState> {
         let rename = self.pending_rename.take()?;
         self.remove_blocks([rename.block_id].into_iter().collect(), cx);
-        self.clear_background_highlights::<Rename>(cx);
+        self.clear_text_highlights::<Rename>(cx);
 
         let editor = rename.editor.read(cx);
         let snapshot = self.buffer.read(cx).snapshot(cx);

crates/editor/src/element.rs 🔗

@@ -606,30 +606,34 @@ impl EditorElement {
         } else {
             let style = &self.style;
             let chunks = snapshot.chunks(rows.clone(), true).map(|chunk| {
-                let mut highlight_style = HighlightStyle {
-                    color: style.text.color,
-                    font_properties: style.text.font_properties,
-                    ..Default::default()
-                };
-
-                if let Some(syntax_highlight_style) = chunk
+                let mut highlight_style = chunk
                     .syntax_highlight_id
-                    .and_then(|id| id.style(&style.syntax))
-                {
-                    highlight_style.highlight(syntax_highlight_style);
-                }
+                    .and_then(|id| id.style(&style.syntax));
 
-                if let Some(style) = chunk.highlight_style {
-                    highlight_style.highlight(style);
+                if let Some(chunk_highlight) = chunk.highlight_style {
+                    if let Some(highlight_style) = highlight_style.as_mut() {
+                        highlight_style.highlight(chunk_highlight);
+                    } else {
+                        highlight_style = Some(chunk_highlight);
+                    }
                 }
 
                 if let Some(severity) = chunk.diagnostic {
                     let diagnostic_style = super::diagnostic_style(severity, true, style);
-                    highlight_style.underline = Some(Underline {
-                        color: diagnostic_style.message.text.color,
-                        thickness: 1.0.into(),
-                        squiggly: true,
-                    });
+                    let diagnostic_highlight = HighlightStyle {
+                        underline: Some(Underline {
+                            color: diagnostic_style.message.text.color,
+                            thickness: 1.0.into(),
+                            squiggly: true,
+                        }),
+                        ..Default::default()
+                    };
+
+                    if let Some(highlight_style) = highlight_style.as_mut() {
+                        highlight_style.highlight(diagnostic_highlight);
+                    } else {
+                        highlight_style = Some(diagnostic_highlight);
+                    }
                 }
 
                 (chunk.text, highlight_style)

crates/gpui/src/color.rs 🔗

@@ -50,9 +50,11 @@ impl Color {
     }
 
     pub fn blend(source: Color, dest: Color) -> Color {
-        // If source is fully opaque, don't blend.
+        // Skip blending if we don't need it.
         if source.a == 255 {
             return source;
+        } else if source.a == 0 {
+            return dest;
         }
 
         let source = source.0.to_f32();
@@ -66,11 +68,9 @@ impl Color {
         Self(ColorF::new(r, g, b, a).to_u8())
     }
 
-    pub fn fade_out(&mut self, factor: f32) {
-        let source_alpha = 1. - factor.clamp(0., 1.);
-        let dest_alpha = self.0.a as f32 / 255.;
-        let dest_alpha = source_alpha + (dest_alpha * (1. - source_alpha));
-        self.0.a = (dest_alpha * (1. / 255.)) as u8;
+    pub fn fade_out(&mut self, fade: f32) {
+        let fade = fade.clamp(0., 1.);
+        self.0.a = (self.0.a as f32 * (1. - fade)) as u8;
     }
 }
 

crates/gpui/src/elements/text.rs 🔗

@@ -69,18 +69,15 @@ impl Element for Text {
             let result;
             if let Some((range, highlight_style)) = highlight_ranges.peek() {
                 if offset < range.start {
-                    result = Some((
-                        &self.text[offset..range.start],
-                        HighlightStyle::from(&self.style),
-                    ));
+                    result = Some((&self.text[offset..range.start], None));
                     offset = range.start;
                 } else {
-                    result = Some((&self.text[range.clone()], *highlight_style));
+                    result = Some((&self.text[range.clone()], Some(*highlight_style)));
                     highlight_ranges.next();
                     offset = range.end;
                 }
             } else if offset < self.text.len() {
-                result = Some((&self.text[offset..], HighlightStyle::from(&self.style)));
+                result = Some((&self.text[offset..], None));
                 offset = self.text.len();
             } else {
                 result = None;
@@ -200,7 +197,7 @@ impl Element for Text {
 
 /// Perform text layout on a series of highlighted chunks of text.
 pub fn layout_highlighted_chunks<'a>(
-    chunks: impl Iterator<Item = (&'a str, HighlightStyle)>,
+    chunks: impl Iterator<Item = (&'a str, Option<HighlightStyle>)>,
     text_style: &'a TextStyle,
     text_layout_cache: &'a TextLayoutCache,
     font_cache: &'a Arc<FontCache>,
@@ -228,12 +225,29 @@ pub fn layout_highlighted_chunks<'a>(
             }
 
             if !line_chunk.is_empty() && !line_exceeded_max_len {
+                let font_properties;
+                let mut color;
+                let underline;
+
+                if let Some(highlight_style) = highlight_style {
+                    font_properties = highlight_style.font_properties;
+                    color = Color::blend(highlight_style.color, text_style.color);
+                    if let Some(fade) = highlight_style.fade_out {
+                        color.fade_out(fade);
+                    }
+                    underline = highlight_style.underline;
+                } else {
+                    font_properties = text_style.font_properties;
+                    color = text_style.color;
+                    underline = None;
+                }
+
                 // Avoid a lookup if the font properties match the previous ones.
-                let font_id = if highlight_style.font_properties == prev_font_properties {
+                let font_id = if font_properties == prev_font_properties {
                     prev_font_id
                 } else {
                     font_cache
-                        .select_font(text_style.font_family_id, &highlight_style.font_properties)
+                        .select_font(text_style.font_family_id, &font_properties)
                         .unwrap_or(text_style.font_id)
                 };
 
@@ -251,12 +265,12 @@ pub fn layout_highlighted_chunks<'a>(
                     line_chunk.len(),
                     RunStyle {
                         font_id,
-                        color: highlight_style.color,
-                        underline: highlight_style.underline,
+                        color,
+                        underline,
                     },
                 ));
                 prev_font_id = font_id;
-                prev_font_properties = highlight_style.font_properties;
+                prev_font_properties = font_properties;
             }
         }
     }

crates/gpui/src/fonts.rs 🔗

@@ -267,8 +267,16 @@ impl HighlightStyle {
 
     pub fn highlight(&mut self, other: HighlightStyle) {
         self.color = Color::blend(other.color, self.color);
-        if let Some(factor) = other.fade_out {
-            self.color.fade_out(factor);
+        match (other.fade_out, self.fade_out) {
+            (Some(source_fade), None) => self.fade_out = Some(source_fade),
+            (Some(source_fade), Some(dest_fade)) => {
+                let source_alpha = 1. - source_fade;
+                let dest_alpha = 1. - dest_fade;
+                let blended_alpha = source_alpha + (dest_alpha * source_fade);
+                let blended_fade = 1. - blended_alpha;
+                self.fade_out = Some(blended_fade);
+            }
+            _ => {}
         }
         self.font_properties = other.font_properties;
         if other.underline.is_some() {

crates/theme/src/theme.rs 🔗

@@ -282,6 +282,7 @@ pub struct Editor {
     pub gutter_padding_factor: f32,
     pub active_line_background: Color,
     pub highlighted_line_background: Color,
+    pub rename_fade: f32,
     pub document_highlight_read_background: Color,
     pub document_highlight_write_background: Color,
     pub diff_background_deleted: Color,

crates/zed/assets/themes/_base.toml 🔗

@@ -249,6 +249,7 @@ gutter_background = "$surface.1"
 gutter_padding_factor = 2.5
 active_line_background = "$state.active_line"
 highlighted_line_background = "$state.highlighted_line"
+rename_fade = 0.6
 document_highlight_read_background = "#99999920"
 document_highlight_write_background = "#99999916"
 diff_background_deleted = "$state.deleted_line"