crates/assistant/src/assistant.rs 🔗
@@ -1,5 +1,6 @@
#![cfg_attr(target_os = "windows", allow(unused, dead_code))]
+mod assistant_configuration;
pub mod assistant_panel;
mod inline_assistant;
pub mod slash_command_settings;
Marshall Bowers created
This PR is a small refactoring that extracts the Assistant's
`ConfigurationView` into its own module.
Release Notes:
- N/A
crates/assistant/src/assistant.rs | 1
crates/assistant/src/assistant_configuration.rs | 197 ++++++++++++++++++
crates/assistant/src/assistant_panel.rs | 206 ------------------
3 files changed, 204 insertions(+), 200 deletions(-)
@@ -1,5 +1,6 @@
#![cfg_attr(target_os = "windows", allow(unused, dead_code))]
+mod assistant_configuration;
pub mod assistant_panel;
mod inline_assistant;
pub mod slash_command_settings;
@@ -0,0 +1,197 @@
+use std::sync::Arc;
+
+use collections::HashMap;
+use gpui::{canvas, AnyView, AppContext, EventEmitter, FocusHandle, FocusableView, Subscription};
+use language_model::{LanguageModelProvider, LanguageModelProviderId, LanguageModelRegistry};
+use ui::{prelude::*, ElevationIndex};
+use workspace::Item;
+
+pub struct ConfigurationView {
+ focus_handle: FocusHandle,
+ configuration_views: HashMap<LanguageModelProviderId, AnyView>,
+ _registry_subscription: Subscription,
+}
+
+impl ConfigurationView {
+ pub fn new(cx: &mut ViewContext<Self>) -> Self {
+ let focus_handle = cx.focus_handle();
+
+ let registry_subscription = cx.subscribe(
+ &LanguageModelRegistry::global(cx),
+ |this, _, event: &language_model::Event, cx| match event {
+ language_model::Event::AddedProvider(provider_id) => {
+ let provider = LanguageModelRegistry::read_global(cx).provider(provider_id);
+ if let Some(provider) = provider {
+ this.add_configuration_view(&provider, cx);
+ }
+ }
+ language_model::Event::RemovedProvider(provider_id) => {
+ this.remove_configuration_view(provider_id);
+ }
+ _ => {}
+ },
+ );
+
+ let mut this = Self {
+ focus_handle,
+ configuration_views: HashMap::default(),
+ _registry_subscription: registry_subscription,
+ };
+ this.build_configuration_views(cx);
+ this
+ }
+
+ fn build_configuration_views(&mut self, cx: &mut ViewContext<Self>) {
+ let providers = LanguageModelRegistry::read_global(cx).providers();
+ for provider in providers {
+ self.add_configuration_view(&provider, cx);
+ }
+ }
+
+ fn remove_configuration_view(&mut self, provider_id: &LanguageModelProviderId) {
+ self.configuration_views.remove(provider_id);
+ }
+
+ fn add_configuration_view(
+ &mut self,
+ provider: &Arc<dyn LanguageModelProvider>,
+ cx: &mut ViewContext<Self>,
+ ) {
+ let configuration_view = provider.configuration_view(cx);
+ self.configuration_views
+ .insert(provider.id(), configuration_view);
+ }
+
+ fn render_provider_view(
+ &mut self,
+ provider: &Arc<dyn LanguageModelProvider>,
+ cx: &mut ViewContext<Self>,
+ ) -> Div {
+ let provider_id = provider.id().0.clone();
+ let provider_name = provider.name().0.clone();
+ let configuration_view = self.configuration_views.get(&provider.id()).cloned();
+
+ let open_new_context = cx.listener({
+ let provider = provider.clone();
+ move |_, _, cx| {
+ cx.emit(ConfigurationViewEvent::NewProviderContextEditor(
+ provider.clone(),
+ ))
+ }
+ });
+
+ v_flex()
+ .gap_2()
+ .child(
+ h_flex()
+ .justify_between()
+ .child(Headline::new(provider_name.clone()).size(HeadlineSize::Small))
+ .when(provider.is_authenticated(cx), move |this| {
+ this.child(
+ h_flex().justify_end().child(
+ Button::new(
+ SharedString::from(format!("new-context-{provider_id}")),
+ "Open New Chat",
+ )
+ .icon_position(IconPosition::Start)
+ .icon(IconName::Plus)
+ .style(ButtonStyle::Filled)
+ .layer(ElevationIndex::ModalSurface)
+ .on_click(open_new_context),
+ ),
+ )
+ }),
+ )
+ .child(
+ div()
+ .p(DynamicSpacing::Base08.rems(cx))
+ .bg(cx.theme().colors().surface_background)
+ .border_1()
+ .border_color(cx.theme().colors().border_variant)
+ .rounded_md()
+ .when(configuration_view.is_none(), |this| {
+ this.child(div().child(Label::new(format!(
+ "No configuration view for {}",
+ provider_name
+ ))))
+ })
+ .when_some(configuration_view, |this, configuration_view| {
+ this.child(configuration_view)
+ }),
+ )
+ }
+}
+
+impl Render for ConfigurationView {
+ fn render(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement {
+ let providers = LanguageModelRegistry::read_global(cx).providers();
+ let provider_views = providers
+ .into_iter()
+ .map(|provider| self.render_provider_view(&provider, cx))
+ .collect::<Vec<_>>();
+
+ let mut element = v_flex()
+ .id("assistant-configuration-view")
+ .track_focus(&self.focus_handle(cx))
+ .bg(cx.theme().colors().editor_background)
+ .size_full()
+ .overflow_y_scroll()
+ .child(
+ v_flex()
+ .p(DynamicSpacing::Base16.rems(cx))
+ .border_b_1()
+ .border_color(cx.theme().colors().border)
+ .gap_1()
+ .child(Headline::new("Configure your Assistant").size(HeadlineSize::Medium))
+ .child(
+ Label::new(
+ "At least one LLM provider must be configured to use the Assistant.",
+ )
+ .color(Color::Muted),
+ ),
+ )
+ .child(
+ v_flex()
+ .p(DynamicSpacing::Base16.rems(cx))
+ .mt_1()
+ .gap_6()
+ .flex_1()
+ .children(provider_views),
+ )
+ .into_any();
+
+ // We use a canvas here to get scrolling to work in the ConfigurationView. It's a workaround
+ // because we couldn't the element to take up the size of the parent.
+ canvas(
+ move |bounds, cx| {
+ element.prepaint_as_root(bounds.origin, bounds.size.into(), cx);
+ element
+ },
+ |_, mut element, cx| {
+ element.paint(cx);
+ },
+ )
+ .flex_1()
+ .w_full()
+ }
+}
+
+pub enum ConfigurationViewEvent {
+ NewProviderContextEditor(Arc<dyn LanguageModelProvider>),
+}
+
+impl EventEmitter<ConfigurationViewEvent> for ConfigurationView {}
+
+impl FocusableView for ConfigurationView {
+ fn focus_handle(&self, _: &AppContext) -> FocusHandle {
+ self.focus_handle.clone()
+ }
+}
+
+impl Item for ConfigurationView {
+ type Event = ConfigurationViewEvent;
+
+ fn tab_content_text(&self, _cx: &WindowContext) -> Option<SharedString> {
+ Some("Configuration".into())
+ }
+}
@@ -1,3 +1,4 @@
+use crate::assistant_configuration::{ConfigurationView, ConfigurationViewEvent};
use crate::{
terminal_inline_assistant::TerminalInlineAssistant, DeployHistory, DeployPromptLibrary,
InlineAssistant, NewContext,
@@ -13,19 +14,15 @@ use assistant_settings::{AssistantDockPosition, AssistantSettings};
use assistant_slash_command::SlashCommandWorkingSet;
use assistant_tool::ToolWorkingSet;
use client::{proto, Client, Status};
-use collections::HashMap;
use editor::{Editor, EditorEvent};
use fs::Fs;
use gpui::{
- canvas, div, prelude::*, Action, AnyView, AppContext, AsyncWindowContext, EventEmitter,
- ExternalPaths, FocusHandle, FocusableView, InteractiveElement, IntoElement, Model,
- ParentElement, Pixels, Render, SharedString, StatefulInteractiveElement, Styled, Subscription,
- Task, UpdateGlobal, View, WeakView,
+ prelude::*, Action, AppContext, AsyncWindowContext, EventEmitter, ExternalPaths, FocusHandle,
+ FocusableView, InteractiveElement, IntoElement, Model, ParentElement, Pixels, Render, Styled,
+ Subscription, Task, UpdateGlobal, View, WeakView,
};
use language::LanguageRegistry;
-use language_model::{
- LanguageModelProvider, LanguageModelProviderId, LanguageModelRegistry, ZED_CLOUD_PROVIDER_ID,
-};
+use language_model::{LanguageModelProviderId, LanguageModelRegistry, ZED_CLOUD_PROVIDER_ID};
use language_model_selector::LanguageModelSelector;
use project::Project;
use prompt_library::{open_prompt_library, PromptBuilder, PromptLibrary};
@@ -34,12 +31,11 @@ use settings::{update_settings_file, Settings};
use smol::stream::StreamExt;
use std::{ops::ControlFlow, path::PathBuf, sync::Arc};
use terminal_view::{terminal_panel::TerminalPanel, TerminalView};
-use ui::{prelude::*, ContextMenu, ElevationIndex, PopoverMenu, PopoverMenuHandle, Tooltip};
+use ui::{prelude::*, ContextMenu, PopoverMenu, PopoverMenuHandle, Tooltip};
use util::{maybe, ResultExt};
use workspace::DraggedTab;
use workspace::{
dock::{DockPosition, Panel, PanelEvent},
- item::Item,
pane, DraggedSelection, Pane, ShowConfiguration, ToggleZoom, Workspace,
};
use zed_actions::assistant::{InlineAssist, ToggleFocus};
@@ -1371,193 +1367,3 @@ pub enum WorkflowAssistStatus {
Done,
Idle,
}
-
-pub struct ConfigurationView {
- focus_handle: FocusHandle,
- configuration_views: HashMap<LanguageModelProviderId, AnyView>,
- _registry_subscription: Subscription,
-}
-
-impl ConfigurationView {
- fn new(cx: &mut ViewContext<Self>) -> Self {
- let focus_handle = cx.focus_handle();
-
- let registry_subscription = cx.subscribe(
- &LanguageModelRegistry::global(cx),
- |this, _, event: &language_model::Event, cx| match event {
- language_model::Event::AddedProvider(provider_id) => {
- let provider = LanguageModelRegistry::read_global(cx).provider(provider_id);
- if let Some(provider) = provider {
- this.add_configuration_view(&provider, cx);
- }
- }
- language_model::Event::RemovedProvider(provider_id) => {
- this.remove_configuration_view(provider_id);
- }
- _ => {}
- },
- );
-
- let mut this = Self {
- focus_handle,
- configuration_views: HashMap::default(),
- _registry_subscription: registry_subscription,
- };
- this.build_configuration_views(cx);
- this
- }
-
- fn build_configuration_views(&mut self, cx: &mut ViewContext<Self>) {
- let providers = LanguageModelRegistry::read_global(cx).providers();
- for provider in providers {
- self.add_configuration_view(&provider, cx);
- }
- }
-
- fn remove_configuration_view(&mut self, provider_id: &LanguageModelProviderId) {
- self.configuration_views.remove(provider_id);
- }
-
- fn add_configuration_view(
- &mut self,
- provider: &Arc<dyn LanguageModelProvider>,
- cx: &mut ViewContext<Self>,
- ) {
- let configuration_view = provider.configuration_view(cx);
- self.configuration_views
- .insert(provider.id(), configuration_view);
- }
-
- fn render_provider_view(
- &mut self,
- provider: &Arc<dyn LanguageModelProvider>,
- cx: &mut ViewContext<Self>,
- ) -> Div {
- let provider_id = provider.id().0.clone();
- let provider_name = provider.name().0.clone();
- let configuration_view = self.configuration_views.get(&provider.id()).cloned();
-
- let open_new_context = cx.listener({
- let provider = provider.clone();
- move |_, _, cx| {
- cx.emit(ConfigurationViewEvent::NewProviderContextEditor(
- provider.clone(),
- ))
- }
- });
-
- v_flex()
- .gap_2()
- .child(
- h_flex()
- .justify_between()
- .child(Headline::new(provider_name.clone()).size(HeadlineSize::Small))
- .when(provider.is_authenticated(cx), move |this| {
- this.child(
- h_flex().justify_end().child(
- Button::new(
- SharedString::from(format!("new-context-{provider_id}")),
- "Open New Chat",
- )
- .icon_position(IconPosition::Start)
- .icon(IconName::Plus)
- .style(ButtonStyle::Filled)
- .layer(ElevationIndex::ModalSurface)
- .on_click(open_new_context),
- ),
- )
- }),
- )
- .child(
- div()
- .p(DynamicSpacing::Base08.rems(cx))
- .bg(cx.theme().colors().surface_background)
- .border_1()
- .border_color(cx.theme().colors().border_variant)
- .rounded_md()
- .when(configuration_view.is_none(), |this| {
- this.child(div().child(Label::new(format!(
- "No configuration view for {}",
- provider_name
- ))))
- })
- .when_some(configuration_view, |this, configuration_view| {
- this.child(configuration_view)
- }),
- )
- }
-}
-
-impl Render for ConfigurationView {
- fn render(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement {
- let providers = LanguageModelRegistry::read_global(cx).providers();
- let provider_views = providers
- .into_iter()
- .map(|provider| self.render_provider_view(&provider, cx))
- .collect::<Vec<_>>();
-
- let mut element = v_flex()
- .id("assistant-configuration-view")
- .track_focus(&self.focus_handle(cx))
- .bg(cx.theme().colors().editor_background)
- .size_full()
- .overflow_y_scroll()
- .child(
- v_flex()
- .p(DynamicSpacing::Base16.rems(cx))
- .border_b_1()
- .border_color(cx.theme().colors().border)
- .gap_1()
- .child(Headline::new("Configure your Assistant").size(HeadlineSize::Medium))
- .child(
- Label::new(
- "At least one LLM provider must be configured to use the Assistant.",
- )
- .color(Color::Muted),
- ),
- )
- .child(
- v_flex()
- .p(DynamicSpacing::Base16.rems(cx))
- .mt_1()
- .gap_6()
- .flex_1()
- .children(provider_views),
- )
- .into_any();
-
- // We use a canvas here to get scrolling to work in the ConfigurationView. It's a workaround
- // because we couldn't the element to take up the size of the parent.
- canvas(
- move |bounds, cx| {
- element.prepaint_as_root(bounds.origin, bounds.size.into(), cx);
- element
- },
- |_, mut element, cx| {
- element.paint(cx);
- },
- )
- .flex_1()
- .w_full()
- }
-}
-
-pub enum ConfigurationViewEvent {
- NewProviderContextEditor(Arc<dyn LanguageModelProvider>),
-}
-
-impl EventEmitter<ConfigurationViewEvent> for ConfigurationView {}
-
-impl FocusableView for ConfigurationView {
- fn focus_handle(&self, _: &AppContext) -> FocusHandle {
- self.focus_handle.clone()
- }
-}
-
-impl Item for ConfigurationView {
- type Event = ConfigurationViewEvent;
-
- fn tab_content_text(&self, _cx: &WindowContext) -> Option<SharedString> {
- Some("Configuration".into())
- }
-}