Compare commits

..

2 Commits

Author SHA1 Message Date
Oleksiy Syvokon
95f4f12384 Recommended replacement for gemini-1.5-flash is 2.0-flash-lite 2025-05-06 18:58:59 +03:00
Oleksiy Syvokon
101399fb66 models: Remove deprecated models 2025-05-06 18:46:59 +03:00
105 changed files with 996 additions and 1704 deletions

View File

@@ -162,23 +162,13 @@ jobs:
working-directory: ./docs
run: |
pnpm dlx prettier@${PRETTIER_VERSION} . --check || {
echo "To fix, run from the root of the Zed repo:"
echo "To fix, run from the root of the zed repo:"
echo " cd docs && pnpm dlx prettier@${PRETTIER_VERSION} . --write && cd .."
false
}
env:
PRETTIER_VERSION: 3.5.0
- name: Prettier Check on default.json
run: |
pnpm dlx prettier@${PRETTIER_VERSION} assets/settings/default.json --check || {
echo "To fix, run from the root of the Zed repo:"
echo " pnpm dlx prettier@${PRETTIER_VERSION} assets/settings/default.json --write"
false
}
env:
PRETTIER_VERSION: 3.5.0
# To support writing comments that they will certainly be revisited.
- name: Check for todo! and FIXME comments
run: script/check-todos

View File

@@ -1,3 +0,0 @@
{
"printWidth": 120
}

64
Cargo.lock generated
View File

@@ -52,9 +52,9 @@ dependencies = [
name = "agent"
version = "0.1.0"
dependencies = [
"agent_settings",
"anyhow",
"assistant_context_editor",
"assistant_settings",
"assistant_slash_command",
"assistant_tool",
"async-watch",
@@ -134,31 +134,6 @@ dependencies = [
"zed_llm_client",
]
[[package]]
name = "agent_settings"
version = "0.1.0"
dependencies = [
"anthropic",
"anyhow",
"deepseek",
"feature_flags",
"fs",
"gpui",
"indexmap",
"language_model",
"lmstudio",
"log",
"ollama",
"open_ai",
"paths",
"schemars",
"serde",
"serde_json",
"serde_json_lenient",
"settings",
"workspace-hack",
]
[[package]]
name = "ahash"
version = "0.7.8"
@@ -500,9 +475,9 @@ dependencies = [
name = "assistant"
version = "0.1.0"
dependencies = [
"agent_settings",
"anyhow",
"assistant_context_editor",
"assistant_settings",
"assistant_slash_command",
"assistant_slash_commands",
"assistant_tool",
@@ -562,8 +537,8 @@ dependencies = [
name = "assistant_context_editor"
version = "0.1.0"
dependencies = [
"agent_settings",
"anyhow",
"assistant_settings",
"assistant_slash_command",
"assistant_slash_commands",
"chrono",
@@ -614,6 +589,30 @@ dependencies = [
"zed_actions",
]
[[package]]
name = "assistant_settings"
version = "0.1.0"
dependencies = [
"anthropic",
"anyhow",
"deepseek",
"feature_flags",
"fs",
"gpui",
"indexmap",
"language_model",
"lmstudio",
"log",
"ollama",
"open_ai",
"paths",
"schemars",
"serde",
"serde_json_lenient",
"settings",
"workspace-hack",
]
[[package]]
name = "assistant_slash_command"
version = "0.1.0"
@@ -711,9 +710,9 @@ dependencies = [
name = "assistant_tools"
version = "0.1.0"
dependencies = [
"agent_settings",
"aho-corasick",
"anyhow",
"assistant_settings",
"assistant_tool",
"buffer_diff",
"chrono",
@@ -5004,8 +5003,8 @@ name = "eval"
version = "0.1.0"
dependencies = [
"agent",
"agent_settings",
"anyhow",
"assistant_settings",
"assistant_tool",
"assistant_tools",
"async-trait",
@@ -6064,9 +6063,9 @@ dependencies = [
name = "git_ui"
version = "0.1.0"
dependencies = [
"agent_settings",
"anyhow",
"askpass",
"assistant_settings",
"buffer_diff",
"chrono",
"collections",
@@ -18158,7 +18157,6 @@ dependencies = [
"itertools 0.14.0",
"language",
"log",
"menu",
"node_runtime",
"parking_lot",
"postage",
@@ -18698,13 +18696,13 @@ version = "0.186.0"
dependencies = [
"activity_indicator",
"agent",
"agent_settings",
"anyhow",
"ashpd",
"askpass",
"assets",
"assistant",
"assistant_context_editor",
"assistant_settings",
"assistant_tools",
"async-watch",
"audio",

View File

@@ -3,12 +3,12 @@ resolver = "2"
members = [
"crates/activity_indicator",
"crates/agent",
"crates/agent_settings",
"crates/anthropic",
"crates/askpass",
"crates/assets",
"crates/assistant",
"crates/assistant_context_editor",
"crates/assistant_settings",
"crates/assistant_slash_command",
"crates/assistant_slash_commands",
"crates/assistant_tool",
@@ -216,7 +216,7 @@ askpass = { path = "crates/askpass" }
assets = { path = "crates/assets" }
assistant = { path = "crates/assistant" }
assistant_context_editor = { path = "crates/assistant_context_editor" }
agent_settings = { path = "crates/agent_settings" }
assistant_settings = { path = "crates/assistant_settings" }
assistant_slash_command = { path = "crates/assistant_slash_command" }
assistant_slash_commands = { path = "crates/assistant_slash_commands" }
assistant_tool = { path = "crates/assistant_tool" }

View File

@@ -309,12 +309,8 @@
},
// Titlebar related settings
"title_bar": {
// Whether to show the branch icon beside branch switcher in the titlebar.
"show_branch_icon": false,
// Whether to show onboarding banners in the titlebar.
"show_onboarding_banner": true,
// Whether to show user picture in the titlebar.
"show_user_picture": true
// Whether to show the branch icon beside branch switcher in the title bar.
"show_branch_icon": false
},
// Scrollbar related settings
"scrollbar": {
@@ -912,8 +908,6 @@
"hard_tabs": false,
// How many columns a tab should occupy.
"tab_size": 4,
// What debuggers are preferred by default for all languages.
"debuggers": [],
// Control what info is collected by Zed.
"telemetry": {
// Send debug info like crash reports.
@@ -1610,6 +1604,8 @@
// "W": "workspace::Save"
// }
"command_aliases": {},
// Whether to show user picture in titlebar.
"show_user_picture": true,
// ssh_connections is an array of ssh connections.
// You can configure these from `project: Open Remote` in the command palette.
// Zed's ssh support will pull configuration from your ~/.ssh too.

View File

@@ -21,7 +21,7 @@ test-support = [
[dependencies]
anyhow.workspace = true
assistant_context_editor.workspace = true
agent_settings.workspace = true
assistant_settings.workspace = true
assistant_slash_command.workspace = true
assistant_tool.workspace = true
async-watch.workspace = true

View File

@@ -12,8 +12,8 @@ use crate::tool_use::{PendingToolUseStatus, ToolUse};
use crate::ui::{
AddedContext, AgentNotification, AgentNotificationEvent, AnimatedLabel, ContextPill,
};
use agent_settings::{AgentSettings, NotifyWhenAgentWaiting};
use anyhow::Context as _;
use assistant_settings::{AssistantSettings, NotifyWhenAgentWaiting};
use assistant_tool::ToolUseStatus;
use collections::{HashMap, HashSet};
use editor::actions::{MoveUp, Paste};
@@ -1145,7 +1145,7 @@ impl ActiveThread {
.summary()
.unwrap_or("Agent Panel".into());
match AgentSettings::get_global(cx).notify_when_agent_waiting {
match AssistantSettings::get_global(cx).notify_when_agent_waiting {
NotifyWhenAgentWaiting::PrimaryScreen => {
if let Some(primary) = cx.primary_display() {
self.pop_up(icon, caption.into(), title.clone(), window, primary, cx);
@@ -2082,7 +2082,7 @@ impl ActiveThread {
v_flex()
.w_full()
.map(|parent| {
if let Some(checkpoint) = checkpoint.filter(|_| !is_generating) {
if let Some(checkpoint) = checkpoint.filter(|_| is_generating) {
let mut is_pending = false;
let mut error = None;
if let Some(last_restore_checkpoint) =
@@ -3080,7 +3080,7 @@ impl ActiveThread {
.on_click(cx.listener(
move |this, event, window, cx| {
if let Some(fs) = fs.clone() {
update_settings_file::<AgentSettings>(
update_settings_file::<AssistantSettings>(
fs.clone(),
cx,
|settings, _| {
@@ -3662,7 +3662,7 @@ mod tests {
cx.set_global(settings_store);
language::init(cx);
Project::init_settings(cx);
AgentSettings::register(cx);
AssistantSettings::register(cx);
prompt_store::init(cx);
thread_store::init(cx);
workspace::init_settings(cx);

View File

@@ -1,8 +1,8 @@
use crate::{
Keep, KeepAll, OpenAgentDiff, Reject, RejectAll, Thread, ThreadEvent, ui::AnimatedLabel,
};
use agent_settings::AgentSettings;
use anyhow::Result;
use assistant_settings::AssistantSettings;
use buffer_diff::DiffHunkStatus;
use collections::{HashMap, HashSet};
use editor::{
@@ -1250,9 +1250,9 @@ impl AgentDiff {
let settings_subscription = cx.observe_global_in::<SettingsStore>(window, {
let workspace = workspace.clone();
let mut was_active = AgentSettings::get_global(cx).single_file_review;
let mut was_active = AssistantSettings::get_global(cx).single_file_review;
move |this, window, cx| {
let is_active = AgentSettings::get_global(cx).single_file_review;
let is_active = AssistantSettings::get_global(cx).single_file_review;
if was_active != is_active {
was_active = is_active;
this.update_reviewing_editors(&workspace, window, cx);
@@ -1457,7 +1457,7 @@ impl AgentDiff {
window: &mut Window,
cx: &mut Context<Self>,
) {
if !AgentSettings::get_global(cx).single_file_review {
if !AssistantSettings::get_global(cx).single_file_review {
for (editor, _) in self.reviewing_editors.drain() {
editor
.update(cx, |editor, cx| editor.end_temporary_diff_override(cx))
@@ -1732,7 +1732,7 @@ impl editor::Addon for EditorAgentDiffAddon {
mod tests {
use super::*;
use crate::{Keep, ThreadStore, thread_store};
use agent_settings::AgentSettings;
use assistant_settings::AssistantSettings;
use assistant_tool::ToolWorkingSet;
use editor::EditorSettings;
use gpui::{TestAppContext, UpdateGlobal, VisualTestContext};
@@ -1751,7 +1751,7 @@ mod tests {
cx.set_global(settings_store);
language::init(cx);
Project::init_settings(cx);
AgentSettings::register(cx);
AssistantSettings::register(cx);
prompt_store::init(cx);
thread_store::init(cx);
workspace::init_settings(cx);
@@ -1907,7 +1907,7 @@ mod tests {
cx.set_global(settings_store);
language::init(cx);
Project::init_settings(cx);
AgentSettings::register(cx);
AssistantSettings::register(cx);
prompt_store::init(cx);
thread_store::init(cx);
workspace::init_settings(cx);

View File

@@ -27,7 +27,7 @@ mod ui;
use std::sync::Arc;
use agent_settings::{AgentProfileId, AgentSettings};
use assistant_settings::{AgentProfileId, AssistantSettings};
use client::Client;
use command_palette_hooks::CommandPaletteFilter;
use feature_flags::{Assistant2FeatureFlag, FeatureFlagAppExt};
@@ -117,7 +117,7 @@ pub fn init(
language_registry: Arc<LanguageRegistry>,
cx: &mut App,
) {
AgentSettings::register(cx);
AssistantSettings::register(cx);
thread_store::init(cx);
assistant_panel::init(cx);
context_server_configuration::init(language_registry, cx);

View File

@@ -5,7 +5,7 @@ mod tool_picker;
use std::{sync::Arc, time::Duration};
use agent_settings::AgentSettings;
use assistant_settings::AssistantSettings;
use assistant_tool::{ToolSource, ToolWorkingSet};
use collections::HashMap;
use context_server::ContextServerId;
@@ -213,7 +213,7 @@ impl AssistantConfiguration {
}
fn render_command_permission(&mut self, cx: &mut Context<Self>) -> impl IntoElement {
let always_allow_tool_actions = AgentSettings::get_global(cx).always_allow_tool_actions;
let always_allow_tool_actions = AssistantSettings::get_global(cx).always_allow_tool_actions;
h_flex()
.gap_4()
@@ -241,7 +241,7 @@ impl AssistantConfiguration {
let fs = self.fs.clone();
move |state, _window, cx| {
let allow = state == &ToggleState::Selected;
update_settings_file::<AgentSettings>(
update_settings_file::<AssistantSettings>(
fs.clone(),
cx,
move |settings, _| {
@@ -254,7 +254,7 @@ impl AssistantConfiguration {
}
fn render_single_file_review(&mut self, cx: &mut Context<Self>) -> impl IntoElement {
let single_file_review = AgentSettings::get_global(cx).single_file_review;
let single_file_review = AssistantSettings::get_global(cx).single_file_review;
h_flex()
.gap_4()
@@ -279,7 +279,7 @@ impl AssistantConfiguration {
let fs = self.fs.clone();
move |state, _window, cx| {
let allow = state == &ToggleState::Selected;
update_settings_file::<AgentSettings>(
update_settings_file::<AssistantSettings>(
fs.clone(),
cx,
move |settings, _| {

View File

@@ -147,50 +147,47 @@ impl Render for AddContextServerModal {
),
)
.footer(
ModalFooter::new().end_slot(
h_flex()
.gap_2()
.child(
Button::new("cancel", "Cancel")
.key_binding(
KeyBinding::for_action_in(
&menu::Cancel,
&focus_handle,
window,
cx,
)
.map(|kb| kb.size(rems_from_px(12.))),
ModalFooter::new()
.start_slot(
Button::new("cancel", "Cancel")
.key_binding(
KeyBinding::for_action_in(
&menu::Cancel,
&focus_handle,
window,
cx,
)
.on_click(cx.listener(|this, _event, _window, cx| {
this.cancel(&menu::Cancel, cx)
})),
)
.child(
Button::new("add-server", "Add Server")
.disabled(is_name_empty || is_command_empty)
.key_binding(
KeyBinding::for_action_in(
&menu::Confirm,
&focus_handle,
window,
cx,
)
.map(|kb| kb.size(rems_from_px(12.))),
.map(|kb| kb.size(rems_from_px(12.))),
)
.on_click(cx.listener(|this, _event, _window, cx| {
this.cancel(&menu::Cancel, cx)
})),
)
.end_slot(
Button::new("add-server", "Add Server")
.disabled(is_name_empty || is_command_empty)
.key_binding(
KeyBinding::for_action_in(
&menu::Confirm,
&focus_handle,
window,
cx,
)
.map(|button| {
if is_name_empty {
button.tooltip(Tooltip::text("Name is required"))
} else if is_command_empty {
button.tooltip(Tooltip::text("Command is required"))
} else {
button
}
})
.on_click(cx.listener(|this, _event, _window, cx| {
this.confirm(&menu::Confirm, cx)
})),
),
),
.map(|kb| kb.size(rems_from_px(12.))),
)
.map(|button| {
if is_name_empty {
button.tooltip(Tooltip::text("Name is required"))
} else if is_command_empty {
button.tooltip(Tooltip::text("Command is required"))
} else {
button
}
})
.on_click(cx.listener(|this, _event, _window, cx| {
this.confirm(&menu::Confirm, cx)
})),
),
),
)
}

View File

@@ -19,24 +19,18 @@ use project::{
};
use settings::{Settings as _, update_settings_file};
use theme::ThemeSettings;
use ui::{KeyBinding, Modal, ModalFooter, ModalHeader, Section, Tooltip, prelude::*};
use ui::{KeyBinding, Modal, ModalFooter, ModalHeader, Section, prelude::*};
use util::ResultExt;
use workspace::{ModalView, Workspace};
pub(crate) struct ConfigureContextServerModal {
workspace: WeakEntity<Workspace>,
focus_handle: FocusHandle,
context_servers_to_setup: Vec<ContextServerSetup>,
context_servers_to_setup: Vec<ConfigureContextServer>,
context_server_store: Entity<ContextServerStore>,
}
#[allow(clippy::large_enum_variant)]
enum Configuration {
NotAvailable,
Required(ConfigurationRequiredState),
}
struct ConfigurationRequiredState {
struct ConfigureContextServer {
id: ContextServerId,
installation_instructions: Entity<markdown::Markdown>,
settings_validator: Option<jsonschema::Validator>,
settings_editor: Entity<Editor>,
@@ -44,91 +38,64 @@ struct ConfigurationRequiredState {
waiting_for_context_server: bool,
}
struct ContextServerSetup {
id: ContextServerId,
repository_url: Option<SharedString>,
configuration: Configuration,
}
impl ConfigureContextServerModal {
pub fn new(
configurations: impl Iterator<Item = crate::context_server_configuration::Configuration>,
configurations: impl Iterator<Item = (ContextServerId, extension::ContextServerConfiguration)>,
context_server_store: Entity<ContextServerStore>,
jsonc_language: Option<Arc<Language>>,
language_registry: Arc<LanguageRegistry>,
workspace: WeakEntity<Workspace>,
window: &mut Window,
cx: &mut Context<Self>,
) -> Self {
cx: &mut App,
) -> Option<Self> {
let context_servers_to_setup = configurations
.map(|config| match config {
crate::context_server_configuration::Configuration::NotAvailable(
context_server_id,
repository_url,
) => ContextServerSetup {
id: context_server_id,
repository_url,
configuration: Configuration::NotAvailable,
},
crate::context_server_configuration::Configuration::Required(
context_server_id,
repository_url,
config,
) => {
let jsonc_language = jsonc_language.clone();
let settings_validator = jsonschema::validator_for(&config.settings_schema)
.context("Failed to load JSON schema for context server settings")
.log_err();
let state = ConfigurationRequiredState {
installation_instructions: cx.new(|cx| {
Markdown::new(
config.installation_instructions.clone().into(),
Some(language_registry.clone()),
None,
cx,
)
}),
settings_validator,
settings_editor: cx.new(|cx| {
let mut editor = Editor::auto_height(16, window, cx);
editor.set_text(config.default_settings.trim(), window, cx);
editor.set_show_gutter(false, cx);
editor.set_soft_wrap_mode(
language::language_settings::SoftWrap::None,
cx,
);
if let Some(buffer) = editor.buffer().read(cx).as_singleton() {
buffer.update(cx, |buffer, cx| {
buffer.set_language(jsonc_language, cx)
})
}
editor
}),
waiting_for_context_server: false,
last_error: None,
};
ContextServerSetup {
id: context_server_id,
repository_url,
configuration: Configuration::Required(state),
}
.map(|(id, manifest)| {
let jsonc_language = jsonc_language.clone();
let settings_validator = jsonschema::validator_for(&manifest.settings_schema)
.context("Failed to load JSON schema for context server settings")
.log_err();
ConfigureContextServer {
id: id.clone(),
installation_instructions: cx.new(|cx| {
Markdown::new(
manifest.installation_instructions.clone().into(),
Some(language_registry.clone()),
None,
cx,
)
}),
settings_validator,
settings_editor: cx.new(|cx| {
let mut editor = Editor::auto_height(16, window, cx);
editor.set_text(manifest.default_settings.trim(), window, cx);
editor.set_show_gutter(false, cx);
editor.set_soft_wrap_mode(language::language_settings::SoftWrap::None, cx);
if let Some(buffer) = editor.buffer().read(cx).as_singleton() {
buffer.update(cx, |buffer, cx| buffer.set_language(jsonc_language, cx))
}
editor
}),
waiting_for_context_server: false,
last_error: None,
}
})
.collect::<Vec<_>>();
Self {
if context_servers_to_setup.is_empty() {
return None;
}
Some(Self {
workspace,
focus_handle: cx.focus_handle(),
context_servers_to_setup,
context_server_store,
}
})
}
}
impl ConfigureContextServerModal {
pub fn confirm(&mut self, cx: &mut Context<Self>) {
if self.context_servers_to_setup.is_empty() {
self.dismiss(cx);
return;
}
@@ -136,18 +103,7 @@ impl ConfigureContextServerModal {
return;
};
let id = self.context_servers_to_setup[0].id.clone();
let configuration = match &mut self.context_servers_to_setup[0].configuration {
Configuration::NotAvailable => {
self.context_servers_to_setup.remove(0);
if self.context_servers_to_setup.is_empty() {
self.dismiss(cx);
}
return;
}
Configuration::Required(state) => state,
};
let configuration = &mut self.context_servers_to_setup[0];
configuration.last_error.take();
if configuration.waiting_for_context_server {
return;
@@ -171,7 +127,7 @@ impl ConfigureContextServerModal {
return;
}
}
let id = id.clone();
let id = configuration.id.clone();
let settings_changed = ProjectSettings::get_global(cx)
.context_servers
@@ -200,14 +156,9 @@ impl ConfigureContextServerModal {
this.complete_setup(id, cx);
}
Err(err) => {
if let Some(setup) = this.context_servers_to_setup.get_mut(0) {
match &mut setup.configuration {
Configuration::NotAvailable => {}
Configuration::Required(state) => {
state.last_error = Some(err.into());
state.waiting_for_context_server = false;
}
}
if let Some(configuration) = this.context_servers_to_setup.get_mut(0) {
configuration.last_error = Some(err.into());
configuration.waiting_for_context_server = false;
} else {
this.dismiss(cx);
}
@@ -316,8 +267,8 @@ fn wait_for_context_server(
impl Render for ConfigureContextServerModal {
fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
let Some(setup) = self.context_servers_to_setup.first() else {
return div().into_any_element();
let Some(configuration) = self.context_servers_to_setup.first() else {
return div().child("No context servers to setup");
};
let focus_handle = self.focus_handle(cx);
@@ -326,7 +277,6 @@ impl Render for ConfigureContextServerModal {
.elevation_3(cx)
.w(rems(42.))
.key_context("ConfigureContextServerModal")
.track_focus(&focus_handle)
.on_action(cx.listener(|this, _: &menu::Confirm, _window, cx| this.confirm(cx)))
.on_action(cx.listener(|this, _: &menu::Cancel, _window, cx| this.dismiss(cx)))
.capture_any_mouse_down(cx.listener(|this, _, window, cx| {
@@ -334,15 +284,9 @@ impl Render for ConfigureContextServerModal {
}))
.child(
Modal::new("configure-context-server", None)
.header(ModalHeader::new().headline(format!("Configure {}", setup.id)))
.section(match &setup.configuration {
Configuration::NotAvailable => Section::new().child(
Label::new(
"No configuration options available for this context server. Visit the Repository for any further instructions.",
)
.color(Color::Muted),
),
Configuration::Required(configuration) => Section::new()
.header(ModalHeader::new().headline(format!("Configure {}", configuration.id)))
.section(
Section::new()
.child(div().pb_2().text_sm().child(MarkdownElement::new(
configuration.installation_instructions.clone(),
default_markdown_style(window, cx),
@@ -426,84 +370,45 @@ impl Render for ConfigureContextServerModal {
),
)
}),
})
)
.footer(
ModalFooter::new()
.when_some(setup.repository_url.clone(), |this, repository_url| {
this.start_slot(
h_flex().w_full().child(
Button::new("open-repository", "Open Repository")
.icon(IconName::ArrowUpRight)
.icon_color(Color::Muted)
.icon_size(IconSize::XSmall)
.tooltip({
let repository_url = repository_url.clone();
move |window, cx| {
Tooltip::with_meta(
"Open Repository",
None,
repository_url.clone(),
window,
cx,
)
}
})
.on_click(move |_, _, cx| cx.open_url(&repository_url)),
),
)
})
.end_slot(match &setup.configuration {
Configuration::NotAvailable => Button::new("dismiss", "Dismiss")
.key_binding(
KeyBinding::for_action_in(
&menu::Cancel,
&focus_handle,
window,
cx,
ModalFooter::new().end_slot(
h_flex()
.gap_1()
.child(
Button::new("cancel", "Cancel")
.key_binding(
KeyBinding::for_action_in(
&menu::Cancel,
&focus_handle,
window,
cx,
)
.map(|kb| kb.size(rems_from_px(12.))),
)
.map(|kb| kb.size(rems_from_px(12.))),
)
.on_click(
cx.listener(|this, _event, _window, cx| this.dismiss(cx)),
)
.into_any_element(),
Configuration::Required(state) => h_flex()
.gap_2()
.child(
Button::new("cancel", "Cancel")
.key_binding(
KeyBinding::for_action_in(
&menu::Cancel,
&focus_handle,
window,
cx,
)
.map(|kb| kb.size(rems_from_px(12.))),
.on_click(cx.listener(|this, _event, _window, cx| {
this.dismiss(cx)
})),
)
.child(
Button::new("configure-server", "Configure MCP")
.disabled(configuration.waiting_for_context_server)
.key_binding(
KeyBinding::for_action_in(
&menu::Confirm,
&focus_handle,
window,
cx,
)
.on_click(cx.listener(|this, _event, _window, cx| {
this.dismiss(cx)
})),
)
.child(
Button::new("configure-server", "Configure MCP")
.disabled(state.waiting_for_context_server)
.key_binding(
KeyBinding::for_action_in(
&menu::Confirm,
&focus_handle,
window,
cx,
)
.map(|kb| kb.size(rems_from_px(12.))),
)
.on_click(cx.listener(|this, _event, _window, cx| {
this.confirm(cx)
})),
)
.into_any_element(),
}),
.map(|kb| kb.size(rems_from_px(12.))),
)
.on_click(cx.listener(|this, _event, _window, cx| {
this.confirm(cx)
})),
),
),
),
).into_any_element()
)
}
}
@@ -541,14 +446,9 @@ impl EventEmitter<DismissEvent> for ConfigureContextServerModal {}
impl Focusable for ConfigureContextServerModal {
fn focus_handle(&self, cx: &App) -> FocusHandle {
if let Some(current) = self.context_servers_to_setup.first() {
match &current.configuration {
Configuration::NotAvailable => self.focus_handle.clone(),
Configuration::Required(configuration) => {
configuration.settings_editor.read(cx).focus_handle(cx)
}
}
current.settings_editor.read(cx).focus_handle(cx)
} else {
self.focus_handle.clone()
cx.focus_handle()
}
}
}

View File

@@ -2,7 +2,7 @@ mod profile_modal_header;
use std::sync::Arc;
use agent_settings::{AgentProfile, AgentProfileId, AgentSettings, builtin_profiles};
use assistant_settings::{AgentProfile, AgentProfileId, AssistantSettings, builtin_profiles};
use assistant_tool::ToolWorkingSet;
use convert_case::{Case, Casing as _};
use editor::Editor;
@@ -42,7 +42,7 @@ enum Mode {
impl Mode {
pub fn choose_profile(_window: &mut Window, cx: &mut Context<ManageProfilesModal>) -> Self {
let settings = AgentSettings::get_global(cx);
let settings = AssistantSettings::get_global(cx);
let mut builtin_profiles = Vec::new();
let mut custom_profiles = Vec::new();
@@ -196,7 +196,7 @@ impl ManageProfilesModal {
window: &mut Window,
cx: &mut Context<Self>,
) {
let settings = AgentSettings::get_global(cx);
let settings = AssistantSettings::get_global(cx);
let Some(profile) = settings.profiles.get(&profile_id).cloned() else {
return;
};
@@ -234,7 +234,7 @@ impl ManageProfilesModal {
window: &mut Window,
cx: &mut Context<Self>,
) {
let settings = AgentSettings::get_global(cx);
let settings = AssistantSettings::get_global(cx);
let Some(profile) = settings.profiles.get(&profile_id).cloned() else {
return;
};
@@ -270,7 +270,7 @@ impl ManageProfilesModal {
match &self.mode {
Mode::ChooseProfile { .. } => {}
Mode::NewProfile(mode) => {
let settings = AgentSettings::get_global(cx);
let settings = AssistantSettings::get_global(cx);
let base_profile = mode
.base_profile_id
@@ -332,7 +332,7 @@ impl ManageProfilesModal {
profile: AgentProfile,
cx: &mut Context<Self>,
) {
update_settings_file::<AgentSettings>(self.fs.clone(), cx, {
update_settings_file::<AssistantSettings>(self.fs.clone(), cx, {
move |settings, _cx| {
settings.create_profile(profile_id, profile).log_err();
}
@@ -485,7 +485,7 @@ impl ManageProfilesModal {
_window: &mut Window,
cx: &mut Context<Self>,
) -> impl IntoElement {
let settings = AgentSettings::get_global(cx);
let settings = AssistantSettings::get_global(cx);
let base_profile_name = mode.base_profile_id.as_ref().map(|base_profile_id| {
settings
@@ -518,7 +518,7 @@ impl ManageProfilesModal {
window: &mut Window,
cx: &mut Context<Self>,
) -> impl IntoElement {
let settings = AgentSettings::get_global(cx);
let settings = AssistantSettings::get_global(cx);
let profile_id = &settings.default_profile;
let profile_name = settings
@@ -704,7 +704,7 @@ impl ManageProfilesModal {
impl Render for ManageProfilesModal {
fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
let settings = AgentSettings::get_global(cx);
let settings = AssistantSettings::get_global(cx);
let go_back_item = div()
.id("cancel-item")

View File

@@ -1,7 +1,7 @@
use std::{collections::BTreeMap, sync::Arc};
use agent_settings::{
AgentProfile, AgentProfileContent, AgentProfileId, AgentSettings, AgentSettingsContent,
use assistant_settings::{
AgentProfile, AgentProfileContent, AgentProfileId, AssistantSettings, AssistantSettingsContent,
ContextServerPresetContent,
};
use assistant_tool::{ToolSource, ToolWorkingSet};
@@ -259,7 +259,7 @@ impl PickerDelegate for ToolPickerDelegate {
is_enabled
};
let active_profile_id = &AgentSettings::get_global(cx).default_profile;
let active_profile_id = &AssistantSettings::get_global(cx).default_profile;
if active_profile_id == &self.profile_id {
self.thread_store
.update(cx, |this, cx| {
@@ -268,12 +268,12 @@ impl PickerDelegate for ToolPickerDelegate {
.log_err();
}
update_settings_file::<AgentSettings>(self.fs.clone(), cx, {
update_settings_file::<AssistantSettings>(self.fs.clone(), cx, {
let profile_id = self.profile_id.clone();
let default_profile = self.profile.clone();
let server_id = server_id.clone();
let tool_name = tool_name.clone();
move |settings: &mut AgentSettingsContent, _cx| {
move |settings: &mut AssistantSettingsContent, _cx| {
settings
.v2_setting(|v2_settings| {
let profiles = v2_settings.profiles.get_or_insert_default();

View File

@@ -1,4 +1,4 @@
use agent_settings::AgentSettings;
use assistant_settings::AssistantSettings;
use fs::Fs;
use gpui::{Entity, FocusHandle, SharedString};
@@ -63,7 +63,7 @@ impl AssistantModelSelector {
);
}
});
update_settings_file::<AgentSettings>(
update_settings_file::<AssistantSettings>(
fs.clone(),
cx,
move |settings, _cx| {
@@ -72,7 +72,7 @@ impl AssistantModelSelector {
);
}
ModelType::InlineAssistant => {
update_settings_file::<AgentSettings>(
update_settings_file::<AssistantSettings>(
fs.clone(),
cx,
move |settings, _cx| {

View File

@@ -7,13 +7,13 @@ use db::kvp::KEY_VALUE_STORE;
use markdown::Markdown;
use serde::{Deserialize, Serialize};
use agent_settings::{AgentDockPosition, AgentSettings};
use anyhow::{Result, anyhow};
use assistant_context_editor::{
AssistantContext, AssistantPanelDelegate, ConfigurationError, ContextEditor, ContextEvent,
SlashCommandCompletionProvider, humanize_token_count, make_lsp_adapter_delegate,
render_remaining_tokens,
};
use assistant_settings::{AssistantDockPosition, AssistantSettings};
use assistant_slash_command::SlashCommandWorkingSet;
use assistant_tool::ToolWorkingSet;
@@ -27,9 +27,7 @@ use gpui::{
linear_gradient, prelude::*, pulsating_between,
};
use language::LanguageRegistry;
use language_model::{
LanguageModelProviderTosView, LanguageModelRegistry, RequestUsage, ZED_CLOUD_PROVIDER_ID,
};
use language_model::{LanguageModelProviderTosView, LanguageModelRegistry, RequestUsage};
use language_model_selector::ToggleModelSelector;
use project::{Project, ProjectPath, Worktree};
use prompt_store::{PromptBuilder, PromptStore, UserPromptId};
@@ -1179,7 +1177,7 @@ impl AssistantPanel {
.map_or(true, |model| model.provider.id() != provider.id())
{
if let Some(model) = provider.default_model(cx) {
update_settings_file::<AgentSettings>(
update_settings_file::<AssistantSettings>(
self.fs.clone(),
cx,
move |settings, _| settings.set_model(model),
@@ -1298,10 +1296,10 @@ impl Focusable for AssistantPanel {
}
fn agent_panel_dock_position(cx: &App) -> DockPosition {
match AgentSettings::get_global(cx).dock {
AgentDockPosition::Left => DockPosition::Left,
AgentDockPosition::Bottom => DockPosition::Bottom,
AgentDockPosition::Right => DockPosition::Right,
match AssistantSettings::get_global(cx).dock {
AssistantDockPosition::Left => DockPosition::Left,
AssistantDockPosition::Bottom => DockPosition::Bottom,
AssistantDockPosition::Right => DockPosition::Right,
}
}
@@ -1325,18 +1323,22 @@ impl Panel for AssistantPanel {
message_editor.set_dock_position(position, cx);
});
settings::update_settings_file::<AgentSettings>(self.fs.clone(), cx, move |settings, _| {
let dock = match position {
DockPosition::Left => AgentDockPosition::Left,
DockPosition::Bottom => AgentDockPosition::Bottom,
DockPosition::Right => AgentDockPosition::Right,
};
settings.set_dock(dock);
});
settings::update_settings_file::<AssistantSettings>(
self.fs.clone(),
cx,
move |settings, _| {
let dock = match position {
DockPosition::Left => AssistantDockPosition::Left,
DockPosition::Bottom => AssistantDockPosition::Bottom,
DockPosition::Right => AssistantDockPosition::Right,
};
settings.set_dock(dock);
},
);
}
fn size(&self, window: &Window, cx: &App) -> Pixels {
let settings = AgentSettings::get_global(cx);
let settings = AssistantSettings::get_global(cx);
match self.position(window, cx) {
DockPosition::Left | DockPosition::Right => {
self.width.unwrap_or(settings.default_width)
@@ -1361,7 +1363,8 @@ impl Panel for AssistantPanel {
}
fn icon(&self, _window: &Window, cx: &App) -> Option<IconName> {
(self.enabled(cx) && AgentSettings::get_global(cx).button).then_some(IconName::ZedAssistant)
(self.enabled(cx) && AssistantSettings::get_global(cx).button)
.then_some(IconName::ZedAssistant)
}
fn icon_tooltip(&self, _window: &Window, _cx: &App) -> Option<&'static str> {
@@ -1377,7 +1380,7 @@ impl Panel for AssistantPanel {
}
fn enabled(&self, cx: &App) -> bool {
AgentSettings::get_global(cx).enabled
AssistantSettings::get_global(cx).enabled
}
}
@@ -1457,7 +1460,6 @@ impl AssistantPanel {
let thread = active_thread.thread().read(cx);
let thread_id = thread.id().clone();
let is_empty = active_thread.is_empty();
let editor_empty = self.message_editor.read(cx).is_editor_fully_empty(cx);
let last_usage = active_thread.thread().read(cx).last_usage().or_else(|| {
maybe!({
let amount = user_store.model_request_usage_amount()?;
@@ -1480,7 +1482,7 @@ impl AssistantPanel {
let account_url = zed_urls::account_url(cx);
let show_token_count = match &self.active_view {
ActiveView::Thread { .. } => !is_empty || !editor_empty,
ActiveView::Thread { .. } => !is_empty,
ActiveView::PromptEditor { .. } => true,
_ => false,
};
@@ -1804,19 +1806,6 @@ impl AssistantPanel {
return false;
}
let is_using_zed_provider = self
.thread
.read(cx)
.thread()
.read(cx)
.configured_model()
.map_or(false, |model| {
model.provider.id().0 == ZED_CLOUD_PROVIDER_ID
});
if !is_using_zed_provider {
return false;
}
let plan = self.user_store.read(cx).current_plan();
if matches!(plan, Some(Plan::ZedPro | Plan::ZedProTrial)) {
return false;

View File

@@ -2,8 +2,7 @@ use std::sync::Arc;
use anyhow::Context as _;
use context_server::ContextServerId;
use extension::{ContextServerConfiguration, ExtensionManifest};
use gpui::Task;
use extension::ExtensionManifest;
use language::LanguageRegistry;
use project::context_server_store::registry::ContextServerDescriptorRegistry;
use ui::prelude::*;
@@ -55,15 +54,6 @@ pub(crate) fn init(language_registry: Arc<LanguageRegistry>, cx: &mut App) {
.detach();
}
pub enum Configuration {
NotAvailable(ContextServerId, Option<SharedString>),
Required(
ContextServerId,
Option<SharedString>,
ContextServerConfiguration,
),
}
fn show_configure_mcp_modal(
language_registry: Arc<LanguageRegistry>,
manifest: &Arc<ExtensionManifest>,
@@ -72,7 +62,6 @@ fn show_configure_mcp_modal(
cx: &mut Context<'_, Workspace>,
) {
let context_server_store = workspace.project().read(cx).context_server_store();
let repository: Option<SharedString> = manifest.repository.as_ref().map(|s| s.clone().into());
let registry = ContextServerDescriptorRegistry::default_global(cx).read(cx);
let worktree_store = workspace.project().read(cx).worktree_store();
@@ -80,37 +69,21 @@ fn show_configure_mcp_modal(
.context_servers
.keys()
.cloned()
.map({
.filter_map({
|key| {
let Some(descriptor) = registry.context_server_descriptor(&key) else {
return Task::ready(Configuration::NotAvailable(
ContextServerId(key),
repository.clone(),
));
};
cx.spawn({
let repository_url = repository.clone();
let descriptor = registry.context_server_descriptor(&key)?;
Some(cx.spawn({
let worktree_store = worktree_store.clone();
async move |_, cx| {
let configuration = descriptor
descriptor
.configuration(worktree_store.clone(), &cx)
.await
.context("Failed to resolve context server configuration")
.log_err()
.flatten();
match configuration {
Some(config) => Configuration::Required(
ContextServerId(key),
repository_url,
config,
),
None => {
Configuration::NotAvailable(ContextServerId(key), repository_url)
}
}
.flatten()
.map(|config| (ContextServerId(key), config))
}
})
}))
}
})
.collect::<Vec<_>>();
@@ -118,22 +91,22 @@ fn show_configure_mcp_modal(
let jsonc_language = language_registry.language_for_name("jsonc");
cx.spawn_in(window, async move |this, cx| {
let configurations = futures::future::join_all(configuration_tasks).await;
let descriptors = futures::future::join_all(configuration_tasks).await;
let jsonc_language = jsonc_language.await.ok();
this.update_in(cx, |this, window, cx| {
let workspace = cx.entity().downgrade();
this.toggle_modal(window, cx, |window, cx| {
ConfigureContextServerModal::new(
configurations.into_iter(),
context_server_store,
jsonc_language,
language_registry,
workspace,
window,
cx,
)
});
let modal = ConfigureContextServerModal::new(
descriptors.into_iter().flatten(),
context_server_store,
jsonc_language,
language_registry,
cx.entity().downgrade(),
window,
cx,
);
if let Some(modal) = modal {
this.toggle_modal(window, cx, |_, _| modal);
}
})
})
.detach();

View File

@@ -97,10 +97,9 @@ impl HistoryStore {
let contents = cx
.background_spawn(async move { std::fs::read_to_string(path) })
.await
.ok()?;
.context("reading persisted agent panel navigation history")?;
let entries = serde_json::from_str::<Vec<SerializedRecentEntry>>(&contents)
.context("deserializing persisted agent panel navigation history")
.log_err()?
.context("deserializing persisted agent panel navigation history")?
.into_iter()
.take(MAX_RECENTLY_OPENED_ENTRIES)
.map(|serialized| match serialized {
@@ -135,10 +134,10 @@ impl HistoryStore {
})
.ok();
Some(())
anyhow::Ok(())
}
})
.detach();
.detach_and_log_err(cx);
Self {
thread_store,

View File

@@ -4,8 +4,8 @@ use std::ops::Range;
use std::rc::Rc;
use std::sync::Arc;
use agent_settings::AgentSettings;
use anyhow::{Context as _, Result};
use assistant_settings::AssistantSettings;
use client::telemetry::Telemetry;
use collections::{HashMap, HashSet, VecDeque, hash_map};
use editor::{
@@ -145,7 +145,7 @@ impl InlineAssistant {
let Some(terminal_panel) = workspace.read(cx).panel::<TerminalPanel>(cx) else {
return;
};
let enabled = AgentSettings::get_global(cx).enabled;
let enabled = AssistantSettings::get_global(cx).enabled;
terminal_panel.update(cx, |terminal_panel, cx| {
terminal_panel.set_assistant_enabled(enabled, cx)
});
@@ -231,7 +231,7 @@ impl InlineAssistant {
window: &mut Window,
cx: &mut Context<Workspace>,
) {
let settings = AgentSettings::get_global(cx);
let settings = AssistantSettings::get_global(cx);
if !settings.enabled {
return;
}
@@ -1766,7 +1766,7 @@ impl CodeActionProvider for AssistantCodeActionProvider {
_: &mut Window,
cx: &mut App,
) -> Task<Result<Vec<CodeAction>>> {
if !AgentSettings::get_global(cx).enabled {
if !AssistantSettings::get_global(cx).enabled {
return Task::ready(Ok(Vec::new()));
}

View File

@@ -26,10 +26,7 @@ use gpui::{
Task, TextStyle, WeakEntity, linear_color_stop, linear_gradient, point, pulsating_between,
};
use language::{Buffer, Language};
use language_model::{
ConfiguredModel, LanguageModelRequestMessage, MessageContent, RequestUsage,
ZED_CLOUD_PROVIDER_ID,
};
use language_model::{ConfiguredModel, LanguageModelRequestMessage, MessageContent, RequestUsage};
use language_model_selector::ToggleModelSelector;
use multi_buffer;
use project::Project;
@@ -315,10 +312,6 @@ impl MessageEditor {
self.editor.read(cx).text(cx).trim().is_empty()
}
pub fn is_editor_fully_empty(&self, cx: &App) -> bool {
self.editor.read(cx).is_empty(cx)
}
fn send_to_model(&mut self, window: &mut Window, cx: &mut Context<Self>) {
let Some(ConfiguredModel { model, provider }) = self
.thread
@@ -475,17 +468,12 @@ impl MessageEditor {
}
let active_completion_mode = thread.completion_mode();
let max_mode_enabled = active_completion_mode == CompletionMode::Max;
Some(
Button::new("max-mode", "Max Mode")
.label_size(LabelSize::Small)
.color(Color::Muted)
.icon(IconName::ZedMaxMode)
IconButton::new("max-mode", IconName::ZedMaxMode)
.icon_size(IconSize::Small)
.icon_color(Color::Muted)
.icon_position(IconPosition::Start)
.toggle_state(max_mode_enabled)
.toggle_state(active_completion_mode == CompletionMode::Max)
.on_click(cx.listener(move |this, _event, _window, cx| {
this.thread.update(cx, |thread, _cx| {
thread.set_completion_mode(match active_completion_mode {
@@ -494,10 +482,7 @@ impl MessageEditor {
});
});
}))
.tooltip(move |_window, cx| {
cx.new(|_| MaxModeTooltip::new().selected(max_mode_enabled))
.into()
})
.tooltip(|_, cx| cx.new(MaxModeTooltip::new).into())
.into_any_element(),
)
}
@@ -1078,17 +1063,6 @@ impl MessageEditor {
return None;
}
let is_using_zed_provider = self
.thread
.read(cx)
.configured_model()
.map_or(false, |model| {
model.provider.id().0 == ZED_CLOUD_PROVIDER_ID
});
if !is_using_zed_provider {
return None;
}
let user_store = self.user_store.read(cx);
let ubb_enable = user_store

View File

@@ -1,7 +1,7 @@
use std::sync::Arc;
use agent_settings::{
AgentProfile, AgentProfileId, AgentSettings, GroupedAgentProfiles, builtin_profiles,
use assistant_settings::{
AgentProfile, AgentProfileId, AssistantSettings, GroupedAgentProfiles, builtin_profiles,
};
use fs::Fs;
use gpui::{Action, Entity, FocusHandle, Subscription, WeakEntity, prelude::*};
@@ -38,7 +38,7 @@ impl ProfileSelector {
});
Self {
profiles: GroupedAgentProfiles::from_settings(AgentSettings::get_global(cx)),
profiles: GroupedAgentProfiles::from_settings(AssistantSettings::get_global(cx)),
fs,
thread_store,
menu_handle: PopoverMenuHandle::default(),
@@ -58,7 +58,7 @@ impl ProfileSelector {
}
fn refresh_profiles(&mut self, cx: &mut Context<Self>) {
self.profiles = GroupedAgentProfiles::from_settings(AgentSettings::get_global(cx));
self.profiles = GroupedAgentProfiles::from_settings(AssistantSettings::get_global(cx));
}
fn build_context_menu(
@@ -67,7 +67,7 @@ impl ProfileSelector {
cx: &mut Context<Self>,
) -> Entity<ContextMenu> {
ContextMenu::build(window, cx, |mut menu, _window, cx| {
let settings = AgentSettings::get_global(cx);
let settings = AssistantSettings::get_global(cx);
for (profile_id, profile) in self.profiles.builtin.iter() {
menu =
menu.item(self.menu_entry_for_profile(profile_id.clone(), profile, settings));
@@ -99,7 +99,7 @@ impl ProfileSelector {
&self,
profile_id: AgentProfileId,
profile: &AgentProfile,
settings: &AgentSettings,
settings: &AssistantSettings,
) -> ContextMenuEntry {
let documentation = match profile.name.to_lowercase().as_str() {
builtin_profiles::WRITE => Some("Get help to write anything."),
@@ -124,7 +124,7 @@ impl ProfileSelector {
let thread_store = self.thread_store.clone();
let profile_id = profile_id.clone();
move |_window, cx| {
update_settings_file::<AgentSettings>(fs.clone(), cx, {
update_settings_file::<AssistantSettings>(fs.clone(), cx, {
let profile_id = profile_id.clone();
move |settings, _cx| {
settings.set_profile(profile_id.clone());
@@ -143,7 +143,7 @@ impl ProfileSelector {
impl Render for ProfileSelector {
fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
let settings = AgentSettings::get_global(cx);
let settings = AssistantSettings::get_global(cx);
let profile_id = &settings.default_profile;
let profile = settings.profiles.get(profile_id);

View File

@@ -4,8 +4,8 @@ use std::ops::Range;
use std::sync::Arc;
use std::time::Instant;
use agent_settings::AgentSettings;
use anyhow::{Result, anyhow};
use assistant_settings::AssistantSettings;
use assistant_tool::{ActionLog, AnyToolCard, Tool, ToolWorkingSet};
use chrono::{DateTime, Utc};
use collections::HashMap;
@@ -267,7 +267,7 @@ impl DetailedSummaryState {
}
}
#[derive(Default, Debug)]
#[derive(Default)]
pub struct TotalTokenUsage {
pub total: usize,
pub max: usize,
@@ -1890,7 +1890,7 @@ impl Thread {
for tool_use in pending_tool_uses.iter() {
if let Some(tool) = self.tools.read(cx).tool(&tool_use.name, cx) {
if tool.needs_confirmation(&tool_use.input, cx)
&& !AgentSettings::get_global(cx).always_allow_tool_actions
&& !AssistantSettings::get_global(cx).always_allow_tool_actions
{
self.tool_use.confirm_tool_use(
tool_use.id.clone(),
@@ -2658,7 +2658,7 @@ struct PendingCompletion {
mod tests {
use super::*;
use crate::{ThreadStore, context::load_context, context_store::ContextStore, thread_store};
use agent_settings::AgentSettings;
use assistant_settings::AssistantSettings;
use assistant_tool::ToolRegistry;
use editor::EditorSettings;
use gpui::TestAppContext;
@@ -3075,7 +3075,7 @@ fn main() {{
cx.set_global(settings_store);
language::init(cx);
Project::init_settings(cx);
AgentSettings::register(cx);
AssistantSettings::register(cx);
prompt_store::init(cx);
thread_store::init(cx);
workspace::init_settings(cx);

View File

@@ -4,8 +4,8 @@ use std::path::{Path, PathBuf};
use std::rc::Rc;
use std::sync::Arc;
use agent_settings::{AgentProfile, AgentProfileId, AgentSettings};
use anyhow::{Context as _, Result, anyhow};
use assistant_settings::{AgentProfile, AgentProfileId, AssistantSettings};
use assistant_tool::{ToolId, ToolSource, ToolWorkingSet};
use chrono::{DateTime, Utc};
use collections::HashMap;
@@ -462,15 +462,15 @@ impl ThreadStore {
}
fn load_default_profile(&self, cx: &mut Context<Self>) {
let agent_settings = AgentSettings::get_global(cx);
let assistant_settings = AssistantSettings::get_global(cx);
self.load_profile_by_id(agent_settings.default_profile.clone(), cx);
self.load_profile_by_id(assistant_settings.default_profile.clone(), cx);
}
pub fn load_profile_by_id(&self, profile_id: AgentProfileId, cx: &mut Context<Self>) {
let agent_settings = AgentSettings::get_global(cx);
let assistant_settings = AssistantSettings::get_global(cx);
if let Some(profile) = agent_settings.profiles.get(&profile_id) {
if let Some(profile) = assistant_settings.profiles.get(&profile_id) {
self.load_profile(profile.clone(), cx);
}
}

View File

@@ -110,27 +110,20 @@ impl ToolUseState {
}
pub fn cancel_pending(&mut self) -> Vec<PendingToolUse> {
let mut cancelled_tool_uses = Vec::new();
self.pending_tool_uses_by_id
.retain(|tool_use_id, tool_use| {
if matches!(tool_use.status, PendingToolUseStatus::Error { .. }) {
return true;
}
let content = "Tool canceled by user".into();
self.tool_results.insert(
tool_use_id.clone(),
LanguageModelToolResult {
tool_use_id: tool_use_id.clone(),
tool_name: tool_use.name.clone(),
content,
is_error: true,
},
);
cancelled_tool_uses.push(tool_use.clone());
false
});
cancelled_tool_uses
let mut pending_tools = Vec::new();
for (tool_use_id, tool_use) in self.pending_tool_uses_by_id.drain() {
self.tool_results.insert(
tool_use_id.clone(),
LanguageModelToolResult {
tool_use_id,
tool_name: tool_use.name.clone(),
content: "Tool canceled by user".into(),
is_error: true,
},
);
pending_tools.push(tool_use.clone());
}
pending_tools
}
pub fn pending_tool_uses(&self) -> Vec<&PendingToolUse> {

View File

@@ -1,50 +1,24 @@
use gpui::{Context, IntoElement, Render, Window};
use ui::{prelude::*, tooltip_container};
pub struct MaxModeTooltip {
selected: bool,
}
pub struct MaxModeTooltip;
impl MaxModeTooltip {
pub fn new() -> Self {
Self { selected: false }
}
pub fn selected(mut self, selected: bool) -> Self {
self.selected = selected;
self
pub fn new(_cx: &mut Context<Self>) -> Self {
Self
}
}
impl Render for MaxModeTooltip {
fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
tooltip_container(window, cx, |this, _, _| {
fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
tooltip_container(_window, cx, |this, _, _| {
this.gap_1()
.map(|header| if self.selected {
header.child(
h_flex()
.justify_between()
.child(
h_flex()
.gap_1p5()
.child(Icon::new(IconName::ZedMaxMode).size(IconSize::Small).color(Color::Accent))
.child(Label::new("Zed's Max Mode"))
)
.child(
h_flex()
.gap_0p5()
.child(Icon::new(IconName::Check).size(IconSize::XSmall).color(Color::Accent))
.child(Label::new("Turned On").size(LabelSize::XSmall).color(Color::Accent))
)
)
} else {
header.child(
h_flex()
.gap_1p5()
.child(Icon::new(IconName::ZedMaxMode).size(IconSize::Small))
.child(Label::new("Zed's Max Mode"))
)
})
.child(
h_flex()
.gap_1p5()
.child(Icon::new(IconName::ZedMaxMode).size(IconSize::Small))
.child(Label::new("Zed's Max Mode"))
)
.child(
div()
.max_w_72()

View File

@@ -46,8 +46,6 @@ pub enum Model {
Claude3_5Haiku,
#[serde(rename = "claude-3-opus", alias = "claude-3-opus-latest")]
Claude3Opus,
#[serde(rename = "claude-3-sonnet", alias = "claude-3-sonnet-latest")]
Claude3Sonnet,
#[serde(rename = "claude-3-haiku", alias = "claude-3-haiku-latest")]
Claude3Haiku,
#[serde(rename = "custom")]
@@ -85,8 +83,6 @@ impl Model {
Ok(Self::Claude3_5Haiku)
} else if id.starts_with("claude-3-opus") {
Ok(Self::Claude3Opus)
} else if id.starts_with("claude-3-sonnet") {
Ok(Self::Claude3Sonnet)
} else if id.starts_with("claude-3-haiku") {
Ok(Self::Claude3Haiku)
} else {
@@ -101,7 +97,6 @@ impl Model {
Model::Claude3_7SonnetThinking => "claude-3-7-sonnet-thinking-latest",
Model::Claude3_5Haiku => "claude-3-5-haiku-latest",
Model::Claude3Opus => "claude-3-opus-latest",
Model::Claude3Sonnet => "claude-3-sonnet-20240229",
Model::Claude3Haiku => "claude-3-haiku-20240307",
Self::Custom { name, .. } => name,
}
@@ -114,7 +109,6 @@ impl Model {
Model::Claude3_7Sonnet | Model::Claude3_7SonnetThinking => "claude-3-7-sonnet-latest",
Model::Claude3_5Haiku => "claude-3-5-haiku-latest",
Model::Claude3Opus => "claude-3-opus-latest",
Model::Claude3Sonnet => "claude-3-sonnet-20240229",
Model::Claude3Haiku => "claude-3-haiku-20240307",
Self::Custom { name, .. } => name,
}
@@ -127,7 +121,6 @@ impl Model {
Self::Claude3_7SonnetThinking => "Claude 3.7 Sonnet Thinking",
Self::Claude3_5Haiku => "Claude 3.5 Haiku",
Self::Claude3Opus => "Claude 3 Opus",
Self::Claude3Sonnet => "Claude 3 Sonnet",
Self::Claude3Haiku => "Claude 3 Haiku",
Self::Custom {
name, display_name, ..
@@ -161,7 +154,6 @@ impl Model {
| Self::Claude3_7Sonnet
| Self::Claude3_7SonnetThinking
| Self::Claude3Opus
| Self::Claude3Sonnet
| Self::Claude3Haiku => 200_000,
Self::Custom { max_tokens, .. } => *max_tokens,
}
@@ -169,7 +161,7 @@ impl Model {
pub fn max_output_tokens(&self) -> u32 {
match self {
Self::Claude3Opus | Self::Claude3Sonnet | Self::Claude3Haiku => 4_096,
Self::Claude3Opus | Self::Claude3Haiku => 4_096,
Self::Claude3_5Sonnet
| Self::Claude3_7Sonnet
| Self::Claude3_7SonnetThinking
@@ -187,7 +179,6 @@ impl Model {
| Self::Claude3_7SonnetThinking
| Self::Claude3_5Haiku
| Self::Claude3Opus
| Self::Claude3Sonnet
| Self::Claude3Haiku => 1.0,
Self::Custom {
default_temperature,
@@ -202,7 +193,6 @@ impl Model {
| Self::Claude3_7Sonnet
| Self::Claude3_5Haiku
| Self::Claude3Opus
| Self::Claude3Sonnet
| Self::Claude3Haiku => AnthropicModelMode::Default,
Self::Claude3_7SonnetThinking => AnthropicModelMode::Thinking {
budget_tokens: Some(4_096),

View File

@@ -23,7 +23,7 @@ test-support = [
[dependencies]
anyhow.workspace = true
assistant_context_editor.workspace = true
agent_settings.workspace = true
assistant_settings.workspace = true
assistant_slash_command.workspace = true
assistant_slash_commands.workspace = true
assistant_tool.workspace = true

View File

@@ -8,7 +8,7 @@ mod terminal_inline_assistant;
use std::sync::Arc;
use agent_settings::{AgentSettings, LanguageModelSelection};
use assistant_settings::{AssistantSettings, LanguageModelSelection};
use assistant_slash_command::SlashCommandRegistry;
use client::Client;
use command_palette_hooks::CommandPaletteFilter;
@@ -97,7 +97,7 @@ pub fn init(
cx: &mut App,
) {
cx.set_global(Assistant::default());
AgentSettings::register(cx);
AssistantSettings::register(cx);
SlashCommandSettings::register(cx);
assistant_context_editor::init(client.clone(), cx);
@@ -126,13 +126,13 @@ pub fn init(
filter.hide_namespace(Assistant::NAMESPACE);
});
Assistant::update_global(cx, |assistant, cx| {
let settings = AgentSettings::get_global(cx);
let settings = AssistantSettings::get_global(cx);
assistant.set_enabled(settings.enabled, cx);
});
cx.observe_global::<SettingsStore>(|cx| {
Assistant::update_global(cx, |assistant, cx| {
let settings = AgentSettings::get_global(cx);
let settings = AssistantSettings::get_global(cx);
assistant.set_enabled(settings.enabled, cx);
});
})
@@ -159,7 +159,7 @@ fn init_language_model_settings(cx: &mut App) {
}
fn update_active_language_model_from_settings(cx: &mut App) {
let settings = AgentSettings::get_global(cx);
let settings = AssistantSettings::get_global(cx);
fn to_selected_model(selection: &LanguageModelSelection) -> language_model::SelectedModel {
language_model::SelectedModel {

View File

@@ -3,7 +3,6 @@ use crate::assistant_configuration::{ConfigurationView, ConfigurationViewEvent};
use crate::{
DeployHistory, InlineAssistant, NewChat, terminal_inline_assistant::TerminalInlineAssistant,
};
use agent_settings::{AgentDockPosition, AgentSettings};
use anyhow::{Result, anyhow};
use assistant_context_editor::{
AssistantContext, AssistantPanelDelegate, ContextEditor, ContextEditorToolbarItem,
@@ -11,6 +10,7 @@ use assistant_context_editor::{
DEFAULT_TAB_TITLE, InsertDraggedFiles, SlashCommandCompletionProvider,
make_lsp_adapter_delegate,
};
use assistant_settings::{AssistantDockPosition, AssistantSettings};
use assistant_slash_command::SlashCommandWorkingSet;
use client::{Client, Status, proto};
use editor::{Anchor, AnchorRangeExt as _, Editor, EditorEvent, MultiBuffer};
@@ -984,7 +984,7 @@ impl AssistantPanel {
.map_or(true, |default| default.provider.id() != provider.id())
{
if let Some(model) = provider.default_model(cx) {
update_settings_file::<AgentSettings>(
update_settings_file::<AssistantSettings>(
this.fs.clone(),
cx,
move |settings, _| settings.set_model(model),
@@ -1231,10 +1231,10 @@ impl Panel for AssistantPanel {
}
fn position(&self, _: &Window, cx: &App) -> DockPosition {
match AgentSettings::get_global(cx).dock {
AgentDockPosition::Left => DockPosition::Left,
AgentDockPosition::Bottom => DockPosition::Bottom,
AgentDockPosition::Right => DockPosition::Right,
match AssistantSettings::get_global(cx).dock {
AssistantDockPosition::Left => DockPosition::Left,
AssistantDockPosition::Bottom => DockPosition::Bottom,
AssistantDockPosition::Right => DockPosition::Right,
}
}
@@ -1243,18 +1243,22 @@ impl Panel for AssistantPanel {
}
fn set_position(&mut self, position: DockPosition, _: &mut Window, cx: &mut Context<Self>) {
settings::update_settings_file::<AgentSettings>(self.fs.clone(), cx, move |settings, _| {
let dock = match position {
DockPosition::Left => AgentDockPosition::Left,
DockPosition::Bottom => AgentDockPosition::Bottom,
DockPosition::Right => AgentDockPosition::Right,
};
settings.set_dock(dock);
});
settings::update_settings_file::<AssistantSettings>(
self.fs.clone(),
cx,
move |settings, _| {
let dock = match position {
DockPosition::Left => AssistantDockPosition::Left,
DockPosition::Bottom => AssistantDockPosition::Bottom,
DockPosition::Right => AssistantDockPosition::Right,
};
settings.set_dock(dock);
},
);
}
fn size(&self, window: &Window, cx: &App) -> Pixels {
let settings = AgentSettings::get_global(cx);
let settings = AssistantSettings::get_global(cx);
match self.position(window, cx) {
DockPosition::Left | DockPosition::Right => {
self.width.unwrap_or(settings.default_width)
@@ -1298,7 +1302,8 @@ impl Panel for AssistantPanel {
}
fn icon(&self, _: &Window, cx: &App) -> Option<IconName> {
(self.enabled(cx) && AgentSettings::get_global(cx).button).then_some(IconName::ZedAssistant)
(self.enabled(cx) && AssistantSettings::get_global(cx).button)
.then_some(IconName::ZedAssistant)
}
fn icon_tooltip(&self, _: &Window, _: &App) -> Option<&'static str> {

View File

@@ -2,9 +2,9 @@ use crate::{
Assistant, AssistantPanel, AssistantPanelEvent, CycleNextInlineAssist,
CyclePreviousInlineAssist,
};
use agent_settings::AgentSettings;
use anyhow::{Context as _, Result, anyhow};
use assistant_context_editor::{RequestType, humanize_token_count};
use assistant_settings::AssistantSettings;
use client::{ErrorExt, telemetry::Telemetry};
use collections::{HashMap, HashSet, VecDeque, hash_map};
use editor::{
@@ -156,7 +156,7 @@ impl InlineAssistant {
let Some(terminal_panel) = workspace.read(cx).panel::<TerminalPanel>(cx) else {
return;
};
let enabled = AgentSettings::get_global(cx).enabled;
let enabled = AssistantSettings::get_global(cx).enabled;
terminal_panel.update(cx, |terminal_panel, cx| {
terminal_panel.set_assistant_enabled(enabled, cx)
});
@@ -1761,7 +1761,7 @@ impl PromptEditor {
LanguageModelSelector::new(
|cx| LanguageModelRegistry::read_global(cx).default_model(),
move |model, cx| {
update_settings_file::<AgentSettings>(
update_settings_file::<AssistantSettings>(
fs.clone(),
cx,
move |settings, _| settings.set_model(model.clone()),

View File

@@ -1,7 +1,7 @@
use crate::{AssistantPanel, AssistantPanelEvent, DEFAULT_CONTEXT_LINES};
use agent_settings::AgentSettings;
use anyhow::{Context as _, Result};
use assistant_context_editor::{RequestType, humanize_token_count};
use assistant_settings::AssistantSettings;
use client::telemetry::Telemetry;
use collections::{HashMap, VecDeque};
use editor::{
@@ -756,7 +756,7 @@ impl PromptEditor {
LanguageModelSelector::new(
|cx| LanguageModelRegistry::read_global(cx).default_model(),
move |model, cx| {
update_settings_file::<AgentSettings>(
update_settings_file::<AssistantSettings>(
fs.clone(),
cx,
move |settings, _| settings.set_model(model.clone()),

View File

@@ -13,7 +13,7 @@ path = "src/assistant_context_editor.rs"
[dependencies]
anyhow.workspace = true
agent_settings.workspace = true
assistant_settings.workspace = true
assistant_slash_command.workspace = true
assistant_slash_commands.workspace = true
chrono.workspace = true

View File

@@ -1,5 +1,5 @@
use agent_settings::AgentSettings;
use anyhow::Result;
use assistant_settings::AssistantSettings;
use assistant_slash_command::{SlashCommand, SlashCommandOutputSection, SlashCommandWorkingSet};
use assistant_slash_commands::{
DefaultSlashCommand, DocsSlashCommand, DocsSlashCommandArgs, FileSlashCommand,
@@ -303,7 +303,7 @@ impl ContextEditor {
LanguageModelSelector::new(
|cx| LanguageModelRegistry::read_global(cx).default_model(),
move |model, cx| {
update_settings_file::<AgentSettings>(
update_settings_file::<AssistantSettings>(
fs.clone(),
cx,
move |settings, _| settings.set_model(model.clone()),
@@ -2462,7 +2462,7 @@ impl ContextEditor {
})
.layer(ElevationIndex::ModalSurface)
.child(Label::new(
if AgentSettings::get_global(cx).are_live_diffs_enabled(cx) {
if AssistantSettings::get_global(cx).are_live_diffs_enabled(cx) {
"Chat"
} else {
"Send"
@@ -3149,7 +3149,7 @@ impl Render for ContextEditor {
.w_full()
.justify_end()
.when(
AgentSettings::get_global(cx).are_live_diffs_enabled(cx),
AssistantSettings::get_global(cx).are_live_diffs_enabled(cx),
|buttons| {
buttons
.items_center()

View File

@@ -1,5 +1,5 @@
[package]
name = "agent_settings"
name = "assistant_settings"
version = "0.1.0"
edition.workspace = true
publish.workspace = true
@@ -9,7 +9,7 @@ license = "GPL-3.0-or-later"
workspace = true
[lib]
path = "src/agent_settings.rs"
path = "src/assistant_settings.rs"
[dependencies]
anthropic = { workspace = true, features = ["schemars"] }
@@ -33,5 +33,4 @@ fs.workspace = true
gpui = { workspace = true, features = ["test-support"] }
paths.workspace = true
serde_json_lenient.workspace = true
serde_json.workspace = true
settings = { workspace = true, features = ["test-support"] }

View File

@@ -24,7 +24,7 @@ pub struct GroupedAgentProfiles {
}
impl GroupedAgentProfiles {
pub fn from_settings(settings: &crate::AgentSettings) -> Self {
pub fn from_settings(settings: &crate::AssistantSettings) -> Self {
let mut builtin = IndexMap::default();
let mut custom = IndexMap::default();

View File

@@ -20,7 +20,7 @@ pub use crate::agent_profile::*;
#[derive(Copy, Clone, Default, Debug, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum AgentDockPosition {
pub enum AssistantDockPosition {
Left,
#[default]
Right,
@@ -70,10 +70,10 @@ pub enum AssistantProviderContentV1 {
}
#[derive(Default, Clone, Debug)]
pub struct AgentSettings {
pub struct AssistantSettings {
pub enabled: bool,
pub button: bool,
pub dock: AgentDockPosition,
pub dock: AssistantDockPosition,
pub default_width: Pixels,
pub default_height: Pixels,
pub default_model: LanguageModelSelection,
@@ -91,7 +91,7 @@ pub struct AgentSettings {
pub single_file_review: bool,
}
impl AgentSettings {
impl AssistantSettings {
pub fn stream_edits(&self, cx: &App) -> bool {
cx.has_flag::<AgentStreamEditsFeatureFlag>() || self.stream_edits
}
@@ -119,54 +119,56 @@ impl AgentSettings {
/// Assistant panel settings
#[derive(Clone, Serialize, Deserialize, Debug, Default)]
pub struct AgentSettingsContent {
pub struct AssistantSettingsContent {
#[serde(flatten)]
pub inner: Option<AgentSettingsContentInner>,
pub inner: Option<AssistantSettingsContentInner>,
}
#[derive(Clone, Serialize, Deserialize, Debug)]
#[serde(untagged)]
pub enum AgentSettingsContentInner {
Versioned(Box<VersionedAgentSettingsContent>),
pub enum AssistantSettingsContentInner {
Versioned(Box<VersionedAssistantSettingsContent>),
Legacy(LegacyAssistantSettingsContent),
}
impl AgentSettingsContentInner {
fn for_v2(content: AgentSettingsContentV2) -> Self {
AgentSettingsContentInner::Versioned(Box::new(VersionedAgentSettingsContent::V2(content)))
impl AssistantSettingsContentInner {
fn for_v2(content: AssistantSettingsContentV2) -> Self {
AssistantSettingsContentInner::Versioned(Box::new(VersionedAssistantSettingsContent::V2(
content,
)))
}
}
impl JsonSchema for AgentSettingsContent {
impl JsonSchema for AssistantSettingsContent {
fn schema_name() -> String {
VersionedAgentSettingsContent::schema_name()
VersionedAssistantSettingsContent::schema_name()
}
fn json_schema(r#gen: &mut schemars::r#gen::SchemaGenerator) -> Schema {
VersionedAgentSettingsContent::json_schema(r#gen)
VersionedAssistantSettingsContent::json_schema(r#gen)
}
fn is_referenceable() -> bool {
VersionedAgentSettingsContent::is_referenceable()
VersionedAssistantSettingsContent::is_referenceable()
}
}
impl AgentSettingsContent {
impl AssistantSettingsContent {
pub fn is_version_outdated(&self) -> bool {
match &self.inner {
Some(AgentSettingsContentInner::Versioned(settings)) => match **settings {
VersionedAgentSettingsContent::V1(_) => true,
VersionedAgentSettingsContent::V2(_) => false,
Some(AssistantSettingsContentInner::Versioned(settings)) => match **settings {
VersionedAssistantSettingsContent::V1(_) => true,
VersionedAssistantSettingsContent::V2(_) => false,
},
Some(AgentSettingsContentInner::Legacy(_)) => true,
Some(AssistantSettingsContentInner::Legacy(_)) => true,
None => false,
}
}
fn upgrade(&self) -> AgentSettingsContentV2 {
fn upgrade(&self) -> AssistantSettingsContentV2 {
match &self.inner {
Some(AgentSettingsContentInner::Versioned(settings)) => match **settings {
VersionedAgentSettingsContent::V1(ref settings) => AgentSettingsContentV2 {
Some(AssistantSettingsContentInner::Versioned(settings)) => match **settings {
VersionedAssistantSettingsContent::V1(ref settings) => AssistantSettingsContentV2 {
enabled: settings.enabled,
button: settings.button,
dock: settings.dock,
@@ -225,9 +227,9 @@ impl AgentSettingsContent {
stream_edits: None,
single_file_review: None,
},
VersionedAgentSettingsContent::V2(ref settings) => settings.clone(),
VersionedAssistantSettingsContent::V2(ref settings) => settings.clone(),
},
Some(AgentSettingsContentInner::Legacy(settings)) => AgentSettingsContentV2 {
Some(AssistantSettingsContentInner::Legacy(settings)) => AssistantSettingsContentV2 {
enabled: None,
button: settings.button,
dock: settings.dock,
@@ -254,28 +256,30 @@ impl AgentSettingsContent {
stream_edits: None,
single_file_review: None,
},
None => AgentSettingsContentV2::default(),
None => AssistantSettingsContentV2::default(),
}
}
pub fn set_dock(&mut self, dock: AgentDockPosition) {
pub fn set_dock(&mut self, dock: AssistantDockPosition) {
match &mut self.inner {
Some(AgentSettingsContentInner::Versioned(settings)) => match **settings {
VersionedAgentSettingsContent::V1(ref mut settings) => {
Some(AssistantSettingsContentInner::Versioned(settings)) => match **settings {
VersionedAssistantSettingsContent::V1(ref mut settings) => {
settings.dock = Some(dock);
}
VersionedAgentSettingsContent::V2(ref mut settings) => {
VersionedAssistantSettingsContent::V2(ref mut settings) => {
settings.dock = Some(dock);
}
},
Some(AgentSettingsContentInner::Legacy(settings)) => {
Some(AssistantSettingsContentInner::Legacy(settings)) => {
settings.dock = Some(dock);
}
None => {
self.inner = Some(AgentSettingsContentInner::for_v2(AgentSettingsContentV2 {
dock: Some(dock),
..Default::default()
}))
self.inner = Some(AssistantSettingsContentInner::for_v2(
AssistantSettingsContentV2 {
dock: Some(dock),
..Default::default()
},
))
}
}
}
@@ -285,95 +289,99 @@ impl AgentSettingsContent {
let provider = language_model.provider_id().0.to_string();
match &mut self.inner {
Some(AgentSettingsContentInner::Versioned(settings)) => match **settings {
VersionedAgentSettingsContent::V1(ref mut settings) => match provider.as_ref() {
"zed.dev" => {
log::warn!("attempted to set zed.dev model on outdated settings");
}
"anthropic" => {
let api_url = match &settings.provider {
Some(AssistantProviderContentV1::Anthropic { api_url, .. }) => {
api_url.clone()
}
_ => None,
};
settings.provider = Some(AssistantProviderContentV1::Anthropic {
default_model: AnthropicModel::from_id(&model).ok(),
api_url,
});
}
"ollama" => {
let api_url = match &settings.provider {
Some(AssistantProviderContentV1::Ollama { api_url, .. }) => {
api_url.clone()
}
_ => None,
};
settings.provider = Some(AssistantProviderContentV1::Ollama {
default_model: Some(ollama::Model::new(
&model,
None,
None,
language_model.supports_tools(),
)),
api_url,
});
}
"lmstudio" => {
let api_url = match &settings.provider {
Some(AssistantProviderContentV1::LmStudio { api_url, .. }) => {
api_url.clone()
}
_ => None,
};
settings.provider = Some(AssistantProviderContentV1::LmStudio {
default_model: Some(lmstudio::Model::new(&model, None, None)),
api_url,
});
}
"openai" => {
let (api_url, available_models) = match &settings.provider {
Some(AssistantProviderContentV1::OpenAi {
Some(AssistantSettingsContentInner::Versioned(settings)) => match **settings {
VersionedAssistantSettingsContent::V1(ref mut settings) => {
match provider.as_ref() {
"zed.dev" => {
log::warn!("attempted to set zed.dev model on outdated settings");
}
"anthropic" => {
let api_url = match &settings.provider {
Some(AssistantProviderContentV1::Anthropic { api_url, .. }) => {
api_url.clone()
}
_ => None,
};
settings.provider = Some(AssistantProviderContentV1::Anthropic {
default_model: AnthropicModel::from_id(&model).ok(),
api_url,
});
}
"ollama" => {
let api_url = match &settings.provider {
Some(AssistantProviderContentV1::Ollama { api_url, .. }) => {
api_url.clone()
}
_ => None,
};
settings.provider = Some(AssistantProviderContentV1::Ollama {
default_model: Some(ollama::Model::new(
&model,
None,
None,
language_model.supports_tools(),
)),
api_url,
});
}
"lmstudio" => {
let api_url = match &settings.provider {
Some(AssistantProviderContentV1::LmStudio { api_url, .. }) => {
api_url.clone()
}
_ => None,
};
settings.provider = Some(AssistantProviderContentV1::LmStudio {
default_model: Some(lmstudio::Model::new(&model, None, None)),
api_url,
});
}
"openai" => {
let (api_url, available_models) = match &settings.provider {
Some(AssistantProviderContentV1::OpenAi {
api_url,
available_models,
..
}) => (api_url.clone(), available_models.clone()),
_ => (None, None),
};
settings.provider = Some(AssistantProviderContentV1::OpenAi {
default_model: OpenAiModel::from_id(&model).ok(),
api_url,
available_models,
..
}) => (api_url.clone(), available_models.clone()),
_ => (None, None),
};
settings.provider = Some(AssistantProviderContentV1::OpenAi {
default_model: OpenAiModel::from_id(&model).ok(),
api_url,
available_models,
});
});
}
"deepseek" => {
let api_url = match &settings.provider {
Some(AssistantProviderContentV1::DeepSeek { api_url, .. }) => {
api_url.clone()
}
_ => None,
};
settings.provider = Some(AssistantProviderContentV1::DeepSeek {
default_model: DeepseekModel::from_id(&model).ok(),
api_url,
});
}
_ => {}
}
"deepseek" => {
let api_url = match &settings.provider {
Some(AssistantProviderContentV1::DeepSeek { api_url, .. }) => {
api_url.clone()
}
_ => None,
};
settings.provider = Some(AssistantProviderContentV1::DeepSeek {
default_model: DeepseekModel::from_id(&model).ok(),
api_url,
});
}
_ => {}
},
VersionedAgentSettingsContent::V2(ref mut settings) => {
}
VersionedAssistantSettingsContent::V2(ref mut settings) => {
settings.default_model = Some(LanguageModelSelection { provider, model });
}
},
Some(AgentSettingsContentInner::Legacy(settings)) => {
Some(AssistantSettingsContentInner::Legacy(settings)) => {
if let Ok(model) = OpenAiModel::from_id(&language_model.id().0) {
settings.default_open_ai_model = Some(model);
}
}
None => {
self.inner = Some(AgentSettingsContentInner::for_v2(AgentSettingsContentV2 {
default_model: Some(LanguageModelSelection { provider, model }),
..Default::default()
}));
self.inner = Some(AssistantSettingsContentInner::for_v2(
AssistantSettingsContentV2 {
default_model: Some(LanguageModelSelection { provider, model }),
..Default::default()
},
));
}
}
}
@@ -396,15 +404,15 @@ impl AgentSettingsContent {
pub fn v2_setting(
&mut self,
f: impl FnOnce(&mut AgentSettingsContentV2) -> anyhow::Result<()>,
f: impl FnOnce(&mut AssistantSettingsContentV2) -> anyhow::Result<()>,
) -> anyhow::Result<()> {
match self.inner.get_or_insert_with(|| {
AgentSettingsContentInner::for_v2(AgentSettingsContentV2 {
AssistantSettingsContentInner::for_v2(AssistantSettingsContentV2 {
..Default::default()
})
}) {
AgentSettingsContentInner::Versioned(boxed) => {
if let VersionedAgentSettingsContent::V2(ref mut settings) = **boxed {
AssistantSettingsContentInner::Versioned(boxed) => {
if let VersionedAssistantSettingsContent::V2(ref mut settings) = **boxed {
f(settings)
} else {
Ok(())
@@ -485,16 +493,16 @@ impl AgentSettingsContent {
#[derive(Clone, Serialize, Deserialize, JsonSchema, Debug)]
#[serde(tag = "version")]
pub enum VersionedAgentSettingsContent {
pub enum VersionedAssistantSettingsContent {
#[serde(rename = "1")]
V1(AssistantSettingsContentV1),
#[serde(rename = "2")]
V2(AgentSettingsContentV2),
V2(AssistantSettingsContentV2),
}
impl Default for VersionedAgentSettingsContent {
impl Default for VersionedAssistantSettingsContent {
fn default() -> Self {
Self::V2(AgentSettingsContentV2 {
Self::V2(AssistantSettingsContentV2 {
enabled: None,
button: None,
dock: None,
@@ -517,30 +525,30 @@ impl Default for VersionedAgentSettingsContent {
}
#[derive(Clone, Serialize, Deserialize, JsonSchema, Debug, Default)]
pub struct AgentSettingsContentV2 {
/// Whether the agent is enabled.
pub struct AssistantSettingsContentV2 {
/// Whether the Assistant is enabled.
///
/// Default: true
enabled: Option<bool>,
/// Whether to show the agent panel button in the status bar.
/// Whether to show the assistant panel button in the status bar.
///
/// Default: true
button: Option<bool>,
/// Where to dock the agent.
/// Where to dock the assistant.
///
/// Default: right
dock: Option<AgentDockPosition>,
/// Default width in pixels when the agent is docked to the left or right.
dock: Option<AssistantDockPosition>,
/// Default width in pixels when the assistant is docked to the left or right.
///
/// Default: 640
default_width: Option<f32>,
/// Default height in pixels when the agent is docked to the bottom.
/// Default height in pixels when the assistant is docked to the bottom.
///
/// Default: 320
default_height: Option<f32>,
/// The default model to use when creating new chats and for other features when a specific model is not specified.
default_model: Option<LanguageModelSelection>,
/// Model to use for the inline agent. Defaults to default_model when not specified.
/// Model to use for the inline assistant. Defaults to default_model when not specified.
inline_assistant_model: Option<LanguageModelSelection>,
/// Model to use for generating git commit messages. Defaults to default_model when not specified.
commit_message_model: Option<LanguageModelSelection>,
@@ -548,7 +556,7 @@ pub struct AgentSettingsContentV2 {
thread_summary_model: Option<LanguageModelSelection>,
/// Additional models with which to generate alternatives when performing inline assists.
inline_alternatives: Option<Vec<LanguageModelSelection>>,
/// Enable experimental live diffs in the agent panel.
/// Enable experimental live diffs in the assistant panel.
///
/// Default: false
enable_experimental_live_diffs: Option<bool>,
@@ -640,7 +648,7 @@ pub struct AssistantSettingsContentV1 {
/// Where to dock the assistant.
///
/// Default: right
dock: Option<AgentDockPosition>,
dock: Option<AssistantDockPosition>,
/// Default width in pixels when the assistant is docked to the left or right.
///
/// Default: 640
@@ -665,7 +673,7 @@ pub struct LegacyAssistantSettingsContent {
/// Where to dock the assistant.
///
/// Default: right
pub dock: Option<AgentDockPosition>,
pub dock: Option<AssistantDockPosition>,
/// Default width in pixels when the assistant is docked to the left or right.
///
/// Default: 640
@@ -684,20 +692,18 @@ pub struct LegacyAssistantSettingsContent {
pub openai_api_url: Option<String>,
}
impl Settings for AgentSettings {
impl Settings for AssistantSettings {
const KEY: Option<&'static str> = Some("agent");
const FALLBACK_KEY: Option<&'static str> = Some("assistant");
const PRESERVED_KEYS: Option<&'static [&'static str]> = Some(&["version"]);
type FileContent = AgentSettingsContent;
type FileContent = AssistantSettingsContent;
fn load(
sources: SettingsSources<Self::FileContent>,
_: &mut gpui::App,
) -> anyhow::Result<Self> {
let mut settings = AgentSettings::default();
let mut settings = AssistantSettings::default();
for value in sources.defaults_and_customizations() {
if value.is_version_outdated() {
@@ -782,25 +788,28 @@ impl Settings for AgentSettings {
.and_then(|b| b.as_bool())
{
match &mut current.inner {
Some(AgentSettingsContentInner::Versioned(versioned)) => match versioned.as_mut() {
VersionedAgentSettingsContent::V1(setting) => {
setting.enabled = Some(b);
setting.button = Some(b);
}
Some(AssistantSettingsContentInner::Versioned(versioned)) => {
match versioned.as_mut() {
VersionedAssistantSettingsContent::V1(setting) => {
setting.enabled = Some(b);
setting.button = Some(b);
}
VersionedAgentSettingsContent::V2(setting) => {
setting.enabled = Some(b);
setting.button = Some(b);
VersionedAssistantSettingsContent::V2(setting) => {
setting.enabled = Some(b);
setting.button = Some(b);
}
}
},
Some(AgentSettingsContentInner::Legacy(setting)) => setting.button = Some(b),
}
Some(AssistantSettingsContentInner::Legacy(setting)) => setting.button = Some(b),
None => {
current.inner =
Some(AgentSettingsContentInner::for_v2(AgentSettingsContentV2 {
current.inner = Some(AssistantSettingsContentInner::for_v2(
AssistantSettingsContentV2 {
enabled: Some(b),
button: Some(b),
..Default::default()
}));
},
));
}
}
}
@@ -817,12 +826,11 @@ fn merge<T>(target: &mut T, value: Option<T>) {
mod tests {
use fs::Fs;
use gpui::{ReadGlobal, TestAppContext};
use settings::SettingsStore;
use super::*;
#[gpui::test]
async fn test_deserialize_agent_settings_with_version(cx: &mut TestAppContext) {
async fn test_deserialize_assistant_settings_with_version(cx: &mut TestAppContext) {
let fs = fs::FakeFs::new(cx.executor().clone());
fs.create_dir(paths::settings_file().parent().unwrap())
.await
@@ -831,13 +839,13 @@ mod tests {
cx.update(|cx| {
let test_settings = settings::SettingsStore::test(cx);
cx.set_global(test_settings);
AgentSettings::register(cx);
AssistantSettings::register(cx);
});
cx.update(|cx| {
assert!(!AgentSettings::get_global(cx).using_outdated_settings_version);
assert!(!AssistantSettings::get_global(cx).using_outdated_settings_version);
assert_eq!(
AgentSettings::get_global(cx).default_model,
AssistantSettings::get_global(cx).default_model,
LanguageModelSelection {
provider: "zed.dev".into(),
model: "claude-3-7-sonnet-latest".into(),
@@ -846,32 +854,34 @@ mod tests {
});
cx.update(|cx| {
settings::SettingsStore::global(cx).update_settings_file::<AgentSettings>(
settings::SettingsStore::global(cx).update_settings_file::<AssistantSettings>(
fs.clone(),
|settings, _| {
*settings = AgentSettingsContent {
inner: Some(AgentSettingsContentInner::for_v2(AgentSettingsContentV2 {
default_model: Some(LanguageModelSelection {
provider: "test-provider".into(),
model: "gpt-99".into(),
}),
inline_assistant_model: None,
commit_message_model: None,
thread_summary_model: None,
inline_alternatives: None,
enabled: None,
button: None,
dock: None,
default_width: None,
default_height: None,
enable_experimental_live_diffs: None,
default_profile: None,
profiles: None,
always_allow_tool_actions: None,
notify_when_agent_waiting: None,
stream_edits: None,
single_file_review: None,
})),
*settings = AssistantSettingsContent {
inner: Some(AssistantSettingsContentInner::for_v2(
AssistantSettingsContentV2 {
default_model: Some(LanguageModelSelection {
provider: "test-provider".into(),
model: "gpt-99".into(),
}),
inline_assistant_model: None,
commit_message_model: None,
thread_summary_model: None,
inline_alternatives: None,
enabled: None,
button: None,
dock: None,
default_width: None,
default_height: None,
enable_experimental_live_diffs: None,
default_profile: None,
profiles: None,
always_allow_tool_actions: None,
notify_when_agent_waiting: None,
stream_edits: None,
single_file_review: None,
},
)),
}
},
);
@@ -883,74 +893,13 @@ mod tests {
assert!(raw_settings_value.contains(r#""version": "2""#));
#[derive(Debug, Deserialize)]
struct AgentSettingsTest {
agent: AgentSettingsContent,
struct AssistantSettingsTest {
agent: AssistantSettingsContent,
}
let agent_settings: AgentSettingsTest =
let assistant_settings: AssistantSettingsTest =
serde_json_lenient::from_str(&raw_settings_value).unwrap();
assert!(!agent_settings.agent.is_version_outdated());
}
#[gpui::test]
async fn test_load_settings_from_old_key(cx: &mut TestAppContext) {
let fs = fs::FakeFs::new(cx.executor().clone());
fs.create_dir(paths::settings_file().parent().unwrap())
.await
.unwrap();
cx.update(|cx| {
let mut test_settings = settings::SettingsStore::test(cx);
let user_settings_content = r#"{
"assistant": {
"enabled": true,
"version": "2",
"default_model": {
"provider": "zed.dev",
"model": "gpt-99"
},
}}"#;
test_settings
.set_user_settings(user_settings_content, cx)
.unwrap();
cx.set_global(test_settings);
AgentSettings::register(cx);
});
cx.run_until_parked();
let agent_settings = cx.update(|cx| AgentSettings::get_global(cx).clone());
assert!(agent_settings.enabled);
assert!(!agent_settings.using_outdated_settings_version);
assert_eq!(agent_settings.default_model.model, "gpt-99");
cx.update_global::<SettingsStore, _>(|settings_store, cx| {
settings_store.update_user_settings::<AgentSettings>(cx, |settings| {
*settings = AgentSettingsContent {
inner: Some(AgentSettingsContentInner::for_v2(AgentSettingsContentV2 {
enabled: Some(false),
default_model: Some(LanguageModelSelection {
provider: "xai".to_owned(),
model: "grok".to_owned(),
}),
..Default::default()
})),
};
});
});
cx.run_until_parked();
let settings = cx.update(|cx| SettingsStore::global(cx).raw_user_settings().clone());
#[derive(Debug, Deserialize)]
struct AgentSettingsTest {
assistant: AgentSettingsContent,
agent: Option<serde_json_lenient::Value>,
}
let agent_settings: AgentSettingsTest = serde_json::from_value(settings).unwrap();
assert!(agent_settings.agent.is_none());
assert!(!assistant_settings.agent.is_version_outdated());
}
}

View File

@@ -18,7 +18,7 @@ eval = []
aho-corasick.workspace = true
anyhow.workspace = true
assistant_tool.workspace = true
agent_settings.workspace = true
assistant_settings.workspace = true
buffer_diff.workspace = true
chrono.workspace = true
collections.workspace = true

View File

@@ -24,7 +24,7 @@ mod web_search_tool;
use std::sync::Arc;
use agent_settings::AgentSettings;
use assistant_settings::AssistantSettings;
use assistant_tool::ToolRegistry;
use copy_path_tool::CopyPathTool;
use feature_flags::{AgentStreamEditsFeatureFlag, FeatureFlagAppExt};
@@ -114,7 +114,7 @@ fn register_edit_file_tool(cx: &mut App) {
registry.unregister_tool(EditFileTool);
registry.unregister_tool(StreamingEditFileTool);
if AgentSettings::get_global(cx).stream_edits(cx) {
if AssistantSettings::get_global(cx).stream_edits(cx) {
registry.register_tool(StreamingEditFileTool);
} else {
registry.register_tool(CreateFileTool);
@@ -160,7 +160,7 @@ mod tests {
#[gpui::test]
fn test_builtin_tool_schema_compatibility(cx: &mut App) {
settings::init(cx);
AgentSettings::register(cx);
AssistantSettings::register(cx);
let client = Client::new(
Arc::new(FakeSystemClock::new()),

View File

@@ -269,12 +269,6 @@ impl EditAgent {
let EditParserEvent::OldText(old_text_query) = edit_event? else {
continue;
};
// Skip edits with an empty old text.
if old_text_query.is_empty() {
continue;
}
let old_text_query = SharedString::from(old_text_query);
let (edits_tx, edits_rx) = mpsc::unbounded();
@@ -748,42 +742,6 @@ mod tests {
use unindent::Unindent;
use util::test::{generate_marked_text, marked_text_ranges};
#[gpui::test(iterations = 100)]
async fn test_empty_old_text(cx: &mut TestAppContext, mut rng: StdRng) {
let agent = init_test(cx).await;
let buffer = cx.new(|cx| {
Buffer::local(
indoc! {"
abc
def
ghi
"},
cx,
)
});
let raw_edits = simulate_llm_output(
indoc! {"
<old_text></old_text>
<new_text>jkl</new_text>
<old_text>def</old_text>
<new_text>DEF</new_text>
"},
&mut rng,
cx,
);
let (apply, _events) =
agent.apply_edit_chunks(buffer.clone(), raw_edits, &mut cx.to_async());
apply.await.unwrap();
pretty_assertions::assert_eq!(
buffer.read_with(cx, |buffer, _| buffer.snapshot().text()),
indoc! {"
abc
DEF
ghi
"}
);
}
#[gpui::test(iterations = 100)]
async fn test_indentation(cx: &mut TestAppContext, mut rng: StdRng) {
let agent = init_test(cx).await;

View File

@@ -2737,12 +2737,8 @@ async fn update_user_plan(user_id: UserId, session: &Session) -> Result<()> {
trial_started_at: billing_customer
.and_then(|billing_customer| billing_customer.trial_started_at)
.map(|trial_started_at| trial_started_at.and_utc().timestamp() as u64),
is_usage_based_billing_enabled: if session.is_staff() {
Some(true)
} else {
billing_preferences
.map(|preferences| preferences.model_request_overages_enabled)
},
is_usage_based_billing_enabled: billing_preferences
.map(|preferences| preferences.model_request_overages_enabled),
usage: usage.map(|usage| {
let plan = match plan {
proto::Plan::Free => zed_llm_client::Plan::Free,

View File

@@ -260,7 +260,7 @@ impl StripeBilling {
const BILLING_THRESHOLD_IN_CENTS: i64 = 20 * 100;
let price_per_unit = price.unit_amount.unwrap_or_default();
let _units_for_billing_threshold = BILLING_THRESHOLD_IN_CENTS / price_per_unit;
let units_for_billing_threshold = BILLING_THRESHOLD_IN_CENTS / price_per_unit;
stripe::Subscription::update(
&self.client,
@@ -268,6 +268,9 @@ impl StripeBilling {
stripe::UpdateSubscription {
items: Some(vec![stripe::UpdateSubscriptionItems {
price: Some(price.id.to_string()),
billing_thresholds: Some(stripe::SubscriptionItemBillingThresholds {
usage_gte: Some(units_for_billing_threshold),
}),
..Default::default()
}]),
trial_settings: Some(stripe::UpdateSubscriptionTrialSettings {

View File

@@ -22,9 +22,7 @@ use ui::{
Avatar, Button, Icon, IconButton, IconName, Label, Tab, Tooltip, h_flex, prelude::*, v_flex,
};
use util::{ResultExt, TryFutureExt};
use workspace::notifications::{
Notification as WorkspaceNotification, NotificationId, SuppressEvent,
};
use workspace::notifications::{Notification as WorkspaceNotification, NotificationId};
use workspace::{
Workspace,
dock::{DockPosition, Panel, PanelEvent},
@@ -825,11 +823,6 @@ impl Render for NotificationToast {
IconButton::new("close", IconName::Close)
.on_click(cx.listener(|_, _, _, cx| cx.emit(DismissEvent))),
)
.child(
IconButton::new("suppress", IconName::XCircle)
.tooltip(Tooltip::text("Do not show until restart"))
.on_click(cx.listener(|_, _, _, cx| cx.emit(SuppressEvent))),
)
.on_click(cx.listener(|this, _, window, cx| {
this.focus_notification_panel(window, cx);
cx.emit(DismissEvent);
@@ -838,4 +831,3 @@ impl Render for NotificationToast {
}
impl EventEmitter<DismissEvent> for NotificationToast {}
impl EventEmitter<SuppressEvent> for NotificationToast {}

View File

@@ -35,8 +35,6 @@ pub enum Model {
Gpt4,
#[serde(alias = "gpt-4.1", rename = "gpt-4.1")]
Gpt4_1,
#[serde(alias = "gpt-3.5-turbo", rename = "gpt-3.5-turbo")]
Gpt3_5Turbo,
#[serde(alias = "o1", rename = "o1")]
O1,
#[serde(alias = "o1-mini", rename = "o3-mini")]
@@ -70,7 +68,6 @@ impl Model {
Self::Gpt4o
| Self::Gpt4
| Self::Gpt4_1
| Self::Gpt3_5Turbo
| Self::O3
| Self::O4Mini
| Self::Claude3_5Sonnet
@@ -85,7 +82,6 @@ impl Model {
"gpt-4o" => Ok(Self::Gpt4o),
"gpt-4" => Ok(Self::Gpt4),
"gpt-4.1" => Ok(Self::Gpt4_1),
"gpt-3.5-turbo" => Ok(Self::Gpt3_5Turbo),
"o1" => Ok(Self::O1),
"o3-mini" => Ok(Self::O3Mini),
"o3" => Ok(Self::O3),
@@ -101,7 +97,6 @@ impl Model {
pub fn id(&self) -> &'static str {
match self {
Self::Gpt3_5Turbo => "gpt-3.5-turbo",
Self::Gpt4 => "gpt-4",
Self::Gpt4_1 => "gpt-4.1",
Self::Gpt4o => "gpt-4o",
@@ -119,7 +114,6 @@ impl Model {
pub fn display_name(&self) -> &'static str {
match self {
Self::Gpt3_5Turbo => "GPT-3.5",
Self::Gpt4 => "GPT-4",
Self::Gpt4_1 => "GPT-4.1",
Self::Gpt4o => "GPT-4o",
@@ -140,7 +134,6 @@ impl Model {
Self::Gpt4o => 64_000,
Self::Gpt4 => 32_768,
Self::Gpt4_1 => 128_000,
Self::Gpt3_5Turbo => 12_288,
Self::O3Mini => 64_000,
Self::O1 => 20_000,
Self::O3 => 128_000,

View File

@@ -1,9 +1,9 @@
use anyhow::Result;
use async_trait::async_trait;
use collections::FxHashMap;
use gpui::{App, Global, SharedString};
use gpui::{App, Global};
use parking_lot::RwLock;
use task::{DebugRequest, DebugScenario, SpawnInTerminal, TaskTemplate};
use task::{DebugRequest, SpawnInTerminal};
use crate::adapters::{DebugAdapter, DebugAdapterName};
use std::{collections::BTreeMap, sync::Arc};
@@ -11,17 +11,15 @@ use std::{collections::BTreeMap, sync::Arc};
/// Given a user build configuration, locator creates a fill-in debug target ([DebugRequest]) on behalf of the user.
#[async_trait]
pub trait DapLocator: Send + Sync {
fn name(&self) -> SharedString;
/// Determines whether this locator can generate debug target for given task.
fn create_scenario(&self, build_config: &TaskTemplate, adapter: &str) -> Option<DebugScenario>;
fn accepts(&self, build_config: &SpawnInTerminal) -> bool;
async fn run(&self, build_config: SpawnInTerminal) -> Result<DebugRequest>;
}
#[derive(Default)]
struct DapRegistryState {
adapters: BTreeMap<DebugAdapterName, Arc<dyn DebugAdapter>>,
locators: FxHashMap<SharedString, Arc<dyn DapLocator>>,
locators: FxHashMap<String, Arc<dyn DapLocator>>,
}
#[derive(Clone, Default)]
@@ -50,15 +48,15 @@ impl DapRegistry {
);
}
pub fn add_locator(&self, locator: Arc<dyn DapLocator>) {
let _previous_value = self.0.write().locators.insert(locator.name(), locator);
pub fn add_locator(&self, name: String, locator: Arc<dyn DapLocator>) {
let _previous_value = self.0.write().locators.insert(name, locator);
debug_assert!(
_previous_value.is_none(),
"Attempted to insert a new debug locator when one is already registered"
);
}
pub fn locators(&self) -> FxHashMap<SharedString, Arc<dyn DapLocator>> {
pub fn locators(&self) -> FxHashMap<String, Arc<dyn DapLocator>> {
self.0.read().locators.clone()
}

View File

@@ -621,32 +621,20 @@ impl DebugPanel {
move |_, window, cx| {
let weak_panel = weak_panel.clone();
let past_debug_definition = past_debug_definition.clone();
let workspace = workspace.clone();
window
.spawn(cx, async move |cx| {
let task_contexts = workspace
.update_in(cx, |workspace, window, cx| {
tasks_ui::task_contexts(workspace, window, cx)
})?
.await;
workspace.update_in(cx, |this, window, cx| {
this.toggle_modal(window, cx, |window, cx| {
NewSessionModal::new(
past_debug_definition,
weak_panel,
workspace.clone(),
None,
task_contexts,
window,
cx,
)
});
})?;
Result::<_, anyhow::Error>::Ok(())
})
.detach();
let _ = workspace.update(cx, |this, cx| {
let workspace = cx.weak_entity();
this.toggle_modal(window, cx, |window, cx| {
NewSessionModal::new(
past_debug_definition,
weak_panel,
workspace,
None,
window,
cx,
)
});
});
}
})
.tooltip({

View File

@@ -153,29 +153,16 @@ pub fn init(cx: &mut App) {
let weak_panel = debug_panel.downgrade();
let weak_workspace = cx.weak_entity();
cx.spawn_in(window, async move |this, cx| {
let task_contexts = this
.update_in(cx, |workspace, window, cx| {
tasks_ui::task_contexts(workspace, window, cx)
})?
.await;
this.update_in(cx, |workspace, window, cx| {
workspace.toggle_modal(window, cx, |window, cx| {
NewSessionModal::new(
debug_panel.read(cx).past_debug_definition.clone(),
weak_panel,
weak_workspace,
None,
task_contexts,
window,
cx,
)
});
})?;
Result::<_, anyhow::Error>::Ok(())
})
.detach();
workspace.toggle_modal(window, cx, |window, cx| {
NewSessionModal::new(
debug_panel.read(cx).past_debug_definition.clone(),
weak_panel,
weak_workspace,
None,
window,
cx,
)
});
}
},
)
@@ -185,30 +172,16 @@ pub fn init(cx: &mut App) {
let weak_workspace = cx.weak_entity();
let task_store = workspace.project().read(cx).task_store().clone();
cx.spawn_in(window, async move |this, cx| {
let task_contexts = this
.update_in(cx, |workspace, window, cx| {
tasks_ui::task_contexts(workspace, window, cx)
})?
.await;
this.update_in(cx, |workspace, window, cx| {
workspace.toggle_modal(window, cx, |window, cx| {
NewSessionModal::new(
debug_panel.read(cx).past_debug_definition.clone(),
weak_panel,
weak_workspace,
Some(task_store),
task_contexts,
window,
cx,
)
});
})?;
anyhow::Ok(())
})
.detach()
workspace.toggle_modal(window, cx, |window, cx| {
NewSessionModal::new(
debug_panel.read(cx).past_debug_definition.clone(),
weak_panel,
weak_workspace,
Some(task_store),
window,
cx,
)
});
}
});
})

View File

@@ -1,12 +1,9 @@
use std::{
borrow::Cow,
cmp::Reverse,
ops::Not,
path::{Path, PathBuf},
sync::Arc,
};
use collections::{HashMap, HashSet};
use dap::{
DapRegistry, DebugRequest,
adapters::{DebugAdapterName, DebugTaskDefinition},
@@ -18,9 +15,10 @@ use gpui::{
Subscription, TextStyle, WeakEntity,
};
use picker::{Picker, PickerDelegate, highlighted_match_with_paths::HighlightedMatch};
use project::{TaskContexts, TaskSourceKind, task_store::TaskStore};
use project::{TaskSourceKind, task_store::TaskStore};
use settings::Settings;
use task::{DebugScenario, LaunchRequest};
use tasks_ui::task_contexts;
use theme::ThemeSettings;
use ui::{
ActiveTheme, Button, ButtonCommon, ButtonSize, CheckboxWithLabel, Clickable, Color, Context,
@@ -34,6 +32,7 @@ use workspace::{ModalView, Workspace};
use crate::{attach_modal::AttachModal, debugger_panel::DebugPanel};
#[derive(Clone)]
pub(super) struct NewSessionModal {
workspace: WeakEntity<Workspace>,
debug_panel: WeakEntity<DebugPanel>,
@@ -42,7 +41,6 @@ pub(super) struct NewSessionModal {
initialize_args: Option<serde_json::Value>,
debugger: Option<DebugAdapterName>,
last_selected_profile_name: Option<SharedString>,
task_contexts: Arc<TaskContexts>,
}
fn suggested_label(request: &DebugRequest, debugger: &str) -> SharedString {
@@ -69,7 +67,6 @@ impl NewSessionModal {
debug_panel: WeakEntity<DebugPanel>,
workspace: WeakEntity<Workspace>,
task_store: Option<Entity<TaskStore>>,
task_contexts: TaskContexts,
window: &mut Window,
cx: &mut Context<Self>,
) -> Self {
@@ -108,7 +105,6 @@ impl NewSessionModal {
.unwrap_or(ToggleState::Unselected),
last_selected_profile_name: None,
initialize_args: None,
task_contexts: Arc::new(task_contexts),
}
}
@@ -149,10 +145,22 @@ impl NewSessionModal {
};
let debug_panel = self.debug_panel.clone();
let task_contexts = self.task_contexts.clone();
let workspace = self.workspace.clone();
cx.spawn_in(window, async move |this, cx| {
let task_context = task_contexts.active_context().cloned().unwrap_or_default();
let task_contexts = workspace
.update_in(cx, |this, window, cx| task_contexts(this, window, cx))?
.await;
let worktree_id = task_contexts.worktree();
let task_context = task_contexts
.active_item_context
.map(|(_, _, context)| context)
.or_else(|| {
task_contexts
.active_worktree_context
.map(|(_, context)| context)
})
.unwrap_or_default();
debug_panel.update_in(cx, |debug_panel, window, cx| {
debug_panel.start_session(config, task_context, None, worktree_id, window, cx)
})?;
@@ -190,27 +198,14 @@ impl NewSessionModal {
&self,
window: &mut Window,
cx: &mut Context<Self>,
) -> Option<ui::DropdownMenu> {
) -> ui::DropdownMenu {
let workspace = self.workspace.clone();
let language_registry = self
.workspace
.update(cx, |this, _| this.app_state().languages.clone())
.ok()?;
let weak = cx.weak_entity();
let label = self
.debugger
.as_ref()
.map(|d| d.0.clone())
.unwrap_or_else(|| SELECT_DEBUGGER_LABEL.clone());
let active_buffer_language_name =
self.task_contexts
.active_item_context
.as_ref()
.and_then(|item| {
item.1
.as_ref()
.and_then(|location| location.buffer.read(cx).language()?.name().into())
});
DropdownMenu::new(
"dap-adapter-picker",
label,
@@ -229,50 +224,17 @@ impl NewSessionModal {
}
};
let available_languages = language_registry.language_names();
let mut debugger_to_languages = HashMap::default();
for language in available_languages {
let Some(language) =
language_registry.available_language_for_name(language.as_str())
else {
continue;
};
language.config().debuggers.iter().for_each(|adapter| {
debugger_to_languages
.entry(adapter.clone())
.or_insert_with(HashSet::default)
.insert(language.name());
});
}
let mut available_adapters = workspace
let available_adapters = workspace
.update(cx, |_, cx| DapRegistry::global(cx).enumerate_adapters())
.ok()
.unwrap_or_default();
available_adapters.sort_by_key(|name| {
let languages_for_debugger = debugger_to_languages.get(name.as_ref());
let languages_count =
languages_for_debugger.map_or(0, |languages| languages.len());
let contains_language_of_active_buffer = languages_for_debugger
.zip(active_buffer_language_name.as_ref())
.map_or(false, |(languages, active_buffer_language)| {
languages.contains(active_buffer_language)
});
(
Reverse(contains_language_of_active_buffer),
Reverse(languages_count),
)
});
for adapter in available_adapters.into_iter() {
for adapter in available_adapters {
menu = menu.entry(adapter.0.clone(), None, setter_for_name(adapter.clone()));
}
menu
}),
)
.into()
}
fn debug_config_drop_down_menu(
@@ -629,9 +591,7 @@ impl Render for NewSessionModal {
),
)
.justify_between()
.when(!matches!(self.mode, NewSessionMode::Scenario(_)), |this| {
this.children(self.adapter_drop_down_menu(window, cx))
})
.child(self.adapter_drop_down_menu(window, cx))
.border_color(cx.theme().colors().border_variant)
.border_b_1(),
)

View File

@@ -38,8 +38,8 @@ use serde_json::Value;
use settings::Settings;
use stack_frame_list::StackFrameList;
use task::{
BuildTaskDefinition, DebugScenario, LaunchRequest, ShellBuilder, SpawnInTerminal, TaskContext,
substitute_variables_in_map, substitute_variables_in_str,
DebugScenario, LaunchRequest, TaskContext, substitute_variables_in_map,
substitute_variables_in_str,
};
use terminal_view::TerminalView;
use ui::{
@@ -696,7 +696,6 @@ impl RunningState {
let task_store = project.read(cx).task_store().downgrade();
let weak_project = project.downgrade();
let weak_workspace = workspace.downgrade();
let is_local = project.read(cx).is_local();
cx.spawn_in(window, async move |this, cx| {
let DebugScenario {
adapter,
@@ -707,68 +706,27 @@ impl RunningState {
tcp_connection,
stop_on_entry,
} = scenario;
let build_output = if let Some(build) = build {
let (task, locator_name) = match build {
BuildTaskDefinition::Template {
task_template,
locator_name,
} => (task_template, locator_name),
BuildTaskDefinition::ByName(ref label) => {
let Some(task) = task_store.update(cx, |this, cx| {
this.task_inventory().and_then(|inventory| {
inventory.read(cx).task_template_by_label(
buffer,
worktree_id,
&label,
cx,
)
})
})?
else {
anyhow::bail!("Couldn't find task template for {:?}", build)
};
(task, None)
}
let request = if let Some(request) = request {
request
} else if let Some(build) = build {
let Some(task) = task_store.update(cx, |this, cx| {
this.task_inventory().and_then(|inventory| {
inventory
.read(cx)
.task_template_by_label(buffer, worktree_id, &build, cx)
})
})?
else {
anyhow::bail!("Couldn't find task template for {:?}", build)
};
let locator_name = if let Some(locator_name) = locator_name {
debug_assert!(request.is_none());
Some(locator_name)
} else if request.is_none() {
dap_store
.update(cx, |this, cx| {
this.debug_scenario_for_build_task(task.clone(), adapter.clone(), cx)
.and_then(|scenario| match scenario.build {
Some(BuildTaskDefinition::Template {
locator_name, ..
}) => locator_name,
_ => None,
})
})
.ok()
.flatten()
} else {
None
};
let Some(task) = task.resolve_task("debug-build-task", &task_context) else {
anyhow::bail!("Could not resolve task variables within a debug scenario");
};
let builder = ShellBuilder::new(is_local, &task.resolved.shell);
let command_label = builder.command_label(&task.resolved.command_label);
let (command, args) =
builder.build(task.resolved.command.clone(), &task.resolved.args);
let task_with_shell = SpawnInTerminal {
command_label,
command,
args,
..task.resolved.clone()
};
let terminal = project
.update_in(cx, |project, window, cx| {
project.create_terminal(
TerminalKind::Task(task_with_shell.clone()),
TerminalKind::Task(task.resolved.clone()),
window.window_handle(),
cx,
)
@@ -803,19 +761,9 @@ impl RunningState {
if !exit_status.success() {
anyhow::bail!("Build failed");
}
Some((task.resolved.clone(), locator_name))
} else {
None
};
let request = if let Some(request) = request {
request
} else if let Some((task, locator_name)) = build_output {
let locator_name = locator_name
.ok_or_else(|| anyhow!("Could not find a valid locator for a build task"))?;
dap_store
.update(cx, |this, cx| {
this.run_debug_locator(&locator_name, task, cx)
})?
.update(cx, |this, cx| this.run_debug_locator(task.resolved, cx))?
.await?
} else {
return Err(anyhow!("No request or build provided"));

View File

@@ -5206,27 +5206,20 @@ impl Editor {
let dap_store = project.read(cx).dap_store();
let mut scenarios = vec![];
let resolved_tasks = resolved_tasks.as_ref()?;
let buffer = buffer.read(cx);
let language = buffer.language()?;
let file = buffer.file();
let debug_adapter =
language_settings(language.name().into(), file, cx)
.debuggers
.first()
.map(SharedString::from)
.or_else(|| {
language
.config()
.debuggers
.first()
.map(SharedString::from)
})?;
let debug_adapter: SharedString = buffer
.read(cx)
.language()?
.context_provider()?
.debug_adapter()?
.into();
dap_store.update(cx, |this, cx| {
for (_, task) in &resolved_tasks.templates {
if let Some(scenario) = this
.debug_scenario_for_build_task(
task.original_task().clone(),
task.resolved.clone(),
SharedString::from(
task.original_task().label.clone(),
),
debug_adapter.clone(),
cx,
)

View File

@@ -20,7 +20,7 @@ path = "src/explorer.rs"
[dependencies]
agent.workspace = true
anyhow.workspace = true
agent_settings.workspace = true
assistant_settings.workspace = true
assistant_tool.workspace = true
assistant_tools.workspace = true
async-trait.workspace = true

View File

@@ -11,8 +11,8 @@ use crate::{
assertions::{AssertionsReport, RanAssertion, RanAssertionResult},
};
use agent::{ContextLoadResult, Thread, ThreadEvent};
use agent_settings::AgentProfileId;
use anyhow::{Result, anyhow};
use assistant_settings::AgentProfileId;
use async_trait::async_trait;
use buffer_diff::DiffHunkStatus;
use collections::HashMap;

View File

@@ -1,7 +1,7 @@
use std::path::Path;
use agent_settings::AgentProfileId;
use anyhow::Result;
use assistant_settings::AgentProfileId;
use async_trait::async_trait;
use crate::example::{Example, ExampleContext, ExampleMetadata, JudgeAssertion, LanguageServer};

View File

@@ -1,5 +1,5 @@
use agent_settings::AgentProfileId;
use anyhow::Result;
use assistant_settings::AgentProfileId;
use async_trait::async_trait;
use markdown::PathWithRange;

View File

@@ -1,6 +1,6 @@
use crate::example::{Example, ExampleContext, ExampleMetadata, JudgeAssertion};
use agent_settings::AgentProfileId;
use anyhow::Result;
use assistant_settings::AgentProfileId;
use assistant_tools::StreamingEditFileToolInput;
use async_trait::async_trait;

View File

@@ -1,5 +1,5 @@
use agent_settings::AgentProfileId;
use anyhow::Result;
use assistant_settings::AgentProfileId;
use assistant_tools::FindPathToolInput;
use async_trait::async_trait;
use regex::Regex;

View File

@@ -1,5 +1,5 @@
use agent_settings::AgentProfileId;
use anyhow::Result;
use assistant_settings::AgentProfileId;
use async_trait::async_trait;
use serde::Deserialize;
use std::collections::BTreeMap;

View File

@@ -1,5 +1,5 @@
use agent_settings::AgentProfileId;
use anyhow::Result;
use assistant_settings::AgentProfileId;
use assistant_tool::Tool;
use assistant_tools::{OpenTool, TerminalTool};
use async_trait::async_trait;

View File

@@ -4,7 +4,7 @@ use std::sync::Arc;
use anyhow::Result;
use fs::Fs;
use gpui::{App, Global, ReadGlobal, SharedString, Task};
use language::{BinaryStatus, LanguageConfig, LanguageName, LoadedLanguage};
use language::{BinaryStatus, LanguageMatcher, LanguageName, LoadedLanguage};
use lsp::LanguageServerName;
use parking_lot::RwLock;
@@ -224,7 +224,10 @@ impl ExtensionGrammarProxy for ExtensionHostProxy {
pub trait ExtensionLanguageProxy: Send + Sync + 'static {
fn register_language(
&self,
config: LanguageConfig,
language: LanguageName,
grammar: Option<Arc<str>>,
matcher: LanguageMatcher,
hidden: bool,
load: Arc<dyn Fn() -> Result<LoadedLanguage> + Send + Sync + 'static>,
);
@@ -238,14 +241,17 @@ pub trait ExtensionLanguageProxy: Send + Sync + 'static {
impl ExtensionLanguageProxy for ExtensionHostProxy {
fn register_language(
&self,
language: LanguageConfig,
language: LanguageName,
grammar: Option<Arc<str>>,
matcher: LanguageMatcher,
hidden: bool,
load: Arc<dyn Fn() -> Result<LoadedLanguage> + Send + Sync + 'static>,
) {
let Some(proxy) = self.language_proxy.read().clone() else {
return;
};
proxy.register_language(language, load)
proxy.register_language(language, grammar, matcher, hidden, load)
}
fn remove_languages(

View File

@@ -34,7 +34,8 @@ use gpui::{
};
use http_client::{AsyncBody, HttpClient, HttpClientWithUrl};
use language::{
LanguageConfig, LanguageName, LanguageQueries, LoadedLanguage, QUERY_FILENAME_PREFIXES, Rope,
LanguageConfig, LanguageMatcher, LanguageName, LanguageQueries, LoadedLanguage,
QUERY_FILENAME_PREFIXES, Rope,
};
use node_runtime::NodeRuntime;
use project::ContextProviderWithTasks;
@@ -139,7 +140,7 @@ struct GlobalExtensionStore(Entity<ExtensionStore>);
impl Global for GlobalExtensionStore {}
#[derive(Deserialize, Serialize, Default)]
#[derive(Debug, Deserialize, Serialize, Default, PartialEq, Eq)]
pub struct ExtensionIndex {
pub extensions: BTreeMap<Arc<str>, ExtensionIndexEntry>,
pub themes: BTreeMap<Arc<str>, ExtensionIndexThemeEntry>,
@@ -166,12 +167,13 @@ pub struct ExtensionIndexIconThemeEntry {
pub path: PathBuf,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Deserialize, Serialize)]
pub struct ExtensionIndexLanguageEntry {
pub extension: Arc<str>,
pub path: PathBuf,
#[serde(skip)]
pub config: LanguageConfig,
pub matcher: LanguageMatcher,
pub hidden: bool,
pub grammar: Option<Arc<str>>,
}
actions!(zed, [ReloadExtensions]);
@@ -1013,7 +1015,7 @@ impl ExtensionStore {
/// added to the manifest, or whose files have changed on disk.
fn extensions_updated(
&mut self,
mut new_index: ExtensionIndex,
new_index: ExtensionIndex,
cx: &mut Context<Self>,
) -> Task<()> {
let old_index = &self.extension_index;
@@ -1141,6 +1143,11 @@ impl ExtensionStore {
self.proxy
.remove_languages(&languages_to_remove, &grammars_to_remove);
let languages_to_add = new_index
.languages
.iter()
.filter(|(_, entry)| extensions_to_load.contains(&entry.extension))
.collect::<Vec<_>>();
let mut grammars_to_add = Vec::new();
let mut themes_to_add = Vec::new();
let mut icon_themes_to_add = Vec::new();
@@ -1182,7 +1189,39 @@ impl ExtensionStore {
self.proxy.register_grammars(grammars_to_add);
let installed_dir = self.installed_dir.clone();
for (language_name, language) in languages_to_add {
let mut language_path = self.installed_dir.clone();
language_path.extend([
Path::new(language.extension.as_ref()),
language.path.as_path(),
]);
self.proxy.register_language(
language_name.clone(),
language.grammar.clone(),
language.matcher.clone(),
language.hidden,
Arc::new(move || {
let config = std::fs::read_to_string(language_path.join("config.toml"))?;
let config: LanguageConfig = ::toml::from_str(&config)?;
let queries = load_plugin_queries(&language_path);
let context_provider =
std::fs::read_to_string(language_path.join("tasks.json"))
.ok()
.and_then(|contents| {
let definitions =
serde_json_lenient::from_str(&contents).log_err()?;
Some(Arc::new(ContextProviderWithTasks::new(definitions)) as Arc<_>)
});
Ok(LoadedLanguage {
config,
queries,
context_provider,
toolchain_provider: None,
})
}),
);
}
let fs = self.fs.clone();
let wasm_host = self.wasm_host.clone();
@@ -1193,59 +1232,11 @@ impl ExtensionStore {
.filter_map(|name| new_index.extensions.get(name).cloned())
.collect::<Vec<_>>();
cx.spawn(async move |this, cx| {
let languages_to_add = new_index
.languages
.iter_mut()
.filter(|(_, entry)| extensions_to_load.contains(&entry.extension))
.collect::<Vec<_>>();
for (_, language) in languages_to_add {
let mut language_path = installed_dir.clone();
language_path.extend([
Path::new(language.extension.as_ref()),
language.path.as_path(),
]);
let Some(config) = fs.load(&language_path.join("config.toml")).await.ok() else {
log::error!("Could not load config.toml in {:?}", language_path);
continue;
};
let Some(config) = ::toml::from_str::<LanguageConfig>(&config).ok() else {
log::error!(
"Could not parse language config.toml in {:?}",
language_path
);
continue;
};
language.config = config.clone();
proxy.register_language(
language.config.clone(),
Arc::new(move || {
let queries = load_plugin_queries(&language_path);
let context_provider =
std::fs::read_to_string(language_path.join("tasks.json"))
.ok()
.and_then(|contents| {
let definitions =
serde_json_lenient::from_str(&contents).log_err()?;
Some(Arc::new(ContextProviderWithTasks::new(definitions))
as Arc<_>)
});
self.extension_index = new_index;
cx.notify();
cx.emit(Event::ExtensionsUpdated);
Ok(LoadedLanguage {
config: config.clone(),
queries,
context_provider,
toolchain_provider: None,
})
}),
);
}
this.update(cx, |this, cx| {
this.extension_index = new_index;
cx.notify();
cx.emit(Event::ExtensionsUpdated);
})
.ok();
cx.spawn(async move |this, cx| {
cx.background_spawn({
let fs = fs.clone();
async move {
@@ -1448,7 +1439,9 @@ impl ExtensionStore {
ExtensionIndexLanguageEntry {
extension: extension_id.clone(),
path: relative_path,
config,
matcher: config.matcher,
hidden: config.hidden,
grammar: config.grammar,
},
);
}

View File

@@ -10,7 +10,7 @@ use fs::{FakeFs, Fs, RealFs};
use futures::{AsyncReadExt, StreamExt, io::BufReader};
use gpui::{AppContext as _, SemanticVersion, SharedString, TestAppContext};
use http_client::{FakeHttpClient, Response};
use language::{BinaryStatus, LanguageConfig, LanguageMatcher, LanguageRegistry};
use language::{BinaryStatus, LanguageMatcher, LanguageRegistry};
use lsp::LanguageServerName;
use node_runtime::NodeRuntime;
use parking_lot::Mutex;
@@ -206,14 +206,11 @@ async fn test_extension_store(cx: &mut TestAppContext) {
ExtensionIndexLanguageEntry {
extension: "zed-ruby".into(),
path: "languages/erb".into(),
config: LanguageConfig {
grammar: Some("embedded_template".into()),
hidden: false,
matcher: LanguageMatcher {
path_suffixes: vec!["erb".into()],
first_line_pattern: None,
},
..Default::default()
grammar: Some("embedded_template".into()),
hidden: false,
matcher: LanguageMatcher {
path_suffixes: vec!["erb".into()],
first_line_pattern: None,
},
},
),
@@ -222,14 +219,11 @@ async fn test_extension_store(cx: &mut TestAppContext) {
ExtensionIndexLanguageEntry {
extension: "zed-ruby".into(),
path: "languages/ruby".into(),
config: LanguageConfig {
grammar: Some("ruby".into()),
hidden: false,
matcher: LanguageMatcher {
path_suffixes: vec!["rb".into()],
first_line_pattern: None,
},
..Default::default()
grammar: Some("ruby".into()),
hidden: false,
matcher: LanguageMatcher {
path_suffixes: vec!["rb".into()],
first_line_pattern: None,
},
},
),
@@ -296,24 +290,7 @@ async fn test_extension_store(cx: &mut TestAppContext) {
store.read_with(cx, |store, _| {
let index = &store.extension_index;
assert_eq!(index.extensions, expected_index.extensions);
for ((actual_key, actual_language), (expected_key, expected_language)) in
index.languages.iter().zip(expected_index.languages.iter())
{
assert_eq!(actual_key, expected_key);
assert_eq!(
actual_language.config.grammar,
expected_language.config.grammar
);
assert_eq!(
actual_language.config.matcher,
expected_language.config.matcher
);
assert_eq!(
actual_language.config.hidden,
expected_language.config.hidden
);
}
assert_eq!(index.languages, expected_index.languages);
assert_eq!(index.themes, expected_index.themes);
assert_eq!(
@@ -400,26 +377,8 @@ async fn test_extension_store(cx: &mut TestAppContext) {
cx.executor().advance_clock(RELOAD_DEBOUNCE_DURATION);
store.read_with(cx, |store, _| {
let index = &store.extension_index;
for ((actual_key, actual_language), (expected_key, expected_language)) in
index.languages.iter().zip(expected_index.languages.iter())
{
assert_eq!(actual_key, expected_key);
assert_eq!(
actual_language.config.grammar,
expected_language.config.grammar
);
assert_eq!(
actual_language.config.matcher,
expected_language.config.matcher
);
assert_eq!(
actual_language.config.hidden,
expected_language.config.hidden
);
}
assert_eq!(index.extensions, expected_index.extensions);
assert_eq!(index.languages, expected_index.languages);
assert_eq!(index.themes, expected_index.themes);
assert_eq!(
@@ -456,34 +415,7 @@ async fn test_extension_store(cx: &mut TestAppContext) {
cx.executor().run_until_parked();
store.read_with(cx, |store, _| {
assert_eq!(store.extension_index.extensions, expected_index.extensions);
assert_eq!(store.extension_index.themes, expected_index.themes);
assert_eq!(
store.extension_index.icon_themes,
expected_index.icon_themes
);
for ((actual_key, actual_language), (expected_key, expected_language)) in store
.extension_index
.languages
.iter()
.zip(expected_index.languages.iter())
{
assert_eq!(actual_key, expected_key);
assert_eq!(
actual_language.config.grammar,
expected_language.config.grammar
);
assert_eq!(
actual_language.config.matcher,
expected_language.config.matcher
);
assert_eq!(
actual_language.config.hidden,
expected_language.config.hidden
);
}
assert_eq!(store.extension_index, expected_index);
assert_eq!(
language_registry.language_names(),
["ERB", "Plain Text", "Ruby"]
@@ -520,34 +452,7 @@ async fn test_extension_store(cx: &mut TestAppContext) {
expected_index.languages.remove("ERB");
store.read_with(cx, |store, _| {
assert_eq!(store.extension_index.extensions, expected_index.extensions);
assert_eq!(store.extension_index.themes, expected_index.themes);
assert_eq!(
store.extension_index.icon_themes,
expected_index.icon_themes
);
for ((actual_key, actual_language), (expected_key, expected_language)) in store
.extension_index
.languages
.iter()
.zip(expected_index.languages.iter())
{
assert_eq!(actual_key, expected_key);
assert_eq!(
actual_language.config.grammar,
expected_language.config.grammar
);
assert_eq!(
actual_language.config.matcher,
expected_language.config.matcher
);
assert_eq!(
actual_language.config.hidden,
expected_language.config.hidden
);
}
assert_eq!(store.extension_index, expected_index);
assert_eq!(language_registry.language_names(), ["Plain Text"]);
assert_eq!(language_registry.grammar_names(), []);
});

View File

@@ -149,7 +149,10 @@ impl HeadlessExtensionStore {
config.grammar = None;
this.proxy.register_language(
config.clone(),
config.name.clone(),
None,
config.matcher.clone(),
config.hidden,
Arc::new(move || {
Ok(LoadedLanguage {
config: config.clone(),

View File

@@ -19,7 +19,7 @@ test-support = ["multi_buffer/test-support"]
[dependencies]
anyhow.workspace = true
askpass.workspace = true
agent_settings.workspace = true
assistant_settings.workspace = true
buffer_diff.workspace = true
chrono.workspace = true
collections.workspace = true

View File

@@ -9,9 +9,9 @@ use crate::{branch_picker, picker_prompt, render_remote_button};
use crate::{
git_panel_settings::GitPanelSettings, git_status_icon, repository_selector::RepositorySelector,
};
use agent_settings::AgentSettings;
use anyhow::Result;
use askpass::AskPassDelegate;
use assistant_settings::AssistantSettings;
use db::kvp::KEY_VALUE_STORE;
use editor::{
@@ -481,10 +481,10 @@ impl GitPanel {
hide_task: None,
};
let mut assistant_enabled = AgentSettings::get_global(cx).enabled;
let mut assistant_enabled = AssistantSettings::get_global(cx).enabled;
let _settings_subscription = cx.observe_global::<SettingsStore>(move |_, cx| {
if assistant_enabled != AgentSettings::get_global(cx).enabled {
assistant_enabled = AgentSettings::get_global(cx).enabled;
if assistant_enabled != AssistantSettings::get_global(cx).enabled {
assistant_enabled = AssistantSettings::get_global(cx).enabled;
cx.notify();
}
});
@@ -4053,7 +4053,7 @@ impl GitPanel {
}
fn current_language_model(cx: &Context<'_, GitPanel>) -> Option<Arc<dyn LanguageModel>> {
agent_settings::AgentSettings::get_global(cx)
assistant_settings::AssistantSettings::get_global(cx)
.enabled
.then(|| {
let ConfiguredModel { provider, model } =
@@ -4778,7 +4778,7 @@ mod tests {
cx.update(|cx| {
let settings_store = SettingsStore::test(cx);
cx.set_global(settings_store);
AgentSettings::register(cx);
AssistantSettings::register(cx);
WorktreeSettings::register(cx);
workspace::init_settings(cx);
theme::init(LoadThemes::JustBase, cx);

View File

@@ -496,7 +496,7 @@ pub enum Model {
impl Model {
pub fn default_fast() -> Model {
Model::Gemini15Flash
Model::Gemini20FlashLite
}
pub fn id(&self) -> &str {

View File

@@ -26,7 +26,7 @@ pub use crate::language_settings::EditPredictionsMode;
use crate::language_settings::SoftWrap;
use anyhow::{Context as _, Result, anyhow};
use async_trait::async_trait;
use collections::{HashMap, HashSet, IndexSet};
use collections::{HashMap, HashSet};
use fs::Fs;
use futures::Future;
use gpui::{App, AsyncApp, Entity, SharedString, Task};
@@ -666,7 +666,7 @@ pub struct CodeLabel {
pub filter_range: Range<usize>,
}
#[derive(Clone, Deserialize, JsonSchema, Serialize, Debug)]
#[derive(Clone, Deserialize, JsonSchema)]
pub struct LanguageConfig {
/// Human-readable name of the language.
pub name: LanguageName,
@@ -690,20 +690,12 @@ pub struct LanguageConfig {
pub auto_indent_on_paste: Option<bool>,
/// A regex that is used to determine whether the indentation level should be
/// increased in the following line.
#[serde(
default,
deserialize_with = "deserialize_regex",
serialize_with = "serialize_regex"
)]
#[serde(default, deserialize_with = "deserialize_regex")]
#[schemars(schema_with = "regex_json_schema")]
pub increase_indent_pattern: Option<Regex>,
/// A regex that is used to determine whether the indentation level should be
/// decreased in the following line.
#[serde(
default,
deserialize_with = "deserialize_regex",
serialize_with = "serialize_regex"
)]
#[serde(default, deserialize_with = "deserialize_regex")]
#[schemars(schema_with = "regex_json_schema")]
pub decrease_indent_pattern: Option<Regex>,
/// A list of characters that trigger the automatic insertion of a closing
@@ -756,9 +748,6 @@ pub struct LanguageConfig {
/// A list of characters that Zed should treat as word characters for completion queries.
#[serde(default)]
pub completion_query_characters: HashSet<char>,
/// A list of preferred debuggers for this language.
#[serde(default)]
pub debuggers: IndexSet<String>,
}
#[derive(Clone, Debug, Serialize, Deserialize, Default, JsonSchema)]
@@ -777,7 +766,7 @@ pub struct LanguageMatcher {
}
/// The configuration for JSX tag auto-closing.
#[derive(Clone, Deserialize, JsonSchema, Serialize, Debug)]
#[derive(Clone, Deserialize, JsonSchema)]
pub struct JsxTagAutoCloseConfig {
/// The name of the node for a opening tag
pub open_tag_node_name: String,
@@ -818,7 +807,7 @@ pub struct LanguageScope {
override_id: Option<u32>,
}
#[derive(Clone, Deserialize, Default, Debug, JsonSchema, Serialize)]
#[derive(Clone, Deserialize, Default, Debug, JsonSchema)]
pub struct LanguageConfigOverride {
#[serde(default)]
pub line_comments: Override<Vec<Arc<str>>>,
@@ -883,7 +872,6 @@ impl Default for LanguageConfig {
hidden: false,
jsx_tag_auto_close: None,
completion_query_characters: Default::default(),
debuggers: Default::default(),
}
}
}
@@ -944,7 +932,7 @@ pub struct FakeLspAdapter {
///
/// This struct includes settings for defining which pairs of characters are considered brackets and
/// also specifies any language-specific scopes where these pairs should be ignored for bracket matching purposes.
#[derive(Clone, Debug, Default, JsonSchema, Serialize)]
#[derive(Clone, Debug, Default, JsonSchema)]
pub struct BracketPairConfig {
/// A list of character pairs that should be treated as brackets in the context of a given language.
pub pairs: Vec<BracketPair>,
@@ -994,7 +982,7 @@ impl<'de> Deserialize<'de> for BracketPairConfig {
/// Describes a single bracket pair and how an editor should react to e.g. inserting
/// an opening bracket or to a newline character insertion in between `start` and `end` characters.
#[derive(Clone, Debug, Default, Deserialize, PartialEq, JsonSchema, Serialize)]
#[derive(Clone, Debug, Default, Deserialize, PartialEq, JsonSchema)]
pub struct BracketPair {
/// Starting substring for a bracket.
pub start: String,

View File

@@ -145,24 +145,24 @@ pub enum BinaryStatus {
#[derive(Clone)]
pub struct AvailableLanguage {
id: LanguageId,
config: LanguageConfig,
name: LanguageName,
grammar: Option<Arc<str>>,
matcher: LanguageMatcher,
hidden: bool,
load: Arc<dyn Fn() -> Result<LoadedLanguage> + 'static + Send + Sync>,
loaded: bool,
}
impl AvailableLanguage {
pub fn name(&self) -> LanguageName {
self.config.name.clone()
self.name.clone()
}
pub fn matcher(&self) -> &LanguageMatcher {
&self.config.matcher
&self.matcher
}
pub fn hidden(&self) -> bool {
self.config.hidden
}
pub fn config(&self) -> &LanguageConfig {
&self.config
self.hidden
}
}
@@ -326,7 +326,10 @@ impl LanguageRegistry {
#[cfg(any(feature = "test-support", test))]
pub fn register_test_language(&self, config: LanguageConfig) {
self.register_language(
config.clone(),
config.name.clone(),
config.grammar.clone(),
config.matcher.clone(),
config.hidden,
Arc::new(move || {
Ok(LoadedLanguage {
config: config.clone(),
@@ -485,14 +488,18 @@ impl LanguageRegistry {
/// Adds a language to the registry, which can be loaded if needed.
pub fn register_language(
&self,
config: LanguageConfig,
name: LanguageName,
grammar_name: Option<Arc<str>>,
matcher: LanguageMatcher,
hidden: bool,
load: Arc<dyn Fn() -> Result<LoadedLanguage> + 'static + Send + Sync>,
) {
let state = &mut *self.state.write();
for existing_language in &mut state.available_languages {
if existing_language.config.name == config.name {
existing_language.config = config;
if existing_language.name == name {
existing_language.grammar = grammar_name;
existing_language.matcher = matcher;
existing_language.load = load;
return;
}
@@ -500,8 +507,11 @@ impl LanguageRegistry {
state.available_languages.push(AvailableLanguage {
id: LanguageId::new(),
config,
name,
grammar: grammar_name,
matcher,
load,
hidden,
loaded: false,
});
state.version += 1;
@@ -547,7 +557,7 @@ impl LanguageRegistry {
let mut result = state
.available_languages
.iter()
.filter_map(|l| l.loaded.not().then_some(l.config.name.to_string()))
.filter_map(|l| l.loaded.not().then_some(l.name.to_string()))
.chain(state.languages.iter().map(|l| l.config.name.to_string()))
.collect::<Vec<_>>();
result.sort_unstable_by_key(|language_name| language_name.to_lowercase());
@@ -566,7 +576,10 @@ impl LanguageRegistry {
let mut state = self.state.write();
state.available_languages.push(AvailableLanguage {
id: language.id,
config: language.config.clone(),
name: language.name(),
grammar: language.config.grammar.clone(),
matcher: language.config.matcher.clone(),
hidden: language.config.hidden,
load: Arc::new(|| Err(anyhow!("already loaded"))),
loaded: true,
});
@@ -635,7 +648,7 @@ impl LanguageRegistry {
state
.available_languages
.iter()
.find(|l| l.config.name.0.as_ref() == name)
.find(|l| l.name.0.as_ref() == name)
.cloned()
}
@@ -752,11 +765,8 @@ impl LanguageRegistry {
let current_match_type = best_language_match
.as_ref()
.map_or(LanguageMatchPrecedence::default(), |(_, score)| *score);
let language_score = callback(
&language.config.name,
&language.config.matcher,
current_match_type,
);
let language_score =
callback(&language.name, &language.matcher, current_match_type);
debug_assert!(
language_score.is_none_or(|new_score| new_score > current_match_type),
"Matching callback should only return a better match than the current one"
@@ -804,7 +814,7 @@ impl LanguageRegistry {
let this = self.clone();
let id = language.id;
let name = language.config.name.clone();
let name = language.name.clone();
let language_load = language.load.clone();
self.executor
@@ -1120,7 +1130,7 @@ impl LanguageRegistryState {
self.languages
.retain(|language| !languages_to_remove.contains(&language.name()));
self.available_languages
.retain(|language| !languages_to_remove.contains(&language.config.name));
.retain(|language| !languages_to_remove.contains(&language.name));
self.grammars
.retain(|name, _| !grammars_to_remove.contains(name));
self.version += 1;

View File

@@ -153,8 +153,6 @@ pub struct LanguageSettings {
pub show_completion_documentation: bool,
/// Completion settings for this language.
pub completions: CompletionSettings,
/// Preferred debuggers for this language.
pub debuggers: Vec<String>,
}
impl LanguageSettings {
@@ -553,10 +551,6 @@ pub struct LanguageSettingsContent {
pub show_completion_documentation: Option<bool>,
/// Controls how completions are processed for this language.
pub completions: Option<CompletionSettings>,
/// Preferred debuggers for this language.
///
/// Default: []
pub debuggers: Option<Vec<String>>,
}
/// The behavior of `editor::Rewrap`.

View File

@@ -47,4 +47,7 @@ pub trait ContextProvider: Send + Sync {
fn lsp_task_source(&self) -> Option<LanguageServerName> {
None
}
/// Default debug adapter for a given language.
fn debug_adapter(&self) -> Option<String>;
}

View File

@@ -5,7 +5,7 @@ use std::sync::Arc;
use anyhow::Result;
use extension::{ExtensionGrammarProxy, ExtensionHostProxy, ExtensionLanguageProxy};
use language::{LanguageConfig, LanguageName, LanguageRegistry, LoadedLanguage};
use language::{LanguageMatcher, LanguageName, LanguageRegistry, LoadedLanguage};
pub fn init(
extension_host_proxy: Arc<ExtensionHostProxy>,
@@ -31,10 +31,14 @@ impl ExtensionGrammarProxy for LanguageServerRegistryProxy {
impl ExtensionLanguageProxy for LanguageServerRegistryProxy {
fn register_language(
&self,
language: LanguageConfig,
language: LanguageName,
grammar: Option<Arc<str>>,
matcher: LanguageMatcher,
hidden: bool,
load: Arc<dyn Fn() -> Result<LoadedLanguage> + Send + Sync + 'static>,
) {
self.language_registry.register_language(language, load);
self.language_registry
.register_language(language, grammar, matcher, hidden, load);
}
fn remove_languages(

View File

@@ -70,7 +70,6 @@ impl CloudModel {
LanguageModelAvailability::RequiresPlan(Plan::Free)
}
anthropic::Model::Claude3Opus
| anthropic::Model::Claude3Sonnet
| anthropic::Model::Claude3Haiku
| anthropic::Model::Claude3_5Haiku
| anthropic::Model::Custom { .. } => {
@@ -78,8 +77,7 @@ impl CloudModel {
}
},
Self::OpenAi(model) => match model {
open_ai::Model::ThreePointFiveTurbo
| open_ai::Model::Four
open_ai::Model::Four
| open_ai::Model::FourTurbo
| open_ai::Model::FourOmni
| open_ai::Model::FourOmniMini

View File

@@ -222,7 +222,6 @@ impl LanguageModel for CopilotChatLanguageModel {
CopilotChatModel::Gpt4o => open_ai::Model::FourOmni,
CopilotChatModel::Gpt4 => open_ai::Model::Four,
CopilotChatModel::Gpt4_1 => open_ai::Model::FourPointOne,
CopilotChatModel::Gpt3_5Turbo => open_ai::Model::ThreePointFiveTurbo,
CopilotChatModel::O1 => open_ai::Model::O1,
CopilotChatModel::O3Mini => open_ai::Model::O3Mini,
CopilotChatModel::O3 => open_ai::Model::O3,
@@ -436,7 +435,6 @@ impl CopilotChatLanguageModel {
}
}
let mut tool_called = false;
let mut messages: Vec<ChatMessage> = Vec::new();
for message in request_messages {
let text_content = {
@@ -477,7 +475,6 @@ impl CopilotChatLanguageModel {
let mut tool_calls = Vec::new();
for content in &message.content {
if let MessageContent::ToolUse(tool_use) = content {
tool_called = true;
tool_calls.push(ToolCall {
id: tool_use.id.to_string(),
content: copilot::copilot_chat::ToolCallContent::Function {
@@ -505,7 +502,7 @@ impl CopilotChatLanguageModel {
}
}
let mut tools = request
let tools = request
.tools
.iter()
.map(|tool| Tool::Function {
@@ -515,21 +512,7 @@ impl CopilotChatLanguageModel {
parameters: tool.input_schema.clone(),
},
})
.collect::<Vec<_>>();
// The API will return a Bad Request (with no error message) when tools
// were used previously in the conversation but no tools are provided as
// part of this request. Inserting a dummy tool seems to circumvent this
// error.
if tool_called && tools.is_empty() {
tools.push(Tool::Function {
function: copilot::copilot_chat::Function {
name: "noop".to_string(),
description: "No operation".to_string(),
parameters: serde_json::json!({}),
},
});
}
.collect();
Ok(CopilotChatRequest {
intent: true,

View File

@@ -330,23 +330,41 @@ impl LanguageModel for LmStudioLanguageModel {
let future = self.request_limiter.stream(async move {
let response = stream_chat_completion(http_client.as_ref(), &api_url, request).await?;
// Create a stream mapper to handle content across multiple deltas
let stream_mapper = LmStudioStreamMapper::new();
let stream = response
.map(move |response| {
response.and_then(|fragment| stream_mapper.process_fragment(fragment))
})
.filter_map(|result| async move {
match result {
Ok(Some(content)) => Some(Ok(content)),
Ok(None) => None,
.filter_map(|response| async move {
match response {
Ok(fragment) => {
// Skip empty deltas
if fragment.choices[0].delta.is_object()
&& fragment.choices[0].delta.as_object().unwrap().is_empty()
{
return None;
}
// Try to parse the delta as ChatMessage
if let Ok(chat_message) = serde_json::from_value::<ChatMessage>(
fragment.choices[0].delta.clone(),
) {
let content = match chat_message {
ChatMessage::User { content } => content,
ChatMessage::Assistant { content, .. } => {
content.unwrap_or_default()
}
ChatMessage::System { content } => content,
};
if !content.is_empty() {
Some(Ok(content))
} else {
None
}
} else {
None
}
}
Err(error) => Some(Err(error)),
}
})
.boxed();
Ok(stream)
});
@@ -364,40 +382,6 @@ impl LanguageModel for LmStudioLanguageModel {
}
}
// This will be more useful when we implement tool calling. Currently keeping it empty.
struct LmStudioStreamMapper {}
impl LmStudioStreamMapper {
fn new() -> Self {
Self {}
}
fn process_fragment(&self, fragment: lmstudio::ChatResponse) -> Result<Option<String>> {
// Most of the time, there will be only one choice
let Some(choice) = fragment.choices.first() else {
return Ok(None);
};
// Extract the delta content
if let Ok(delta) =
serde_json::from_value::<lmstudio::ResponseMessageDelta>(choice.delta.clone())
{
if let Some(content) = delta.content {
if !content.is_empty() {
return Ok(Some(content));
}
}
}
// If there's a finish_reason, we're done
if choice.finish_reason.is_some() {
return Ok(None);
}
Ok(None)
}
}
struct ConfigurationView {
state: gpui::Entity<State>,
loading_models_task: Option<Task<()>>,

View File

@@ -11,4 +11,3 @@ brackets = [
{ start = "'", end = "'", close = true, newline = false, not_in = ["string", "comment"] },
{ start = "/*", end = " */", close = true, newline = false, not_in = ["string", "comment"] },
]
debuggers = ["CodeLLDB", "GDB"]

View File

@@ -11,4 +11,3 @@ brackets = [
{ start = "'", end = "'", close = true, newline = false, not_in = ["string", "comment"] },
{ start = "/*", end = " */", close = true, newline = false, not_in = ["string", "comment"] },
]
debuggers = ["CodeLLDB", "GDB"]

View File

@@ -630,6 +630,10 @@ impl ContextProvider for GoContextProvider {
},
]))
}
fn debug_adapter(&self) -> Option<String> {
Some("Delve".into())
}
}
fn extract_subtest_name(input: &str) -> Option<String> {

View File

@@ -14,4 +14,3 @@ brackets = [
]
tab_size = 4
hard_tabs = true
debuggers = ["Delve"]

View File

@@ -19,7 +19,6 @@ word_characters = ["$", "#"]
tab_size = 2
scope_opt_in_language_servers = ["tailwindcss-language-server", "emmet-language-server"]
prettier_parser_name = "babel"
debuggers = ["JavaScript"]
[jsx_tag_auto_close]
open_tag_node_name = "jsx_opening_element"

View File

@@ -325,7 +325,10 @@ fn register_language(
languages.register_lsp_adapter(config.name.clone(), adapter);
}
languages.register_language(
config.clone(),
config.name.clone(),
config.grammar.clone(),
config.matcher.clone(),
config.hidden,
Arc::new(move || {
Ok(LoadedLanguage {
config: config.clone(),

View File

@@ -474,6 +474,10 @@ impl ContextProvider for PythonContextProvider {
Some(TaskTemplates(tasks))
}
fn debug_adapter(&self) -> Option<String> {
Some("Debugpy".into())
}
}
fn selected_test_runner(location: Option<&Arc<dyn language::File>>, cx: &App) -> TestRunner {

View File

@@ -29,4 +29,3 @@ brackets = [
auto_indent_using_last_non_empty_line = false
increase_indent_pattern = "^[^#].*:\\s*$"
decrease_indent_pattern = "^\\s*(else|elif|except|finally)\\b.*:"
debuggers = ["Debugpy"]

View File

@@ -651,6 +651,11 @@ impl ContextProvider for RustContextProvider {
} else {
vec!["run".into()]
};
let build_task_args = if let Some(package_to_run) = package_to_run {
vec!["build".into(), "-p".into(), package_to_run]
} else {
vec!["build".into()]
};
let mut task_templates = vec![
TaskTemplate {
label: format!(
@@ -684,8 +689,8 @@ impl ContextProvider for RustContextProvider {
"test".into(),
"-p".into(),
RUST_PACKAGE_TASK_VARIABLE.template_value(),
"--".into(),
RUST_TEST_NAME_TASK_VARIABLE.template_value(),
"--".into(),
"--nocapture".into(),
],
tags: vec!["rust-test".to_owned()],
@@ -704,9 +709,9 @@ impl ContextProvider for RustContextProvider {
"--doc".into(),
"-p".into(),
RUST_PACKAGE_TASK_VARIABLE.template_value(),
RUST_DOC_TEST_NAME_TASK_VARIABLE.template_value(),
"--".into(),
"--nocapture".into(),
RUST_DOC_TEST_NAME_TASK_VARIABLE.template_value(),
],
tags: vec!["rust-doc-test".to_owned()],
cwd: Some("$ZED_DIRNAME".to_owned()),
@@ -723,7 +728,6 @@ impl ContextProvider for RustContextProvider {
"test".into(),
"-p".into(),
RUST_PACKAGE_TASK_VARIABLE.template_value(),
"--".into(),
RUST_TEST_FRAGMENT_TASK_VARIABLE.template_value(),
],
tags: vec!["rust-mod-test".to_owned()],
@@ -779,6 +783,37 @@ impl ContextProvider for RustContextProvider {
cwd: Some("$ZED_DIRNAME".to_owned()),
..TaskTemplate::default()
},
TaskTemplate {
label: format!(
"Build {} {} (package: {})",
RUST_BIN_KIND_TASK_VARIABLE.template_value(),
RUST_BIN_NAME_TASK_VARIABLE.template_value(),
RUST_PACKAGE_TASK_VARIABLE.template_value(),
),
cwd: Some("$ZED_DIRNAME".to_owned()),
command: "cargo".into(),
args: build_task_args,
tags: vec!["rust-main".to_owned()],
..TaskTemplate::default()
},
TaskTemplate {
label: format!(
"Build Test '{}' (package: {})",
RUST_TEST_NAME_TASK_VARIABLE.template_value(),
RUST_PACKAGE_TASK_VARIABLE.template_value(),
),
command: "cargo".into(),
args: vec![
"test".into(),
"-p".into(),
RUST_PACKAGE_TASK_VARIABLE.template_value(),
RUST_TEST_NAME_TASK_VARIABLE.template_value(),
"--no-run".into(),
],
tags: vec!["rust-test".to_owned()],
cwd: Some("$ZED_DIRNAME".to_owned()),
..TaskTemplate::default()
},
];
if let Some(custom_target_dir) = custom_target_dir {
@@ -803,6 +838,10 @@ impl ContextProvider for RustContextProvider {
fn lsp_task_source(&self) -> Option<LanguageServerName> {
Some(SERVER_NAME)
}
fn debug_adapter(&self) -> Option<String> {
Some("CodeLLDB".to_owned())
}
}
/// Part of the data structure of Cargo metadata

View File

@@ -15,4 +15,3 @@ brackets = [
{ start = "/*", end = " */", close = true, newline = false, not_in = ["string", "comment"] },
]
collapsed_placeholder = " /* ... */ "
debuggers = ["CodeLLDB", "GDB"]

View File

@@ -17,7 +17,6 @@ word_characters = ["#", "$"]
scope_opt_in_language_servers = ["tailwindcss-language-server", "emmet-language-server"]
prettier_parser_name = "typescript"
tab_size = 2
debuggers = ["JavaScript"]
[jsx_tag_auto_close]
open_tag_node_name = "jsx_opening_element"

View File

@@ -17,7 +17,6 @@ brackets = [
word_characters = ["#", "$"]
prettier_parser_name = "typescript"
tab_size = 2
debuggers = ["JavaScript"]
[overrides.string]
completion_query_characters = ["."]

View File

@@ -221,14 +221,6 @@ pub enum CompatibilityType {
Mlx,
}
#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)]
pub struct ResponseMessageDelta {
pub role: Option<Role>,
pub content: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub tool_calls: Option<Vec<ToolCallChunk>>,
}
pub async fn complete(
client: &dyn HttpClient,
api_url: &str,

View File

@@ -56,8 +56,6 @@ impl From<Role> for String {
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq, EnumIter)]
pub enum Model {
#[serde(rename = "gpt-3.5-turbo", alias = "gpt-3.5-turbo")]
ThreePointFiveTurbo,
#[serde(rename = "gpt-4", alias = "gpt-4")]
Four,
#[serde(rename = "gpt-4-turbo", alias = "gpt-4-turbo")]
@@ -104,7 +102,6 @@ impl Model {
pub fn from_id(id: &str) -> Result<Self> {
match id {
"gpt-3.5-turbo" => Ok(Self::ThreePointFiveTurbo),
"gpt-4" => Ok(Self::Four),
"gpt-4-turbo-preview" => Ok(Self::FourTurbo),
"gpt-4o" => Ok(Self::FourOmni),
@@ -124,7 +121,6 @@ impl Model {
pub fn id(&self) -> &str {
match self {
Self::ThreePointFiveTurbo => "gpt-3.5-turbo",
Self::Four => "gpt-4",
Self::FourTurbo => "gpt-4-turbo",
Self::FourOmni => "gpt-4o",
@@ -144,7 +140,6 @@ impl Model {
pub fn display_name(&self) -> &str {
match self {
Self::ThreePointFiveTurbo => "gpt-3.5-turbo",
Self::Four => "gpt-4",
Self::FourTurbo => "gpt-4-turbo",
Self::FourOmni => "gpt-4o",
@@ -166,7 +161,6 @@ impl Model {
pub fn max_token_count(&self) -> usize {
match self {
Self::ThreePointFiveTurbo => 16_385,
Self::Four => 8_192,
Self::FourTurbo => 128_000,
Self::FourOmni => 128_000,
@@ -198,8 +192,7 @@ impl Model {
/// If the model does not support the parameter, do not pass it up, or the API will return an error.
pub fn supports_parallel_tool_calls(&self) -> bool {
match self {
Self::ThreePointFiveTurbo
| Self::Four
Self::Four
| Self::FourTurbo
| Self::FourOmni
| Self::FourOmniMini

View File

@@ -46,7 +46,7 @@ use std::{
path::{Path, PathBuf},
sync::{Arc, Once},
};
use task::{DebugScenario, SpawnInTerminal, TaskTemplate};
use task::{DebugScenario, SpawnInTerminal};
use util::{ResultExt as _, merge_json_value_into};
use worktree::Worktree;
@@ -99,7 +99,8 @@ impl DapStore {
pub fn init(client: &AnyProtoClient, cx: &mut App) {
static ADD_LOCATORS: Once = Once::new();
ADD_LOCATORS.call_once(|| {
DapRegistry::global(cx).add_locator(Arc::new(locators::cargo::CargoLocator {}))
DapRegistry::global(cx)
.add_locator("cargo".into(), Arc::new(locators::cargo::CargoLocator {}))
});
client.add_entity_request_handler(Self::handle_run_debug_locator);
client.add_entity_request_handler(Self::handle_get_debug_adapter_binary);
@@ -281,38 +282,78 @@ impl DapStore {
pub fn debug_scenario_for_build_task(
&self,
build: TaskTemplate,
mut build: SpawnInTerminal,
unresoved_label: SharedString,
adapter: SharedString,
cx: &mut App,
) -> Option<DebugScenario> {
build.args = build
.args
.into_iter()
.map(|arg| {
if arg.starts_with("$") {
arg.strip_prefix("$")
.and_then(|arg| build.env.get(arg).map(ToOwned::to_owned))
.unwrap_or_else(|| arg)
} else {
arg
}
})
.collect();
DapRegistry::global(cx)
.locators()
.values()
.find_map(|locator| locator.create_scenario(&build, &adapter))
.find(|locator| locator.accepts(&build))
.map(|_| DebugScenario {
adapter,
label: format!("Debug `{}`", build.label).into(),
build: Some(unresoved_label),
request: None,
initialize_args: None,
tcp_connection: None,
stop_on_entry: None,
})
}
pub fn run_debug_locator(
&mut self,
locator_name: &str,
build_command: SpawnInTerminal,
mut build_command: SpawnInTerminal,
cx: &mut Context<Self>,
) -> Task<Result<DebugRequest>> {
match &self.mode {
DapStoreMode::Local(_) => {
// Pre-resolve args with existing environment.
let locators = DapRegistry::global(cx).locators();
let locator = locators.get(locator_name);
if let Some(locator) = locator.cloned() {
cx.background_spawn(async move {
let result = locator
.run(build_command.clone())
.await
.log_with_level(log::Level::Error);
if let Some(result) = result {
return Ok(result);
build_command.args = build_command
.args
.into_iter()
.map(|arg| {
if arg.starts_with("$") {
arg.strip_prefix("$")
.and_then(|arg| build_command.env.get(arg).map(ToOwned::to_owned))
.unwrap_or_else(|| arg)
} else {
arg
}
})
.collect();
let locators = DapRegistry::global(cx)
.locators()
.values()
.filter(|locator| locator.accepts(&build_command))
.cloned()
.collect::<Vec<_>>();
if !locators.is_empty() {
cx.background_spawn(async move {
for locator in locators {
let result = locator
.run(build_command.clone())
.await
.log_with_level(log::Level::Error);
if let Some(result) = result {
return Ok(result);
}
}
Err(anyhow!(
"None of the locators for task `{}` completed successfully",
build_command.label
@@ -329,7 +370,6 @@ impl DapStore {
let request = ssh.upstream_client.request(proto::RunDebugLocators {
project_id: ssh.upstream_project_id,
build_command: Some(build_command.to_proto()),
locator: locator_name.to_owned(),
});
cx.background_spawn(async move {
let response = request.await?;
@@ -749,11 +789,8 @@ impl DapStore {
.build_command
.ok_or_else(|| anyhow!("missing definition"))?;
let build_task = SpawnInTerminal::from_proto(task);
let locator = envelope.payload.locator;
let request = this
.update(&mut cx, |this, cx| {
this.run_debug_locator(&locator, build_task, cx)
})?
.update(&mut cx, |this, cx| this.run_debug_locator(build_task, cx))?
.await?;
Ok(request.to_proto())

View File

@@ -1,13 +1,12 @@
use anyhow::{Result, anyhow};
use async_trait::async_trait;
use dap::{DapLocator, DebugRequest};
use gpui::SharedString;
use serde_json::Value;
use smol::{
io::AsyncReadExt,
process::{Command, Stdio},
};
use task::{BuildTaskDefinition, DebugScenario, ShellBuilder, SpawnInTerminal, TaskTemplate};
use task::SpawnInTerminal;
pub(crate) struct CargoLocator;
@@ -38,51 +37,18 @@ async fn find_best_executable(executables: &[String], test_name: &str) -> Option
}
#[async_trait]
impl DapLocator for CargoLocator {
fn name(&self) -> SharedString {
SharedString::new_static("rust-cargo-locator")
}
fn create_scenario(&self, build_config: &TaskTemplate, adapter: &str) -> Option<DebugScenario> {
fn accepts(&self, build_config: &SpawnInTerminal) -> bool {
if build_config.command != "cargo" {
return None;
return false;
}
let mut task_template = build_config.clone();
let cargo_action = task_template.args.first_mut()?;
if cargo_action == "check" {
return None;
let Some(command) = build_config.args.first().map(|s| s.as_str()) else {
return false;
};
if matches!(command, "check" | "run") {
return false;
}
match cargo_action.as_ref() {
"run" => {
*cargo_action = "build".to_owned();
}
"test" | "bench" => {
let delimiter = task_template
.args
.iter()
.position(|arg| arg == "--")
.unwrap_or(task_template.args.len());
if !task_template.args[..delimiter]
.iter()
.any(|arg| arg == "--no-run")
{
task_template.args.insert(delimiter, "--no-run".to_owned());
}
}
_ => {}
}
let label = format!("Debug `{}`", build_config.label);
Some(DebugScenario {
adapter: adapter.to_owned().into(),
label: SharedString::from(label),
build: Some(BuildTaskDefinition::Template {
task_template,
locator_name: Some(self.name()),
}),
request: None,
initialize_args: None,
tcp_connection: None,
stop_on_entry: None,
})
!matches!(command, "test" | "bench")
|| build_config.args.iter().any(|arg| arg == "--no-run")
}
async fn run(&self, build_config: SpawnInTerminal) -> Result<DebugRequest> {
@@ -91,19 +57,10 @@ impl DapLocator for CargoLocator {
"Couldn't get cwd from debug config which is needed for locators"
));
};
let builder = ShellBuilder::new(true, &build_config.shell).non_interactive();
let (program, args) = builder.build(
"cargo".into(),
&build_config
.args
.iter()
.cloned()
.take_while(|arg| arg != "--")
.chain(Some("--message-format=json".to_owned()))
.collect(),
);
let mut child = Command::new(program)
.args(args)
let mut child = Command::new("cargo")
.args(&build_config.args)
.arg("--message-format=json")
.envs(build_config.env.iter().map(|(k, v)| (k.clone(), v.clone())))
.current_dir(cwd)
.stdout(Stdio::piped())
@@ -132,6 +89,7 @@ impl DapLocator for CargoLocator {
if executables.is_empty() {
return Err(anyhow!("Couldn't get executable in cargo locator"));
};
let is_test = build_config.args.first().map_or(false, |arg| arg == "test");
let mut test_name = None;

View File

@@ -808,6 +808,10 @@ impl ContextProvider for BasicContextProvider {
Task::ready(Ok(task_variables))
}
fn debug_adapter(&self) -> Option<String> {
None
}
}
/// A ContextProvider that doesn't provide any task variables on it's own, though it has some associated tasks.
@@ -831,6 +835,10 @@ impl ContextProvider for ContextProviderWithTasks {
) -> Option<TaskTemplates> {
Some(self.templates.clone())
}
fn debug_adapter(&self) -> Option<String> {
None
}
}
#[cfg(test)]

View File

@@ -580,7 +580,6 @@ message DebugAdapterBinary {
message RunDebugLocators {
uint64 project_id = 1;
SpawnInTerminal build_command = 2;
string locator = 3;
}
message DebugRequest {

View File

@@ -37,8 +37,6 @@ pub trait Settings: 'static + Send + Sync {
/// from the root object.
const KEY: Option<&'static str>;
const FALLBACK_KEY: Option<&'static str> = None;
/// The name of the keys in the [`FileContent`](Self::FileContent) that should
/// always be written to a settings file, even if their value matches the default
/// value.
@@ -233,13 +231,7 @@ struct SettingValue<T> {
trait AnySettingValue: 'static + Send + Sync {
fn key(&self) -> Option<&'static str>;
fn setting_type_name(&self) -> &'static str;
fn deserialize_setting(&self, json: &Value) -> Result<DeserializedSetting> {
self.deserialize_setting_with_key(json).1
}
fn deserialize_setting_with_key(
&self,
json: &Value,
) -> (Option<&'static str>, Result<DeserializedSetting>);
fn deserialize_setting(&self, json: &Value) -> Result<DeserializedSetting>;
fn load_setting(
&self,
sources: SettingsSources<DeserializedSetting>,
@@ -545,8 +537,7 @@ impl SettingsStore {
.get(&setting_type_id)
.unwrap_or_else(|| panic!("unregistered setting type {}", type_name::<T>()));
let raw_settings = parse_json_with_comments::<Value>(text).unwrap_or_default();
let (key, deserialized_setting) = setting.deserialize_setting_with_key(&raw_settings);
let old_content = match deserialized_setting {
let old_content = match setting.deserialize_setting(&raw_settings) {
Ok(content) => content.0.downcast::<T::FileContent>().unwrap(),
Err(_) => Box::<<T as Settings>::FileContent>::default(),
};
@@ -557,7 +548,7 @@ impl SettingsStore {
let new_value = serde_json::to_value(new_content).unwrap();
let mut key_path = Vec::new();
if let Some(key) = key {
if let Some(key) = T::KEY {
key_path.push(key);
}
@@ -1162,27 +1153,17 @@ impl<T: Settings> AnySettingValue for SettingValue<T> {
)?))
}
fn deserialize_setting_with_key(
&self,
mut json: &Value,
) -> (Option<&'static str>, Result<DeserializedSetting>) {
let mut key = None;
if let Some(k) = T::KEY {
if let Some(value) = json.get(k) {
fn deserialize_setting(&self, mut json: &Value) -> Result<DeserializedSetting> {
if let Some(key) = T::KEY {
if let Some(value) = json.get(key) {
json = value;
key = Some(k);
} else if let Some((k, value)) = T::FALLBACK_KEY.and_then(|k| Some((k, json.get(k)?))) {
json = value;
key = Some(k);
} else {
let value = T::FileContent::default();
return (T::KEY, Ok(DeserializedSetting(Box::new(value))));
return Ok(DeserializedSetting(Box::new(value)));
}
}
let value = T::FileContent::deserialize(json)
.map(|value| DeserializedSetting(Box::new(value)))
.map_err(anyhow::Error::from);
(key, value)
let value = T::FileContent::deserialize(json)?;
Ok(DeserializedSetting(Box::new(value)))
}
fn value_for_path(&self, path: Option<SettingsLocation>) -> &dyn Any {
@@ -1230,8 +1211,7 @@ impl<T: Settings> AnySettingValue for SettingValue<T> {
text: &mut String,
edits: &mut Vec<(Range<usize>, String)>,
) {
let (key, deserialized_setting) = self.deserialize_setting_with_key(raw_settings);
let old_content = match deserialized_setting {
let old_content = match self.deserialize_setting(raw_settings) {
Ok(content) => content.0.downcast::<T::FileContent>().unwrap(),
Err(_) => Box::<<T as Settings>::FileContent>::default(),
};
@@ -1242,7 +1222,7 @@ impl<T: Settings> AnySettingValue for SettingValue<T> {
let new_value = serde_json::to_value(new_content).unwrap();
let mut key_path = Vec::new();
if let Some(key) = key {
if let Some(key) = T::KEY {
key_path.push(key);
}

View File

@@ -6,8 +6,6 @@ use serde::{Deserialize, Serialize};
use std::path::PathBuf;
use std::{net::Ipv4Addr, path::Path};
use crate::TaskTemplate;
/// Represents the host information of the debug adapter
#[derive(Default, Deserialize, Serialize, PartialEq, Eq, JsonSchema, Clone, Debug)]
pub struct TcpArgumentsTemplate {
@@ -173,18 +171,6 @@ impl From<AttachRequest> for DebugRequest {
}
}
#[derive(Deserialize, Serialize, PartialEq, Eq, JsonSchema, Clone, Debug)]
#[serde(untagged)]
#[allow(clippy::large_enum_variant)]
pub enum BuildTaskDefinition {
ByName(SharedString),
Template {
#[serde(flatten)]
task_template: TaskTemplate,
#[serde(skip)]
locator_name: Option<SharedString>,
},
}
/// This struct represent a user created debug task
#[derive(Deserialize, Serialize, PartialEq, Eq, JsonSchema, Clone, Debug)]
#[serde(rename_all = "snake_case")]
@@ -194,7 +180,7 @@ pub struct DebugScenario {
pub label: SharedString,
/// A task to run prior to spawning the debuggee.
#[serde(default)]
pub build: Option<BuildTaskDefinition>,
pub build: Option<SharedString>,
#[serde(flatten)]
pub request: Option<DebugRequest>,
/// Additional initialization arguments to be sent on DAP initialization

View File

@@ -16,8 +16,7 @@ use std::path::PathBuf;
use std::str::FromStr;
pub use debug_format::{
AttachRequest, BuildTaskDefinition, DebugRequest, DebugScenario, DebugTaskFile, LaunchRequest,
TcpArgumentsTemplate,
AttachRequest, DebugRequest, DebugScenario, DebugTaskFile, LaunchRequest, TcpArgumentsTemplate,
};
pub use task_template::{
DebugArgsRequest, HideStrategy, RevealStrategy, TaskTemplate, TaskTemplates,
@@ -342,7 +341,6 @@ enum WindowsShellType {
pub struct ShellBuilder {
program: String,
args: Vec<String>,
interactive: bool,
}
pub static DEFAULT_REMOTE_SHELL: &str = "\"${SHELL:-sh}\"";
@@ -361,15 +359,7 @@ impl ShellBuilder {
Shell::Program(shell) => (shell.clone(), Vec::new()),
Shell::WithArguments { program, args, .. } => (program.clone(), args.clone()),
};
Self {
program,
args,
interactive: true,
}
}
pub fn non_interactive(mut self) -> Self {
self.interactive = false;
self
Self { program, args }
}
}
@@ -377,8 +367,7 @@ impl ShellBuilder {
impl ShellBuilder {
/// Returns the label to show in the terminal tab
pub fn command_label(&self, command_label: &str) -> String {
let interactivity = self.interactive.then_some("-i ").unwrap_or_default();
format!("{} {interactivity}-c '{}'", self.program, command_label)
format!("{} -i -c '{}'", self.program, command_label)
}
/// Returns the program and arguments to run this task in a shell.
@@ -390,12 +379,8 @@ impl ShellBuilder {
command.push_str(&arg);
command
});
self.args.extend(
self.interactive
.then(|| "-i".to_owned())
.into_iter()
.chain(["-c".to_owned(), combined_command]),
);
self.args
.extend(["-i".to_owned(), "-c".to_owned(), combined_command]);
(self.program, self.args)
}

View File

@@ -208,10 +208,7 @@ impl Render for TitleBar {
.on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation()),
)
.child(self.render_collaborator_list(window, cx))
.when(
TitleBarSettings::get_global(cx).show_onboarding_banner,
|title_bar| title_bar.child(self.banner.clone()),
)
.child(self.banner.clone())
.child(
h_flex()
.gap_1()
@@ -726,7 +723,7 @@ impl TitleBar {
h_flex()
.gap_0p5()
.children(
TitleBarSettings::get_global(cx)
workspace::WorkspaceSettings::get_global(cx)
.show_user_picture
.then(|| Avatar::new(user.avatar_uri.clone())),
)

View File

@@ -6,8 +6,6 @@ use settings::{Settings, SettingsSources};
#[derive(Deserialize, Debug, Clone, Copy, PartialEq)]
pub struct TitleBarSettings {
pub show_branch_icon: bool,
pub show_onboarding_banner: bool,
pub show_user_picture: bool,
}
#[derive(Clone, Default, Serialize, Deserialize, JsonSchema, Debug)]
@@ -16,14 +14,6 @@ pub struct TitleBarSettingsContent {
///
/// Default: false
pub show_branch_icon: Option<bool>,
/// Whether to show onboarding banners in the title bar.
///
/// Default: true
pub show_onboarding_banner: Option<bool>,
/// Whether to show user avatar in the title bar.
///
/// Default: true
pub show_user_picture: Option<bool>,
}
impl Settings for TitleBarSettings {

View File

@@ -253,7 +253,7 @@ impl RenderOnce for ModalFooter {
.mt_4()
.p(DynamicSpacing::Base08.rems(cx))
.flex_none()
.justify_between()
.justify_end()
.gap_1()
.border_t_1()
.border_color(cx.theme().colors().border_variant)

View File

@@ -43,7 +43,6 @@ http_client.workspace = true
itertools.workspace = true
language.workspace = true
log.workspace = true
menu.workspace = true
node_runtime.workspace = true
parking_lot.workspace = true
postage.workspace = true

View File

@@ -29,7 +29,7 @@ impl std::ops::DerefMut for Notifications {
}
}
#[derive(Debug, Eq, PartialEq, Clone, Hash)]
#[derive(Debug, PartialEq, Clone)]
pub enum NotificationId {
Unique(TypeId),
Composite(TypeId, ElementId),
@@ -54,12 +54,7 @@ impl NotificationId {
}
}
pub trait Notification:
EventEmitter<DismissEvent> + EventEmitter<SuppressEvent> + Focusable + Render
{
}
pub struct SuppressEvent;
pub trait Notification: EventEmitter<DismissEvent> + Focusable + Render {}
impl Workspace {
#[cfg(any(test, feature = "test-support"))]
@@ -86,13 +81,6 @@ impl Workspace {
}
})
.detach();
cx.subscribe(&notification, {
let id = id.clone();
move |workspace: &mut Workspace, _, _: &SuppressEvent, cx| {
workspace.suppress_notification(&id, cx);
}
})
.detach();
notification.into()
});
}
@@ -108,9 +96,6 @@ impl Workspace {
cx: &mut Context<Self>,
build_notification: impl FnOnce(&mut Context<Self>) -> AnyView,
) {
if self.suppressed_notifications.contains(id) {
return;
}
self.dismiss_notification(id, cx);
self.notifications
.push((id.clone(), build_notification(cx)));
@@ -187,11 +172,6 @@ impl Workspace {
cx.notify();
}
pub fn suppress_notification(&mut self, id: &NotificationId, cx: &mut Context<Self>) {
self.dismiss_notification(id, cx);
self.suppressed_notifications.insert(id.clone());
}
pub fn show_initial_notifications(&mut self, cx: &mut Context<Self>) {
// Allow absence of the global so that tests don't need to initialize it.
let app_notifications = GLOBAL_APP_NOTIFICATIONS
@@ -288,14 +268,6 @@ impl Render for LanguageServerPrompt {
)
.child(
h_flex()
.gap_2()
.child(
IconButton::new("suppress", IconName::XCircle)
.tooltip(Tooltip::text("Do not show until restart"))
.on_click(
cx.listener(|_, _, _, cx| cx.emit(SuppressEvent)),
),
)
.child(
IconButton::new("copy", IconName::Copy)
.on_click({
@@ -333,7 +305,6 @@ impl Render for LanguageServerPrompt {
}
impl EventEmitter<DismissEvent> for LanguageServerPrompt {}
impl EventEmitter<SuppressEvent> for LanguageServerPrompt {}
fn workspace_error_notification_id() -> NotificationId {
struct WorkspaceErrorNotification;
@@ -430,7 +401,6 @@ impl Focusable for ErrorMessagePrompt {
}
impl EventEmitter<DismissEvent> for ErrorMessagePrompt {}
impl EventEmitter<SuppressEvent> for ErrorMessagePrompt {}
impl Notification for ErrorMessagePrompt {}
@@ -441,9 +411,9 @@ pub mod simple_message_notification {
AnyElement, DismissEvent, EventEmitter, FocusHandle, Focusable, ParentElement, Render,
SharedString, Styled, div,
};
use ui::{Tooltip, prelude::*};
use ui::prelude::*;
use super::{Notification, SuppressEvent};
use super::Notification;
pub struct MessageNotification {
focus_handle: FocusHandle,
@@ -459,7 +429,6 @@ pub mod simple_message_notification {
more_info_message: Option<SharedString>,
more_info_url: Option<Arc<str>>,
show_close_button: bool,
show_suppress_button: bool,
title: Option<SharedString>,
}
@@ -470,7 +439,6 @@ pub mod simple_message_notification {
}
impl EventEmitter<DismissEvent> for MessageNotification {}
impl EventEmitter<SuppressEvent> for MessageNotification {}
impl Notification for MessageNotification {}
@@ -502,7 +470,6 @@ pub mod simple_message_notification {
more_info_message: None,
more_info_url: None,
show_close_button: true,
show_suppress_button: true,
title: None,
focus_handle: cx.focus_handle(),
}
@@ -601,11 +568,6 @@ pub mod simple_message_notification {
self
}
pub fn show_suppress_button(mut self, show: bool) -> Self {
self.show_suppress_button = show;
self
}
pub fn with_title<S>(mut self, title: S) -> Self
where
S: Into<SharedString>,
@@ -635,26 +597,12 @@ pub mod simple_message_notification {
})
.child(div().max_w_96().child((self.build_content)(window, cx))),
)
.child(
h_flex()
.gap_2()
.when(self.show_suppress_button, |this| {
this.child(
IconButton::new("suppress", IconName::XCircle)
.tooltip(Tooltip::text("Do not show until restart"))
.on_click(cx.listener(|_, _, _, cx| {
cx.emit(SuppressEvent);
})),
)
})
.when(self.show_close_button, |this| {
this.child(
IconButton::new("close", IconName::Close).on_click(
cx.listener(|this, _, _, cx| this.dismiss(cx)),
),
)
}),
),
.when(self.show_close_button, |this| {
this.child(
IconButton::new("close", IconName::Close)
.on_click(cx.listener(|this, _, _, cx| this.dismiss(cx))),
)
}),
)
.child(
h_flex()

View File

@@ -52,8 +52,7 @@ use language::{Buffer, LanguageRegistry, Rope};
pub use modal_layer::*;
use node_runtime::NodeRuntime;
use notifications::{
DetachAndPromptErr, Notifications, dismiss_app_notification,
simple_message_notification::MessageNotification,
DetachAndPromptErr, Notifications, simple_message_notification::MessageNotification,
};
pub use pane::*;
pub use pane_group::*;
@@ -180,7 +179,6 @@ actions!(
SaveAs,
SaveWithoutFormat,
ShutdownDebugAdapters,
SuppressNotification,
ToggleBottomDock,
ToggleCenteredLayout,
ToggleLeftDock,
@@ -923,7 +921,6 @@ pub struct Workspace {
toast_layer: Entity<ToastLayer>,
titlebar_item: Option<AnyView>,
notifications: Notifications,
suppressed_notifications: HashSet<NotificationId>,
project: Entity<Project>,
follower_states: HashMap<CollaboratorId, FollowerState>,
last_leaders_by_pane: HashMap<WeakEntity<Pane>, CollaboratorId>,
@@ -1248,8 +1245,7 @@ impl Workspace {
modal_layer,
toast_layer,
titlebar_item: None,
notifications: Notifications::default(),
suppressed_notifications: HashSet::default(),
notifications: Default::default(),
left_dock,
bottom_dock,
bottom_dock_layout,
@@ -5305,20 +5301,12 @@ impl Workspace {
workspace.clear_all_notifications(cx);
},
))
.on_action(cx.listener(
|workspace: &mut Workspace, _: &SuppressNotification, _, cx| {
if let Some((notification_id, _)) = workspace.notifications.pop() {
workspace.suppress_notification(&notification_id, cx);
}
},
))
.on_action(cx.listener(
|workspace: &mut Workspace, _: &ReopenClosedItem, window, cx| {
workspace.reopen_closed_item(window, cx).detach();
},
))
.on_action(cx.listener(Workspace::toggle_centered_layout))
.on_action(cx.listener(Workspace::cancel))
}
#[cfg(any(test, feature = "test-support"))]
@@ -5489,15 +5477,6 @@ impl Workspace {
.update(cx, |_, window, _| window.activate_window())
.ok();
}
pub fn cancel(&mut self, _: &menu::Cancel, _: &mut Window, cx: &mut Context<Self>) {
if let Some((notification_id, _)) = self.notifications.pop() {
dismiss_app_notification(&notification_id, cx);
return;
}
cx.propagate();
}
}
fn leader_border_for_pane(

Some files were not shown because too many files have changed in this diff Show More