Settings refactor (#38367)
Co-Authored-By: Ben K <ben@zed.dev> Co-Authored-By: Anthony <anthony@zed.dev> Co-Authored-By: Mikayla <mikayla@zed.dev> Release Notes: - settings: Major internal changes to settings. The primary user-facing effect is that some settings which did not make sense in project settings files are no-longer read from there. (For example the inline blame settings) --------- Co-authored-by: Ben Kunkle <ben@zed.dev> Co-authored-by: Mikayla Maki <mikayla.c.maki@gmail.com> Co-authored-by: Anthony <anthony@zed.dev>
This commit is contained in:
co-authored by
Ben Kunkle
Mikayla Maki
Anthony
parent
0a9023bce0
commit
fcdab160f9
Generated
+196
-132
File diff suppressed because it is too large
Load Diff
+1
-1
@@ -150,7 +150,6 @@ members = [
|
||||
"crates/session",
|
||||
"crates/settings",
|
||||
"crates/settings_profile_selector",
|
||||
"crates/settings_ui",
|
||||
"crates/settings_ui_macros",
|
||||
"crates/snippet",
|
||||
"crates/snippet_provider",
|
||||
@@ -630,6 +629,7 @@ serde_json_lenient = { version = "0.2", features = [
|
||||
serde_path_to_error = "0.1.17"
|
||||
serde_repr = "0.1"
|
||||
serde_urlencoded = "0.7"
|
||||
serde_with = "3.4.0"
|
||||
sha2 = "0.10"
|
||||
shellexpand = "2.1.0"
|
||||
shlex = "1.3.0"
|
||||
|
||||
@@ -311,7 +311,7 @@
|
||||
// bracket, brace, single or double quote characters.
|
||||
// For example, when you select text and type (, Zed will surround the text with ().
|
||||
"use_auto_surround": true,
|
||||
/// Whether indentation should be adjusted based on the context whilst typing.
|
||||
// Whether indentation should be adjusted based on the context whilst typing.
|
||||
"auto_indent": true,
|
||||
// Whether indentation of pasted content should be adjusted based on the context.
|
||||
"auto_indent_on_paste": true,
|
||||
@@ -408,6 +408,21 @@
|
||||
// Whether to show the menus in the titlebar.
|
||||
"show_menus": false
|
||||
},
|
||||
"audio": {
|
||||
// Opt into the new audio system.
|
||||
"experimental.rodio_audio": false,
|
||||
// Requires 'rodio_audio: true'
|
||||
//
|
||||
// Use the new audio systems automatic gain control for your microphone.
|
||||
// This affects how loud you sound to others.
|
||||
"experimental.control_input_volume": false,
|
||||
// Requires 'rodio_audio: true'
|
||||
//
|
||||
// Use the new audio systems automatic gain control on everyone in the
|
||||
// call. This makes call members who are too quite louder and those who are
|
||||
// too loud quieter. This only affects how things sound for you.
|
||||
"experimental.control_output_volume": false
|
||||
},
|
||||
// Scrollbar related settings
|
||||
"scrollbar": {
|
||||
// When to show the scrollbar in the editor.
|
||||
@@ -588,6 +603,7 @@
|
||||
// Toggle certain types of hints on and off, all switched on by default.
|
||||
"show_type_hints": true,
|
||||
"show_parameter_hints": true,
|
||||
"show_value_hints": true,
|
||||
// Corresponds to null/None LSP hint type value.
|
||||
"show_other_hints": true,
|
||||
// Whether to show a background for inlay hints.
|
||||
@@ -796,7 +812,7 @@
|
||||
"agent": {
|
||||
// Whether the agent is enabled.
|
||||
"enabled": true,
|
||||
/// What completion mode to start new threads in, if available. Can be 'normal' or 'burn'.
|
||||
// What completion mode to start new threads in, if available. Can be 'normal' or 'burn'.
|
||||
"preferred_completion_mode": "normal",
|
||||
// Whether to show the agent panel button in the status bar.
|
||||
"button": true,
|
||||
@@ -806,6 +822,8 @@
|
||||
"default_width": 640,
|
||||
// Default height when the agent panel is docked to the bottom.
|
||||
"default_height": 320,
|
||||
// The view to use by default (thread, or text_thread)
|
||||
"default_view": "thread",
|
||||
// The default model to use when creating new threads.
|
||||
"default_model": {
|
||||
// The provider to use.
|
||||
@@ -907,14 +925,18 @@
|
||||
|
||||
// Default: false
|
||||
"play_sound_when_agent_done": false,
|
||||
/// Whether to have edit cards in the agent panel expanded, showing a preview of the full diff.
|
||||
///
|
||||
/// Default: true
|
||||
// Whether to have edit cards in the agent panel expanded, showing a preview of the full diff.
|
||||
//
|
||||
// Default: true
|
||||
"expand_edit_card": true,
|
||||
/// Whether to have terminal cards in the agent panel expanded, showing the whole command output.
|
||||
///
|
||||
/// Default: true
|
||||
// Whether to have terminal cards in the agent panel expanded, showing the whole command output.
|
||||
//
|
||||
// Default: true
|
||||
"expand_terminal_card": true,
|
||||
// Whether to always use cmd-enter (or ctrl-enter on Linux or Windows) to send messages in the agent panel.
|
||||
//
|
||||
// Default: false
|
||||
"use_modifier_to_send": false,
|
||||
// Minimum number of lines to display in the agent message editor.
|
||||
//
|
||||
// Default: 4
|
||||
@@ -931,6 +953,7 @@
|
||||
//
|
||||
// This is typically customized on a per-language basis.
|
||||
"language_servers": ["..."],
|
||||
|
||||
// When to automatically save edited buffers. This setting can
|
||||
// take four values.
|
||||
//
|
||||
@@ -1262,7 +1285,13 @@
|
||||
// },
|
||||
// Whether edit predictions are enabled when editing text threads.
|
||||
// This setting has no effect if globally disabled.
|
||||
"enabled_in_text_threads": true
|
||||
"enabled_in_text_threads": true,
|
||||
|
||||
"copilot": {
|
||||
"enterprise_uri": null,
|
||||
"proxy": null,
|
||||
"proxy_no_verify": null
|
||||
}
|
||||
},
|
||||
// Settings specific to journaling
|
||||
"journal": {
|
||||
@@ -1765,6 +1794,7 @@
|
||||
"anthropic": {
|
||||
"api_url": "https://api.anthropic.com"
|
||||
},
|
||||
"bedrock": {},
|
||||
"google": {
|
||||
"api_url": "https://generativelanguage.googleapis.com"
|
||||
},
|
||||
@@ -1786,14 +1816,30 @@
|
||||
},
|
||||
"mistral": {
|
||||
"api_url": "https://api.mistral.ai/v1"
|
||||
}
|
||||
},
|
||||
"vercel": {
|
||||
"api_url": "https://api.v0.dev/v1"
|
||||
},
|
||||
"x_ai": {
|
||||
"api_url": "https://api.x.ai/v1"
|
||||
},
|
||||
"zed.dev": {}
|
||||
},
|
||||
"session": {
|
||||
// Whether or not to restore unsaved buffers on restart.
|
||||
//
|
||||
// If this is true, user won't be prompted whether to save/discard
|
||||
// dirty files when closing the application.
|
||||
//
|
||||
// Default: true
|
||||
"restore_unsaved_buffers": true
|
||||
},
|
||||
// Zed's Prettier integration settings.
|
||||
// Allows to enable/disable formatting with Prettier
|
||||
// and configure default Prettier, used when no project-level Prettier installation is found.
|
||||
"prettier": {
|
||||
// // Whether to consider prettier formatter or not when attempting to format a file.
|
||||
// "allowed": false,
|
||||
"allowed": false
|
||||
//
|
||||
// // Use regular Prettier json configuration.
|
||||
// // If Prettier is allowed, Zed will use this for its Prettier instance for any applicable file, if
|
||||
@@ -1826,6 +1872,10 @@
|
||||
// }
|
||||
// }
|
||||
},
|
||||
// DAP Specific settings.
|
||||
"dap": {
|
||||
// Specify the DAP name as a key here.
|
||||
},
|
||||
// Common language server settings.
|
||||
"global_lsp_settings": {
|
||||
// Whether to show the LSP servers button in the status bar.
|
||||
@@ -1833,7 +1883,8 @@
|
||||
},
|
||||
// Jupyter settings
|
||||
"jupyter": {
|
||||
"enabled": true
|
||||
"enabled": true,
|
||||
"kernel_selections": {}
|
||||
// Specify the language name as the key and the kernel name as the value.
|
||||
// "kernel_selections": {
|
||||
// "python": "conda-base"
|
||||
@@ -1964,5 +2015,11 @@
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
"profiles": []
|
||||
"profiles": [],
|
||||
|
||||
// A map of log scopes to the desired log level.
|
||||
// Useful for filtering out noisy logs or enabling more verbose logging.
|
||||
//
|
||||
// Example: {"log": {"client": "warn"}}
|
||||
"log": {}
|
||||
}
|
||||
|
||||
@@ -49,10 +49,10 @@ impl AgentProfile {
|
||||
.unwrap_or_default(),
|
||||
};
|
||||
|
||||
update_settings_file::<AgentSettings>(fs, cx, {
|
||||
update_settings_file(fs, cx, {
|
||||
let id = id.clone();
|
||||
move |settings, _cx| {
|
||||
settings.create_profile(id, profile_settings).log_err();
|
||||
profile_settings.save_to_settings(id, settings).log_err();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -3272,7 +3272,7 @@ mod tests {
|
||||
|
||||
// Test-specific constants
|
||||
const TEST_RATE_LIMIT_RETRY_SECS: u64 = 30;
|
||||
use agent_settings::{AgentProfileId, AgentSettings, LanguageModelParameters};
|
||||
use agent_settings::{AgentProfileId, AgentSettings};
|
||||
use assistant_tool::ToolRegistry;
|
||||
use assistant_tools;
|
||||
use futures::StreamExt;
|
||||
@@ -3289,7 +3289,7 @@ mod tests {
|
||||
use project::{FakeFs, Project};
|
||||
use prompt_store::PromptBuilder;
|
||||
use serde_json::json;
|
||||
use settings::{Settings, SettingsStore};
|
||||
use settings::{LanguageModelParameters, Settings, SettingsStore};
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use theme::ThemeSettings;
|
||||
|
||||
@@ -6,7 +6,6 @@ use crate::{HistoryStore, TerminalHandle, ThreadEnvironment, TitleUpdated, Token
|
||||
use acp_thread::{AcpThread, AgentModelSelector};
|
||||
use action_log::ActionLog;
|
||||
use agent_client_protocol as acp;
|
||||
use agent_settings::AgentSettings;
|
||||
use anyhow::{Context as _, Result, anyhow};
|
||||
use collections::{HashSet, IndexMap};
|
||||
use fs::Fs;
|
||||
@@ -21,7 +20,7 @@ use project::{Project, ProjectItem, ProjectPath, Worktree};
|
||||
use prompt_store::{
|
||||
ProjectContext, PromptId, PromptStore, RulesFileContext, UserRulesContext, WorktreeContext,
|
||||
};
|
||||
use settings::update_settings_file;
|
||||
use settings::{LanguageModelSelection, update_settings_file};
|
||||
use std::any::Any;
|
||||
use std::collections::HashMap;
|
||||
use std::path::{Path, PathBuf};
|
||||
@@ -873,13 +872,17 @@ impl AgentModelSelector for NativeAgentConnection {
|
||||
thread.set_model(model.clone(), cx);
|
||||
});
|
||||
|
||||
update_settings_file::<AgentSettings>(
|
||||
self.0.read(cx).fs.clone(),
|
||||
cx,
|
||||
move |settings, _cx| {
|
||||
settings.set_model(model);
|
||||
},
|
||||
);
|
||||
update_settings_file(self.0.read(cx).fs.clone(), cx, move |settings, _cx| {
|
||||
let provider = model.provider_id().0.to_string();
|
||||
let model = model.id().0.to_string();
|
||||
settings
|
||||
.agent
|
||||
.get_or_insert_default()
|
||||
.set_model(LanguageModelSelection {
|
||||
provider: provider.into(),
|
||||
model,
|
||||
});
|
||||
});
|
||||
|
||||
Task::ready(Ok(()))
|
||||
}
|
||||
|
||||
@@ -2477,8 +2477,11 @@ impl ToolCallEventStream {
|
||||
"always_allow" => {
|
||||
if let Some(fs) = fs.clone() {
|
||||
cx.update(|cx| {
|
||||
update_settings_file::<AgentSettings>(fs, cx, |settings, _| {
|
||||
settings.set_always_allow_tool_actions(true);
|
||||
update_settings_file(fs, cx, |settings, _| {
|
||||
settings
|
||||
.agent
|
||||
.get_or_insert_default()
|
||||
.set_always_allow_tool_actions(true);
|
||||
});
|
||||
})?;
|
||||
}
|
||||
|
||||
@@ -791,14 +791,11 @@ mod tests {
|
||||
// First, test with format_on_save enabled
|
||||
cx.update(|cx| {
|
||||
SettingsStore::update_global(cx, |store, cx| {
|
||||
store.update_user_settings::<language::language_settings::AllLanguageSettings>(
|
||||
cx,
|
||||
|settings| {
|
||||
settings.defaults.format_on_save = Some(FormatOnSave::On);
|
||||
settings.defaults.formatter =
|
||||
Some(language::language_settings::SelectedFormatter::Auto);
|
||||
},
|
||||
);
|
||||
store.update_user_settings(cx, |settings| {
|
||||
settings.project.all_languages.defaults.format_on_save = Some(FormatOnSave::On);
|
||||
settings.project.all_languages.defaults.formatter =
|
||||
Some(language::language_settings::SelectedFormatter::Auto);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -853,12 +850,10 @@ mod tests {
|
||||
// Next, test with format_on_save disabled
|
||||
cx.update(|cx| {
|
||||
SettingsStore::update_global(cx, |store, cx| {
|
||||
store.update_user_settings::<language::language_settings::AllLanguageSettings>(
|
||||
cx,
|
||||
|settings| {
|
||||
settings.defaults.format_on_save = Some(FormatOnSave::Off);
|
||||
},
|
||||
);
|
||||
store.update_user_settings(cx, |settings| {
|
||||
settings.project.all_languages.defaults.format_on_save =
|
||||
Some(FormatOnSave::Off);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -935,12 +930,13 @@ mod tests {
|
||||
// First, test with remove_trailing_whitespace_on_save enabled
|
||||
cx.update(|cx| {
|
||||
SettingsStore::update_global(cx, |store, cx| {
|
||||
store.update_user_settings::<language::language_settings::AllLanguageSettings>(
|
||||
cx,
|
||||
|settings| {
|
||||
settings.defaults.remove_trailing_whitespace_on_save = Some(true);
|
||||
},
|
||||
);
|
||||
store.update_user_settings(cx, |settings| {
|
||||
settings
|
||||
.project
|
||||
.all_languages
|
||||
.defaults
|
||||
.remove_trailing_whitespace_on_save = Some(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -991,12 +987,13 @@ mod tests {
|
||||
// Next, test with remove_trailing_whitespace_on_save disabled
|
||||
cx.update(|cx| {
|
||||
SettingsStore::update_global(cx, |store, cx| {
|
||||
store.update_user_settings::<language::language_settings::AllLanguageSettings>(
|
||||
cx,
|
||||
|settings| {
|
||||
settings.defaults.remove_trailing_whitespace_on_save = Some(false);
|
||||
},
|
||||
);
|
||||
store.update_user_settings(cx, |settings| {
|
||||
settings
|
||||
.project
|
||||
.all_languages
|
||||
.defaults
|
||||
.remove_trailing_whitespace_on_save = Some(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -308,7 +308,7 @@ mod tests {
|
||||
use super::*;
|
||||
use gpui::{TestAppContext, UpdateGlobal};
|
||||
use language::{Language, LanguageConfig, LanguageMatcher};
|
||||
use project::{FakeFs, Project, WorktreeSettings};
|
||||
use project::{FakeFs, Project};
|
||||
use serde_json::json;
|
||||
use settings::SettingsStore;
|
||||
use unindent::Unindent;
|
||||
@@ -827,15 +827,14 @@ mod tests {
|
||||
|
||||
cx.update(|cx| {
|
||||
use gpui::UpdateGlobal;
|
||||
use project::WorktreeSettings;
|
||||
use settings::SettingsStore;
|
||||
SettingsStore::update_global(cx, |store, cx| {
|
||||
store.update_user_settings::<WorktreeSettings>(cx, |settings| {
|
||||
settings.file_scan_exclusions = Some(vec![
|
||||
store.update_user_settings(cx, |settings| {
|
||||
settings.project.worktree.file_scan_exclusions = Some(vec![
|
||||
"**/.secretdir".to_string(),
|
||||
"**/.mymetadata".to_string(),
|
||||
]);
|
||||
settings.private_files = Some(vec![
|
||||
settings.project.worktree.private_files = Some(vec![
|
||||
"**/.mysecrets".to_string(),
|
||||
"**/*.privatekey".to_string(),
|
||||
"**/*.mysensitive".to_string(),
|
||||
@@ -1062,10 +1061,10 @@ mod tests {
|
||||
// Set global settings
|
||||
cx.update(|cx| {
|
||||
SettingsStore::update_global(cx, |store, cx| {
|
||||
store.update_user_settings::<WorktreeSettings>(cx, |settings| {
|
||||
settings.file_scan_exclusions =
|
||||
store.update_user_settings(cx, |settings| {
|
||||
settings.project.worktree.file_scan_exclusions =
|
||||
Some(vec!["**/.git".to_string(), "**/node_modules".to_string()]);
|
||||
settings.private_files = Some(vec!["**/.env".to_string()]);
|
||||
settings.project.worktree.private_files = Some(vec!["**/.env".to_string()]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -214,7 +214,7 @@ mod tests {
|
||||
use super::*;
|
||||
use gpui::{TestAppContext, UpdateGlobal};
|
||||
use indoc::indoc;
|
||||
use project::{FakeFs, Project, WorktreeSettings};
|
||||
use project::{FakeFs, Project};
|
||||
use serde_json::json;
|
||||
use settings::SettingsStore;
|
||||
use util::path;
|
||||
@@ -421,13 +421,13 @@ mod tests {
|
||||
// Configure settings explicitly
|
||||
cx.update(|cx| {
|
||||
SettingsStore::update_global(cx, |store, cx| {
|
||||
store.update_user_settings::<WorktreeSettings>(cx, |settings| {
|
||||
settings.file_scan_exclusions = Some(vec![
|
||||
store.update_user_settings(cx, |settings| {
|
||||
settings.project.worktree.file_scan_exclusions = Some(vec![
|
||||
"**/.secretdir".to_string(),
|
||||
"**/.mymetadata".to_string(),
|
||||
"**/.hidden_subdir".to_string(),
|
||||
]);
|
||||
settings.private_files = Some(vec![
|
||||
settings.project.worktree.private_files = Some(vec![
|
||||
"**/.mysecrets".to_string(),
|
||||
"**/*.privatekey".to_string(),
|
||||
"**/*.mysensitive".to_string(),
|
||||
@@ -565,10 +565,10 @@ mod tests {
|
||||
// Set global settings
|
||||
cx.update(|cx| {
|
||||
SettingsStore::update_global(cx, |store, cx| {
|
||||
store.update_user_settings::<WorktreeSettings>(cx, |settings| {
|
||||
settings.file_scan_exclusions =
|
||||
store.update_user_settings(cx, |settings| {
|
||||
settings.project.worktree.file_scan_exclusions =
|
||||
Some(vec!["**/.git".to_string(), "**/node_modules".to_string()]);
|
||||
settings.private_files = Some(vec!["**/.env".to_string()]);
|
||||
settings.project.worktree.private_files = Some(vec!["**/.env".to_string()]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -586,15 +586,14 @@ mod test {
|
||||
|
||||
cx.update(|cx| {
|
||||
use gpui::UpdateGlobal;
|
||||
use project::WorktreeSettings;
|
||||
use settings::SettingsStore;
|
||||
SettingsStore::update_global(cx, |store, cx| {
|
||||
store.update_user_settings::<WorktreeSettings>(cx, |settings| {
|
||||
settings.file_scan_exclusions = Some(vec![
|
||||
store.update_user_settings(cx, |settings| {
|
||||
settings.project.worktree.file_scan_exclusions = Some(vec![
|
||||
"**/.secretdir".to_string(),
|
||||
"**/.mymetadata".to_string(),
|
||||
]);
|
||||
settings.private_files = Some(vec![
|
||||
settings.project.worktree.private_files = Some(vec![
|
||||
"**/.mysecrets".to_string(),
|
||||
"**/*.privatekey".to_string(),
|
||||
"**/*.mysensitive".to_string(),
|
||||
@@ -802,10 +801,10 @@ mod test {
|
||||
// Set global settings
|
||||
cx.update(|cx| {
|
||||
SettingsStore::update_global(cx, |store, cx| {
|
||||
store.update_user_settings::<WorktreeSettings>(cx, |settings| {
|
||||
settings.file_scan_exclusions =
|
||||
store.update_user_settings(cx, |settings| {
|
||||
settings.project.worktree.file_scan_exclusions =
|
||||
Some(vec!["**/.git".to_string(), "**/node_modules".to_string()]);
|
||||
settings.private_files = Some(vec!["**/.env".to_string()]);
|
||||
settings.project.worktree.private_files = Some(vec!["**/.env".to_string()]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -45,8 +45,13 @@ impl AgentServer for ClaudeCode {
|
||||
}
|
||||
|
||||
fn set_default_mode(&self, mode_id: Option<acp::SessionModeId>, fs: Arc<dyn Fs>, cx: &mut App) {
|
||||
update_settings_file::<AllAgentServersSettings>(fs, cx, |settings, _| {
|
||||
settings.claude.get_or_insert_default().default_mode = mode_id.map(|m| m.to_string())
|
||||
update_settings_file(fs, cx, |settings, _| {
|
||||
settings
|
||||
.agent_servers
|
||||
.get_or_insert_default()
|
||||
.claude
|
||||
.get_or_insert_default()
|
||||
.default_mode = mode_id.map(|m| m.to_string())
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -49,8 +49,14 @@ impl crate::AgentServer for CustomAgentServer {
|
||||
|
||||
fn set_default_mode(&self, mode_id: Option<acp::SessionModeId>, fs: Arc<dyn Fs>, cx: &mut App) {
|
||||
let name = self.name();
|
||||
update_settings_file::<AllAgentServersSettings>(fs, cx, move |settings, _| {
|
||||
settings.custom.get_mut(&name).unwrap().default_mode = mode_id.map(|m| m.to_string())
|
||||
update_settings_file(fs, cx, move |settings, _| {
|
||||
settings
|
||||
.agent_servers
|
||||
.get_or_insert_default()
|
||||
.custom
|
||||
.get_mut(&name)
|
||||
.unwrap()
|
||||
.default_mode = mode_id.map(|m| m.to_string())
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use anyhow::{Result, bail};
|
||||
use collections::IndexMap;
|
||||
use convert_case::{Case, Casing as _};
|
||||
use fs::Fs;
|
||||
use gpui::{App, SharedString};
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use settings::{Settings as _, update_settings_file};
|
||||
use settings::{
|
||||
AgentProfileContent, ContextServerPresetContent, Settings as _, SettingsContent,
|
||||
update_settings_file,
|
||||
};
|
||||
use util::ResultExt as _;
|
||||
|
||||
use crate::AgentSettings;
|
||||
use crate::{AgentProfileId, AgentSettings};
|
||||
|
||||
pub mod builtin_profiles {
|
||||
use super::AgentProfileId;
|
||||
@@ -23,27 +25,6 @@ pub mod builtin_profiles {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize, Deserialize, JsonSchema)]
|
||||
pub struct AgentProfileId(pub Arc<str>);
|
||||
|
||||
impl AgentProfileId {
|
||||
pub fn as_str(&self) -> &str {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for AgentProfileId {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for AgentProfileId {
|
||||
fn default() -> Self {
|
||||
Self("write".into())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub struct AgentProfile {
|
||||
id: AgentProfileId,
|
||||
@@ -87,10 +68,10 @@ impl AgentProfile {
|
||||
.unwrap_or_default(),
|
||||
};
|
||||
|
||||
update_settings_file::<AgentSettings>(fs, cx, {
|
||||
update_settings_file(fs, cx, {
|
||||
let id = id.clone();
|
||||
move |settings, _cx| {
|
||||
settings.create_profile(id, profile_settings).log_err();
|
||||
profile_settings.save_to_settings(id, settings).log_err();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -129,9 +110,71 @@ impl AgentProfileSettings {
|
||||
.get(server_id)
|
||||
.is_some_and(|preset| preset.tools.get(tool_name) == Some(&true))
|
||||
}
|
||||
|
||||
pub fn save_to_settings(
|
||||
&self,
|
||||
profile_id: AgentProfileId,
|
||||
content: &mut SettingsContent,
|
||||
) -> Result<()> {
|
||||
let profiles = content
|
||||
.agent
|
||||
.get_or_insert_default()
|
||||
.profiles
|
||||
.get_or_insert_default();
|
||||
if profiles.contains_key(&profile_id.0) {
|
||||
bail!("profile with ID '{profile_id}' already exists");
|
||||
}
|
||||
|
||||
profiles.insert(
|
||||
profile_id.0,
|
||||
AgentProfileContent {
|
||||
name: self.name.clone().into(),
|
||||
tools: self.tools.clone(),
|
||||
enable_all_context_servers: Some(self.enable_all_context_servers),
|
||||
context_servers: self
|
||||
.context_servers
|
||||
.clone()
|
||||
.into_iter()
|
||||
.map(|(server_id, preset)| {
|
||||
(
|
||||
server_id,
|
||||
ContextServerPresetContent {
|
||||
tools: preset.tools,
|
||||
},
|
||||
)
|
||||
})
|
||||
.collect(),
|
||||
},
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<AgentProfileContent> for AgentProfileSettings {
|
||||
fn from(content: AgentProfileContent) -> Self {
|
||||
Self {
|
||||
name: content.name.into(),
|
||||
tools: content.tools,
|
||||
enable_all_context_servers: content.enable_all_context_servers.unwrap_or_default(),
|
||||
context_servers: content
|
||||
.context_servers
|
||||
.into_iter()
|
||||
.map(|(server_id, preset)| (server_id, preset.into()))
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct ContextServerPreset {
|
||||
pub tools: IndexMap<Arc<str>, bool>,
|
||||
}
|
||||
|
||||
impl From<settings::ContextServerPresetContent> for ContextServerPreset {
|
||||
fn from(content: settings::ContextServerPresetContent) -> Self {
|
||||
Self {
|
||||
tools: content.tools,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,14 +2,16 @@ mod agent_profile;
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
use anyhow::{Result, bail};
|
||||
use collections::IndexMap;
|
||||
use gpui::{App, Pixels, SharedString};
|
||||
use gpui::{App, Pixels, px};
|
||||
use language_model::LanguageModel;
|
||||
use schemars::{JsonSchema, json_schema};
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use settings::{Settings, SettingsKey, SettingsSources, SettingsUi};
|
||||
use std::borrow::Cow;
|
||||
use settings::{
|
||||
DefaultAgentView, DockPosition, LanguageModelParameters, LanguageModelSelection,
|
||||
NotifyWhenAgentWaiting, Settings, SettingsContent,
|
||||
};
|
||||
use util::MergeFrom;
|
||||
|
||||
pub use crate::agent_profile::*;
|
||||
|
||||
@@ -22,37 +24,11 @@ pub fn init(cx: &mut App) {
|
||||
AgentSettings::register(cx);
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Default, Debug, Serialize, Deserialize, JsonSchema)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum AgentDockPosition {
|
||||
Left,
|
||||
#[default]
|
||||
Right,
|
||||
Bottom,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Default, Debug, Serialize, Deserialize, JsonSchema)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum DefaultView {
|
||||
#[default]
|
||||
Thread,
|
||||
TextThread,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Default, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum NotifyWhenAgentWaiting {
|
||||
#[default]
|
||||
PrimaryScreen,
|
||||
AllScreens,
|
||||
Never,
|
||||
}
|
||||
|
||||
#[derive(Default, Clone, Debug)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct AgentSettings {
|
||||
pub enabled: bool,
|
||||
pub button: bool,
|
||||
pub dock: AgentDockPosition,
|
||||
pub dock: DockPosition,
|
||||
pub default_width: Pixels,
|
||||
pub default_height: Pixels,
|
||||
pub default_model: Option<LanguageModelSelection>,
|
||||
@@ -60,9 +36,8 @@ pub struct AgentSettings {
|
||||
pub commit_message_model: Option<LanguageModelSelection>,
|
||||
pub thread_summary_model: Option<LanguageModelSelection>,
|
||||
pub inline_alternatives: Vec<LanguageModelSelection>,
|
||||
pub using_outdated_settings_version: bool,
|
||||
pub default_profile: AgentProfileId,
|
||||
pub default_view: DefaultView,
|
||||
pub default_view: DefaultAgentView,
|
||||
pub profiles: IndexMap<AgentProfileId, AgentProfileSettings>,
|
||||
pub always_allow_tool_actions: bool,
|
||||
pub notify_when_agent_waiting: NotifyWhenAgentWaiting,
|
||||
@@ -81,11 +56,20 @@ pub struct AgentSettings {
|
||||
impl AgentSettings {
|
||||
pub fn temperature_for_model(model: &Arc<dyn LanguageModel>, cx: &App) -> Option<f32> {
|
||||
let settings = Self::get_global(cx);
|
||||
settings
|
||||
.model_parameters
|
||||
.iter()
|
||||
.rfind(|setting| setting.matches(model))
|
||||
.and_then(|m| m.temperature)
|
||||
for setting in settings.model_parameters.iter().rev() {
|
||||
if let Some(provider) = &setting.provider
|
||||
&& provider.0 != model.provider_id().0
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if let Some(setting_model) = &setting.model
|
||||
&& *setting_model != model.id().0
|
||||
{
|
||||
continue;
|
||||
}
|
||||
return setting.temperature;
|
||||
}
|
||||
return None;
|
||||
}
|
||||
|
||||
pub fn set_inline_assistant_model(&mut self, provider: String, model: String) {
|
||||
@@ -114,223 +98,6 @@ impl AgentSettings {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq)]
|
||||
pub struct LanguageModelParameters {
|
||||
pub provider: Option<LanguageModelProviderSetting>,
|
||||
pub model: Option<SharedString>,
|
||||
pub temperature: Option<f32>,
|
||||
}
|
||||
|
||||
impl LanguageModelParameters {
|
||||
pub fn matches(&self, model: &Arc<dyn LanguageModel>) -> bool {
|
||||
if let Some(provider) = &self.provider
|
||||
&& provider.0 != model.provider_id().0
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if let Some(setting_model) = &self.model
|
||||
&& *setting_model != model.id().0
|
||||
{
|
||||
return false;
|
||||
}
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
impl AgentSettingsContent {
|
||||
pub fn set_dock(&mut self, dock: AgentDockPosition) {
|
||||
self.dock = Some(dock);
|
||||
}
|
||||
|
||||
pub fn set_model(&mut self, language_model: Arc<dyn LanguageModel>) {
|
||||
let model = language_model.id().0.to_string();
|
||||
let provider = language_model.provider_id().0.to_string();
|
||||
|
||||
self.default_model = Some(LanguageModelSelection {
|
||||
provider: provider.into(),
|
||||
model,
|
||||
});
|
||||
}
|
||||
|
||||
pub fn set_inline_assistant_model(&mut self, provider: String, model: String) {
|
||||
self.inline_assistant_model = Some(LanguageModelSelection {
|
||||
provider: provider.into(),
|
||||
model,
|
||||
});
|
||||
}
|
||||
|
||||
pub fn set_commit_message_model(&mut self, provider: String, model: String) {
|
||||
self.commit_message_model = Some(LanguageModelSelection {
|
||||
provider: provider.into(),
|
||||
model,
|
||||
});
|
||||
}
|
||||
|
||||
pub fn set_thread_summary_model(&mut self, provider: String, model: String) {
|
||||
self.thread_summary_model = Some(LanguageModelSelection {
|
||||
provider: provider.into(),
|
||||
model,
|
||||
});
|
||||
}
|
||||
|
||||
pub fn set_always_allow_tool_actions(&mut self, allow: bool) {
|
||||
self.always_allow_tool_actions = Some(allow);
|
||||
}
|
||||
|
||||
pub fn set_play_sound_when_agent_done(&mut self, allow: bool) {
|
||||
self.play_sound_when_agent_done = Some(allow);
|
||||
}
|
||||
|
||||
pub fn set_single_file_review(&mut self, allow: bool) {
|
||||
self.single_file_review = Some(allow);
|
||||
}
|
||||
|
||||
pub fn set_use_modifier_to_send(&mut self, always_use: bool) {
|
||||
self.use_modifier_to_send = Some(always_use);
|
||||
}
|
||||
|
||||
pub fn set_profile(&mut self, profile_id: AgentProfileId) {
|
||||
self.default_profile = Some(profile_id);
|
||||
}
|
||||
|
||||
pub fn create_profile(
|
||||
&mut self,
|
||||
profile_id: AgentProfileId,
|
||||
profile_settings: AgentProfileSettings,
|
||||
) -> Result<()> {
|
||||
let profiles = self.profiles.get_or_insert_default();
|
||||
if profiles.contains_key(&profile_id) {
|
||||
bail!("profile with ID '{profile_id}' already exists");
|
||||
}
|
||||
|
||||
profiles.insert(
|
||||
profile_id,
|
||||
AgentProfileContent {
|
||||
name: profile_settings.name.into(),
|
||||
tools: profile_settings.tools,
|
||||
enable_all_context_servers: Some(profile_settings.enable_all_context_servers),
|
||||
context_servers: profile_settings
|
||||
.context_servers
|
||||
.into_iter()
|
||||
.map(|(server_id, preset)| {
|
||||
(
|
||||
server_id,
|
||||
ContextServerPresetContent {
|
||||
tools: preset.tools,
|
||||
},
|
||||
)
|
||||
})
|
||||
.collect(),
|
||||
},
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize, JsonSchema, Debug, Default, SettingsUi, SettingsKey)]
|
||||
#[settings_key(key = "agent", fallback_key = "assistant")]
|
||||
pub struct AgentSettingsContent {
|
||||
/// Whether the Agent is enabled.
|
||||
///
|
||||
/// Default: true
|
||||
enabled: Option<bool>,
|
||||
/// Whether to show the agent panel button in the status bar.
|
||||
///
|
||||
/// Default: true
|
||||
button: Option<bool>,
|
||||
/// Where to dock the agent panel.
|
||||
///
|
||||
/// Default: right
|
||||
dock: Option<AgentDockPosition>,
|
||||
/// Default width in pixels when the agent panel is docked to the left or right.
|
||||
///
|
||||
/// Default: 640
|
||||
default_width: Option<f32>,
|
||||
/// Default height in pixels when the agent panel 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 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>,
|
||||
/// Model to use for generating thread summaries. Defaults to default_model when not specified.
|
||||
thread_summary_model: Option<LanguageModelSelection>,
|
||||
/// Additional models with which to generate alternatives when performing inline assists.
|
||||
inline_alternatives: Option<Vec<LanguageModelSelection>>,
|
||||
/// The default profile to use in the Agent.
|
||||
///
|
||||
/// Default: write
|
||||
default_profile: Option<AgentProfileId>,
|
||||
/// Which view type to show by default in the agent panel.
|
||||
///
|
||||
/// Default: "thread"
|
||||
default_view: Option<DefaultView>,
|
||||
/// The available agent profiles.
|
||||
pub profiles: Option<IndexMap<AgentProfileId, AgentProfileContent>>,
|
||||
/// Whenever a tool action would normally wait for your confirmation
|
||||
/// that you allow it, always choose to allow it.
|
||||
///
|
||||
/// This setting has no effect on external agents that support permission modes, such as Claude Code.
|
||||
///
|
||||
/// Set `agent_servers.claude.default_mode` to `bypassPermissions`, to disable all permission requests when using Claude Code.
|
||||
///
|
||||
/// Default: false
|
||||
always_allow_tool_actions: Option<bool>,
|
||||
/// Where to show a popup notification when the agent is waiting for user input.
|
||||
///
|
||||
/// Default: "primary_screen"
|
||||
notify_when_agent_waiting: Option<NotifyWhenAgentWaiting>,
|
||||
/// Whether to play a sound when the agent has either completed its response, or needs user input.
|
||||
///
|
||||
/// Default: false
|
||||
play_sound_when_agent_done: Option<bool>,
|
||||
/// Whether to stream edits from the agent as they are received.
|
||||
///
|
||||
/// Default: false
|
||||
stream_edits: Option<bool>,
|
||||
/// Whether to display agent edits in single-file editors in addition to the review multibuffer pane.
|
||||
///
|
||||
/// Default: true
|
||||
single_file_review: Option<bool>,
|
||||
/// Additional parameters for language model requests. When making a request
|
||||
/// to a model, parameters will be taken from the last entry in this list
|
||||
/// that matches the model's provider and name. In each entry, both provider
|
||||
/// and model are optional, so that you can specify parameters for either
|
||||
/// one.
|
||||
///
|
||||
/// Default: []
|
||||
#[serde(default)]
|
||||
model_parameters: Vec<LanguageModelParameters>,
|
||||
/// What completion mode to enable for new threads
|
||||
///
|
||||
/// Default: normal
|
||||
preferred_completion_mode: Option<CompletionMode>,
|
||||
/// Whether to show thumb buttons for feedback in the agent panel.
|
||||
///
|
||||
/// Default: true
|
||||
enable_feedback: Option<bool>,
|
||||
/// Whether to have edit cards in the agent panel expanded, showing a preview of the full diff.
|
||||
///
|
||||
/// Default: true
|
||||
expand_edit_card: Option<bool>,
|
||||
/// Whether to have terminal cards in the agent panel expanded, showing the whole command output.
|
||||
///
|
||||
/// Default: true
|
||||
expand_terminal_card: Option<bool>,
|
||||
/// Whether to always use cmd-enter (or ctrl-enter on Linux or Windows) to send messages in the agent panel.
|
||||
///
|
||||
/// Default: false
|
||||
use_modifier_to_send: Option<bool>,
|
||||
/// Minimum number of lines of height the agent message editor should have.
|
||||
///
|
||||
/// Default: 4
|
||||
message_editor_min_lines: Option<usize>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Default)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum CompletionMode {
|
||||
@@ -349,215 +116,140 @@ impl From<CompletionMode> for cloud_llm_client::CompletionMode {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq)]
|
||||
pub struct LanguageModelSelection {
|
||||
pub provider: LanguageModelProviderSetting,
|
||||
pub model: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
pub struct LanguageModelProviderSetting(pub String);
|
||||
|
||||
impl JsonSchema for LanguageModelProviderSetting {
|
||||
fn schema_name() -> Cow<'static, str> {
|
||||
"LanguageModelProviderSetting".into()
|
||||
}
|
||||
|
||||
fn json_schema(_: &mut schemars::SchemaGenerator) -> schemars::Schema {
|
||||
// list the builtin providers as a subset so that we still auto complete them in the settings
|
||||
json_schema!({
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"amazon-bedrock",
|
||||
"anthropic",
|
||||
"copilot_chat",
|
||||
"deepseek",
|
||||
"google",
|
||||
"lmstudio",
|
||||
"mistral",
|
||||
"ollama",
|
||||
"openai",
|
||||
"openrouter",
|
||||
"vercel",
|
||||
"x_ai",
|
||||
"zed.dev"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
}
|
||||
]
|
||||
})
|
||||
impl From<settings::CompletionMode> for CompletionMode {
|
||||
fn from(value: settings::CompletionMode) -> Self {
|
||||
match value {
|
||||
settings::CompletionMode::Normal => CompletionMode::Normal,
|
||||
settings::CompletionMode::Burn => CompletionMode::Burn,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<String> for LanguageModelProviderSetting {
|
||||
fn from(provider: String) -> Self {
|
||||
Self(provider)
|
||||
#[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize, Deserialize, JsonSchema)]
|
||||
pub struct AgentProfileId(pub Arc<str>);
|
||||
|
||||
impl AgentProfileId {
|
||||
pub fn as_str(&self) -> &str {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&str> for LanguageModelProviderSetting {
|
||||
fn from(provider: &str) -> Self {
|
||||
Self(provider.to_string())
|
||||
impl std::fmt::Display for AgentProfileId {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, JsonSchema)]
|
||||
pub struct AgentProfileContent {
|
||||
pub name: Arc<str>,
|
||||
#[serde(default)]
|
||||
pub tools: IndexMap<Arc<str>, bool>,
|
||||
/// Whether all context servers are enabled by default.
|
||||
pub enable_all_context_servers: Option<bool>,
|
||||
#[serde(default)]
|
||||
pub context_servers: IndexMap<Arc<str>, ContextServerPresetContent>,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone, Default, Serialize, Deserialize, JsonSchema)]
|
||||
pub struct ContextServerPresetContent {
|
||||
pub tools: IndexMap<Arc<str>, bool>,
|
||||
impl Default for AgentProfileId {
|
||||
fn default() -> Self {
|
||||
Self("write".into())
|
||||
}
|
||||
}
|
||||
|
||||
impl Settings for AgentSettings {
|
||||
const PRESERVED_KEYS: Option<&'static [&'static str]> = Some(&["version"]);
|
||||
|
||||
type FileContent = AgentSettingsContent;
|
||||
|
||||
fn load(
|
||||
sources: SettingsSources<Self::FileContent>,
|
||||
_: &mut gpui::App,
|
||||
) -> anyhow::Result<Self> {
|
||||
let mut settings = AgentSettings::default();
|
||||
|
||||
for value in sources.defaults_and_customizations() {
|
||||
merge(&mut settings.enabled, value.enabled);
|
||||
merge(&mut settings.button, value.button);
|
||||
merge(&mut settings.dock, value.dock);
|
||||
merge(
|
||||
&mut settings.default_width,
|
||||
value.default_width.map(Into::into),
|
||||
);
|
||||
merge(
|
||||
&mut settings.default_height,
|
||||
value.default_height.map(Into::into),
|
||||
);
|
||||
settings.default_model = value
|
||||
.default_model
|
||||
.clone()
|
||||
.or(settings.default_model.take());
|
||||
settings.inline_assistant_model = value
|
||||
.inline_assistant_model
|
||||
.clone()
|
||||
.or(settings.inline_assistant_model.take());
|
||||
settings.commit_message_model = value
|
||||
.clone()
|
||||
.commit_message_model
|
||||
.or(settings.commit_message_model.take());
|
||||
settings.thread_summary_model = value
|
||||
.clone()
|
||||
.thread_summary_model
|
||||
.or(settings.thread_summary_model.take());
|
||||
merge(
|
||||
&mut settings.inline_alternatives,
|
||||
value.inline_alternatives.clone(),
|
||||
);
|
||||
merge(
|
||||
&mut settings.notify_when_agent_waiting,
|
||||
value.notify_when_agent_waiting,
|
||||
);
|
||||
merge(
|
||||
&mut settings.play_sound_when_agent_done,
|
||||
value.play_sound_when_agent_done,
|
||||
);
|
||||
merge(&mut settings.stream_edits, value.stream_edits);
|
||||
merge(&mut settings.single_file_review, value.single_file_review);
|
||||
merge(&mut settings.default_profile, value.default_profile.clone());
|
||||
merge(&mut settings.default_view, value.default_view);
|
||||
merge(
|
||||
&mut settings.preferred_completion_mode,
|
||||
value.preferred_completion_mode,
|
||||
);
|
||||
merge(&mut settings.enable_feedback, value.enable_feedback);
|
||||
merge(&mut settings.expand_edit_card, value.expand_edit_card);
|
||||
merge(
|
||||
&mut settings.expand_terminal_card,
|
||||
value.expand_terminal_card,
|
||||
);
|
||||
merge(
|
||||
&mut settings.use_modifier_to_send,
|
||||
value.use_modifier_to_send,
|
||||
);
|
||||
merge(
|
||||
&mut settings.message_editor_min_lines,
|
||||
value.message_editor_min_lines,
|
||||
);
|
||||
|
||||
settings
|
||||
.model_parameters
|
||||
.extend_from_slice(&value.model_parameters);
|
||||
|
||||
if let Some(profiles) = value.profiles.as_ref() {
|
||||
settings
|
||||
.profiles
|
||||
.extend(profiles.into_iter().map(|(id, profile)| {
|
||||
(
|
||||
id.clone(),
|
||||
AgentProfileSettings {
|
||||
name: profile.name.clone().into(),
|
||||
tools: profile.tools.clone(),
|
||||
enable_all_context_servers: profile
|
||||
.enable_all_context_servers
|
||||
.unwrap_or_default(),
|
||||
context_servers: profile
|
||||
.context_servers
|
||||
.iter()
|
||||
.map(|(context_server_id, preset)| {
|
||||
(
|
||||
context_server_id.clone(),
|
||||
ContextServerPreset {
|
||||
tools: preset.tools.clone(),
|
||||
},
|
||||
)
|
||||
})
|
||||
.collect(),
|
||||
},
|
||||
)
|
||||
}));
|
||||
}
|
||||
fn from_defaults(content: &settings::SettingsContent, _cx: &mut App) -> Self {
|
||||
let agent = content.agent.clone().unwrap();
|
||||
Self {
|
||||
enabled: agent.enabled.unwrap(),
|
||||
button: agent.button.unwrap(),
|
||||
dock: agent.dock.unwrap(),
|
||||
default_width: px(agent.default_width.unwrap()),
|
||||
default_height: px(agent.default_height.unwrap()),
|
||||
default_model: Some(agent.default_model.unwrap()),
|
||||
inline_assistant_model: agent.inline_assistant_model,
|
||||
commit_message_model: agent.commit_message_model,
|
||||
thread_summary_model: agent.thread_summary_model,
|
||||
inline_alternatives: agent.inline_alternatives.unwrap_or_default(),
|
||||
default_profile: AgentProfileId(agent.default_profile.unwrap()),
|
||||
default_view: agent.default_view.unwrap(),
|
||||
profiles: agent
|
||||
.profiles
|
||||
.unwrap()
|
||||
.into_iter()
|
||||
.map(|(key, val)| (AgentProfileId(key), val.into()))
|
||||
.collect(),
|
||||
always_allow_tool_actions: agent.always_allow_tool_actions.unwrap(),
|
||||
notify_when_agent_waiting: agent.notify_when_agent_waiting.unwrap(),
|
||||
play_sound_when_agent_done: agent.play_sound_when_agent_done.unwrap(),
|
||||
stream_edits: agent.stream_edits.unwrap(),
|
||||
single_file_review: agent.single_file_review.unwrap(),
|
||||
model_parameters: agent.model_parameters,
|
||||
preferred_completion_mode: agent.preferred_completion_mode.unwrap().into(),
|
||||
enable_feedback: agent.enable_feedback.unwrap(),
|
||||
expand_edit_card: agent.expand_edit_card.unwrap(),
|
||||
expand_terminal_card: agent.expand_terminal_card.unwrap(),
|
||||
use_modifier_to_send: agent.use_modifier_to_send.unwrap(),
|
||||
message_editor_min_lines: agent.message_editor_min_lines.unwrap(),
|
||||
}
|
||||
|
||||
debug_assert!(
|
||||
!sources.default.always_allow_tool_actions.unwrap_or(false),
|
||||
"For security, agent.always_allow_tool_actions should always be false in default.json. If it's true, that is a bug that should be fixed!"
|
||||
);
|
||||
|
||||
// For security reasons, only trust the user's global settings for whether to always allow tool actions.
|
||||
// If this could be overridden locally, an attacker could (e.g. by committing to source control and
|
||||
// convincing you to switch branches) modify your project-local settings to disable the agent's safety checks.
|
||||
settings.always_allow_tool_actions = sources
|
||||
.user
|
||||
.and_then(|setting| setting.always_allow_tool_actions)
|
||||
.unwrap_or(false);
|
||||
|
||||
Ok(settings)
|
||||
}
|
||||
|
||||
fn import_from_vscode(vscode: &settings::VsCodeSettings, current: &mut Self::FileContent) {
|
||||
fn refine(&mut self, content: &settings::SettingsContent, _: &mut App) {
|
||||
let Some(value) = &content.agent else { return };
|
||||
self.enabled.merge_from(&value.enabled);
|
||||
self.button.merge_from(&value.button);
|
||||
self.dock.merge_from(&value.dock);
|
||||
self.default_width
|
||||
.merge_from(&value.default_width.map(Into::into));
|
||||
self.default_height
|
||||
.merge_from(&value.default_height.map(Into::into));
|
||||
self.default_model = value.default_model.clone().or(self.default_model.take());
|
||||
|
||||
self.inline_assistant_model = value
|
||||
.inline_assistant_model
|
||||
.clone()
|
||||
.or(self.inline_assistant_model.take());
|
||||
self.commit_message_model = value
|
||||
.clone()
|
||||
.commit_message_model
|
||||
.or(self.commit_message_model.take());
|
||||
self.thread_summary_model = value
|
||||
.clone()
|
||||
.thread_summary_model
|
||||
.or(self.thread_summary_model.take());
|
||||
self.inline_alternatives
|
||||
.merge_from(&value.inline_alternatives.clone());
|
||||
self.default_profile
|
||||
.merge_from(&value.default_profile.clone().map(AgentProfileId));
|
||||
self.default_view.merge_from(&value.default_view);
|
||||
self.always_allow_tool_actions
|
||||
.merge_from(&value.always_allow_tool_actions);
|
||||
self.notify_when_agent_waiting
|
||||
.merge_from(&value.notify_when_agent_waiting);
|
||||
self.play_sound_when_agent_done
|
||||
.merge_from(&value.play_sound_when_agent_done);
|
||||
self.stream_edits.merge_from(&value.stream_edits);
|
||||
self.single_file_review
|
||||
.merge_from(&value.single_file_review);
|
||||
self.preferred_completion_mode
|
||||
.merge_from(&value.preferred_completion_mode.map(Into::into));
|
||||
self.enable_feedback.merge_from(&value.enable_feedback);
|
||||
self.expand_edit_card.merge_from(&value.expand_edit_card);
|
||||
self.expand_terminal_card
|
||||
.merge_from(&value.expand_terminal_card);
|
||||
self.use_modifier_to_send
|
||||
.merge_from(&value.use_modifier_to_send);
|
||||
|
||||
self.model_parameters
|
||||
.extend_from_slice(&value.model_parameters);
|
||||
self.message_editor_min_lines
|
||||
.merge_from(&value.message_editor_min_lines);
|
||||
|
||||
if let Some(profiles) = value.profiles.as_ref() {
|
||||
self.profiles.extend(
|
||||
profiles
|
||||
.into_iter()
|
||||
.map(|(id, profile)| (AgentProfileId(id.clone()), profile.clone().into())),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn import_from_vscode(vscode: &settings::VsCodeSettings, current: &mut SettingsContent) {
|
||||
if let Some(b) = vscode
|
||||
.read_value("chat.agent.enabled")
|
||||
.and_then(|b| b.as_bool())
|
||||
{
|
||||
current.enabled = Some(b);
|
||||
current.button = Some(b);
|
||||
current.agent.get_or_insert_default().enabled = Some(b);
|
||||
current.agent.get_or_insert_default().button = Some(b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn merge<T>(target: &mut T, value: Option<T>) {
|
||||
if let Some(value) = value {
|
||||
*target = value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ use acp_thread::{AgentConnection, Plan};
|
||||
use action_log::ActionLog;
|
||||
use agent_client_protocol::{self as acp, PromptCapabilities};
|
||||
use agent_servers::{AgentServer, AgentServerDelegate};
|
||||
use agent_settings::{AgentProfileId, AgentSettings, CompletionMode, NotifyWhenAgentWaiting};
|
||||
use agent_settings::{AgentProfileId, AgentSettings, CompletionMode};
|
||||
use agent2::{DbThreadMetadata, HistoryEntry, HistoryEntryId, HistoryStore, NativeAgentServer};
|
||||
use anyhow::{Result, anyhow, bail};
|
||||
use arrayvec::ArrayVec;
|
||||
@@ -35,7 +35,7 @@ use markdown::{HeadingLevelStyles, Markdown, MarkdownElement, MarkdownStyle};
|
||||
use project::{Project, ProjectEntryId};
|
||||
use prompt_store::{PromptId, PromptStore};
|
||||
use rope::Point;
|
||||
use settings::{Settings as _, SettingsStore};
|
||||
use settings::{NotifyWhenAgentWaiting, Settings as _, SettingsStore};
|
||||
use std::cell::RefCell;
|
||||
use std::path::Path;
|
||||
use std::sync::Arc;
|
||||
|
||||
@@ -26,12 +26,8 @@ use language_model::{
|
||||
};
|
||||
use notifications::status_toast::{StatusToast, ToastIcon};
|
||||
use project::{
|
||||
agent_server_store::{
|
||||
AgentServerCommand, AgentServerStore, AllAgentServersSettings, CLAUDE_CODE_NAME,
|
||||
CustomAgentServerSettings, GEMINI_NAME,
|
||||
},
|
||||
agent_server_store::{AgentServerStore, CLAUDE_CODE_NAME, GEMINI_NAME},
|
||||
context_server_store::{ContextServerConfiguration, ContextServerStatus, ContextServerStore},
|
||||
project_settings::{ContextServerSettings, ProjectSettings},
|
||||
};
|
||||
use settings::{Settings, SettingsStore, update_settings_file};
|
||||
use ui::{
|
||||
@@ -419,8 +415,8 @@ impl AgentConfiguration {
|
||||
always_allow_tool_actions,
|
||||
move |state, _window, cx| {
|
||||
let allow = state == &ToggleState::Selected;
|
||||
update_settings_file::<AgentSettings>(fs.clone(), cx, move |settings, _| {
|
||||
settings.set_always_allow_tool_actions(allow);
|
||||
update_settings_file(fs.clone(), cx, move |settings, _| {
|
||||
settings.agent.get_or_insert_default().set_always_allow_tool_actions(allow);
|
||||
});
|
||||
},
|
||||
)
|
||||
@@ -437,8 +433,11 @@ impl AgentConfiguration {
|
||||
single_file_review,
|
||||
move |state, _window, cx| {
|
||||
let allow = state == &ToggleState::Selected;
|
||||
update_settings_file::<AgentSettings>(fs.clone(), cx, move |settings, _| {
|
||||
settings.set_single_file_review(allow);
|
||||
update_settings_file(fs.clone(), cx, move |settings, _| {
|
||||
settings
|
||||
.agent
|
||||
.get_or_insert_default()
|
||||
.set_single_file_review(allow);
|
||||
});
|
||||
},
|
||||
)
|
||||
@@ -457,8 +456,8 @@ impl AgentConfiguration {
|
||||
play_sound_when_agent_done,
|
||||
move |state, _window, cx| {
|
||||
let allow = state == &ToggleState::Selected;
|
||||
update_settings_file::<AgentSettings>(fs.clone(), cx, move |settings, _| {
|
||||
settings.set_play_sound_when_agent_done(allow);
|
||||
update_settings_file(fs.clone(), cx, move |settings, _| {
|
||||
settings.agent.get_or_insert_default().set_play_sound_when_agent_done(allow);
|
||||
});
|
||||
},
|
||||
)
|
||||
@@ -477,8 +476,8 @@ impl AgentConfiguration {
|
||||
use_modifier_to_send,
|
||||
move |state, _window, cx| {
|
||||
let allow = state == &ToggleState::Selected;
|
||||
update_settings_file::<AgentSettings>(fs.clone(), cx, move |settings, _| {
|
||||
settings.set_use_modifier_to_send(allow);
|
||||
update_settings_file(fs.clone(), cx, move |settings, _| {
|
||||
settings.agent.get_or_insert_default().set_use_modifier_to_send(allow);
|
||||
});
|
||||
},
|
||||
)
|
||||
@@ -862,14 +861,14 @@ impl AgentConfiguration {
|
||||
async move |cx| {
|
||||
uninstall_extension_task.await?;
|
||||
cx.update(|cx| {
|
||||
update_settings_file::<ProjectSettings>(
|
||||
update_settings_file(
|
||||
fs.clone(),
|
||||
cx,
|
||||
{
|
||||
let context_server_id =
|
||||
context_server_id.clone();
|
||||
move |settings, _| {
|
||||
settings
|
||||
settings.project
|
||||
.context_servers
|
||||
.remove(&context_server_id.0);
|
||||
}
|
||||
@@ -944,67 +943,53 @@ impl AgentConfiguration {
|
||||
.flex_none()
|
||||
.child(context_server_configuration_menu)
|
||||
.child(
|
||||
Switch::new("context-server-switch", is_running.into())
|
||||
.color(SwitchColor::Accent)
|
||||
.on_click({
|
||||
let context_server_manager =
|
||||
self.context_server_store.clone();
|
||||
let fs = self.fs.clone();
|
||||
Switch::new("context-server-switch", is_running.into())
|
||||
.color(SwitchColor::Accent)
|
||||
.on_click({
|
||||
let context_server_manager = self.context_server_store.clone();
|
||||
let fs = self.fs.clone();
|
||||
|
||||
move |state, _window, cx| {
|
||||
let is_enabled = match state {
|
||||
ToggleState::Unselected
|
||||
| ToggleState::Indeterminate => {
|
||||
context_server_manager.update(
|
||||
cx,
|
||||
|this, cx| {
|
||||
this.stop_server(
|
||||
&context_server_id,
|
||||
cx,
|
||||
)
|
||||
.log_err();
|
||||
},
|
||||
);
|
||||
false
|
||||
}
|
||||
ToggleState::Selected => {
|
||||
context_server_manager.update(
|
||||
cx,
|
||||
|this, cx| {
|
||||
if let Some(server) =
|
||||
this.get_server(&context_server_id)
|
||||
{
|
||||
this.start_server(server, cx);
|
||||
}
|
||||
},
|
||||
);
|
||||
true
|
||||
}
|
||||
};
|
||||
update_settings_file::<ProjectSettings>(
|
||||
fs.clone(),
|
||||
cx,
|
||||
{
|
||||
let context_server_id =
|
||||
context_server_id.clone();
|
||||
|
||||
move |settings, _| {
|
||||
settings
|
||||
.context_servers
|
||||
.entry(context_server_id.0)
|
||||
.or_insert_with(|| {
|
||||
ContextServerSettings::Extension {
|
||||
enabled: is_enabled,
|
||||
settings: serde_json::json!({}),
|
||||
}
|
||||
})
|
||||
.set_enabled(is_enabled);
|
||||
move |state, _window, cx| {
|
||||
let is_enabled = match state {
|
||||
ToggleState::Unselected
|
||||
| ToggleState::Indeterminate => {
|
||||
context_server_manager.update(cx, |this, cx| {
|
||||
this.stop_server(&context_server_id, cx)
|
||||
.log_err();
|
||||
});
|
||||
false
|
||||
}
|
||||
ToggleState::Selected => {
|
||||
context_server_manager.update(cx, |this, cx| {
|
||||
if let Some(server) =
|
||||
this.get_server(&context_server_id)
|
||||
{
|
||||
this.start_server(server, cx);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
}),
|
||||
),
|
||||
});
|
||||
true
|
||||
}
|
||||
};
|
||||
update_settings_file(fs.clone(), cx, {
|
||||
let context_server_id = context_server_id.clone();
|
||||
|
||||
move |settings, _| {
|
||||
settings
|
||||
.project
|
||||
.context_servers
|
||||
.entry(context_server_id.0)
|
||||
.or_insert_with(|| {
|
||||
settings::ContextServerSettingsContent::Extension {
|
||||
enabled: is_enabled,
|
||||
settings: serde_json::json!({}),
|
||||
}
|
||||
})
|
||||
.set_enabled(is_enabled);
|
||||
}
|
||||
});
|
||||
}
|
||||
}),
|
||||
),
|
||||
),
|
||||
)
|
||||
.map(|parent| {
|
||||
@@ -1236,15 +1221,12 @@ fn show_unable_to_uninstall_extension_with_context_server(
|
||||
let context_server_id = context_server_id.clone();
|
||||
async move |_workspace_handle, cx| {
|
||||
cx.update(|cx| {
|
||||
update_settings_file::<ProjectSettings>(
|
||||
fs,
|
||||
cx,
|
||||
move |settings, _| {
|
||||
settings
|
||||
.context_servers
|
||||
.remove(&context_server_id.0);
|
||||
},
|
||||
);
|
||||
update_settings_file(fs, cx, move |settings, _| {
|
||||
settings
|
||||
.project
|
||||
.context_servers
|
||||
.remove(&context_server_id.0);
|
||||
});
|
||||
})?;
|
||||
anyhow::Ok(())
|
||||
}
|
||||
@@ -1282,7 +1264,7 @@ async fn open_new_agent_servers_entry_in_settings_editor(
|
||||
let settings = cx.global::<SettingsStore>();
|
||||
|
||||
let mut unique_server_name = None;
|
||||
let edits = settings.edits_for_update::<AllAgentServersSettings>(&text, |file| {
|
||||
let edits = settings.edits_for_update(&text, |settings| {
|
||||
let server_name: Option<SharedString> = (0..u8::MAX)
|
||||
.map(|i| {
|
||||
if i == 0 {
|
||||
@@ -1291,20 +1273,27 @@ async fn open_new_agent_servers_entry_in_settings_editor(
|
||||
format!("your_agent_{}", i).into()
|
||||
}
|
||||
})
|
||||
.find(|name| !file.custom.contains_key(name));
|
||||
.find(|name| {
|
||||
!settings
|
||||
.agent_servers
|
||||
.as_ref()
|
||||
.is_some_and(|agent_servers| agent_servers.custom.contains_key(name))
|
||||
});
|
||||
if let Some(server_name) = server_name {
|
||||
unique_server_name = Some(server_name.clone());
|
||||
file.custom.insert(
|
||||
server_name,
|
||||
CustomAgentServerSettings {
|
||||
command: AgentServerCommand {
|
||||
settings
|
||||
.agent_servers
|
||||
.get_or_insert_default()
|
||||
.custom
|
||||
.insert(
|
||||
server_name,
|
||||
settings::CustomAgentServerSettings {
|
||||
path: "path_to_executable".into(),
|
||||
args: vec![],
|
||||
env: Some(HashMap::default()),
|
||||
default_mode: None,
|
||||
},
|
||||
default_mode: None,
|
||||
},
|
||||
);
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -5,11 +5,8 @@ use collections::HashSet;
|
||||
use fs::Fs;
|
||||
use gpui::{DismissEvent, Entity, EventEmitter, FocusHandle, Focusable, Render, Task};
|
||||
use language_model::LanguageModelRegistry;
|
||||
use language_models::{
|
||||
AllLanguageModelSettings, OpenAiCompatibleSettingsContent,
|
||||
provider::open_ai_compatible::{AvailableModel, ModelCapabilities},
|
||||
};
|
||||
use settings::update_settings_file;
|
||||
use language_models::provider::open_ai_compatible::{AvailableModel, ModelCapabilities};
|
||||
use settings::{OpenAiCompatibleSettingsContent, update_settings_file};
|
||||
use ui::{
|
||||
Banner, Checkbox, KeyBinding, Modal, ModalFooter, ModalHeader, Section, ToggleState, prelude::*,
|
||||
};
|
||||
@@ -238,14 +235,19 @@ fn save_provider_to_settings(
|
||||
task.await
|
||||
.map_err(|_| "Failed to write API key to keychain")?;
|
||||
cx.update(|cx| {
|
||||
update_settings_file::<AllLanguageModelSettings>(fs, cx, |settings, _cx| {
|
||||
settings.openai_compatible.get_or_insert_default().insert(
|
||||
provider_name,
|
||||
OpenAiCompatibleSettingsContent {
|
||||
api_url,
|
||||
available_models: models,
|
||||
},
|
||||
);
|
||||
update_settings_file(fs, cx, |settings, _cx| {
|
||||
settings
|
||||
.language_models
|
||||
.get_or_insert_default()
|
||||
.openai_compatible
|
||||
.get_or_insert_default()
|
||||
.insert(
|
||||
provider_name,
|
||||
OpenAiCompatibleSettingsContent {
|
||||
api_url,
|
||||
available_models: models,
|
||||
},
|
||||
);
|
||||
});
|
||||
})
|
||||
.ok();
|
||||
|
||||
@@ -422,18 +422,17 @@ impl ConfigureContextServerModal {
|
||||
workspace.update(cx, |workspace, cx| {
|
||||
let fs = workspace.app_state().fs.clone();
|
||||
let original_server_id = self.original_server_id.clone();
|
||||
update_settings_file::<ProjectSettings>(
|
||||
fs.clone(),
|
||||
cx,
|
||||
move |project_settings, _| {
|
||||
if let Some(original_id) = original_server_id {
|
||||
if original_id != id {
|
||||
project_settings.context_servers.remove(&original_id.0);
|
||||
}
|
||||
update_settings_file(fs.clone(), cx, move |current, _| {
|
||||
if let Some(original_id) = original_server_id {
|
||||
if original_id != id {
|
||||
current.project.context_servers.remove(&original_id.0);
|
||||
}
|
||||
project_settings.context_servers.insert(id.0, settings);
|
||||
},
|
||||
);
|
||||
}
|
||||
current
|
||||
.project
|
||||
.context_servers
|
||||
.insert(id.0, settings.into());
|
||||
});
|
||||
});
|
||||
} else if let Some(existing_server) = existing_server {
|
||||
self.context_server_store
|
||||
|
||||
@@ -1,14 +1,11 @@
|
||||
use std::{collections::BTreeMap, sync::Arc};
|
||||
|
||||
use agent_settings::{
|
||||
AgentProfileContent, AgentProfileId, AgentProfileSettings, AgentSettings, AgentSettingsContent,
|
||||
ContextServerPresetContent,
|
||||
};
|
||||
use agent_settings::{AgentProfileId, AgentProfileSettings};
|
||||
use assistant_tool::{ToolSource, ToolWorkingSet};
|
||||
use fs::Fs;
|
||||
use gpui::{App, Context, DismissEvent, Entity, EventEmitter, Focusable, Task, WeakEntity, Window};
|
||||
use picker::{Picker, PickerDelegate};
|
||||
use settings::update_settings_file;
|
||||
use settings::{AgentProfileContent, ContextServerPresetContent, update_settings_file};
|
||||
use ui::{ListItem, ListItemSpacing, prelude::*};
|
||||
use util::ResultExt as _;
|
||||
|
||||
@@ -266,15 +263,19 @@ impl PickerDelegate for ToolPickerDelegate {
|
||||
is_enabled
|
||||
};
|
||||
|
||||
update_settings_file::<AgentSettings>(self.fs.clone(), cx, {
|
||||
update_settings_file(self.fs.clone(), cx, {
|
||||
let profile_id = self.profile_id.clone();
|
||||
let default_profile = self.profile_settings.clone();
|
||||
let server_id = server_id.clone();
|
||||
let tool_name = tool_name.clone();
|
||||
move |settings: &mut AgentSettingsContent, _cx| {
|
||||
let profiles = settings.profiles.get_or_insert_default();
|
||||
move |settings, _cx| {
|
||||
let profiles = settings
|
||||
.agent
|
||||
.get_or_insert_default()
|
||||
.profiles
|
||||
.get_or_insert_default();
|
||||
let profile = profiles
|
||||
.entry(profile_id)
|
||||
.entry(profile_id.0)
|
||||
.or_insert_with(|| AgentProfileContent {
|
||||
name: default_profile.name.into(),
|
||||
tools: default_profile.tools,
|
||||
|
||||
@@ -2,7 +2,6 @@ use crate::{
|
||||
ModelUsageContext,
|
||||
language_model_selector::{LanguageModelSelector, language_model_selector},
|
||||
};
|
||||
use agent_settings::AgentSettings;
|
||||
use fs::Fs;
|
||||
use gpui::{Entity, FocusHandle, SharedString};
|
||||
use picker::popover_menu::PickerPopoverMenu;
|
||||
@@ -39,14 +38,12 @@ impl AgentModelSelector {
|
||||
let model_id = model.id().0.to_string();
|
||||
match &model_usage_context {
|
||||
ModelUsageContext::InlineAssistant => {
|
||||
update_settings_file::<AgentSettings>(
|
||||
fs.clone(),
|
||||
cx,
|
||||
move |settings, _cx| {
|
||||
settings
|
||||
.set_inline_assistant_model(provider.clone(), model_id);
|
||||
},
|
||||
);
|
||||
update_settings_file(fs.clone(), cx, move |settings, _cx| {
|
||||
settings
|
||||
.agent
|
||||
.get_or_insert_default()
|
||||
.set_inline_assistant_model(provider.clone(), model_id);
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -10,6 +10,9 @@ use project::agent_server_store::{
|
||||
AgentServerCommand, AllAgentServersSettings, CLAUDE_CODE_NAME, GEMINI_NAME,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use settings::{
|
||||
DefaultAgentView as DefaultView, LanguageModelProviderSetting, LanguageModelSelection,
|
||||
};
|
||||
use zed_actions::OpenBrowser;
|
||||
use zed_actions::agent::{OpenClaudeCodeOnboardingModal, ReauthenticateAgent};
|
||||
|
||||
@@ -33,7 +36,7 @@ use agent::{
|
||||
history_store::{HistoryEntryId, HistoryStore},
|
||||
thread_store::{TextThreadStore, ThreadStore},
|
||||
};
|
||||
use agent_settings::{AgentDockPosition, AgentSettings, DefaultView};
|
||||
use agent_settings::AgentSettings;
|
||||
use ai_onboarding::AgentPanelOnboarding;
|
||||
use anyhow::{Result, anyhow};
|
||||
use assistant_context::{AssistantContext, ContextEvent, ContextSummary};
|
||||
@@ -1058,17 +1061,14 @@ impl AgentPanel {
|
||||
match self.active_view.which_font_size_used() {
|
||||
WhichFontSize::AgentFont => {
|
||||
if persist {
|
||||
update_settings_file::<ThemeSettings>(
|
||||
self.fs.clone(),
|
||||
cx,
|
||||
move |settings, cx| {
|
||||
let agent_font_size =
|
||||
ThemeSettings::get_global(cx).agent_font_size(cx) + delta;
|
||||
let _ = settings
|
||||
.agent_font_size
|
||||
.insert(Some(theme::clamp_font_size(agent_font_size).into()));
|
||||
},
|
||||
);
|
||||
update_settings_file(self.fs.clone(), cx, move |settings, cx| {
|
||||
let agent_font_size =
|
||||
ThemeSettings::get_global(cx).agent_font_size(cx) + delta;
|
||||
let _ = settings
|
||||
.theme
|
||||
.agent_font_size
|
||||
.insert(Some(theme::clamp_font_size(agent_font_size).into()));
|
||||
});
|
||||
} else {
|
||||
theme::adjust_agent_font_size(cx, |size| size + delta);
|
||||
}
|
||||
@@ -1089,8 +1089,8 @@ impl AgentPanel {
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
if action.persist {
|
||||
update_settings_file::<ThemeSettings>(self.fs.clone(), cx, move |settings, _| {
|
||||
settings.agent_font_size = None;
|
||||
update_settings_file(self.fs.clone(), cx, move |settings, _| {
|
||||
settings.theme.agent_font_size = None;
|
||||
});
|
||||
} else {
|
||||
theme::reset_agent_font_size(cx);
|
||||
@@ -1175,11 +1175,17 @@ impl AgentPanel {
|
||||
.is_none_or(|model| model.provider.id() != provider.id())
|
||||
&& let Some(model) = provider.default_model(cx)
|
||||
{
|
||||
update_settings_file::<AgentSettings>(
|
||||
self.fs.clone(),
|
||||
cx,
|
||||
move |settings, _| settings.set_model(model),
|
||||
);
|
||||
update_settings_file(self.fs.clone(), cx, move |settings, _| {
|
||||
let provider = model.provider_id().0.to_string();
|
||||
let model = model.id().0.to_string();
|
||||
settings
|
||||
.agent
|
||||
.get_or_insert_default()
|
||||
.set_model(LanguageModelSelection {
|
||||
provider: LanguageModelProviderSetting(provider),
|
||||
model,
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
self.new_thread(&NewThread::default(), window, cx);
|
||||
@@ -1424,11 +1430,7 @@ impl Focusable for AgentPanel {
|
||||
}
|
||||
|
||||
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,
|
||||
}
|
||||
AgentSettings::get_global(cx).dock.into()
|
||||
}
|
||||
|
||||
impl EventEmitter<PanelEvent> for AgentPanel {}
|
||||
@@ -1447,13 +1449,11 @@ impl Panel for AgentPanel {
|
||||
}
|
||||
|
||||
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(self.fs.clone(), cx, move |settings, _| {
|
||||
settings
|
||||
.agent
|
||||
.get_or_insert_default()
|
||||
.set_dock(position.into());
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ use std::rc::Rc;
|
||||
use std::sync::Arc;
|
||||
|
||||
use agent::ThreadId;
|
||||
use agent_settings::{AgentProfileId, AgentSettings, LanguageModelSelection};
|
||||
use agent_settings::{AgentProfileId, AgentSettings};
|
||||
use assistant_slash_command::SlashCommandRegistry;
|
||||
use client::Client;
|
||||
use command_palette_hooks::CommandPaletteFilter;
|
||||
@@ -39,7 +39,7 @@ use project::agent_server_store::AgentServerCommand;
|
||||
use prompt_store::PromptBuilder;
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use settings::{Settings as _, SettingsStore};
|
||||
use settings::{LanguageModelSelection, Settings as _, SettingsStore};
|
||||
use std::any::TypeId;
|
||||
|
||||
use crate::agent_configuration::{ConfigureContextServerModal, ManageProfilesModal};
|
||||
|
||||
@@ -5,7 +5,6 @@ use extension::ExtensionManifest;
|
||||
use fs::Fs;
|
||||
use gpui::WeakEntity;
|
||||
use language::LanguageRegistry;
|
||||
use project::project_settings::ProjectSettings;
|
||||
use settings::update_settings_file;
|
||||
use ui::prelude::*;
|
||||
use util::ResultExt;
|
||||
@@ -69,8 +68,9 @@ fn remove_context_server_settings(
|
||||
fs: Arc<dyn Fs>,
|
||||
cx: &mut App,
|
||||
) {
|
||||
update_settings_file::<ProjectSettings>(fs, cx, move |settings, _| {
|
||||
update_settings_file(fs, cx, move |settings, _| {
|
||||
settings
|
||||
.project
|
||||
.context_servers
|
||||
.retain(|server_id, _| !context_server_ids.contains(server_id));
|
||||
});
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
use crate::{ManageProfiles, ToggleProfileSelector};
|
||||
use agent_settings::{
|
||||
AgentDockPosition, AgentProfile, AgentProfileId, AgentSettings, AvailableProfiles,
|
||||
builtin_profiles,
|
||||
AgentProfile, AgentProfileId, AgentSettings, AvailableProfiles, builtin_profiles,
|
||||
};
|
||||
use fs::Fs;
|
||||
use gpui::{Action, Entity, FocusHandle, Subscription, prelude::*};
|
||||
use settings::{Settings as _, SettingsStore, update_settings_file};
|
||||
use settings::{DockPosition, Settings as _, SettingsStore, update_settings_file};
|
||||
use std::sync::Arc;
|
||||
use ui::{
|
||||
ContextMenu, ContextMenuEntry, DocumentationEdge, DocumentationSide, PopoverMenu,
|
||||
@@ -142,10 +141,13 @@ impl ProfileSelector {
|
||||
let fs = self.fs.clone();
|
||||
let provider = self.provider.clone();
|
||||
move |_window, cx| {
|
||||
update_settings_file::<AgentSettings>(fs.clone(), cx, {
|
||||
update_settings_file(fs.clone(), cx, {
|
||||
let profile_id = profile_id.clone();
|
||||
move |settings, _cx| {
|
||||
settings.set_profile(profile_id);
|
||||
settings
|
||||
.agent
|
||||
.get_or_insert_default()
|
||||
.set_profile(profile_id.0);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -216,10 +218,10 @@ impl Render for ProfileSelector {
|
||||
}
|
||||
}
|
||||
|
||||
fn documentation_side(position: AgentDockPosition) -> DocumentationSide {
|
||||
fn documentation_side(position: DockPosition) -> DocumentationSide {
|
||||
match position {
|
||||
AgentDockPosition::Left => DocumentationSide::Right,
|
||||
AgentDockPosition::Bottom => DocumentationSide::Left,
|
||||
AgentDockPosition::Right => DocumentationSide::Left,
|
||||
DockPosition::Left => DocumentationSide::Right,
|
||||
DockPosition::Bottom => DocumentationSide::Left,
|
||||
DockPosition::Right => DocumentationSide::Left,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ use crate::{
|
||||
language_model_selector::{LanguageModelSelector, language_model_selector},
|
||||
ui::BurnModeTooltip,
|
||||
};
|
||||
use agent_settings::{AgentSettings, CompletionMode};
|
||||
use agent_settings::CompletionMode;
|
||||
use anyhow::Result;
|
||||
use assistant_slash_command::{SlashCommand, SlashCommandOutputSection, SlashCommandWorkingSet};
|
||||
use assistant_slash_commands::{DefaultSlashCommand, FileSlashCommand, selections_creases};
|
||||
@@ -41,7 +41,10 @@ use project::{Project, Worktree};
|
||||
use project::{ProjectPath, lsp_store::LocalLspAdapterDelegate};
|
||||
use rope::Point;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use settings::{Settings, SettingsStore, update_settings_file};
|
||||
use settings::{
|
||||
LanguageModelProviderSetting, LanguageModelSelection, Settings, SettingsStore,
|
||||
update_settings_file,
|
||||
};
|
||||
use std::{
|
||||
any::TypeId,
|
||||
cmp,
|
||||
@@ -294,11 +297,16 @@ impl TextThreadEditor {
|
||||
language_model_selector(
|
||||
|cx| LanguageModelRegistry::read_global(cx).default_model(),
|
||||
move |model, cx| {
|
||||
update_settings_file::<AgentSettings>(
|
||||
fs.clone(),
|
||||
cx,
|
||||
move |settings, _| settings.set_model(model.clone()),
|
||||
);
|
||||
update_settings_file(fs.clone(), cx, move |settings, _| {
|
||||
let provider = model.provider_id().0.to_string();
|
||||
let model = model.id().0.to_string();
|
||||
settings.agent.get_or_insert_default().set_model(
|
||||
LanguageModelSelection {
|
||||
provider: LanguageModelProviderSetting(provider),
|
||||
model,
|
||||
},
|
||||
)
|
||||
});
|
||||
},
|
||||
window,
|
||||
cx,
|
||||
|
||||
@@ -23,6 +23,7 @@ http_client.workspace = true
|
||||
schemars = { workspace = true, optional = true }
|
||||
serde.workspace = true
|
||||
serde_json.workspace = true
|
||||
settings.workspace = true
|
||||
strum.workspace = true
|
||||
thiserror.workspace = true
|
||||
workspace-hack.workspace = true
|
||||
|
||||
@@ -8,6 +8,7 @@ use futures::{AsyncBufReadExt, AsyncReadExt, StreamExt, io::BufReader, stream::B
|
||||
use http_client::http::{self, HeaderMap, HeaderValue};
|
||||
use http_client::{AsyncBody, HttpClient, Method, Request as HttpRequest, StatusCode};
|
||||
use serde::{Deserialize, Serialize};
|
||||
pub use settings::{AnthropicAvailableModel as AvailableModel, ModelMode};
|
||||
use strum::{EnumIter, EnumString};
|
||||
use thiserror::Error;
|
||||
|
||||
@@ -31,6 +32,24 @@ pub enum AnthropicModelMode {
|
||||
},
|
||||
}
|
||||
|
||||
impl From<ModelMode> for AnthropicModelMode {
|
||||
fn from(value: ModelMode) -> Self {
|
||||
match value {
|
||||
ModelMode::Default => AnthropicModelMode::Default,
|
||||
ModelMode::Thinking { budget_tokens } => AnthropicModelMode::Thinking { budget_tokens },
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<AnthropicModelMode> for ModelMode {
|
||||
fn from(value: AnthropicModelMode) -> Self {
|
||||
match value {
|
||||
AnthropicModelMode::Default => ModelMode::Default,
|
||||
AnthropicModelMode::Thinking { budget_tokens } => ModelMode::Thinking { budget_tokens },
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
|
||||
#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq, EnumIter)]
|
||||
pub enum Model {
|
||||
|
||||
@@ -1445,8 +1445,8 @@ mod tests {
|
||||
|
||||
fn init_test_with_config(cx: &mut TestAppContext, data_dir: &Path) {
|
||||
cx.update(|cx| {
|
||||
// Set custom data directory (config will be under data_dir/config)
|
||||
paths::set_custom_data_dir(data_dir.to_str().unwrap());
|
||||
// Set custom data directory (config will be under data_dir/config)
|
||||
|
||||
let settings_store = SettingsStore::test(cx);
|
||||
cx.set_global(settings_store);
|
||||
@@ -1537,14 +1537,11 @@ mod tests {
|
||||
// First, test with format_on_save enabled
|
||||
cx.update(|cx| {
|
||||
SettingsStore::update_global(cx, |store, cx| {
|
||||
store.update_user_settings::<language::language_settings::AllLanguageSettings>(
|
||||
cx,
|
||||
|settings| {
|
||||
settings.defaults.format_on_save = Some(FormatOnSave::On);
|
||||
settings.defaults.formatter =
|
||||
Some(language::language_settings::SelectedFormatter::Auto);
|
||||
},
|
||||
);
|
||||
store.update_user_settings(cx, |settings| {
|
||||
settings.project.all_languages.defaults.format_on_save = Some(FormatOnSave::On);
|
||||
settings.project.all_languages.defaults.formatter =
|
||||
Some(language::language_settings::SelectedFormatter::Auto);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1603,12 +1600,10 @@ mod tests {
|
||||
// Next, test with format_on_save disabled
|
||||
cx.update(|cx| {
|
||||
SettingsStore::update_global(cx, |store, cx| {
|
||||
store.update_user_settings::<language::language_settings::AllLanguageSettings>(
|
||||
cx,
|
||||
|settings| {
|
||||
settings.defaults.format_on_save = Some(FormatOnSave::Off);
|
||||
},
|
||||
);
|
||||
store.update_user_settings(cx, |settings| {
|
||||
settings.project.all_languages.defaults.format_on_save =
|
||||
Some(FormatOnSave::Off);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1679,12 +1674,13 @@ mod tests {
|
||||
// First, test with remove_trailing_whitespace_on_save enabled
|
||||
cx.update(|cx| {
|
||||
SettingsStore::update_global(cx, |store, cx| {
|
||||
store.update_user_settings::<language::language_settings::AllLanguageSettings>(
|
||||
cx,
|
||||
|settings| {
|
||||
settings.defaults.remove_trailing_whitespace_on_save = Some(true);
|
||||
},
|
||||
);
|
||||
store.update_user_settings(cx, |settings| {
|
||||
settings
|
||||
.project
|
||||
.all_languages
|
||||
.defaults
|
||||
.remove_trailing_whitespace_on_save = Some(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1741,12 +1737,13 @@ mod tests {
|
||||
// Next, test with remove_trailing_whitespace_on_save disabled
|
||||
cx.update(|cx| {
|
||||
SettingsStore::update_global(cx, |store, cx| {
|
||||
store.update_user_settings::<language::language_settings::AllLanguageSettings>(
|
||||
cx,
|
||||
|settings| {
|
||||
settings.defaults.remove_trailing_whitespace_on_save = Some(false);
|
||||
},
|
||||
);
|
||||
store.update_user_settings(cx, |settings| {
|
||||
settings
|
||||
.project
|
||||
.all_languages
|
||||
.defaults
|
||||
.remove_trailing_whitespace_on_save = Some(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -314,7 +314,7 @@ mod tests {
|
||||
use gpui::{AppContext, TestAppContext, UpdateGlobal};
|
||||
use language::{Language, LanguageConfig, LanguageMatcher};
|
||||
use language_model::fake_provider::FakeLanguageModel;
|
||||
use project::{FakeFs, Project, WorktreeSettings};
|
||||
use project::{FakeFs, Project};
|
||||
use serde_json::json;
|
||||
use settings::SettingsStore;
|
||||
use unindent::Unindent;
|
||||
@@ -849,15 +849,14 @@ mod tests {
|
||||
|
||||
cx.update(|cx| {
|
||||
use gpui::UpdateGlobal;
|
||||
use project::WorktreeSettings;
|
||||
use settings::SettingsStore;
|
||||
SettingsStore::update_global(cx, |store, cx| {
|
||||
store.update_user_settings::<WorktreeSettings>(cx, |settings| {
|
||||
settings.file_scan_exclusions = Some(vec![
|
||||
store.update_user_settings(cx, |settings| {
|
||||
settings.project.worktree.file_scan_exclusions = Some(vec![
|
||||
"**/.secretdir".to_string(),
|
||||
"**/.mymetadata".to_string(),
|
||||
]);
|
||||
settings.private_files = Some(vec![
|
||||
settings.project.worktree.private_files = Some(vec![
|
||||
"**/.mysecrets".to_string(),
|
||||
"**/*.privatekey".to_string(),
|
||||
"**/*.mysensitive".to_string(),
|
||||
@@ -1158,10 +1157,10 @@ mod tests {
|
||||
// Set global settings
|
||||
cx.update(|cx| {
|
||||
SettingsStore::update_global(cx, |store, cx| {
|
||||
store.update_user_settings::<WorktreeSettings>(cx, |settings| {
|
||||
settings.file_scan_exclusions =
|
||||
store.update_user_settings(cx, |settings| {
|
||||
settings.project.worktree.file_scan_exclusions =
|
||||
Some(vec!["**/.git".to_string(), "**/node_modules".to_string()]);
|
||||
settings.private_files = Some(vec!["**/.env".to_string()]);
|
||||
settings.project.worktree.private_files = Some(vec!["**/.env".to_string()]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -230,7 +230,7 @@ mod tests {
|
||||
use gpui::{AppContext, TestAppContext, UpdateGlobal};
|
||||
use indoc::indoc;
|
||||
use language_model::fake_provider::FakeLanguageModel;
|
||||
use project::{FakeFs, Project, WorktreeSettings};
|
||||
use project::{FakeFs, Project};
|
||||
use serde_json::json;
|
||||
use settings::SettingsStore;
|
||||
use util::path;
|
||||
@@ -507,13 +507,13 @@ mod tests {
|
||||
// Configure settings explicitly
|
||||
cx.update(|cx| {
|
||||
SettingsStore::update_global(cx, |store, cx| {
|
||||
store.update_user_settings::<WorktreeSettings>(cx, |settings| {
|
||||
settings.file_scan_exclusions = Some(vec![
|
||||
store.update_user_settings(cx, |settings| {
|
||||
settings.project.worktree.file_scan_exclusions = Some(vec![
|
||||
"**/.secretdir".to_string(),
|
||||
"**/.mymetadata".to_string(),
|
||||
"**/.hidden_subdir".to_string(),
|
||||
]);
|
||||
settings.private_files = Some(vec![
|
||||
settings.project.worktree.private_files = Some(vec![
|
||||
"**/.mysecrets".to_string(),
|
||||
"**/*.privatekey".to_string(),
|
||||
"**/*.mysensitive".to_string(),
|
||||
@@ -698,10 +698,10 @@ mod tests {
|
||||
// Set global settings
|
||||
cx.update(|cx| {
|
||||
SettingsStore::update_global(cx, |store, cx| {
|
||||
store.update_user_settings::<WorktreeSettings>(cx, |settings| {
|
||||
settings.file_scan_exclusions =
|
||||
store.update_user_settings(cx, |settings| {
|
||||
settings.project.worktree.file_scan_exclusions =
|
||||
Some(vec!["**/.git".to_string(), "**/node_modules".to_string()]);
|
||||
settings.private_files = Some(vec!["**/.env".to_string()]);
|
||||
settings.project.worktree.private_files = Some(vec!["**/.env".to_string()]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -299,7 +299,7 @@ mod test {
|
||||
use gpui::{AppContext, TestAppContext, UpdateGlobal};
|
||||
use language::{Language, LanguageConfig, LanguageMatcher};
|
||||
use language_model::fake_provider::FakeLanguageModel;
|
||||
use project::{FakeFs, Project, WorktreeSettings};
|
||||
use project::{FakeFs, Project};
|
||||
use serde_json::json;
|
||||
use settings::SettingsStore;
|
||||
use util::path;
|
||||
@@ -677,15 +677,14 @@ mod test {
|
||||
|
||||
cx.update(|cx| {
|
||||
use gpui::UpdateGlobal;
|
||||
use project::WorktreeSettings;
|
||||
use settings::SettingsStore;
|
||||
SettingsStore::update_global(cx, |store, cx| {
|
||||
store.update_user_settings::<WorktreeSettings>(cx, |settings| {
|
||||
settings.file_scan_exclusions = Some(vec![
|
||||
store.update_user_settings(cx, |settings| {
|
||||
settings.project.worktree.file_scan_exclusions = Some(vec![
|
||||
"**/.secretdir".to_string(),
|
||||
"**/.mymetadata".to_string(),
|
||||
]);
|
||||
settings.private_files = Some(vec![
|
||||
settings.project.worktree.private_files = Some(vec![
|
||||
"**/.mysecrets".to_string(),
|
||||
"**/*.privatekey".to_string(),
|
||||
"**/*.mysensitive".to_string(),
|
||||
@@ -968,10 +967,10 @@ mod test {
|
||||
// Set global settings
|
||||
cx.update(|cx| {
|
||||
SettingsStore::update_global(cx, |store, cx| {
|
||||
store.update_user_settings::<WorktreeSettings>(cx, |settings| {
|
||||
settings.file_scan_exclusions =
|
||||
store.update_user_settings(cx, |settings| {
|
||||
settings.project.worktree.file_scan_exclusions =
|
||||
Some(vec!["**/.git".to_string(), "**/node_modules".to_string()]);
|
||||
settings.private_files = Some(vec!["**/.env".to_string()]);
|
||||
settings.project.worktree.private_files = Some(vec!["**/.env".to_string()]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -21,7 +21,6 @@ gpui.workspace = true
|
||||
log.workspace = true
|
||||
parking_lot.workspace = true
|
||||
rodio = { workspace = true, features = [ "wav", "playback", "wav_output" ] }
|
||||
schemars.workspace = true
|
||||
serde.workspace = true
|
||||
settings.workspace = true
|
||||
smol.workspace = true
|
||||
|
||||
@@ -1,62 +1,53 @@
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
|
||||
use anyhow::Result;
|
||||
use gpui::App;
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use settings::{Settings, SettingsKey, SettingsSources, SettingsStore, SettingsUi};
|
||||
use settings::{Settings, SettingsStore};
|
||||
use util::MergeFrom as _;
|
||||
|
||||
#[derive(Clone, Default, Serialize, Deserialize, JsonSchema, Debug, SettingsUi)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct AudioSettings {
|
||||
/// Opt into the new audio system.
|
||||
#[serde(rename = "experimental.rodio_audio", default)]
|
||||
pub rodio_audio: bool, // default is false
|
||||
/// Requires 'rodio_audio: true'
|
||||
///
|
||||
/// Use the new audio systems automatic gain control for your microphone.
|
||||
/// This affects how loud you sound to others.
|
||||
#[serde(rename = "experimental.control_input_volume", default)]
|
||||
pub control_input_volume: bool,
|
||||
/// Requires 'rodio_audio: true'
|
||||
///
|
||||
/// Use the new audio systems automatic gain control on everyone in the
|
||||
/// call. This makes call members who are too quite louder and those who are
|
||||
/// too loud quieter. This only affects how things sound for you.
|
||||
#[serde(rename = "experimental.control_output_volume", default)]
|
||||
pub control_output_volume: bool,
|
||||
}
|
||||
|
||||
/// Configuration of audio in Zed.
|
||||
#[derive(Clone, Default, Serialize, Deserialize, JsonSchema, Debug, SettingsUi, SettingsKey)]
|
||||
#[serde(default)]
|
||||
#[settings_key(key = "audio")]
|
||||
pub struct AudioSettingsContent {
|
||||
/// Opt into the new audio system.
|
||||
#[serde(rename = "experimental.rodio_audio", default)]
|
||||
pub rodio_audio: bool, // default is false
|
||||
/// Requires 'rodio_audio: true'
|
||||
///
|
||||
/// Use the new audio systems automatic gain control for your microphone.
|
||||
/// This affects how loud you sound to others.
|
||||
#[serde(rename = "experimental.control_input_volume", default)]
|
||||
pub control_input_volume: bool,
|
||||
/// Requires 'rodio_audio: true'
|
||||
///
|
||||
/// Use the new audio systems automatic gain control on everyone in the
|
||||
/// call. This makes call members who are too quite louder and those who are
|
||||
/// too loud quieter. This only affects how things sound for you.
|
||||
#[serde(rename = "experimental.control_output_volume", default)]
|
||||
pub control_output_volume: bool,
|
||||
}
|
||||
|
||||
/// Configuration of audio in Zed
|
||||
impl Settings for AudioSettings {
|
||||
type FileContent = AudioSettingsContent;
|
||||
|
||||
fn load(sources: SettingsSources<Self::FileContent>, _cx: &mut App) -> Result<Self> {
|
||||
sources.json_merge()
|
||||
fn from_defaults(content: &settings::SettingsContent, _cx: &mut App) -> Self {
|
||||
let audio = &content.audio.as_ref().unwrap();
|
||||
AudioSettings {
|
||||
control_input_volume: audio.control_input_volume.unwrap(),
|
||||
control_output_volume: audio.control_output_volume.unwrap(),
|
||||
rodio_audio: audio.rodio_audio.unwrap(),
|
||||
}
|
||||
}
|
||||
|
||||
fn import_from_vscode(_vscode: &settings::VsCodeSettings, _current: &mut Self::FileContent) {}
|
||||
fn refine(&mut self, content: &settings::SettingsContent, _cx: &mut App) {
|
||||
let Some(audio) = content.audio.as_ref() else {
|
||||
return;
|
||||
};
|
||||
self.control_input_volume
|
||||
.merge_from(&audio.control_input_volume);
|
||||
self.control_output_volume
|
||||
.merge_from(&audio.control_output_volume);
|
||||
self.rodio_audio.merge_from(&audio.rodio_audio);
|
||||
}
|
||||
|
||||
fn import_from_vscode(
|
||||
_vscode: &settings::VsCodeSettings,
|
||||
_current: &mut settings::SettingsContent,
|
||||
) {
|
||||
}
|
||||
}
|
||||
|
||||
/// See docs on [LIVE_SETTINGS]
|
||||
|
||||
@@ -21,7 +21,6 @@ http_client.workspace = true
|
||||
log.workspace = true
|
||||
paths.workspace = true
|
||||
release_channel.workspace = true
|
||||
schemars.workspace = true
|
||||
serde.workspace = true
|
||||
serde_json.workspace = true
|
||||
settings.workspace = true
|
||||
|
||||
@@ -8,9 +8,8 @@ use gpui::{
|
||||
use http_client::{AsyncBody, HttpClient, HttpClientWithUrl};
|
||||
use paths::remote_servers_dir;
|
||||
use release_channel::{AppCommitSha, ReleaseChannel};
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use settings::{Settings, SettingsKey, SettingsSources, SettingsStore, SettingsUi};
|
||||
use settings::{Settings, SettingsContent, SettingsStore};
|
||||
use smol::{fs, io::AsyncReadExt};
|
||||
use smol::{fs::File, process::Command};
|
||||
use std::{
|
||||
@@ -113,47 +112,27 @@ impl Drop for MacOsUnmounter {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
struct AutoUpdateSetting(bool);
|
||||
|
||||
/// Whether or not to automatically check for updates.
|
||||
///
|
||||
/// Default: true
|
||||
#[derive(Clone, Copy, Default, JsonSchema, Deserialize, Serialize, SettingsUi, SettingsKey)]
|
||||
#[settings_key(None)]
|
||||
#[settings_ui(group = "Auto Update")]
|
||||
struct AutoUpdateSettingContent {
|
||||
pub auto_update: Option<bool>,
|
||||
}
|
||||
|
||||
impl Settings for AutoUpdateSetting {
|
||||
type FileContent = AutoUpdateSettingContent;
|
||||
|
||||
fn load(sources: SettingsSources<Self::FileContent>, _: &mut App) -> Result<Self> {
|
||||
let auto_update = [
|
||||
sources.server,
|
||||
sources.release_channel,
|
||||
sources.operating_system,
|
||||
sources.user,
|
||||
]
|
||||
.into_iter()
|
||||
.find_map(|value| value.and_then(|val| val.auto_update))
|
||||
.or(sources.default.auto_update)
|
||||
.ok_or_else(Self::missing_default)?;
|
||||
|
||||
Ok(Self(auto_update))
|
||||
fn from_defaults(content: &settings::SettingsContent, _cx: &mut App) -> Self {
|
||||
debug_assert_eq!(content.auto_update.unwrap(), true);
|
||||
Self(content.auto_update.unwrap())
|
||||
}
|
||||
|
||||
fn import_from_vscode(vscode: &settings::VsCodeSettings, current: &mut Self::FileContent) {
|
||||
let mut cur = &mut Some(*current);
|
||||
vscode.enum_setting("update.mode", &mut cur, |s| match s {
|
||||
"none" | "manual" => Some(AutoUpdateSettingContent {
|
||||
auto_update: Some(false),
|
||||
}),
|
||||
_ => Some(AutoUpdateSettingContent {
|
||||
auto_update: Some(true),
|
||||
}),
|
||||
});
|
||||
*current = cur.unwrap();
|
||||
fn refine(&mut self, content: &settings::SettingsContent, _cx: &mut App) {
|
||||
if let Some(auto_update) = content.auto_update {
|
||||
self.0 = auto_update;
|
||||
}
|
||||
}
|
||||
|
||||
fn import_from_vscode(_: &settings::VsCodeSettings, _: &mut SettingsContent) {
|
||||
// We could match on vscode's update.mode here, but
|
||||
// I think it's more important to have more people updating zed by default.
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1002,7 +981,7 @@ mod tests {
|
||||
#[gpui::test]
|
||||
fn test_auto_update_defaults_to_true(cx: &mut TestAppContext) {
|
||||
cx.update(|cx| {
|
||||
let mut store = SettingsStore::new(cx);
|
||||
let mut store = SettingsStore::new(cx, &settings::default_settings());
|
||||
store
|
||||
.set_default_settings(&default_settings(), cx)
|
||||
.expect("Unable to set default settings");
|
||||
|
||||
@@ -35,7 +35,6 @@ language.workspace = true
|
||||
log.workspace = true
|
||||
postage.workspace = true
|
||||
project.workspace = true
|
||||
schemars.workspace = true
|
||||
serde.workspace = true
|
||||
settings.workspace = true
|
||||
telemetry.workspace = true
|
||||
|
||||
@@ -1,36 +1,32 @@
|
||||
use anyhow::Result;
|
||||
use gpui::App;
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use settings::{Settings, SettingsKey, SettingsSources, SettingsUi};
|
||||
use settings::Settings;
|
||||
use util::MergeFrom;
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
#[derive(Debug)]
|
||||
pub struct CallSettings {
|
||||
pub mute_on_join: bool,
|
||||
pub share_on_join: bool,
|
||||
}
|
||||
|
||||
/// Configuration of voice calls in Zed.
|
||||
#[derive(Clone, Default, Serialize, Deserialize, JsonSchema, Debug, SettingsUi, SettingsKey)]
|
||||
#[settings_key(key = "calls")]
|
||||
pub struct CallSettingsContent {
|
||||
/// Whether the microphone should be muted when joining a channel or a call.
|
||||
///
|
||||
/// Default: false
|
||||
pub mute_on_join: Option<bool>,
|
||||
|
||||
/// Whether your current project should be shared when joining an empty channel.
|
||||
///
|
||||
/// Default: false
|
||||
pub share_on_join: Option<bool>,
|
||||
}
|
||||
|
||||
impl Settings for CallSettings {
|
||||
type FileContent = CallSettingsContent;
|
||||
|
||||
fn load(sources: SettingsSources<Self::FileContent>, _: &mut App) -> Result<Self> {
|
||||
sources.json_merge()
|
||||
fn from_defaults(content: &settings::SettingsContent, _cx: &mut App) -> Self {
|
||||
let call = content.calls.clone().unwrap();
|
||||
CallSettings {
|
||||
mute_on_join: call.mute_on_join.unwrap(),
|
||||
share_on_join: call.share_on_join.unwrap(),
|
||||
}
|
||||
}
|
||||
|
||||
fn import_from_vscode(_vscode: &settings::VsCodeSettings, _current: &mut Self::FileContent) {}
|
||||
fn refine(&mut self, content: &settings::SettingsContent, _cx: &mut App) {
|
||||
if let Some(call) = content.calls.clone() {
|
||||
self.mute_on_join.merge_from(&call.mute_on_join);
|
||||
self.share_on_join.merge_from(&call.share_on_join);
|
||||
}
|
||||
}
|
||||
|
||||
fn import_from_vscode(
|
||||
_vscode: &settings::VsCodeSettings,
|
||||
_current: &mut settings::SettingsContent,
|
||||
) {
|
||||
}
|
||||
}
|
||||
|
||||
+57
-49
@@ -31,7 +31,7 @@ use release_channel::{AppVersion, ReleaseChannel};
|
||||
use rpc::proto::{AnyTypedEnvelope, EnvelopedMessage, PeerId, RequestMessage};
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use settings::{Settings, SettingsKey, SettingsSources, SettingsUi};
|
||||
use settings::{Settings, SettingsContent, SettingsKey, SettingsUi};
|
||||
use std::{
|
||||
any::TypeId,
|
||||
convert::TryFrom,
|
||||
@@ -50,7 +50,7 @@ use telemetry::Telemetry;
|
||||
use thiserror::Error;
|
||||
use tokio::net::TcpStream;
|
||||
use url::Url;
|
||||
use util::{ConnectionResult, ResultExt};
|
||||
use util::{ConnectionResult, MergeFrom, ResultExt};
|
||||
|
||||
pub use rpc::*;
|
||||
pub use telemetry_events::Event;
|
||||
@@ -96,29 +96,33 @@ actions!(
|
||||
]
|
||||
);
|
||||
|
||||
#[derive(Clone, Default, Serialize, Deserialize, JsonSchema, SettingsUi, SettingsKey)]
|
||||
#[settings_key(None)]
|
||||
pub struct ClientSettingsContent {
|
||||
server_url: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct ClientSettings {
|
||||
pub server_url: String,
|
||||
}
|
||||
|
||||
impl Settings for ClientSettings {
|
||||
type FileContent = ClientSettingsContent;
|
||||
|
||||
fn load(sources: SettingsSources<Self::FileContent>, _: &mut App) -> Result<Self> {
|
||||
let mut result = sources.json_merge::<Self>()?;
|
||||
fn from_defaults(content: &settings::SettingsContent, _cx: &mut App) -> Self {
|
||||
if let Some(server_url) = &*ZED_SERVER_URL {
|
||||
result.server_url.clone_from(server_url)
|
||||
return Self {
|
||||
server_url: server_url.clone(),
|
||||
};
|
||||
}
|
||||
Self {
|
||||
server_url: content.server_url.clone().unwrap(),
|
||||
}
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
fn import_from_vscode(_vscode: &settings::VsCodeSettings, _current: &mut Self::FileContent) {}
|
||||
fn refine(&mut self, content: &settings::SettingsContent, _: &mut App) {
|
||||
if ZED_SERVER_URL.is_some() {
|
||||
return;
|
||||
}
|
||||
if let Some(server_url) = content.server_url.clone() {
|
||||
self.server_url = server_url;
|
||||
}
|
||||
}
|
||||
|
||||
fn import_from_vscode(_vscode: &settings::VsCodeSettings, _current: &mut SettingsContent) {}
|
||||
}
|
||||
|
||||
#[derive(Default, Clone, Serialize, Deserialize, JsonSchema, SettingsUi, SettingsKey)]
|
||||
@@ -147,19 +151,19 @@ impl ProxySettings {
|
||||
}
|
||||
|
||||
impl Settings for ProxySettings {
|
||||
type FileContent = ProxySettingsContent;
|
||||
|
||||
fn load(sources: SettingsSources<Self::FileContent>, _: &mut App) -> Result<Self> {
|
||||
Ok(Self {
|
||||
proxy: sources
|
||||
.user
|
||||
.or(sources.server)
|
||||
.and_then(|value| value.proxy.clone())
|
||||
.or(sources.default.proxy.clone()),
|
||||
})
|
||||
fn from_defaults(content: &settings::SettingsContent, _cx: &mut App) -> Self {
|
||||
Self {
|
||||
proxy: content.proxy.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
fn import_from_vscode(vscode: &settings::VsCodeSettings, current: &mut Self::FileContent) {
|
||||
fn refine(&mut self, content: &settings::SettingsContent, _: &mut App) {
|
||||
if let Some(proxy) = content.proxy.clone() {
|
||||
self.proxy = Some(proxy)
|
||||
}
|
||||
}
|
||||
|
||||
fn import_from_vscode(vscode: &settings::VsCodeSettings, current: &mut SettingsContent) {
|
||||
vscode.string_setting("http.proxy", &mut current.proxy);
|
||||
}
|
||||
}
|
||||
@@ -538,37 +542,41 @@ pub struct TelemetrySettings {
|
||||
pub metrics: bool,
|
||||
}
|
||||
|
||||
/// Control what info is collected by Zed.
|
||||
#[derive(Default, Clone, Serialize, Deserialize, JsonSchema, Debug, SettingsUi, SettingsKey)]
|
||||
#[settings_key(key = "telemetry")]
|
||||
pub struct TelemetrySettingsContent {
|
||||
/// Send debug info like crash reports.
|
||||
///
|
||||
/// Default: true
|
||||
pub diagnostics: Option<bool>,
|
||||
/// Send anonymized usage data like what languages you're using Zed with.
|
||||
///
|
||||
/// Default: true
|
||||
pub metrics: Option<bool>,
|
||||
}
|
||||
|
||||
impl settings::Settings for TelemetrySettings {
|
||||
type FileContent = TelemetrySettingsContent;
|
||||
|
||||
fn load(sources: SettingsSources<Self::FileContent>, _: &mut App) -> Result<Self> {
|
||||
sources.json_merge()
|
||||
fn from_defaults(content: &SettingsContent, _cx: &mut App) -> Self {
|
||||
Self {
|
||||
diagnostics: content.telemetry.as_ref().unwrap().diagnostics.unwrap(),
|
||||
metrics: content.telemetry.as_ref().unwrap().metrics.unwrap(),
|
||||
}
|
||||
}
|
||||
|
||||
fn import_from_vscode(vscode: &settings::VsCodeSettings, current: &mut Self::FileContent) {
|
||||
vscode.enum_setting("telemetry.telemetryLevel", &mut current.metrics, |s| {
|
||||
fn refine(&mut self, content: &SettingsContent, _cx: &mut App) {
|
||||
let Some(telemetry) = &content.telemetry else {
|
||||
return;
|
||||
};
|
||||
self.diagnostics.merge_from(&telemetry.diagnostics);
|
||||
self.metrics.merge_from(&telemetry.metrics);
|
||||
}
|
||||
|
||||
fn import_from_vscode(vscode: &settings::VsCodeSettings, current: &mut SettingsContent) {
|
||||
let mut telemetry = settings::TelemetrySettingsContent::default();
|
||||
vscode.enum_setting("telemetry.telemetryLevel", &mut telemetry.metrics, |s| {
|
||||
Some(s == "all")
|
||||
});
|
||||
vscode.enum_setting("telemetry.telemetryLevel", &mut current.diagnostics, |s| {
|
||||
Some(matches!(s, "all" | "error" | "crash"))
|
||||
});
|
||||
vscode.enum_setting(
|
||||
"telemetry.telemetryLevel",
|
||||
&mut telemetry.diagnostics,
|
||||
|s| Some(matches!(s, "all" | "error" | "crash")),
|
||||
);
|
||||
// we could translate telemetry.telemetryLevel, but just because users didn't want
|
||||
// to send microsoft telemetry doesn't mean they don't want to send it to zed. their
|
||||
// all/error/crash/off correspond to combinations of our "diagnostics" and "metrics".
|
||||
if let Some(diagnostics) = telemetry.diagnostics {
|
||||
current.telemetry.get_or_insert_default().diagnostics = Some(diagnostics)
|
||||
}
|
||||
if let Some(metrics) = telemetry.metrics {
|
||||
current.telemetry.get_or_insert_default().metrics = Some(metrics)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ use crate::{
|
||||
};
|
||||
use call::ActiveCall;
|
||||
use editor::{
|
||||
DocumentColorsRenderMode, Editor, EditorSettings, RowInfo, SelectionEffects,
|
||||
DocumentColorsRenderMode, Editor, RowInfo, SelectionEffects,
|
||||
actions::{
|
||||
ConfirmCodeAction, ConfirmCompletion, ConfirmRename, ContextMenuFirst,
|
||||
ExpandMacroRecursively, MoveToEnd, Redo, Rename, SelectAll, ToggleCodeActions, Undo,
|
||||
@@ -18,20 +18,16 @@ use fs::Fs;
|
||||
use futures::{SinkExt, StreamExt, channel::mpsc, lock::Mutex};
|
||||
use gpui::{App, Rgba, TestAppContext, UpdateGlobal, VisualContext, VisualTestContext};
|
||||
use indoc::indoc;
|
||||
use language::{
|
||||
FakeLspAdapter,
|
||||
language_settings::{AllLanguageSettings, InlayHintSettings},
|
||||
};
|
||||
use language::FakeLspAdapter;
|
||||
use lsp::LSP_REQUEST_TIMEOUT;
|
||||
use project::{
|
||||
ProjectPath, SERVER_PROGRESS_THROTTLE_TIMEOUT,
|
||||
lsp_store::lsp_ext_command::{ExpandedMacro, LspExtExpandMacro},
|
||||
project_settings::{InlineBlameSettings, ProjectSettings},
|
||||
};
|
||||
use recent_projects::disconnected_overlay::DisconnectedOverlay;
|
||||
use rpc::RECEIVE_TIMEOUT;
|
||||
use serde_json::json;
|
||||
use settings::SettingsStore;
|
||||
use settings::{InlayHintSettingsContent, InlineBlameSettings, SettingsStore};
|
||||
use std::{
|
||||
collections::BTreeSet,
|
||||
ops::{Deref as _, Range},
|
||||
@@ -1789,35 +1785,37 @@ async fn test_mutual_editor_inlay_hint_cache_update(
|
||||
|
||||
cx_a.update(|cx| {
|
||||
SettingsStore::update_global(cx, |store, cx| {
|
||||
store.update_user_settings::<AllLanguageSettings>(cx, |settings| {
|
||||
settings.defaults.inlay_hints = Some(InlayHintSettings {
|
||||
enabled: true,
|
||||
show_value_hints: true,
|
||||
edit_debounce_ms: 0,
|
||||
scroll_debounce_ms: 0,
|
||||
show_type_hints: true,
|
||||
show_parameter_hints: false,
|
||||
show_other_hints: true,
|
||||
show_background: false,
|
||||
toggle_on_modifiers_press: None,
|
||||
})
|
||||
store.update_user_settings(cx, |settings| {
|
||||
settings.project.all_languages.defaults.inlay_hints =
|
||||
Some(InlayHintSettingsContent {
|
||||
enabled: Some(true),
|
||||
show_value_hints: Some(true),
|
||||
edit_debounce_ms: Some(0),
|
||||
scroll_debounce_ms: Some(0),
|
||||
show_type_hints: Some(true),
|
||||
show_parameter_hints: Some(false),
|
||||
show_other_hints: Some(true),
|
||||
show_background: Some(false),
|
||||
toggle_on_modifiers_press: None,
|
||||
})
|
||||
});
|
||||
});
|
||||
});
|
||||
cx_b.update(|cx| {
|
||||
SettingsStore::update_global(cx, |store, cx| {
|
||||
store.update_user_settings::<AllLanguageSettings>(cx, |settings| {
|
||||
settings.defaults.inlay_hints = Some(InlayHintSettings {
|
||||
show_value_hints: true,
|
||||
enabled: true,
|
||||
edit_debounce_ms: 0,
|
||||
scroll_debounce_ms: 0,
|
||||
show_type_hints: true,
|
||||
show_parameter_hints: false,
|
||||
show_other_hints: true,
|
||||
show_background: false,
|
||||
toggle_on_modifiers_press: None,
|
||||
})
|
||||
store.update_user_settings(cx, |settings| {
|
||||
settings.project.all_languages.defaults.inlay_hints =
|
||||
Some(InlayHintSettingsContent {
|
||||
show_value_hints: Some(true),
|
||||
enabled: Some(true),
|
||||
edit_debounce_ms: Some(0),
|
||||
scroll_debounce_ms: Some(0),
|
||||
show_type_hints: Some(true),
|
||||
show_parameter_hints: Some(false),
|
||||
show_other_hints: Some(true),
|
||||
show_background: Some(false),
|
||||
toggle_on_modifiers_press: None,
|
||||
})
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -2039,35 +2037,37 @@ async fn test_inlay_hint_refresh_is_forwarded(
|
||||
|
||||
cx_a.update(|cx| {
|
||||
SettingsStore::update_global(cx, |store, cx| {
|
||||
store.update_user_settings::<AllLanguageSettings>(cx, |settings| {
|
||||
settings.defaults.inlay_hints = Some(InlayHintSettings {
|
||||
show_value_hints: true,
|
||||
enabled: false,
|
||||
edit_debounce_ms: 0,
|
||||
scroll_debounce_ms: 0,
|
||||
show_type_hints: false,
|
||||
show_parameter_hints: false,
|
||||
show_other_hints: false,
|
||||
show_background: false,
|
||||
toggle_on_modifiers_press: None,
|
||||
})
|
||||
store.update_user_settings(cx, |settings| {
|
||||
settings.project.all_languages.defaults.inlay_hints =
|
||||
Some(InlayHintSettingsContent {
|
||||
show_value_hints: Some(true),
|
||||
enabled: Some(false),
|
||||
edit_debounce_ms: Some(0),
|
||||
scroll_debounce_ms: Some(0),
|
||||
show_type_hints: Some(false),
|
||||
show_parameter_hints: Some(false),
|
||||
show_other_hints: Some(false),
|
||||
show_background: Some(false),
|
||||
toggle_on_modifiers_press: None,
|
||||
})
|
||||
});
|
||||
});
|
||||
});
|
||||
cx_b.update(|cx| {
|
||||
SettingsStore::update_global(cx, |store, cx| {
|
||||
store.update_user_settings::<AllLanguageSettings>(cx, |settings| {
|
||||
settings.defaults.inlay_hints = Some(InlayHintSettings {
|
||||
show_value_hints: true,
|
||||
enabled: true,
|
||||
edit_debounce_ms: 0,
|
||||
scroll_debounce_ms: 0,
|
||||
show_type_hints: true,
|
||||
show_parameter_hints: true,
|
||||
show_other_hints: true,
|
||||
show_background: false,
|
||||
toggle_on_modifiers_press: None,
|
||||
})
|
||||
store.update_user_settings(cx, |settings| {
|
||||
settings.project.all_languages.defaults.inlay_hints =
|
||||
Some(InlayHintSettingsContent {
|
||||
show_value_hints: Some(true),
|
||||
enabled: Some(true),
|
||||
edit_debounce_ms: Some(0),
|
||||
scroll_debounce_ms: Some(0),
|
||||
show_type_hints: Some(true),
|
||||
show_parameter_hints: Some(true),
|
||||
show_other_hints: Some(true),
|
||||
show_background: Some(false),
|
||||
toggle_on_modifiers_press: None,
|
||||
})
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -2241,15 +2241,15 @@ async fn test_lsp_document_color(cx_a: &mut TestAppContext, cx_b: &mut TestAppCo
|
||||
|
||||
cx_a.update(|cx| {
|
||||
SettingsStore::update_global(cx, |store, cx| {
|
||||
store.update_user_settings::<EditorSettings>(cx, |settings| {
|
||||
settings.lsp_document_colors = Some(DocumentColorsRenderMode::None);
|
||||
store.update_user_settings(cx, |settings| {
|
||||
settings.editor.lsp_document_colors = Some(DocumentColorsRenderMode::None);
|
||||
});
|
||||
});
|
||||
});
|
||||
cx_b.update(|cx| {
|
||||
SettingsStore::update_global(cx, |store, cx| {
|
||||
store.update_user_settings::<EditorSettings>(cx, |settings| {
|
||||
settings.lsp_document_colors = Some(DocumentColorsRenderMode::Inlay);
|
||||
store.update_user_settings(cx, |settings| {
|
||||
settings.editor.lsp_document_colors = Some(DocumentColorsRenderMode::Inlay);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -2422,8 +2422,8 @@ async fn test_lsp_document_color(cx_a: &mut TestAppContext, cx_b: &mut TestAppCo
|
||||
|
||||
cx_b.update(|_, cx| {
|
||||
SettingsStore::update_global(cx, |store, cx| {
|
||||
store.update_user_settings::<EditorSettings>(cx, |settings| {
|
||||
settings.lsp_document_colors = Some(DocumentColorsRenderMode::Background);
|
||||
store.update_user_settings(cx, |settings| {
|
||||
settings.editor.lsp_document_colors = Some(DocumentColorsRenderMode::Background);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -2450,8 +2450,8 @@ async fn test_lsp_document_color(cx_a: &mut TestAppContext, cx_b: &mut TestAppCo
|
||||
|
||||
cx_b.update(|_, cx| {
|
||||
SettingsStore::update_global(cx, |store, cx| {
|
||||
store.update_user_settings::<EditorSettings>(cx, |settings| {
|
||||
settings.lsp_document_colors = Some(DocumentColorsRenderMode::Inlay);
|
||||
store.update_user_settings(cx, |settings| {
|
||||
settings.editor.lsp_document_colors = Some(DocumentColorsRenderMode::Inlay);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -2478,8 +2478,8 @@ async fn test_lsp_document_color(cx_a: &mut TestAppContext, cx_b: &mut TestAppCo
|
||||
|
||||
cx_a.update(|_, cx| {
|
||||
SettingsStore::update_global(cx, |store, cx| {
|
||||
store.update_user_settings::<EditorSettings>(cx, |settings| {
|
||||
settings.lsp_document_colors = Some(DocumentColorsRenderMode::Border);
|
||||
store.update_user_settings(cx, |settings| {
|
||||
settings.editor.lsp_document_colors = Some(DocumentColorsRenderMode::Border);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -3306,20 +3306,20 @@ async fn test_git_blame_is_forwarded(cx_a: &mut TestAppContext, cx_b: &mut TestA
|
||||
cx_b.update(editor::init);
|
||||
// Turn inline-blame-off by default so no state is transferred without us explicitly doing so
|
||||
let inline_blame_off_settings = Some(InlineBlameSettings {
|
||||
enabled: false,
|
||||
enabled: Some(false),
|
||||
..Default::default()
|
||||
});
|
||||
cx_a.update(|cx| {
|
||||
SettingsStore::update_global(cx, |store, cx| {
|
||||
store.update_user_settings::<ProjectSettings>(cx, |settings| {
|
||||
settings.git.inline_blame = inline_blame_off_settings;
|
||||
store.update_user_settings(cx, |settings| {
|
||||
settings.git.get_or_insert_default().inline_blame = inline_blame_off_settings;
|
||||
});
|
||||
});
|
||||
});
|
||||
cx_b.update(|cx| {
|
||||
SettingsStore::update_global(cx, |store, cx| {
|
||||
store.update_user_settings::<ProjectSettings>(cx, |settings| {
|
||||
settings.git.inline_blame = inline_blame_off_settings;
|
||||
store.update_user_settings(cx, |settings| {
|
||||
settings.git.get_or_insert_default().inline_blame = inline_blame_off_settings;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -12,7 +12,6 @@ use gpui::{
|
||||
VisualContext, VisualTestContext, point,
|
||||
};
|
||||
use language::Capability;
|
||||
use project::WorktreeSettings;
|
||||
use rpc::proto::PeerId;
|
||||
use serde_json::json;
|
||||
use settings::SettingsStore;
|
||||
@@ -1710,8 +1709,9 @@ async fn test_following_into_excluded_file(
|
||||
for cx in [&mut cx_a, &mut cx_b] {
|
||||
cx.update(|cx| {
|
||||
cx.update_global::<SettingsStore, _>(|store, cx| {
|
||||
store.update_user_settings::<WorktreeSettings>(cx, |settings| {
|
||||
settings.file_scan_exclusions = Some(vec!["**/.git".to_string()]);
|
||||
store.update_user_settings(cx, |settings| {
|
||||
settings.project.worktree.file_scan_exclusions =
|
||||
Some(vec!["**/.git".to_string()]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -22,9 +22,7 @@ use gpui::{
|
||||
use language::{
|
||||
Diagnostic, DiagnosticEntry, DiagnosticSourceKind, FakeLspAdapter, Language, LanguageConfig,
|
||||
LanguageMatcher, LineEnding, OffsetRangeExt, Point, Rope,
|
||||
language_settings::{
|
||||
AllLanguageSettings, Formatter, FormatterList, PrettierSettings, SelectedFormatter,
|
||||
},
|
||||
language_settings::{Formatter, FormatterList, SelectedFormatter},
|
||||
tree_sitter_rust, tree_sitter_typescript,
|
||||
};
|
||||
use lsp::{LanguageServerId, OneOf};
|
||||
@@ -38,7 +36,7 @@ use project::{
|
||||
use prompt_store::PromptBuilder;
|
||||
use rand::prelude::*;
|
||||
use serde_json::json;
|
||||
use settings::SettingsStore;
|
||||
use settings::{PrettierSettingsContent, SettingsStore};
|
||||
use std::{
|
||||
cell::{Cell, RefCell},
|
||||
env, future, mem,
|
||||
@@ -3507,10 +3505,14 @@ async fn test_local_settings(
|
||||
assert_eq!(
|
||||
store
|
||||
.local_settings(worktree_b.read(cx).id())
|
||||
.map(|(path, content)| (
|
||||
path,
|
||||
content.all_languages.defaults.tab_size.map(Into::into)
|
||||
))
|
||||
.collect::<Vec<_>>(),
|
||||
&[
|
||||
(Path::new("").into(), r#"{"tab_size":2}"#.to_string()),
|
||||
(Path::new("a").into(), r#"{"tab_size":8}"#.to_string()),
|
||||
(Path::new("").into(), Some(2)),
|
||||
(Path::new("a").into(), Some(8)),
|
||||
]
|
||||
)
|
||||
});
|
||||
@@ -3526,10 +3528,14 @@ async fn test_local_settings(
|
||||
assert_eq!(
|
||||
store
|
||||
.local_settings(worktree_b.read(cx).id())
|
||||
.map(|(path, content)| (
|
||||
path,
|
||||
content.all_languages.defaults.tab_size.map(Into::into)
|
||||
))
|
||||
.collect::<Vec<_>>(),
|
||||
&[
|
||||
(Path::new("").into(), r#"{}"#.to_string()),
|
||||
(Path::new("a").into(), r#"{"tab_size":8}"#.to_string()),
|
||||
(Path::new("").into(), None),
|
||||
(Path::new("a").into(), Some(8)),
|
||||
]
|
||||
)
|
||||
});
|
||||
@@ -3555,10 +3561,14 @@ async fn test_local_settings(
|
||||
assert_eq!(
|
||||
store
|
||||
.local_settings(worktree_b.read(cx).id())
|
||||
.map(|(path, content)| (
|
||||
path,
|
||||
content.all_languages.defaults.tab_size.map(Into::into)
|
||||
))
|
||||
.collect::<Vec<_>>(),
|
||||
&[
|
||||
(Path::new("a").into(), r#"{"tab_size":8}"#.to_string()),
|
||||
(Path::new("b").into(), r#"{"tab_size":4}"#.to_string()),
|
||||
(Path::new("a").into(), Some(8)),
|
||||
(Path::new("b").into(), Some(4)),
|
||||
]
|
||||
)
|
||||
});
|
||||
@@ -3587,8 +3597,9 @@ async fn test_local_settings(
|
||||
assert_eq!(
|
||||
store
|
||||
.local_settings(worktree_b.read(cx).id())
|
||||
.map(|(path, content)| (path, content.all_languages.defaults.hard_tabs))
|
||||
.collect::<Vec<_>>(),
|
||||
&[(Path::new("a").into(), r#"{"hard_tabs":true}"#.to_string()),]
|
||||
&[(Path::new("a").into(), Some(true))],
|
||||
)
|
||||
});
|
||||
}
|
||||
@@ -4598,15 +4609,15 @@ async fn test_formatting_buffer(
|
||||
// host's configuration is honored as opposed to using the guest's settings.
|
||||
cx_a.update(|cx| {
|
||||
SettingsStore::update_global(cx, |store, cx| {
|
||||
store.update_user_settings::<AllLanguageSettings>(cx, |file| {
|
||||
file.defaults.formatter = Some(SelectedFormatter::List(FormatterList::Single(
|
||||
Formatter::External {
|
||||
store.update_user_settings(cx, |file| {
|
||||
file.project.all_languages.defaults.formatter = Some(SelectedFormatter::List(
|
||||
FormatterList::Single(Formatter::External {
|
||||
command: "awk".into(),
|
||||
arguments: Some(
|
||||
vec!["{sub(/two/,\"{buffer_path}\")}1".to_string()].into(),
|
||||
),
|
||||
},
|
||||
)));
|
||||
}),
|
||||
));
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -4694,24 +4705,24 @@ async fn test_prettier_formatting_buffer(
|
||||
|
||||
cx_a.update(|cx| {
|
||||
SettingsStore::update_global(cx, |store, cx| {
|
||||
store.update_user_settings::<AllLanguageSettings>(cx, |file| {
|
||||
file.defaults.formatter = Some(SelectedFormatter::Auto);
|
||||
file.defaults.prettier = Some(PrettierSettings {
|
||||
allowed: true,
|
||||
..PrettierSettings::default()
|
||||
store.update_user_settings(cx, |file| {
|
||||
file.project.all_languages.defaults.formatter = Some(SelectedFormatter::Auto);
|
||||
file.project.all_languages.defaults.prettier = Some(PrettierSettingsContent {
|
||||
allowed: Some(true),
|
||||
..Default::default()
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
cx_b.update(|cx| {
|
||||
SettingsStore::update_global(cx, |store, cx| {
|
||||
store.update_user_settings::<AllLanguageSettings>(cx, |file| {
|
||||
file.defaults.formatter = Some(SelectedFormatter::List(FormatterList::Single(
|
||||
Formatter::LanguageServer { name: None },
|
||||
)));
|
||||
file.defaults.prettier = Some(PrettierSettings {
|
||||
allowed: true,
|
||||
..PrettierSettings::default()
|
||||
store.update_user_settings(cx, |file| {
|
||||
file.project.all_languages.defaults.formatter = Some(SelectedFormatter::List(
|
||||
FormatterList::Single(Formatter::LanguageServer { name: None }),
|
||||
));
|
||||
file.project.all_languages.defaults.prettier = Some(PrettierSettingsContent {
|
||||
allowed: Some(true),
|
||||
..Default::default()
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -14,10 +14,7 @@ use gpui::{
|
||||
use http_client::BlockedHttpClient;
|
||||
use language::{
|
||||
FakeLspAdapter, Language, LanguageConfig, LanguageMatcher, LanguageRegistry,
|
||||
language_settings::{
|
||||
AllLanguageSettings, Formatter, FormatterList, PrettierSettings, SelectedFormatter,
|
||||
language_settings,
|
||||
},
|
||||
language_settings::{Formatter, FormatterList, SelectedFormatter, language_settings},
|
||||
tree_sitter_typescript,
|
||||
};
|
||||
use node_runtime::NodeRuntime;
|
||||
@@ -30,7 +27,7 @@ use remote::RemoteClient;
|
||||
use remote_server::{HeadlessAppState, HeadlessProject};
|
||||
use rpc::proto;
|
||||
use serde_json::json;
|
||||
use settings::SettingsStore;
|
||||
use settings::{PrettierSettingsContent, SettingsStore};
|
||||
use std::{
|
||||
path::Path,
|
||||
sync::{Arc, atomic::AtomicUsize},
|
||||
@@ -499,24 +496,24 @@ async fn test_ssh_collaboration_formatting_with_prettier(
|
||||
|
||||
cx_a.update(|cx| {
|
||||
SettingsStore::update_global(cx, |store, cx| {
|
||||
store.update_user_settings::<AllLanguageSettings>(cx, |file| {
|
||||
file.defaults.formatter = Some(SelectedFormatter::Auto);
|
||||
file.defaults.prettier = Some(PrettierSettings {
|
||||
allowed: true,
|
||||
..PrettierSettings::default()
|
||||
store.update_user_settings(cx, |file| {
|
||||
file.project.all_languages.defaults.formatter = Some(SelectedFormatter::Auto);
|
||||
file.project.all_languages.defaults.prettier = Some(PrettierSettingsContent {
|
||||
allowed: Some(true),
|
||||
..Default::default()
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
cx_b.update(|cx| {
|
||||
SettingsStore::update_global(cx, |store, cx| {
|
||||
store.update_user_settings::<AllLanguageSettings>(cx, |file| {
|
||||
file.defaults.formatter = Some(SelectedFormatter::List(FormatterList::Single(
|
||||
Formatter::LanguageServer { name: None },
|
||||
)));
|
||||
file.defaults.prettier = Some(PrettierSettings {
|
||||
allowed: true,
|
||||
..PrettierSettings::default()
|
||||
store.update_user_settings(cx, |file| {
|
||||
file.project.all_languages.defaults.formatter = Some(SelectedFormatter::List(
|
||||
FormatterList::Single(Formatter::LanguageServer { name: None }),
|
||||
));
|
||||
file.project.all_languages.defaults.prettier = Some(PrettierSettingsContent {
|
||||
allowed: Some(true),
|
||||
..Default::default()
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -556,11 +553,11 @@ async fn test_ssh_collaboration_formatting_with_prettier(
|
||||
|
||||
cx_a.update(|cx| {
|
||||
SettingsStore::update_global(cx, |store, cx| {
|
||||
store.update_user_settings::<AllLanguageSettings>(cx, |file| {
|
||||
file.defaults.formatter = Some(SelectedFormatter::Auto);
|
||||
file.defaults.prettier = Some(PrettierSettings {
|
||||
allowed: true,
|
||||
..PrettierSettings::default()
|
||||
store.update_user_settings(cx, |file| {
|
||||
file.project.all_languages.defaults.formatter = Some(SelectedFormatter::Auto);
|
||||
file.project.all_languages.defaults.prettier = Some(PrettierSettingsContent {
|
||||
allowed: Some(true),
|
||||
..Default::default()
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -47,7 +47,6 @@ picker.workspace = true
|
||||
project.workspace = true
|
||||
release_channel.workspace = true
|
||||
rpc.workspace = true
|
||||
schemars.workspace = true
|
||||
serde.workspace = true
|
||||
serde_json.workspace = true
|
||||
settings.workspace = true
|
||||
|
||||
@@ -2993,11 +2993,9 @@ impl Panel for CollabPanel {
|
||||
_window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
settings::update_settings_file::<CollaborationPanelSettings>(
|
||||
self.fs.clone(),
|
||||
cx,
|
||||
move |settings, _| settings.dock = Some(position),
|
||||
);
|
||||
settings::update_settings_file(self.fs.clone(), cx, move |settings, _| {
|
||||
settings.collaboration_panel.get_or_insert_default().dock = Some(position.into())
|
||||
});
|
||||
}
|
||||
|
||||
fn size(&self, _window: &Window, cx: &App) -> Pixels {
|
||||
|
||||
@@ -11,7 +11,6 @@ use gpui::{
|
||||
App, Pixels, PlatformDisplay, Size, WindowBackgroundAppearance, WindowBounds,
|
||||
WindowDecorations, WindowKind, WindowOptions, point,
|
||||
};
|
||||
use panel_settings::MessageEditorSettings;
|
||||
pub use panel_settings::{CollaborationPanelSettings, NotificationPanelSettings};
|
||||
use release_channel::ReleaseChannel;
|
||||
use settings::Settings;
|
||||
@@ -21,7 +20,6 @@ use workspace::AppState;
|
||||
pub fn init(app_state: &Arc<AppState>, cx: &mut App) {
|
||||
CollaborationPanelSettings::register(cx);
|
||||
NotificationPanelSettings::register(cx);
|
||||
MessageEditorSettings::register(cx);
|
||||
|
||||
channel_view::init(cx);
|
||||
collab_panel::init(cx);
|
||||
|
||||
@@ -621,11 +621,9 @@ impl Panel for NotificationPanel {
|
||||
}
|
||||
|
||||
fn set_position(&mut self, position: DockPosition, _: &mut Window, cx: &mut Context<Self>) {
|
||||
settings::update_settings_file::<NotificationPanelSettings>(
|
||||
self.fs.clone(),
|
||||
cx,
|
||||
move |settings, _| settings.dock = Some(position),
|
||||
);
|
||||
settings::update_settings_file(self.fs.clone(), cx, move |settings, _| {
|
||||
settings.notification_panel.get_or_insert_default().dock = Some(position.into())
|
||||
});
|
||||
}
|
||||
|
||||
fn size(&self, _: &Window, cx: &App) -> Pixels {
|
||||
|
||||
@@ -1,102 +1,72 @@
|
||||
use gpui::Pixels;
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use settings::{Settings, SettingsKey, SettingsSources, SettingsUi};
|
||||
use settings::Settings;
|
||||
use ui::px;
|
||||
use util::MergeFrom as _;
|
||||
use workspace::dock::DockPosition;
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
#[derive(Debug)]
|
||||
pub struct CollaborationPanelSettings {
|
||||
pub button: bool,
|
||||
pub dock: DockPosition,
|
||||
pub default_width: Pixels,
|
||||
}
|
||||
|
||||
#[derive(Clone, Default, Serialize, Deserialize, JsonSchema, Debug, SettingsUi, SettingsKey)]
|
||||
#[settings_key(key = "collaboration_panel")]
|
||||
pub struct PanelSettingsContent {
|
||||
/// Whether to show the panel button in the status bar.
|
||||
///
|
||||
/// Default: true
|
||||
pub button: Option<bool>,
|
||||
/// Where to dock the panel.
|
||||
///
|
||||
/// Default: left
|
||||
pub dock: Option<DockPosition>,
|
||||
/// Default width of the panel in pixels.
|
||||
///
|
||||
/// Default: 240
|
||||
pub default_width: Option<f32>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
#[derive(Debug)]
|
||||
pub struct NotificationPanelSettings {
|
||||
pub button: bool,
|
||||
pub dock: DockPosition,
|
||||
pub default_width: Pixels,
|
||||
}
|
||||
|
||||
#[derive(Clone, Default, Serialize, Deserialize, JsonSchema, Debug, SettingsUi, SettingsKey)]
|
||||
#[settings_key(key = "notification_panel")]
|
||||
pub struct NotificationPanelSettingsContent {
|
||||
/// Whether to show the panel button in the status bar.
|
||||
///
|
||||
/// Default: true
|
||||
pub button: Option<bool>,
|
||||
/// Where to dock the panel.
|
||||
///
|
||||
/// Default: right
|
||||
pub dock: Option<DockPosition>,
|
||||
/// Default width of the panel in pixels.
|
||||
///
|
||||
/// Default: 300
|
||||
pub default_width: Option<f32>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Default, Serialize, Deserialize, JsonSchema, Debug, SettingsUi, SettingsKey)]
|
||||
#[settings_key(key = "message_editor")]
|
||||
pub struct MessageEditorSettings {
|
||||
/// Whether to automatically replace emoji shortcodes with emoji characters.
|
||||
/// For example: typing `:wave:` gets replaced with `👋`.
|
||||
///
|
||||
/// Default: false
|
||||
pub auto_replace_emoji_shortcode: Option<bool>,
|
||||
}
|
||||
|
||||
impl Settings for CollaborationPanelSettings {
|
||||
type FileContent = PanelSettingsContent;
|
||||
fn from_defaults(content: &settings::SettingsContent, _cx: &mut ui::App) -> Self {
|
||||
let panel = content.collaboration_panel.as_ref().unwrap();
|
||||
|
||||
fn load(
|
||||
sources: SettingsSources<Self::FileContent>,
|
||||
_: &mut gpui::App,
|
||||
) -> anyhow::Result<Self> {
|
||||
sources.json_merge()
|
||||
Self {
|
||||
button: panel.button.unwrap(),
|
||||
dock: panel.dock.unwrap().into(),
|
||||
default_width: panel.default_width.map(px).unwrap(),
|
||||
}
|
||||
}
|
||||
|
||||
fn import_from_vscode(_vscode: &settings::VsCodeSettings, _current: &mut Self::FileContent) {}
|
||||
fn refine(&mut self, content: &settings::SettingsContent, _cx: &mut ui::App) {
|
||||
if let Some(panel) = content.collaboration_panel.as_ref() {
|
||||
self.button.merge_from(&panel.button);
|
||||
self.default_width
|
||||
.merge_from(&panel.default_width.map(Pixels::from));
|
||||
self.dock.merge_from(&panel.dock.map(Into::into));
|
||||
}
|
||||
}
|
||||
|
||||
fn import_from_vscode(
|
||||
_vscode: &settings::VsCodeSettings,
|
||||
_content: &mut settings::SettingsContent,
|
||||
) {
|
||||
}
|
||||
}
|
||||
|
||||
impl Settings for NotificationPanelSettings {
|
||||
type FileContent = NotificationPanelSettingsContent;
|
||||
|
||||
fn load(
|
||||
sources: SettingsSources<Self::FileContent>,
|
||||
_: &mut gpui::App,
|
||||
) -> anyhow::Result<Self> {
|
||||
sources.json_merge()
|
||||
fn from_defaults(content: &settings::SettingsContent, _cx: &mut ui::App) -> Self {
|
||||
let panel = content.notification_panel.as_ref().unwrap();
|
||||
return Self {
|
||||
button: panel.button.unwrap(),
|
||||
dock: panel.dock.unwrap().into(),
|
||||
default_width: panel.default_width.map(px).unwrap(),
|
||||
};
|
||||
}
|
||||
|
||||
fn import_from_vscode(_vscode: &settings::VsCodeSettings, _current: &mut Self::FileContent) {}
|
||||
}
|
||||
|
||||
impl Settings for MessageEditorSettings {
|
||||
type FileContent = MessageEditorSettings;
|
||||
|
||||
fn load(
|
||||
sources: SettingsSources<Self::FileContent>,
|
||||
_: &mut gpui::App,
|
||||
) -> anyhow::Result<Self> {
|
||||
sources.json_merge()
|
||||
fn refine(&mut self, content: &settings::SettingsContent, _cx: &mut ui::App) {
|
||||
let Some(panel) = content.notification_panel.as_ref() else {
|
||||
return;
|
||||
};
|
||||
self.button.merge_from(&panel.button);
|
||||
self.dock.merge_from(&panel.dock.map(Into::into));
|
||||
self.default_width.merge_from(&panel.default_width.map(px));
|
||||
}
|
||||
|
||||
fn import_from_vscode(_vscode: &settings::VsCodeSettings, _current: &mut Self::FileContent) {}
|
||||
fn import_from_vscode(
|
||||
_vscode: &settings::VsCodeSettings,
|
||||
_current: &mut settings::SettingsContent,
|
||||
) {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,8 +25,9 @@ net.workspace = true
|
||||
parking_lot.workspace = true
|
||||
postage.workspace = true
|
||||
schemars.workspace = true
|
||||
serde.workspace = true
|
||||
serde_json.workspace = true
|
||||
serde.workspace = true
|
||||
settings.workspace = true
|
||||
smol.workspace = true
|
||||
tempfile.workspace = true
|
||||
url = { workspace = true, features = ["serde"] }
|
||||
|
||||
@@ -12,12 +12,9 @@ use std::{fmt::Display, path::PathBuf};
|
||||
|
||||
use anyhow::Result;
|
||||
use client::Client;
|
||||
use collections::HashMap;
|
||||
use gpui::AsyncApp;
|
||||
use parking_lot::RwLock;
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use util::redact::should_redact;
|
||||
pub use settings::ContextServerCommand;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct ContextServerId(pub Arc<str>);
|
||||
@@ -28,32 +25,6 @@ impl Display for ContextServerId {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize, Clone, PartialEq, Eq, JsonSchema)]
|
||||
pub struct ContextServerCommand {
|
||||
#[serde(rename = "command")]
|
||||
pub path: PathBuf,
|
||||
pub args: Vec<String>,
|
||||
pub env: Option<HashMap<String, String>>,
|
||||
/// Timeout for tool calls in milliseconds. Defaults to 60000 (60 seconds) if not specified.
|
||||
pub timeout: Option<u64>,
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for ContextServerCommand {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
let filtered_env = self.env.as_ref().map(|env| {
|
||||
env.iter()
|
||||
.map(|(k, v)| (k, if should_redact(k) { "[REDACTED]" } else { v }))
|
||||
.collect::<Vec<_>>()
|
||||
});
|
||||
|
||||
f.debug_struct("ContextServerCommand")
|
||||
.field("path", &self.path)
|
||||
.field("args", &self.args)
|
||||
.field("env", &filtered_env)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
enum ContextServerTransport {
|
||||
Stdio(ContextServerCommand, Option<PathBuf>),
|
||||
Custom(Arc<dyn crate::transport::Transport>),
|
||||
|
||||
@@ -281,14 +281,11 @@ mod tests {
|
||||
use indoc::indoc;
|
||||
use language::{
|
||||
Point,
|
||||
language_settings::{
|
||||
AllLanguageSettings, AllLanguageSettingsContent, CompletionSettings, LspInsertMode,
|
||||
WordsCompletionMode,
|
||||
},
|
||||
language_settings::{CompletionSettingsContent, LspInsertMode, WordsCompletionMode},
|
||||
};
|
||||
use project::Project;
|
||||
use serde_json::json;
|
||||
use settings::SettingsStore;
|
||||
use settings::{AllLanguageSettingsContent, SettingsStore};
|
||||
use std::future::Future;
|
||||
use util::{
|
||||
path,
|
||||
@@ -299,12 +296,11 @@ mod tests {
|
||||
async fn test_copilot(executor: BackgroundExecutor, cx: &mut TestAppContext) {
|
||||
// flaky
|
||||
init_test(cx, |settings| {
|
||||
settings.defaults.completions = Some(CompletionSettings {
|
||||
words: WordsCompletionMode::Disabled,
|
||||
words_min_length: 0,
|
||||
lsp: true,
|
||||
lsp_fetch_timeout_ms: 0,
|
||||
lsp_insert_mode: LspInsertMode::Insert,
|
||||
settings.defaults.completions = Some(CompletionSettingsContent {
|
||||
words: Some(WordsCompletionMode::Disabled),
|
||||
words_min_length: Some(0),
|
||||
lsp_insert_mode: Some(LspInsertMode::Insert),
|
||||
..Default::default()
|
||||
});
|
||||
});
|
||||
|
||||
@@ -532,12 +528,11 @@ mod tests {
|
||||
) {
|
||||
// flaky
|
||||
init_test(cx, |settings| {
|
||||
settings.defaults.completions = Some(CompletionSettings {
|
||||
words: WordsCompletionMode::Disabled,
|
||||
words_min_length: 0,
|
||||
lsp: true,
|
||||
lsp_fetch_timeout_ms: 0,
|
||||
lsp_insert_mode: LspInsertMode::Insert,
|
||||
settings.defaults.completions = Some(CompletionSettingsContent {
|
||||
words: Some(WordsCompletionMode::Disabled),
|
||||
words_min_length: Some(0),
|
||||
lsp_insert_mode: Some(LspInsertMode::Insert),
|
||||
..Default::default()
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1128,7 +1123,7 @@ mod tests {
|
||||
Project::init_settings(cx);
|
||||
workspace::init_settings(cx);
|
||||
SettingsStore::update_global(cx, |store: &mut SettingsStore, cx| {
|
||||
store.update_user_settings::<AllLanguageSettings>(cx, f);
|
||||
store.update_user_settings(cx, |settings| f(&mut settings.project.all_languages));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,28 +1,12 @@
|
||||
use dap_types::SteppingGranularity;
|
||||
use gpui::{App, Global};
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use settings::{Settings, SettingsKey, SettingsSources, SettingsUi};
|
||||
use gpui::App;
|
||||
use settings::{Settings, SettingsContent};
|
||||
use util::MergeFrom;
|
||||
|
||||
#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq, SettingsUi)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum DebugPanelDockPosition {
|
||||
Left,
|
||||
Bottom,
|
||||
Right,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, JsonSchema, Clone, SettingsUi, SettingsKey)]
|
||||
#[serde(default)]
|
||||
// todo(settings_ui) @ben: I'm pretty sure not having the fields be optional here is a bug,
|
||||
// it means the defaults will override previously set values if a single key is missing
|
||||
#[settings_ui(group = "Debugger")]
|
||||
#[settings_key(key = "debugger")]
|
||||
pub struct DebuggerSettings {
|
||||
/// Determines the stepping granularity.
|
||||
///
|
||||
/// Default: line
|
||||
#[settings_ui(skip)]
|
||||
pub stepping_granularity: SteppingGranularity,
|
||||
/// Whether the breakpoints should be reused across Zed sessions.
|
||||
///
|
||||
@@ -47,31 +31,53 @@ pub struct DebuggerSettings {
|
||||
/// The dock position of the debug panel
|
||||
///
|
||||
/// Default: Bottom
|
||||
pub dock: DebugPanelDockPosition,
|
||||
}
|
||||
|
||||
impl Default for DebuggerSettings {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
button: true,
|
||||
save_breakpoints: true,
|
||||
stepping_granularity: SteppingGranularity::Line,
|
||||
timeout: 2000,
|
||||
log_dap_communications: true,
|
||||
format_dap_log_messages: true,
|
||||
dock: DebugPanelDockPosition::Bottom,
|
||||
}
|
||||
}
|
||||
pub dock: settings::DockPosition,
|
||||
}
|
||||
|
||||
impl Settings for DebuggerSettings {
|
||||
type FileContent = Self;
|
||||
|
||||
fn load(sources: SettingsSources<Self::FileContent>, _: &mut App) -> anyhow::Result<Self> {
|
||||
sources.json_merge()
|
||||
fn from_defaults(content: &SettingsContent, _cx: &mut App) -> Self {
|
||||
let content = content.debugger.clone().unwrap();
|
||||
Self {
|
||||
stepping_granularity: dap_granularity_from_settings(
|
||||
content.stepping_granularity.unwrap(),
|
||||
),
|
||||
save_breakpoints: content.save_breakpoints.unwrap(),
|
||||
button: content.button.unwrap(),
|
||||
timeout: content.timeout.unwrap(),
|
||||
log_dap_communications: content.log_dap_communications.unwrap(),
|
||||
format_dap_log_messages: content.format_dap_log_messages.unwrap(),
|
||||
dock: content.dock.unwrap(),
|
||||
}
|
||||
}
|
||||
|
||||
fn import_from_vscode(_vscode: &settings::VsCodeSettings, _current: &mut Self::FileContent) {}
|
||||
fn refine(&mut self, content: &SettingsContent, _cx: &mut App) {
|
||||
let Some(content) = &content.debugger else {
|
||||
return;
|
||||
};
|
||||
self.stepping_granularity.merge_from(
|
||||
&content
|
||||
.stepping_granularity
|
||||
.map(dap_granularity_from_settings),
|
||||
);
|
||||
self.save_breakpoints.merge_from(&content.save_breakpoints);
|
||||
self.button.merge_from(&content.button);
|
||||
self.timeout.merge_from(&content.timeout);
|
||||
self.log_dap_communications
|
||||
.merge_from(&content.log_dap_communications);
|
||||
self.format_dap_log_messages
|
||||
.merge_from(&content.format_dap_log_messages);
|
||||
self.dock.merge_from(&content.dock);
|
||||
}
|
||||
|
||||
fn import_from_vscode(_vscode: &settings::VsCodeSettings, _current: &mut SettingsContent) {}
|
||||
}
|
||||
|
||||
impl Global for DebuggerSettings {}
|
||||
fn dap_granularity_from_settings(
|
||||
granularity: settings::SteppingGranularity,
|
||||
) -> dap_types::SteppingGranularity {
|
||||
match granularity {
|
||||
settings::SteppingGranularity::Instruction => dap_types::SteppingGranularity::Instruction,
|
||||
settings::SteppingGranularity::Line => dap_types::SteppingGranularity::Line,
|
||||
settings::SteppingGranularity::Statement => dap_types::SteppingGranularity::Statement,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,6 @@ use crate::{
|
||||
use anyhow::{Context as _, Result, anyhow};
|
||||
use collections::IndexMap;
|
||||
use dap::adapters::DebugAdapterName;
|
||||
use dap::debugger_settings::DebugPanelDockPosition;
|
||||
use dap::{DapRegistry, StartDebuggingRequestArguments};
|
||||
use dap::{client::SessionId, debugger_settings::DebuggerSettings};
|
||||
use editor::Editor;
|
||||
@@ -1400,11 +1399,7 @@ impl Panel for DebugPanel {
|
||||
}
|
||||
|
||||
fn position(&self, _window: &Window, cx: &App) -> DockPosition {
|
||||
match DebuggerSettings::get_global(cx).dock {
|
||||
DebugPanelDockPosition::Left => DockPosition::Left,
|
||||
DebugPanelDockPosition::Bottom => DockPosition::Bottom,
|
||||
DebugPanelDockPosition::Right => DockPosition::Right,
|
||||
}
|
||||
DebuggerSettings::get_global(cx).dock.into()
|
||||
}
|
||||
|
||||
fn position_is_valid(&self, _: DockPosition) -> bool {
|
||||
@@ -1426,18 +1421,9 @@ impl Panel for DebugPanel {
|
||||
});
|
||||
}
|
||||
|
||||
settings::update_settings_file::<DebuggerSettings>(
|
||||
self.fs.clone(),
|
||||
cx,
|
||||
move |settings, _| {
|
||||
let dock = match position {
|
||||
DockPosition::Left => DebugPanelDockPosition::Left,
|
||||
DockPosition::Bottom => DebugPanelDockPosition::Bottom,
|
||||
DockPosition::Right => DebugPanelDockPosition::Right,
|
||||
};
|
||||
settings.dock = dock;
|
||||
},
|
||||
);
|
||||
settings::update_settings_file(self.fs.clone(), cx, move |settings, _| {
|
||||
settings.debugger.get_or_insert_default().dock = Some(position.into());
|
||||
});
|
||||
}
|
||||
|
||||
fn size(&self, _window: &Window, _: &App) -> Pixels {
|
||||
|
||||
@@ -910,8 +910,10 @@ async fn open_disabled_globs_setting_in_editor(
|
||||
let settings = cx.global::<SettingsStore>();
|
||||
|
||||
// Ensure that we always have "edit_predictions { "disabled_globs": [] }"
|
||||
let edits = settings.edits_for_update::<AllLanguageSettings>(&text, |file| {
|
||||
file.edit_predictions
|
||||
let edits = settings.edits_for_update(&text, |file| {
|
||||
file.project
|
||||
.all_languages
|
||||
.edit_predictions
|
||||
.get_or_insert_with(Default::default)
|
||||
.disabled_globs
|
||||
.get_or_insert_with(Vec::new);
|
||||
@@ -948,9 +950,12 @@ async fn open_disabled_globs_setting_in_editor(
|
||||
}
|
||||
|
||||
fn set_completion_provider(fs: Arc<dyn Fs>, cx: &mut App, provider: EditPredictionProvider) {
|
||||
update_settings_file::<AllLanguageSettings>(fs, cx, move |file, _| {
|
||||
file.features
|
||||
.get_or_insert(Default::default())
|
||||
update_settings_file(fs, cx, move |settings, _| {
|
||||
settings
|
||||
.project
|
||||
.all_languages
|
||||
.features
|
||||
.get_or_insert_default()
|
||||
.edit_prediction_provider = Some(provider);
|
||||
});
|
||||
}
|
||||
@@ -962,18 +967,24 @@ fn toggle_show_edit_predictions_for_language(
|
||||
) {
|
||||
let show_edit_predictions =
|
||||
all_language_settings(None, cx).show_edit_predictions(Some(&language), cx);
|
||||
update_settings_file::<AllLanguageSettings>(fs, cx, move |file, _| {
|
||||
file.languages
|
||||
update_settings_file(fs, cx, move |settings, _| {
|
||||
settings
|
||||
.project
|
||||
.all_languages
|
||||
.languages
|
||||
.0
|
||||
.entry(language.name())
|
||||
.entry(language.name().0)
|
||||
.or_default()
|
||||
.show_edit_predictions = Some(!show_edit_predictions);
|
||||
});
|
||||
}
|
||||
|
||||
fn hide_copilot(fs: Arc<dyn Fs>, cx: &mut App) {
|
||||
update_settings_file::<AllLanguageSettings>(fs, cx, move |file, _| {
|
||||
file.features
|
||||
update_settings_file(fs, cx, move |settings, _| {
|
||||
settings
|
||||
.project
|
||||
.all_languages
|
||||
.features
|
||||
.get_or_insert(Default::default())
|
||||
.edit_prediction_provider = Some(EditPredictionProvider::None);
|
||||
});
|
||||
@@ -984,13 +995,14 @@ fn toggle_edit_prediction_mode(fs: Arc<dyn Fs>, mode: EditPredictionsMode, cx: &
|
||||
let current_mode = settings.edit_predictions_mode();
|
||||
|
||||
if current_mode != mode {
|
||||
update_settings_file::<AllLanguageSettings>(fs, cx, move |settings, _cx| {
|
||||
if let Some(edit_predictions) = settings.edit_predictions.as_mut() {
|
||||
edit_predictions.mode = mode;
|
||||
update_settings_file(fs, cx, move |settings, _cx| {
|
||||
if let Some(edit_predictions) = settings.project.all_languages.edit_predictions.as_mut()
|
||||
{
|
||||
edit_predictions.mode = Some(mode);
|
||||
} else {
|
||||
settings.edit_predictions =
|
||||
Some(language_settings::EditPredictionSettingsContent {
|
||||
mode,
|
||||
settings.project.all_languages.edit_predictions =
|
||||
Some(settings::EditPredictionSettingsContent {
|
||||
mode: Some(mode),
|
||||
..Default::default()
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
use crate::{code_context_menus::CompletionsMenu, editor_settings::SnippetSortOrder};
|
||||
use crate::code_context_menus::CompletionsMenu;
|
||||
use fuzzy::{StringMatch, StringMatchCandidate};
|
||||
use gpui::TestAppContext;
|
||||
use language::CodeLabel;
|
||||
use lsp::{CompletionItem, CompletionItemKind, LanguageServerId};
|
||||
use project::{Completion, CompletionSource};
|
||||
use settings::SnippetSortOrder;
|
||||
use std::sync::Arc;
|
||||
use std::sync::atomic::AtomicBool;
|
||||
use text::Anchor;
|
||||
|
||||
@@ -32,7 +32,6 @@ use ui::{Color, IntoElement, ListItem, Pixels, Popover, Styled, prelude::*};
|
||||
use util::ResultExt;
|
||||
|
||||
use crate::CodeActionSource;
|
||||
use crate::editor_settings::SnippetSortOrder;
|
||||
use crate::hover_popover::{hover_markdown_style, open_markdown_url};
|
||||
use crate::{
|
||||
CodeActionProvider, CompletionId, CompletionItemKind, CompletionProvider, DisplayRow, Editor,
|
||||
@@ -40,6 +39,7 @@ use crate::{
|
||||
actions::{ConfirmCodeAction, ConfirmCompletion},
|
||||
split_words, styled_runs_for_code_label,
|
||||
};
|
||||
use settings::SnippetSortOrder;
|
||||
|
||||
pub const MENU_GAP: Pixels = px(4.);
|
||||
pub const MENU_ASIDE_X_PADDING: Pixels = px(16.);
|
||||
|
||||
@@ -1529,12 +1529,11 @@ pub mod tests {
|
||||
use language::{
|
||||
Buffer, Diagnostic, DiagnosticEntry, DiagnosticSet, Language, LanguageConfig,
|
||||
LanguageMatcher,
|
||||
language_settings::{AllLanguageSettings, AllLanguageSettingsContent},
|
||||
};
|
||||
use lsp::LanguageServerId;
|
||||
use project::Project;
|
||||
use rand::{Rng, prelude::*};
|
||||
use settings::SettingsStore;
|
||||
use settings::{SettingsContent, SettingsStore};
|
||||
use smol::stream::StreamExt;
|
||||
use std::{env, sync::Arc};
|
||||
use text::PointUtf16;
|
||||
@@ -1564,7 +1563,9 @@ pub mod tests {
|
||||
log::info!("wrap width: {:?}", wrap_width);
|
||||
|
||||
cx.update(|cx| {
|
||||
init_test(cx, |s| s.defaults.tab_size = NonZeroU32::new(tab_size));
|
||||
init_test(cx, |s| {
|
||||
s.project.all_languages.defaults.tab_size = NonZeroU32::new(tab_size)
|
||||
});
|
||||
});
|
||||
|
||||
let buffer = cx.update(|cx| {
|
||||
@@ -1623,8 +1624,9 @@ pub mod tests {
|
||||
log::info!("setting tab size to {:?}", tab_size);
|
||||
cx.update(|cx| {
|
||||
cx.update_global::<SettingsStore, _>(|store, cx| {
|
||||
store.update_user_settings::<AllLanguageSettings>(cx, |s| {
|
||||
s.defaults.tab_size = NonZeroU32::new(tab_size);
|
||||
store.update_user_settings(cx, |s| {
|
||||
s.project.all_languages.defaults.tab_size =
|
||||
NonZeroU32::new(tab_size);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -2084,7 +2086,11 @@ pub mod tests {
|
||||
);
|
||||
language.set_theme(&theme);
|
||||
|
||||
cx.update(|cx| init_test(cx, |s| s.defaults.tab_size = Some(2.try_into().unwrap())));
|
||||
cx.update(|cx| {
|
||||
init_test(cx, |s| {
|
||||
s.project.all_languages.defaults.tab_size = Some(2.try_into().unwrap())
|
||||
})
|
||||
});
|
||||
|
||||
let buffer = cx.new(|cx| Buffer::local(text, cx).with_language(language, cx));
|
||||
cx.condition(&buffer, |buf, _| !buf.is_parsing()).await;
|
||||
@@ -2910,7 +2916,7 @@ pub mod tests {
|
||||
chunks
|
||||
}
|
||||
|
||||
fn init_test(cx: &mut App, f: impl Fn(&mut AllLanguageSettingsContent)) {
|
||||
fn init_test(cx: &mut App, f: impl Fn(&mut SettingsContent)) {
|
||||
let settings = SettingsStore::test(cx);
|
||||
cx.set_global(settings);
|
||||
workspace::init_settings(cx);
|
||||
@@ -2919,7 +2925,7 @@ pub mod tests {
|
||||
Project::init_settings(cx);
|
||||
theme::init(LoadThemes::JustBase, cx);
|
||||
cx.update_global::<SettingsStore, _>(|store, cx| {
|
||||
store.update_user_settings::<AllLanguageSettings>(cx, f);
|
||||
store.update_user_settings(cx, f);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
+13
-13
@@ -160,9 +160,7 @@ use project::{
|
||||
},
|
||||
git_store::{GitStoreEvent, RepositoryEvent},
|
||||
lsp_store::{CompletionDocumentation, FormatTrigger, LspFormatTarget, OpenLspBufferHandle},
|
||||
project_settings::{
|
||||
DiagnosticSeverity, GitGutterSetting, GoToDiagnosticSeverityFilter, ProjectSettings,
|
||||
},
|
||||
project_settings::{DiagnosticSeverity, GoToDiagnosticSeverityFilter, ProjectSettings},
|
||||
};
|
||||
use rand::seq::SliceRandom;
|
||||
use rpc::{ErrorCode, ErrorExt, proto::PeerId};
|
||||
@@ -171,7 +169,7 @@ use selections_collection::{
|
||||
MutableSelectionsCollection, SelectionsCollection, resolve_selections,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use settings::{Settings, SettingsLocation, SettingsStore, update_settings_file};
|
||||
use settings::{GitGutterSetting, Settings, SettingsLocation, SettingsStore, update_settings_file};
|
||||
use smallvec::{SmallVec, smallvec};
|
||||
use snippet::Snippet;
|
||||
use std::{
|
||||
@@ -2189,7 +2187,7 @@ impl Editor {
|
||||
show_selection_menu: None,
|
||||
show_git_blame_inline_delay_task: None,
|
||||
git_blame_inline_enabled: full_mode
|
||||
&& ProjectSettings::get_global(cx).git.inline_blame_enabled(),
|
||||
&& ProjectSettings::get_global(cx).git.inline_blame.enabled,
|
||||
render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
|
||||
serialize_dirty_buffers: !is_minimap
|
||||
&& ProjectSettings::get_global(cx)
|
||||
@@ -5591,8 +5589,9 @@ impl Editor {
|
||||
.language_at(buffer_position)
|
||||
.map(|language| language.name());
|
||||
|
||||
let completion_settings =
|
||||
language_settings(language.clone(), buffer_snapshot.file(), cx).completions;
|
||||
let completion_settings = language_settings(language.clone(), buffer_snapshot.file(), cx)
|
||||
.completions
|
||||
.clone();
|
||||
|
||||
let show_completion_documentation = buffer_snapshot
|
||||
.settings_at(buffer_position, cx)
|
||||
@@ -19008,8 +19007,8 @@ impl Editor {
|
||||
};
|
||||
let fs = workspace.read(cx).app_state().fs.clone();
|
||||
let current_show = TabBarSettings::get_global(cx).show;
|
||||
update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
|
||||
setting.show = Some(!current_show);
|
||||
update_settings_file(fs, cx, move |setting, _| {
|
||||
setting.tab_bar.get_or_insert_default().show = Some(!current_show);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -20723,7 +20722,7 @@ impl Editor {
|
||||
|
||||
if self.mode.is_full() {
|
||||
let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
|
||||
let inline_blame_enabled = project_settings.git.inline_blame_enabled();
|
||||
let inline_blame_enabled = project_settings.git.inline_blame.enabled;
|
||||
if self.show_inline_diagnostics != show_inline_diagnostics {
|
||||
self.show_inline_diagnostics = show_inline_diagnostics;
|
||||
self.refresh_inline_diagnostics(false, window, cx);
|
||||
@@ -21679,11 +21678,12 @@ impl Editor {
|
||||
}
|
||||
}
|
||||
|
||||
// todo(settings_refactor) this should not be!
|
||||
fn vim_enabled(cx: &App) -> bool {
|
||||
cx.global::<SettingsStore>()
|
||||
.raw_user_settings()
|
||||
.get("vim_mode")
|
||||
== Some(&serde_json::Value::Bool(true))
|
||||
.and_then(|settings| settings.content.vim_mode)
|
||||
== Some(true)
|
||||
}
|
||||
|
||||
fn process_completion_for_edit(
|
||||
@@ -23123,7 +23123,7 @@ impl EditorSnapshot {
|
||||
let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
|
||||
matches!(
|
||||
ProjectSettings::get_global(cx).git.git_gutter,
|
||||
Some(GitGutterSetting::TrackedFiles)
|
||||
GitGutterSetting::TrackedFiles
|
||||
)
|
||||
});
|
||||
let gutter_settings = EditorSettings::get_global(cx).gutter;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,8 +1,8 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use gpui::{App, FontFeatures, FontWeight};
|
||||
use project::project_settings::{InlineBlameSettings, ProjectSettings};
|
||||
use settings::{EditableSettingControl, Settings};
|
||||
use project::project_settings::ProjectSettings;
|
||||
use settings::{EditableSettingControl, Settings, SettingsContent};
|
||||
use theme::{FontFamilyCache, FontFamilyName, ThemeSettings};
|
||||
use ui::{
|
||||
CheckboxWithLabel, ContextMenu, DropdownMenu, NumericStepper, SettingsContainer, SettingsGroup,
|
||||
@@ -59,7 +59,6 @@ struct BufferFontFamilyControl;
|
||||
|
||||
impl EditableSettingControl for BufferFontFamilyControl {
|
||||
type Value = SharedString;
|
||||
type Settings = ThemeSettings;
|
||||
|
||||
fn name(&self) -> SharedString {
|
||||
"Buffer Font Family".into()
|
||||
@@ -70,12 +69,8 @@ impl EditableSettingControl for BufferFontFamilyControl {
|
||||
settings.buffer_font.family.clone()
|
||||
}
|
||||
|
||||
fn apply(
|
||||
settings: &mut <Self::Settings as Settings>::FileContent,
|
||||
value: Self::Value,
|
||||
_cx: &App,
|
||||
) {
|
||||
settings.buffer_font_family = Some(FontFamilyName(value.into()));
|
||||
fn apply(settings: &mut SettingsContent, value: Self::Value, _cx: &App) {
|
||||
settings.theme.buffer_font_family = Some(FontFamilyName(value.into()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -118,7 +113,6 @@ struct BufferFontSizeControl;
|
||||
|
||||
impl EditableSettingControl for BufferFontSizeControl {
|
||||
type Value = Pixels;
|
||||
type Settings = ThemeSettings;
|
||||
|
||||
fn name(&self) -> SharedString {
|
||||
"Buffer Font Size".into()
|
||||
@@ -128,12 +122,8 @@ impl EditableSettingControl for BufferFontSizeControl {
|
||||
ThemeSettings::get_global(cx).buffer_font_size(cx)
|
||||
}
|
||||
|
||||
fn apply(
|
||||
settings: &mut <Self::Settings as Settings>::FileContent,
|
||||
value: Self::Value,
|
||||
_cx: &App,
|
||||
) {
|
||||
settings.buffer_font_size = Some(value.into());
|
||||
fn apply(settings: &mut SettingsContent, value: Self::Value, _cx: &App) {
|
||||
settings.theme.buffer_font_size = Some(value.into());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -162,7 +152,6 @@ struct BufferFontWeightControl;
|
||||
|
||||
impl EditableSettingControl for BufferFontWeightControl {
|
||||
type Value = FontWeight;
|
||||
type Settings = ThemeSettings;
|
||||
|
||||
fn name(&self) -> SharedString {
|
||||
"Buffer Font Weight".into()
|
||||
@@ -173,12 +162,8 @@ impl EditableSettingControl for BufferFontWeightControl {
|
||||
settings.buffer_font.weight
|
||||
}
|
||||
|
||||
fn apply(
|
||||
settings: &mut <Self::Settings as Settings>::FileContent,
|
||||
value: Self::Value,
|
||||
_cx: &App,
|
||||
) {
|
||||
settings.buffer_font_weight = Some(value.0);
|
||||
fn apply(settings: &mut SettingsContent, value: Self::Value, _cx: &App) {
|
||||
settings.theme.buffer_font_weight = Some(value.0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -215,7 +200,6 @@ struct BufferFontLigaturesControl;
|
||||
|
||||
impl EditableSettingControl for BufferFontLigaturesControl {
|
||||
type Value = bool;
|
||||
type Settings = ThemeSettings;
|
||||
|
||||
fn name(&self) -> SharedString {
|
||||
"Buffer Font Ligatures".into()
|
||||
@@ -230,14 +214,11 @@ impl EditableSettingControl for BufferFontLigaturesControl {
|
||||
.unwrap_or(true)
|
||||
}
|
||||
|
||||
fn apply(
|
||||
settings: &mut <Self::Settings as Settings>::FileContent,
|
||||
value: Self::Value,
|
||||
_cx: &App,
|
||||
) {
|
||||
fn apply(settings: &mut SettingsContent, value: Self::Value, _cx: &App) {
|
||||
let value = if value { 1 } else { 0 };
|
||||
|
||||
let mut features = settings
|
||||
.theme
|
||||
.buffer_font_features
|
||||
.as_ref()
|
||||
.map(|features| features.tag_value_list().to_vec())
|
||||
@@ -249,7 +230,7 @@ impl EditableSettingControl for BufferFontLigaturesControl {
|
||||
features.push(("calt".into(), value));
|
||||
}
|
||||
|
||||
settings.buffer_font_features = Some(FontFeatures(Arc::new(features)));
|
||||
settings.theme.buffer_font_features = Some(FontFeatures(Arc::new(features)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -279,7 +260,6 @@ struct InlineGitBlameControl;
|
||||
|
||||
impl EditableSettingControl for InlineGitBlameControl {
|
||||
type Value = bool;
|
||||
type Settings = ProjectSettings;
|
||||
|
||||
fn name(&self) -> SharedString {
|
||||
"Inline Git Blame".into()
|
||||
@@ -287,22 +267,16 @@ impl EditableSettingControl for InlineGitBlameControl {
|
||||
|
||||
fn read(cx: &App) -> Self::Value {
|
||||
let settings = ProjectSettings::get_global(cx);
|
||||
settings.git.inline_blame_enabled()
|
||||
settings.git.inline_blame.enabled
|
||||
}
|
||||
|
||||
fn apply(
|
||||
settings: &mut <Self::Settings as Settings>::FileContent,
|
||||
value: Self::Value,
|
||||
_cx: &App,
|
||||
) {
|
||||
if let Some(inline_blame) = settings.git.inline_blame.as_mut() {
|
||||
inline_blame.enabled = value;
|
||||
} else {
|
||||
settings.git.inline_blame = Some(InlineBlameSettings {
|
||||
enabled: false,
|
||||
..Default::default()
|
||||
});
|
||||
}
|
||||
fn apply(settings: &mut SettingsContent, value: Self::Value, _cx: &App) {
|
||||
settings
|
||||
.git
|
||||
.get_or_insert_default()
|
||||
.inline_blame
|
||||
.get_or_insert_default()
|
||||
.enabled = Some(value)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -332,7 +306,6 @@ struct LineNumbersControl;
|
||||
|
||||
impl EditableSettingControl for LineNumbersControl {
|
||||
type Value = bool;
|
||||
type Settings = EditorSettings;
|
||||
|
||||
fn name(&self) -> SharedString {
|
||||
"Line Numbers".into()
|
||||
@@ -343,19 +316,8 @@ impl EditableSettingControl for LineNumbersControl {
|
||||
settings.gutter.line_numbers
|
||||
}
|
||||
|
||||
fn apply(
|
||||
settings: &mut <Self::Settings as Settings>::FileContent,
|
||||
value: Self::Value,
|
||||
_cx: &App,
|
||||
) {
|
||||
if let Some(gutter) = settings.gutter.as_mut() {
|
||||
gutter.line_numbers = Some(value);
|
||||
} else {
|
||||
settings.gutter = Some(crate::editor_settings::GutterContent {
|
||||
line_numbers: Some(value),
|
||||
..Default::default()
|
||||
});
|
||||
}
|
||||
fn apply(settings: &mut SettingsContent, value: Self::Value, _cx: &App) {
|
||||
settings.editor.gutter.get_or_insert_default().line_numbers = Some(value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -385,7 +347,6 @@ struct RelativeLineNumbersControl;
|
||||
|
||||
impl EditableSettingControl for RelativeLineNumbersControl {
|
||||
type Value = bool;
|
||||
type Settings = EditorSettings;
|
||||
|
||||
fn name(&self) -> SharedString {
|
||||
"Relative Line Numbers".into()
|
||||
@@ -396,12 +357,8 @@ impl EditableSettingControl for RelativeLineNumbersControl {
|
||||
settings.relative_line_numbers
|
||||
}
|
||||
|
||||
fn apply(
|
||||
settings: &mut <Self::Settings as Settings>::FileContent,
|
||||
value: Self::Value,
|
||||
_cx: &App,
|
||||
) {
|
||||
settings.relative_line_numbers = Some(value);
|
||||
fn apply(settings: &mut SettingsContent, value: Self::Value, _cx: &App) {
|
||||
settings.editor.relative_line_numbers = Some(value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -22,15 +22,15 @@ use indoc::indoc;
|
||||
use language::{
|
||||
BracketPairConfig,
|
||||
Capability::ReadWrite,
|
||||
DiagnosticSourceKind, FakeLspAdapter, LanguageConfig, LanguageConfigOverride, LanguageMatcher,
|
||||
LanguageName, Override, Point,
|
||||
DiagnosticSourceKind, FakeLspAdapter, IndentGuideSettings, LanguageConfig,
|
||||
LanguageConfigOverride, LanguageMatcher, LanguageName, Override, Point,
|
||||
language_settings::{
|
||||
AllLanguageSettings, AllLanguageSettingsContent, CompletionSettings, FormatterList,
|
||||
LanguageSettingsContent, LspInsertMode, PrettierSettings, SelectedFormatter,
|
||||
CompletionSettingsContent, FormatterList, LanguageSettingsContent, LspInsertMode,
|
||||
SelectedFormatter,
|
||||
},
|
||||
tree_sitter_python,
|
||||
};
|
||||
use language_settings::{Formatter, IndentGuideSettings};
|
||||
use language_settings::Formatter;
|
||||
use lsp::CompletionParams;
|
||||
use multi_buffer::{IndentGuide, PathKey};
|
||||
use parking_lot::Mutex;
|
||||
@@ -38,9 +38,13 @@ use pretty_assertions::{assert_eq, assert_ne};
|
||||
use project::{
|
||||
FakeFs,
|
||||
debugger::breakpoint_store::{BreakpointState, SourceBreakpoint},
|
||||
project_settings::{LspSettings, ProjectSettings},
|
||||
project_settings::LspSettings,
|
||||
};
|
||||
use serde_json::{self, json};
|
||||
use settings::{
|
||||
AllLanguageSettingsContent, IndentGuideBackgroundColoring, IndentGuideColoring,
|
||||
ProjectSettingsContent,
|
||||
};
|
||||
use std::{cell::RefCell, future::Future, rc::Rc, sync::atomic::AtomicBool, time::Instant};
|
||||
use std::{
|
||||
iter,
|
||||
@@ -11699,10 +11703,7 @@ async fn test_document_format_manual_trigger(cx: &mut TestAppContext) {
|
||||
update_test_language_settings(cx, |settings| {
|
||||
// Enable Prettier formatting for the same buffer, and ensure
|
||||
// LSP is called instead of Prettier.
|
||||
settings.defaults.prettier = Some(PrettierSettings {
|
||||
allowed: true,
|
||||
..PrettierSettings::default()
|
||||
});
|
||||
settings.defaults.prettier.get_or_insert_default().allowed = Some(true);
|
||||
});
|
||||
let mut fake_servers = language_registry.register_fake_lsp(
|
||||
"Rust",
|
||||
@@ -12088,10 +12089,7 @@ async fn test_organize_imports_manual_trigger(cx: &mut TestAppContext) {
|
||||
Some(tree_sitter_typescript::LANGUAGE_TYPESCRIPT.into()),
|
||||
)));
|
||||
update_test_language_settings(cx, |settings| {
|
||||
settings.defaults.prettier = Some(PrettierSettings {
|
||||
allowed: true,
|
||||
..PrettierSettings::default()
|
||||
});
|
||||
settings.defaults.prettier.get_or_insert_default().allowed = Some(true);
|
||||
});
|
||||
let mut fake_servers = language_registry.register_fake_lsp(
|
||||
"TypeScript",
|
||||
@@ -12402,8 +12400,8 @@ async fn test_handle_input_for_show_signature_help_auto_signature_help_true(
|
||||
|
||||
cx.update(|cx| {
|
||||
cx.update_global::<SettingsStore, _>(|settings, cx| {
|
||||
settings.update_user_settings::<EditorSettings>(cx, |settings| {
|
||||
settings.auto_signature_help = Some(true);
|
||||
settings.update_user_settings(cx, |settings| {
|
||||
settings.editor.auto_signature_help = Some(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -12542,9 +12540,9 @@ async fn test_handle_input_with_different_show_signature_settings(cx: &mut TestA
|
||||
|
||||
cx.update(|cx| {
|
||||
cx.update_global::<SettingsStore, _>(|settings, cx| {
|
||||
settings.update_user_settings::<EditorSettings>(cx, |settings| {
|
||||
settings.auto_signature_help = Some(false);
|
||||
settings.show_signature_help_after_edits = Some(false);
|
||||
settings.update_user_settings(cx, |settings| {
|
||||
settings.editor.auto_signature_help = Some(false);
|
||||
settings.editor.show_signature_help_after_edits = Some(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -12669,9 +12667,9 @@ async fn test_handle_input_with_different_show_signature_settings(cx: &mut TestA
|
||||
// Ensure that signature_help is called when enabled afte edits
|
||||
cx.update(|_, cx| {
|
||||
cx.update_global::<SettingsStore, _>(|settings, cx| {
|
||||
settings.update_user_settings::<EditorSettings>(cx, |settings| {
|
||||
settings.auto_signature_help = Some(false);
|
||||
settings.show_signature_help_after_edits = Some(true);
|
||||
settings.update_user_settings(cx, |settings| {
|
||||
settings.editor.auto_signature_help = Some(false);
|
||||
settings.editor.show_signature_help_after_edits = Some(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -12711,9 +12709,9 @@ async fn test_handle_input_with_different_show_signature_settings(cx: &mut TestA
|
||||
// Ensure that signature_help is called when auto signature help override is enabled
|
||||
cx.update(|_, cx| {
|
||||
cx.update_global::<SettingsStore, _>(|settings, cx| {
|
||||
settings.update_user_settings::<EditorSettings>(cx, |settings| {
|
||||
settings.auto_signature_help = Some(true);
|
||||
settings.show_signature_help_after_edits = Some(false);
|
||||
settings.update_user_settings(cx, |settings| {
|
||||
settings.editor.auto_signature_help = Some(true);
|
||||
settings.editor.show_signature_help_after_edits = Some(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -12755,8 +12753,8 @@ async fn test_signature_help(cx: &mut TestAppContext) {
|
||||
init_test(cx, |_| {});
|
||||
cx.update(|cx| {
|
||||
cx.update_global::<SettingsStore, _>(|settings, cx| {
|
||||
settings.update_user_settings::<EditorSettings>(cx, |settings| {
|
||||
settings.auto_signature_help = Some(true);
|
||||
settings.update_user_settings(cx, |settings| {
|
||||
settings.editor.auto_signature_help = Some(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -13346,12 +13344,11 @@ async fn test_completion_mode(cx: &mut TestAppContext) {
|
||||
);
|
||||
|
||||
update_test_language_settings(&mut cx, |settings| {
|
||||
settings.defaults.completions = Some(CompletionSettings {
|
||||
lsp_insert_mode,
|
||||
words: WordsCompletionMode::Disabled,
|
||||
words_min_length: 0,
|
||||
lsp: true,
|
||||
lsp_fetch_timeout_ms: 0,
|
||||
settings.defaults.completions = Some(CompletionSettingsContent {
|
||||
lsp_insert_mode: Some(lsp_insert_mode),
|
||||
words: Some(WordsCompletionMode::Disabled),
|
||||
words_min_length: Some(0),
|
||||
..Default::default()
|
||||
});
|
||||
});
|
||||
|
||||
@@ -13406,13 +13403,12 @@ async fn test_completion_with_mode_specified_by_action(cx: &mut TestAppContext)
|
||||
let expected_with_replace_mode = "SubscriptionErrorˇ";
|
||||
|
||||
update_test_language_settings(&mut cx, |settings| {
|
||||
settings.defaults.completions = Some(CompletionSettings {
|
||||
words: WordsCompletionMode::Disabled,
|
||||
words_min_length: 0,
|
||||
settings.defaults.completions = Some(CompletionSettingsContent {
|
||||
words: Some(WordsCompletionMode::Disabled),
|
||||
words_min_length: Some(0),
|
||||
// set the opposite here to ensure that the action is overriding the default behavior
|
||||
lsp_insert_mode: LspInsertMode::Insert,
|
||||
lsp: true,
|
||||
lsp_fetch_timeout_ms: 0,
|
||||
lsp_insert_mode: Some(LspInsertMode::Insert),
|
||||
..Default::default()
|
||||
});
|
||||
});
|
||||
|
||||
@@ -13443,13 +13439,12 @@ async fn test_completion_with_mode_specified_by_action(cx: &mut TestAppContext)
|
||||
apply_additional_edits.await.unwrap();
|
||||
|
||||
update_test_language_settings(&mut cx, |settings| {
|
||||
settings.defaults.completions = Some(CompletionSettings {
|
||||
words: WordsCompletionMode::Disabled,
|
||||
words_min_length: 0,
|
||||
settings.defaults.completions = Some(CompletionSettingsContent {
|
||||
words: Some(WordsCompletionMode::Disabled),
|
||||
words_min_length: Some(0),
|
||||
// set the opposite here to ensure that the action is overriding the default behavior
|
||||
lsp_insert_mode: LspInsertMode::Replace,
|
||||
lsp: true,
|
||||
lsp_fetch_timeout_ms: 0,
|
||||
lsp_insert_mode: Some(LspInsertMode::Replace),
|
||||
..Default::default()
|
||||
});
|
||||
});
|
||||
|
||||
@@ -14185,12 +14180,11 @@ async fn test_completion_reuse(cx: &mut TestAppContext) {
|
||||
async fn test_word_completion(cx: &mut TestAppContext) {
|
||||
let lsp_fetch_timeout_ms = 10;
|
||||
init_test(cx, |language_settings| {
|
||||
language_settings.defaults.completions = Some(CompletionSettings {
|
||||
words: WordsCompletionMode::Fallback,
|
||||
words_min_length: 0,
|
||||
lsp: true,
|
||||
lsp_fetch_timeout_ms: 10,
|
||||
lsp_insert_mode: LspInsertMode::Insert,
|
||||
language_settings.defaults.completions = Some(CompletionSettingsContent {
|
||||
words_min_length: Some(0),
|
||||
lsp_fetch_timeout_ms: Some(10),
|
||||
lsp_insert_mode: Some(LspInsertMode::Insert),
|
||||
..Default::default()
|
||||
});
|
||||
});
|
||||
|
||||
@@ -14282,12 +14276,11 @@ async fn test_word_completion(cx: &mut TestAppContext) {
|
||||
#[gpui::test]
|
||||
async fn test_word_completions_do_not_duplicate_lsp_ones(cx: &mut TestAppContext) {
|
||||
init_test(cx, |language_settings| {
|
||||
language_settings.defaults.completions = Some(CompletionSettings {
|
||||
words: WordsCompletionMode::Enabled,
|
||||
words_min_length: 0,
|
||||
lsp: true,
|
||||
lsp_fetch_timeout_ms: 0,
|
||||
lsp_insert_mode: LspInsertMode::Insert,
|
||||
language_settings.defaults.completions = Some(CompletionSettingsContent {
|
||||
words: Some(WordsCompletionMode::Enabled),
|
||||
words_min_length: Some(0),
|
||||
lsp_insert_mode: Some(LspInsertMode::Insert),
|
||||
..Default::default()
|
||||
});
|
||||
});
|
||||
|
||||
@@ -14346,12 +14339,11 @@ async fn test_word_completions_do_not_duplicate_lsp_ones(cx: &mut TestAppContext
|
||||
#[gpui::test]
|
||||
async fn test_word_completions_continue_on_typing(cx: &mut TestAppContext) {
|
||||
init_test(cx, |language_settings| {
|
||||
language_settings.defaults.completions = Some(CompletionSettings {
|
||||
words: WordsCompletionMode::Disabled,
|
||||
words_min_length: 0,
|
||||
lsp: true,
|
||||
lsp_fetch_timeout_ms: 0,
|
||||
lsp_insert_mode: LspInsertMode::Insert,
|
||||
language_settings.defaults.completions = Some(CompletionSettingsContent {
|
||||
words: Some(WordsCompletionMode::Disabled),
|
||||
words_min_length: Some(0),
|
||||
lsp_insert_mode: Some(LspInsertMode::Insert),
|
||||
..Default::default()
|
||||
});
|
||||
});
|
||||
|
||||
@@ -14420,12 +14412,11 @@ async fn test_word_completions_continue_on_typing(cx: &mut TestAppContext) {
|
||||
#[gpui::test]
|
||||
async fn test_word_completions_usually_skip_digits(cx: &mut TestAppContext) {
|
||||
init_test(cx, |language_settings| {
|
||||
language_settings.defaults.completions = Some(CompletionSettings {
|
||||
words: WordsCompletionMode::Fallback,
|
||||
words_min_length: 0,
|
||||
lsp: false,
|
||||
lsp_fetch_timeout_ms: 0,
|
||||
lsp_insert_mode: LspInsertMode::Insert,
|
||||
language_settings.defaults.completions = Some(CompletionSettingsContent {
|
||||
words_min_length: Some(0),
|
||||
lsp: Some(false),
|
||||
lsp_insert_mode: Some(LspInsertMode::Insert),
|
||||
..Default::default()
|
||||
});
|
||||
});
|
||||
|
||||
@@ -14483,12 +14474,11 @@ async fn test_word_completions_usually_skip_digits(cx: &mut TestAppContext) {
|
||||
#[gpui::test]
|
||||
async fn test_word_completions_do_not_show_before_threshold(cx: &mut TestAppContext) {
|
||||
init_test(cx, |language_settings| {
|
||||
language_settings.defaults.completions = Some(CompletionSettings {
|
||||
words: WordsCompletionMode::Enabled,
|
||||
words_min_length: 3,
|
||||
lsp: true,
|
||||
lsp_fetch_timeout_ms: 0,
|
||||
lsp_insert_mode: LspInsertMode::Insert,
|
||||
language_settings.defaults.completions = Some(CompletionSettingsContent {
|
||||
words: Some(WordsCompletionMode::Enabled),
|
||||
words_min_length: Some(3),
|
||||
lsp_insert_mode: Some(LspInsertMode::Insert),
|
||||
..Default::default()
|
||||
});
|
||||
});
|
||||
|
||||
@@ -14553,12 +14543,11 @@ async fn test_word_completions_do_not_show_before_threshold(cx: &mut TestAppCont
|
||||
#[gpui::test]
|
||||
async fn test_word_completions_disabled(cx: &mut TestAppContext) {
|
||||
init_test(cx, |language_settings| {
|
||||
language_settings.defaults.completions = Some(CompletionSettings {
|
||||
words: WordsCompletionMode::Enabled,
|
||||
words_min_length: 0,
|
||||
lsp: true,
|
||||
lsp_fetch_timeout_ms: 0,
|
||||
lsp_insert_mode: LspInsertMode::Insert,
|
||||
language_settings.defaults.completions = Some(CompletionSettingsContent {
|
||||
words: Some(WordsCompletionMode::Enabled),
|
||||
words_min_length: Some(0),
|
||||
lsp_insert_mode: Some(LspInsertMode::Insert),
|
||||
..Default::default()
|
||||
});
|
||||
});
|
||||
|
||||
@@ -17067,7 +17056,7 @@ async fn test_language_server_restart_due_to_settings_change(cx: &mut TestAppCon
|
||||
let _fake_server = fake_servers.next().await.unwrap();
|
||||
update_test_language_settings(cx, |language_settings| {
|
||||
language_settings.languages.0.insert(
|
||||
language_name.clone(),
|
||||
language_name.clone().0,
|
||||
LanguageSettingsContent {
|
||||
tab_size: NonZeroU32::new(8),
|
||||
..Default::default()
|
||||
@@ -17991,10 +17980,7 @@ async fn test_document_format_with_prettier(cx: &mut TestAppContext) {
|
||||
Some(tree_sitter_typescript::LANGUAGE_TYPESCRIPT.into()),
|
||||
)));
|
||||
update_test_language_settings(cx, |settings| {
|
||||
settings.defaults.prettier = Some(PrettierSettings {
|
||||
allowed: true,
|
||||
..PrettierSettings::default()
|
||||
});
|
||||
settings.defaults.prettier.get_or_insert_default().allowed = Some(true);
|
||||
});
|
||||
|
||||
let test_plugin = "test_plugin";
|
||||
@@ -19982,7 +19968,8 @@ fn indent_guide(buffer_id: BufferId, start_row: u32, end_row: u32, depth: u32) -
|
||||
enabled: true,
|
||||
line_width: 1,
|
||||
active_line_width: 1,
|
||||
..Default::default()
|
||||
coloring: IndentGuideColoring::default(),
|
||||
background_coloring: IndentGuideBackgroundColoring::default(),
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -23672,8 +23659,8 @@ println!("5");
|
||||
});
|
||||
|
||||
cx.update_global(|store: &mut SettingsStore, cx| {
|
||||
store.update_user_settings::<WorkspaceSettings>(cx, |s| {
|
||||
s.restore_on_file_reopen = Some(false);
|
||||
store.update_user_settings(cx, |s| {
|
||||
s.workspace.restore_on_file_reopen = Some(false);
|
||||
});
|
||||
});
|
||||
editor.update_in(cx, |editor, window, cx| {
|
||||
@@ -23697,8 +23684,8 @@ println!("5");
|
||||
assert!(pane.active_item().is_none());
|
||||
});
|
||||
cx.update_global(|store: &mut SettingsStore, cx| {
|
||||
store.update_user_settings::<WorkspaceSettings>(cx, |s| {
|
||||
s.restore_on_file_reopen = Some(true);
|
||||
store.update_user_settings(cx, |s| {
|
||||
s.workspace.restore_on_file_reopen = Some(true);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -25120,18 +25107,18 @@ pub(crate) fn update_test_language_settings(
|
||||
) {
|
||||
cx.update(|cx| {
|
||||
SettingsStore::update_global(cx, |store, cx| {
|
||||
store.update_user_settings::<AllLanguageSettings>(cx, f);
|
||||
store.update_user_settings(cx, |settings| f(&mut settings.project.all_languages));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
pub(crate) fn update_test_project_settings(
|
||||
cx: &mut TestAppContext,
|
||||
f: impl Fn(&mut ProjectSettings),
|
||||
f: impl Fn(&mut ProjectSettingsContent),
|
||||
) {
|
||||
cx.update(|cx| {
|
||||
SettingsStore::update_global(cx, |store, cx| {
|
||||
store.update_user_settings::<ProjectSettings>(cx, f);
|
||||
store.update_user_settings(cx, |settings| f(&mut settings.project));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -51,9 +51,7 @@ use gpui::{
|
||||
transparent_black,
|
||||
};
|
||||
use itertools::Itertools;
|
||||
use language::language_settings::{
|
||||
IndentGuideBackgroundColoring, IndentGuideColoring, IndentGuideSettings, ShowWhitespaceSetting,
|
||||
};
|
||||
use language::{IndentGuideSettings, language_settings::ShowWhitespaceSetting};
|
||||
use markdown::Markdown;
|
||||
use multi_buffer::{
|
||||
Anchor, ExcerptId, ExcerptInfo, ExpandExcerptDirection, ExpandInfo, MultiBufferPoint,
|
||||
@@ -63,9 +61,12 @@ use multi_buffer::{
|
||||
use project::{
|
||||
Entry, ProjectPath,
|
||||
debugger::breakpoint_store::{Breakpoint, BreakpointSessionState},
|
||||
project_settings::{GitGutterSetting, GitHunkStyleSetting, ProjectSettings},
|
||||
project_settings::ProjectSettings,
|
||||
};
|
||||
use settings::{
|
||||
GitGutterSetting, GitHunkStyleSetting, IndentGuideBackgroundColoring, IndentGuideColoring,
|
||||
Settings,
|
||||
};
|
||||
use settings::Settings;
|
||||
use smallvec::{SmallVec, smallvec};
|
||||
use std::{
|
||||
any::TypeId,
|
||||
@@ -2099,10 +2100,7 @@ impl EditorElement {
|
||||
.display_diff_hunks_for_rows(display_rows, folded_buffers)
|
||||
.map(|hunk| (hunk, None))
|
||||
.collect::<Vec<_>>();
|
||||
let git_gutter_setting = ProjectSettings::get_global(cx)
|
||||
.git
|
||||
.git_gutter
|
||||
.unwrap_or_default();
|
||||
let git_gutter_setting = ProjectSettings::get_global(cx).git.git_gutter;
|
||||
if let GitGutterSetting::TrackedFiles = git_gutter_setting {
|
||||
for (hunk, hitbox) in &mut display_hunks {
|
||||
if matches!(hunk, DisplayDiffHunk::Unfolded { .. }) {
|
||||
@@ -2454,11 +2452,7 @@ impl EditorElement {
|
||||
let padding = {
|
||||
const INLINE_ACCEPT_SUGGESTION_EM_WIDTHS: f32 = 14.;
|
||||
|
||||
let mut padding = ProjectSettings::get_global(cx)
|
||||
.git
|
||||
.inline_blame
|
||||
.unwrap_or_default()
|
||||
.padding as f32;
|
||||
let mut padding = ProjectSettings::get_global(cx).git.inline_blame.padding as f32;
|
||||
|
||||
if let Some(edit_prediction) = editor.active_edit_prediction.as_ref()
|
||||
&& let EditPrediction::Edit {
|
||||
@@ -2492,12 +2486,10 @@ impl EditorElement {
|
||||
|
||||
let padded_line_end = line_end + padding;
|
||||
|
||||
let min_column_in_pixels = ProjectSettings::get_global(cx)
|
||||
.git
|
||||
.inline_blame
|
||||
.map(|settings| settings.min_column)
|
||||
.map(|col| self.column_pixels(col as usize, window))
|
||||
.unwrap_or(px(0.));
|
||||
let min_column_in_pixels = self.column_pixels(
|
||||
ProjectSettings::get_global(cx).git.inline_blame.min_column as usize,
|
||||
window,
|
||||
);
|
||||
let min_start = content_origin.x - scroll_pixel_position.x + min_column_in_pixels;
|
||||
|
||||
cmp::max(padded_line_end, min_start)
|
||||
@@ -5673,7 +5665,7 @@ impl EditorElement {
|
||||
|
||||
for indent_guide in indent_guides {
|
||||
let indent_accent_colors = cx.theme().accents().color_for_index(indent_guide.depth);
|
||||
let settings = indent_guide.settings;
|
||||
let settings = &indent_guide.settings;
|
||||
|
||||
// TODO fixed for now, expose them through themes later
|
||||
const INDENT_AWARE_ALPHA: f32 = 0.2;
|
||||
@@ -6008,7 +6000,7 @@ impl EditorElement {
|
||||
.unwrap_or_else(|| {
|
||||
matches!(
|
||||
ProjectSettings::get_global(cx).git.git_gutter,
|
||||
Some(GitGutterSetting::TrackedFiles)
|
||||
GitGutterSetting::TrackedFiles
|
||||
)
|
||||
});
|
||||
if show_git_gutter {
|
||||
@@ -7303,10 +7295,10 @@ impl EditorElement {
|
||||
|
||||
fn diff_hunk_hollow(status: DiffHunkStatus, cx: &mut App) -> bool {
|
||||
let unstaged = status.has_secondary_hunk();
|
||||
let unstaged_hollow = ProjectSettings::get_global(cx)
|
||||
.git
|
||||
.hunk_style
|
||||
.is_some_and(|style| matches!(style, GitHunkStyleSetting::UnstagedHollow));
|
||||
let unstaged_hollow = matches!(
|
||||
ProjectSettings::get_global(cx).git.hunk_style,
|
||||
GitHunkStyleSetting::UnstagedHollow
|
||||
);
|
||||
|
||||
unstaged == unstaged_hollow
|
||||
}
|
||||
@@ -8843,13 +8835,9 @@ impl Element for EditorElement {
|
||||
})
|
||||
.flatten()?;
|
||||
let mut element = render_inline_blame_entry(blame_entry, style, cx)?;
|
||||
let inline_blame_padding = ProjectSettings::get_global(cx)
|
||||
.git
|
||||
.inline_blame
|
||||
.unwrap_or_default()
|
||||
.padding
|
||||
as f32
|
||||
* em_advance;
|
||||
let inline_blame_padding =
|
||||
ProjectSettings::get_global(cx).git.inline_blame.padding as f32
|
||||
* em_advance;
|
||||
Some(
|
||||
element
|
||||
.layout_as_root(AvailableSpace::min_size(), window, cx)
|
||||
|
||||
@@ -931,8 +931,8 @@ mod tests {
|
||||
use futures::StreamExt;
|
||||
use gpui::Modifiers;
|
||||
use indoc::indoc;
|
||||
use language::language_settings::InlayHintSettings;
|
||||
use lsp::request::{GotoDefinition, GotoTypeDefinition};
|
||||
use settings::InlayHintSettingsContent;
|
||||
use util::{assert_set_eq, path};
|
||||
use workspace::item::Item;
|
||||
|
||||
@@ -1280,15 +1280,15 @@ mod tests {
|
||||
#[gpui::test]
|
||||
async fn test_inlay_hover_links(cx: &mut gpui::TestAppContext) {
|
||||
init_test(cx, |settings| {
|
||||
settings.defaults.inlay_hints = Some(InlayHintSettings {
|
||||
enabled: true,
|
||||
show_value_hints: false,
|
||||
edit_debounce_ms: 0,
|
||||
scroll_debounce_ms: 0,
|
||||
show_type_hints: true,
|
||||
show_parameter_hints: true,
|
||||
show_other_hints: true,
|
||||
show_background: false,
|
||||
settings.defaults.inlay_hints = Some(InlayHintSettingsContent {
|
||||
enabled: Some(true),
|
||||
show_value_hints: Some(false),
|
||||
edit_debounce_ms: Some(0),
|
||||
scroll_debounce_ms: Some(0),
|
||||
show_type_hints: Some(true),
|
||||
show_parameter_hints: Some(true),
|
||||
show_other_hints: Some(true),
|
||||
show_background: Some(false),
|
||||
toggle_on_modifiers_press: None,
|
||||
})
|
||||
});
|
||||
|
||||
@@ -1004,8 +1004,8 @@ mod tests {
|
||||
use collections::BTreeSet;
|
||||
use gpui::App;
|
||||
use indoc::indoc;
|
||||
use language::language_settings::InlayHintSettings;
|
||||
use markdown::parser::MarkdownEvent;
|
||||
use settings::InlayHintSettingsContent;
|
||||
use smol::stream::StreamExt;
|
||||
use std::sync::atomic;
|
||||
use std::sync::atomic::AtomicUsize;
|
||||
@@ -1551,15 +1551,15 @@ mod tests {
|
||||
#[gpui::test]
|
||||
async fn test_hover_inlay_label_parts(cx: &mut gpui::TestAppContext) {
|
||||
init_test(cx, |settings| {
|
||||
settings.defaults.inlay_hints = Some(InlayHintSettings {
|
||||
show_value_hints: true,
|
||||
enabled: true,
|
||||
edit_debounce_ms: 0,
|
||||
scroll_debounce_ms: 0,
|
||||
show_type_hints: true,
|
||||
show_parameter_hints: true,
|
||||
show_other_hints: true,
|
||||
show_background: false,
|
||||
settings.defaults.inlay_hints = Some(InlayHintSettingsContent {
|
||||
show_value_hints: Some(true),
|
||||
enabled: Some(true),
|
||||
edit_debounce_ms: Some(0),
|
||||
scroll_debounce_ms: Some(0),
|
||||
show_type_hints: Some(true),
|
||||
show_parameter_hints: Some(true),
|
||||
show_other_hints: Some(true),
|
||||
show_background: Some(false),
|
||||
toggle_on_modifiers_press: None,
|
||||
})
|
||||
});
|
||||
|
||||
@@ -20,12 +20,14 @@ use anyhow::Context as _;
|
||||
use clock::Global;
|
||||
use futures::future;
|
||||
use gpui::{AppContext as _, AsyncApp, Context, Entity, Task, Window};
|
||||
use language::{Buffer, BufferSnapshot, language_settings::InlayHintKind};
|
||||
use language::{
|
||||
Buffer, BufferSnapshot,
|
||||
language_settings::{InlayHintKind, InlayHintSettings},
|
||||
};
|
||||
use parking_lot::RwLock;
|
||||
use project::{InlayHint, ResolveState};
|
||||
|
||||
use collections::{HashMap, HashSet, hash_map};
|
||||
use language::language_settings::InlayHintSettings;
|
||||
use smol::lock::Semaphore;
|
||||
use sum_tree::Bias;
|
||||
use text::{BufferId, ToOffset, ToPoint};
|
||||
@@ -1301,13 +1303,13 @@ pub mod tests {
|
||||
use futures::StreamExt;
|
||||
use gpui::{AppContext as _, Context, SemanticVersion, TestAppContext, WindowHandle};
|
||||
use itertools::Itertools as _;
|
||||
use language::{Capability, FakeLspAdapter, language_settings::AllLanguageSettingsContent};
|
||||
use language::{Capability, FakeLspAdapter};
|
||||
use language::{Language, LanguageConfig, LanguageMatcher};
|
||||
use lsp::FakeLanguageServer;
|
||||
use parking_lot::Mutex;
|
||||
use project::{FakeFs, Project};
|
||||
use serde_json::json;
|
||||
use settings::SettingsStore;
|
||||
use settings::{AllLanguageSettingsContent, InlayHintSettingsContent, SettingsStore};
|
||||
use std::sync::atomic::{AtomicBool, AtomicU32, AtomicUsize, Ordering};
|
||||
use text::Point;
|
||||
use util::path;
|
||||
@@ -1318,15 +1320,17 @@ pub mod tests {
|
||||
async fn test_basic_cache_update_with_duplicate_hints(cx: &mut gpui::TestAppContext) {
|
||||
let allowed_hint_kinds = HashSet::from_iter([None, Some(InlayHintKind::Type)]);
|
||||
init_test(cx, |settings| {
|
||||
settings.defaults.inlay_hints = Some(InlayHintSettings {
|
||||
show_value_hints: true,
|
||||
enabled: true,
|
||||
edit_debounce_ms: 0,
|
||||
scroll_debounce_ms: 0,
|
||||
show_type_hints: allowed_hint_kinds.contains(&Some(InlayHintKind::Type)),
|
||||
show_parameter_hints: allowed_hint_kinds.contains(&Some(InlayHintKind::Parameter)),
|
||||
show_other_hints: allowed_hint_kinds.contains(&None),
|
||||
show_background: false,
|
||||
settings.defaults.inlay_hints = Some(InlayHintSettingsContent {
|
||||
show_value_hints: Some(true),
|
||||
enabled: Some(true),
|
||||
edit_debounce_ms: Some(0),
|
||||
scroll_debounce_ms: Some(0),
|
||||
show_type_hints: Some(allowed_hint_kinds.contains(&Some(InlayHintKind::Type))),
|
||||
show_parameter_hints: Some(
|
||||
allowed_hint_kinds.contains(&Some(InlayHintKind::Parameter)),
|
||||
),
|
||||
show_other_hints: Some(allowed_hint_kinds.contains(&None)),
|
||||
show_background: Some(false),
|
||||
toggle_on_modifiers_press: None,
|
||||
})
|
||||
});
|
||||
@@ -1428,15 +1432,15 @@ pub mod tests {
|
||||
#[gpui::test]
|
||||
async fn test_cache_update_on_lsp_completion_tasks(cx: &mut gpui::TestAppContext) {
|
||||
init_test(cx, |settings| {
|
||||
settings.defaults.inlay_hints = Some(InlayHintSettings {
|
||||
show_value_hints: true,
|
||||
enabled: true,
|
||||
edit_debounce_ms: 0,
|
||||
scroll_debounce_ms: 0,
|
||||
show_type_hints: true,
|
||||
show_parameter_hints: true,
|
||||
show_other_hints: true,
|
||||
show_background: false,
|
||||
settings.defaults.inlay_hints = Some(InlayHintSettingsContent {
|
||||
show_value_hints: Some(true),
|
||||
enabled: Some(true),
|
||||
edit_debounce_ms: Some(0),
|
||||
scroll_debounce_ms: Some(0),
|
||||
show_type_hints: Some(true),
|
||||
show_parameter_hints: Some(true),
|
||||
show_other_hints: Some(true),
|
||||
show_background: Some(false),
|
||||
toggle_on_modifiers_press: None,
|
||||
})
|
||||
});
|
||||
@@ -1535,15 +1539,15 @@ pub mod tests {
|
||||
#[gpui::test]
|
||||
async fn test_no_hint_updates_for_unrelated_language_files(cx: &mut gpui::TestAppContext) {
|
||||
init_test(cx, |settings| {
|
||||
settings.defaults.inlay_hints = Some(InlayHintSettings {
|
||||
show_value_hints: true,
|
||||
enabled: true,
|
||||
edit_debounce_ms: 0,
|
||||
scroll_debounce_ms: 0,
|
||||
show_type_hints: true,
|
||||
show_parameter_hints: true,
|
||||
show_other_hints: true,
|
||||
show_background: false,
|
||||
settings.defaults.inlay_hints = Some(InlayHintSettingsContent {
|
||||
show_value_hints: Some(true),
|
||||
enabled: Some(true),
|
||||
edit_debounce_ms: Some(0),
|
||||
scroll_debounce_ms: Some(0),
|
||||
show_type_hints: Some(true),
|
||||
show_parameter_hints: Some(true),
|
||||
show_other_hints: Some(true),
|
||||
show_background: Some(false),
|
||||
toggle_on_modifiers_press: None,
|
||||
})
|
||||
});
|
||||
@@ -1765,15 +1769,17 @@ pub mod tests {
|
||||
async fn test_hint_setting_changes(cx: &mut gpui::TestAppContext) {
|
||||
let allowed_hint_kinds = HashSet::from_iter([None, Some(InlayHintKind::Type)]);
|
||||
init_test(cx, |settings| {
|
||||
settings.defaults.inlay_hints = Some(InlayHintSettings {
|
||||
show_value_hints: true,
|
||||
enabled: true,
|
||||
edit_debounce_ms: 0,
|
||||
scroll_debounce_ms: 0,
|
||||
show_type_hints: allowed_hint_kinds.contains(&Some(InlayHintKind::Type)),
|
||||
show_parameter_hints: allowed_hint_kinds.contains(&Some(InlayHintKind::Parameter)),
|
||||
show_other_hints: allowed_hint_kinds.contains(&None),
|
||||
show_background: false,
|
||||
settings.defaults.inlay_hints = Some(InlayHintSettingsContent {
|
||||
show_value_hints: Some(true),
|
||||
enabled: Some(true),
|
||||
edit_debounce_ms: Some(0),
|
||||
scroll_debounce_ms: Some(0),
|
||||
show_type_hints: Some(allowed_hint_kinds.contains(&Some(InlayHintKind::Type))),
|
||||
show_parameter_hints: Some(
|
||||
allowed_hint_kinds.contains(&Some(InlayHintKind::Parameter)),
|
||||
),
|
||||
show_other_hints: Some(allowed_hint_kinds.contains(&None)),
|
||||
show_background: Some(false),
|
||||
toggle_on_modifiers_press: None,
|
||||
})
|
||||
});
|
||||
@@ -1926,16 +1932,19 @@ pub mod tests {
|
||||
),
|
||||
] {
|
||||
update_test_language_settings(cx, |settings| {
|
||||
settings.defaults.inlay_hints = Some(InlayHintSettings {
|
||||
show_value_hints: true,
|
||||
enabled: true,
|
||||
edit_debounce_ms: 0,
|
||||
scroll_debounce_ms: 0,
|
||||
show_type_hints: new_allowed_hint_kinds.contains(&Some(InlayHintKind::Type)),
|
||||
show_parameter_hints: new_allowed_hint_kinds
|
||||
.contains(&Some(InlayHintKind::Parameter)),
|
||||
show_other_hints: new_allowed_hint_kinds.contains(&None),
|
||||
show_background: false,
|
||||
settings.defaults.inlay_hints = Some(InlayHintSettingsContent {
|
||||
show_value_hints: Some(true),
|
||||
enabled: Some(true),
|
||||
edit_debounce_ms: Some(0),
|
||||
scroll_debounce_ms: Some(0),
|
||||
show_type_hints: Some(
|
||||
new_allowed_hint_kinds.contains(&Some(InlayHintKind::Type)),
|
||||
),
|
||||
show_parameter_hints: Some(
|
||||
new_allowed_hint_kinds.contains(&Some(InlayHintKind::Parameter)),
|
||||
),
|
||||
show_other_hints: Some(new_allowed_hint_kinds.contains(&None)),
|
||||
show_background: Some(false),
|
||||
toggle_on_modifiers_press: None,
|
||||
})
|
||||
});
|
||||
@@ -1970,16 +1979,19 @@ pub mod tests {
|
||||
|
||||
let another_allowed_hint_kinds = HashSet::from_iter([Some(InlayHintKind::Type)]);
|
||||
update_test_language_settings(cx, |settings| {
|
||||
settings.defaults.inlay_hints = Some(InlayHintSettings {
|
||||
show_value_hints: true,
|
||||
enabled: false,
|
||||
edit_debounce_ms: 0,
|
||||
scroll_debounce_ms: 0,
|
||||
show_type_hints: another_allowed_hint_kinds.contains(&Some(InlayHintKind::Type)),
|
||||
show_parameter_hints: another_allowed_hint_kinds
|
||||
.contains(&Some(InlayHintKind::Parameter)),
|
||||
show_other_hints: another_allowed_hint_kinds.contains(&None),
|
||||
show_background: false,
|
||||
settings.defaults.inlay_hints = Some(InlayHintSettingsContent {
|
||||
show_value_hints: Some(true),
|
||||
enabled: Some(false),
|
||||
edit_debounce_ms: Some(0),
|
||||
scroll_debounce_ms: Some(0),
|
||||
show_type_hints: Some(
|
||||
another_allowed_hint_kinds.contains(&Some(InlayHintKind::Type)),
|
||||
),
|
||||
show_parameter_hints: Some(
|
||||
another_allowed_hint_kinds.contains(&Some(InlayHintKind::Parameter)),
|
||||
),
|
||||
show_other_hints: Some(another_allowed_hint_kinds.contains(&None)),
|
||||
show_background: Some(false),
|
||||
toggle_on_modifiers_press: None,
|
||||
})
|
||||
});
|
||||
@@ -2027,16 +2039,19 @@ pub mod tests {
|
||||
|
||||
let final_allowed_hint_kinds = HashSet::from_iter([Some(InlayHintKind::Parameter)]);
|
||||
update_test_language_settings(cx, |settings| {
|
||||
settings.defaults.inlay_hints = Some(InlayHintSettings {
|
||||
show_value_hints: true,
|
||||
enabled: true,
|
||||
edit_debounce_ms: 0,
|
||||
scroll_debounce_ms: 0,
|
||||
show_type_hints: final_allowed_hint_kinds.contains(&Some(InlayHintKind::Type)),
|
||||
show_parameter_hints: final_allowed_hint_kinds
|
||||
.contains(&Some(InlayHintKind::Parameter)),
|
||||
show_other_hints: final_allowed_hint_kinds.contains(&None),
|
||||
show_background: false,
|
||||
settings.defaults.inlay_hints = Some(InlayHintSettingsContent {
|
||||
show_value_hints: Some(true),
|
||||
enabled: Some(true),
|
||||
edit_debounce_ms: Some(0),
|
||||
scroll_debounce_ms: Some(0),
|
||||
show_type_hints: Some(
|
||||
final_allowed_hint_kinds.contains(&Some(InlayHintKind::Type)),
|
||||
),
|
||||
show_parameter_hints: Some(
|
||||
final_allowed_hint_kinds.contains(&Some(InlayHintKind::Parameter)),
|
||||
),
|
||||
show_other_hints: Some(final_allowed_hint_kinds.contains(&None)),
|
||||
show_background: Some(false),
|
||||
toggle_on_modifiers_press: None,
|
||||
})
|
||||
});
|
||||
@@ -2102,15 +2117,15 @@ pub mod tests {
|
||||
#[gpui::test]
|
||||
async fn test_hint_request_cancellation(cx: &mut gpui::TestAppContext) {
|
||||
init_test(cx, |settings| {
|
||||
settings.defaults.inlay_hints = Some(InlayHintSettings {
|
||||
show_value_hints: true,
|
||||
enabled: true,
|
||||
edit_debounce_ms: 0,
|
||||
scroll_debounce_ms: 0,
|
||||
show_type_hints: true,
|
||||
show_parameter_hints: true,
|
||||
show_other_hints: true,
|
||||
show_background: false,
|
||||
settings.defaults.inlay_hints = Some(InlayHintSettingsContent {
|
||||
show_value_hints: Some(true),
|
||||
enabled: Some(true),
|
||||
edit_debounce_ms: Some(0),
|
||||
scroll_debounce_ms: Some(0),
|
||||
show_type_hints: Some(true),
|
||||
show_parameter_hints: Some(true),
|
||||
show_other_hints: Some(true),
|
||||
show_background: Some(false),
|
||||
toggle_on_modifiers_press: None,
|
||||
})
|
||||
});
|
||||
@@ -2239,15 +2254,15 @@ pub mod tests {
|
||||
#[gpui::test(iterations = 10)]
|
||||
async fn test_large_buffer_inlay_requests_split(cx: &mut gpui::TestAppContext) {
|
||||
init_test(cx, |settings| {
|
||||
settings.defaults.inlay_hints = Some(InlayHintSettings {
|
||||
show_value_hints: true,
|
||||
enabled: true,
|
||||
edit_debounce_ms: 0,
|
||||
scroll_debounce_ms: 0,
|
||||
show_type_hints: true,
|
||||
show_parameter_hints: true,
|
||||
show_other_hints: true,
|
||||
show_background: false,
|
||||
settings.defaults.inlay_hints = Some(InlayHintSettingsContent {
|
||||
show_value_hints: Some(true),
|
||||
enabled: Some(true),
|
||||
edit_debounce_ms: Some(0),
|
||||
scroll_debounce_ms: Some(0),
|
||||
show_type_hints: Some(true),
|
||||
show_parameter_hints: Some(true),
|
||||
show_other_hints: Some(true),
|
||||
show_background: Some(false),
|
||||
toggle_on_modifiers_press: None,
|
||||
})
|
||||
});
|
||||
@@ -2540,15 +2555,15 @@ pub mod tests {
|
||||
#[gpui::test]
|
||||
async fn test_multiple_excerpts_large_multibuffer(cx: &mut gpui::TestAppContext) {
|
||||
init_test(cx, |settings| {
|
||||
settings.defaults.inlay_hints = Some(InlayHintSettings {
|
||||
show_value_hints: true,
|
||||
enabled: true,
|
||||
edit_debounce_ms: 0,
|
||||
scroll_debounce_ms: 0,
|
||||
show_type_hints: true,
|
||||
show_parameter_hints: true,
|
||||
show_other_hints: true,
|
||||
show_background: false,
|
||||
settings.defaults.inlay_hints = Some(InlayHintSettingsContent {
|
||||
show_value_hints: Some(true),
|
||||
enabled: Some(true),
|
||||
edit_debounce_ms: Some(0),
|
||||
scroll_debounce_ms: Some(0),
|
||||
show_type_hints: Some(true),
|
||||
show_parameter_hints: Some(true),
|
||||
show_other_hints: Some(true),
|
||||
show_background: Some(false),
|
||||
toggle_on_modifiers_press: None,
|
||||
})
|
||||
});
|
||||
@@ -2864,15 +2879,15 @@ pub mod tests {
|
||||
#[gpui::test]
|
||||
async fn test_excerpts_removed(cx: &mut gpui::TestAppContext) {
|
||||
init_test(cx, |settings| {
|
||||
settings.defaults.inlay_hints = Some(InlayHintSettings {
|
||||
show_value_hints: true,
|
||||
enabled: true,
|
||||
edit_debounce_ms: 0,
|
||||
scroll_debounce_ms: 0,
|
||||
show_type_hints: false,
|
||||
show_parameter_hints: false,
|
||||
show_other_hints: false,
|
||||
show_background: false,
|
||||
settings.defaults.inlay_hints = Some(InlayHintSettingsContent {
|
||||
show_value_hints: Some(true),
|
||||
enabled: Some(true),
|
||||
edit_debounce_ms: Some(0),
|
||||
scroll_debounce_ms: Some(0),
|
||||
show_type_hints: Some(false),
|
||||
show_parameter_hints: Some(false),
|
||||
show_other_hints: Some(false),
|
||||
show_background: Some(false),
|
||||
toggle_on_modifiers_press: None,
|
||||
})
|
||||
});
|
||||
@@ -3041,15 +3056,15 @@ pub mod tests {
|
||||
.unwrap();
|
||||
|
||||
update_test_language_settings(cx, |settings| {
|
||||
settings.defaults.inlay_hints = Some(InlayHintSettings {
|
||||
show_value_hints: true,
|
||||
enabled: true,
|
||||
edit_debounce_ms: 0,
|
||||
scroll_debounce_ms: 0,
|
||||
show_type_hints: true,
|
||||
show_parameter_hints: true,
|
||||
show_other_hints: true,
|
||||
show_background: false,
|
||||
settings.defaults.inlay_hints = Some(InlayHintSettingsContent {
|
||||
show_value_hints: Some(true),
|
||||
enabled: Some(true),
|
||||
edit_debounce_ms: Some(0),
|
||||
scroll_debounce_ms: Some(0),
|
||||
show_type_hints: Some(true),
|
||||
show_parameter_hints: Some(true),
|
||||
show_other_hints: Some(true),
|
||||
show_background: Some(false),
|
||||
toggle_on_modifiers_press: None,
|
||||
})
|
||||
});
|
||||
@@ -3074,15 +3089,15 @@ pub mod tests {
|
||||
#[gpui::test]
|
||||
async fn test_inside_char_boundary_range_hints(cx: &mut gpui::TestAppContext) {
|
||||
init_test(cx, |settings| {
|
||||
settings.defaults.inlay_hints = Some(InlayHintSettings {
|
||||
show_value_hints: true,
|
||||
enabled: true,
|
||||
edit_debounce_ms: 0,
|
||||
scroll_debounce_ms: 0,
|
||||
show_type_hints: true,
|
||||
show_parameter_hints: true,
|
||||
show_other_hints: true,
|
||||
show_background: false,
|
||||
settings.defaults.inlay_hints = Some(InlayHintSettingsContent {
|
||||
show_value_hints: Some(true),
|
||||
enabled: Some(true),
|
||||
edit_debounce_ms: Some(0),
|
||||
scroll_debounce_ms: Some(0),
|
||||
show_type_hints: Some(true),
|
||||
show_parameter_hints: Some(true),
|
||||
show_other_hints: Some(true),
|
||||
show_background: Some(false),
|
||||
toggle_on_modifiers_press: None,
|
||||
})
|
||||
});
|
||||
@@ -3167,15 +3182,15 @@ pub mod tests {
|
||||
#[gpui::test]
|
||||
async fn test_toggle_inlay_hints(cx: &mut gpui::TestAppContext) {
|
||||
init_test(cx, |settings| {
|
||||
settings.defaults.inlay_hints = Some(InlayHintSettings {
|
||||
show_value_hints: true,
|
||||
enabled: false,
|
||||
edit_debounce_ms: 0,
|
||||
scroll_debounce_ms: 0,
|
||||
show_type_hints: true,
|
||||
show_parameter_hints: true,
|
||||
show_other_hints: true,
|
||||
show_background: false,
|
||||
settings.defaults.inlay_hints = Some(InlayHintSettingsContent {
|
||||
show_value_hints: Some(true),
|
||||
enabled: Some(false),
|
||||
edit_debounce_ms: Some(0),
|
||||
scroll_debounce_ms: Some(0),
|
||||
show_type_hints: Some(true),
|
||||
show_parameter_hints: Some(true),
|
||||
show_other_hints: Some(true),
|
||||
show_background: Some(false),
|
||||
toggle_on_modifiers_press: None,
|
||||
})
|
||||
});
|
||||
@@ -3244,15 +3259,15 @@ pub mod tests {
|
||||
.unwrap();
|
||||
|
||||
update_test_language_settings(cx, |settings| {
|
||||
settings.defaults.inlay_hints = Some(InlayHintSettings {
|
||||
show_value_hints: true,
|
||||
enabled: true,
|
||||
edit_debounce_ms: 0,
|
||||
scroll_debounce_ms: 0,
|
||||
show_type_hints: true,
|
||||
show_parameter_hints: true,
|
||||
show_other_hints: true,
|
||||
show_background: false,
|
||||
settings.defaults.inlay_hints = Some(InlayHintSettingsContent {
|
||||
show_value_hints: Some(true),
|
||||
enabled: Some(true),
|
||||
edit_debounce_ms: Some(0),
|
||||
scroll_debounce_ms: Some(0),
|
||||
show_type_hints: Some(true),
|
||||
show_parameter_hints: Some(true),
|
||||
show_other_hints: Some(true),
|
||||
show_background: Some(false),
|
||||
toggle_on_modifiers_press: None,
|
||||
})
|
||||
});
|
||||
@@ -3305,15 +3320,15 @@ pub mod tests {
|
||||
#[gpui::test]
|
||||
async fn test_inlays_at_the_same_place(cx: &mut gpui::TestAppContext) {
|
||||
init_test(cx, |settings| {
|
||||
settings.defaults.inlay_hints = Some(InlayHintSettings {
|
||||
show_value_hints: true,
|
||||
enabled: true,
|
||||
edit_debounce_ms: 0,
|
||||
scroll_debounce_ms: 0,
|
||||
show_type_hints: true,
|
||||
show_parameter_hints: true,
|
||||
show_other_hints: true,
|
||||
show_background: false,
|
||||
settings.defaults.inlay_hints = Some(InlayHintSettingsContent {
|
||||
show_value_hints: Some(true),
|
||||
enabled: Some(true),
|
||||
edit_debounce_ms: Some(0),
|
||||
scroll_debounce_ms: Some(0),
|
||||
show_type_hints: Some(true),
|
||||
show_parameter_hints: Some(true),
|
||||
show_other_hints: Some(true),
|
||||
show_background: Some(false),
|
||||
toggle_on_modifiers_press: None,
|
||||
})
|
||||
});
|
||||
|
||||
@@ -328,7 +328,7 @@ pub(crate) fn refresh_enabled_in_any_buffer(
|
||||
snapshot.file(),
|
||||
cx,
|
||||
);
|
||||
if language_settings.jsx_tag_auto_close.enabled {
|
||||
if language_settings.jsx_tag_auto_close {
|
||||
found_enabled = true;
|
||||
}
|
||||
}
|
||||
@@ -406,7 +406,7 @@ pub(crate) fn handle_from(
|
||||
};
|
||||
|
||||
let language_settings = snapshot.settings_at(edit.new.end, cx);
|
||||
if !language_settings.jsx_tag_auto_close.enabled {
|
||||
if !language_settings.jsx_tag_auto_close {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -620,14 +620,17 @@ mod jsx_tag_autoclose_tests {
|
||||
|
||||
use super::*;
|
||||
use gpui::{AppContext as _, TestAppContext};
|
||||
use language::language_settings::JsxTagAutoCloseSettings;
|
||||
use languages::language;
|
||||
use multi_buffer::ExcerptRange;
|
||||
use text::Selection;
|
||||
|
||||
async fn test_setup(cx: &mut TestAppContext) -> EditorTestContext {
|
||||
init_test(cx, |settings| {
|
||||
settings.defaults.jsx_tag_auto_close = Some(JsxTagAutoCloseSettings { enabled: true });
|
||||
settings
|
||||
.defaults
|
||||
.jsx_tag_auto_close
|
||||
.get_or_insert_default()
|
||||
.enabled = Some(true);
|
||||
});
|
||||
|
||||
let mut cx = EditorTestContext::new(cx).await;
|
||||
@@ -789,7 +792,11 @@ mod jsx_tag_autoclose_tests {
|
||||
#[gpui::test]
|
||||
async fn test_multibuffer(cx: &mut TestAppContext) {
|
||||
init_test(cx, |settings| {
|
||||
settings.defaults.jsx_tag_auto_close = Some(JsxTagAutoCloseSettings { enabled: true });
|
||||
settings
|
||||
.defaults
|
||||
.jsx_tag_auto_close
|
||||
.get_or_insert_default()
|
||||
.enabled = Some(true);
|
||||
});
|
||||
|
||||
let buffer_a = cx.new(|cx| {
|
||||
|
||||
@@ -340,10 +340,7 @@ pub fn init(cx: &mut App) -> Arc<AgentAppState> {
|
||||
release_channel::init(app_version, cx);
|
||||
gpui_tokio::init(cx);
|
||||
|
||||
let mut settings_store = SettingsStore::new(cx);
|
||||
settings_store
|
||||
.set_default_settings(settings::default_settings().as_ref(), cx)
|
||||
.unwrap();
|
||||
let settings_store = SettingsStore::new(cx, &settings::default_settings());
|
||||
cx.set_global(settings_store);
|
||||
client::init_settings(cx);
|
||||
|
||||
|
||||
@@ -37,7 +37,6 @@ paths.workspace = true
|
||||
project.workspace = true
|
||||
remote.workspace = true
|
||||
release_channel.workspace = true
|
||||
schemars.workspace = true
|
||||
semantic_version.workspace = true
|
||||
serde.workspace = true
|
||||
serde_json.workspace = true
|
||||
|
||||
@@ -1,13 +1,9 @@
|
||||
use anyhow::Result;
|
||||
use collections::HashMap;
|
||||
use gpui::App;
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use settings::{Settings, SettingsKey, SettingsSources, SettingsUi};
|
||||
use settings::Settings;
|
||||
use std::sync::Arc;
|
||||
|
||||
#[derive(Deserialize, Serialize, Debug, Default, Clone, JsonSchema, SettingsUi, SettingsKey)]
|
||||
#[settings_key(None)]
|
||||
#[derive(Debug, Default, Clone)]
|
||||
pub struct ExtensionSettings {
|
||||
/// The extensions that should be automatically installed by Zed.
|
||||
///
|
||||
@@ -15,9 +11,7 @@ pub struct ExtensionSettings {
|
||||
/// available out-of-the-box.
|
||||
///
|
||||
/// Default: { "html": true }
|
||||
#[serde(default)]
|
||||
pub auto_install_extensions: HashMap<Arc<str>, bool>,
|
||||
#[serde(default)]
|
||||
pub auto_update_extensions: HashMap<Arc<str>, bool>,
|
||||
}
|
||||
|
||||
@@ -39,18 +33,24 @@ impl ExtensionSettings {
|
||||
}
|
||||
|
||||
impl Settings for ExtensionSettings {
|
||||
type FileContent = Self;
|
||||
|
||||
fn load(sources: SettingsSources<Self::FileContent>, _cx: &mut App) -> Result<Self> {
|
||||
SettingsSources::<Self::FileContent>::json_merge_with(
|
||||
[sources.default]
|
||||
.into_iter()
|
||||
.chain(sources.user)
|
||||
.chain(sources.server),
|
||||
)
|
||||
fn from_defaults(content: &settings::SettingsContent, _cx: &mut App) -> Self {
|
||||
Self {
|
||||
auto_install_extensions: content.extension.auto_install_extensions.clone(),
|
||||
auto_update_extensions: content.extension.auto_update_extensions.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
fn import_from_vscode(_vscode: &settings::VsCodeSettings, _current: &mut Self::FileContent) {
|
||||
fn refine(&mut self, content: &settings::SettingsContent, _cx: &mut App) {
|
||||
self.auto_install_extensions
|
||||
.extend(content.extension.auto_install_extensions.clone());
|
||||
self.auto_update_extensions
|
||||
.extend(content.extension.auto_update_extensions.clone());
|
||||
}
|
||||
|
||||
fn import_from_vscode(
|
||||
_vscode: &settings::VsCodeSettings,
|
||||
_current: &mut settings::SettingsContent,
|
||||
) {
|
||||
// settingsSync.ignoredExtensions controls autoupdate for vscode extensions, but we
|
||||
// don't have a mapping to zed-extensions. there's also extensions.autoCheckUpdates
|
||||
// and extensions.autoUpdate which are global switches, we don't support those yet
|
||||
|
||||
@@ -2,7 +2,7 @@ use std::str::FromStr;
|
||||
use std::sync::Arc;
|
||||
|
||||
use client::ExtensionMetadata;
|
||||
use extension_host::{ExtensionSettings, ExtensionStore};
|
||||
use extension_host::ExtensionStore;
|
||||
use fs::Fs;
|
||||
use fuzzy::{StringMatch, StringMatchCandidate, match_strings};
|
||||
use gpui::{App, DismissEvent, Entity, EventEmitter, Focusable, Task, WeakEntity, prelude::*};
|
||||
@@ -183,10 +183,13 @@ impl PickerDelegate for ExtensionVersionSelectorDelegate {
|
||||
let extension_id = extension_version.id.clone();
|
||||
let version = extension_version.manifest.version.clone();
|
||||
|
||||
update_settings_file::<ExtensionSettings>(self.fs.clone(), cx, {
|
||||
update_settings_file(self.fs.clone(), cx, {
|
||||
let extension_id = extension_id.clone();
|
||||
move |settings, _| {
|
||||
settings.auto_update_extensions.insert(extension_id, false);
|
||||
settings
|
||||
.extension
|
||||
.auto_update_extensions
|
||||
.insert(extension_id, false);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ use gpui::{
|
||||
use num_format::{Locale, ToFormattedString};
|
||||
use project::DirectoryLister;
|
||||
use release_channel::ReleaseChannel;
|
||||
use settings::Settings;
|
||||
use settings::{Settings, SettingsContent};
|
||||
use strum::IntoEnumIterator as _;
|
||||
use theme::ThemeSettings;
|
||||
use ui::{
|
||||
@@ -1269,17 +1269,17 @@ impl ExtensionsPage {
|
||||
Label::new(message)
|
||||
}
|
||||
|
||||
fn update_settings<T: Settings>(
|
||||
fn update_settings(
|
||||
&mut self,
|
||||
selection: &ToggleState,
|
||||
|
||||
cx: &mut Context<Self>,
|
||||
callback: impl 'static + Send + Fn(&mut T::FileContent, bool),
|
||||
callback: impl 'static + Send + Fn(&mut SettingsContent, bool),
|
||||
) {
|
||||
if let Some(workspace) = self.workspace.upgrade() {
|
||||
let fs = workspace.read(cx).app_state().fs.clone();
|
||||
let selection = *selection;
|
||||
settings::update_settings_file::<T>(fs, cx, move |settings, _| {
|
||||
settings::update_settings_file(fs, cx, move |settings, _| {
|
||||
let value = match selection {
|
||||
ToggleState::Unselected => false,
|
||||
ToggleState::Selected => true,
|
||||
@@ -1340,11 +1340,9 @@ impl ExtensionsPage {
|
||||
},
|
||||
cx.listener(move |this, selection, _, cx| {
|
||||
telemetry::event!("Vim Mode Toggled", source = "Feature Upsell");
|
||||
this.update_settings::<VimModeSetting>(
|
||||
selection,
|
||||
cx,
|
||||
|setting, value| setting.vim_mode = Some(value),
|
||||
);
|
||||
this.update_settings(selection, cx, |setting, value| {
|
||||
setting.vim_mode = Some(value)
|
||||
});
|
||||
}),
|
||||
)),
|
||||
Feature::LanguageBash => FeatureUpsell::new("Shell support is built-in to Zed!")
|
||||
|
||||
@@ -347,16 +347,16 @@ impl FileFinder {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn modal_max_width(width_setting: Option<FileFinderWidth>, window: &mut Window) -> Pixels {
|
||||
pub fn modal_max_width(width_setting: FileFinderWidth, window: &mut Window) -> Pixels {
|
||||
let window_width = window.viewport_size().width;
|
||||
let small_width = rems(34.).to_pixels(window.rem_size());
|
||||
|
||||
match width_setting {
|
||||
None | Some(FileFinderWidth::Small) => small_width,
|
||||
Some(FileFinderWidth::Full) => window_width,
|
||||
Some(FileFinderWidth::XLarge) => (window_width - Pixels(512.)).max(small_width),
|
||||
Some(FileFinderWidth::Large) => (window_width - Pixels(768.)).max(small_width),
|
||||
Some(FileFinderWidth::Medium) => (window_width - Pixels(1024.)).max(small_width),
|
||||
FileFinderWidth::Small => small_width,
|
||||
FileFinderWidth::Full => window_width,
|
||||
FileFinderWidth::XLarge => (window_width - Pixels(512.)).max(small_width),
|
||||
FileFinderWidth::Large => (window_width - Pixels(768.)).max(small_width),
|
||||
FileFinderWidth::Medium => (window_width - Pixels(1024.)).max(small_width),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,55 +1,41 @@
|
||||
use anyhow::Result;
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use settings::{Settings, SettingsKey, SettingsSources, SettingsUi};
|
||||
use settings::Settings;
|
||||
use util::MergeFrom;
|
||||
|
||||
#[derive(Deserialize, Debug, Clone, Copy, PartialEq)]
|
||||
pub struct FileFinderSettings {
|
||||
pub file_icons: bool,
|
||||
pub modal_max_width: Option<FileFinderWidth>,
|
||||
pub modal_max_width: FileFinderWidth,
|
||||
pub skip_focus_for_active_in_search: bool,
|
||||
pub include_ignored: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Default, Serialize, Deserialize, JsonSchema, Debug, SettingsUi, SettingsKey)]
|
||||
#[settings_key(key = "file_finder")]
|
||||
pub struct FileFinderSettingsContent {
|
||||
/// Whether to show file icons in the file finder.
|
||||
///
|
||||
/// Default: true
|
||||
pub file_icons: Option<bool>,
|
||||
/// Determines how much space the file finder can take up in relation to the available window width.
|
||||
///
|
||||
/// Default: small
|
||||
pub modal_max_width: Option<FileFinderWidth>,
|
||||
/// Determines whether the file finder should skip focus for the active file in search results.
|
||||
///
|
||||
/// Default: true
|
||||
pub skip_focus_for_active_in_search: Option<bool>,
|
||||
/// Determines whether to show the git status in the file finder
|
||||
///
|
||||
/// Default: true
|
||||
pub git_status: Option<bool>,
|
||||
/// Whether to use gitignored files when searching.
|
||||
/// Only the file Zed had indexed will be used, not necessary all the gitignored files.
|
||||
///
|
||||
/// Can accept 3 values:
|
||||
/// * `Some(true)`: Use all gitignored files
|
||||
/// * `Some(false)`: Use only the files Zed had indexed
|
||||
/// * `None`: Be smart and search for ignored when called from a gitignored worktree
|
||||
///
|
||||
/// Default: None
|
||||
pub include_ignored: Option<Option<bool>>,
|
||||
}
|
||||
|
||||
impl Settings for FileFinderSettings {
|
||||
type FileContent = FileFinderSettingsContent;
|
||||
fn from_defaults(content: &settings::SettingsContent, _cx: &mut ui::App) -> Self {
|
||||
let file_finder = content.file_finder.as_ref().unwrap();
|
||||
|
||||
fn load(sources: SettingsSources<Self::FileContent>, _: &mut gpui::App) -> Result<Self> {
|
||||
sources.json_merge()
|
||||
Self {
|
||||
file_icons: file_finder.file_icons.unwrap(),
|
||||
modal_max_width: file_finder.modal_max_width.unwrap().into(),
|
||||
skip_focus_for_active_in_search: file_finder.skip_focus_for_active_in_search.unwrap(),
|
||||
include_ignored: file_finder.include_ignored.flatten(),
|
||||
}
|
||||
}
|
||||
|
||||
fn import_from_vscode(_vscode: &settings::VsCodeSettings, _current: &mut Self::FileContent) {}
|
||||
fn refine(&mut self, content: &settings::SettingsContent, _cx: &mut ui::App) {
|
||||
let Some(file_finder) = content.file_finder.as_ref() else {
|
||||
return;
|
||||
};
|
||||
|
||||
self.file_icons.merge_from(&file_finder.file_icons);
|
||||
self.modal_max_width
|
||||
.merge_from(&file_finder.modal_max_width.map(Into::into));
|
||||
self.skip_focus_for_active_in_search
|
||||
.merge_from(&file_finder.skip_focus_for_active_in_search);
|
||||
self.include_ignored
|
||||
.merge_from(&file_finder.include_ignored);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy, Default, Serialize, Deserialize, JsonSchema)]
|
||||
@@ -62,3 +48,15 @@ pub enum FileFinderWidth {
|
||||
XLarge,
|
||||
Full,
|
||||
}
|
||||
|
||||
impl From<settings::FileFinderWidthContent> for FileFinderWidth {
|
||||
fn from(content: settings::FileFinderWidthContent) -> Self {
|
||||
match content {
|
||||
settings::FileFinderWidthContent::Small => FileFinderWidth::Small,
|
||||
settings::FileFinderWidthContent::Medium => FileFinderWidth::Medium,
|
||||
settings::FileFinderWidthContent::Large => FileFinderWidth::Large,
|
||||
settings::FileFinderWidthContent::XLarge => FileFinderWidth::XLarge,
|
||||
settings::FileFinderWidthContent::Full => FileFinderWidth::Full,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,6 @@ git.workspace = true
|
||||
gpui.workspace = true
|
||||
http_client.workspace = true
|
||||
regex.workspace = true
|
||||
schemars.workspace = true
|
||||
serde.workspace = true
|
||||
serde_json.workspace = true
|
||||
settings.workspace = true
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use anyhow::Result;
|
||||
use git::GitHostingProviderRegistry;
|
||||
use gpui::App;
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use settings::{Settings, SettingsKey, SettingsStore, SettingsUi};
|
||||
use settings::{GitHostingProviderConfig, GitHostingProviderKind, Settings, SettingsStore};
|
||||
use url::Url;
|
||||
use util::ResultExt as _;
|
||||
|
||||
@@ -55,43 +52,23 @@ fn update_git_hosting_providers_from_settings(cx: &mut App) {
|
||||
provider_registry.set_setting_providers(iter);
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum GitHostingProviderKind {
|
||||
Github,
|
||||
Gitlab,
|
||||
Bitbucket,
|
||||
}
|
||||
|
||||
/// A custom Git hosting provider.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
|
||||
pub struct GitHostingProviderConfig {
|
||||
/// The type of the provider.
|
||||
///
|
||||
/// Must be one of `github`, `gitlab`, or `bitbucket`.
|
||||
pub provider: GitHostingProviderKind,
|
||||
|
||||
/// The base URL for the provider (e.g., "https://code.corp.big.com").
|
||||
pub base_url: String,
|
||||
|
||||
/// The display name for the provider (e.g., "BigCorp GitHub").
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, SettingsUi, SettingsKey)]
|
||||
#[settings_key(None)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct GitHostingProviderSettings {
|
||||
/// The list of custom Git hosting providers.
|
||||
#[serde(default)]
|
||||
pub git_hosting_providers: Vec<GitHostingProviderConfig>,
|
||||
}
|
||||
|
||||
impl Settings for GitHostingProviderSettings {
|
||||
type FileContent = Self;
|
||||
|
||||
fn load(sources: settings::SettingsSources<Self::FileContent>, _: &mut App) -> Result<Self> {
|
||||
sources.json_merge()
|
||||
fn from_defaults(content: &settings::SettingsContent, _cx: &mut App) -> Self {
|
||||
Self {
|
||||
git_hosting_providers: content.project.git_hosting_providers.clone().unwrap(),
|
||||
}
|
||||
}
|
||||
|
||||
fn import_from_vscode(_vscode: &settings::VsCodeSettings, _current: &mut Self::FileContent) {}
|
||||
fn refine(&mut self, content: &settings::SettingsContent, _: &mut App) {
|
||||
if let Some(more) = &content.project.git_hosting_providers {
|
||||
self.git_hosting_providers.extend_from_slice(&more.clone());
|
||||
}
|
||||
}
|
||||
|
||||
fn import_from_vscode(_: &settings::VsCodeSettings, _: &mut settings::SettingsContent) {}
|
||||
}
|
||||
|
||||
@@ -139,7 +139,8 @@ impl BlameRenderer for GitBlameRenderer {
|
||||
let author = blame_entry.author.as_deref().unwrap_or_default();
|
||||
let summary_enabled = ProjectSettings::get_global(cx)
|
||||
.git
|
||||
.show_inline_commit_summary();
|
||||
.inline_blame
|
||||
.show_commit_summary;
|
||||
|
||||
let text = match blame_entry.summary.as_ref() {
|
||||
Some(summary) if summary_enabled => {
|
||||
|
||||
@@ -564,7 +564,6 @@ impl PickerDelegate for BranchListDelegate {
|
||||
let show_author_name = ProjectSettings::get_global(cx)
|
||||
.git
|
||||
.branch_picker
|
||||
.unwrap_or_default()
|
||||
.show_author_name;
|
||||
|
||||
subject.map_or("no commits found".into(), |subject| {
|
||||
|
||||
@@ -2,7 +2,6 @@ use crate::askpass_modal::AskPassModal;
|
||||
use crate::commit_modal::CommitModal;
|
||||
use crate::commit_tooltip::CommitTooltip;
|
||||
use crate::commit_view::CommitView;
|
||||
use crate::git_panel_settings::StatusStyle;
|
||||
use crate::project_diff::{self, Diff, ProjectDiff};
|
||||
use crate::remote_output::{self, RemoteAction, SuccessMessage};
|
||||
use crate::{branch_picker, picker_prompt, render_remote_button};
|
||||
@@ -51,7 +50,7 @@ use project::{
|
||||
git_store::{GitStoreEvent, Repository, RepositoryEvent, RepositoryId},
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use settings::{Settings, SettingsStore};
|
||||
use settings::{Settings, SettingsStore, StatusStyle};
|
||||
use std::future::Future;
|
||||
use std::ops::Range;
|
||||
use std::path::{Path, PathBuf};
|
||||
@@ -2439,8 +2438,9 @@ impl GitPanel {
|
||||
let workspace = workspace.read(cx);
|
||||
let fs = workspace.app_state().fs.clone();
|
||||
cx.update_global::<SettingsStore, _>(|store, _cx| {
|
||||
store.update_settings_file::<GitPanelSettings>(fs, move |settings, _cx| {
|
||||
settings.sort_by_path = Some(!current_setting);
|
||||
store.update_settings_file(fs, move |settings, _cx| {
|
||||
settings.git_panel.get_or_insert_default().sort_by_path =
|
||||
Some(!current_setting);
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -4356,11 +4356,9 @@ impl Panel for GitPanel {
|
||||
}
|
||||
|
||||
fn set_position(&mut self, position: DockPosition, _: &mut Window, cx: &mut Context<Self>) {
|
||||
settings::update_settings_file::<GitPanelSettings>(
|
||||
self.fs.clone(),
|
||||
cx,
|
||||
move |settings, _| settings.dock = Some(position),
|
||||
);
|
||||
settings::update_settings_file(self.fs.clone(), cx, move |settings, _| {
|
||||
settings.git_panel.get_or_insert_default().dock = Some(position.into())
|
||||
});
|
||||
}
|
||||
|
||||
fn size(&self, _: &Window, cx: &App) -> Pixels {
|
||||
|
||||
@@ -2,8 +2,12 @@ use editor::EditorSettings;
|
||||
use gpui::Pixels;
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use settings::{Settings, SettingsKey, SettingsSources, SettingsUi};
|
||||
use ui::scrollbars::{ScrollbarVisibility, ShowScrollbar};
|
||||
use settings::{Settings, SettingsContent, StatusStyle};
|
||||
use ui::{
|
||||
px,
|
||||
scrollbars::{ScrollbarVisibility, ShowScrollbar},
|
||||
};
|
||||
use util::MergeFrom;
|
||||
use workspace::dock::DockPosition;
|
||||
|
||||
#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
|
||||
@@ -19,67 +23,7 @@ pub struct ScrollbarSettings {
|
||||
pub show: Option<ShowScrollbar>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
// Style of the git status indicator in the panel.
|
||||
//
|
||||
// Default: icon
|
||||
pub enum StatusStyleContent {
|
||||
Icon,
|
||||
LabelColor,
|
||||
}
|
||||
|
||||
#[derive(Default, Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum StatusStyle {
|
||||
#[default]
|
||||
Icon,
|
||||
LabelColor,
|
||||
}
|
||||
|
||||
#[derive(Clone, Default, Serialize, Deserialize, JsonSchema, Debug, SettingsUi, SettingsKey)]
|
||||
#[settings_key(key = "git_panel")]
|
||||
pub struct GitPanelSettingsContent {
|
||||
/// Whether to show the panel button in the status bar.
|
||||
///
|
||||
/// Default: true
|
||||
pub button: Option<bool>,
|
||||
/// Where to dock the panel.
|
||||
///
|
||||
/// Default: left
|
||||
pub dock: Option<DockPosition>,
|
||||
/// Default width of the panel in pixels.
|
||||
///
|
||||
/// Default: 360
|
||||
pub default_width: Option<f32>,
|
||||
/// How entry statuses are displayed.
|
||||
///
|
||||
/// Default: icon
|
||||
pub status_style: Option<StatusStyle>,
|
||||
/// How and when the scrollbar should be displayed.
|
||||
///
|
||||
/// Default: inherits editor scrollbar settings
|
||||
pub scrollbar: Option<ScrollbarSettings>,
|
||||
|
||||
/// What the default branch name should be when
|
||||
/// `init.defaultBranch` is not set in git
|
||||
///
|
||||
/// Default: main
|
||||
pub fallback_branch_name: Option<String>,
|
||||
|
||||
/// Whether to sort entries in the panel by path
|
||||
/// or by status (the default).
|
||||
///
|
||||
/// Default: false
|
||||
pub sort_by_path: Option<bool>,
|
||||
|
||||
/// Whether to collapse untracked files in the diff panel.
|
||||
///
|
||||
/// Default: false
|
||||
pub collapse_untracked_diff: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug, Clone, PartialEq)]
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct GitPanelSettings {
|
||||
pub button: bool,
|
||||
pub dock: DockPosition,
|
||||
@@ -108,17 +52,50 @@ impl ScrollbarVisibility for GitPanelSettings {
|
||||
}
|
||||
|
||||
impl Settings for GitPanelSettings {
|
||||
type FileContent = GitPanelSettingsContent;
|
||||
|
||||
fn load(
|
||||
sources: SettingsSources<Self::FileContent>,
|
||||
_: &mut gpui::App,
|
||||
) -> anyhow::Result<Self> {
|
||||
sources.json_merge()
|
||||
fn from_defaults(content: &settings::SettingsContent, _cx: &mut ui::App) -> Self {
|
||||
let git_panel = content.git_panel.clone().unwrap();
|
||||
Self {
|
||||
button: git_panel.button.unwrap(),
|
||||
dock: git_panel.dock.unwrap().into(),
|
||||
default_width: px(git_panel.default_width.unwrap()),
|
||||
status_style: git_panel.status_style.unwrap(),
|
||||
scrollbar: ScrollbarSettings {
|
||||
show: git_panel.scrollbar.unwrap().show.map(Into::into),
|
||||
},
|
||||
fallback_branch_name: git_panel.fallback_branch_name.unwrap(),
|
||||
sort_by_path: git_panel.sort_by_path.unwrap(),
|
||||
collapse_untracked_diff: git_panel.collapse_untracked_diff.unwrap(),
|
||||
}
|
||||
}
|
||||
|
||||
fn import_from_vscode(vscode: &settings::VsCodeSettings, current: &mut Self::FileContent) {
|
||||
vscode.bool_setting("git.enabled", &mut current.button);
|
||||
vscode.string_setting("git.defaultBranchName", &mut current.fallback_branch_name);
|
||||
fn refine(&mut self, content: &settings::SettingsContent, _cx: &mut ui::App) {
|
||||
let Some(git_panel) = &content.git_panel else {
|
||||
return;
|
||||
};
|
||||
self.button.merge_from(&git_panel.button);
|
||||
self.dock.merge_from(&git_panel.dock.map(Into::into));
|
||||
self.default_width
|
||||
.merge_from(&git_panel.default_width.map(px));
|
||||
self.status_style.merge_from(&git_panel.status_style);
|
||||
self.fallback_branch_name
|
||||
.merge_from(&git_panel.fallback_branch_name);
|
||||
self.sort_by_path.merge_from(&git_panel.sort_by_path);
|
||||
self.collapse_untracked_diff
|
||||
.merge_from(&git_panel.collapse_untracked_diff);
|
||||
if let Some(show) = git_panel.scrollbar.as_ref().and_then(|s| s.show) {
|
||||
self.scrollbar.show = Some(show.into())
|
||||
}
|
||||
}
|
||||
|
||||
fn import_from_vscode(vscode: &settings::VsCodeSettings, current: &mut SettingsContent) {
|
||||
if let Some(git_enabled) = vscode.read_bool("git.enabled") {
|
||||
current.git_panel.get_or_insert_default().button = Some(git_enabled);
|
||||
}
|
||||
if let Some(default_branch) = vscode.read_string("git.defaultBranchName") {
|
||||
current
|
||||
.git_panel
|
||||
.get_or_insert_default()
|
||||
.fallback_branch_name = Some(default_branch.to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,12 +13,10 @@ path = "src/go_to_line.rs"
|
||||
doctest = false
|
||||
|
||||
[dependencies]
|
||||
anyhow.workspace = true
|
||||
editor.workspace = true
|
||||
gpui.workspace = true
|
||||
language.workspace = true
|
||||
menu.workspace = true
|
||||
schemars.workspace = true
|
||||
serde.workspace = true
|
||||
settings.workspace = true
|
||||
text.workspace = true
|
||||
|
||||
@@ -1,15 +1,13 @@
|
||||
use editor::{Editor, EditorSettings, MultiBufferSnapshot};
|
||||
use gpui::{App, Entity, FocusHandle, Focusable, Subscription, Task, WeakEntity};
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use settings::{Settings, SettingsKey, SettingsSources, SettingsUi};
|
||||
use settings::Settings;
|
||||
use std::{fmt::Write, num::NonZeroU32, time::Duration};
|
||||
use text::{Point, Selection};
|
||||
use ui::{
|
||||
Button, ButtonCommon, Clickable, Context, FluentBuilder, IntoElement, LabelSize, ParentElement,
|
||||
Render, Tooltip, Window, div,
|
||||
};
|
||||
use util::paths::FILE_ROW_COLUMN_DELIMITER;
|
||||
use util::{MergeFrom, paths::FILE_ROW_COLUMN_DELIMITER};
|
||||
use workspace::{StatusItemView, Workspace, item::ItemHandle};
|
||||
|
||||
#[derive(Copy, Clone, Debug, Default, PartialOrd, PartialEq)]
|
||||
@@ -293,41 +291,27 @@ impl StatusItemView for CursorPosition {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Default, PartialEq, Debug, JsonSchema, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub(crate) enum LineIndicatorFormat {
|
||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||
pub enum LineIndicatorFormat {
|
||||
Short,
|
||||
#[default]
|
||||
Long,
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Clone, Copy, Default, Debug, JsonSchema, Deserialize, Serialize, SettingsUi, SettingsKey,
|
||||
)]
|
||||
#[settings_key(None)]
|
||||
pub(crate) struct LineIndicatorFormatContent {
|
||||
line_indicator_format: Option<LineIndicatorFormat>,
|
||||
impl From<settings::LineIndicatorFormat> for LineIndicatorFormat {
|
||||
fn from(format: settings::LineIndicatorFormat) -> Self {
|
||||
match format {
|
||||
settings::LineIndicatorFormat::Short => LineIndicatorFormat::Short,
|
||||
settings::LineIndicatorFormat::Long => LineIndicatorFormat::Long,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Settings for LineIndicatorFormat {
|
||||
type FileContent = LineIndicatorFormatContent;
|
||||
|
||||
fn load(sources: SettingsSources<Self::FileContent>, _: &mut App) -> anyhow::Result<Self> {
|
||||
let format = [
|
||||
sources.release_channel,
|
||||
sources.profile,
|
||||
sources.user,
|
||||
sources.operating_system,
|
||||
Some(sources.default),
|
||||
]
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.filter_map(|val| val.line_indicator_format)
|
||||
.next()
|
||||
.ok_or_else(Self::missing_default)?;
|
||||
|
||||
Ok(format)
|
||||
fn from_defaults(content: &settings::SettingsContent, _cx: &mut App) -> Self {
|
||||
content.line_indicator_format.unwrap().into()
|
||||
}
|
||||
|
||||
fn import_from_vscode(_vscode: &settings::VsCodeSettings, _current: &mut Self::FileContent) {}
|
||||
fn refine(&mut self, content: &settings::SettingsContent, _cx: &mut App) {
|
||||
self.merge_from(&content.line_indicator_format.map(Into::into));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,5 +21,6 @@ http_client.workspace = true
|
||||
schemars = { workspace = true, optional = true }
|
||||
serde.workspace = true
|
||||
serde_json.workspace = true
|
||||
settings.workspace = true
|
||||
strum.workspace = true
|
||||
workspace-hack.workspace = true
|
||||
|
||||
@@ -4,6 +4,7 @@ use anyhow::{Result, anyhow, bail};
|
||||
use futures::{AsyncBufReadExt, AsyncReadExt, StreamExt, io::BufReader, stream::BoxStream};
|
||||
use http_client::{AsyncBody, HttpClient, Method, Request as HttpRequest};
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
pub use settings::ModelMode as GoogleModelMode;
|
||||
|
||||
pub const API_URL: &str = "https://generativelanguage.googleapis.com";
|
||||
|
||||
@@ -295,16 +296,6 @@ pub struct ThinkingConfig {
|
||||
pub thinking_budget: u32,
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
|
||||
#[derive(Copy, Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq)]
|
||||
pub enum GoogleModelMode {
|
||||
#[default]
|
||||
Default,
|
||||
Thinking {
|
||||
budget_tokens: Option<u32>,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct GenerationConfig {
|
||||
|
||||
@@ -24,7 +24,6 @@ gpui.workspace = true
|
||||
language.workspace = true
|
||||
log.workspace = true
|
||||
project.workspace = true
|
||||
schemars.workspace = true
|
||||
serde.workspace = true
|
||||
settings.workspace = true
|
||||
theme.workspace = true
|
||||
|
||||
@@ -1,40 +1,30 @@
|
||||
use gpui::App;
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use settings::{Settings, SettingsKey, SettingsSources, SettingsUi};
|
||||
pub use settings::ImageFileSizeUnit;
|
||||
use settings::Settings;
|
||||
use util::MergeFrom;
|
||||
|
||||
/// The settings for the image viewer.
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, Default, SettingsUi, SettingsKey)]
|
||||
#[settings_key(key = "image_viewer")]
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct ImageViewerSettings {
|
||||
/// The unit to use for displaying image file sizes.
|
||||
///
|
||||
/// Default: "binary"
|
||||
#[serde(default)]
|
||||
pub unit: ImageFileSizeUnit,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Serialize, Deserialize, JsonSchema, Default)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum ImageFileSizeUnit {
|
||||
/// Displays file size in binary units (e.g., KiB, MiB).
|
||||
#[default]
|
||||
Binary,
|
||||
/// Displays file size in decimal units (e.g., KB, MB).
|
||||
Decimal,
|
||||
}
|
||||
|
||||
impl Settings for ImageViewerSettings {
|
||||
type FileContent = Self;
|
||||
|
||||
fn load(sources: SettingsSources<Self::FileContent>, _: &mut App) -> anyhow::Result<Self> {
|
||||
SettingsSources::<Self::FileContent>::json_merge_with(
|
||||
[sources.default]
|
||||
.into_iter()
|
||||
.chain(sources.user)
|
||||
.chain(sources.server),
|
||||
)
|
||||
fn from_defaults(content: &settings::SettingsContent, _cx: &mut App) -> Self {
|
||||
Self {
|
||||
unit: content.image_viewer.clone().unwrap().unit.unwrap(),
|
||||
}
|
||||
}
|
||||
|
||||
fn import_from_vscode(_vscode: &settings::VsCodeSettings, _current: &mut Self::FileContent) {}
|
||||
fn refine(&mut self, content: &settings::SettingsContent, _cx: &mut App) {
|
||||
self.unit.merge_from(
|
||||
&content
|
||||
.image_viewer
|
||||
.as_ref()
|
||||
.and_then(|image_viewer| image_viewer.unit),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,12 +18,12 @@ chrono.workspace = true
|
||||
editor.workspace = true
|
||||
gpui.workspace = true
|
||||
log.workspace = true
|
||||
schemars.workspace = true
|
||||
serde.workspace = true
|
||||
settings.workspace = true
|
||||
shellexpand.workspace = true
|
||||
workspace.workspace = true
|
||||
workspace-hack.workspace = true
|
||||
util.workspace = true
|
||||
|
||||
[dev-dependencies]
|
||||
editor = { workspace = true, features = ["test-support"] }
|
||||
|
||||
@@ -1,16 +1,15 @@
|
||||
use anyhow::Result;
|
||||
use chrono::{Datelike, Local, NaiveTime, Timelike};
|
||||
use editor::scroll::Autoscroll;
|
||||
use editor::{Editor, SelectionEffects};
|
||||
use gpui::{App, AppContext as _, Context, Window, actions};
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use settings::{Settings, SettingsKey, SettingsSources, SettingsUi};
|
||||
pub use settings::HourFormat;
|
||||
use settings::Settings;
|
||||
use std::{
|
||||
fs::OpenOptions,
|
||||
path::{Path, PathBuf},
|
||||
sync::Arc,
|
||||
};
|
||||
use util::MergeFrom;
|
||||
use workspace::{AppState, OpenVisible, Workspace};
|
||||
|
||||
actions!(
|
||||
@@ -22,44 +21,35 @@ actions!(
|
||||
);
|
||||
|
||||
/// Settings specific to journaling
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, SettingsUi, SettingsKey)]
|
||||
#[settings_key(key = "journal")]
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct JournalSettings {
|
||||
/// The path of the directory where journal entries are stored.
|
||||
///
|
||||
/// Default: `~`
|
||||
pub path: Option<String>,
|
||||
pub path: String,
|
||||
/// What format to display the hours in.
|
||||
///
|
||||
/// Default: hour12
|
||||
pub hour_format: Option<HourFormat>,
|
||||
}
|
||||
|
||||
impl Default for JournalSettings {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
path: Some("~".into()),
|
||||
hour_format: Some(Default::default()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, Serialize, Deserialize, JsonSchema)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum HourFormat {
|
||||
#[default]
|
||||
Hour12,
|
||||
Hour24,
|
||||
pub hour_format: HourFormat,
|
||||
}
|
||||
|
||||
impl settings::Settings for JournalSettings {
|
||||
type FileContent = Self;
|
||||
fn from_defaults(content: &settings::SettingsContent, _cx: &mut App) -> Self {
|
||||
let journal = content.journal.clone().unwrap();
|
||||
|
||||
fn load(sources: SettingsSources<Self::FileContent>, _: &mut App) -> Result<Self> {
|
||||
sources.json_merge()
|
||||
Self {
|
||||
path: journal.path.unwrap(),
|
||||
hour_format: journal.hour_format.unwrap(),
|
||||
}
|
||||
}
|
||||
|
||||
fn import_from_vscode(_vscode: &settings::VsCodeSettings, _current: &mut Self::FileContent) {}
|
||||
fn refine(&mut self, content: &settings::SettingsContent, _cx: &mut App) {
|
||||
let Some(journal) = content.journal.as_ref() else {
|
||||
return;
|
||||
};
|
||||
self.path.merge_from(&journal.path);
|
||||
self.hour_format.merge_from(&journal.hour_format);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn init(_: Arc<AppState>, cx: &mut App) {
|
||||
@@ -77,7 +67,7 @@ pub fn init(_: Arc<AppState>, cx: &mut App) {
|
||||
|
||||
pub fn new_journal_entry(workspace: &Workspace, window: &mut Window, cx: &mut App) {
|
||||
let settings = JournalSettings::get_global(cx);
|
||||
let journal_dir = match journal_dir(settings.path.as_ref().unwrap()) {
|
||||
let journal_dir = match journal_dir(&settings.path) {
|
||||
Some(journal_dir) => journal_dir,
|
||||
None => {
|
||||
log::error!("Can't determine journal directory");
|
||||
@@ -199,13 +189,13 @@ fn journal_dir(path: &str) -> Option<PathBuf> {
|
||||
.map(|dir| Path::new(&dir.to_string()).to_path_buf().join("journal"))
|
||||
}
|
||||
|
||||
fn heading_entry(now: NaiveTime, hour_format: &Option<HourFormat>) -> String {
|
||||
fn heading_entry(now: NaiveTime, hour_format: &HourFormat) -> String {
|
||||
match hour_format {
|
||||
Some(HourFormat::Hour24) => {
|
||||
HourFormat::Hour24 => {
|
||||
let hour = now.hour();
|
||||
format!("# {}:{:02}", hour, now.minute())
|
||||
}
|
||||
_ => {
|
||||
HourFormat::Hour12 => {
|
||||
let (pm, hour) = now.hour12();
|
||||
let am_or_pm = if pm { "PM" } else { "AM" };
|
||||
format!("# {}:{:02} {}", hour, now.minute(), am_or_pm)
|
||||
@@ -221,7 +211,7 @@ mod tests {
|
||||
#[test]
|
||||
fn test_heading_entry_defaults_to_hour_12() {
|
||||
let naive_time = NaiveTime::from_hms_milli_opt(15, 0, 0, 0).unwrap();
|
||||
let actual_heading_entry = heading_entry(naive_time, &None);
|
||||
let actual_heading_entry = heading_entry(naive_time, &HourFormat::Hour12);
|
||||
let expected_heading_entry = "# 3:00 PM";
|
||||
|
||||
assert_eq!(actual_heading_entry, expected_heading_entry);
|
||||
@@ -230,7 +220,7 @@ mod tests {
|
||||
#[test]
|
||||
fn test_heading_entry_is_hour_12() {
|
||||
let naive_time = NaiveTime::from_hms_milli_opt(15, 0, 0, 0).unwrap();
|
||||
let actual_heading_entry = heading_entry(naive_time, &Some(HourFormat::Hour12));
|
||||
let actual_heading_entry = heading_entry(naive_time, &HourFormat::Hour12);
|
||||
let expected_heading_entry = "# 3:00 PM";
|
||||
|
||||
assert_eq!(actual_heading_entry, expected_heading_entry);
|
||||
@@ -239,7 +229,7 @@ mod tests {
|
||||
#[test]
|
||||
fn test_heading_entry_is_hour_24() {
|
||||
let naive_time = NaiveTime::from_hms_milli_opt(15, 0, 0, 0).unwrap();
|
||||
let actual_heading_entry = heading_entry(naive_time, &Some(HourFormat::Hour24));
|
||||
let actual_heading_entry = heading_entry(naive_time, &HourFormat::Hour24);
|
||||
let expected_heading_entry = "# 15:00";
|
||||
|
||||
assert_eq!(actual_heading_entry, expected_heading_entry);
|
||||
|
||||
@@ -30,10 +30,9 @@ use gpui::{
|
||||
|
||||
use lsp::{LanguageServerId, NumberOrString};
|
||||
use parking_lot::Mutex;
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::Value;
|
||||
use settings::{SettingsUi, WorktreeId};
|
||||
use settings::WorktreeId;
|
||||
use smallvec::SmallVec;
|
||||
use smol::future::yield_now;
|
||||
use std::{
|
||||
@@ -174,10 +173,7 @@ pub enum IndentKind {
|
||||
}
|
||||
|
||||
/// The shape of a selection cursor.
|
||||
#[derive(
|
||||
Copy, Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq, JsonSchema, SettingsUi,
|
||||
)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
|
||||
pub enum CursorShape {
|
||||
/// A vertical bar
|
||||
#[default]
|
||||
@@ -190,6 +186,17 @@ pub enum CursorShape {
|
||||
Hollow,
|
||||
}
|
||||
|
||||
impl From<settings::CursorShape> for CursorShape {
|
||||
fn from(shape: settings::CursorShape) -> Self {
|
||||
match shape {
|
||||
settings::CursorShape::Bar => CursorShape::Bar,
|
||||
settings::CursorShape::Block => CursorShape::Block,
|
||||
settings::CursorShape::Underline => CursorShape::Underline,
|
||||
settings::CursorShape::Hollow => CursorShape::Hollow,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
struct SelectionSet {
|
||||
line_mode: bool,
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
use super::*;
|
||||
use crate::Buffer;
|
||||
use crate::language_settings::{
|
||||
AllLanguageSettings, AllLanguageSettingsContent, LanguageSettingsContent,
|
||||
};
|
||||
use clock::ReplicaId;
|
||||
use collections::BTreeMap;
|
||||
use futures::FutureExt as _;
|
||||
@@ -13,6 +10,7 @@ use proto::deserialize_operation;
|
||||
use rand::prelude::*;
|
||||
use regex::RegexBuilder;
|
||||
use settings::SettingsStore;
|
||||
use settings::{AllLanguageSettingsContent, LanguageSettingsContent};
|
||||
use std::collections::BTreeSet;
|
||||
use std::{
|
||||
env,
|
||||
@@ -3849,7 +3847,7 @@ fn init_settings(cx: &mut App, f: fn(&mut AllLanguageSettingsContent)) {
|
||||
cx.set_global(settings_store);
|
||||
crate::init(cx);
|
||||
cx.update_global::<SettingsStore, _>(|settings, cx| {
|
||||
settings.update_user_settings::<AllLanguageSettings>(cx, f);
|
||||
settings.update_user_settings(cx, |content| f(&mut content.project.all_languages));
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -22,8 +22,8 @@ mod toolchain;
|
||||
#[cfg(test)]
|
||||
pub mod buffer_tests;
|
||||
|
||||
pub use crate::language_settings::EditPredictionsMode;
|
||||
use crate::language_settings::SoftWrap;
|
||||
pub use crate::language_settings::{EditPredictionsMode, IndentGuideSettings};
|
||||
use anyhow::{Context as _, Result};
|
||||
use async_trait::async_trait;
|
||||
use collections::{HashMap, HashSet, IndexSet};
|
||||
|
||||
@@ -1,14 +1,11 @@
|
||||
use crate::{
|
||||
CachedLspAdapter, File, Language, LanguageConfig, LanguageId, LanguageMatcher,
|
||||
LanguageServerName, LspAdapter, ManifestName, PLAIN_TEXT, ToolchainLister,
|
||||
language_settings::{
|
||||
AllLanguageSettingsContent, LanguageSettingsContent, all_language_settings,
|
||||
},
|
||||
task_context::ContextProvider,
|
||||
with_parser,
|
||||
language_settings::all_language_settings, task_context::ContextProvider, with_parser,
|
||||
};
|
||||
use anyhow::{Context as _, Result, anyhow};
|
||||
use collections::{FxHashMap, HashMap, HashSet, hash_map};
|
||||
use settings::{AllLanguageSettingsContent, LanguageSettingsContent};
|
||||
|
||||
use futures::{
|
||||
Future,
|
||||
@@ -1175,7 +1172,7 @@ impl LanguageRegistryState {
|
||||
language.set_theme(theme.syntax());
|
||||
}
|
||||
self.language_settings.languages.0.insert(
|
||||
language.name(),
|
||||
language.name().0,
|
||||
LanguageSettingsContent {
|
||||
tab_size: language.config.tab_size,
|
||||
hard_tabs: language.config.hard_tabs,
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -35,6 +35,7 @@ proto.workspace = true
|
||||
schemars.workspace = true
|
||||
serde.workspace = true
|
||||
serde_json.workspace = true
|
||||
settings.workspace = true
|
||||
smol.workspace = true
|
||||
telemetry_events.workspace = true
|
||||
thiserror.workspace = true
|
||||
|
||||
@@ -21,6 +21,7 @@ use open_router::OpenRouterError;
|
||||
use parking_lot::Mutex;
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize, de::DeserializeOwned};
|
||||
pub use settings::LanguageModelCacheConfiguration;
|
||||
use std::ops::{Add, Sub};
|
||||
use std::str::FromStr;
|
||||
use std::sync::Arc;
|
||||
@@ -62,14 +63,6 @@ pub fn init_settings(cx: &mut App) {
|
||||
registry::init(cx);
|
||||
}
|
||||
|
||||
/// Configuration for caching language model messages.
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
|
||||
pub struct LanguageModelCacheConfiguration {
|
||||
pub max_cache_anchors: usize,
|
||||
pub should_speculate: bool,
|
||||
pub min_total_token: u64,
|
||||
}
|
||||
|
||||
/// A completion event from a language model.
|
||||
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
|
||||
pub enum LanguageModelCompletionEvent {
|
||||
|
||||
@@ -18,8 +18,6 @@ use language_model::{
|
||||
LanguageModelToolResultContent, MessageContent, RateLimiter, Role,
|
||||
};
|
||||
use language_model::{LanguageModelCompletionEvent, LanguageModelToolUse, StopReason};
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use settings::{Settings, SettingsStore};
|
||||
use std::pin::Pin;
|
||||
use std::str::FromStr;
|
||||
@@ -30,6 +28,8 @@ use ui::{Icon, IconName, List, Tooltip, prelude::*};
|
||||
use util::{ResultExt, truncate_and_trailoff};
|
||||
use zed_env_vars::{EnvVar, env_var};
|
||||
|
||||
pub use settings::AnthropicAvailableModel as AvailableModel;
|
||||
|
||||
const PROVIDER_ID: LanguageModelProviderId = language_model::ANTHROPIC_PROVIDER_ID;
|
||||
const PROVIDER_NAME: LanguageModelProviderName = language_model::ANTHROPIC_PROVIDER_NAME;
|
||||
|
||||
@@ -40,55 +40,6 @@ pub struct AnthropicSettings {
|
||||
pub available_models: Vec<AvailableModel>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
|
||||
pub struct AvailableModel {
|
||||
/// The model's name in the Anthropic API. e.g. claude-3-5-sonnet-latest, claude-3-opus-20240229, etc
|
||||
pub name: String,
|
||||
/// The model's name in Zed's UI, such as in the model selector dropdown menu in the assistant panel.
|
||||
pub display_name: Option<String>,
|
||||
/// The model's context window size.
|
||||
pub max_tokens: u64,
|
||||
/// A model `name` to substitute when calling tools, in case the primary model doesn't support tool calling.
|
||||
pub tool_override: Option<String>,
|
||||
/// Configuration of Anthropic's caching API.
|
||||
pub cache_configuration: Option<LanguageModelCacheConfiguration>,
|
||||
pub max_output_tokens: Option<u64>,
|
||||
pub default_temperature: Option<f32>,
|
||||
#[serde(default)]
|
||||
pub extra_beta_headers: Vec<String>,
|
||||
/// The model's mode (e.g. thinking)
|
||||
pub mode: Option<ModelMode>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize, JsonSchema)]
|
||||
#[serde(tag = "type", rename_all = "lowercase")]
|
||||
pub enum ModelMode {
|
||||
#[default]
|
||||
Default,
|
||||
Thinking {
|
||||
/// The maximum number of tokens to use for reasoning. Must be lower than the model's `max_output_tokens`.
|
||||
budget_tokens: Option<u32>,
|
||||
},
|
||||
}
|
||||
|
||||
impl From<ModelMode> for AnthropicModelMode {
|
||||
fn from(value: ModelMode) -> Self {
|
||||
match value {
|
||||
ModelMode::Default => AnthropicModelMode::Default,
|
||||
ModelMode::Thinking { budget_tokens } => AnthropicModelMode::Thinking { budget_tokens },
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<AnthropicModelMode> for ModelMode {
|
||||
fn from(value: AnthropicModelMode) -> Self {
|
||||
match value {
|
||||
AnthropicModelMode::Default => ModelMode::Default,
|
||||
AnthropicModelMode::Thinking { budget_tokens } => ModelMode::Thinking { budget_tokens },
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct AnthropicLanguageModelProvider {
|
||||
http_client: Arc<dyn HttpClient>,
|
||||
state: gpui::Entity<State>,
|
||||
@@ -237,7 +188,7 @@ impl LanguageModelProvider for AnthropicLanguageModelProvider {
|
||||
max_output_tokens: model.max_output_tokens,
|
||||
default_temperature: model.default_temperature,
|
||||
extra_beta_headers: model.extra_beta_headers.clone(),
|
||||
mode: model.mode.clone().unwrap_or_default().into(),
|
||||
mode: model.mode.unwrap_or_default().into(),
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ use language_model::{
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::Value;
|
||||
use settings::{Settings, SettingsStore};
|
||||
use settings::{BedrockAvailableModel as AvailableModel, Settings, SettingsStore};
|
||||
use smol::lock::OnceCell;
|
||||
use strum::{EnumIter, IntoEnumIterator, IntoStaticStr};
|
||||
use theme::ThemeSettings;
|
||||
@@ -83,15 +83,14 @@ pub enum BedrockAuthMethod {
|
||||
Automatic,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
|
||||
pub struct AvailableModel {
|
||||
pub name: String,
|
||||
pub display_name: Option<String>,
|
||||
pub max_tokens: u64,
|
||||
pub cache_configuration: Option<LanguageModelCacheConfiguration>,
|
||||
pub max_output_tokens: Option<u64>,
|
||||
pub default_temperature: Option<f32>,
|
||||
pub mode: Option<ModelMode>,
|
||||
impl From<settings::BedrockAuthMethodContent> for BedrockAuthMethod {
|
||||
fn from(value: settings::BedrockAuthMethodContent) -> Self {
|
||||
match value {
|
||||
settings::BedrockAuthMethodContent::SingleSignOn => BedrockAuthMethod::SingleSignOn,
|
||||
settings::BedrockAuthMethodContent::Automatic => BedrockAuthMethod::Automatic,
|
||||
settings::BedrockAuthMethodContent::NamedProfile => BedrockAuthMethod::NamedProfile,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize, JsonSchema)]
|
||||
|
||||
@@ -32,6 +32,8 @@ use release_channel::AppVersion;
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize, de::DeserializeOwned};
|
||||
use settings::SettingsStore;
|
||||
pub use settings::ZedDotDevAvailableModel as AvailableModel;
|
||||
pub use settings::ZedDotDevAvailableProvider as AvailableProvider;
|
||||
use smol::io::{AsyncReadExt, BufReader};
|
||||
use std::pin::Pin;
|
||||
use std::str::FromStr as _;
|
||||
@@ -52,42 +54,6 @@ const PROVIDER_NAME: LanguageModelProviderName = language_model::ZED_CLOUD_PROVI
|
||||
pub struct ZedDotDevSettings {
|
||||
pub available_models: Vec<AvailableModel>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
pub enum AvailableProvider {
|
||||
Anthropic,
|
||||
OpenAi,
|
||||
Google,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
|
||||
pub struct AvailableModel {
|
||||
/// The provider of the language model.
|
||||
pub provider: AvailableProvider,
|
||||
/// The model's name in the provider's API. e.g. claude-3-5-sonnet-20240620
|
||||
pub name: String,
|
||||
/// The name displayed in the UI, such as in the assistant panel model dropdown menu.
|
||||
pub display_name: Option<String>,
|
||||
/// The size of the context window, indicating the maximum number of tokens the model can process.
|
||||
pub max_tokens: usize,
|
||||
/// The maximum number of output tokens allowed by the model.
|
||||
pub max_output_tokens: Option<u64>,
|
||||
/// The maximum number of completion tokens allowed by the model (o1-* only)
|
||||
pub max_completion_tokens: Option<u64>,
|
||||
/// Override this model with a different Anthropic model for tool calls.
|
||||
pub tool_override: Option<String>,
|
||||
/// Indicates whether this custom model supports caching.
|
||||
pub cache_configuration: Option<LanguageModelCacheConfiguration>,
|
||||
/// The default temperature to use for this model.
|
||||
pub default_temperature: Option<f32>,
|
||||
/// Any extra beta headers to provide when using the model.
|
||||
#[serde(default)]
|
||||
pub extra_beta_headers: Vec<String>,
|
||||
/// The model's mode (e.g. thinking)
|
||||
pub mode: Option<ModelMode>,
|
||||
}
|
||||
|
||||
#[derive(Default, Clone, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
|
||||
#[serde(tag = "type", rename_all = "lowercase")]
|
||||
pub enum ModelMode {
|
||||
|
||||
@@ -16,8 +16,7 @@ use language_model::{
|
||||
LanguageModelToolChoice, LanguageModelToolResultContent, LanguageModelToolUse, MessageContent,
|
||||
RateLimiter, Role, StopReason, TokenUsage,
|
||||
};
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
pub use settings::DeepseekAvailableModel as AvailableModel;
|
||||
use settings::{Settings, SettingsStore};
|
||||
use std::pin::Pin;
|
||||
use std::str::FromStr;
|
||||
@@ -47,15 +46,6 @@ pub struct DeepSeekSettings {
|
||||
pub api_url: String,
|
||||
pub available_models: Vec<AvailableModel>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
|
||||
pub struct AvailableModel {
|
||||
pub name: String,
|
||||
pub display_name: Option<String>,
|
||||
pub max_tokens: u64,
|
||||
pub max_output_tokens: Option<u64>,
|
||||
}
|
||||
|
||||
pub struct DeepSeekLanguageModelProvider {
|
||||
http_client: Arc<dyn HttpClient>,
|
||||
state: Entity<State>,
|
||||
|
||||
@@ -24,6 +24,7 @@ use language_model::{
|
||||
};
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
pub use settings::GoogleAvailableModel as AvailableModel;
|
||||
use settings::{Settings, SettingsStore};
|
||||
use std::pin::Pin;
|
||||
use std::sync::{
|
||||
@@ -60,32 +61,6 @@ pub enum ModelMode {
|
||||
},
|
||||
}
|
||||
|
||||
impl From<ModelMode> for GoogleModelMode {
|
||||
fn from(value: ModelMode) -> Self {
|
||||
match value {
|
||||
ModelMode::Default => GoogleModelMode::Default,
|
||||
ModelMode::Thinking { budget_tokens } => GoogleModelMode::Thinking { budget_tokens },
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<GoogleModelMode> for ModelMode {
|
||||
fn from(value: GoogleModelMode) -> Self {
|
||||
match value {
|
||||
GoogleModelMode::Default => ModelMode::Default,
|
||||
GoogleModelMode::Thinking { budget_tokens } => ModelMode::Thinking { budget_tokens },
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
|
||||
pub struct AvailableModel {
|
||||
name: String,
|
||||
display_name: Option<String>,
|
||||
max_tokens: u64,
|
||||
mode: Option<ModelMode>,
|
||||
}
|
||||
|
||||
pub struct GoogleLanguageModelProvider {
|
||||
http_client: Arc<dyn HttpClient>,
|
||||
state: gpui::Entity<State>,
|
||||
@@ -234,7 +209,7 @@ impl LanguageModelProvider for GoogleLanguageModelProvider {
|
||||
name: model.name.clone(),
|
||||
display_name: model.display_name.clone(),
|
||||
max_tokens: model.max_tokens,
|
||||
mode: model.mode.unwrap_or_default().into(),
|
||||
mode: model.mode.unwrap_or_default(),
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@@ -15,8 +15,7 @@ use language_model::{
|
||||
LanguageModelRequest, RateLimiter, Role,
|
||||
};
|
||||
use lmstudio::{ModelType, get_models};
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
pub use settings::LmStudioAvailableModel as AvailableModel;
|
||||
use settings::{Settings, SettingsStore};
|
||||
use std::pin::Pin;
|
||||
use std::str::FromStr;
|
||||
@@ -40,15 +39,6 @@ pub struct LmStudioSettings {
|
||||
pub available_models: Vec<AvailableModel>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
|
||||
pub struct AvailableModel {
|
||||
pub name: String,
|
||||
pub display_name: Option<String>,
|
||||
pub max_tokens: u64,
|
||||
pub supports_tool_calls: bool,
|
||||
pub supports_images: bool,
|
||||
}
|
||||
|
||||
pub struct LmStudioLanguageModelProvider {
|
||||
http_client: Arc<dyn HttpClient>,
|
||||
state: gpui::Entity<State>,
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user