Remove semantic search UI

Mikayla created

Change summary

crates/gpui/src/elements/component.rs |  51 +++-
crates/search/src/buffer_search.rs    |   7 
crates/search/src/mode.rs             |  20 -
crates/search/src/project_search.rs   | 296 +++-------------------------
crates/search/src/search.rs           |   7 
crates/settings/src/settings.rs       |   2 
crates/theme/src/components.rs        |   9 
crates/workspace/src/pane.rs          |   4 
8 files changed, 89 insertions(+), 307 deletions(-)

Detailed changes

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

@@ -1,5 +1,3 @@
-use std::marker::PhantomData;
-
 use pathfinder_geometry::{rect::RectF, vector::Vector2F};
 
 use crate::{
@@ -52,22 +50,26 @@ impl<V: View, C: GeneralComponent> Component<V> for C {
     }
 }
 
-pub struct ComponentAdapter<V, E> {
+pub struct ComponentAdapter<V: View, E> {
     component: Option<E>,
-    phantom: PhantomData<V>,
+    element: Option<AnyElement<V>>,
+    #[cfg(debug_assertions)]
+    _component_name: &'static str,
 }
 
-impl<E, V> ComponentAdapter<V, E> {
+impl<E, V: View> ComponentAdapter<V, E> {
     pub fn new(e: E) -> Self {
         Self {
             component: Some(e),
-            phantom: PhantomData,
+            element: None,
+            #[cfg(debug_assertions)]
+            _component_name: std::any::type_name::<E>(),
         }
     }
 }
 
 impl<V: View, C: Component<V> + 'static> Element<V> for ComponentAdapter<V, C> {
-    type LayoutState = AnyElement<V>;
+    type LayoutState = ();
 
     type PaintState = ();
 
@@ -77,10 +79,12 @@ impl<V: View, C: Component<V> + 'static> Element<V> for ComponentAdapter<V, C> {
         view: &mut V,
         cx: &mut LayoutContext<V>,
     ) -> (Vector2F, Self::LayoutState) {
-        let component = self.component.take().unwrap();
-        let mut element = component.render(view, cx.view_context());
-        let constraint = element.layout(constraint, view, cx);
-        (constraint, element)
+        if self.element.is_none() {
+            let component = self.component.take().unwrap();
+            self.element = Some(component.render(view, cx.view_context()));
+        }
+        let constraint = self.element.as_mut().unwrap().layout(constraint, view, cx);
+        (constraint, ())
     }
 
     fn paint(
@@ -88,11 +92,14 @@ impl<V: View, C: Component<V> + 'static> Element<V> for ComponentAdapter<V, C> {
         scene: &mut SceneBuilder,
         bounds: RectF,
         visible_bounds: RectF,
-        layout: &mut Self::LayoutState,
+        _: &mut Self::LayoutState,
         view: &mut V,
         cx: &mut PaintContext<V>,
     ) -> Self::PaintState {
-        layout.paint(scene, bounds.origin(), visible_bounds, view, cx)
+        self.element
+            .as_mut()
+            .unwrap()
+            .paint(scene, bounds.origin(), visible_bounds, view, cx)
     }
 
     fn rect_for_text_range(
@@ -100,25 +107,35 @@ impl<V: View, C: Component<V> + 'static> Element<V> for ComponentAdapter<V, C> {
         range_utf16: std::ops::Range<usize>,
         _: RectF,
         _: RectF,
-        element: &Self::LayoutState,
+        _: &Self::LayoutState,
         _: &Self::PaintState,
         view: &V,
         cx: &ViewContext<V>,
     ) -> Option<RectF> {
-        element.rect_for_text_range(range_utf16, view, cx)
+        self.element
+            .as_ref()
+            .unwrap()
+            .rect_for_text_range(range_utf16, view, cx)
     }
 
     fn debug(
         &self,
         _: RectF,
-        element: &Self::LayoutState,
+        _: &Self::LayoutState,
         _: &Self::PaintState,
         view: &V,
         cx: &ViewContext<V>,
     ) -> serde_json::Value {
+        #[cfg(debug_assertions)]
+        let component_name = self._component_name;
+
+        #[cfg(not(debug_assertions))]
+        let component_name = "Unknown";
+
         serde_json::json!({
             "type": "ComponentAdapter",
-            "child": element.debug(view, cx),
+            "child": self.element.as_ref().unwrap().debug(view, cx),
+            "component_name": component_name
         })
     }
 }

crates/search/src/buffer_search.rs 🔗

@@ -523,11 +523,6 @@ impl BufferSearchBar {
     }
 
     pub fn activate_search_mode(&mut self, mode: SearchMode, cx: &mut ViewContext<Self>) {
-        assert_ne!(
-            mode,
-            SearchMode::Semantic,
-            "Semantic search is not supported in buffer search"
-        );
         if mode == self.current_mode {
             return;
         }
@@ -802,7 +797,7 @@ impl BufferSearchBar {
         }
     }
     fn cycle_mode(&mut self, _: &CycleMode, cx: &mut ViewContext<Self>) {
-        self.activate_search_mode(next_mode(&self.current_mode, false), cx);
+        self.activate_search_mode(next_mode(&self.current_mode), cx);
     }
     fn cycle_mode_on_pane(pane: &mut Pane, action: &CycleMode, cx: &mut ViewContext<Pane>) {
         let mut should_propagate = true;

crates/search/src/mode.rs 🔗

@@ -1,12 +1,11 @@
 use gpui::Action;
 
-use crate::{ActivateRegexMode, ActivateSemanticMode, ActivateTextMode};
+use crate::{ActivateRegexMode, ActivateTextMode};
 // TODO: Update the default search mode to get from config
 #[derive(Copy, Clone, Debug, Default, PartialEq)]
 pub enum SearchMode {
     #[default]
     Text,
-    Semantic,
     Regex,
 }
 
@@ -20,7 +19,6 @@ impl SearchMode {
     pub(crate) fn label(&self) -> &'static str {
         match self {
             SearchMode::Text => "Text",
-            SearchMode::Semantic => "Semantic",
             SearchMode::Regex => "Regex",
         }
     }
@@ -28,7 +26,6 @@ impl SearchMode {
     pub(crate) fn region_id(&self) -> usize {
         match self {
             SearchMode::Text => 3,
-            SearchMode::Semantic => 4,
             SearchMode::Regex => 5,
         }
     }
@@ -36,7 +33,6 @@ impl SearchMode {
     pub(crate) fn tooltip_text(&self) -> &'static str {
         match self {
             SearchMode::Text => "Activate Text Search",
-            SearchMode::Semantic => "Activate Semantic Search",
             SearchMode::Regex => "Activate Regex Search",
         }
     }
@@ -44,7 +40,6 @@ impl SearchMode {
     pub(crate) fn activate_action(&self) -> Box<dyn Action> {
         match self {
             SearchMode::Text => Box::new(ActivateTextMode),
-            SearchMode::Semantic => Box::new(ActivateSemanticMode),
             SearchMode::Regex => Box::new(ActivateRegexMode),
         }
     }
@@ -53,7 +48,6 @@ impl SearchMode {
         match self {
             SearchMode::Regex => true,
             SearchMode::Text => true,
-            SearchMode::Semantic => true,
         }
     }
 
@@ -67,22 +61,14 @@ impl SearchMode {
     pub(crate) fn button_side(&self) -> Option<Side> {
         match self {
             SearchMode::Text => Some(Side::Left),
-            SearchMode::Semantic => None,
             SearchMode::Regex => Some(Side::Right),
         }
     }
 }
 
-pub(crate) fn next_mode(mode: &SearchMode, semantic_enabled: bool) -> SearchMode {
-    let next_text_state = if semantic_enabled {
-        SearchMode::Semantic
-    } else {
-        SearchMode::Regex
-    };
-
+pub(crate) fn next_mode(mode: &SearchMode) -> SearchMode {
     match mode {
-        SearchMode::Text => next_text_state,
-        SearchMode::Semantic => SearchMode::Regex,
+        SearchMode::Text => SearchMode::Regex,
         SearchMode::Regex => SearchMode::Text,
     }
 }

crates/search/src/project_search.rs 🔗

@@ -2,10 +2,10 @@ use crate::{
     history::SearchHistory,
     mode::SearchMode,
     search_bar::{render_nav_button, render_option_button_icon, render_search_mode_button},
-    ActivateRegexMode, CycleMode, NextHistoryQuery, PreviousHistoryQuery, SearchOptions,
-    SelectNextMatch, SelectPrevMatch, ToggleCaseSensitive, ToggleWholeWord,
+    CycleMode, NextHistoryQuery, PreviousHistoryQuery, SearchOptions, SelectNextMatch,
+    SelectPrevMatch, ToggleCaseSensitive, ToggleWholeWord,
 };
-use anyhow::{Context, Result};
+use anyhow::Context;
 use collections::HashMap;
 use editor::{
     items::active_match_index, scroll::autoscroll::Autoscroll, Anchor, Editor, MultiBuffer,
@@ -13,8 +13,6 @@ use editor::{
 };
 use futures::StreamExt;
 
-use gpui::platform::PromptLevel;
-
 use gpui::{
     actions, elements::*, platform::MouseButton, Action, AnyElement, AnyViewHandle, AppContext,
     Entity, ModelContext, ModelHandle, Subscription, Task, View, ViewContext, ViewHandle,
@@ -22,12 +20,10 @@ use gpui::{
 };
 
 use menu::Confirm;
-use postage::stream::Stream;
 use project::{
-    search::{PathMatcher, SearchInputs, SearchQuery},
+    search::{PathMatcher, SearchQuery},
     Entry, Project,
 };
-use semantic_index::SemanticIndex;
 use smallvec::SmallVec;
 use std::{
     any::{Any, TypeId},
@@ -118,8 +114,6 @@ pub struct ProjectSearchView {
     model: ModelHandle<ProjectSearch>,
     query_editor: ViewHandle<Editor>,
     results_editor: ViewHandle<Editor>,
-    semantic_state: Option<SemanticSearchState>,
-    semantic_permissioned: Option<bool>,
     search_options: SearchOptions,
     panels_with_errors: HashSet<InputPanel>,
     active_match_index: Option<usize>,
@@ -131,12 +125,6 @@ pub struct ProjectSearchView {
     current_mode: SearchMode,
 }
 
-struct SemanticSearchState {
-    file_count: usize,
-    outstanding_file_count: usize,
-    _progress_task: Task<()>,
-}
-
 pub struct ProjectSearchBar {
     active_project_search: Option<ViewHandle<ProjectSearchView>>,
     subscription: Option<Subscription>,
@@ -218,60 +206,6 @@ impl ProjectSearch {
         }));
         cx.notify();
     }
-
-    fn semantic_search(&mut self, inputs: &SearchInputs, cx: &mut ModelContext<Self>) {
-        let search = SemanticIndex::global(cx).map(|index| {
-            index.update(cx, |semantic_index, cx| {
-                semantic_index.search_project(
-                    self.project.clone(),
-                    inputs.as_str().to_owned(),
-                    10,
-                    inputs.files_to_include().to_vec(),
-                    inputs.files_to_exclude().to_vec(),
-                    cx,
-                )
-            })
-        });
-        self.search_id += 1;
-        self.match_ranges.clear();
-        self.search_history.add(inputs.as_str().to_string());
-        self.no_results = Some(true);
-        self.pending_search = Some(cx.spawn(|this, mut cx| async move {
-            let results = search?.await.log_err()?;
-
-            let (_task, mut match_ranges) = this.update(&mut cx, |this, cx| {
-                this.excerpts.update(cx, |excerpts, cx| {
-                    excerpts.clear(cx);
-
-                    let matches = results
-                        .into_iter()
-                        .map(|result| (result.buffer, vec![result.range.start..result.range.start]))
-                        .collect();
-
-                    excerpts.stream_excerpts_with_context_lines(matches, 3, cx)
-                })
-            });
-
-            while let Some(match_range) = match_ranges.next().await {
-                this.update(&mut cx, |this, cx| {
-                    this.match_ranges.push(match_range);
-                    while let Ok(Some(match_range)) = match_ranges.try_next() {
-                        this.match_ranges.push(match_range);
-                    }
-                    this.no_results = Some(false);
-                    cx.notify();
-                });
-            }
-
-            this.update(&mut cx, |this, cx| {
-                this.pending_search.take();
-                cx.notify();
-            });
-
-            None
-        }));
-        cx.notify();
-    }
 }
 
 #[derive(Clone, Debug, PartialEq, Eq)]
@@ -311,27 +245,10 @@ impl View for ProjectSearchView {
             } else {
                 match current_mode {
                     SearchMode::Text => Cow::Borrowed("Text search all files and folders"),
-                    SearchMode::Semantic => {
-                        Cow::Borrowed("Search all code objects using Natural Language")
-                    }
                     SearchMode::Regex => Cow::Borrowed("Regex search all files and folders"),
                 }
             };
 
-            let semantic_status = if let Some(semantic) = &self.semantic_state {
-                if semantic.outstanding_file_count > 0 {
-                    format!(
-                        "Indexing: {} of {}...",
-                        semantic.file_count - semantic.outstanding_file_count,
-                        semantic.file_count
-                    )
-                } else {
-                    "Indexing complete".to_string()
-                }
-            } else {
-                "Indexing: ...".to_string()
-            };
-
             let minor_text = if let Some(no_results) = model.no_results {
                 if model.pending_search.is_none() && no_results {
                     vec!["No results found in this project for the provided query".to_owned()]
@@ -339,19 +256,11 @@ impl View for ProjectSearchView {
                     vec![]
                 }
             } else {
-                match current_mode {
-                    SearchMode::Semantic => vec![
-                        "".to_owned(),
-                        semantic_status,
-                        "Simply explain the code you are looking to find.".to_owned(),
-                        "ex. 'prompt user for permissions to index their project'".to_owned(),
-                    ],
-                    _ => vec![
-                        "".to_owned(),
-                        "Include/exclude specific paths with the filter option.".to_owned(),
-                        "Matching exact word and/or casing is available too.".to_owned(),
-                    ],
-                }
+                vec![
+                    "".to_owned(),
+                    "Include/exclude specific paths with the filter option.".to_owned(),
+                    "Matching exact word and/or casing is available too.".to_owned(),
+                ]
             };
 
             let previous_query_keystrokes =
@@ -630,49 +539,6 @@ impl ProjectSearchView {
         self.search_options.toggle(option);
     }
 
-    fn index_project(&mut self, cx: &mut ViewContext<Self>) {
-        if let Some(semantic_index) = SemanticIndex::global(cx) {
-            // Semantic search uses no options
-            self.search_options = SearchOptions::none();
-
-            let project = self.model.read(cx).project.clone();
-            let index_task = semantic_index.update(cx, |semantic_index, cx| {
-                semantic_index.index_project(project, cx)
-            });
-
-            cx.spawn(|search_view, mut cx| async move {
-                let (files_to_index, mut files_remaining_rx) = index_task.await?;
-
-                search_view.update(&mut cx, |search_view, cx| {
-                    cx.notify();
-                    search_view.semantic_state = Some(SemanticSearchState {
-                        file_count: files_to_index,
-                        outstanding_file_count: files_to_index,
-                        _progress_task: cx.spawn(|search_view, mut cx| async move {
-                            while let Some(count) = files_remaining_rx.recv().await {
-                                search_view
-                                    .update(&mut cx, |search_view, cx| {
-                                        if let Some(semantic_search_state) =
-                                            &mut search_view.semantic_state
-                                        {
-                                            semantic_search_state.outstanding_file_count = count;
-                                            cx.notify();
-                                            if count == 0 {
-                                                return;
-                                            }
-                                        }
-                                    })
-                                    .ok();
-                            }
-                        }),
-                    });
-                })?;
-                anyhow::Ok(())
-            })
-            .detach_and_log_err(cx);
-        }
-    }
-
     fn clear_search(&mut self, cx: &mut ViewContext<Self>) {
         self.model.update(cx, |model, cx| {
             model.pending_search = None;
@@ -696,56 +562,7 @@ impl ProjectSearchView {
         self.current_mode = mode;
 
         match mode {
-            SearchMode::Semantic => {
-                let has_permission = self.semantic_permissioned(cx);
-                self.active_match_index = None;
-                cx.spawn(|this, mut cx| async move {
-                    let has_permission = has_permission.await?;
-
-                    if !has_permission {
-                        let mut answer = this.update(&mut cx, |this, cx| {
-                            let project = this.model.read(cx).project.clone();
-                            let project_name = project
-                                .read(cx)
-                                .worktree_root_names(cx)
-                                .collect::<Vec<&str>>()
-                                .join("/");
-                            let is_plural =
-                                project_name.chars().filter(|letter| *letter == '/').count() > 0;
-                            let prompt_text = format!("Would you like to index the '{}' project{} for semantic search? This requires sending code to the OpenAI API", project_name,
-                                if is_plural {
-                                    "s"
-                                } else {""});
-                            cx.prompt(
-                                PromptLevel::Info,
-                                prompt_text.as_str(),
-                                &["Continue", "Cancel"],
-                            )
-                        })?;
-
-                        if answer.next().await == Some(0) {
-                            this.update(&mut cx, |this, _| {
-                                this.semantic_permissioned = Some(true);
-                            })?;
-                        } else {
-                            this.update(&mut cx, |this, cx| {
-                                this.semantic_permissioned = Some(false);
-                                debug_assert_ne!(previous_mode, SearchMode::Semantic, "Tried to re-enable semantic search mode after user modal was rejected");
-                                this.activate_search_mode(previous_mode, cx);
-                            })?;
-                            return anyhow::Ok(());
-                        }
-                    }
-
-                    this.update(&mut cx, |this, cx| {
-                        this.index_project(cx);
-                    })?;
-
-                    anyhow::Ok(())
-                }).detach_and_log_err(cx);
-            }
             SearchMode::Regex | SearchMode::Text => {
-                self.semantic_state = None;
                 self.active_match_index = None;
             }
         }
@@ -843,8 +660,6 @@ impl ProjectSearchView {
             model,
             query_editor,
             results_editor,
-            semantic_state: None,
-            semantic_permissioned: None,
             search_options: options,
             panels_with_errors: HashSet::new(),
             active_match_index: None,
@@ -858,18 +673,6 @@ impl ProjectSearchView {
         this
     }
 
-    fn semantic_permissioned(&mut self, cx: &mut ViewContext<Self>) -> Task<Result<bool>> {
-        if let Some(value) = self.semantic_permissioned {
-            return Task::ready(Ok(value));
-        }
-
-        SemanticIndex::global(cx)
-            .map(|semantic| {
-                let project = self.model.read(cx).project.clone();
-                semantic.update(cx, |this, cx| this.project_previously_indexed(project, cx))
-            })
-            .unwrap_or(Task::ready(Ok(false)))
-    }
     pub fn new_search_in_directory(
         workspace: &mut Workspace,
         dir_entry: &Entry,
@@ -945,26 +748,8 @@ impl ProjectSearchView {
     }
 
     fn search(&mut self, cx: &mut ViewContext<Self>) {
-        let mode = self.current_mode;
-        match mode {
-            SearchMode::Semantic => {
-                if let Some(semantic) = &mut self.semantic_state {
-                    if semantic.outstanding_file_count > 0 {
-                        return;
-                    }
-
-                    if let Some(query) = self.build_search_query(cx) {
-                        self.model
-                            .update(cx, |model, cx| model.semantic_search(query.as_inner(), cx));
-                    }
-                }
-            }
-
-            _ => {
-                if let Some(query) = self.build_search_query(cx) {
-                    self.model.update(cx, |model, cx| model.search(query, cx));
-                }
-            }
+        if let Some(query) = self.build_search_query(cx) {
+            self.model.update(cx, |model, cx| model.search(query, cx));
         }
     }
 
@@ -1164,8 +949,7 @@ impl ProjectSearchBar {
             .and_then(|item| item.downcast::<ProjectSearchView>())
         {
             search_view.update(cx, |this, cx| {
-                let new_mode =
-                    crate::mode::next_mode(&this.current_mode, SemanticIndex::enabled(cx));
+                let new_mode = crate::mode::next_mode(&this.current_mode);
                 this.activate_search_mode(new_mode, cx);
             })
         }
@@ -1288,18 +1072,18 @@ impl ProjectSearchBar {
         }
     }
 
-    fn activate_regex_mode(pane: &mut Pane, _: &ActivateRegexMode, cx: &mut ViewContext<Pane>) {
-        if let Some(search_view) = pane
-            .active_item()
-            .and_then(|item| item.downcast::<ProjectSearchView>())
-        {
-            search_view.update(cx, |view, cx| {
-                view.activate_search_mode(SearchMode::Regex, cx)
-            });
-        } else {
-            cx.propagate_action();
-        }
-    }
+    // fn activate_regex_mode(pane: &mut Pane, _: &ActivateRegexMode, cx: &mut ViewContext<Pane>) {
+    //     if let Some(search_view) = pane
+    //         .active_item()
+    //         .and_then(|item| item.downcast::<ProjectSearchView>())
+    //     {
+    //         search_view.update(cx, |view, cx| {
+    //             view.activate_search_mode(SearchMode::Regex, cx)
+    //         });
+    //     } else {
+    //         cx.propagate_action();
+    //     }
+    // }
 
     fn toggle_filters(&mut self, cx: &mut ViewContext<Self>) -> bool {
         if let Some(search_view) = self.active_project_search.as_ref() {
@@ -1400,7 +1184,6 @@ impl View for ProjectSearchBar {
                 theme.search.editor.input.container
             };
 
-            let row_spacing = theme.workspace.toolbar.container.padding.bottom;
             let search = _search.read(cx);
             let filter_button = render_option_button_icon(
                 search.filters_enabled,
@@ -1413,8 +1196,7 @@ impl View for ProjectSearchBar {
                 },
                 cx,
             );
-            let search = _search.read(cx);
-            let is_semantic_disabled = search.semantic_state.is_none();
+
             let render_option_button_icon = |path, option, cx: &mut ViewContext<Self>| {
                 crate::search_bar::render_option_button_icon(
                     self.is_option_enabled(option, cx),
@@ -1428,17 +1210,17 @@ impl View for ProjectSearchBar {
                     cx,
                 )
             };
-            let case_sensitive = is_semantic_disabled.then(|| {
-                render_option_button_icon(
-                    "icons/case_insensitive_12.svg",
-                    SearchOptions::CASE_SENSITIVE,
-                    cx,
-                )
-            });
+            let case_sensitive = render_option_button_icon(
+                "icons/case_insensitive_12.svg",
+                SearchOptions::CASE_SENSITIVE,
+                cx,
+            );
 
-            let whole_word = is_semantic_disabled.then(|| {
-                render_option_button_icon("icons/word_search_12.svg", SearchOptions::WHOLE_WORD, cx)
-            });
+            let whole_word = render_option_button_icon(
+                "icons/word_search_12.svg",
+                SearchOptions::WHOLE_WORD,
+                cx,
+            );
 
             let search = _search.read(cx);
             let icon_style = theme.search.editor_icon.clone();
@@ -1454,8 +1236,8 @@ impl View for ProjectSearchBar {
                 .with_child(
                     Flex::row()
                         .with_child(filter_button)
-                        .with_children(case_sensitive)
-                        .with_children(whole_word)
+                        .with_child(case_sensitive)
+                        .with_child(whole_word)
                         .flex(1., false)
                         .constrained()
                         .contained(),
@@ -1554,8 +1336,7 @@ impl View for ProjectSearchBar {
                 )
             };
             let is_active = search.active_match_index.is_some();
-            let semantic_index = SemanticIndex::enabled(cx)
-                .then(|| search_button_for_mode(SearchMode::Semantic, cx));
+
             let nav_button_for_direction = |label, direction, cx: &mut ViewContext<Self>| {
                 render_nav_button(
                     label,
@@ -1581,7 +1362,6 @@ impl View for ProjectSearchBar {
                 .with_child(
                     Flex::row()
                         .with_child(search_button_for_mode(SearchMode::Text, cx))
-                        .with_children(semantic_index)
                         .with_child(search_button_for_mode(SearchMode::Regex, cx))
                         .contained()
                         .with_style(theme.search.modes_container),

crates/search/src/search.rs 🔗

@@ -8,7 +8,9 @@ use gpui::{
 pub use mode::SearchMode;
 use project::search::SearchQuery;
 pub use project_search::{ProjectSearchBar, ProjectSearchView};
-use theme::components::{action_button::ActionButton, ComponentExt, ToggleIconButtonStyle};
+use theme::components::{
+    action_button::ActionButton, svg::Svg, ComponentExt, ToggleIconButtonStyle,
+};
 
 pub mod buffer_search;
 mod history;
@@ -33,7 +35,6 @@ actions!(
         NextHistoryQuery,
         PreviousHistoryQuery,
         ActivateTextMode,
-        ActivateSemanticMode,
         ActivateRegexMode
     ]
 );
@@ -94,7 +95,7 @@ impl SearchOptions {
             format!("Toggle {}", self.label()),
             tooltip_style,
         )
-        .with_contents(theme::components::svg::Svg::new(self.icon()))
+        .with_contents(Svg::new(self.icon()))
         .toggleable(active)
         .with_style(button_style)
         .into_element()

crates/theme/src/components.rs 🔗

@@ -175,8 +175,13 @@ pub mod action_button {
             .on_click(MouseButton::Left, {
                 let action = self.action.boxed_clone();
                 move |_, _, cx| {
-                    cx.window()
-                        .dispatch_action(cx.view_id(), action.as_ref(), cx);
+                    let window = cx.window();
+                    let view = cx.view_id();
+                    let action = action.boxed_clone();
+                    cx.spawn(|_, mut cx| async move {
+                        window.dispatch_action(view, action.as_ref(), &mut cx);
+                    })
+                    .detach();
                 }
             })
             .with_cursor_style(CursorStyle::PointingHand)

crates/workspace/src/pane.rs 🔗

@@ -286,10 +286,6 @@ impl Pane {
         context_menu.update(cx, |menu, _| {
             menu.set_position_mode(OverlayPositionMode::Local)
         });
-        let theme = theme::current(cx).workspace.tab_bar.clone();
-
-        let nav_button_height = theme.height;
-        let button_style = theme.nav_button;
 
         Self {
             items: Vec::new(),