Language Selector 2 working!

This commit is contained in:
Conrad Irwin 2023-12-01 08:41:49 -07:00
parent 2de6758443
commit 6a5b5f022d
8 changed files with 131 additions and 98 deletions

1
Cargo.lock generated
View file

@ -4804,6 +4804,7 @@ dependencies = [
"project2",
"settings2",
"theme2",
"ui2",
"util",
"workspace2",
]

View file

@ -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<Buffer>, Range<text::Anchor>)> {
// self.buffer
// .read(cx)
// .excerpt_containing(self.selections.newest_anchor().head(), cx)
// }
pub fn active_excerpt(
&self,
cx: &AppContext,
) -> Option<(ExcerptId, Model<Buffer>, Range<text::Anchor>)> {
self.buffer
.read(cx)
.excerpt_containing(self.selections.newest_anchor().head(), cx)
}
// pub fn style(&self, cx: &AppContext) -> EditorStyle {
// build_style(

View file

@ -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" }

View file

@ -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<Option<Arc<str>>>,
workspace: WeakViewHandle<Workspace>,
workspace: WeakView<Workspace>,
_observe_active_editor: Option<Subscription>,
}
@ -22,7 +23,7 @@ impl ActiveBufferLanguage {
}
}
fn update_language(&mut self, editor: ViewHandle<Editor>, cx: &mut ViewContext<Self>) {
fn update_language(&mut self, editor: View<Editor>, cx: &mut ViewContext<Self>) {
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<Self>) -> AnyElement<Self> {
if let Some(active_language) = self.active_language.as_ref() {
fn render(&mut self, cx: &mut ViewContext<Self>) -> 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::<Self, _>(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::<Self>(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)),
)
})
}
}

View file

@ -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::<LanguageSelectorDelegate>::init(cx);
cx.add_action(toggle);
pub struct LanguageSelector {
picker: View<Picker<LanguageSelectorDelegate>>,
}
pub fn toggle(
workspace: &mut Workspace,
_: &Toggle,
cx: &mut ViewContext<Workspace>,
) -> Option<()> {
let (_, buffer, _) = workspace
.active_item(cx)?
.act_as::<Editor>(cx)?
.read(cx)
.active_excerpt(cx)?;
workspace.toggle_modal(cx, |workspace, cx| {
impl LanguageSelector {
fn register(workspace: &mut Workspace, cx: &mut ViewContext<Workspace>) {
dbg!("regsiter");
workspace.register_action(move |workspace, _: &Toggle, cx| {
Self::toggle(workspace, cx);
});
}
fn toggle(workspace: &mut Workspace, cx: &mut ViewContext<Workspace>) -> 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::<Editor>(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<Buffer>,
project: Model<Project>,
language_registry: Arc<LanguageRegistry>,
cx: &mut ViewContext<Self>,
) -> 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>) -> 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<DismissEvent> for LanguageSelector {}
pub struct LanguageSelectorDelegate {
buffer: ModelHandle<Buffer>,
project: ModelHandle<Project>,
language_selector: WeakView<LanguageSelector>,
buffer: Model<Buffer>,
project: Model<Project>,
language_registry: Arc<LanguageRegistry>,
candidates: Vec<StringMatchCandidate>,
matches: Vec<StringMatch>,
@ -56,8 +94,9 @@ pub struct LanguageSelectorDelegate {
impl LanguageSelectorDelegate {
fn new(
buffer: ModelHandle<Buffer>,
project: ModelHandle<Project>,
language_selector: WeakView<LanguageSelector>,
buffer: Model<Buffer>,
project: Model<Project>,
language_registry: Arc<LanguageRegistry>,
) -> 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<str> {
"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<Picker<Self>>) {}
fn dismissed(&mut self, cx: &mut ViewContext<Picker<Self>>) {
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<Picker<Self>>,
) -> 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<Picker<Self>> {
let theme = theme::current(cx);
cx: &mut ViewContext<Picker<Self>>,
) -> Option<Self::ListItem> {
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())),
)
}
}

View file

@ -2164,7 +2164,10 @@ impl Workspace {
cx: &mut ViewContext<Self>,
) {
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);
}

View file

@ -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);

View file

@ -142,8 +142,8 @@ pub fn initialize_workspace(app_state: Arc<AppState>, 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<AppState>, 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);
});