Fix replace button in project-search not rendering as filled when active

Lukas Wirth created

Change summary

crates/search/src/buffer_search.rs  | 48 +++++--------------------
crates/search/src/project_search.rs | 57 +++++++++---------------------
crates/search/src/search_bar.rs     | 36 +++++++++++++++++++
3 files changed, 63 insertions(+), 78 deletions(-)

Detailed changes

crates/search/src/buffer_search.rs 🔗

@@ -3,7 +3,8 @@ mod registrar;
 use crate::{
     FocusSearch, NextHistoryQuery, PreviousHistoryQuery, ReplaceAll, ReplaceNext, SearchOptions,
     SelectAllMatches, SelectNextMatch, SelectPreviousMatch, ToggleCaseSensitive, ToggleRegex,
-    ToggleReplace, ToggleSelection, ToggleWholeWord, search_bar::render_nav_button,
+    ToggleReplace, ToggleSelection, ToggleWholeWord,
+    search_bar::{input_base_styles, render_nav_button, toggle_replace_button},
 };
 use any_vec::AnyVec;
 use anyhow::Context as _;
@@ -238,18 +239,8 @@ impl Render for BufferSearchBar {
         let container_width = window.viewport_size().width;
         let input_width = SearchInputWidth::calc_width(container_width);
 
-        let input_base_styles = |border_color| {
-            h_flex()
-                .min_w_32()
-                .w(input_width)
-                .h_8()
-                .pl_2()
-                .pr_1()
-                .py_1()
-                .border_1()
-                .border_color(border_color)
-                .rounded_lg()
-        };
+        let input_base_styles =
+            |border_color| input_base_styles(border_color, |div| div.w(input_width));
 
         let search_line = h_flex()
             .gap_2()
@@ -304,33 +295,14 @@ impl Render for BufferSearchBar {
                     .gap_1()
                     .min_w_64()
                     .when(supported_options.replacement, |this| {
-                        this.child(
-                            IconButton::new(
-                                "buffer-search-bar-toggle-replace-button",
-                                IconName::Replace,
-                            )
-                            .style(ButtonStyle::Subtle)
-                            .shape(IconButtonShape::Square)
-                            .when(self.replace_enabled, |button| {
-                                button.style(ButtonStyle::Filled)
-                            })
-                            .on_click(cx.listener(|this, _: &ClickEvent, window, cx| {
+                        this.child(toggle_replace_button(
+                            "buffer-search-bar-toggle-replace-button",
+                            focus_handle.clone(),
+                            self.replace_enabled,
+                            cx.listener(|this, _: &ClickEvent, window, cx| {
                                 this.toggle_replace(&ToggleReplace, window, cx);
-                            }))
-                            .toggle_state(self.replace_enabled)
-                            .tooltip({
-                                let focus_handle = focus_handle.clone();
-                                move |window, cx| {
-                                    Tooltip::for_action_in(
-                                        "Toggle Replace",
-                                        &ToggleReplace,
-                                        &focus_handle,
-                                        window,
-                                        cx,
-                                    )
-                                }
                             }),
-                        )
+                        ))
                     })
                     .when(supported_options.selection, |this| {
                         this.child(

crates/search/src/project_search.rs 🔗

@@ -1,7 +1,9 @@
 use crate::{
     BufferSearchBar, FocusSearch, NextHistoryQuery, PreviousHistoryQuery, ReplaceAll, ReplaceNext,
     SearchOptions, SelectNextMatch, SelectPreviousMatch, ToggleCaseSensitive, ToggleIncludeIgnored,
-    ToggleRegex, ToggleReplace, ToggleWholeWord, buffer_search::Deploy,
+    ToggleRegex, ToggleReplace, ToggleWholeWord,
+    buffer_search::Deploy,
+    search_bar::{input_base_styles, toggle_replace_button},
 };
 use anyhow::Context as _;
 use collections::{HashMap, HashSet};
@@ -1965,19 +1967,10 @@ impl Render for ProjectSearchBar {
         }
 
         let input_base_styles = |base_style: BaseStyle, panel: InputPanel| {
-            h_flex()
-                .min_w_32()
-                .map(|div| match base_style {
-                    BaseStyle::SingleInput => div.w(input_width),
-                    BaseStyle::MultipleInputs => div.flex_grow(),
-                })
-                .h_8()
-                .pl_2()
-                .pr_1()
-                .py_1()
-                .border_1()
-                .border_color(search.border_color_for(panel, cx))
-                .rounded_lg()
+            input_base_styles(search.border_color_for(panel, cx), |div| match base_style {
+                BaseStyle::SingleInput => div.w(input_width),
+                BaseStyle::MultipleInputs => div.flex_grow(),
+            })
         };
 
         let query_column = input_base_styles(BaseStyle::SingleInput, InputPanel::Query)
@@ -2045,31 +2038,17 @@ impl Render for ProjectSearchBar {
                         }
                     }),
             )
-            .child(
-                IconButton::new("project-search-toggle-replace", IconName::Replace)
-                    .shape(IconButtonShape::Square)
-                    .on_click(cx.listener(|this, _, window, cx| {
-                        this.toggle_replace(&ToggleReplace, window, cx);
-                    }))
-                    .toggle_state(
-                        self.active_project_search
-                            .as_ref()
-                            .map(|search| search.read(cx).replace_enabled)
-                            .unwrap_or_default(),
-                    )
-                    .tooltip({
-                        let focus_handle = focus_handle.clone();
-                        move |window, cx| {
-                            Tooltip::for_action_in(
-                                "Toggle Replace",
-                                &ToggleReplace,
-                                &focus_handle,
-                                window,
-                                cx,
-                            )
-                        }
-                    }),
-            );
+            .child(toggle_replace_button(
+                "project-search-toggle-replace",
+                focus_handle.clone(),
+                self.active_project_search
+                    .as_ref()
+                    .map(|search| search.read(cx).replace_enabled)
+                    .unwrap_or_default(),
+                cx.listener(|this, _, window, cx| {
+                    this.toggle_replace(&ToggleReplace, window, cx);
+                }),
+            ));
 
         let limit_reached = search.entity.read(cx).limit_reached;
 

crates/search/src/search_bar.rs 🔗

@@ -1,7 +1,9 @@
-use gpui::{Action, FocusHandle, IntoElement};
+use gpui::{Action, FocusHandle, Hsla, IntoElement};
 use ui::{IconButton, IconButtonShape};
 use ui::{Tooltip, prelude::*};
 
+use crate::ToggleReplace;
+
 pub(super) fn render_nav_button(
     icon: ui::IconName,
     active: bool,
@@ -26,3 +28,35 @@ pub(super) fn render_nav_button(
     .tooltip(move |window, cx| Tooltip::for_action_in(tooltip, action, &focus_handle, window, cx))
     .disabled(!active)
 }
+
+pub(crate) fn input_base_styles(border_color: Hsla, map: impl FnOnce(Div) -> Div) -> Div {
+    h_flex()
+        .min_w_32()
+        .map(map)
+        .h_8()
+        .pl_2()
+        .pr_1()
+        .py_1()
+        .border_1()
+        .border_color(border_color)
+        .rounded_lg()
+}
+
+pub(crate) fn toggle_replace_button(
+    id: &'static str,
+    focus_handle: FocusHandle,
+    replace_enabled: bool,
+    on_click: impl Fn(&gpui::ClickEvent, &mut Window, &mut App) + 'static,
+) -> IconButton {
+    IconButton::new(id, IconName::Replace)
+        .shape(IconButtonShape::Square)
+        .style(ButtonStyle::Subtle)
+        .when(replace_enabled, |button| button.style(ButtonStyle::Filled))
+        .on_click(on_click)
+        .toggle_state(replace_enabled)
+        .tooltip({
+            move |window, cx| {
+                Tooltip::for_action_in("Toggle Replace", &ToggleReplace, &focus_handle, window, cx)
+            }
+        })
+}