mirror of
https://github.com/zed-industries/zed.git
synced 2026-06-01 03:14:56 +07:00
Split settings content into its own crate (#46845)
Closes #ISSUE Moves the settings content definitions into their own crate, so that they are compiled+cached separately from settings, primarily to avoid recompiles due to changes in gpui. In that vain many gpui types such as font weight/features, and `SharedString` were replaced in the content crate, either with `*Content` types for font/modifier things, or `String`/`Arc<str>` for `SharedString`. To make the conversions easy a new trait method in the settings crate named `IntoGpui::into_gpui` allows for `into()` like conversions to the gpui types in `from_settings` impls. Release Notes: - N/A --------- Co-authored-by: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com>
This commit is contained in:
parent
6fcc5e9461
commit
a2728e39a8
49 changed files with 622 additions and 328 deletions
22
Cargo.lock
generated
22
Cargo.lock
generated
|
|
@ -14899,7 +14899,6 @@ version = "0.1.0"
|
|||
dependencies = [
|
||||
"anyhow",
|
||||
"collections",
|
||||
"derive_more 0.99.20",
|
||||
"ec4rs",
|
||||
"fs",
|
||||
"futures 0.3.31",
|
||||
|
|
@ -14916,16 +14915,33 @@ dependencies = [
|
|||
"serde",
|
||||
"serde_json",
|
||||
"serde_json_lenient",
|
||||
"serde_repr",
|
||||
"settings_content",
|
||||
"settings_json",
|
||||
"settings_macros",
|
||||
"smallvec",
|
||||
"strum 0.27.2",
|
||||
"unindent",
|
||||
"util",
|
||||
"zlog",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "settings_content"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"collections",
|
||||
"derive_more 0.99.20",
|
||||
"log",
|
||||
"schemars",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_json_lenient",
|
||||
"settings_json",
|
||||
"settings_macros",
|
||||
"strum 0.27.2",
|
||||
"util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "settings_json"
|
||||
version = "0.1.0"
|
||||
|
|
|
|||
|
|
@ -153,6 +153,7 @@ members = [
|
|||
"crates/search",
|
||||
"crates/session",
|
||||
"crates/settings",
|
||||
"crates/settings_content",
|
||||
"crates/settings_json",
|
||||
"crates/settings_macros",
|
||||
"crates/settings_profile_selector",
|
||||
|
|
@ -387,6 +388,7 @@ scheduler = { path = "crates/scheduler" }
|
|||
search = { path = "crates/search" }
|
||||
session = { path = "crates/session" }
|
||||
settings = { path = "crates/settings" }
|
||||
settings_content = { path = "crates/settings_content" }
|
||||
settings_json = { path = "crates/settings_json" }
|
||||
settings_macros = { path = "crates/settings_macros" }
|
||||
settings_ui = { path = "crates/settings_ui" }
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ impl AgentServer for CustomAgentServer {
|
|||
settings
|
||||
.get::<AllAgentServersSettings>(None)
|
||||
.custom
|
||||
.get(&self.name())
|
||||
.get(self.name().as_ref())
|
||||
.cloned()
|
||||
});
|
||||
|
||||
|
|
@ -53,7 +53,7 @@ impl AgentServer for CustomAgentServer {
|
|||
settings
|
||||
.get::<AllAgentServersSettings>(None)
|
||||
.custom
|
||||
.get(&self.name())
|
||||
.get(self.name().as_ref())
|
||||
.cloned()
|
||||
});
|
||||
|
||||
|
|
@ -87,7 +87,7 @@ impl AgentServer for CustomAgentServer {
|
|||
.agent_servers
|
||||
.get_or_insert_default()
|
||||
.custom
|
||||
.entry(name.clone())
|
||||
.entry(name.to_string())
|
||||
.or_insert_with(|| settings::CustomAgentServerSettings::Extension {
|
||||
default_model: None,
|
||||
default_mode: None,
|
||||
|
|
@ -131,7 +131,7 @@ impl AgentServer for CustomAgentServer {
|
|||
.agent_servers
|
||||
.get_or_insert_default()
|
||||
.custom
|
||||
.entry(name.clone())
|
||||
.entry(name.to_string())
|
||||
.or_insert_with(|| settings::CustomAgentServerSettings::Extension {
|
||||
default_model: None,
|
||||
default_mode: None,
|
||||
|
|
@ -154,7 +154,7 @@ impl AgentServer for CustomAgentServer {
|
|||
settings
|
||||
.get::<AllAgentServersSettings>(None)
|
||||
.custom
|
||||
.get(&self.name())
|
||||
.get(self.name().as_ref())
|
||||
.cloned()
|
||||
});
|
||||
|
||||
|
|
@ -170,7 +170,7 @@ impl AgentServer for CustomAgentServer {
|
|||
.agent_servers
|
||||
.get_or_insert_default()
|
||||
.custom
|
||||
.entry(name.clone())
|
||||
.entry(name.to_string())
|
||||
.or_insert_with(|| settings::CustomAgentServerSettings::Extension {
|
||||
default_model: None,
|
||||
default_mode: None,
|
||||
|
|
@ -193,7 +193,7 @@ impl AgentServer for CustomAgentServer {
|
|||
settings
|
||||
.get::<AllAgentServersSettings>(None)
|
||||
.custom
|
||||
.get(&self.name())
|
||||
.get(self.name().as_ref())
|
||||
.cloned()
|
||||
});
|
||||
|
||||
|
|
@ -221,7 +221,7 @@ impl AgentServer for CustomAgentServer {
|
|||
.agent_servers
|
||||
.get_or_insert_default()
|
||||
.custom
|
||||
.entry(name.clone())
|
||||
.entry(name.to_string())
|
||||
.or_insert_with(|| settings::CustomAgentServerSettings::Extension {
|
||||
default_model: None,
|
||||
default_mode: None,
|
||||
|
|
@ -255,7 +255,7 @@ impl AgentServer for CustomAgentServer {
|
|||
settings
|
||||
.get::<AllAgentServersSettings>(None)
|
||||
.custom
|
||||
.get(&self.name())
|
||||
.get(self.name().as_ref())
|
||||
.cloned()
|
||||
});
|
||||
|
||||
|
|
@ -279,7 +279,7 @@ impl AgentServer for CustomAgentServer {
|
|||
.agent_servers
|
||||
.get_or_insert_default()
|
||||
.custom
|
||||
.entry(name.clone())
|
||||
.entry(name.to_string())
|
||||
.or_insert_with(|| settings::CustomAgentServerSettings::Extension {
|
||||
default_model: None,
|
||||
default_mode: None,
|
||||
|
|
@ -322,7 +322,7 @@ impl AgentServer for CustomAgentServer {
|
|||
settings
|
||||
.get::<AllAgentServersSettings>(None)
|
||||
.custom
|
||||
.get(&self.name())
|
||||
.get(self.name().as_ref())
|
||||
.map(|s| match s {
|
||||
project::agent_server_store::CustomAgentServerSettings::Custom {
|
||||
default_config_options,
|
||||
|
|
|
|||
|
|
@ -1338,22 +1338,24 @@ async fn open_new_agent_servers_entry_in_settings_editor(
|
|||
|
||||
let mut unique_server_name = None;
|
||||
let edits = settings.edits_for_update(&text, |settings| {
|
||||
let server_name: Option<SharedString> = (0..u8::MAX)
|
||||
let server_name: Option<String> = (0..u8::MAX)
|
||||
.map(|i| {
|
||||
if i == 0 {
|
||||
"your_agent".into()
|
||||
"your_agent".to_string()
|
||||
} else {
|
||||
format!("your_agent_{}", i).into()
|
||||
format!("your_agent_{}", i)
|
||||
}
|
||||
})
|
||||
.find(|name| {
|
||||
!settings
|
||||
.agent_servers
|
||||
.as_ref()
|
||||
.is_some_and(|agent_servers| agent_servers.custom.contains_key(name))
|
||||
.is_some_and(|agent_servers| {
|
||||
agent_servers.custom.contains_key(name.as_str())
|
||||
})
|
||||
});
|
||||
if let Some(server_name) = server_name {
|
||||
unique_server_name = Some(server_name.clone());
|
||||
unique_server_name = Some(SharedString::from(server_name.clone()));
|
||||
settings
|
||||
.agent_servers
|
||||
.get_or_insert_default()
|
||||
|
|
|
|||
|
|
@ -1140,11 +1140,10 @@ impl AgentPanel {
|
|||
let _ = settings
|
||||
.theme
|
||||
.agent_ui_font_size
|
||||
.insert(theme::clamp_font_size(agent_ui_font_size).into());
|
||||
let _ = settings
|
||||
.theme
|
||||
.agent_buffer_font_size
|
||||
.insert(theme::clamp_font_size(agent_buffer_font_size).into());
|
||||
.insert(f32::from(theme::clamp_font_size(agent_ui_font_size)).into());
|
||||
let _ = settings.theme.agent_buffer_font_size.insert(
|
||||
f32::from(theme::clamp_font_size(agent_buffer_font_size)).into(),
|
||||
);
|
||||
});
|
||||
} else {
|
||||
theme::adjust_agent_ui_font_size(cx, |size| size + delta);
|
||||
|
|
|
|||
|
|
@ -4615,9 +4615,7 @@ async fn test_formatting_buffer(
|
|||
file.project.all_languages.defaults.formatter =
|
||||
Some(FormatterList::Single(Formatter::External {
|
||||
command: "awk".into(),
|
||||
arguments: Some(
|
||||
vec!["{sub(/two/,\"{buffer_path}\")}1".to_string()].into(),
|
||||
),
|
||||
arguments: Some(vec!["{sub(/two/,\"{buffer_path}\")}1".to_string()]),
|
||||
}));
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1344,7 +1344,7 @@ fn toggle_show_edit_predictions_for_language(
|
|||
.all_languages
|
||||
.languages
|
||||
.0
|
||||
.entry(language.name().0)
|
||||
.entry(language.name().0.to_string())
|
||||
.or_default()
|
||||
.show_edit_predictions = Some(!show_edit_predictions);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -186,7 +186,7 @@ mod tests {
|
|||
use settings::{AccentContent, SettingsStore};
|
||||
use text::{Bias, OffsetRangeExt, ToOffset};
|
||||
use theme::ThemeStyleContent;
|
||||
use ui::SharedString;
|
||||
|
||||
use util::{path, post_inc};
|
||||
|
||||
#[gpui::test]
|
||||
|
|
@ -1304,8 +1304,8 @@ mod foo «1{
|
|||
theme.to_string(),
|
||||
ThemeStyleContent {
|
||||
accents: vec![
|
||||
AccentContent(Some(SharedString::new("#ff0000"))),
|
||||
AccentContent(Some(SharedString::new("#0000ff"))),
|
||||
AccentContent(Some("#ff0000".to_string())),
|
||||
AccentContent(Some("#0000ff".to_string())),
|
||||
],
|
||||
..ThemeStyleContent::default()
|
||||
},
|
||||
|
|
|
|||
|
|
@ -23678,7 +23678,7 @@ impl Editor {
|
|||
.into_iter()
|
||||
.flatten(),
|
||||
)
|
||||
.flat_map(|accent| accent.0.clone())
|
||||
.flat_map(|accent| accent.0.clone().map(SharedString::from))
|
||||
.collect();
|
||||
|
||||
Some(AccentData {
|
||||
|
|
|
|||
|
|
@ -18484,7 +18484,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().0,
|
||||
language_name.clone().0.to_string(),
|
||||
LanguageSettingsContent {
|
||||
tab_size: NonZeroU32::new(8),
|
||||
..Default::default()
|
||||
|
|
|
|||
|
|
@ -1190,7 +1190,7 @@ impl LanguageRegistryState {
|
|||
language.set_theme(theme.syntax());
|
||||
}
|
||||
self.language_settings.languages.0.insert(
|
||||
language.name().0,
|
||||
language.name().0.to_string(),
|
||||
LanguageSettingsContent {
|
||||
tab_size: language.config.tab_size,
|
||||
hard_tabs: language.config.hard_tabs,
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ use ec4rs::{
|
|||
use globset::{Glob, GlobMatcher, GlobSet, GlobSetBuilder};
|
||||
use gpui::{App, Modifiers, SharedString};
|
||||
use itertools::{Either, Itertools};
|
||||
use settings::IntoGpui;
|
||||
|
||||
pub use settings::{
|
||||
CompletionSettingsContent, EditPredictionProvider, EditPredictionsMode, FormatOnSave,
|
||||
|
|
@ -584,7 +585,9 @@ impl settings::Settings for AllLanguageSettings {
|
|||
show_background: inlay_hints.show_background.unwrap(),
|
||||
edit_debounce_ms: inlay_hints.edit_debounce_ms.unwrap(),
|
||||
scroll_debounce_ms: inlay_hints.scroll_debounce_ms.unwrap(),
|
||||
toggle_on_modifiers_press: inlay_hints.toggle_on_modifiers_press,
|
||||
toggle_on_modifiers_press: inlay_hints
|
||||
.toggle_on_modifiers_press
|
||||
.map(|m| m.into_gpui()),
|
||||
},
|
||||
use_autoclose: settings.use_autoclose.unwrap(),
|
||||
use_auto_surround: settings.use_auto_surround.unwrap(),
|
||||
|
|
@ -623,7 +626,7 @@ impl settings::Settings for AllLanguageSettings {
|
|||
let mut language_settings = all_languages.defaults.clone();
|
||||
settings::merge_from::MergeFrom::merge_from(&mut language_settings, settings);
|
||||
languages.insert(
|
||||
LanguageName(language_name.clone()),
|
||||
LanguageName(language_name.clone().into()),
|
||||
load_from_content(language_settings),
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -650,7 +650,7 @@ impl AgentServerStore {
|
|||
.iter()
|
||||
.filter_map(|(name, settings)| match settings {
|
||||
CustomAgentServerSettings::Custom { command, .. } => Some((
|
||||
ExternalAgentServerName(name.clone()),
|
||||
ExternalAgentServerName(name.clone().into()),
|
||||
Box::new(LocalCustomAgent {
|
||||
command: command.clone(),
|
||||
project_environment: project_environment.clone(),
|
||||
|
|
@ -2014,7 +2014,7 @@ pub struct AllAgentServersSettings {
|
|||
pub gemini: Option<BuiltinAgentServerSettings>,
|
||||
pub claude: Option<BuiltinAgentServerSettings>,
|
||||
pub codex: Option<BuiltinAgentServerSettings>,
|
||||
pub custom: HashMap<SharedString, CustomAgentServerSettings>,
|
||||
pub custom: HashMap<String, CustomAgentServerSettings>,
|
||||
}
|
||||
#[derive(Default, Clone, JsonSchema, Debug, PartialEq)]
|
||||
pub struct BuiltinAgentServerSettings {
|
||||
|
|
|
|||
|
|
@ -1649,7 +1649,7 @@ impl LocalLspStore {
|
|||
|
||||
let diff = Self::format_via_external_command(
|
||||
buffer,
|
||||
command.as_ref(),
|
||||
&command,
|
||||
arguments.as_deref(),
|
||||
cx,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -312,8 +312,8 @@ pub(crate) async fn start_dev_container(
|
|||
.await?;
|
||||
|
||||
let connection = Connection::DevContainer(DevContainerConnection {
|
||||
name: project_name.into(),
|
||||
container_id: container_id.into(),
|
||||
name: project_name,
|
||||
container_id,
|
||||
});
|
||||
|
||||
Ok((connection, remote_workspace_folder))
|
||||
|
|
|
|||
|
|
@ -329,7 +329,7 @@ pub fn add_wsl_distro(
|
|||
use gpui::ReadGlobal;
|
||||
use settings::SettingsStore;
|
||||
|
||||
let distro_name = SharedString::from(&connection_options.distro_name);
|
||||
let distro_name = connection_options.distro_name.clone();
|
||||
let user = connection_options.user.clone();
|
||||
SettingsStore::global(cx).update_settings_file(fs, move |setting, _| {
|
||||
let connections = setting
|
||||
|
|
|
|||
|
|
@ -96,8 +96,8 @@ impl From<Connection> for RemoteConnectionOptions {
|
|||
Connection::Wsl(conn) => RemoteConnectionOptions::Wsl(conn.into()),
|
||||
Connection::DevContainer(conn) => {
|
||||
RemoteConnectionOptions::Docker(DockerConnectionOptions {
|
||||
name: conn.name.to_string(),
|
||||
container_id: conn.container_id.to_string(),
|
||||
name: conn.name,
|
||||
container_id: conn.container_id,
|
||||
upload_binary_over_docker_exec: false,
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -470,7 +470,7 @@ impl RemoteEntry {
|
|||
Self::Project { connection, .. } => Cow::Borrowed(connection),
|
||||
Self::SshConfig { host, .. } => Cow::Owned(
|
||||
SshConnection {
|
||||
host: host.clone(),
|
||||
host: host.to_string(),
|
||||
..SshConnection::default()
|
||||
}
|
||||
.into(),
|
||||
|
|
@ -1129,7 +1129,7 @@ impl RemoteServerProjects {
|
|||
Connection::Ssh(connection) => {
|
||||
if let Some(nickname) = connection.nickname.clone() {
|
||||
let aux_label = SharedString::from(format!("({})", connection.host));
|
||||
(nickname.into(), Some(aux_label), false)
|
||||
(nickname, Some(aux_label), false)
|
||||
} else {
|
||||
(connection.host.clone(), None, false)
|
||||
}
|
||||
|
|
@ -1535,7 +1535,7 @@ impl RemoteServerProjects {
|
|||
.ssh_connections
|
||||
.get_or_insert(Default::default())
|
||||
.push(SshConnection {
|
||||
host: SharedString::from(connection_options.host.to_string()),
|
||||
host: connection_options.host.to_string(),
|
||||
username: connection_options.username,
|
||||
port: connection_options.port,
|
||||
projects: BTreeSet::new(),
|
||||
|
|
@ -2340,7 +2340,7 @@ impl RemoteServerProjects {
|
|||
.track_focus(&self.focus_handle(cx))
|
||||
.child(
|
||||
SshConnectionHeader {
|
||||
connection_string,
|
||||
connection_string: connection_string.into(),
|
||||
paths: Default::default(),
|
||||
nickname,
|
||||
is_wsl: false,
|
||||
|
|
@ -2408,7 +2408,7 @@ impl RemoteServerProjects {
|
|||
..
|
||||
} = server
|
||||
{
|
||||
expected_ssh_hosts.remove(&connection.host);
|
||||
expected_ssh_hosts.remove(connection.host.as_str());
|
||||
}
|
||||
}
|
||||
should_rebuild = current_ssh_hosts != expected_ssh_hosts;
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ pub struct WslConnectionOptions {
|
|||
impl From<settings::WslConnection> for WslConnectionOptions {
|
||||
fn from(val: settings::WslConnection) -> Self {
|
||||
WslConnectionOptions {
|
||||
distro_name: val.distro_name.into(),
|
||||
distro_name: val.distro_name,
|
||||
user: val.user,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@ test-support = ["gpui/test-support", "fs/test-support"]
|
|||
[dependencies]
|
||||
anyhow.workspace = true
|
||||
collections.workspace = true
|
||||
derive_more.workspace = true
|
||||
ec4rs.workspace = true
|
||||
fs.workspace = true
|
||||
futures.workspace = true
|
||||
|
|
@ -33,11 +32,10 @@ schemars.workspace = true
|
|||
serde.workspace = true
|
||||
serde_json.workspace = true
|
||||
serde_json_lenient.workspace = true
|
||||
serde_repr.workspace = true
|
||||
settings_content.workspace = true
|
||||
settings_json.workspace = true
|
||||
settings_macros.workspace = true
|
||||
smallvec.workspace = true
|
||||
strum.workspace = true
|
||||
util.workspace = true
|
||||
zlog.workspace = true
|
||||
|
||||
|
|
|
|||
104
crates/settings/src/content_into_gpui.rs
Normal file
104
crates/settings/src/content_into_gpui.rs
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
use gpui::{
|
||||
FontFeatures, FontStyle, FontWeight, Modifiers, Pixels, SharedString,
|
||||
WindowBackgroundAppearance, px,
|
||||
};
|
||||
use settings_content::{
|
||||
FontFamilyName, FontFeaturesContent, FontSize, FontStyleContent, FontWeightContent,
|
||||
ModifiersContent, WindowBackgroundContent,
|
||||
};
|
||||
use std::sync::Arc;
|
||||
|
||||
/// A trait for converting settings content types into their GPUI equivalents.
|
||||
pub trait IntoGpui {
|
||||
type Output;
|
||||
fn into_gpui(self) -> Self::Output;
|
||||
}
|
||||
|
||||
impl IntoGpui for FontStyleContent {
|
||||
type Output = FontStyle;
|
||||
|
||||
fn into_gpui(self) -> Self::Output {
|
||||
match self {
|
||||
FontStyleContent::Normal => FontStyle::Normal,
|
||||
FontStyleContent::Italic => FontStyle::Italic,
|
||||
FontStyleContent::Oblique => FontStyle::Oblique,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoGpui for FontWeightContent {
|
||||
type Output = FontWeight;
|
||||
|
||||
fn into_gpui(self) -> Self::Output {
|
||||
FontWeight(self.0.clamp(100., 950.))
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoGpui for FontFeaturesContent {
|
||||
type Output = FontFeatures;
|
||||
|
||||
fn into_gpui(self) -> Self::Output {
|
||||
FontFeatures(Arc::new(self.0.into_iter().collect()))
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoGpui for WindowBackgroundContent {
|
||||
type Output = WindowBackgroundAppearance;
|
||||
|
||||
fn into_gpui(self) -> Self::Output {
|
||||
match self {
|
||||
WindowBackgroundContent::Opaque => WindowBackgroundAppearance::Opaque,
|
||||
WindowBackgroundContent::Transparent => WindowBackgroundAppearance::Transparent,
|
||||
WindowBackgroundContent::Blurred => WindowBackgroundAppearance::Blurred,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoGpui for ModifiersContent {
|
||||
type Output = Modifiers;
|
||||
|
||||
fn into_gpui(self) -> Self::Output {
|
||||
Modifiers {
|
||||
control: self.control,
|
||||
alt: self.alt,
|
||||
shift: self.shift,
|
||||
platform: self.platform,
|
||||
function: self.function,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoGpui for FontSize {
|
||||
type Output = Pixels;
|
||||
|
||||
fn into_gpui(self) -> Self::Output {
|
||||
px(self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoGpui for FontFamilyName {
|
||||
type Output = SharedString;
|
||||
|
||||
fn into_gpui(self) -> Self::Output {
|
||||
SharedString::from(self.0)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use gpui::FontWeight;
|
||||
use settings_content::FontWeightContent;
|
||||
|
||||
#[test]
|
||||
fn test_font_weight_content_constants_match_gpui() {
|
||||
assert_eq!(FontWeightContent::THIN.0, FontWeight::THIN.0);
|
||||
assert_eq!(FontWeightContent::EXTRA_LIGHT.0, FontWeight::EXTRA_LIGHT.0);
|
||||
assert_eq!(FontWeightContent::LIGHT.0, FontWeight::LIGHT.0);
|
||||
assert_eq!(FontWeightContent::NORMAL.0, FontWeight::NORMAL.0);
|
||||
assert_eq!(FontWeightContent::MEDIUM.0, FontWeight::MEDIUM.0);
|
||||
assert_eq!(FontWeightContent::SEMIBOLD.0, FontWeight::SEMIBOLD.0);
|
||||
assert_eq!(FontWeightContent::BOLD.0, FontWeight::BOLD.0);
|
||||
assert_eq!(FontWeightContent::EXTRA_BOLD.0, FontWeight::EXTRA_BOLD.0);
|
||||
assert_eq!(FontWeightContent::BLACK.0, FontWeight::BLACK.0);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,17 +1,21 @@
|
|||
mod base_keymap_setting;
|
||||
mod content_into_gpui;
|
||||
mod editable_setting_control;
|
||||
mod fallible_options;
|
||||
mod keymap_file;
|
||||
pub mod merge_from;
|
||||
mod serde_helper;
|
||||
mod settings_content;
|
||||
mod settings_file;
|
||||
mod settings_store;
|
||||
mod vscode_import;
|
||||
|
||||
pub use settings_content::*;
|
||||
pub use settings_macros::RegisterSetting;
|
||||
|
||||
pub mod settings_content {
|
||||
pub use ::settings_content::*;
|
||||
}
|
||||
|
||||
pub mod fallible_options {
|
||||
pub use ::settings_content::{FallibleOption, parse_json};
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub mod private {
|
||||
pub use crate::settings_store::{RegisteredSetting, SettingValue};
|
||||
|
|
@ -19,22 +23,25 @@ pub mod private {
|
|||
}
|
||||
|
||||
use gpui::{App, Global};
|
||||
use release_channel::ReleaseChannel;
|
||||
use rust_embed::RustEmbed;
|
||||
use std::env;
|
||||
use std::{borrow::Cow, fmt, str};
|
||||
use util::asset_str;
|
||||
|
||||
pub use ::settings_content::*;
|
||||
pub use base_keymap_setting::*;
|
||||
pub use content_into_gpui::IntoGpui;
|
||||
pub use editable_setting_control::*;
|
||||
pub use keymap_file::{
|
||||
KeyBindingValidator, KeyBindingValidatorRegistration, KeybindSource, KeybindUpdateOperation,
|
||||
KeybindUpdateTarget, KeymapFile, KeymapFileLoadResult,
|
||||
};
|
||||
pub use serde_helper::*;
|
||||
pub use settings_file::*;
|
||||
pub use settings_json::*;
|
||||
pub use settings_store::{
|
||||
InvalidSettingsError, LSP_SETTINGS_SCHEMA_URL_PREFIX, LocalSettingsKind, MigrationStatus,
|
||||
ParseStatus, Settings, SettingsFile, SettingsJsonSchemaParams, SettingsKey, SettingsLocation,
|
||||
Settings, SettingsFile, SettingsJsonSchemaParams, SettingsKey, SettingsLocation,
|
||||
SettingsParseResult, SettingsStore,
|
||||
};
|
||||
|
||||
|
|
@ -47,6 +54,39 @@ pub struct ActiveSettingsProfileName(pub String);
|
|||
|
||||
impl Global for ActiveSettingsProfileName {}
|
||||
|
||||
pub trait UserSettingsContentExt {
|
||||
fn for_profile(&self, cx: &App) -> Option<&SettingsContent>;
|
||||
fn for_release_channel(&self) -> Option<&SettingsContent>;
|
||||
fn for_os(&self) -> Option<&SettingsContent>;
|
||||
}
|
||||
|
||||
impl UserSettingsContentExt for UserSettingsContent {
|
||||
fn for_profile(&self, cx: &App) -> Option<&SettingsContent> {
|
||||
let Some(active_profile) = cx.try_global::<ActiveSettingsProfileName>() else {
|
||||
return None;
|
||||
};
|
||||
self.profiles.get(&active_profile.0)
|
||||
}
|
||||
|
||||
fn for_release_channel(&self) -> Option<&SettingsContent> {
|
||||
match *release_channel::RELEASE_CHANNEL {
|
||||
ReleaseChannel::Dev => self.dev.as_deref(),
|
||||
ReleaseChannel::Nightly => self.nightly.as_deref(),
|
||||
ReleaseChannel::Preview => self.preview.as_deref(),
|
||||
ReleaseChannel::Stable => self.stable.as_deref(),
|
||||
}
|
||||
}
|
||||
|
||||
fn for_os(&self) -> Option<&SettingsContent> {
|
||||
match env::consts::OS {
|
||||
"macos" => self.macos.as_deref(),
|
||||
"linux" => self.linux.as_deref(),
|
||||
"windows" => self.windows.as_deref(),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash, PartialOrd, Ord, serde::Serialize)]
|
||||
pub struct WorktreeId(usize);
|
||||
|
||||
|
|
|
|||
|
|
@ -30,17 +30,17 @@ use util::{
|
|||
|
||||
pub type EditorconfigProperties = ec4rs::Properties;
|
||||
|
||||
use crate::{
|
||||
ActiveSettingsProfileName, FontFamilyName, IconThemeName, LanguageSettingsContent,
|
||||
LanguageToSettingsMap, LspSettings, LspSettingsMap, ThemeName, VsCodeSettings, WorktreeId,
|
||||
fallible_options,
|
||||
merge_from::MergeFrom,
|
||||
settings_content::{
|
||||
ExtensionsSettingsContent, ProjectSettingsContent, SettingsContent, UserSettingsContent,
|
||||
},
|
||||
use crate::settings_content::{
|
||||
ExtensionsSettingsContent, FontFamilyName, IconThemeName, LanguageSettingsContent,
|
||||
LanguageToSettingsMap, LspSettings, LspSettingsMap, ProjectSettingsContent, SettingsContent,
|
||||
ThemeName, UserSettingsContent,
|
||||
};
|
||||
use crate::{
|
||||
ActiveSettingsProfileName, ParseStatus, UserSettingsContentExt, VsCodeSettings, WorktreeId,
|
||||
};
|
||||
use settings_content::{RootUserSettings, merge_from::MergeFrom};
|
||||
|
||||
use settings_json::{infer_json_indent_size, parse_json_with_comments, update_value_in_json_text};
|
||||
use settings_json::{infer_json_indent_size, update_value_in_json_text};
|
||||
|
||||
pub const LSP_SETTINGS_SCHEMA_URL_PREFIX: &str = "zed://schemas/settings/lsp/";
|
||||
|
||||
|
|
@ -266,7 +266,9 @@ impl SettingsStore {
|
|||
pub fn new(cx: &App, default_settings: &str) -> Self {
|
||||
let (setting_file_updates_tx, mut setting_file_updates_rx) = mpsc::unbounded();
|
||||
let default_settings: Rc<SettingsContent> =
|
||||
parse_json_with_comments(default_settings).unwrap();
|
||||
SettingsContent::parse_json_with_comments(default_settings)
|
||||
.unwrap()
|
||||
.into();
|
||||
let mut this = Self {
|
||||
setting_values: Default::default(),
|
||||
default_settings: default_settings.clone(),
|
||||
|
|
@ -665,14 +667,14 @@ impl SettingsStore {
|
|||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn parse_and_migrate_zed_settings<SettingsContentType: serde::de::DeserializeOwned>(
|
||||
fn parse_and_migrate_zed_settings<SettingsContentType: RootUserSettings>(
|
||||
&mut self,
|
||||
user_settings_content: &str,
|
||||
file: SettingsFile,
|
||||
) -> (Option<SettingsContentType>, SettingsParseResult) {
|
||||
let mut migration_status = MigrationStatus::NotNeeded;
|
||||
let (settings, parse_status) = if user_settings_content.is_empty() {
|
||||
fallible_options::parse_json("{}")
|
||||
SettingsContentType::parse_json("{}")
|
||||
} else {
|
||||
let migration_res = migrator::migrate_settings(user_settings_content);
|
||||
migration_status = match &migration_res {
|
||||
|
|
@ -687,7 +689,7 @@ impl SettingsStore {
|
|||
Ok(None) => user_settings_content,
|
||||
Err(_) => user_settings_content,
|
||||
};
|
||||
fallible_options::parse_json(content)
|
||||
SettingsContentType::parse_json(content)
|
||||
};
|
||||
|
||||
let result = SettingsParseResult {
|
||||
|
|
@ -735,8 +737,9 @@ impl SettingsStore {
|
|||
text: &str,
|
||||
update: impl FnOnce(&mut SettingsContent),
|
||||
) -> Vec<(Range<usize>, String)> {
|
||||
let old_content: UserSettingsContent =
|
||||
parse_json_with_comments(text).log_err().unwrap_or_default();
|
||||
let old_content = UserSettingsContent::parse_json_with_comments(text)
|
||||
.log_err()
|
||||
.unwrap_or_default();
|
||||
let mut new_content = old_content.clone();
|
||||
update(&mut new_content.content);
|
||||
|
||||
|
|
@ -766,7 +769,8 @@ impl SettingsStore {
|
|||
default_settings_content: &str,
|
||||
cx: &mut App,
|
||||
) -> Result<()> {
|
||||
self.default_settings = parse_json_with_comments(default_settings_content)?;
|
||||
self.default_settings =
|
||||
SettingsContent::parse_json_with_comments(default_settings_content)?.into();
|
||||
self.recompute_values(None, cx);
|
||||
Ok(())
|
||||
}
|
||||
|
|
@ -814,10 +818,10 @@ impl SettingsStore {
|
|||
server_settings_content: &str,
|
||||
cx: &mut App,
|
||||
) -> Result<()> {
|
||||
let settings: Option<SettingsContent> = if server_settings_content.is_empty() {
|
||||
let settings = if server_settings_content.is_empty() {
|
||||
None
|
||||
} else {
|
||||
parse_json_with_comments(server_settings_content)?
|
||||
Option::<SettingsContent>::parse_json_with_comments(server_settings_content)?
|
||||
};
|
||||
|
||||
// Rewrite the server settings into a content type
|
||||
|
|
@ -1217,14 +1221,6 @@ pub struct SettingsParseResult {
|
|||
pub migration_status: MigrationStatus,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum ParseStatus {
|
||||
/// Settings were parsed successfully
|
||||
Success,
|
||||
/// Settings failed to parse
|
||||
Failed { error: String },
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum MigrationStatus {
|
||||
/// No migration was needed - settings are up to date
|
||||
|
|
|
|||
|
|
@ -803,7 +803,7 @@ impl VsCodeSettings {
|
|||
buffer_font_family,
|
||||
buffer_font_fallbacks,
|
||||
buffer_font_size: self.read_f32("editor.fontSize").map(FontSize::from),
|
||||
buffer_font_weight: self.read_f32("editor.fontWeight").map(|w| w.into()),
|
||||
buffer_font_weight: self.read_f32("editor.fontWeight").map(FontWeightContent),
|
||||
buffer_line_height: None,
|
||||
buffer_font_features: None,
|
||||
agent_ui_font_size: None,
|
||||
|
|
|
|||
35
crates/settings_content/Cargo.toml
Normal file
35
crates/settings_content/Cargo.toml
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
[package]
|
||||
name = "settings_content"
|
||||
version = "0.1.0"
|
||||
edition.workspace = true
|
||||
publish.workspace = true
|
||||
license = "GPL-3.0-or-later"
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
[lib]
|
||||
path = "src/settings_content.rs"
|
||||
|
||||
[features]
|
||||
default = []
|
||||
|
||||
[dependencies]
|
||||
anyhow.workspace = true
|
||||
collections.workspace = true
|
||||
derive_more.workspace = true
|
||||
log.workspace = true
|
||||
schemars.workspace = true
|
||||
serde.workspace = true
|
||||
serde_json.workspace = true
|
||||
serde_json_lenient.workspace = true
|
||||
settings_json.workspace = true
|
||||
settings_macros.workspace = true
|
||||
strum.workspace = true
|
||||
util.workspace = true
|
||||
|
||||
# Uncomment other workspace dependencies as needed
|
||||
# assistant.workspace = true
|
||||
# client.workspace = true
|
||||
# project.workspace = true
|
||||
# settings.workspace = true
|
||||
1
crates/settings_content/LICENSE-GPL
Symbolic link
1
crates/settings_content/LICENSE-GPL
Symbolic link
|
|
@ -0,0 +1 @@
|
|||
../../LICENSE-GPL
|
||||
|
|
@ -1,5 +1,4 @@
|
|||
use collections::{HashMap, IndexMap};
|
||||
use gpui::SharedString;
|
||||
use schemars::{JsonSchema, json_schema};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use settings_macros::{MergeFrom, with_fallible_options};
|
||||
|
|
@ -311,7 +310,7 @@ pub enum CompletionMode {
|
|||
#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, MergeFrom, PartialEq)]
|
||||
pub struct LanguageModelParameters {
|
||||
pub provider: Option<LanguageModelProviderSetting>,
|
||||
pub model: Option<SharedString>,
|
||||
pub model: Option<String>,
|
||||
#[serde(serialize_with = "crate::serialize_optional_f32_with_two_decimal_places")]
|
||||
pub temperature: Option<f32>,
|
||||
}
|
||||
|
|
@ -375,7 +374,7 @@ pub struct AllAgentServersSettings {
|
|||
|
||||
/// Custom agent servers configured by the user
|
||||
#[serde(flatten)]
|
||||
pub custom: HashMap<SharedString, CustomAgentServerSettings>,
|
||||
pub custom: HashMap<String, CustomAgentServerSettings>,
|
||||
}
|
||||
|
||||
#[with_fallible_options]
|
||||
|
|
@ -8,7 +8,7 @@ thread_local! {
|
|||
static ERRORS: RefCell<Option<Vec<anyhow::Error>>> = const { RefCell::new(None) };
|
||||
}
|
||||
|
||||
pub(crate) fn parse_json<'de, T>(json: &'de str) -> (Option<T>, ParseStatus)
|
||||
pub fn parse_json<'de, T>(json: &'de str) -> (Option<T>, ParseStatus)
|
||||
where
|
||||
T: Deserialize<'de>,
|
||||
{
|
||||
|
|
@ -98,7 +98,7 @@ mod tests {
|
|||
}
|
||||
);
|
||||
|
||||
assert!(crate::parse_json_with_comments::<Foo>(&input).is_err());
|
||||
assert!(settings_json::parse_json_with_comments::<Foo>(&input).is_err());
|
||||
|
||||
let ParseStatus::Failed { error } = result else {
|
||||
panic!("Expected parse to fail")
|
||||
|
|
@ -1,7 +1,6 @@
|
|||
use std::{num::NonZeroU32, path::Path};
|
||||
|
||||
use collections::{HashMap, HashSet};
|
||||
use gpui::{Modifiers, SharedString};
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize, de::Error as _};
|
||||
use settings_macros::{MergeFrom, with_fallible_options};
|
||||
|
|
@ -9,6 +8,29 @@ use std::sync::Arc;
|
|||
|
||||
use crate::{ExtendingVec, merge_from};
|
||||
|
||||
/// The state of the modifier keys at some point in time
|
||||
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize, JsonSchema, MergeFrom)]
|
||||
pub struct ModifiersContent {
|
||||
/// The control key
|
||||
#[serde(default)]
|
||||
pub control: bool,
|
||||
/// The alt key
|
||||
/// Sometimes also known as the 'meta' key
|
||||
#[serde(default)]
|
||||
pub alt: bool,
|
||||
/// The shift key
|
||||
#[serde(default)]
|
||||
pub shift: bool,
|
||||
/// The command key, on macos
|
||||
/// the windows key, on windows
|
||||
/// the super key, on linux
|
||||
#[serde(default)]
|
||||
pub platform: bool,
|
||||
/// The function key
|
||||
#[serde(default)]
|
||||
pub function: bool,
|
||||
}
|
||||
|
||||
#[with_fallible_options]
|
||||
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize, JsonSchema)]
|
||||
pub struct AllLanguageSettingsContent {
|
||||
|
|
@ -571,7 +593,7 @@ pub struct InlayHintSettingsContent {
|
|||
/// If no modifiers are specified, this is equivalent to `null`.
|
||||
///
|
||||
/// Default: null
|
||||
pub toggle_on_modifiers_press: Option<Modifiers>,
|
||||
pub toggle_on_modifiers_press: Option<ModifiersContent>,
|
||||
}
|
||||
|
||||
/// The kind of an inlay hint.
|
||||
|
|
@ -769,9 +791,9 @@ pub enum Formatter {
|
|||
/// Format code using an external command.
|
||||
External {
|
||||
/// The external program to run.
|
||||
command: Arc<str>,
|
||||
command: String,
|
||||
/// The arguments to pass to the program.
|
||||
arguments: Option<Arc<[String]>>,
|
||||
arguments: Option<Vec<String>>,
|
||||
},
|
||||
/// Files should be formatted using a code action executed by language servers.
|
||||
CodeAction(String),
|
||||
|
|
@ -890,7 +912,7 @@ pub struct LanguageTaskSettingsContent {
|
|||
/// Map from language name to settings.
|
||||
#[with_fallible_options]
|
||||
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize, JsonSchema, MergeFrom)]
|
||||
pub struct LanguageToSettingsMap(pub HashMap<SharedString, LanguageSettingsContent>);
|
||||
pub struct LanguageToSettingsMap(pub HashMap<String, LanguageSettingsContent>);
|
||||
|
||||
/// Determines how indent guides are colored.
|
||||
#[derive(
|
||||
|
|
@ -27,7 +27,7 @@ pub trait MergeFrom {
|
|||
}
|
||||
|
||||
macro_rules! merge_from_overwrites {
|
||||
($($type:ty),+) => {
|
||||
($($type:ty),+ $(,)?) => {
|
||||
$(
|
||||
impl MergeFrom for $type {
|
||||
fn merge_from(&mut self, other: &Self) {
|
||||
|
|
@ -54,12 +54,8 @@ merge_from_overwrites!(
|
|||
std::num::NonZeroU32,
|
||||
String,
|
||||
std::sync::Arc<str>,
|
||||
gpui::SharedString,
|
||||
std::path::PathBuf,
|
||||
std::sync::Arc<std::path::Path>,
|
||||
gpui::Modifiers,
|
||||
gpui::FontFeatures,
|
||||
gpui::FontWeight
|
||||
);
|
||||
|
||||
impl<T: Clone + MergeFrom> MergeFrom for Option<T> {
|
||||
|
|
@ -67,6 +63,7 @@ impl<T: Clone + MergeFrom> MergeFrom for Option<T> {
|
|||
let Some(other) = other else {
|
||||
return;
|
||||
};
|
||||
|
||||
if let Some(this) = self {
|
||||
this.merge_from(other);
|
||||
} else {
|
||||
|
|
@ -94,11 +91,11 @@ where
|
|||
V: Clone + MergeFrom,
|
||||
{
|
||||
fn merge_from(&mut self, other: &Self) {
|
||||
for (k, v) in other {
|
||||
if let Some(existing) = self.get_mut(k) {
|
||||
existing.merge_from(v);
|
||||
for (key, value) in other {
|
||||
if let Some(existing) = self.get_mut(key) {
|
||||
existing.merge_from(value);
|
||||
} else {
|
||||
self.insert(k.clone(), v.clone());
|
||||
self.insert(key.clone(), value.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -110,11 +107,11 @@ where
|
|||
V: Clone + MergeFrom,
|
||||
{
|
||||
fn merge_from(&mut self, other: &Self) {
|
||||
for (k, v) in other {
|
||||
if let Some(existing) = self.get_mut(k) {
|
||||
existing.merge_from(v);
|
||||
for (key, value) in other {
|
||||
if let Some(existing) = self.get_mut(key) {
|
||||
existing.merge_from(value);
|
||||
} else {
|
||||
self.insert(k.clone(), v.clone());
|
||||
self.insert(key.clone(), value.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -123,15 +120,14 @@ where
|
|||
impl<K, V> MergeFrom for collections::IndexMap<K, V>
|
||||
where
|
||||
K: std::hash::Hash + Eq + Clone,
|
||||
// Q: ?Sized + std::hash::Hash + collections::Equivalent<K> + Eq,
|
||||
V: Clone + MergeFrom,
|
||||
{
|
||||
fn merge_from(&mut self, other: &Self) {
|
||||
for (k, v) in other {
|
||||
if let Some(existing) = self.get_mut(k) {
|
||||
existing.merge_from(v);
|
||||
for (key, value) in other {
|
||||
if let Some(existing) = self.get_mut(key) {
|
||||
existing.merge_from(value);
|
||||
} else {
|
||||
self.insert(k.clone(), v.clone());
|
||||
self.insert(key.clone(), value.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -163,11 +159,11 @@ impl MergeFrom for serde_json::Value {
|
|||
fn merge_from(&mut self, other: &Self) {
|
||||
match (self, other) {
|
||||
(serde_json::Value::Object(this), serde_json::Value::Object(other)) => {
|
||||
for (k, v) in other {
|
||||
if let Some(existing) = this.get_mut(k) {
|
||||
existing.merge_from(v);
|
||||
for (key, value) in other {
|
||||
if let Some(existing) = this.get_mut(key) {
|
||||
existing.merge_from(value);
|
||||
} else {
|
||||
this.insert(k.clone(), v.clone());
|
||||
this.insert(key.clone(), value.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3,12 +3,13 @@ use std::{path::PathBuf, sync::Arc};
|
|||
use collections::{BTreeMap, HashMap};
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use settings_json::parse_json_with_comments;
|
||||
use settings_macros::{MergeFrom, with_fallible_options};
|
||||
use util::serde::default_true;
|
||||
|
||||
use crate::{
|
||||
AllLanguageSettingsContent, DelayMs, ExtendingVec, ProjectTerminalSettingsContent,
|
||||
SlashCommandSettings,
|
||||
AllLanguageSettingsContent, DelayMs, ExtendingVec, ParseStatus, ProjectTerminalSettingsContent,
|
||||
RootUserSettings, SlashCommandSettings, fallible_options,
|
||||
};
|
||||
|
||||
#[with_fallible_options]
|
||||
|
|
@ -24,6 +25,15 @@ impl IntoIterator for LspSettingsMap {
|
|||
}
|
||||
}
|
||||
|
||||
impl RootUserSettings for ProjectSettingsContent {
|
||||
fn parse_json(json: &str) -> (Option<Self>, ParseStatus) {
|
||||
fallible_options::parse_json(json)
|
||||
}
|
||||
fn parse_json_with_comments(json: &str) -> anyhow::Result<Self> {
|
||||
parse_json_with_comments(json)
|
||||
}
|
||||
}
|
||||
|
||||
#[with_fallible_options]
|
||||
#[derive(Debug, PartialEq, Clone, Default, Serialize, Deserialize, JsonSchema, MergeFrom)]
|
||||
pub struct ProjectSettingsContent {
|
||||
|
|
@ -20,7 +20,7 @@ use serde::Serializer;
|
|||
/// This function can be used with Serde's `serialize_with` attribute:
|
||||
/// ```
|
||||
/// use serde::Serialize;
|
||||
/// use settings::serialize_f32_with_two_decimal_places;
|
||||
/// use settings_content::serialize_f32_with_two_decimal_places;
|
||||
///
|
||||
/// #[derive(Serialize)]
|
||||
/// struct ExampleStruct(#[serde(serialize_with = "serialize_f32_with_two_decimal_places")] f32);
|
||||
|
|
@ -64,7 +64,7 @@ where
|
|||
/// This function can be used with Serde's `serialize_with` attribute:
|
||||
/// ```
|
||||
/// use serde::Serialize;
|
||||
/// use settings::serialize_optional_f32_with_two_decimal_places;
|
||||
/// use settings_content::serialize_optional_f32_with_two_decimal_places;
|
||||
///
|
||||
/// #[derive(Serialize)]
|
||||
/// struct ExampleStruct {
|
||||
|
|
@ -1,9 +1,12 @@
|
|||
mod agent;
|
||||
mod editor;
|
||||
mod extension;
|
||||
mod fallible_options;
|
||||
mod language;
|
||||
mod language_model;
|
||||
pub mod merge_from;
|
||||
mod project;
|
||||
mod serde_helper;
|
||||
mod terminal;
|
||||
mod theme;
|
||||
mod workspace;
|
||||
|
|
@ -11,25 +14,35 @@ mod workspace;
|
|||
pub use agent::*;
|
||||
pub use editor::*;
|
||||
pub use extension::*;
|
||||
pub use fallible_options::*;
|
||||
pub use language::*;
|
||||
pub use language_model::*;
|
||||
pub use merge_from::MergeFrom as MergeFromTrait;
|
||||
pub use project::*;
|
||||
use serde::de::DeserializeOwned;
|
||||
pub use serde_helper::{
|
||||
serialize_f32_with_two_decimal_places, serialize_optional_f32_with_two_decimal_places,
|
||||
};
|
||||
use settings_json::parse_json_with_comments;
|
||||
pub use terminal::*;
|
||||
pub use theme::*;
|
||||
pub use workspace::*;
|
||||
|
||||
use collections::{HashMap, IndexMap};
|
||||
use gpui::{App, SharedString};
|
||||
use release_channel::ReleaseChannel;
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use settings_macros::{MergeFrom, with_fallible_options};
|
||||
use std::collections::BTreeSet;
|
||||
use std::env;
|
||||
use std::sync::Arc;
|
||||
pub use util::serde::default_true;
|
||||
|
||||
use crate::{ActiveSettingsProfileName, merge_from};
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum ParseStatus {
|
||||
/// Settings were parsed successfully
|
||||
Success,
|
||||
/// Settings failed to parse
|
||||
Failed { error: String },
|
||||
}
|
||||
|
||||
#[with_fallible_options]
|
||||
#[derive(Debug, PartialEq, Default, Clone, Serialize, Deserialize, JsonSchema, MergeFrom)]
|
||||
|
|
@ -166,11 +179,44 @@ pub struct SettingsContent {
|
|||
}
|
||||
|
||||
impl SettingsContent {
|
||||
pub fn languages_mut(&mut self) -> &mut HashMap<SharedString, LanguageSettingsContent> {
|
||||
pub fn languages_mut(&mut self) -> &mut HashMap<String, LanguageSettingsContent> {
|
||||
&mut self.project.all_languages.languages.0
|
||||
}
|
||||
}
|
||||
|
||||
// These impls are there to optimize builds by avoiding monomorphization downstream. Yes, they're repetitive, but using default impls
|
||||
// break the optimization, for whatever reason.
|
||||
pub trait RootUserSettings: Sized + DeserializeOwned {
|
||||
fn parse_json(json: &str) -> (Option<Self>, ParseStatus);
|
||||
fn parse_json_with_comments(json: &str) -> anyhow::Result<Self>;
|
||||
}
|
||||
|
||||
impl RootUserSettings for SettingsContent {
|
||||
fn parse_json(json: &str) -> (Option<Self>, ParseStatus) {
|
||||
fallible_options::parse_json(json)
|
||||
}
|
||||
fn parse_json_with_comments(json: &str) -> anyhow::Result<Self> {
|
||||
parse_json_with_comments(json)
|
||||
}
|
||||
}
|
||||
// Explicit opt-in instead of blanket impl to avoid monomorphizing downstream. Just a hunch though.
|
||||
impl RootUserSettings for Option<SettingsContent> {
|
||||
fn parse_json(json: &str) -> (Option<Self>, ParseStatus) {
|
||||
fallible_options::parse_json(json)
|
||||
}
|
||||
fn parse_json_with_comments(json: &str) -> anyhow::Result<Self> {
|
||||
parse_json_with_comments(json)
|
||||
}
|
||||
}
|
||||
impl RootUserSettings for UserSettingsContent {
|
||||
fn parse_json(json: &str) -> (Option<Self>, ParseStatus) {
|
||||
fallible_options::parse_json(json)
|
||||
}
|
||||
fn parse_json_with_comments(json: &str) -> anyhow::Result<Self> {
|
||||
parse_json_with_comments(json)
|
||||
}
|
||||
}
|
||||
|
||||
#[with_fallible_options]
|
||||
#[derive(Debug, Default, PartialEq, Clone, Serialize, Deserialize, JsonSchema, MergeFrom)]
|
||||
pub struct UserSettingsContent {
|
||||
|
|
@ -194,33 +240,6 @@ pub struct ExtensionsSettingsContent {
|
|||
pub all_languages: AllLanguageSettingsContent,
|
||||
}
|
||||
|
||||
impl UserSettingsContent {
|
||||
pub fn for_release_channel(&self) -> Option<&SettingsContent> {
|
||||
match *release_channel::RELEASE_CHANNEL {
|
||||
ReleaseChannel::Dev => self.dev.as_deref(),
|
||||
ReleaseChannel::Nightly => self.nightly.as_deref(),
|
||||
ReleaseChannel::Preview => self.preview.as_deref(),
|
||||
ReleaseChannel::Stable => self.stable.as_deref(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn for_os(&self) -> Option<&SettingsContent> {
|
||||
match env::consts::OS {
|
||||
"macos" => self.macos.as_deref(),
|
||||
"linux" => self.linux.as_deref(),
|
||||
"windows" => self.windows.as_deref(),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn for_profile(&self, cx: &App) -> Option<&SettingsContent> {
|
||||
let Some(active_profile) = cx.try_global::<ActiveSettingsProfileName>() else {
|
||||
return None;
|
||||
};
|
||||
self.profiles.get(&active_profile.0)
|
||||
}
|
||||
}
|
||||
|
||||
/// Base key bindings scheme. Base keymaps can be overridden with user keymaps.
|
||||
///
|
||||
/// Default: VSCode
|
||||
|
|
@ -964,14 +983,14 @@ pub struct RemoteSettingsContent {
|
|||
Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq, JsonSchema, MergeFrom, Hash,
|
||||
)]
|
||||
pub struct DevContainerConnection {
|
||||
pub name: SharedString,
|
||||
pub container_id: SharedString,
|
||||
pub name: String,
|
||||
pub container_id: String,
|
||||
}
|
||||
|
||||
#[with_fallible_options]
|
||||
#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq, JsonSchema, MergeFrom)]
|
||||
pub struct SshConnection {
|
||||
pub host: SharedString,
|
||||
pub host: String,
|
||||
pub username: Option<String>,
|
||||
pub port: Option<u16>,
|
||||
#[serde(default)]
|
||||
|
|
@ -994,7 +1013,7 @@ pub struct SshConnection {
|
|||
|
||||
#[derive(Clone, Default, Serialize, Deserialize, PartialEq, JsonSchema, MergeFrom, Debug)]
|
||||
pub struct WslConnection {
|
||||
pub distro_name: SharedString,
|
||||
pub distro_name: String,
|
||||
pub user: Option<String>,
|
||||
#[serde(default)]
|
||||
pub projects: BTreeSet<RemoteProject>,
|
||||
|
|
@ -1,12 +1,11 @@
|
|||
use std::path::PathBuf;
|
||||
|
||||
use collections::HashMap;
|
||||
use gpui::{AbsoluteLength, FontFeatures, FontWeight, SharedString, px};
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use settings_macros::{MergeFrom, with_fallible_options};
|
||||
|
||||
use crate::{FontFamilyName, FontSize};
|
||||
use crate::{FontFamilyName, FontFeaturesContent, FontSize, FontWeightContent};
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize, JsonSchema, MergeFrom)]
|
||||
pub struct ProjectTerminalSettingsContent {
|
||||
|
|
@ -93,9 +92,9 @@ pub struct TerminalSettingsContent {
|
|||
///
|
||||
/// Default: comfortable
|
||||
pub line_height: Option<TerminalLineHeight>,
|
||||
pub font_features: Option<FontFeatures>,
|
||||
pub font_features: Option<FontFeaturesContent>,
|
||||
/// Sets the terminal's font weight in CSS weight units 0-900.
|
||||
pub font_weight: Option<FontWeight>,
|
||||
pub font_weight: Option<FontWeightContent>,
|
||||
/// Default cursor shape for the terminal.
|
||||
/// Can be "bar", "block", "underline", or "hollow".
|
||||
///
|
||||
|
|
@ -202,7 +201,7 @@ pub enum Shell {
|
|||
/// The arguments to pass to the program.
|
||||
args: Vec<String>,
|
||||
/// An optional string to override the title of the terminal tab
|
||||
title_override: Option<SharedString>,
|
||||
title_override: Option<String>,
|
||||
},
|
||||
}
|
||||
|
||||
|
|
@ -259,13 +258,12 @@ pub enum TerminalLineHeight {
|
|||
}
|
||||
|
||||
impl TerminalLineHeight {
|
||||
pub fn value(&self) -> AbsoluteLength {
|
||||
let value = match self {
|
||||
pub fn value(&self) -> f32 {
|
||||
match self {
|
||||
TerminalLineHeight::Comfortable => 1.618,
|
||||
TerminalLineHeight::Standard => 1.3,
|
||||
TerminalLineHeight::Custom(line_height) => f32::max(*line_height, 1.),
|
||||
};
|
||||
px(value).into()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -489,25 +487,20 @@ pub enum ActivateScript {
|
|||
mod test {
|
||||
use serde_json::json;
|
||||
|
||||
use crate::{ProjectSettingsContent, Shell, UserSettingsContent};
|
||||
use crate::{ProjectSettingsContent, Shell};
|
||||
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn test_project_settings() {
|
||||
let project_content =
|
||||
json!({"terminal": {"shell": {"program": "/bin/project"}}, "option_as_meta": true});
|
||||
|
||||
let user_content =
|
||||
let _user_content =
|
||||
json!({"terminal": {"shell": {"program": "/bin/user"}}, "option_as_meta": false});
|
||||
|
||||
let user_settings = serde_json::from_value::<UserSettingsContent>(user_content).unwrap();
|
||||
let project_settings =
|
||||
serde_json::from_value::<ProjectSettingsContent>(project_content).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
user_settings.content.terminal.unwrap().project.shell,
|
||||
Some(Shell::Program("/bin/user".to_owned()))
|
||||
);
|
||||
assert_eq!(user_settings.content.project.terminal, None);
|
||||
assert_eq!(
|
||||
project_settings.terminal.unwrap().shell,
|
||||
Some(Shell::Program("/bin/project".to_owned()))
|
||||
|
|
@ -1,14 +1,116 @@
|
|||
use collections::{HashMap, IndexMap};
|
||||
use gpui::{FontFallbacks, FontFeatures, FontStyle, FontWeight, Pixels, SharedString};
|
||||
use schemars::{JsonSchema, JsonSchema_repr};
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Deserializer, Serialize};
|
||||
use serde_json::Value;
|
||||
use serde_repr::{Deserialize_repr, Serialize_repr};
|
||||
use settings_macros::{MergeFrom, with_fallible_options};
|
||||
use std::{fmt::Display, sync::Arc};
|
||||
use std::{borrow::Cow, fmt::Display, sync::Arc};
|
||||
|
||||
use crate::serialize_f32_with_two_decimal_places;
|
||||
|
||||
/// OpenType font features as a map of feature tag to value.
|
||||
/// This is a content type that mirrors `gpui::FontFeatures` but without the Arc wrapper.
|
||||
/// Values can be specified as booleans (true=1, false=0) or integers.
|
||||
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, MergeFrom)]
|
||||
#[serde(transparent)]
|
||||
pub struct FontFeaturesContent(pub IndexMap<String, u32>);
|
||||
|
||||
impl FontFeaturesContent {
|
||||
pub fn new() -> Self {
|
||||
Self(IndexMap::default())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, serde::Deserialize)]
|
||||
#[serde(untagged)]
|
||||
enum FeatureValue {
|
||||
Bool(bool),
|
||||
Number(serde_json::Number),
|
||||
}
|
||||
|
||||
fn is_valid_feature_tag(tag: &str) -> bool {
|
||||
tag.len() == 4 && tag.chars().all(|c| c.is_ascii_alphanumeric())
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for FontFeaturesContent {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
use serde::de::{MapAccess, Visitor};
|
||||
use std::fmt;
|
||||
|
||||
struct FontFeaturesVisitor;
|
||||
|
||||
impl<'de> Visitor<'de> for FontFeaturesVisitor {
|
||||
type Value = FontFeaturesContent;
|
||||
|
||||
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
formatter.write_str("a map of font features")
|
||||
}
|
||||
|
||||
fn visit_map<M>(self, mut access: M) -> Result<Self::Value, M::Error>
|
||||
where
|
||||
M: MapAccess<'de>,
|
||||
{
|
||||
let mut feature_map = IndexMap::default();
|
||||
|
||||
while let Some((key, value)) =
|
||||
access.next_entry::<String, Option<FeatureValue>>()?
|
||||
{
|
||||
if !is_valid_feature_tag(&key) {
|
||||
log::error!("Incorrect font feature tag: {}", key);
|
||||
continue;
|
||||
}
|
||||
if let Some(value) = value {
|
||||
match value {
|
||||
FeatureValue::Bool(enable) => {
|
||||
feature_map.insert(key, if enable { 1 } else { 0 });
|
||||
}
|
||||
FeatureValue::Number(value) => {
|
||||
if value.is_u64() {
|
||||
feature_map.insert(key, value.as_u64().unwrap() as u32);
|
||||
} else {
|
||||
log::error!(
|
||||
"Incorrect font feature value {} for feature tag {}",
|
||||
value,
|
||||
key
|
||||
);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(FontFeaturesContent(feature_map))
|
||||
}
|
||||
}
|
||||
|
||||
deserializer.deserialize_map(FontFeaturesVisitor)
|
||||
}
|
||||
}
|
||||
|
||||
impl JsonSchema for FontFeaturesContent {
|
||||
fn schema_name() -> Cow<'static, str> {
|
||||
"FontFeaturesContent".into()
|
||||
}
|
||||
|
||||
fn json_schema(_: &mut schemars::SchemaGenerator) -> schemars::Schema {
|
||||
use schemars::json_schema;
|
||||
json_schema!({
|
||||
"type": "object",
|
||||
"patternProperties": {
|
||||
"[0-9a-zA-Z]{4}$": {
|
||||
"type": ["boolean", "integer"],
|
||||
"minimum": 0,
|
||||
"multipleOf": 1
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Settings for rendering text in UI and text buffers.
|
||||
|
||||
#[with_fallible_options]
|
||||
|
|
@ -24,10 +126,10 @@ pub struct ThemeSettingsContent {
|
|||
pub ui_font_fallbacks: Option<Vec<FontFamilyName>>,
|
||||
/// The OpenType features to enable for text in the UI.
|
||||
#[schemars(default = "default_font_features")]
|
||||
pub ui_font_features: Option<FontFeatures>,
|
||||
pub ui_font_features: Option<FontFeaturesContent>,
|
||||
/// The weight of the UI font in CSS units from 100 to 900.
|
||||
#[schemars(default = "default_buffer_font_weight")]
|
||||
pub ui_font_weight: Option<FontWeight>,
|
||||
pub ui_font_weight: Option<FontWeightContent>,
|
||||
/// The name of a font to use for rendering in text buffers.
|
||||
pub buffer_font_family: Option<FontFamilyName>,
|
||||
/// The font fallbacks to use for rendering in text buffers.
|
||||
|
|
@ -37,12 +139,12 @@ pub struct ThemeSettingsContent {
|
|||
pub buffer_font_size: Option<FontSize>,
|
||||
/// The weight of the editor font in CSS units from 100 to 900.
|
||||
#[schemars(default = "default_buffer_font_weight")]
|
||||
pub buffer_font_weight: Option<FontWeight>,
|
||||
pub buffer_font_weight: Option<FontWeightContent>,
|
||||
/// The buffer's line height.
|
||||
pub buffer_line_height: Option<BufferLineHeight>,
|
||||
/// The OpenType features to enable for rendering in text buffers.
|
||||
#[schemars(default = "default_font_features")]
|
||||
pub buffer_font_features: Option<FontFeatures>,
|
||||
pub buffer_font_features: Option<FontFeaturesContent>,
|
||||
/// The font size for agent responses in the agent panel. Falls back to the UI font size if unset.
|
||||
pub agent_ui_font_size: Option<FontSize>,
|
||||
/// The font size for user messages in the agent panel.
|
||||
|
|
@ -103,18 +205,6 @@ impl From<f32> for FontSize {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<FontSize> for Pixels {
|
||||
fn from(value: FontSize) -> Self {
|
||||
value.0.into()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Pixels> for FontSize {
|
||||
fn from(value: Pixels) -> Self {
|
||||
Self(value.into())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Clone,
|
||||
Copy,
|
||||
|
|
@ -142,16 +232,16 @@ impl From<f32> for CodeFade {
|
|||
}
|
||||
}
|
||||
|
||||
fn default_font_features() -> Option<FontFeatures> {
|
||||
Some(FontFeatures::default())
|
||||
fn default_font_features() -> Option<FontFeaturesContent> {
|
||||
Some(FontFeaturesContent::default())
|
||||
}
|
||||
|
||||
fn default_font_fallbacks() -> Option<FontFallbacks> {
|
||||
Some(FontFallbacks::default())
|
||||
fn default_font_fallbacks() -> Option<Vec<FontFamilyName>> {
|
||||
Some(Vec::new())
|
||||
}
|
||||
|
||||
fn default_buffer_font_weight() -> Option<FontWeight> {
|
||||
Some(FontWeight::default())
|
||||
fn default_buffer_font_weight() -> Option<FontWeightContent> {
|
||||
Some(FontWeightContent::NORMAL)
|
||||
}
|
||||
|
||||
/// Represents the selection of a theme, which can be either static or dynamic.
|
||||
|
|
@ -312,18 +402,6 @@ impl AsRef<str> for FontFamilyName {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<SharedString> for FontFamilyName {
|
||||
fn from(value: SharedString) -> Self {
|
||||
Self(Arc::from(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<FontFamilyName> for SharedString {
|
||||
fn from(value: FontFamilyName) -> Self {
|
||||
SharedString::new(value.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<String> for FontFamilyName {
|
||||
fn from(value: String) -> Self {
|
||||
Self(Arc::from(value))
|
||||
|
|
@ -401,7 +479,7 @@ pub struct ThemeStyleContent {
|
|||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, MergeFrom, PartialEq)]
|
||||
pub struct AccentContent(pub Option<SharedString>);
|
||||
pub struct AccentContent(pub Option<String>);
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, MergeFrom, PartialEq)]
|
||||
pub struct PlayerColorContent {
|
||||
|
|
@ -1184,16 +1262,6 @@ pub enum WindowBackgroundContent {
|
|||
Blurred,
|
||||
}
|
||||
|
||||
impl Into<gpui::WindowBackgroundAppearance> for WindowBackgroundContent {
|
||||
fn into(self) -> gpui::WindowBackgroundAppearance {
|
||||
match self {
|
||||
WindowBackgroundContent::Opaque => gpui::WindowBackgroundAppearance::Opaque,
|
||||
WindowBackgroundContent::Transparent => gpui::WindowBackgroundAppearance::Transparent,
|
||||
WindowBackgroundContent::Blurred => gpui::WindowBackgroundAppearance::Blurred,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Serialize, Deserialize, JsonSchema, MergeFrom, PartialEq)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum FontStyleContent {
|
||||
|
|
@ -1202,45 +1270,42 @@ pub enum FontStyleContent {
|
|||
Oblique,
|
||||
}
|
||||
|
||||
impl From<FontStyleContent> for FontStyle {
|
||||
fn from(value: FontStyleContent) -> Self {
|
||||
match value {
|
||||
FontStyleContent::Normal => FontStyle::Normal,
|
||||
FontStyleContent::Italic => FontStyle::Italic,
|
||||
FontStyleContent::Oblique => FontStyle::Oblique,
|
||||
}
|
||||
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Serialize, Deserialize, MergeFrom)]
|
||||
#[serde(transparent)]
|
||||
pub struct FontWeightContent(pub f32);
|
||||
|
||||
impl Default for FontWeightContent {
|
||||
fn default() -> Self {
|
||||
Self::NORMAL
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Debug, Clone, Copy, Serialize_repr, Deserialize_repr, JsonSchema_repr, PartialEq, MergeFrom,
|
||||
)]
|
||||
#[repr(u16)]
|
||||
pub enum FontWeightContent {
|
||||
Thin = 100,
|
||||
ExtraLight = 200,
|
||||
Light = 300,
|
||||
Normal = 400,
|
||||
Medium = 500,
|
||||
Semibold = 600,
|
||||
Bold = 700,
|
||||
ExtraBold = 800,
|
||||
Black = 900,
|
||||
impl FontWeightContent {
|
||||
pub const THIN: FontWeightContent = FontWeightContent(100.0);
|
||||
pub const EXTRA_LIGHT: FontWeightContent = FontWeightContent(200.0);
|
||||
pub const LIGHT: FontWeightContent = FontWeightContent(300.0);
|
||||
pub const NORMAL: FontWeightContent = FontWeightContent(400.0);
|
||||
pub const MEDIUM: FontWeightContent = FontWeightContent(500.0);
|
||||
pub const SEMIBOLD: FontWeightContent = FontWeightContent(600.0);
|
||||
pub const BOLD: FontWeightContent = FontWeightContent(700.0);
|
||||
pub const EXTRA_BOLD: FontWeightContent = FontWeightContent(800.0);
|
||||
pub const BLACK: FontWeightContent = FontWeightContent(900.0);
|
||||
}
|
||||
|
||||
impl From<FontWeightContent> for FontWeight {
|
||||
fn from(value: FontWeightContent) -> Self {
|
||||
match value {
|
||||
FontWeightContent::Thin => FontWeight::THIN,
|
||||
FontWeightContent::ExtraLight => FontWeight::EXTRA_LIGHT,
|
||||
FontWeightContent::Light => FontWeight::LIGHT,
|
||||
FontWeightContent::Normal => FontWeight::NORMAL,
|
||||
FontWeightContent::Medium => FontWeight::MEDIUM,
|
||||
FontWeightContent::Semibold => FontWeight::SEMIBOLD,
|
||||
FontWeightContent::Bold => FontWeight::BOLD,
|
||||
FontWeightContent::ExtraBold => FontWeight::EXTRA_BOLD,
|
||||
FontWeightContent::Black => FontWeight::BLACK,
|
||||
}
|
||||
impl schemars::JsonSchema for FontWeightContent {
|
||||
fn schema_name() -> std::borrow::Cow<'static, str> {
|
||||
"FontWeightContent".into()
|
||||
}
|
||||
|
||||
fn json_schema(_: &mut schemars::SchemaGenerator) -> schemars::Schema {
|
||||
use schemars::json_schema;
|
||||
json_schema!({
|
||||
"type": "number",
|
||||
"minimum": Self::THIN.0,
|
||||
"maximum": Self::BLACK.0,
|
||||
"default": Self::NORMAL.0,
|
||||
"description": "Font weight value between 100 (thin) and 900 (black)"
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1312,27 +1377,27 @@ mod tests {
|
|||
let default_value = &buffer_font_weight["default"];
|
||||
assert_eq!(
|
||||
default_value.as_f64(),
|
||||
Some(FontWeight::NORMAL.0 as f64),
|
||||
"buffer_font_weight default should be 400.0 (FontWeight::NORMAL)"
|
||||
Some(FontWeightContent::NORMAL.0 as f64),
|
||||
"buffer_font_weight default should be 400.0 (FontWeightContent::NORMAL)"
|
||||
);
|
||||
|
||||
let defs = &schema_value["$defs"];
|
||||
let font_weight_def = &defs["FontWeight"];
|
||||
let font_weight_def = &defs["FontWeightContent"];
|
||||
|
||||
assert_eq!(
|
||||
font_weight_def["minimum"].as_f64(),
|
||||
Some(FontWeight::THIN.0 as f64),
|
||||
"FontWeight should have minimum of 100.0"
|
||||
Some(FontWeightContent::THIN.0 as f64),
|
||||
"FontWeightContent should have minimum of 100.0"
|
||||
);
|
||||
assert_eq!(
|
||||
font_weight_def["maximum"].as_f64(),
|
||||
Some(FontWeight::BLACK.0 as f64),
|
||||
"FontWeight should have maximum of 900.0"
|
||||
Some(FontWeightContent::BLACK.0 as f64),
|
||||
"FontWeightContent should have maximum of 900.0"
|
||||
);
|
||||
assert_eq!(
|
||||
font_weight_def["default"].as_f64(),
|
||||
Some(FontWeight::NORMAL.0 as f64),
|
||||
"FontWeight should have default of 400.0"
|
||||
Some(FontWeightContent::NORMAL.0 as f64),
|
||||
"FontWeightContent should have default of 400.0"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -14,11 +14,6 @@ const DEFAULT_STRING: String = String::new();
|
|||
/// to avoid the "NO DEFAULT" case.
|
||||
const DEFAULT_EMPTY_STRING: Option<&String> = Some(&DEFAULT_STRING);
|
||||
|
||||
const DEFAULT_SHARED_STRING: SharedString = SharedString::new_static("");
|
||||
/// A default empty string reference. Useful in `pick` functions for cases either in dynamic item fields, or when dealing with `settings::Maybe`
|
||||
/// to avoid the "NO DEFAULT" case.
|
||||
const DEFAULT_EMPTY_SHARED_STRING: Option<&SharedString> = Some(&DEFAULT_SHARED_STRING);
|
||||
|
||||
macro_rules! concat_sections {
|
||||
(@vec, $($arr:expr),+ $(,)?) => {{
|
||||
let total_len = 0_usize $(+ $arr.len())+;
|
||||
|
|
@ -5667,7 +5662,7 @@ fn terminal_page() -> SettingsPage {
|
|||
pick: |settings_content| {
|
||||
match settings_content.terminal.as_ref()?.project.shell.as_ref() {
|
||||
Some(settings::Shell::WithArguments { title_override, .. }) => {
|
||||
title_override.as_ref().or(DEFAULT_EMPTY_SHARED_STRING)
|
||||
title_override.as_ref().or(DEFAULT_EMPTY_STRING)
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
|
|
@ -7187,7 +7182,11 @@ fn language_settings_field<T>(
|
|||
) -> Option<&T> {
|
||||
let all_languages = &settings_content.project.all_languages;
|
||||
if let Some(current_language_name) = current_language() {
|
||||
if let Some(current_language) = all_languages.languages.0.get(¤t_language_name) {
|
||||
if let Some(current_language) = all_languages
|
||||
.languages
|
||||
.0
|
||||
.get(current_language_name.as_ref())
|
||||
{
|
||||
let value = get(current_language);
|
||||
if value.is_some() {
|
||||
return value;
|
||||
|
|
@ -7208,7 +7207,7 @@ fn language_settings_field_mut<T>(
|
|||
all_languages
|
||||
.languages
|
||||
.0
|
||||
.entry(current_language)
|
||||
.entry(current_language.to_string())
|
||||
.or_default()
|
||||
} else {
|
||||
&mut all_languages.defaults
|
||||
|
|
|
|||
|
|
@ -15,7 +15,9 @@ use project::{Project, WorktreeId};
|
|||
use release_channel::ReleaseChannel;
|
||||
use schemars::JsonSchema;
|
||||
use serde::Deserialize;
|
||||
use settings::{Settings, SettingsContent, SettingsStore, initial_project_settings_content};
|
||||
use settings::{
|
||||
IntoGpui, Settings, SettingsContent, SettingsStore, initial_project_settings_content,
|
||||
};
|
||||
use std::{
|
||||
any::{Any, TypeId, type_name},
|
||||
cell::RefCell,
|
||||
|
|
@ -3794,12 +3796,12 @@ fn render_font_picker(
|
|||
.get_value_from_file(file.to_settings(), field.pick)
|
||||
.1
|
||||
.cloned()
|
||||
.unwrap_or_else(|| SharedString::default().into());
|
||||
.map_or_else(|| SharedString::default(), |value| value.into_gpui());
|
||||
|
||||
PopoverMenu::new("font-picker")
|
||||
.trigger(render_picker_trigger_button(
|
||||
"font_family_picker_trigger".into(),
|
||||
current_value.clone().into(),
|
||||
current_value.clone(),
|
||||
))
|
||||
.menu(move |window, cx| {
|
||||
let file = file.clone();
|
||||
|
|
@ -3807,14 +3809,14 @@ fn render_font_picker(
|
|||
|
||||
Some(cx.new(move |cx| {
|
||||
font_picker(
|
||||
current_value.clone().into(),
|
||||
current_value,
|
||||
move |font_name, cx| {
|
||||
update_settings_file(
|
||||
file.clone(),
|
||||
field.json_path,
|
||||
cx,
|
||||
move |settings, _cx| {
|
||||
(field.write)(settings, Some(font_name.into()));
|
||||
(field.write)(settings, Some(font_name.to_string().into()));
|
||||
},
|
||||
)
|
||||
.log_err(); // todo(settings_ui) don't log err
|
||||
|
|
|
|||
|
|
@ -9,8 +9,9 @@ use serde::{Deserialize, Serialize};
|
|||
pub use settings::AlternateScroll;
|
||||
|
||||
use settings::{
|
||||
PathHyperlinkRegex, RegisterSetting, ShowScrollbar, TerminalBlink, TerminalDockPosition,
|
||||
TerminalLineHeight, VenvSettings, WorkingDirectory, merge_from::MergeFrom,
|
||||
IntoGpui, PathHyperlinkRegex, RegisterSetting, ShowScrollbar, TerminalBlink,
|
||||
TerminalDockPosition, TerminalLineHeight, VenvSettings, WorkingDirectory,
|
||||
merge_from::MergeFrom,
|
||||
};
|
||||
use task::Shell;
|
||||
use theme::FontFamilyName;
|
||||
|
|
@ -70,7 +71,7 @@ fn settings_shell_to_task_shell(shell: settings::Shell) -> Shell {
|
|||
} => Shell::WithArguments {
|
||||
program,
|
||||
args,
|
||||
title_override: title_override.map(Into::into),
|
||||
title_override,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
@ -84,7 +85,7 @@ impl settings::Settings for TerminalSettings {
|
|||
TerminalSettings {
|
||||
shell: settings_shell_to_task_shell(project_content.shell.unwrap()),
|
||||
working_directory: project_content.working_directory.unwrap(),
|
||||
font_size: user_content.font_size.map(Into::into),
|
||||
font_size: user_content.font_size.map(|s| s.into_gpui()),
|
||||
font_family: user_content.font_family,
|
||||
font_fallbacks: user_content.font_fallbacks.map(|fallbacks| {
|
||||
FontFallbacks::from_fonts(
|
||||
|
|
@ -94,8 +95,8 @@ impl settings::Settings for TerminalSettings {
|
|||
.collect(),
|
||||
)
|
||||
}),
|
||||
font_features: user_content.font_features,
|
||||
font_weight: user_content.font_weight,
|
||||
font_features: user_content.font_features.map(|f| f.into_gpui()),
|
||||
font_weight: user_content.font_weight.map(|w| w.into_gpui()),
|
||||
line_height: user_content.line_height.unwrap(),
|
||||
env: project_content.env.unwrap(),
|
||||
cursor_shape: user_content.cursor_shape.unwrap().into(),
|
||||
|
|
|
|||
|
|
@ -844,11 +844,8 @@ impl Element for TerminalElement {
|
|||
} => {
|
||||
let rem_size = window.rem_size();
|
||||
let line_height = f32::from(window.text_style().font_size.to_pixels(rem_size))
|
||||
* TerminalSettings::get_global(cx)
|
||||
.line_height
|
||||
.value()
|
||||
.to_pixels(rem_size);
|
||||
(displayed_lines * line_height).into()
|
||||
* TerminalSettings::get_global(cx).line_height.value();
|
||||
px(displayed_lines as f32 * line_height).into()
|
||||
}
|
||||
ContentMode::Scrollable => {
|
||||
if let TerminalMode::Embedded { .. } = &self.mode {
|
||||
|
|
@ -956,7 +953,7 @@ impl Element for TerminalElement {
|
|||
font_fallbacks,
|
||||
font_size: font_size.into(),
|
||||
font_style: FontStyle::Normal,
|
||||
line_height: line_height.into(),
|
||||
line_height: px(line_height).into(),
|
||||
background_color: Some(theme.colors().terminal_ansi_background),
|
||||
white_space: WhiteSpace::Normal,
|
||||
// These are going to be overridden per-cell
|
||||
|
|
@ -971,8 +968,7 @@ impl Element for TerminalElement {
|
|||
let (dimensions, line_height_px) = {
|
||||
let rem_size = window.rem_size();
|
||||
let font_pixels = text_style.font_size.to_pixels(rem_size);
|
||||
// TODO: line_height should be an f32 not an AbsoluteLength.
|
||||
let line_height = f32::from(font_pixels) * line_height.to_pixels(rem_size);
|
||||
let line_height = f32::from(font_pixels) * line_height;
|
||||
let font_id = cx.text_system().resolve_font(&text_style.font());
|
||||
|
||||
let cell_width = text_system
|
||||
|
|
@ -995,7 +991,7 @@ impl Element for TerminalElement {
|
|||
origin.x += gutter;
|
||||
|
||||
(
|
||||
TerminalBounds::new(line_height, cell_width, Bounds { origin, size }),
|
||||
TerminalBounds::new(px(line_height), cell_width, Bounds { origin, size }),
|
||||
line_height,
|
||||
)
|
||||
};
|
||||
|
|
@ -1106,9 +1102,10 @@ impl Element for TerminalElement {
|
|||
// internal line number (which can be negative in Scrollable mode for
|
||||
// scrollback history).
|
||||
let rows_above_viewport =
|
||||
((intersection.top() - bounds.top()).max(px(0.)) / line_height_px) as usize;
|
||||
f32::from((intersection.top() - bounds.top()).max(px(0.)) / line_height_px)
|
||||
as usize;
|
||||
let visible_row_count =
|
||||
(intersection.size.height / line_height_px).ceil() as usize + 1;
|
||||
f32::from((intersection.size.height / line_height_px).ceil()) as usize + 1;
|
||||
|
||||
TerminalElement::layout_grid(
|
||||
// Group cells by line and filter to only the visible screen rows.
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
#![allow(missing_docs)]
|
||||
|
||||
use gpui::{FontStyle, FontWeight, HighlightStyle, Hsla};
|
||||
use gpui::{HighlightStyle, Hsla};
|
||||
use palette::FromColor;
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use settings::IntoGpui;
|
||||
pub use settings::{FontWeightContent, WindowBackgroundContent};
|
||||
|
||||
use crate::{StatusColorsRefinement, ThemeColorsRefinement};
|
||||
|
|
@ -63,8 +64,8 @@ pub fn syntax_overrides(this: &settings::ThemeStyleContent) -> Vec<(String, High
|
|||
.background_color
|
||||
.as_ref()
|
||||
.and_then(|color| try_parse_color(color).ok()),
|
||||
font_style: style.font_style.map(FontStyle::from),
|
||||
font_weight: style.font_weight.map(FontWeight::from),
|
||||
font_style: style.font_style.map(|s| s.into_gpui()),
|
||||
font_weight: style.font_weight.map(|w| w.into_gpui()),
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
|
|
|
|||
|
|
@ -5,14 +5,13 @@ use crate::{
|
|||
use collections::HashMap;
|
||||
use derive_more::{Deref, DerefMut};
|
||||
use gpui::{
|
||||
App, Context, Font, FontFallbacks, FontStyle, FontWeight, Global, Pixels, Subscription, Window,
|
||||
px,
|
||||
App, Context, Font, FontFallbacks, FontStyle, Global, Pixels, Subscription, Window, px,
|
||||
};
|
||||
use refineable::Refineable;
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
pub use settings::{FontFamilyName, IconThemeName, ThemeAppearanceMode, ThemeName};
|
||||
use settings::{RegisterSetting, Settings, SettingsContent};
|
||||
use settings::{IntoGpui, RegisterSetting, Settings, SettingsContent};
|
||||
use std::sync::Arc;
|
||||
|
||||
const MIN_FONT_SIZE: Pixels = px(6.0);
|
||||
|
|
@ -557,7 +556,8 @@ impl ThemeSettings {
|
|||
|
||||
fn modify_theme(base_theme: &mut Theme, theme_overrides: &settings::ThemeStyleContent) {
|
||||
if let Some(window_background_appearance) = theme_overrides.window_background_appearance {
|
||||
base_theme.styles.window_background_appearance = window_background_appearance.into();
|
||||
base_theme.styles.window_background_appearance =
|
||||
window_background_appearance.into_gpui();
|
||||
}
|
||||
let status_color_refinement = status_colors_refinement(&theme_overrides.status);
|
||||
|
||||
|
|
@ -686,12 +686,7 @@ pub fn clamp_font_size(size: Pixels) -> Pixels {
|
|||
size.clamp(MIN_FONT_SIZE, MAX_FONT_SIZE)
|
||||
}
|
||||
|
||||
fn clamp_font_weight(weight: f32) -> FontWeight {
|
||||
FontWeight(weight.clamp(100., 950.))
|
||||
}
|
||||
|
||||
/// font fallback from settings
|
||||
pub fn font_fallbacks_from_settings(
|
||||
fn font_fallbacks_from_settings(
|
||||
fallbacks: Option<Vec<settings::FontFamilyName>>,
|
||||
) -> Option<FontFallbacks> {
|
||||
fallbacks.map(|fallbacks| {
|
||||
|
|
@ -710,12 +705,12 @@ impl settings::Settings for ThemeSettings {
|
|||
let theme_selection: ThemeSelection = content.theme.clone().unwrap().into();
|
||||
let icon_theme_selection: IconThemeSelection = content.icon_theme.clone().unwrap().into();
|
||||
Self {
|
||||
ui_font_size: clamp_font_size(content.ui_font_size.unwrap().into()),
|
||||
ui_font_size: clamp_font_size(content.ui_font_size.unwrap().into_gpui()),
|
||||
ui_font: Font {
|
||||
family: content.ui_font_family.as_ref().unwrap().0.clone().into(),
|
||||
features: content.ui_font_features.clone().unwrap(),
|
||||
features: content.ui_font_features.clone().unwrap().into_gpui(),
|
||||
fallbacks: font_fallbacks_from_settings(content.ui_font_fallbacks.clone()),
|
||||
weight: clamp_font_weight(content.ui_font_weight.unwrap().0),
|
||||
weight: content.ui_font_weight.unwrap().into_gpui(),
|
||||
style: Default::default(),
|
||||
},
|
||||
buffer_font: Font {
|
||||
|
|
@ -726,15 +721,15 @@ impl settings::Settings for ThemeSettings {
|
|||
.0
|
||||
.clone()
|
||||
.into(),
|
||||
features: content.buffer_font_features.clone().unwrap(),
|
||||
features: content.buffer_font_features.clone().unwrap().into_gpui(),
|
||||
fallbacks: font_fallbacks_from_settings(content.buffer_font_fallbacks.clone()),
|
||||
weight: clamp_font_weight(content.buffer_font_weight.unwrap().0),
|
||||
weight: content.buffer_font_weight.unwrap().into_gpui(),
|
||||
style: FontStyle::default(),
|
||||
},
|
||||
buffer_font_size: clamp_font_size(content.buffer_font_size.unwrap().into()),
|
||||
buffer_font_size: clamp_font_size(content.buffer_font_size.unwrap().into_gpui()),
|
||||
buffer_line_height: content.buffer_line_height.unwrap().into(),
|
||||
agent_ui_font_size: content.agent_ui_font_size.map(Into::into),
|
||||
agent_buffer_font_size: content.agent_buffer_font_size.map(Into::into),
|
||||
agent_ui_font_size: content.agent_ui_font_size.map(|s| s.into_gpui()),
|
||||
agent_buffer_font_size: content.agent_buffer_font_size.map(|s| s.into_gpui()),
|
||||
theme: theme_selection,
|
||||
experimental_theme_overrides: content.experimental_theme_overrides.clone(),
|
||||
theme_overrides: content.theme_overrides.clone(),
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ use std::path::Path;
|
|||
use std::sync::Arc;
|
||||
|
||||
use ::settings::DEFAULT_DARK_THEME;
|
||||
use ::settings::IntoGpui;
|
||||
use ::settings::Settings;
|
||||
use ::settings::SettingsStore;
|
||||
use anyhow::Result;
|
||||
|
|
@ -273,8 +274,8 @@ impl ThemeFamily {
|
|||
.background_color
|
||||
.as_ref()
|
||||
.and_then(|color| try_parse_color(color).ok()),
|
||||
font_style: highlight.font_style.map(Into::into),
|
||||
font_weight: highlight.font_weight.map(Into::into),
|
||||
font_style: highlight.font_style.map(|s| s.into_gpui()),
|
||||
font_weight: highlight.font_weight.map(|w| w.into_gpui()),
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
|
|
@ -285,7 +286,7 @@ impl ThemeFamily {
|
|||
let window_background_appearance = theme
|
||||
.style
|
||||
.window_background_appearance
|
||||
.map(Into::into)
|
||||
.map(|w| w.into_gpui())
|
||||
.unwrap_or_default();
|
||||
|
||||
Theme {
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ use super::ZedSyntaxToken;
|
|||
|
||||
pub(crate) fn try_parse_font_weight(font_style: &str) -> Option<FontWeightContent> {
|
||||
match font_style {
|
||||
style if style.contains("bold") => Some(FontWeightContent::Bold),
|
||||
style if style.contains("bold") => Some(FontWeightContent::BOLD),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -717,7 +717,7 @@ mod test {
|
|||
cx.update_global(|store: &mut SettingsStore, cx| {
|
||||
store.update_user_settings(cx, |settings| {
|
||||
settings.project.all_languages.languages.0.insert(
|
||||
LanguageName::new_static("Rust").0,
|
||||
LanguageName::new_static("Rust").0.to_string(),
|
||||
LanguageSettingsContent {
|
||||
auto_indent_on_paste: Some(false),
|
||||
..Default::default()
|
||||
|
|
|
|||
|
|
@ -922,7 +922,7 @@ fn register_actions(
|
|||
let _ = settings
|
||||
.theme
|
||||
.ui_font_size
|
||||
.insert(theme::clamp_font_size(ui_font_size).into());
|
||||
.insert(f32::from(theme::clamp_font_size(ui_font_size)).into());
|
||||
});
|
||||
} else {
|
||||
theme::adjust_ui_font_size(cx, |size| size + px(1.0));
|
||||
|
|
@ -938,7 +938,7 @@ fn register_actions(
|
|||
let _ = settings
|
||||
.theme
|
||||
.ui_font_size
|
||||
.insert(theme::clamp_font_size(ui_font_size).into());
|
||||
.insert(f32::from(theme::clamp_font_size(ui_font_size)).into());
|
||||
});
|
||||
} else {
|
||||
theme::adjust_ui_font_size(cx, |size| size - px(1.0));
|
||||
|
|
@ -967,7 +967,7 @@ fn register_actions(
|
|||
let _ = settings
|
||||
.theme
|
||||
.buffer_font_size
|
||||
.insert(theme::clamp_font_size(buffer_font_size).into());
|
||||
.insert(f32::from(theme::clamp_font_size(buffer_font_size)).into());
|
||||
});
|
||||
} else {
|
||||
theme::adjust_buffer_font_size(cx, |size| size + px(1.0));
|
||||
|
|
@ -984,7 +984,7 @@ fn register_actions(
|
|||
let _ = settings
|
||||
.theme
|
||||
.buffer_font_size
|
||||
.insert(theme::clamp_font_size(buffer_font_size).into());
|
||||
.insert(f32::from(theme::clamp_font_size(buffer_font_size)).into());
|
||||
});
|
||||
} else {
|
||||
theme::adjust_buffer_font_size(cx, |size| size - px(1.0));
|
||||
|
|
|
|||
Loading…
Reference in a new issue