Skip to content
This repository was archived by the owner on Dec 29, 2022. It is now read-only.

Commit c06e0b1

Browse files
committed
Auto merge of #1298 - lijinpei:kebab-case, r=alexheretic
implement kebab case config support This pr tries to implement half of what's said in #1153 (reporting unused configs can be implemented in a separate pr). It introduces a new dependency on [heck](https://crates.io/crates/heck) for case conversion, add a little bit tweak to [struct Config in lsp_data.rs](https://github.com/lijinpei/rls/commit/cbeb77b03759cefe9091e4587aabb249adaff6c9#diff-5c71a9e04104a098c5f6e6f6af6a2ff5R249) so that Config'keys can be deserialized ignoring case(It basically first deserializes to a serde_json::Value, convert the case, then deserializes to the real struct Config), and add a few test-cases.
2 parents 7ad5329 + 4cc3e64 commit c06e0b1

File tree

6 files changed

+110
-9
lines changed

6 files changed

+110
-9
lines changed

Cargo.lock

Lines changed: 10 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ regex = "1"
5252
ordslice = "0.3"
5353
crossbeam-channel = "0.3"
5454
toml = "0.4"
55+
heck = "0.3"
5556

5657
# A noop dependency that changes in the Rust repository, it's a bit of a hack.
5758
# See the `src/tools/rustc-workspace-hack/README.md` file in `rust-lang/rust`

src/actions/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -306,7 +306,7 @@ impl InitActionContext {
306306
let needs_inference = {
307307
let mut config = self.config.lock().unwrap();
308308

309-
if let Some(init_config) = init_options.settings.map(|s| s.rust) {
309+
if let Some(init_config) = init_options.settings.map(|s| s.rust.0) {
310310
config.update(init_config);
311311
}
312312
config.needs_inference()

src/actions/notifications.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -150,17 +150,18 @@ impl BlockingNotificationAction for Cancel {
150150

151151
impl BlockingNotificationAction for DidChangeConfiguration {
152152
fn handle<O: Output>(
153-
params: DidChangeConfigurationParams,
153+
mut params: DidChangeConfigurationParams,
154154
ctx: &mut InitActionContext,
155155
out: O,
156156
) -> Result<(), ()> {
157157
trace!("config change: {:?}", params.settings);
158+
params.settings = crate::lsp_data::json_key_to_snake_case(params.settings);
158159
let settings = ChangeConfigSettings::deserialize(&params.settings);
159160

160161
let new_config = match settings {
161162
Ok(mut value) => {
162-
value.rust.normalise();
163-
value.rust
163+
value.rust.0.normalise();
164+
value.rust.0
164165
}
165166
Err(err) => {
166167
warn!(

src/lsp_data.rs

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -246,10 +246,31 @@ impl RangeExt for Range {
246246
}
247247
}
248248

249+
pub struct Config(pub config::Config);
250+
251+
impl<'de> serde::Deserialize<'de> for Config {
252+
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
253+
where
254+
D: serde::Deserializer<'de> {
255+
use serde::de::Error;
256+
let val = json_key_to_snake_case(serde_json::Value::deserialize(deserializer)?);
257+
match serde_json::from_value(val) {
258+
Ok(config) => Ok(Config(config)),
259+
_ => Err(D::Error::custom("unable to deserialize Config")),
260+
}
261+
}
262+
}
263+
264+
impl fmt::Debug for Config {
265+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
266+
fmt::Debug::fmt(&self.0, f)
267+
}
268+
}
269+
249270
/// `DidChangeConfigurationParams.settings` payload reading the { rust: {...} } bit.
250271
#[derive(Debug, Deserialize)]
251272
pub struct ChangeConfigSettings {
252-
pub rust: config::Config,
273+
pub rust: Config,
253274
}
254275

255276
/* ----------------- JSON-RPC protocol types ----------------- */
@@ -395,3 +416,29 @@ pub struct ProgressParams {
395416
#[serde(skip_serializing_if = "Option::is_none")]
396417
pub done: Option<bool>,
397418
}
419+
420+
pub fn json_key_to_snake_case(mut val: serde_json::Value) -> serde_json::Value {
421+
fn helper(val: &mut serde_json::Value) -> &mut serde_json::Value {
422+
use heck::SnakeCase;
423+
use serde_json::Value;
424+
match val {
425+
Value::Object(map) => {
426+
let mut map1 = serde_json::map::Map::<String, Value>::with_capacity(map.len());
427+
for kv in map.into_iter() {
428+
match map1.insert(kv.0.as_str().to_snake_case(), kv.1.clone()) {
429+
Some(val) => {
430+
log::error!("Multiple different case uses of `{}` config with value {} and value {}", kv.0, val, kv.1);
431+
}
432+
_ => (),
433+
}
434+
}
435+
std::mem::replace(map, map1);
436+
}
437+
_ => (),
438+
}
439+
val
440+
}
441+
helper(&mut val);
442+
val
443+
}
444+

tests/tests_old.rs

Lines changed: 46 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1105,8 +1105,35 @@ fn test_omit_init_build() {
11051105
);
11061106
}
11071107

1108-
#[test]
1109-
fn test_init_with_configuration() {
1108+
pub trait ConvertStringCase {
1109+
fn convert_string_case(s: &str) -> String;
1110+
}
1111+
1112+
struct CamelCaseConverter;
1113+
impl ConvertStringCase for CamelCaseConverter {
1114+
fn convert_string_case<'a>(s:&'a str) -> String {
1115+
use heck::CamelCase;
1116+
s.to_camel_case().to_string()
1117+
}
1118+
}
1119+
1120+
struct KebabCaseConverter;
1121+
impl ConvertStringCase for KebabCaseConverter {
1122+
fn convert_string_case<'a>(s:&'a str) -> String {
1123+
use heck::KebabCase;
1124+
s.to_kebab_case().to_string()
1125+
}
1126+
}
1127+
1128+
struct SnakeCaseConverter;
1129+
impl ConvertStringCase for SnakeCaseConverter {
1130+
fn convert_string_case<'a>(s:&'a str) -> String {
1131+
use heck::SnakeCase;
1132+
s.to_snake_case().to_string()
1133+
}
1134+
}
1135+
1136+
fn test_init_impl<T:ConvertStringCase>() {
11101137
use serde_json::json;
11111138

11121139
let mut env = Environment::generate_from_fixture("common");
@@ -1116,8 +1143,8 @@ fn test_init_with_configuration() {
11161143
let init_options = json!({
11171144
"settings": {
11181145
"rust": {
1119-
"features": ["some_feature"],
1120-
"all_targets": false
1146+
T::convert_string_case("features"): ["some_feature"],
1147+
T::convert_string_case("all_targets"): false
11211148
}
11221149
}
11231150
});
@@ -1145,6 +1172,21 @@ fn test_init_with_configuration() {
11451172
assert_eq!(config.lock().unwrap().all_targets, false);
11461173
}
11471174

1175+
#[test]
1176+
fn test_init_with_configuration_camel_case() {
1177+
test_init_impl::<CamelCaseConverter>();
1178+
}
1179+
1180+
#[test]
1181+
fn test_init_with_configuration_kebab_case() {
1182+
test_init_impl::<KebabCaseConverter>();
1183+
}
1184+
1185+
#[test]
1186+
fn test_init_with_configuration_snake_case() {
1187+
test_init_impl::<SnakeCaseConverter>();
1188+
}
1189+
11481190
#[test]
11491191
fn test_parse_error_on_malformed_input() {
11501192
let _ = env_logger::try_init();

0 commit comments

Comments
 (0)