Remove 2 suffix for project_symbols, theme_selector

Max Brunsfeld and Mikayla created

Co-authored-by: Mikayla <mikayla@zed.dev>

Change summary

Cargo.lock                                     |  52 --
Cargo.toml                                     |   2 
crates/collab_ui/Cargo.toml                    |   2 
crates/project_symbols/Cargo.toml              |  34 
crates/project_symbols/src/project_symbols.rs  | 166 ++++---
crates/project_symbols2/Cargo.toml             |  37 -
crates/project_symbols2/src/project_symbols.rs | 415 --------------------
crates/theme_selector/Cargo.toml               |  23 
crates/theme_selector/src/theme_selector.rs    | 178 +++++--
crates/theme_selector2/Cargo.toml              |  30 -
crates/theme_selector2/src/theme_selector.rs   | 295 --------------
crates/welcome/Cargo.toml                      |   2 
crates/zed/Cargo.toml                          |   4 
13 files changed, 245 insertions(+), 995 deletions(-)

Detailed changes

Cargo.lock 🔗

@@ -1864,7 +1864,7 @@ dependencies = [
  "settings2",
  "smallvec",
  "theme2",
- "theme_selector2",
+ "theme_selector",
  "time",
  "tree-sitter-markdown",
  "ui2",
@@ -6763,29 +6763,6 @@ dependencies = [
 [[package]]
 name = "project_symbols"
 version = "0.1.0"
-dependencies = [
- "anyhow",
- "editor",
- "futures 0.3.28",
- "fuzzy",
- "gpui",
- "language",
- "lsp",
- "ordered-float 2.10.0",
- "picker",
- "postage",
- "project",
- "settings",
- "smol",
- "text",
- "theme",
- "util",
- "workspace",
-]
-
-[[package]]
-name = "project_symbols2"
-version = "0.1.0"
 dependencies = [
  "anyhow",
  "editor2",
@@ -9464,27 +9441,6 @@ dependencies = [
 [[package]]
 name = "theme_selector"
 version = "0.1.0"
-dependencies = [
- "client",
- "editor",
- "feature_flags",
- "fs",
- "fuzzy",
- "gpui",
- "log",
- "parking_lot 0.11.2",
- "picker",
- "postage",
- "settings",
- "smol",
- "theme",
- "util",
- "workspace",
-]
-
-[[package]]
-name = "theme_selector2"
-version = "0.1.0"
 dependencies = [
  "client2",
  "editor2",
@@ -11048,7 +11004,7 @@ dependencies = [
  "serde",
  "settings2",
  "theme2",
- "theme_selector2",
+ "theme_selector",
  "ui2",
  "util",
  "vim2",
@@ -11511,7 +11467,7 @@ dependencies = [
  "postage",
  "project2",
  "project_panel2",
- "project_symbols2",
+ "project_symbols",
  "quick_action_bar",
  "rand 0.8.5",
  "recent_projects2",
@@ -11536,7 +11492,7 @@ dependencies = [
  "terminal_view2",
  "text2",
  "theme2",
- "theme_selector2",
+ "theme_selector",
  "thiserror",
  "tiny_http",
  "toml 0.5.11",

Cargo.toml 🔗

@@ -89,7 +89,6 @@ members = [
     "crates/project_panel",
     "crates/project_panel2",
     "crates/project_symbols",
-    "crates/project_symbols2",
     "crates/quick_action_bar",
     "crates/recent_projects",
     "crates/recent_projects2",
@@ -116,7 +115,6 @@ members = [
     "crates/theme2",
     "crates/theme_importer",
     "crates/theme_selector",
-    "crates/theme_selector2",
     "crates/ui2",
     "crates/util",
     "crates/story",

crates/collab_ui/Cargo.toml 🔗

@@ -46,7 +46,7 @@ rpc = { package ="rpc2",  path = "../rpc2" }
 settings = { package = "settings2", path = "../settings2" }
 feature_flags = { package = "feature_flags2", path = "../feature_flags2"}
 theme = { package = "theme2", path = "../theme2" }
-theme_selector = { package = "theme_selector2", path = "../theme_selector2" }
+theme_selector = { path = "../theme_selector" }
 vcs_menu = { path = "../vcs_menu" }
 ui = { package = "ui2", path = "../ui2" }
 util = { path = "../util" }

crates/project_symbols/Cargo.toml 🔗

@@ -9,15 +9,15 @@ path = "src/project_symbols.rs"
 doctest = false
 
 [dependencies]
-editor = { path = "../editor" }
-fuzzy = { path = "../fuzzy" }
-gpui = { path = "../gpui" }
-picker = { path = "../picker" }
-project = { path = "../project" }
-text = { path = "../text" }
-settings = { path = "../settings" }
-workspace = { path = "../workspace" }
-theme = { path = "../theme" }
+editor = { package = "editor2", path = "../editor2" }
+fuzzy = {package = "fuzzy2",  path = "../fuzzy2" }
+gpui = {package = "gpui2",  path = "../gpui2" }
+picker = {package = "picker2",  path = "../picker2" }
+project = { package = "project2", path = "../project2" }
+text = {package = "text2",  path = "../text2" }
+settings = {package = "settings2",  path = "../settings2" }
+workspace = {package = "workspace2",  path = "../workspace2" }
+theme = { package = "theme2", path = "../theme2" }
 util = { path = "../util" }
 
 anyhow.workspace = true
@@ -27,11 +27,11 @@ smol.workspace = true
 
 [dev-dependencies]
 futures.workspace = true
-editor = { path = "../editor", features = ["test-support"] }
-settings = { path = "../settings", features = ["test-support"] }
-gpui = { path = "../gpui", features = ["test-support"] }
-language = { path = "../language", features = ["test-support"] }
-lsp = { path = "../lsp", features = ["test-support"] }
-project = { path = "../project", features = ["test-support"] }
-theme = { path = "../theme", features = ["test-support"] }
-workspace = { path = "../workspace", features = ["test-support"] }
+editor = { package = "editor2", path = "../editor2", features = ["test-support"] }
+settings = { package = "settings2", path = "../settings2", features = ["test-support"] }
+gpui = { package = "gpui2", path = "../gpui2", features = ["test-support"] }
+language = { package = "language2", path = "../language2", features = ["test-support"] }
+lsp = { package = "lsp2", path = "../lsp2", features = ["test-support"] }
+project = { package = "project2", path = "../project2", features = ["test-support"] }
+theme = { package = "theme2", path = "../theme2", features = ["test-support"] }
+workspace = { package = "workspace2",  path = "../workspace2", features = ["test-support"] }

crates/project_symbols/src/project_symbols.rs 🔗

@@ -1,38 +1,43 @@
-use editor::{
-    combine_syntax_and_fuzzy_match_highlights, scroll::autoscroll::Autoscroll,
-    styled_runs_for_code_label, Bias, Editor,
-};
+use editor::{scroll::autoscroll::Autoscroll, styled_runs_for_code_label, Bias, Editor};
 use fuzzy::{StringMatch, StringMatchCandidate};
 use gpui::{
-    actions, elements::*, AppContext, ModelHandle, MouseState, Task, ViewContext, WeakViewHandle,
+    actions, rems, AppContext, DismissEvent, FontWeight, Model, ParentElement, StyledText, Task,
+    View, ViewContext, WeakView,
 };
 use ordered_float::OrderedFloat;
-use picker::{Picker, PickerDelegate, PickerEvent};
+use picker::{Picker, PickerDelegate};
 use project::{Project, Symbol};
 use std::{borrow::Cow, cmp::Reverse, sync::Arc};
+use theme::ActiveTheme;
 use util::ResultExt;
-use workspace::Workspace;
+use workspace::{
+    ui::{v_stack, Color, Label, LabelCommon, LabelLike, ListItem, ListItemSpacing, Selectable},
+    Workspace,
+};
 
 actions!(project_symbols, [Toggle]);
 
 pub fn init(cx: &mut AppContext) {
-    cx.add_action(toggle);
-    ProjectSymbols::init(cx);
-}
-
-fn toggle(workspace: &mut Workspace, _: &Toggle, cx: &mut ViewContext<Workspace>) {
-    workspace.toggle_modal(cx, |workspace, cx| {
-        let project = workspace.project().clone();
-        let workspace = cx.weak_handle();
-        cx.add_view(|cx| ProjectSymbols::new(ProjectSymbolsDelegate::new(workspace, project), cx))
-    });
+    cx.observe_new_views(
+        |workspace: &mut Workspace, _: &mut ViewContext<Workspace>| {
+            workspace.register_action(|workspace, _: &Toggle, cx| {
+                let project = workspace.project().clone();
+                let handle = cx.view().downgrade();
+                workspace.toggle_modal(cx, move |cx| {
+                    let delegate = ProjectSymbolsDelegate::new(handle, project);
+                    Picker::new(delegate, cx).width(rems(34.))
+                })
+            });
+        },
+    )
+    .detach();
 }
 
-pub type ProjectSymbols = Picker<ProjectSymbolsDelegate>;
+pub type ProjectSymbols = View<Picker<ProjectSymbolsDelegate>>;
 
 pub struct ProjectSymbolsDelegate {
-    workspace: WeakViewHandle<Workspace>,
-    project: ModelHandle<Project>,
+    workspace: WeakView<Workspace>,
+    project: Model<Project>,
     selected_match_index: usize,
     symbols: Vec<Symbol>,
     visible_match_candidates: Vec<StringMatchCandidate>,
@@ -42,7 +47,7 @@ pub struct ProjectSymbolsDelegate {
 }
 
 impl ProjectSymbolsDelegate {
-    fn new(workspace: WeakViewHandle<Workspace>, project: ModelHandle<Project>) -> Self {
+    fn new(workspace: WeakView<Workspace>, project: Model<Project>) -> Self {
         Self {
             workspace,
             project,
@@ -55,7 +60,7 @@ impl ProjectSymbolsDelegate {
         }
     }
 
-    fn filter(&mut self, query: &str, cx: &mut ViewContext<ProjectSymbols>) {
+    fn filter(&mut self, query: &str, cx: &mut ViewContext<Picker<Self>>) {
         const MAX_MATCHES: usize = 100;
         let mut visible_matches = cx.background_executor().block(fuzzy::match_strings(
             &self.visible_match_candidates,
@@ -63,7 +68,7 @@ impl ProjectSymbolsDelegate {
             false,
             MAX_MATCHES,
             &Default::default(),
-            cx.background().clone(),
+            cx.background_executor().clone(),
         ));
         let mut external_matches = cx.background_executor().block(fuzzy::match_strings(
             &self.external_match_candidates,
@@ -71,7 +76,7 @@ impl ProjectSymbolsDelegate {
             false,
             MAX_MATCHES - visible_matches.len().min(MAX_MATCHES),
             &Default::default(),
-            cx.background().clone(),
+            cx.background_executor().clone(),
         ));
         let sort_key_for_match = |mat: &StringMatch| {
             let symbol = &self.symbols[mat.candidate_id];
@@ -100,11 +105,12 @@ impl ProjectSymbolsDelegate {
 }
 
 impl PickerDelegate for ProjectSymbolsDelegate {
+    type ListItem = ListItem;
     fn placeholder_text(&self) -> Arc<str> {
         "Search project symbols...".into()
     }
 
-    fn confirm(&mut self, secondary: bool, cx: &mut ViewContext<ProjectSymbols>) {
+    fn confirm(&mut self, secondary: bool, cx: &mut ViewContext<Picker<Self>>) {
         if let Some(symbol) = self
             .matches
             .get(self.selected_match_index)
@@ -137,11 +143,11 @@ impl PickerDelegate for ProjectSymbolsDelegate {
                 Ok::<_, anyhow::Error>(())
             })
             .detach_and_log_err(cx);
-            cx.emit(PickerEvent::Dismiss);
+            cx.emit(DismissEvent);
         }
     }
 
-    fn dismissed(&mut self, _cx: &mut ViewContext<ProjectSymbols>) {}
+    fn dismissed(&mut self, _cx: &mut ViewContext<Picker<Self>>) {}
 
     fn match_count(&self) -> usize {
         self.matches.len()
@@ -151,11 +157,11 @@ impl PickerDelegate for ProjectSymbolsDelegate {
         self.selected_match_index
     }
 
-    fn set_selected_index(&mut self, ix: usize, _cx: &mut ViewContext<ProjectSymbols>) {
+    fn set_selected_index(&mut self, ix: usize, _cx: &mut ViewContext<Picker<Self>>) {
         self.selected_match_index = ix;
     }
 
-    fn update_matches(&mut self, query: String, cx: &mut ViewContext<ProjectSymbols>) -> Task<()> {
+    fn update_matches(&mut self, query: String, cx: &mut ViewContext<Picker<Self>>) -> Task<()> {
         self.filter(&query, cx);
         self.show_worktree_root_name = self.project.read(cx).visible_worktrees(cx).count() > 1;
         let symbols = self
@@ -165,7 +171,7 @@ impl PickerDelegate for ProjectSymbolsDelegate {
             let symbols = symbols.await.log_err();
             if let Some(symbols) = symbols {
                 this.update(&mut cx, |this, cx| {
-                    let delegate = this.delegate_mut();
+                    let delegate = &mut this.delegate;
                     let project = delegate.project.read(cx);
                     let (visible_match_candidates, external_match_candidates) = symbols
                         .iter()
@@ -195,17 +201,12 @@ impl PickerDelegate for ProjectSymbolsDelegate {
     fn render_match(
         &self,
         ix: usize,
-        mouse_state: &mut MouseState,
         selected: bool,
-        cx: &AppContext,
-    ) -> AnyElement<Picker<Self>> {
-        let theme = theme::current(cx);
-        let style = &theme.picker.item;
-        let current_style = style.in_state(selected).style_for(mouse_state);
-
+        cx: &mut ViewContext<Picker<Self>>,
+    ) -> Option<Self::ListItem> {
         let string_match = &self.matches[ix];
         let symbol = &self.symbols[string_match.candidate_id];
-        let syntax_runs = styled_runs_for_code_label(&symbol.label, &theme.editor.syntax);
+        let syntax_runs = styled_runs_for_code_label(&symbol.label, cx.theme().syntax());
 
         let mut path = symbol.path.path.to_string_lossy();
         if self.show_worktree_root_name {
@@ -219,29 +220,39 @@ impl PickerDelegate for ProjectSymbolsDelegate {
                 ));
             }
         }
+        let label = symbol.label.text.clone();
+        let path = path.to_string().clone();
+
+        let highlights = gpui::combine_highlights(
+            string_match
+                .positions
+                .iter()
+                .map(|pos| (*pos..pos + 1, FontWeight::BOLD.into())),
+            syntax_runs.map(|(range, mut highlight)| {
+                // Ignore font weight for syntax highlighting, as we'll use it
+                // for fuzzy matches.
+                highlight.font_weight = None;
+                (range, highlight)
+            }),
+        );
 
-        Flex::column()
-            .with_child(
-                Text::new(symbol.label.text.clone(), current_style.label.text.clone())
-                    .with_soft_wrap(false)
-                    .with_highlights(combine_syntax_and_fuzzy_match_highlights(
-                        &symbol.label.text,
-                        current_style.label.text.clone().into(),
-                        syntax_runs,
-                        &string_match.positions,
-                    )),
-            )
-            .with_child(
-                // Avoid styling the path differently when it is selected, since
-                // the symbol's syntax highlighting doesn't change when selected.
-                Label::new(
-                    path.to_string(),
-                    style.inactive_state().default.label.clone(),
+        Some(
+            ListItem::new(ix)
+                .inset(true)
+                .spacing(ListItemSpacing::Sparse)
+                .selected(selected)
+                .child(
+                    // todo!() combine_syntax_and_fuzzy_match_highlights()
+                    v_stack()
+                        .child(
+                            LabelLike::new().child(
+                                StyledText::new(label)
+                                    .with_highlights(&cx.text_style().clone(), highlights),
+                            ),
+                        )
+                        .child(Label::new(path).color(Color::Muted)),
                 ),
-            )
-            .contained()
-            .with_style(current_style.container)
-            .into_any()
+        )
     }
 }
 
@@ -249,7 +260,7 @@ impl PickerDelegate for ProjectSymbolsDelegate {
 mod tests {
     use super::*;
     use futures::StreamExt;
-    use gpui::{serde_json::json, TestAppContext};
+    use gpui::{serde_json::json, TestAppContext, VisualContext};
     use language::{FakeLspAdapter, Language, LanguageConfig};
     use project::FakeFs;
     use settings::SettingsStore;
@@ -271,7 +282,7 @@ mod tests {
             .set_fake_lsp_adapter(Arc::<FakeLspAdapter>::default())
             .await;
 
-        let fs = FakeFs::new(cx.background());
+        let fs = FakeFs::new(cx.executor());
         fs.insert_tree("/dir", json!({ "test.rs": "" })).await;
 
         let project = Project::test(fs.clone(), ["/dir".as_ref()], cx).await;
@@ -294,7 +305,7 @@ mod tests {
         let fake_server = fake_servers.next().await.unwrap();
         fake_server.handle_request::<lsp::WorkspaceSymbolRequest, _, _>(
             move |params: lsp::WorkspaceSymbolParams, cx| {
-                let executor = cx.background();
+                let executor = cx.background_executor().clone();
                 let fake_symbols = fake_symbols.clone();
                 async move {
                     let candidates = fake_symbols
@@ -326,12 +337,11 @@ mod tests {
             },
         );
 
-        let window = cx.add_window(|cx| Workspace::test_new(project.clone(), cx));
-        let workspace = window.root(cx);
+        let (workspace, cx) = cx.add_window_view(|cx| Workspace::test_new(project.clone(), cx));
 
         // Create the project symbols view.
-        let symbols = window.add_view(cx, |cx| {
-            ProjectSymbols::new(
+        let symbols = cx.new_view(|cx| {
+            Picker::new(
                 ProjectSymbolsDelegate::new(workspace.downgrade(), project.clone()),
                 cx,
             )
@@ -346,9 +356,9 @@ mod tests {
             p.update_matches("onex".to_string(), cx);
         });
 
-        cx.foreground().run_until_parked();
-        symbols.read_with(cx, |symbols, _| {
-            assert_eq!(symbols.delegate().matches.len(), 0);
+        cx.run_until_parked();
+        symbols.update(cx, |symbols, _| {
+            assert_eq!(symbols.delegate.matches.len(), 0);
         });
 
         // Spawn more updates such that in the end, there are matches.
@@ -357,9 +367,9 @@ mod tests {
             p.update_matches("on".to_string(), cx);
         });
 
-        cx.foreground().run_until_parked();
-        symbols.read_with(cx, |symbols, _| {
-            let delegate = symbols.delegate();
+        cx.run_until_parked();
+        symbols.update(cx, |symbols, _| {
+            let delegate = &symbols.delegate;
             assert_eq!(delegate.matches.len(), 2);
             assert_eq!(delegate.matches[0].string, "ton");
             assert_eq!(delegate.matches[1].string, "one");
@@ -371,17 +381,17 @@ mod tests {
             p.update_matches("".to_string(), cx);
         });
 
-        cx.foreground().run_until_parked();
-        symbols.read_with(cx, |symbols, _| {
-            assert_eq!(symbols.delegate().matches.len(), 0);
+        cx.run_until_parked();
+        symbols.update(cx, |symbols, _| {
+            assert_eq!(symbols.delegate.matches.len(), 0);
         });
     }
 
     fn init_test(cx: &mut TestAppContext) {
-        cx.foreground().forbid_parking();
         cx.update(|cx| {
-            cx.set_global(SettingsStore::test(cx));
-            theme::init((), cx);
+            let store = SettingsStore::test(cx);
+            cx.set_global(store);
+            theme::init(theme::LoadThemes::JustBase, cx);
             language::init(cx);
             Project::init_settings(cx);
             workspace::init_settings(cx);

crates/project_symbols2/Cargo.toml 🔗

@@ -1,37 +0,0 @@
-[package]
-name = "project_symbols2"
-version = "0.1.0"
-edition = "2021"
-publish = false
-
-[lib]
-path = "src/project_symbols.rs"
-doctest = false
-
-[dependencies]
-editor = { package = "editor2", path = "../editor2" }
-fuzzy = {package = "fuzzy2",  path = "../fuzzy2" }
-gpui = {package = "gpui2",  path = "../gpui2" }
-picker = {package = "picker2",  path = "../picker2" }
-project = { package = "project2", path = "../project2" }
-text = {package = "text2",  path = "../text2" }
-settings = {package = "settings2",  path = "../settings2" }
-workspace = {package = "workspace2",  path = "../workspace2" }
-theme = { package = "theme2", path = "../theme2" }
-util = { path = "../util" }
-
-anyhow.workspace = true
-ordered-float.workspace = true
-postage.workspace = true
-smol.workspace = true
-
-[dev-dependencies]
-futures.workspace = true
-editor = { package = "editor2", path = "../editor2", features = ["test-support"] }
-settings = { package = "settings2", path = "../settings2", features = ["test-support"] }
-gpui = { package = "gpui2", path = "../gpui2", features = ["test-support"] }
-language = { package = "language2", path = "../language2", features = ["test-support"] }
-lsp = { package = "lsp2", path = "../lsp2", features = ["test-support"] }
-project = { package = "project2", path = "../project2", features = ["test-support"] }
-theme = { package = "theme2", path = "../theme2", features = ["test-support"] }
-workspace = { package = "workspace2",  path = "../workspace2", features = ["test-support"] }

crates/project_symbols2/src/project_symbols.rs 🔗

@@ -1,415 +0,0 @@
-use editor::{scroll::autoscroll::Autoscroll, styled_runs_for_code_label, Bias, Editor};
-use fuzzy::{StringMatch, StringMatchCandidate};
-use gpui::{
-    actions, rems, AppContext, DismissEvent, FontWeight, Model, ParentElement, StyledText, Task,
-    View, ViewContext, WeakView,
-};
-use ordered_float::OrderedFloat;
-use picker::{Picker, PickerDelegate};
-use project::{Project, Symbol};
-use std::{borrow::Cow, cmp::Reverse, sync::Arc};
-use theme::ActiveTheme;
-use util::ResultExt;
-use workspace::{
-    ui::{v_stack, Color, Label, LabelCommon, LabelLike, ListItem, ListItemSpacing, Selectable},
-    Workspace,
-};
-
-actions!(project_symbols, [Toggle]);
-
-pub fn init(cx: &mut AppContext) {
-    cx.observe_new_views(
-        |workspace: &mut Workspace, _: &mut ViewContext<Workspace>| {
-            workspace.register_action(|workspace, _: &Toggle, cx| {
-                let project = workspace.project().clone();
-                let handle = cx.view().downgrade();
-                workspace.toggle_modal(cx, move |cx| {
-                    let delegate = ProjectSymbolsDelegate::new(handle, project);
-                    Picker::new(delegate, cx).width(rems(34.))
-                })
-            });
-        },
-    )
-    .detach();
-}
-
-pub type ProjectSymbols = View<Picker<ProjectSymbolsDelegate>>;
-
-pub struct ProjectSymbolsDelegate {
-    workspace: WeakView<Workspace>,
-    project: Model<Project>,
-    selected_match_index: usize,
-    symbols: Vec<Symbol>,
-    visible_match_candidates: Vec<StringMatchCandidate>,
-    external_match_candidates: Vec<StringMatchCandidate>,
-    show_worktree_root_name: bool,
-    matches: Vec<StringMatch>,
-}
-
-impl ProjectSymbolsDelegate {
-    fn new(workspace: WeakView<Workspace>, project: Model<Project>) -> Self {
-        Self {
-            workspace,
-            project,
-            selected_match_index: 0,
-            symbols: Default::default(),
-            visible_match_candidates: Default::default(),
-            external_match_candidates: Default::default(),
-            matches: Default::default(),
-            show_worktree_root_name: false,
-        }
-    }
-
-    fn filter(&mut self, query: &str, cx: &mut ViewContext<Picker<Self>>) {
-        const MAX_MATCHES: usize = 100;
-        let mut visible_matches = cx.background_executor().block(fuzzy::match_strings(
-            &self.visible_match_candidates,
-            query,
-            false,
-            MAX_MATCHES,
-            &Default::default(),
-            cx.background_executor().clone(),
-        ));
-        let mut external_matches = cx.background_executor().block(fuzzy::match_strings(
-            &self.external_match_candidates,
-            query,
-            false,
-            MAX_MATCHES - visible_matches.len().min(MAX_MATCHES),
-            &Default::default(),
-            cx.background_executor().clone(),
-        ));
-        let sort_key_for_match = |mat: &StringMatch| {
-            let symbol = &self.symbols[mat.candidate_id];
-            (
-                Reverse(OrderedFloat(mat.score)),
-                &symbol.label.text[symbol.label.filter_range.clone()],
-            )
-        };
-
-        visible_matches.sort_unstable_by_key(sort_key_for_match);
-        external_matches.sort_unstable_by_key(sort_key_for_match);
-        let mut matches = visible_matches;
-        matches.append(&mut external_matches);
-
-        for mat in &mut matches {
-            let symbol = &self.symbols[mat.candidate_id];
-            let filter_start = symbol.label.filter_range.start;
-            for position in &mut mat.positions {
-                *position += filter_start;
-            }
-        }
-
-        self.matches = matches;
-        self.set_selected_index(0, cx);
-    }
-}
-
-impl PickerDelegate for ProjectSymbolsDelegate {
-    type ListItem = ListItem;
-    fn placeholder_text(&self) -> Arc<str> {
-        "Search project symbols...".into()
-    }
-
-    fn confirm(&mut self, secondary: bool, cx: &mut ViewContext<Picker<Self>>) {
-        if let Some(symbol) = self
-            .matches
-            .get(self.selected_match_index)
-            .map(|mat| self.symbols[mat.candidate_id].clone())
-        {
-            let buffer = self.project.update(cx, |project, cx| {
-                project.open_buffer_for_symbol(&symbol, cx)
-            });
-            let symbol = symbol.clone();
-            let workspace = self.workspace.clone();
-            cx.spawn(|_, mut cx| async move {
-                let buffer = buffer.await?;
-                workspace.update(&mut cx, |workspace, cx| {
-                    let position = buffer
-                        .read(cx)
-                        .clip_point_utf16(symbol.range.start, Bias::Left);
-
-                    let editor = if secondary {
-                        workspace.split_project_item::<Editor>(buffer, cx)
-                    } else {
-                        workspace.open_project_item::<Editor>(buffer, cx)
-                    };
-
-                    editor.update(cx, |editor, cx| {
-                        editor.change_selections(Some(Autoscroll::center()), cx, |s| {
-                            s.select_ranges([position..position])
-                        });
-                    });
-                })?;
-                Ok::<_, anyhow::Error>(())
-            })
-            .detach_and_log_err(cx);
-            cx.emit(DismissEvent);
-        }
-    }
-
-    fn dismissed(&mut self, _cx: &mut ViewContext<Picker<Self>>) {}
-
-    fn match_count(&self) -> usize {
-        self.matches.len()
-    }
-
-    fn selected_index(&self) -> usize {
-        self.selected_match_index
-    }
-
-    fn set_selected_index(&mut self, ix: usize, _cx: &mut ViewContext<Picker<Self>>) {
-        self.selected_match_index = ix;
-    }
-
-    fn update_matches(&mut self, query: String, cx: &mut ViewContext<Picker<Self>>) -> Task<()> {
-        self.filter(&query, cx);
-        self.show_worktree_root_name = self.project.read(cx).visible_worktrees(cx).count() > 1;
-        let symbols = self
-            .project
-            .update(cx, |project, cx| project.symbols(&query, cx));
-        cx.spawn(|this, mut cx| async move {
-            let symbols = symbols.await.log_err();
-            if let Some(symbols) = symbols {
-                this.update(&mut cx, |this, cx| {
-                    let delegate = &mut this.delegate;
-                    let project = delegate.project.read(cx);
-                    let (visible_match_candidates, external_match_candidates) = symbols
-                        .iter()
-                        .enumerate()
-                        .map(|(id, symbol)| {
-                            StringMatchCandidate::new(
-                                id,
-                                symbol.label.text[symbol.label.filter_range.clone()].to_string(),
-                            )
-                        })
-                        .partition(|candidate| {
-                            project
-                                .entry_for_path(&symbols[candidate.id].path, cx)
-                                .map_or(false, |e| !e.is_ignored)
-                        });
-
-                    delegate.visible_match_candidates = visible_match_candidates;
-                    delegate.external_match_candidates = external_match_candidates;
-                    delegate.symbols = symbols;
-                    delegate.filter(&query, cx);
-                })
-                .log_err();
-            }
-        })
-    }
-
-    fn render_match(
-        &self,
-        ix: usize,
-        selected: bool,
-        cx: &mut ViewContext<Picker<Self>>,
-    ) -> Option<Self::ListItem> {
-        let string_match = &self.matches[ix];
-        let symbol = &self.symbols[string_match.candidate_id];
-        let syntax_runs = styled_runs_for_code_label(&symbol.label, cx.theme().syntax());
-
-        let mut path = symbol.path.path.to_string_lossy();
-        if self.show_worktree_root_name {
-            let project = self.project.read(cx);
-            if let Some(worktree) = project.worktree_for_id(symbol.path.worktree_id, cx) {
-                path = Cow::Owned(format!(
-                    "{}{}{}",
-                    worktree.read(cx).root_name(),
-                    std::path::MAIN_SEPARATOR,
-                    path.as_ref()
-                ));
-            }
-        }
-        let label = symbol.label.text.clone();
-        let path = path.to_string().clone();
-
-        let highlights = gpui::combine_highlights(
-            string_match
-                .positions
-                .iter()
-                .map(|pos| (*pos..pos + 1, FontWeight::BOLD.into())),
-            syntax_runs.map(|(range, mut highlight)| {
-                // Ignore font weight for syntax highlighting, as we'll use it
-                // for fuzzy matches.
-                highlight.font_weight = None;
-                (range, highlight)
-            }),
-        );
-
-        Some(
-            ListItem::new(ix)
-                .inset(true)
-                .spacing(ListItemSpacing::Sparse)
-                .selected(selected)
-                .child(
-                    // todo!() combine_syntax_and_fuzzy_match_highlights()
-                    v_stack()
-                        .child(
-                            LabelLike::new().child(
-                                StyledText::new(label)
-                                    .with_highlights(&cx.text_style().clone(), highlights),
-                            ),
-                        )
-                        .child(Label::new(path).color(Color::Muted)),
-                ),
-        )
-    }
-}
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-    use futures::StreamExt;
-    use gpui::{serde_json::json, TestAppContext, VisualContext};
-    use language::{FakeLspAdapter, Language, LanguageConfig};
-    use project::FakeFs;
-    use settings::SettingsStore;
-    use std::{path::Path, sync::Arc};
-
-    #[gpui::test]
-    async fn test_project_symbols(cx: &mut TestAppContext) {
-        init_test(cx);
-
-        let mut language = Language::new(
-            LanguageConfig {
-                name: "Rust".into(),
-                path_suffixes: vec!["rs".to_string()],
-                ..Default::default()
-            },
-            None,
-        );
-        let mut fake_servers = language
-            .set_fake_lsp_adapter(Arc::<FakeLspAdapter>::default())
-            .await;
-
-        let fs = FakeFs::new(cx.executor());
-        fs.insert_tree("/dir", json!({ "test.rs": "" })).await;
-
-        let project = Project::test(fs.clone(), ["/dir".as_ref()], cx).await;
-        project.update(cx, |project, _| project.languages().add(Arc::new(language)));
-
-        let _buffer = project
-            .update(cx, |project, cx| {
-                project.open_local_buffer("/dir/test.rs", cx)
-            })
-            .await
-            .unwrap();
-
-        // Set up fake language server to return fuzzy matches against
-        // a fixed set of symbol names.
-        let fake_symbols = [
-            symbol("one", "/external"),
-            symbol("ton", "/dir/test.rs"),
-            symbol("uno", "/dir/test.rs"),
-        ];
-        let fake_server = fake_servers.next().await.unwrap();
-        fake_server.handle_request::<lsp::WorkspaceSymbolRequest, _, _>(
-            move |params: lsp::WorkspaceSymbolParams, cx| {
-                let executor = cx.background_executor().clone();
-                let fake_symbols = fake_symbols.clone();
-                async move {
-                    let candidates = fake_symbols
-                        .iter()
-                        .enumerate()
-                        .map(|(id, symbol)| StringMatchCandidate::new(id, symbol.name.clone()))
-                        .collect::<Vec<_>>();
-                    let matches = if params.query.is_empty() {
-                        Vec::new()
-                    } else {
-                        fuzzy::match_strings(
-                            &candidates,
-                            &params.query,
-                            true,
-                            100,
-                            &Default::default(),
-                            executor.clone(),
-                        )
-                        .await
-                    };
-
-                    Ok(Some(lsp::WorkspaceSymbolResponse::Flat(
-                        matches
-                            .into_iter()
-                            .map(|mat| fake_symbols[mat.candidate_id].clone())
-                            .collect(),
-                    )))
-                }
-            },
-        );
-
-        let (workspace, cx) = cx.add_window_view(|cx| Workspace::test_new(project.clone(), cx));
-
-        // Create the project symbols view.
-        let symbols = cx.new_view(|cx| {
-            Picker::new(
-                ProjectSymbolsDelegate::new(workspace.downgrade(), project.clone()),
-                cx,
-            )
-        });
-
-        // Spawn multiples updates before the first update completes,
-        // such that in the end, there are no matches. Testing for regression:
-        // https://github.com/zed-industries/zed/issues/861
-        symbols.update(cx, |p, cx| {
-            p.update_matches("o".to_string(), cx);
-            p.update_matches("on".to_string(), cx);
-            p.update_matches("onex".to_string(), cx);
-        });
-
-        cx.run_until_parked();
-        symbols.update(cx, |symbols, _| {
-            assert_eq!(symbols.delegate.matches.len(), 0);
-        });
-
-        // Spawn more updates such that in the end, there are matches.
-        symbols.update(cx, |p, cx| {
-            p.update_matches("one".to_string(), cx);
-            p.update_matches("on".to_string(), cx);
-        });
-
-        cx.run_until_parked();
-        symbols.update(cx, |symbols, _| {
-            let delegate = &symbols.delegate;
-            assert_eq!(delegate.matches.len(), 2);
-            assert_eq!(delegate.matches[0].string, "ton");
-            assert_eq!(delegate.matches[1].string, "one");
-        });
-
-        // Spawn more updates such that in the end, there are again no matches.
-        symbols.update(cx, |p, cx| {
-            p.update_matches("o".to_string(), cx);
-            p.update_matches("".to_string(), cx);
-        });
-
-        cx.run_until_parked();
-        symbols.update(cx, |symbols, _| {
-            assert_eq!(symbols.delegate.matches.len(), 0);
-        });
-    }
-
-    fn init_test(cx: &mut TestAppContext) {
-        cx.update(|cx| {
-            let store = SettingsStore::test(cx);
-            cx.set_global(store);
-            theme::init(theme::LoadThemes::JustBase, cx);
-            language::init(cx);
-            Project::init_settings(cx);
-            workspace::init_settings(cx);
-        });
-    }
-
-    fn symbol(name: &str, path: impl AsRef<Path>) -> lsp::SymbolInformation {
-        #[allow(deprecated)]
-        lsp::SymbolInformation {
-            name: name.to_string(),
-            kind: lsp::SymbolKind::FUNCTION,
-            tags: None,
-            deprecated: None,
-            container_name: None,
-            location: lsp::Location::new(
-                lsp::Url::from_file_path(path.as_ref()).unwrap(),
-                lsp::Range::new(lsp::Position::new(0, 0), lsp::Position::new(0, 0)),
-            ),
-        }
-    }
-}

crates/theme_selector/Cargo.toml 🔗

@@ -9,21 +9,22 @@ path = "src/theme_selector.rs"
 doctest = false
 
 [dependencies]
-client = { path = "../client" }
-editor = { path = "../editor" }
-fuzzy = { path = "../fuzzy" }
-fs = { path = "../fs" }
-gpui = { path = "../gpui" }
-picker = { path = "../picker" }
-theme = { path = "../theme" }
-settings = { path = "../settings" }
-feature_flags = { path = "../feature_flags" }
-workspace = { path = "../workspace" }
+client = { package = "client2", path = "../client2" }
+editor = { package = "editor2", path = "../editor2" }
+feature_flags = { package = "feature_flags2", path = "../feature_flags2" }
+fs = { package = "fs2", path = "../fs2" }
+fuzzy = { package = "fuzzy2", path = "../fuzzy2" }
+gpui = { package = "gpui2", path = "../gpui2" }
+picker = { package = "picker2", path = "../picker2" }
+settings = { package = "settings2", path = "../settings2" }
+theme = { package = "theme2", path = "../theme2" }
+ui = { package = "ui2", path = "../ui2" }
 util = { path = "../util" }
+workspace = { package = "workspace2", path = "../workspace2" }
 log.workspace = true
 parking_lot.workspace = true
 postage.workspace = true
 smol.workspace = true
 
 [dev-dependencies]
-editor = { path = "../editor", features = ["test-support"] }
+editor = { package = "editor2", path = "../editor2", features = ["test-support"] }

crates/theme_selector/src/theme_selector.rs 🔗

@@ -2,35 +2,48 @@ use client::{telemetry::Telemetry, TelemetrySettings};
 use feature_flags::FeatureFlagAppExt;
 use fs::Fs;
 use fuzzy::{match_strings, StringMatch, StringMatchCandidate};
-use gpui::{actions, elements::*, AnyElement, AppContext, Element, MouseState, ViewContext};
-use picker::{Picker, PickerDelegate, PickerEvent};
-use settings::{update_settings_file, SettingsStore};
+use gpui::{
+    actions, AppContext, DismissEvent, EventEmitter, FocusableView, Render, View, ViewContext,
+    VisualContext, WeakView,
+};
+use picker::{Picker, PickerDelegate};
+use settings::{update_settings_file, Settings, SettingsStore};
 use std::sync::Arc;
 use theme::{Theme, ThemeMeta, ThemeRegistry, ThemeSettings};
+use ui::{prelude::*, v_stack, ListItem, ListItemSpacing};
 use util::ResultExt;
-use workspace::Workspace;
+use workspace::{ui::HighlightedLabel, ModalView, Workspace};
 
 actions!(theme_selector, [Toggle, Reload]);
 
 pub fn init(cx: &mut AppContext) {
-    cx.add_action(toggle);
-    ThemeSelector::init(cx);
+    cx.observe_new_views(
+        |workspace: &mut Workspace, _cx: &mut ViewContext<Workspace>| {
+            workspace.register_action(toggle);
+        },
+    )
+    .detach();
 }
 
 pub fn toggle(workspace: &mut Workspace, _: &Toggle, cx: &mut ViewContext<Workspace>) {
-    workspace.toggle_modal(cx, |workspace, cx| {
-        let fs = workspace.app_state().fs.clone();
-        let telemetry = workspace.client().telemetry().clone();
-        cx.add_view(|cx| ThemeSelector::new(ThemeSelectorDelegate::new(fs, telemetry, cx), cx))
+    let fs = workspace.app_state().fs.clone();
+    let telemetry = workspace.client().telemetry().clone();
+    workspace.toggle_modal(cx, |cx| {
+        ThemeSelector::new(
+            ThemeSelectorDelegate::new(cx.view().downgrade(), fs, telemetry, cx),
+            cx,
+        )
     });
 }
 
 #[cfg(debug_assertions)]
 pub fn reload(cx: &mut AppContext) {
-    let current_theme_name = theme::current(cx).meta.name.clone();
-    let registry = cx.global::<Arc<ThemeRegistry>>();
-    registry.clear();
-    match registry.get(&current_theme_name) {
+    let current_theme_name = cx.theme().name.clone();
+    let current_theme = cx.update_global(|registry: &mut ThemeRegistry, _cx| {
+        registry.clear();
+        registry.get(&current_theme_name)
+    });
+    match current_theme {
         Ok(theme) => {
             ThemeSelectorDelegate::set_theme(theme, cx);
             log::info!("reloaded theme {}", current_theme_name);
@@ -41,55 +54,88 @@ pub fn reload(cx: &mut AppContext) {
     }
 }
 
-pub type ThemeSelector = Picker<ThemeSelectorDelegate>;
+impl ModalView for ThemeSelector {}
+
+pub struct ThemeSelector {
+    picker: View<Picker<ThemeSelectorDelegate>>,
+}
+
+impl EventEmitter<DismissEvent> for ThemeSelector {}
+
+impl FocusableView for ThemeSelector {
+    fn focus_handle(&self, cx: &AppContext) -> gpui::FocusHandle {
+        self.picker.focus_handle(cx)
+    }
+}
+
+impl Render for ThemeSelector {
+    fn render(&mut self, _cx: &mut ViewContext<Self>) -> impl IntoElement {
+        v_stack().w(rems(34.)).child(self.picker.clone())
+    }
+}
+
+impl ThemeSelector {
+    pub fn new(delegate: ThemeSelectorDelegate, cx: &mut ViewContext<Self>) -> Self {
+        let picker = cx.new_view(|cx| Picker::new(delegate, cx));
+        Self { picker }
+    }
+}
 
 pub struct ThemeSelectorDelegate {
     fs: Arc<dyn Fs>,
-    theme_data: Vec<ThemeMeta>,
+    themes: Vec<ThemeMeta>,
     matches: Vec<StringMatch>,
     original_theme: Arc<Theme>,
     selection_completed: bool,
     selected_index: usize,
     telemetry: Arc<Telemetry>,
+    view: WeakView<ThemeSelector>,
 }
 
 impl ThemeSelectorDelegate {
     fn new(
+        weak_view: WeakView<ThemeSelector>,
         fs: Arc<dyn Fs>,
         telemetry: Arc<Telemetry>,
         cx: &mut ViewContext<ThemeSelector>,
     ) -> Self {
-        let original_theme = theme::current(cx).clone();
+        let original_theme = cx.theme().clone();
 
         let staff_mode = cx.is_staff();
-        let registry = cx.global::<Arc<ThemeRegistry>>();
-        let mut theme_names = registry.list(staff_mode).collect::<Vec<_>>();
-        theme_names.sort_unstable_by(|a, b| a.is_light.cmp(&b.is_light).then(a.name.cmp(&b.name)));
-        let matches = theme_names
+        let registry = cx.global::<ThemeRegistry>();
+        let mut themes = registry.list(staff_mode).collect::<Vec<_>>();
+        themes.sort_unstable_by(|a, b| {
+            a.appearance
+                .is_light()
+                .cmp(&b.appearance.is_light())
+                .then(a.name.cmp(&b.name))
+        });
+        let matches = themes
             .iter()
             .map(|meta| StringMatch {
                 candidate_id: 0,
                 score: 0.0,
                 positions: Default::default(),
-                string: meta.name.clone(),
+                string: meta.name.to_string(),
             })
             .collect();
         let mut this = Self {
             fs,
-            theme_data: theme_names,
+            themes,
             matches,
             original_theme: original_theme.clone(),
             selected_index: 0,
             selection_completed: false,
             telemetry,
+            view: weak_view,
         };
-        this.select_if_matching(&original_theme.meta.name);
+        this.select_if_matching(&original_theme.name);
         this
     }
 
-    fn show_selected_theme(&mut self, cx: &mut ViewContext<ThemeSelector>) {
+    fn show_selected_theme(&mut self, cx: &mut ViewContext<Picker<ThemeSelectorDelegate>>) {
         if let Some(mat) = self.matches.get(self.selected_index) {
-            let registry = cx.global::<Arc<ThemeRegistry>>();
+            let registry = cx.global::<ThemeRegistry>();
             match registry.get(&mat.string) {
                 Ok(theme) => {
                     Self::set_theme(theme, cx);
@@ -110,16 +156,18 @@ impl ThemeSelectorDelegate {
     }
 
     fn set_theme(theme: Arc<Theme>, cx: &mut AppContext) {
-        cx.update_global::<SettingsStore, _, _>(|store, cx| {
+        cx.update_global(|store: &mut SettingsStore, cx| {
             let mut theme_settings = store.get::<ThemeSettings>(None).clone();
-            theme_settings.theme = theme;
+            theme_settings.active_theme = theme;
             store.override_global(theme_settings);
-            cx.refresh_windows();
+            cx.refresh();
         });
     }
 }
 
 impl PickerDelegate for ThemeSelectorDelegate {
+    type ListItem = ui::ListItem;
+
     fn placeholder_text(&self) -> Arc<str> {
         "Select Theme...".into()
     }
@@ -128,34 +176,46 @@ impl PickerDelegate for ThemeSelectorDelegate {
         self.matches.len()
     }
 
-    fn confirm(&mut self, _: bool, cx: &mut ViewContext<ThemeSelector>) {
+    fn confirm(&mut self, _: bool, cx: &mut ViewContext<Picker<ThemeSelectorDelegate>>) {
         self.selection_completed = true;
 
-        let theme_name = theme::current(cx).meta.name.clone();
+        let theme_name = cx.theme().name.clone();
 
-        let telemetry_settings = *settings::get::<TelemetrySettings>(cx);
+        let telemetry_settings = TelemetrySettings::get_global(cx).clone();
         self.telemetry
             .report_setting_event(telemetry_settings, "theme", theme_name.to_string());
 
-        update_settings_file::<ThemeSettings>(self.fs.clone(), cx, |settings| {
-            settings.theme = Some(theme_name);
+        update_settings_file::<ThemeSettings>(self.fs.clone(), cx, move |settings| {
+            settings.theme = Some(theme_name.to_string());
         });
 
-        cx.emit(PickerEvent::Dismiss);
+        self.view
+            .update(cx, |_, cx| {
+                cx.emit(DismissEvent);
+            })
+            .ok();
     }
 
-    fn dismissed(&mut self, cx: &mut ViewContext<ThemeSelector>) {
+    fn dismissed(&mut self, cx: &mut ViewContext<Picker<ThemeSelectorDelegate>>) {
         if !self.selection_completed {
             Self::set_theme(self.original_theme.clone(), cx);
             self.selection_completed = true;
         }
+
+        self.view
+            .update(cx, |_, cx| cx.emit(DismissEvent))
+            .log_err();
     }
 
     fn selected_index(&self) -> usize {
         self.selected_index
     }
 
-    fn set_selected_index(&mut self, ix: usize, cx: &mut ViewContext<ThemeSelector>) {
+    fn set_selected_index(
+        &mut self,
+        ix: usize,
+        cx: &mut ViewContext<Picker<ThemeSelectorDelegate>>,
+    ) {
         self.selected_index = ix;
         self.show_selected_theme(cx);
     }
@@ -163,17 +223,17 @@ impl PickerDelegate for ThemeSelectorDelegate {
     fn update_matches(
         &mut self,
         query: String,
-        cx: &mut ViewContext<ThemeSelector>,
+        cx: &mut ViewContext<Picker<ThemeSelectorDelegate>>,
     ) -> gpui::Task<()> {
-        let background = cx.background().clone();
+        let background = cx.background_executor().clone();
         let candidates = self
-            .theme_data
+            .themes
             .iter()
             .enumerate()
             .map(|(id, meta)| StringMatchCandidate {
                 id,
-                char_bag: meta.name.as_str().into(),
-                string: meta.name.clone(),
+                char_bag: meta.name.as_ref().into(),
+                string: meta.name.to_string(),
             })
             .collect::<Vec<_>>();
 
@@ -202,12 +262,12 @@ impl PickerDelegate for ThemeSelectorDelegate {
             };
 
             this.update(&mut cx, |this, cx| {
-                let delegate = this.delegate_mut();
-                delegate.matches = matches;
-                delegate.selected_index = delegate
+                this.delegate.matches = matches;
+                this.delegate.selected_index = this
+                    .delegate
                     .selected_index
-                    .min(delegate.matches.len().saturating_sub(1));
-                delegate.show_selected_theme(cx);
+                    .min(this.delegate.matches.len().saturating_sub(1));
+                this.delegate.show_selected_theme(cx);
             })
             .log_err();
         })
@@ -216,18 +276,20 @@ impl PickerDelegate for ThemeSelectorDelegate {
     fn render_match(
         &self,
         ix: usize,
-        mouse_state: &mut MouseState,
         selected: bool,
-        cx: &AppContext,
-    ) -> AnyElement<Picker<Self>> {
-        let theme = theme::current(cx);
-        let style = theme.picker.item.in_state(selected).style_for(mouse_state);
-
+        _cx: &mut ViewContext<Picker<Self>>,
+    ) -> Option<Self::ListItem> {
         let theme_match = &self.matches[ix];
-        Label::new(theme_match.string.clone(), style.label.clone())
-            .with_highlights(theme_match.positions.clone())
-            .contained()
-            .with_style(style.container)
-            .into_any()
+
+        Some(
+            ListItem::new(ix)
+                .inset(true)
+                .spacing(ListItemSpacing::Sparse)
+                .selected(selected)
+                .child(HighlightedLabel::new(
+                    theme_match.string.clone(),
+                    theme_match.positions.clone(),
+                )),
+        )
     }
 }

crates/theme_selector2/Cargo.toml 🔗

@@ -1,30 +0,0 @@
-[package]
-name = "theme_selector2"
-version = "0.1.0"
-edition = "2021"
-publish = false
-
-[lib]
-path = "src/theme_selector.rs"
-doctest = false
-
-[dependencies]
-client = { package = "client2", path = "../client2" }
-editor = { package = "editor2", path = "../editor2" }
-feature_flags = { package = "feature_flags2", path = "../feature_flags2" }
-fs = { package = "fs2", path = "../fs2" }
-fuzzy = { package = "fuzzy2", path = "../fuzzy2" }
-gpui = { package = "gpui2", path = "../gpui2" }
-picker = { package = "picker2", path = "../picker2" }
-settings = { package = "settings2", path = "../settings2" }
-theme = { package = "theme2", path = "../theme2" }
-ui = { package = "ui2", path = "../ui2" }
-util = { path = "../util" }
-workspace = { package = "workspace2", path = "../workspace2" }
-log.workspace = true
-parking_lot.workspace = true
-postage.workspace = true
-smol.workspace = true
-
-[dev-dependencies]
-editor = { package = "editor2", path = "../editor2", features = ["test-support"] }

crates/theme_selector2/src/theme_selector.rs 🔗

@@ -1,295 +0,0 @@
-use client::{telemetry::Telemetry, TelemetrySettings};
-use feature_flags::FeatureFlagAppExt;
-use fs::Fs;
-use fuzzy::{match_strings, StringMatch, StringMatchCandidate};
-use gpui::{
-    actions, AppContext, DismissEvent, EventEmitter, FocusableView, Render, View, ViewContext,
-    VisualContext, WeakView,
-};
-use picker::{Picker, PickerDelegate};
-use settings::{update_settings_file, Settings, SettingsStore};
-use std::sync::Arc;
-use theme::{Theme, ThemeMeta, ThemeRegistry, ThemeSettings};
-use ui::{prelude::*, v_stack, ListItem, ListItemSpacing};
-use util::ResultExt;
-use workspace::{ui::HighlightedLabel, ModalView, Workspace};
-
-actions!(theme_selector, [Toggle, Reload]);
-
-pub fn init(cx: &mut AppContext) {
-    cx.observe_new_views(
-        |workspace: &mut Workspace, _cx: &mut ViewContext<Workspace>| {
-            workspace.register_action(toggle);
-        },
-    )
-    .detach();
-}
-
-pub fn toggle(workspace: &mut Workspace, _: &Toggle, cx: &mut ViewContext<Workspace>) {
-    let fs = workspace.app_state().fs.clone();
-    let telemetry = workspace.client().telemetry().clone();
-    workspace.toggle_modal(cx, |cx| {
-        ThemeSelector::new(
-            ThemeSelectorDelegate::new(cx.view().downgrade(), fs, telemetry, cx),
-            cx,
-        )
-    });
-}
-
-#[cfg(debug_assertions)]
-pub fn reload(cx: &mut AppContext) {
-    let current_theme_name = cx.theme().name.clone();
-    let current_theme = cx.update_global(|registry: &mut ThemeRegistry, _cx| {
-        registry.clear();
-        registry.get(&current_theme_name)
-    });
-    match current_theme {
-        Ok(theme) => {
-            ThemeSelectorDelegate::set_theme(theme, cx);
-            log::info!("reloaded theme {}", current_theme_name);
-        }
-        Err(error) => {
-            log::error!("failed to load theme {}: {:?}", current_theme_name, error)
-        }
-    }
-}
-
-impl ModalView for ThemeSelector {}
-
-pub struct ThemeSelector {
-    picker: View<Picker<ThemeSelectorDelegate>>,
-}
-
-impl EventEmitter<DismissEvent> for ThemeSelector {}
-
-impl FocusableView for ThemeSelector {
-    fn focus_handle(&self, cx: &AppContext) -> gpui::FocusHandle {
-        self.picker.focus_handle(cx)
-    }
-}
-
-impl Render for ThemeSelector {
-    fn render(&mut self, _cx: &mut ViewContext<Self>) -> impl IntoElement {
-        v_stack().w(rems(34.)).child(self.picker.clone())
-    }
-}
-
-impl ThemeSelector {
-    pub fn new(delegate: ThemeSelectorDelegate, cx: &mut ViewContext<Self>) -> Self {
-        let picker = cx.new_view(|cx| Picker::new(delegate, cx));
-        Self { picker }
-    }
-}
-
-pub struct ThemeSelectorDelegate {
-    fs: Arc<dyn Fs>,
-    themes: Vec<ThemeMeta>,
-    matches: Vec<StringMatch>,
-    original_theme: Arc<Theme>,
-    selection_completed: bool,
-    selected_index: usize,
-    telemetry: Arc<Telemetry>,
-    view: WeakView<ThemeSelector>,
-}
-
-impl ThemeSelectorDelegate {
-    fn new(
-        weak_view: WeakView<ThemeSelector>,
-        fs: Arc<dyn Fs>,
-        telemetry: Arc<Telemetry>,
-        cx: &mut ViewContext<ThemeSelector>,
-    ) -> Self {
-        let original_theme = cx.theme().clone();
-
-        let staff_mode = cx.is_staff();
-        let registry = cx.global::<ThemeRegistry>();
-        let mut themes = registry.list(staff_mode).collect::<Vec<_>>();
-        themes.sort_unstable_by(|a, b| {
-            a.appearance
-                .is_light()
-                .cmp(&b.appearance.is_light())
-                .then(a.name.cmp(&b.name))
-        });
-        let matches = themes
-            .iter()
-            .map(|meta| StringMatch {
-                candidate_id: 0,
-                score: 0.0,
-                positions: Default::default(),
-                string: meta.name.to_string(),
-            })
-            .collect();
-        let mut this = Self {
-            fs,
-            themes,
-            matches,
-            original_theme: original_theme.clone(),
-            selected_index: 0,
-            selection_completed: false,
-            telemetry,
-            view: weak_view,
-        };
-        this.select_if_matching(&original_theme.name);
-        this
-    }
-
-    fn show_selected_theme(&mut self, cx: &mut ViewContext<Picker<ThemeSelectorDelegate>>) {
-        if let Some(mat) = self.matches.get(self.selected_index) {
-            let registry = cx.global::<ThemeRegistry>();
-            match registry.get(&mat.string) {
-                Ok(theme) => {
-                    Self::set_theme(theme, cx);
-                }
-                Err(error) => {
-                    log::error!("error loading theme {}: {}", mat.string, error)
-                }
-            }
-        }
-    }
-
-    fn select_if_matching(&mut self, theme_name: &str) {
-        self.selected_index = self
-            .matches
-            .iter()
-            .position(|mat| mat.string == theme_name)
-            .unwrap_or(self.selected_index);
-    }
-
-    fn set_theme(theme: Arc<Theme>, cx: &mut AppContext) {
-        cx.update_global(|store: &mut SettingsStore, cx| {
-            let mut theme_settings = store.get::<ThemeSettings>(None).clone();
-            theme_settings.active_theme = theme;
-            store.override_global(theme_settings);
-            cx.refresh();
-        });
-    }
-}
-
-impl PickerDelegate for ThemeSelectorDelegate {
-    type ListItem = ui::ListItem;
-
-    fn placeholder_text(&self) -> Arc<str> {
-        "Select Theme...".into()
-    }
-
-    fn match_count(&self) -> usize {
-        self.matches.len()
-    }
-
-    fn confirm(&mut self, _: bool, cx: &mut ViewContext<Picker<ThemeSelectorDelegate>>) {
-        self.selection_completed = true;
-
-        let theme_name = cx.theme().name.clone();
-
-        let telemetry_settings = TelemetrySettings::get_global(cx).clone();
-        self.telemetry
-            .report_setting_event(telemetry_settings, "theme", theme_name.to_string());
-
-        update_settings_file::<ThemeSettings>(self.fs.clone(), cx, move |settings| {
-            settings.theme = Some(theme_name.to_string());
-        });
-
-        self.view
-            .update(cx, |_, cx| {
-                cx.emit(DismissEvent);
-            })
-            .ok();
-    }
-
-    fn dismissed(&mut self, cx: &mut ViewContext<Picker<ThemeSelectorDelegate>>) {
-        if !self.selection_completed {
-            Self::set_theme(self.original_theme.clone(), cx);
-            self.selection_completed = true;
-        }
-
-        self.view
-            .update(cx, |_, cx| cx.emit(DismissEvent))
-            .log_err();
-    }
-
-    fn selected_index(&self) -> usize {
-        self.selected_index
-    }
-
-    fn set_selected_index(
-        &mut self,
-        ix: usize,
-        cx: &mut ViewContext<Picker<ThemeSelectorDelegate>>,
-    ) {
-        self.selected_index = ix;
-        self.show_selected_theme(cx);
-    }
-
-    fn update_matches(
-        &mut self,
-        query: String,
-        cx: &mut ViewContext<Picker<ThemeSelectorDelegate>>,
-    ) -> gpui::Task<()> {
-        let background = cx.background_executor().clone();
-        let candidates = self
-            .themes
-            .iter()
-            .enumerate()
-            .map(|(id, meta)| StringMatchCandidate {
-                id,
-                char_bag: meta.name.as_ref().into(),
-                string: meta.name.to_string(),
-            })
-            .collect::<Vec<_>>();
-
-        cx.spawn(|this, mut cx| async move {
-            let matches = if query.is_empty() {
-                candidates
-                    .into_iter()
-                    .enumerate()
-                    .map(|(index, candidate)| StringMatch {
-                        candidate_id: index,
-                        string: candidate.string,
-                        positions: Vec::new(),
-                        score: 0.0,
-                    })
-                    .collect()
-            } else {
-                match_strings(
-                    &candidates,
-                    &query,
-                    false,
-                    100,
-                    &Default::default(),
-                    background,
-                )
-                .await
-            };
-
-            this.update(&mut cx, |this, cx| {
-                this.delegate.matches = matches;
-                this.delegate.selected_index = this
-                    .delegate
-                    .selected_index
-                    .min(this.delegate.matches.len().saturating_sub(1));
-                this.delegate.show_selected_theme(cx);
-            })
-            .log_err();
-        })
-    }
-
-    fn render_match(
-        &self,
-        ix: usize,
-        selected: bool,
-        _cx: &mut ViewContext<Picker<Self>>,
-    ) -> Option<Self::ListItem> {
-        let theme_match = &self.matches[ix];
-
-        Some(
-            ListItem::new(ix)
-                .inset(true)
-                .spacing(ListItemSpacing::Sparse)
-                .selected(selected)
-                .child(HighlightedLabel::new(
-                    theme_match.string.clone(),
-                    theme_match.positions.clone(),
-                )),
-        )
-    }
-}

crates/welcome/Cargo.toml 🔗

@@ -22,7 +22,7 @@ install_cli = { package = "install_cli2", path = "../install_cli2" }
 project = { package = "project2", path = "../project2" }
 settings = { package = "settings2", path = "../settings2" }
 theme = { package = "theme2", path = "../theme2" }
-theme_selector = { package = "theme_selector2", path = "../theme_selector2" }
+theme_selector = { path = "../theme_selector" }
 util = { path = "../util" }
 picker = { package = "picker2", path = "../picker2" }
 workspace = { package = "workspace2", path = "../workspace2" }

crates/zed/Cargo.toml 🔗

@@ -55,7 +55,7 @@ outline = { package = "outline2", path = "../outline2" }
 # plugin_runtime = { path = "../plugin_runtime",optional = true }
 project = { package = "project2", path = "../project2" }
 project_panel = { package = "project_panel2", path = "../project_panel2" }
-project_symbols = { package = "project_symbols2", path = "../project_symbols2" }
+project_symbols = { path = "../project_symbols" }
 quick_action_bar = { path = "../quick_action_bar" }
 recent_projects = { package = "recent_projects2", path = "../recent_projects2" }
 rope = { package = "rope2", path = "../rope2"}
@@ -67,7 +67,7 @@ shellexpand = "2.1.0"
 text = { package = "text2", path = "../text2" }
 terminal_view = { package = "terminal_view2", path = "../terminal_view2" }
 theme = { package = "theme2", path = "../theme2" }
-theme_selector = { package = "theme_selector2", path = "../theme_selector2" }
+theme_selector = { path = "../theme_selector" }
 util = { path = "../util" }
 semantic_index = { package = "semantic_index2", path = "../semantic_index2" }
 vim = { package = "vim2", path = "../vim2" }