From af26b627bf8540edc6eea4146acc081183f6241e Mon Sep 17 00:00:00 2001 From: Ben Kunkle Date: Sat, 30 Aug 2025 12:59:04 -0500 Subject: [PATCH] settings: Improve parse errors (#37234) Closes #ISSUE Adds a dependency on `serde_path_to_error` to the workspace allowing us to include the path to the setting that failed to parse on settings parse failure. Release Notes: - N/A *or* Added/Fixed/Improved ... --- Cargo.lock | 1 + Cargo.toml | 1 + crates/settings/Cargo.toml | 1 + crates/settings/src/settings_json.rs | 3 ++- crates/settings/src/settings_store.rs | 26 +++++++++++++++++++++++--- docs/src/visual-customization.md | 2 +- 6 files changed, 29 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 84d633dd6f126f1ce86cd73b83f9d1aac23c591e..a80809461e5135541b1223e7482310effa6cb50b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -14894,6 +14894,7 @@ dependencies = [ "serde_derive", "serde_json", "serde_json_lenient", + "serde_path_to_error", "settings_ui_macros", "smallvec", "tree-sitter", diff --git a/Cargo.toml b/Cargo.toml index b64113311adb2662562cc4ae488054f54d569c3e..48017d9c6b4858fb7e5415b92bd993e534d1fabb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -592,6 +592,7 @@ serde_json_lenient = { version = "0.2", features = [ "preserve_order", "raw_value", ] } +serde_path_to_error = "0.1.17" serde_repr = "0.1" serde_urlencoded = "0.7" sha2 = "0.10" diff --git a/crates/settings/Cargo.toml b/crates/settings/Cargo.toml index 8768b4073602461a5031b8d70d3a1e930ad2a41e..d9b8d7275f9abdd60df85443988595f025bf26c0 100644 --- a/crates/settings/Cargo.toml +++ b/crates/settings/Cargo.toml @@ -33,6 +33,7 @@ serde_derive.workspace = true serde_json.workspace = true settings_ui_macros.workspace = true serde_json_lenient.workspace = true +serde_path_to_error.workspace = true smallvec.workspace = true tree-sitter-json.workspace = true tree-sitter.workspace = true diff --git a/crates/settings/src/settings_json.rs b/crates/settings/src/settings_json.rs index b916df6e5c205c7fc2c0c920d0ac8343cb986a5c..480fe057eacb8d96255a3bf2d7b5f96208f87ced 100644 --- a/crates/settings/src/settings_json.rs +++ b/crates/settings/src/settings_json.rs @@ -563,7 +563,8 @@ pub fn to_pretty_json( } pub fn parse_json_with_comments(content: &str) -> Result { - Ok(serde_json_lenient::from_str(content)?) + let mut deserializer = serde_json_lenient::Deserializer::from_str(content); + Ok(serde_path_to_error::deserialize(&mut deserializer)?) } #[cfg(test)] diff --git a/crates/settings/src/settings_store.rs b/crates/settings/src/settings_store.rs index 09ac6f9766e32e7a0d8765b09919cd0f8c09866c..023f8cbfba3d96b0a6cad2e1c6ebb930f0bcdf9e 100644 --- a/crates/settings/src/settings_store.rs +++ b/crates/settings/src/settings_store.rs @@ -11,7 +11,7 @@ use gpui::{App, AsyncApp, BorrowAppContext, Global, SharedString, Task, UpdateGl use paths::{EDITORCONFIG_NAME, local_settings_file_relative_path, task_file_name}; use schemars::JsonSchema; -use serde::{Deserialize, Serialize, de::DeserializeOwned}; +use serde::{Serialize, de::DeserializeOwned}; use serde_json::{Value, json}; use smallvec::SmallVec; use std::{ @@ -1464,9 +1464,29 @@ impl AnySettingValue for SettingValue { return (T::KEY, Ok(DeserializedSetting(Box::new(value)))); } } - let value = T::FileContent::deserialize(json) + let value = serde_path_to_error::deserialize::<_, T::FileContent>(json) .map(|value| DeserializedSetting(Box::new(value))) - .map_err(anyhow::Error::from); + .map_err(|err| { + // construct a path using the key and reported error path if possible. + // Unfortunately, serde_path_to_error does not expose the necessary + // methods and data to simply add the key to the path + let mut path = String::new(); + if let Some(key) = key { + path.push_str(key); + } + let err_path = err.path().to_string(); + // when the path is empty, serde_path_to_error stringifies the path as ".", + // when the path is unknown, serde_path_to_error stringifies the path as an empty string + if !err_path.is_empty() && !err_path.starts_with(".") { + path.push('.'); + path.push_str(&err_path); + } + if path.is_empty() { + anyhow::Error::from(err.into_inner()) + } else { + anyhow::anyhow!("'{}': {}", err.into_inner(), path) + } + }); (key, value) } diff --git a/docs/src/visual-customization.md b/docs/src/visual-customization.md index 1df76d17f026c9457b296230f93bec0e10c4aa19..47c72e80f5ea0ca6ce8576e29c51ff9e44041eb5 100644 --- a/docs/src/visual-customization.md +++ b/docs/src/visual-customization.md @@ -8,7 +8,7 @@ See [Configuring Zed](./configuring-zed.md) for additional information and other Use may install zed extensions providing [Themes](./themes.md) and [Icon Themes](./icon-themes.md) via {#action zed::Extensions} from the command palette or menu. -You can preview/choose amongsts your installed themes and icon themes with {#action theme_selector::Toggle} ({#kb theme_selector::Toggle}) and ({#action icon_theme_selector::Toggle}) which will modify the following settings: +You can preview/choose amongst your installed themes and icon themes with {#action theme_selector::Toggle} ({#kb theme_selector::Toggle}) and ({#action icon_theme_selector::Toggle}) which will modify the following settings: ```json {