settings: Show notification when user/project settings fail to parse (#18122)

Closes #16876

We only ever showed parsing errors, but not if something failed to
deserialize.

Basically, if you had a stray `,` somewhere, we'd show a notification
for user errors, but only squiggly lines if you had a `[]` instead of a
`{}`.

The squiggly lines would only show up when there were schema errors.

In the case of `formatter` settings, for example, if someone put in a
`{}` instead of `[]`, we'd never show anything.

With this change we always show a notification if parsing user or
project settings fails.

(Right now, the error message might still be bad, but that's a separate
change)


Release Notes:

- Added a notification to warn users if their user settings or
project-local settings failed to deserialize.

Demo:


https://github.com/user-attachments/assets/e5c48165-f2f7-4b5c-9c6d-6ea74f678683
This commit is contained in:
Thorsten Ball 2024-09-20 10:53:06 +02:00 committed by GitHub
parent 93730983dd
commit ace4d5185d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 172 additions and 50 deletions

View file

@ -1,11 +1,11 @@
use collections::HashMap;
use fs::Fs;
use gpui::{AppContext, AsyncAppContext, BorrowAppContext, Model, ModelContext};
use gpui::{AppContext, AsyncAppContext, BorrowAppContext, EventEmitter, Model, ModelContext};
use paths::local_settings_file_relative_path;
use rpc::{proto, AnyProtoClient, TypedEnvelope};
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use settings::{Settings, SettingsSources, SettingsStore};
use settings::{InvalidSettingsError, Settings, SettingsSources, SettingsStore};
use std::{
path::{Path, PathBuf},
sync::Arc,
@ -176,6 +176,13 @@ pub enum SettingsObserverMode {
Remote,
}
#[derive(Clone, Debug, PartialEq)]
pub enum SettingsObserverEvent {
LocalSettingsUpdated(Result<(), InvalidSettingsError>),
}
impl EventEmitter<SettingsObserverEvent> for SettingsObserver {}
pub struct SettingsObserver {
mode: SettingsObserverMode,
downstream_client: Option<AnyProtoClient>,
@ -415,11 +422,16 @@ impl SettingsObserver {
) {
let worktree_id = worktree.read(cx).id();
let remote_worktree_id = worktree.read(cx).id();
cx.update_global::<SettingsStore, _>(|store, cx| {
let result = cx.update_global::<SettingsStore, anyhow::Result<()>>(|store, cx| {
for (directory, file_content) in settings_contents {
store
.set_local_settings(worktree_id, directory.clone(), file_content.as_deref(), cx)
.log_err();
store.set_local_settings(
worktree_id,
directory.clone(),
file_content.as_deref(),
cx,
)?;
if let Some(downstream_client) = &self.downstream_client {
downstream_client
.send(proto::UpdateWorktreeSettings {
@ -431,6 +443,25 @@ impl SettingsObserver {
.log_err();
}
}
})
anyhow::Ok(())
});
match result {
Err(error) => {
if let Ok(error) = error.downcast::<InvalidSettingsError>() {
if let InvalidSettingsError::LocalSettings {
ref path,
ref message,
} = error
{
log::error!("Failed to set local settings in {:?}: {:?}", path, message);
cx.emit(SettingsObserverEvent::LocalSettingsUpdated(Err(error)));
}
}
}
Ok(()) => {
cx.emit(SettingsObserverEvent::LocalSettingsUpdated(Ok(())));
}
}
}
}