Compare commits
2 Commits
rename-set
...
remove-dep
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
95f4f12384 | ||
|
|
101399fb66 |
12
.github/workflows/ci.yml
vendored
12
.github/workflows/ci.yml
vendored
@@ -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
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"printWidth": 120
|
||||
}
|
||||
64
Cargo.lock
generated
64
Cargo.lock
generated
@@ -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",
|
||||
|
||||
@@ -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" }
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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, _| {
|
||||
|
||||
@@ -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)
|
||||
})),
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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 ¤t.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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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| {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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()));
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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> {
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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> {
|
||||
|
||||
@@ -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()),
|
||||
|
||||
@@ -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()),
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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"] }
|
||||
@@ -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();
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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()),
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
|
||||
@@ -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({
|
||||
|
||||
@@ -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,
|
||||
)
|
||||
});
|
||||
}
|
||||
});
|
||||
})
|
||||
|
||||
@@ -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(),
|
||||
)
|
||||
|
||||
@@ -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"));
|
||||
|
||||
@@ -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,
|
||||
)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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};
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use agent_settings::AgentProfileId;
|
||||
use anyhow::Result;
|
||||
use assistant_settings::AgentProfileId;
|
||||
use async_trait::async_trait;
|
||||
use markdown::PathWithRange;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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(), []);
|
||||
});
|
||||
|
||||
@@ -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(),
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -496,7 +496,7 @@ pub enum Model {
|
||||
|
||||
impl Model {
|
||||
pub fn default_fast() -> Model {
|
||||
Model::Gemini15Flash
|
||||
Model::Gemini20FlashLite
|
||||
}
|
||||
|
||||
pub fn id(&self) -> &str {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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`.
|
||||
|
||||
@@ -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>;
|
||||
}
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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<()>>,
|
||||
|
||||
@@ -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"]
|
||||
|
||||
@@ -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"]
|
||||
|
||||
@@ -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> {
|
||||
|
||||
@@ -14,4 +14,3 @@ brackets = [
|
||||
]
|
||||
tab_size = 4
|
||||
hard_tabs = true
|
||||
debuggers = ["Delve"]
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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(),
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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"]
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -15,4 +15,3 @@ brackets = [
|
||||
{ start = "/*", end = " */", close = true, newline = false, not_in = ["string", "comment"] },
|
||||
]
|
||||
collapsed_placeholder = " /* ... */ "
|
||||
debuggers = ["CodeLLDB", "GDB"]
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -17,7 +17,6 @@ brackets = [
|
||||
word_characters = ["#", "$"]
|
||||
prettier_parser_name = "typescript"
|
||||
tab_size = 2
|
||||
debuggers = ["JavaScript"]
|
||||
|
||||
[overrides.string]
|
||||
completion_query_characters = ["."]
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)]
|
||||
|
||||
@@ -580,7 +580,6 @@ message DebugAdapterBinary {
|
||||
message RunDebugLocators {
|
||||
uint64 project_id = 1;
|
||||
SpawnInTerminal build_command = 2;
|
||||
string locator = 3;
|
||||
}
|
||||
|
||||
message DebugRequest {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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())),
|
||||
)
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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(¬ification, {
|
||||
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()
|
||||
|
||||
@@ -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(¬ification_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(¬ification_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
Reference in New Issue
Block a user