diff --git a/Cargo.lock b/Cargo.lock index 5911848611..e9e20c9102 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4804,6 +4804,7 @@ dependencies = [ "project2", "settings2", "theme2", + "ui2", "util", "workspace2", ] diff --git a/crates/editor2/src/editor.rs b/crates/editor2/src/editor.rs index 9b2681e563..92fa4ca792 100644 --- a/crates/editor2/src/editor.rs +++ b/crates/editor2/src/editor.rs @@ -1920,14 +1920,14 @@ impl Editor { // self.buffer.read(cx).read(cx).file_at(point).cloned() // } - // pub fn active_excerpt( - // &self, - // cx: &AppContext, - // ) -> Option<(ExcerptId, Model, Range)> { - // self.buffer - // .read(cx) - // .excerpt_containing(self.selections.newest_anchor().head(), cx) - // } + pub fn active_excerpt( + &self, + cx: &AppContext, + ) -> Option<(ExcerptId, Model, Range)> { + self.buffer + .read(cx) + .excerpt_containing(self.selections.newest_anchor().head(), cx) + } // pub fn style(&self, cx: &AppContext) -> EditorStyle { // build_style( diff --git a/crates/language_selector2/Cargo.toml b/crates/language_selector2/Cargo.toml index a588dccde8..67f0d1e0ee 100644 --- a/crates/language_selector2/Cargo.toml +++ b/crates/language_selector2/Cargo.toml @@ -9,13 +9,14 @@ path = "src/language_selector.rs" doctest = false [dependencies] -editor2 = { package = "editor2", path = "../editor2" } +editor = { package = "editor2", path = "../editor2" } fuzzy = { package = "fuzzy2", path = "../fuzzy2" } language = { package = "language2", path = "../language2" } gpui = { package = "gpui2", path = "../gpui2" } picker = { package = "picker2", path = "../picker2" } project = { package = "project2", path = "../project2" } theme = { package = "theme2", path = "../theme2" } +ui = { package = "ui2", path = "../ui2" } settings = { package = "settings2", path = "../settings2" } util = { path = "../util" } workspace = { package = "workspace2", path = "../workspace2" } diff --git a/crates/language_selector2/src/active_buffer_language.rs b/crates/language_selector2/src/active_buffer_language.rs index 01333c1ffb..4034cb0429 100644 --- a/crates/language_selector2/src/active_buffer_language.rs +++ b/crates/language_selector2/src/active_buffer_language.rs @@ -1,15 +1,16 @@ use editor::Editor; use gpui::{ - elements::*, - platform::{CursorStyle, MouseButton}, - Entity, Subscription, View, ViewContext, ViewHandle, WeakViewHandle, + div, Div, IntoElement, ParentElement, Render, Subscription, View, ViewContext, WeakView, }; use std::sync::Arc; +use ui::{Button, ButtonCommon, Clickable, Tooltip}; use workspace::{item::ItemHandle, StatusItemView, Workspace}; +use crate::LanguageSelector; + pub struct ActiveBufferLanguage { active_language: Option>>, - workspace: WeakViewHandle, + workspace: WeakView, _observe_active_editor: Option, } @@ -22,7 +23,7 @@ impl ActiveBufferLanguage { } } - fn update_language(&mut self, editor: ViewHandle, cx: &mut ViewContext) { + fn update_language(&mut self, editor: View, cx: &mut ViewContext) { self.active_language = Some(None); let editor = editor.read(cx); @@ -36,44 +37,29 @@ impl ActiveBufferLanguage { } } -impl Entity for ActiveBufferLanguage { - type Event = (); -} +impl Render for ActiveBufferLanguage { + type Element = Div; -impl View for ActiveBufferLanguage { - fn ui_name() -> &'static str { - "ActiveBufferLanguage" - } - - fn render(&mut self, cx: &mut ViewContext) -> AnyElement { - if let Some(active_language) = self.active_language.as_ref() { + fn render(&mut self, cx: &mut ViewContext) -> Div { + div().when_some(self.active_language.as_ref(), |el, active_language| { let active_language_text = if let Some(active_language_text) = active_language { active_language_text.to_string() } else { "Unknown".to_string() }; - let theme = theme::current(cx).clone(); - MouseEventHandler::new::(0, cx, |state, cx| { - let theme = &theme::current(cx).workspace.status_bar; - let style = theme.active_language.style_for(state); - Label::new(active_language_text, style.text.clone()) - .contained() - .with_style(style.container) - }) - .with_cursor_style(CursorStyle::PointingHand) - .on_click(MouseButton::Left, |_, this, cx| { - if let Some(workspace) = this.workspace.upgrade(cx) { - workspace.update(cx, |workspace, cx| { - crate::toggle(workspace, &Default::default(), cx) - }); - } - }) - .with_tooltip::(0, "Select Language", None, theme.tooltip.clone(), cx) - .into_any() - } else { - Empty::new().into_any() - } + el.child( + Button::new("change-language", active_language_text) + .on_click(cx.listener(|this, _, cx| { + if let Some(workspace) = this.workspace.upgrade() { + workspace.update(cx, |workspace, cx| { + LanguageSelector::toggle(workspace, cx) + }); + } + })) + .tooltip(|cx| Tooltip::text("Select Language", cx)), + ) + }) } } diff --git a/crates/language_selector2/src/language_selector.rs b/crates/language_selector2/src/language_selector.rs index 00379919d5..d0802daaa0 100644 --- a/crates/language_selector2/src/language_selector.rs +++ b/crates/language_selector2/src/language_selector.rs @@ -4,50 +4,88 @@ pub use active_buffer_language::ActiveBufferLanguage; use anyhow::anyhow; use editor::Editor; use fuzzy::{match_strings, StringMatch, StringMatchCandidate}; -use gpui::{actions, elements::*, AppContext, ModelHandle, MouseState, ViewContext}; +use gpui::{ + actions, Action, AppContext, DismissEvent, Div, EventEmitter, FocusHandle, FocusableView, + Model, ParentElement, Render, Styled, View, ViewContext, VisualContext, WeakView, +}; use language::{Buffer, LanguageRegistry}; -use picker::{Picker, PickerDelegate, PickerEvent}; +use picker::{Picker, PickerDelegate}; use project::Project; use std::sync::Arc; +use ui::{v_stack, HighlightedLabel, ListItem, Selectable}; use util::ResultExt; use workspace::Workspace; actions!(Toggle); pub fn init(cx: &mut AppContext) { - cx.observe_new_views(LanguagePicker::register).detach(); + cx.observe_new_views(LanguageSelector::register).detach(); } -pub fn init(cx: &mut AppContext) { - Picker::::init(cx); - cx.add_action(toggle); +pub struct LanguageSelector { + picker: View>, } -pub fn toggle( - workspace: &mut Workspace, - _: &Toggle, - cx: &mut ViewContext, -) -> Option<()> { - let (_, buffer, _) = workspace - .active_item(cx)? - .act_as::(cx)? - .read(cx) - .active_excerpt(cx)?; - workspace.toggle_modal(cx, |workspace, cx| { +impl LanguageSelector { + fn register(workspace: &mut Workspace, cx: &mut ViewContext) { + dbg!("regsiter"); + workspace.register_action(move |workspace, _: &Toggle, cx| { + Self::toggle(workspace, cx); + }); + } + + fn toggle(workspace: &mut Workspace, cx: &mut ViewContext) -> Option<()> { let registry = workspace.app_state().languages.clone(); - cx.add_view(|cx| { - Picker::new( - LanguageSelectorDelegate::new(buffer, workspace.project().clone(), registry), - cx, - ) - }) - }); - Some(()) + let (_, buffer, _) = workspace + .active_item(cx)? + .act_as::(cx)? + .read(cx) + .active_excerpt(cx)?; + let project = workspace.project().clone(); + + workspace.toggle_modal(cx, move |cx| { + LanguageSelector::new(buffer, project, registry, cx) + }); + Some(()) + } + + fn new( + buffer: Model, + project: Model, + language_registry: Arc, + cx: &mut ViewContext, + ) -> Self { + let delegate = LanguageSelectorDelegate::new( + cx.view().downgrade(), + buffer, + project, + language_registry, + ); + + let picker = cx.build_view(|cx| Picker::new(delegate, cx)); + Self { picker } + } } +impl Render for LanguageSelector { + type Element = Div; + + fn render(&mut self, _cx: &mut ViewContext) -> Self::Element { + v_stack().min_w_96().child(self.picker.clone()) + } +} + +impl FocusableView for LanguageSelector { + fn focus_handle(&self, cx: &AppContext) -> FocusHandle { + self.picker.focus_handle(cx) + } +} +impl EventEmitter for LanguageSelector {} + pub struct LanguageSelectorDelegate { - buffer: ModelHandle, - project: ModelHandle, + language_selector: WeakView, + buffer: Model, + project: Model, language_registry: Arc, candidates: Vec, matches: Vec, @@ -56,8 +94,9 @@ pub struct LanguageSelectorDelegate { impl LanguageSelectorDelegate { fn new( - buffer: ModelHandle, - project: ModelHandle, + language_selector: WeakView, + buffer: Model, + project: Model, language_registry: Arc, ) -> Self { let candidates = language_registry @@ -78,6 +117,7 @@ impl LanguageSelectorDelegate { matches.sort_unstable_by(|mat1, mat2| mat1.string.cmp(&mat2.string)); Self { + language_selector, buffer, project, language_registry, @@ -89,6 +129,8 @@ impl LanguageSelectorDelegate { } impl PickerDelegate for LanguageSelectorDelegate { + type ListItem = ListItem; + fn placeholder_text(&self) -> Arc { "Select a language...".into() } @@ -106,23 +148,25 @@ impl PickerDelegate for LanguageSelectorDelegate { cx.spawn(|_, mut cx| async move { let language = language.await?; let project = project - .upgrade(&cx) + .upgrade() .ok_or_else(|| anyhow!("project was dropped"))?; let buffer = buffer - .upgrade(&cx) + .upgrade() .ok_or_else(|| anyhow!("buffer was dropped"))?; project.update(&mut cx, |project, cx| { project.set_language_for_buffer(&buffer, language, cx); - }); - anyhow::Ok(()) + }) }) .detach_and_log_err(cx); } - - cx.emit(PickerEvent::Dismiss); + self.dismissed(cx); } - fn dismissed(&mut self, _cx: &mut ViewContext>) {} + fn dismissed(&mut self, cx: &mut ViewContext>) { + self.language_selector + .update(cx, |_, cx| cx.emit(DismissEvent)) + .log_err(); + } fn selected_index(&self) -> usize { self.selected_index @@ -137,7 +181,7 @@ impl PickerDelegate for LanguageSelectorDelegate { query: String, cx: &mut ViewContext>, ) -> gpui::Task<()> { - let background = cx.background().clone(); + let background = cx.background_executor().clone(); let candidates = self.candidates.clone(); cx.spawn(|this, mut cx| async move { let matches = if query.is_empty() { @@ -164,7 +208,7 @@ impl PickerDelegate for LanguageSelectorDelegate { }; this.update(&mut cx, |this, cx| { - let delegate = this.delegate_mut(); + let delegate = &mut this.delegate; delegate.matches = matches; delegate.selected_index = delegate .selected_index @@ -178,23 +222,21 @@ impl PickerDelegate for LanguageSelectorDelegate { fn render_match( &self, ix: usize, - mouse_state: &mut MouseState, selected: bool, - cx: &AppContext, - ) -> AnyElement> { - let theme = theme::current(cx); + cx: &mut ViewContext>, + ) -> Option { let mat = &self.matches[ix]; - let style = theme.picker.item.in_state(selected).style_for(mouse_state); let buffer_language_name = self.buffer.read(cx).language().map(|l| l.name()); let mut label = mat.string.clone(); if buffer_language_name.as_deref() == Some(mat.string.as_str()) { label.push_str(" (current)"); } - Label::new(label, style.label.clone()) - .with_highlights(mat.positions.clone()) - .contained() - .with_style(style.container) - .into_any() + Some( + ListItem::new(ix) + .inset(true) + .selected(selected) + .child(HighlightedLabel::new(label, mat.positions.clone())), + ) } } diff --git a/crates/workspace2/src/workspace2.rs b/crates/workspace2/src/workspace2.rs index 5dcec2cabd..11c3cbe556 100644 --- a/crates/workspace2/src/workspace2.rs +++ b/crates/workspace2/src/workspace2.rs @@ -2164,7 +2164,10 @@ impl Workspace { cx: &mut ViewContext, ) { match event { - pane::Event::AddItem { item } => item.added_to_pane(self, pane, cx), + pane::Event::AddItem { item } => { + self.handle_pane_focused(pane.clone(), cx); + item.added_to_pane(self, pane, cx); + } pane::Event::Split(direction) => { self.split_and_clone(pane, *direction, cx); } diff --git a/crates/zed2/src/main.rs b/crates/zed2/src/main.rs index 4c7e914e37..1cf3793fe1 100644 --- a/crates/zed2/src/main.rs +++ b/crates/zed2/src/main.rs @@ -216,7 +216,7 @@ fn main() { terminal_view::init(cx); // journal2::init(app_state.clone(), cx); - // language_selector::init(cx); + language_selector::init(cx); theme_selector::init(cx); // activity_indicator::init(cx); // language_tools::init(cx); diff --git a/crates/zed2/src/zed2.rs b/crates/zed2/src/zed2.rs index 63469a9132..87dabdec51 100644 --- a/crates/zed2/src/zed2.rs +++ b/crates/zed2/src/zed2.rs @@ -142,8 +142,8 @@ pub fn initialize_workspace(app_state: Arc, cx: &mut AppContext) { cx.build_view(|cx| diagnostics::items::DiagnosticIndicator::new(workspace, cx)); let activity_indicator = activity_indicator::ActivityIndicator::new(workspace, app_state.languages.clone(), cx); - let active_buffer_language = - cx.add_view(|_| language_selector::ActiveBufferLanguage::new(workspace)); + let active_buffer_language = + cx.build_view(|_| language_selector::ActiveBufferLanguage::new(workspace)); // let vim_mode_indicator = cx.add_view(|cx| vim::ModeIndicator::new(cx)); // let feedback_button = cx.add_view(|_| { // feedback::deploy_feedback_button::DeployFeedbackButton::new(workspace) @@ -155,7 +155,7 @@ pub fn initialize_workspace(app_state: Arc, cx: &mut AppContext) { // status_bar.add_right_item(feedback_button, cx); // status_bar.add_right_item(copilot, cx); - status_bar.add_right_item(active_buffer_language, cx); + status_bar.add_right_item(active_buffer_language, cx); // status_bar.add_right_item(vim_mode_indicator, cx); status_bar.add_right_item(cursor_position, cx); });