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
@@ -700,7 +700,7 @@ mod tests {
|
||||
use dap::debugger_settings::DebuggerSettings;
|
||||
use editor::Editor;
|
||||
use gpui::{TestAppContext, UpdateGlobal, WindowHandle};
|
||||
use project::{Project, project_settings::ProjectSettings};
|
||||
use project::Project;
|
||||
use serde_json::json;
|
||||
use settings::SettingsStore;
|
||||
use util::path;
|
||||
@@ -714,8 +714,11 @@ mod tests {
|
||||
|
||||
cx.update(|cx| {
|
||||
SettingsStore::update_global(cx, |store, cx| {
|
||||
store.update_user_settings::<ProjectSettings>(cx, |settings| {
|
||||
settings.session.restore_unsaved_buffers = false
|
||||
store.update_user_settings(cx, |settings| {
|
||||
settings
|
||||
.session
|
||||
.get_or_insert_default()
|
||||
.restore_unsaved_buffers = Some(false)
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
use std::collections::BTreeSet;
|
||||
use std::{path::PathBuf, sync::Arc};
|
||||
|
||||
use anyhow::{Context as _, Result};
|
||||
@@ -17,35 +16,32 @@ use markdown::{Markdown, MarkdownElement, MarkdownStyle};
|
||||
use release_channel::ReleaseChannel;
|
||||
use remote::{
|
||||
ConnectionIdentifier, RemoteClient, RemoteConnectionOptions, RemotePlatform,
|
||||
SshConnectionOptions, SshPortForwardOption, WslConnectionOptions,
|
||||
SshConnectionOptions,
|
||||
};
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use settings::{Settings, SettingsKey, SettingsSources, SettingsUi};
|
||||
pub use settings::SshConnection;
|
||||
use settings::{Settings, WslConnection};
|
||||
use theme::ThemeSettings;
|
||||
use ui::{
|
||||
ActiveTheme, Color, CommonAnimationExt, Context, Icon, IconName, IconSize, InteractiveElement,
|
||||
IntoElement, Label, LabelCommon, Styled, Window, prelude::*,
|
||||
};
|
||||
use util::serde::default_true;
|
||||
use util::MergeFrom;
|
||||
use workspace::{AppState, ModalView, Workspace};
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct SshSettings {
|
||||
pub ssh_connections: Option<Vec<SshConnection>>,
|
||||
pub wsl_connections: Option<Vec<WslConnection>>,
|
||||
pub ssh_connections: Vec<SshConnection>,
|
||||
pub wsl_connections: Vec<WslConnection>,
|
||||
/// Whether to read ~/.ssh/config for ssh connection sources.
|
||||
#[serde(default = "default_true")]
|
||||
pub read_ssh_config: bool,
|
||||
}
|
||||
|
||||
impl SshSettings {
|
||||
pub fn ssh_connections(&self) -> impl Iterator<Item = SshConnection> + use<> {
|
||||
self.ssh_connections.clone().into_iter().flatten()
|
||||
self.ssh_connections.clone().into_iter()
|
||||
}
|
||||
|
||||
pub fn wsl_connections(&self) -> impl Iterator<Item = WslConnection> + use<> {
|
||||
self.wsl_connections.clone().into_iter().flatten()
|
||||
self.wsl_connections.clone().into_iter()
|
||||
}
|
||||
|
||||
pub fn fill_connection_options_from_settings(&self, options: &mut SshConnectionOptions) {
|
||||
@@ -80,66 +76,7 @@ impl SshSettings {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Default, Serialize, Deserialize, PartialEq, JsonSchema)]
|
||||
pub struct SshConnection {
|
||||
pub host: SharedString,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub username: Option<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub port: Option<u16>,
|
||||
#[serde(skip_serializing_if = "Vec::is_empty")]
|
||||
#[serde(default)]
|
||||
pub args: Vec<String>,
|
||||
#[serde(default)]
|
||||
pub projects: BTreeSet<SshProject>,
|
||||
/// Name to use for this server in UI.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub nickname: Option<String>,
|
||||
// By default Zed will download the binary to the host directly.
|
||||
// If this is set to true, Zed will download the binary to your local machine,
|
||||
// and then upload it over the SSH connection. Useful if your SSH server has
|
||||
// limited outbound internet access.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub upload_binary_over_ssh: Option<bool>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub port_forwards: Option<Vec<SshPortForwardOption>>,
|
||||
}
|
||||
|
||||
impl From<SshConnection> for SshConnectionOptions {
|
||||
fn from(val: SshConnection) -> Self {
|
||||
SshConnectionOptions {
|
||||
host: val.host.into(),
|
||||
username: val.username,
|
||||
port: val.port,
|
||||
password: None,
|
||||
args: Some(val.args),
|
||||
nickname: val.nickname,
|
||||
upload_binary_over_ssh: val.upload_binary_over_ssh.unwrap_or_default(),
|
||||
port_forwards: val.port_forwards,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Default, Serialize, Deserialize, PartialEq, JsonSchema)]
|
||||
pub struct WslConnection {
|
||||
pub distro_name: SharedString,
|
||||
#[serde(default)]
|
||||
pub user: Option<String>,
|
||||
#[serde(default)]
|
||||
pub projects: BTreeSet<SshProject>,
|
||||
}
|
||||
|
||||
impl From<WslConnection> for WslConnectionOptions {
|
||||
fn from(val: WslConnection) -> Self {
|
||||
WslConnectionOptions {
|
||||
distro_name: val.distro_name.into(),
|
||||
user: val.user,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize, PartialEq, JsonSchema)]
|
||||
#[derive(Clone, PartialEq)]
|
||||
pub enum Connection {
|
||||
Ssh(SshConnection),
|
||||
Wsl(WslConnection),
|
||||
@@ -166,27 +103,26 @@ impl From<WslConnection> for Connection {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Default, Serialize, PartialEq, Eq, PartialOrd, Ord, Deserialize, JsonSchema)]
|
||||
pub struct SshProject {
|
||||
pub paths: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Default, Serialize, Deserialize, JsonSchema, SettingsUi, SettingsKey)]
|
||||
#[settings_key(None)]
|
||||
pub struct RemoteSettingsContent {
|
||||
pub ssh_connections: Option<Vec<SshConnection>>,
|
||||
pub wsl_connections: Option<Vec<WslConnection>>,
|
||||
pub read_ssh_config: Option<bool>,
|
||||
}
|
||||
|
||||
impl Settings for SshSettings {
|
||||
type FileContent = RemoteSettingsContent;
|
||||
|
||||
fn load(sources: SettingsSources<Self::FileContent>, _: &mut App) -> Result<Self> {
|
||||
sources.json_merge()
|
||||
fn from_defaults(content: &settings::SettingsContent, _cx: &mut App) -> Self {
|
||||
let remote = &content.remote;
|
||||
Self {
|
||||
ssh_connections: remote.ssh_connections.clone().unwrap_or_default(),
|
||||
wsl_connections: remote.wsl_connections.clone().unwrap_or_default(),
|
||||
read_ssh_config: remote.read_ssh_config.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(ssh_connections) = content.remote.ssh_connections.clone() {
|
||||
self.ssh_connections.extend(ssh_connections)
|
||||
}
|
||||
if let Some(wsl_connections) = content.remote.wsl_connections.clone() {
|
||||
self.wsl_connections.extend(wsl_connections)
|
||||
}
|
||||
self.read_ssh_config
|
||||
.merge_from(&content.remote.read_ssh_config);
|
||||
}
|
||||
}
|
||||
|
||||
pub struct RemoteConnectionPrompt {
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
use crate::{
|
||||
remote_connections::{
|
||||
Connection, RemoteConnectionModal, RemoteConnectionPrompt, RemoteSettingsContent,
|
||||
SshConnection, SshConnectionHeader, SshProject, SshSettings, connect, connect_over_ssh,
|
||||
open_remote_project,
|
||||
Connection, RemoteConnectionModal, RemoteConnectionPrompt, SshConnection,
|
||||
SshConnectionHeader, SshSettings, connect, connect_over_ssh, open_remote_project,
|
||||
},
|
||||
ssh_config::parse_ssh_config_hosts,
|
||||
};
|
||||
@@ -22,7 +21,10 @@ use remote::{
|
||||
RemoteClient, RemoteConnectionOptions, SshConnectionOptions, WslConnectionOptions,
|
||||
remote_client::ConnectionIdentifier,
|
||||
};
|
||||
use settings::{Settings, SettingsStore, update_settings_file, watch_config_file};
|
||||
use settings::{
|
||||
RemoteSettingsContent, Settings as _, SettingsStore, SshProject, update_settings_file,
|
||||
watch_config_file,
|
||||
};
|
||||
use smol::stream::StreamExt as _;
|
||||
use std::{
|
||||
borrow::Cow,
|
||||
@@ -233,14 +235,15 @@ impl ProjectPicker {
|
||||
|
||||
cx.update(|_, cx| {
|
||||
let fs = app_state.fs.clone();
|
||||
update_settings_file::<SshSettings>(fs, cx, {
|
||||
update_settings_file(fs, cx, {
|
||||
let paths = paths
|
||||
.iter()
|
||||
.map(|path| path.to_string_lossy().to_string())
|
||||
.collect();
|
||||
move |setting, _| match index {
|
||||
move |settings, _| match index {
|
||||
ServerIndex::Ssh(index) => {
|
||||
if let Some(server) = setting
|
||||
if let Some(server) = settings
|
||||
.remote
|
||||
.ssh_connections
|
||||
.as_mut()
|
||||
.and_then(|connections| connections.get_mut(index.0))
|
||||
@@ -249,7 +252,8 @@ impl ProjectPicker {
|
||||
};
|
||||
}
|
||||
ServerIndex::Wsl(index) => {
|
||||
if let Some(server) = setting
|
||||
if let Some(server) = settings
|
||||
.remote
|
||||
.wsl_connections
|
||||
.as_mut()
|
||||
.and_then(|connections| connections.get_mut(index.0))
|
||||
@@ -1317,7 +1321,7 @@ impl RemoteServerProjects {
|
||||
else {
|
||||
return;
|
||||
};
|
||||
update_settings_file::<SshSettings>(fs, cx, move |setting, cx| f(setting, cx));
|
||||
update_settings_file(fs, cx, move |setting, cx| f(&mut setting.remote, cx));
|
||||
}
|
||||
|
||||
fn delete_ssh_server(&mut self, server: SshServerIndex, cx: &mut Context<Self>) {
|
||||
@@ -1356,7 +1360,7 @@ impl RemoteServerProjects {
|
||||
setting
|
||||
.wsl_connections
|
||||
.get_or_insert(Default::default())
|
||||
.push(crate::remote_connections::WslConnection {
|
||||
.push(settings::WslConnection {
|
||||
distro_name: SharedString::from(connection_options.distro_name),
|
||||
user: connection_options.user,
|
||||
projects: BTreeSet::new(),
|
||||
@@ -1881,41 +1885,27 @@ impl RemoteServerProjects {
|
||||
let ssh_settings = SshSettings::get_global(cx);
|
||||
let mut should_rebuild = false;
|
||||
|
||||
let ssh_connections_changed =
|
||||
ssh_settings
|
||||
.ssh_connections
|
||||
.as_ref()
|
||||
.is_some_and(|connections| {
|
||||
state
|
||||
.servers
|
||||
.iter()
|
||||
.filter_map(|server| match server {
|
||||
RemoteEntry::Project {
|
||||
connection: Connection::Ssh(connection),
|
||||
..
|
||||
} => Some(connection),
|
||||
_ => None,
|
||||
})
|
||||
.ne(connections.iter())
|
||||
});
|
||||
let ssh_connections_changed = ssh_settings.ssh_connections.iter().ne(state
|
||||
.servers
|
||||
.iter()
|
||||
.filter_map(|server| match server {
|
||||
RemoteEntry::Project {
|
||||
connection: Connection::Ssh(connection),
|
||||
..
|
||||
} => Some(connection),
|
||||
_ => None,
|
||||
}));
|
||||
|
||||
let wsl_connections_changed =
|
||||
ssh_settings
|
||||
.wsl_connections
|
||||
.as_ref()
|
||||
.is_some_and(|connections| {
|
||||
state
|
||||
.servers
|
||||
.iter()
|
||||
.filter_map(|server| match server {
|
||||
RemoteEntry::Project {
|
||||
connection: Connection::Wsl(connection),
|
||||
..
|
||||
} => Some(connection),
|
||||
_ => None,
|
||||
})
|
||||
.ne(connections.iter())
|
||||
});
|
||||
let wsl_connections_changed = ssh_settings.wsl_connections.iter().ne(state
|
||||
.servers
|
||||
.iter()
|
||||
.filter_map(|server| match server {
|
||||
RemoteEntry::Project {
|
||||
connection: Connection::Wsl(connection),
|
||||
..
|
||||
} => Some(connection),
|
||||
_ => None,
|
||||
}));
|
||||
|
||||
if ssh_connections_changed || wsl_connections_changed {
|
||||
should_rebuild = true;
|
||||
|
||||
Reference in New Issue
Block a user