settings_ui: Collect all settings files (#38816)
Closes #ISSUE Updates the settings editor to collect all known settings files from the settings store, in order to show them in the UI. Additionally adds a fake worktree instantiation in the settings UI example binary in order to have more than one file available when testing. Release Notes: - N/A *or* Added/Fixed/Improved ...
This commit is contained in:
Generated
+3
@@ -14508,6 +14508,7 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"assets",
|
||||
"client",
|
||||
"command_palette_hooks",
|
||||
"editor",
|
||||
"feature_flags",
|
||||
@@ -14516,9 +14517,11 @@ dependencies = [
|
||||
"gpui",
|
||||
"language",
|
||||
"menu",
|
||||
"node_runtime",
|
||||
"paths",
|
||||
"project",
|
||||
"serde",
|
||||
"session",
|
||||
"settings",
|
||||
"theme",
|
||||
"ui",
|
||||
|
||||
@@ -43,7 +43,7 @@ impl Session {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
// #[cfg(any(test, feature = "test-support"))]
|
||||
pub fn test() -> Self {
|
||||
Self {
|
||||
session_id: Uuid::new_v4().to_string(),
|
||||
|
||||
@@ -24,7 +24,8 @@ pub use keymap_file::{
|
||||
pub use settings_file::*;
|
||||
pub use settings_json::*;
|
||||
pub use settings_store::{
|
||||
InvalidSettingsError, LocalSettingsKind, Settings, SettingsKey, SettingsLocation, SettingsStore,
|
||||
InvalidSettingsError, LocalSettingsKind, Settings, SettingsFile, SettingsKey, SettingsLocation,
|
||||
SettingsStore,
|
||||
};
|
||||
|
||||
pub use vscode_import::{VsCodeSettings, VsCodeSettingsSource};
|
||||
|
||||
@@ -156,6 +156,16 @@ pub struct SettingsStore {
|
||||
mpsc::UnboundedSender<Box<dyn FnOnce(AsyncApp) -> LocalBoxFuture<'static, Result<()>>>>,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq)]
|
||||
pub enum SettingsFile {
|
||||
User,
|
||||
Global,
|
||||
Extension,
|
||||
Server,
|
||||
Default,
|
||||
Local((WorktreeId, Arc<Path>)),
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Editorconfig {
|
||||
pub is_root: bool,
|
||||
@@ -479,6 +489,36 @@ impl SettingsStore {
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
pub fn get_all_files(&self) -> Vec<SettingsFile> {
|
||||
let mut files = Vec::from_iter(
|
||||
self.local_settings
|
||||
.keys()
|
||||
// rev because these are sorted by path, so highest precedence is last
|
||||
.rev()
|
||||
.cloned()
|
||||
.map(SettingsFile::Local),
|
||||
);
|
||||
|
||||
if self.server_settings.is_some() {
|
||||
files.push(SettingsFile::Server);
|
||||
}
|
||||
// ignoring profiles
|
||||
// ignoring os profiles
|
||||
// ignoring release channel profiles
|
||||
|
||||
if self.user_settings.is_some() {
|
||||
files.push(SettingsFile::User);
|
||||
}
|
||||
if self.extension_settings.is_some() {
|
||||
files.push(SettingsFile::Extension);
|
||||
}
|
||||
if self.global_settings.is_some() {
|
||||
files.push(SettingsFile::Global);
|
||||
}
|
||||
files.push(SettingsFile::Default);
|
||||
files
|
||||
}
|
||||
}
|
||||
|
||||
impl SettingsStore {
|
||||
|
||||
@@ -32,12 +32,15 @@ workspace-hack.workspace = true
|
||||
workspace.workspace = true
|
||||
|
||||
[dev-dependencies]
|
||||
settings = { workspace = true, features = ["test-support"] }
|
||||
settings.workspace = true
|
||||
futures.workspace = true
|
||||
language.workspace = true
|
||||
assets.workspace = true
|
||||
paths.workspace = true
|
||||
zlog.workspace = true
|
||||
client.workspace = true
|
||||
session.workspace = true
|
||||
node_runtime.workspace = true
|
||||
|
||||
[[example]]
|
||||
name = "ui"
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
{}
|
||||
@@ -1,11 +1,42 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use futures::StreamExt;
|
||||
use gpui::AppContext as _;
|
||||
use settings::{DEFAULT_KEYMAP_PATH, KeymapFile, SettingsStore, watch_config_file};
|
||||
use settings_ui::open_settings_editor;
|
||||
use ui::BorrowAppContext;
|
||||
|
||||
fn merge_paths(a: &std::path::Path, b: &std::path::Path) -> std::path::PathBuf {
|
||||
let a_parts: Vec<_> = a.components().collect();
|
||||
let b_parts: Vec<_> = b.components().collect();
|
||||
|
||||
let mut overlap = 0;
|
||||
for i in 0..=a_parts.len().min(b_parts.len()) {
|
||||
if a_parts[a_parts.len() - i..] == b_parts[..i] {
|
||||
overlap = i;
|
||||
}
|
||||
}
|
||||
|
||||
let mut result = std::path::PathBuf::new();
|
||||
for part in &a_parts {
|
||||
result.push(part.as_os_str());
|
||||
}
|
||||
for part in &b_parts[overlap..] {
|
||||
result.push(part.as_os_str());
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
fn main() {
|
||||
zlog::init();
|
||||
zlog::init_output_stderr();
|
||||
|
||||
let [crate_path, file_path] = [env!("CARGO_MANIFEST_DIR"), file!()].map(std::path::Path::new);
|
||||
let example_dir_abs_path = merge_paths(crate_path, file_path)
|
||||
.parent()
|
||||
.unwrap()
|
||||
.to_path_buf();
|
||||
|
||||
let app = gpui::Application::new().with_assets(assets::Assets);
|
||||
|
||||
let fs = Arc::new(fs::RealFs::new(None, app.background_executor()));
|
||||
@@ -14,15 +45,49 @@ fn main() {
|
||||
fs.clone(),
|
||||
paths::settings_file().clone(),
|
||||
);
|
||||
zlog::init();
|
||||
zlog::init_output_stderr();
|
||||
|
||||
app.run(move |cx| {
|
||||
<dyn fs::Fs>::set_global(fs.clone(), cx);
|
||||
settings::init(cx);
|
||||
theme::init(theme::LoadThemes::JustBase, cx);
|
||||
|
||||
client::init_settings(cx);
|
||||
workspace::init_settings(cx);
|
||||
project::Project::init_settings(cx);
|
||||
// production client because fake client requires gpui/test-support
|
||||
// and that causes issues with the real stuff we want to do
|
||||
let client = client::Client::production(cx);
|
||||
let user_store = cx.new(|cx| client::UserStore::new(client.clone(), cx));
|
||||
let languages = Arc::new(language::LanguageRegistry::new(
|
||||
cx.background_executor().clone(),
|
||||
));
|
||||
|
||||
client::init(&client, cx);
|
||||
|
||||
project::Project::init(&client, cx);
|
||||
|
||||
zlog::info!(
|
||||
"Creating fake worktree in {}",
|
||||
example_dir_abs_path.display(),
|
||||
);
|
||||
let project = project::Project::local(
|
||||
client.clone(),
|
||||
node_runtime::NodeRuntime::unavailable(),
|
||||
user_store,
|
||||
languages,
|
||||
fs.clone(),
|
||||
Some(Default::default()), // WARN: if None is passed here, prepare to be process bombed
|
||||
cx,
|
||||
);
|
||||
let worktree_task = project.update(cx, |project, cx| {
|
||||
project.create_worktree(example_dir_abs_path, true, cx)
|
||||
});
|
||||
cx.spawn(async move |_| {
|
||||
let worktree = worktree_task.await.unwrap();
|
||||
std::mem::forget(worktree);
|
||||
})
|
||||
.detach();
|
||||
std::mem::forget(project);
|
||||
|
||||
language::init(cx);
|
||||
editor::init(cx);
|
||||
menu::init();
|
||||
|
||||
@@ -200,7 +200,7 @@ struct SettingItem {
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
#[derive(Clone)]
|
||||
#[derive(Clone, PartialEq)]
|
||||
enum SettingsFile {
|
||||
User, // Uses all settings.
|
||||
Local((WorktreeId, Arc<Path>)), // Has a special name, and special set of settings
|
||||
@@ -216,11 +216,11 @@ impl SettingsFile {
|
||||
}
|
||||
}
|
||||
|
||||
fn name(&self) -> String {
|
||||
fn name(&self) -> SharedString {
|
||||
match self {
|
||||
SettingsFile::User => "User".to_string(),
|
||||
SettingsFile::Local((_, path)) => format!("Local ({})", path.display()),
|
||||
SettingsFile::Server(file) => format!("Server ({})", file),
|
||||
SettingsFile::User => SharedString::new_static("User"),
|
||||
SettingsFile::Local((_, path)) => format!("Local ({})", path.display()).into(),
|
||||
SettingsFile::Server(file) => format!("Server ({})", file).into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -234,22 +234,18 @@ impl SettingsWindow {
|
||||
editor
|
||||
});
|
||||
let mut this = Self {
|
||||
files: vec![
|
||||
SettingsFile::User,
|
||||
SettingsFile::Local((
|
||||
WorktreeId::from_usize(0),
|
||||
Arc::from(Path::new("/my-project/")),
|
||||
)),
|
||||
],
|
||||
files: vec![],
|
||||
current_file: current_file,
|
||||
pages: vec![],
|
||||
current_page: 0,
|
||||
search,
|
||||
};
|
||||
cx.observe_global_in::<SettingsStore>(window, move |_, _, cx| {
|
||||
cx.observe_global_in::<SettingsStore>(window, move |this, _, cx| {
|
||||
this.fetch_files(cx);
|
||||
cx.notify();
|
||||
})
|
||||
.detach();
|
||||
this.fetch_files(cx);
|
||||
|
||||
this.build_ui();
|
||||
this
|
||||
@@ -259,7 +255,36 @@ impl SettingsWindow {
|
||||
self.pages = self.current_file.pages();
|
||||
}
|
||||
|
||||
fn fetch_files(&mut self, cx: &mut App) {
|
||||
let settings_store = cx.global::<SettingsStore>();
|
||||
let mut ui_files = vec![];
|
||||
let all_files = settings_store.get_all_files();
|
||||
for file in all_files {
|
||||
let settings_ui_file = match file {
|
||||
settings::SettingsFile::User => SettingsFile::User,
|
||||
settings::SettingsFile::Global => continue,
|
||||
settings::SettingsFile::Extension => continue,
|
||||
settings::SettingsFile::Server => SettingsFile::Server("todo: server name"),
|
||||
settings::SettingsFile::Default => continue,
|
||||
settings::SettingsFile::Local(location) => SettingsFile::Local(location),
|
||||
};
|
||||
ui_files.push(settings_ui_file);
|
||||
}
|
||||
ui_files.reverse();
|
||||
if !ui_files.contains(&self.current_file) {
|
||||
self.change_file(0);
|
||||
}
|
||||
self.files = ui_files;
|
||||
}
|
||||
|
||||
fn change_file(&mut self, ix: usize) {
|
||||
if ix >= self.files.len() {
|
||||
self.current_file = SettingsFile::User;
|
||||
return;
|
||||
}
|
||||
if self.files[ix] == self.current_file {
|
||||
return;
|
||||
}
|
||||
self.current_file = self.files[ix].clone();
|
||||
self.build_ui();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user