diff options
Diffstat (limited to 'crates')
-rw-r--r-- | crates/hir/src/lib.rs | 40 | ||||
-rw-r--r-- | crates/ide_assists/src/handlers/generate_function.rs | 73 | ||||
-rw-r--r-- | crates/ide_completion/src/completions/postfix.rs | 14 | ||||
-rw-r--r-- | crates/rust-analyzer/src/config.rs | 48 | ||||
-rw-r--r-- | crates/syntax/Cargo.toml | 2 |
5 files changed, 124 insertions, 53 deletions
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index c4691d34c..d5a3d9034 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs | |||
@@ -812,13 +812,11 @@ impl Function { | |||
812 | /// Get this function's return type | 812 | /// Get this function's return type |
813 | pub fn ret_type(self, db: &dyn HirDatabase) -> Type { | 813 | pub fn ret_type(self, db: &dyn HirDatabase) -> Type { |
814 | let resolver = self.id.resolver(db.upcast()); | 814 | let resolver = self.id.resolver(db.upcast()); |
815 | let krate = self.id.lookup(db.upcast()).container.module(db.upcast()).krate(); | ||
815 | let ret_type = &db.function_data(self.id).ret_type; | 816 | let ret_type = &db.function_data(self.id).ret_type; |
816 | let ctx = hir_ty::TyLoweringContext::new(db, &resolver); | 817 | let ctx = hir_ty::TyLoweringContext::new(db, &resolver); |
817 | let environment = TraitEnvironment::lower(db, &resolver); | 818 | let ty = Ty::from_hir_ext(&ctx, ret_type).0; |
818 | Type { | 819 | Type::new_with_resolver_inner(db, krate, &resolver, ty) |
819 | krate: self.id.lookup(db.upcast()).container.module(db.upcast()).krate(), | ||
820 | ty: InEnvironment { value: Ty::from_hir_ext(&ctx, ret_type).0, environment }, | ||
821 | } | ||
822 | } | 820 | } |
823 | 821 | ||
824 | pub fn self_param(self, db: &dyn HirDatabase) -> Option<SelfParam> { | 822 | pub fn self_param(self, db: &dyn HirDatabase) -> Option<SelfParam> { |
@@ -830,6 +828,7 @@ impl Function { | |||
830 | 828 | ||
831 | pub fn assoc_fn_params(self, db: &dyn HirDatabase) -> Vec<Param> { | 829 | pub fn assoc_fn_params(self, db: &dyn HirDatabase) -> Vec<Param> { |
832 | let resolver = self.id.resolver(db.upcast()); | 830 | let resolver = self.id.resolver(db.upcast()); |
831 | let krate = self.id.lookup(db.upcast()).container.module(db.upcast()).krate(); | ||
833 | let ctx = hir_ty::TyLoweringContext::new(db, &resolver); | 832 | let ctx = hir_ty::TyLoweringContext::new(db, &resolver); |
834 | let environment = TraitEnvironment::lower(db, &resolver); | 833 | let environment = TraitEnvironment::lower(db, &resolver); |
835 | db.function_data(self.id) | 834 | db.function_data(self.id) |
@@ -837,7 +836,7 @@ impl Function { | |||
837 | .iter() | 836 | .iter() |
838 | .map(|type_ref| { | 837 | .map(|type_ref| { |
839 | let ty = Type { | 838 | let ty = Type { |
840 | krate: self.id.lookup(db.upcast()).container.module(db.upcast()).krate(), | 839 | krate, |
841 | ty: InEnvironment { | 840 | ty: InEnvironment { |
842 | value: Ty::from_hir_ext(&ctx, type_ref).0, | 841 | value: Ty::from_hir_ext(&ctx, type_ref).0, |
843 | environment: environment.clone(), | 842 | environment: environment.clone(), |
@@ -1403,12 +1402,9 @@ impl TypeParam { | |||
1403 | 1402 | ||
1404 | pub fn ty(self, db: &dyn HirDatabase) -> Type { | 1403 | pub fn ty(self, db: &dyn HirDatabase) -> Type { |
1405 | let resolver = self.id.parent.resolver(db.upcast()); | 1404 | let resolver = self.id.parent.resolver(db.upcast()); |
1406 | let environment = TraitEnvironment::lower(db, &resolver); | 1405 | let krate = self.id.parent.module(db.upcast()).krate(); |
1407 | let ty = Ty::Placeholder(self.id); | 1406 | let ty = Ty::Placeholder(self.id); |
1408 | Type { | 1407 | Type::new_with_resolver_inner(db, krate, &resolver, ty) |
1409 | krate: self.id.parent.module(db.upcast()).krate(), | ||
1410 | ty: InEnvironment { value: ty, environment }, | ||
1411 | } | ||
1412 | } | 1408 | } |
1413 | 1409 | ||
1414 | pub fn trait_bounds(self, db: &dyn HirDatabase) -> Vec<Trait> { | 1410 | pub fn trait_bounds(self, db: &dyn HirDatabase) -> Vec<Trait> { |
@@ -1427,14 +1423,11 @@ impl TypeParam { | |||
1427 | let params = db.generic_defaults(self.id.parent); | 1423 | let params = db.generic_defaults(self.id.parent); |
1428 | let local_idx = hir_ty::param_idx(db, self.id)?; | 1424 | let local_idx = hir_ty::param_idx(db, self.id)?; |
1429 | let resolver = self.id.parent.resolver(db.upcast()); | 1425 | let resolver = self.id.parent.resolver(db.upcast()); |
1430 | let environment = TraitEnvironment::lower(db, &resolver); | 1426 | let krate = self.id.parent.module(db.upcast()).krate(); |
1431 | let ty = params.get(local_idx)?.clone(); | 1427 | let ty = params.get(local_idx)?.clone(); |
1432 | let subst = Substs::type_params(db, self.id.parent); | 1428 | let subst = Substs::type_params(db, self.id.parent); |
1433 | let ty = ty.subst(&subst.prefix(local_idx)); | 1429 | let ty = ty.subst(&subst.prefix(local_idx)); |
1434 | Some(Type { | 1430 | Some(Type::new_with_resolver_inner(db, krate, &resolver, ty)) |
1435 | krate: self.id.parent.module(db.upcast()).krate(), | ||
1436 | ty: InEnvironment { value: ty, environment }, | ||
1437 | }) | ||
1438 | } | 1431 | } |
1439 | } | 1432 | } |
1440 | 1433 | ||
@@ -1523,13 +1516,10 @@ impl Impl { | |||
1523 | pub fn target_ty(self, db: &dyn HirDatabase) -> Type { | 1516 | pub fn target_ty(self, db: &dyn HirDatabase) -> Type { |
1524 | let impl_data = db.impl_data(self.id); | 1517 | let impl_data = db.impl_data(self.id); |
1525 | let resolver = self.id.resolver(db.upcast()); | 1518 | let resolver = self.id.resolver(db.upcast()); |
1519 | let krate = self.id.lookup(db.upcast()).container.module(db.upcast()).krate(); | ||
1526 | let ctx = hir_ty::TyLoweringContext::new(db, &resolver); | 1520 | let ctx = hir_ty::TyLoweringContext::new(db, &resolver); |
1527 | let environment = TraitEnvironment::lower(db, &resolver); | ||
1528 | let ty = Ty::from_hir(&ctx, &impl_data.target_type); | 1521 | let ty = Ty::from_hir(&ctx, &impl_data.target_type); |
1529 | Type { | 1522 | Type::new_with_resolver_inner(db, krate, &resolver, ty) |
1530 | krate: self.id.lookup(db.upcast()).container.module(db.upcast()).krate(), | ||
1531 | ty: InEnvironment { value: ty, environment }, | ||
1532 | } | ||
1533 | } | 1523 | } |
1534 | 1524 | ||
1535 | pub fn items(self, db: &dyn HirDatabase) -> Vec<AssocItem> { | 1525 | pub fn items(self, db: &dyn HirDatabase) -> Vec<AssocItem> { |
@@ -1725,13 +1715,11 @@ impl Type { | |||
1725 | }; | 1715 | }; |
1726 | 1716 | ||
1727 | match db.trait_solve(self.krate, goal)? { | 1717 | match db.trait_solve(self.krate, goal)? { |
1728 | Solution::Unique(SolutionVariables(subst)) => subst.value.first().cloned(), | 1718 | Solution::Unique(SolutionVariables(subst)) => { |
1719 | subst.value.first().map(|ty| self.derived(ty.clone())) | ||
1720 | } | ||
1729 | Solution::Ambig(_) => None, | 1721 | Solution::Ambig(_) => None, |
1730 | } | 1722 | } |
1731 | .map(|ty| Type { | ||
1732 | krate: self.krate, | ||
1733 | ty: InEnvironment { value: ty, environment: Arc::clone(&self.ty.environment) }, | ||
1734 | }) | ||
1735 | } | 1723 | } |
1736 | 1724 | ||
1737 | pub fn is_copy(&self, db: &dyn HirDatabase) -> bool { | 1725 | pub fn is_copy(&self, db: &dyn HirDatabase) -> bool { |
diff --git a/crates/ide_assists/src/handlers/generate_function.rs b/crates/ide_assists/src/handlers/generate_function.rs index 3870b7e75..6f95b1a07 100644 --- a/crates/ide_assists/src/handlers/generate_function.rs +++ b/crates/ide_assists/src/handlers/generate_function.rs | |||
@@ -83,17 +83,18 @@ struct FunctionTemplate { | |||
83 | leading_ws: String, | 83 | leading_ws: String, |
84 | fn_def: ast::Fn, | 84 | fn_def: ast::Fn, |
85 | ret_type: ast::RetType, | 85 | ret_type: ast::RetType, |
86 | should_render_snippet: bool, | ||
86 | trailing_ws: String, | 87 | trailing_ws: String, |
87 | file: FileId, | 88 | file: FileId, |
88 | } | 89 | } |
89 | 90 | ||
90 | impl FunctionTemplate { | 91 | impl FunctionTemplate { |
91 | fn to_string(&self, cap: Option<SnippetCap>) -> String { | 92 | fn to_string(&self, cap: Option<SnippetCap>) -> String { |
92 | let f = match cap { | 93 | let f = match (cap, self.should_render_snippet) { |
93 | Some(cap) => { | 94 | (Some(cap), true) => { |
94 | render_snippet(cap, self.fn_def.syntax(), Cursor::Replace(self.ret_type.syntax())) | 95 | render_snippet(cap, self.fn_def.syntax(), Cursor::Replace(self.ret_type.syntax())) |
95 | } | 96 | } |
96 | None => self.fn_def.to_string(), | 97 | _ => self.fn_def.to_string(), |
97 | }; | 98 | }; |
98 | format!("{}{}{}", self.leading_ws, f, self.trailing_ws) | 99 | format!("{}{}{}", self.leading_ws, f, self.trailing_ws) |
99 | } | 100 | } |
@@ -104,6 +105,8 @@ struct FunctionBuilder { | |||
104 | fn_name: ast::Name, | 105 | fn_name: ast::Name, |
105 | type_params: Option<ast::GenericParamList>, | 106 | type_params: Option<ast::GenericParamList>, |
106 | params: ast::ParamList, | 107 | params: ast::ParamList, |
108 | ret_type: ast::RetType, | ||
109 | should_render_snippet: bool, | ||
107 | file: FileId, | 110 | file: FileId, |
108 | needs_pub: bool, | 111 | needs_pub: bool, |
109 | } | 112 | } |
@@ -132,7 +135,43 @@ impl FunctionBuilder { | |||
132 | let fn_name = fn_name(&path)?; | 135 | let fn_name = fn_name(&path)?; |
133 | let (type_params, params) = fn_args(ctx, target_module, &call)?; | 136 | let (type_params, params) = fn_args(ctx, target_module, &call)?; |
134 | 137 | ||
135 | Some(Self { target, fn_name, type_params, params, file, needs_pub }) | 138 | // should_render_snippet intends to express a rough level of confidence about |
139 | // the correctness of the return type. | ||
140 | // | ||
141 | // If we are able to infer some return type, and that return type is not unit, we | ||
142 | // don't want to render the snippet. The assumption here is in this situation the | ||
143 | // return type is just as likely to be correct as any other part of the generated | ||
144 | // function. | ||
145 | // | ||
146 | // In the case where the return type is inferred as unit it is likely that the | ||
147 | // user does in fact intend for this generated function to return some non unit | ||
148 | // type, but that the current state of their code doesn't allow that return type | ||
149 | // to be accurately inferred. | ||
150 | let (ret_ty, should_render_snippet) = { | ||
151 | match ctx.sema.type_of_expr(&ast::Expr::CallExpr(call.clone())) { | ||
152 | Some(ty) if ty.is_unknown() || ty.is_unit() => (make::ty_unit(), true), | ||
153 | Some(ty) => { | ||
154 | let rendered = ty.display_source_code(ctx.db(), target_module.into()); | ||
155 | match rendered { | ||
156 | Ok(rendered) => (make::ty(&rendered), false), | ||
157 | Err(_) => (make::ty_unit(), true), | ||
158 | } | ||
159 | } | ||
160 | None => (make::ty_unit(), true), | ||
161 | } | ||
162 | }; | ||
163 | let ret_type = make::ret_type(ret_ty); | ||
164 | |||
165 | Some(Self { | ||
166 | target, | ||
167 | fn_name, | ||
168 | type_params, | ||
169 | params, | ||
170 | ret_type, | ||
171 | should_render_snippet, | ||
172 | file, | ||
173 | needs_pub, | ||
174 | }) | ||
136 | } | 175 | } |
137 | 176 | ||
138 | fn render(self) -> FunctionTemplate { | 177 | fn render(self) -> FunctionTemplate { |
@@ -145,7 +184,7 @@ impl FunctionBuilder { | |||
145 | self.type_params, | 184 | self.type_params, |
146 | self.params, | 185 | self.params, |
147 | fn_body, | 186 | fn_body, |
148 | Some(make::ret_type(make::ty_unit())), | 187 | Some(self.ret_type), |
149 | ); | 188 | ); |
150 | let leading_ws; | 189 | let leading_ws; |
151 | let trailing_ws; | 190 | let trailing_ws; |
@@ -171,6 +210,7 @@ impl FunctionBuilder { | |||
171 | insert_offset, | 210 | insert_offset, |
172 | leading_ws, | 211 | leading_ws, |
173 | ret_type: fn_def.ret_type().unwrap(), | 212 | ret_type: fn_def.ret_type().unwrap(), |
213 | should_render_snippet: self.should_render_snippet, | ||
174 | fn_def, | 214 | fn_def, |
175 | trailing_ws, | 215 | trailing_ws, |
176 | file: self.file, | 216 | file: self.file, |
@@ -546,7 +586,7 @@ impl Baz { | |||
546 | } | 586 | } |
547 | } | 587 | } |
548 | 588 | ||
549 | fn bar(baz: Baz) ${0:-> ()} { | 589 | fn bar(baz: Baz) -> Baz { |
550 | todo!() | 590 | todo!() |
551 | } | 591 | } |
552 | ", | 592 | ", |
@@ -1060,6 +1100,27 @@ pub(crate) fn bar() ${0:-> ()} { | |||
1060 | } | 1100 | } |
1061 | 1101 | ||
1062 | #[test] | 1102 | #[test] |
1103 | fn add_function_with_return_type() { | ||
1104 | check_assist( | ||
1105 | generate_function, | ||
1106 | r" | ||
1107 | fn main() { | ||
1108 | let x: u32 = foo$0(); | ||
1109 | } | ||
1110 | ", | ||
1111 | r" | ||
1112 | fn main() { | ||
1113 | let x: u32 = foo(); | ||
1114 | } | ||
1115 | |||
1116 | fn foo() -> u32 { | ||
1117 | todo!() | ||
1118 | } | ||
1119 | ", | ||
1120 | ) | ||
1121 | } | ||
1122 | |||
1123 | #[test] | ||
1063 | fn add_function_not_applicable_if_function_already_exists() { | 1124 | fn add_function_not_applicable_if_function_already_exists() { |
1064 | check_assist_not_applicable( | 1125 | check_assist_not_applicable( |
1065 | generate_function, | 1126 | generate_function, |
diff --git a/crates/ide_completion/src/completions/postfix.rs b/crates/ide_completion/src/completions/postfix.rs index 9c34ed0b6..d45ad7944 100644 --- a/crates/ide_completion/src/completions/postfix.rs +++ b/crates/ide_completion/src/completions/postfix.rs | |||
@@ -187,6 +187,16 @@ pub(crate) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) { | |||
187 | ctx, | 187 | ctx, |
188 | cap, | 188 | cap, |
189 | &dot_receiver, | 189 | &dot_receiver, |
190 | "err", | ||
191 | "Err(expr)", | ||
192 | &format!("Err({})", receiver_text), | ||
193 | ) | ||
194 | .add_to(acc); | ||
195 | |||
196 | postfix_snippet( | ||
197 | ctx, | ||
198 | cap, | ||
199 | &dot_receiver, | ||
190 | "some", | 200 | "some", |
191 | "Some(expr)", | 201 | "Some(expr)", |
192 | &format!("Some({})", receiver_text), | 202 | &format!("Some({})", receiver_text), |
@@ -325,6 +335,7 @@ fn main() { | |||
325 | sn match match expr {} | 335 | sn match match expr {} |
326 | sn box Box::new(expr) | 336 | sn box Box::new(expr) |
327 | sn ok Ok(expr) | 337 | sn ok Ok(expr) |
338 | sn err Err(expr) | ||
328 | sn some Some(expr) | 339 | sn some Some(expr) |
329 | sn dbg dbg!(expr) | 340 | sn dbg dbg!(expr) |
330 | sn dbgr dbg!(&expr) | 341 | sn dbgr dbg!(&expr) |
@@ -357,6 +368,7 @@ fn main() { | |||
357 | sn match match expr {} | 368 | sn match match expr {} |
358 | sn box Box::new(expr) | 369 | sn box Box::new(expr) |
359 | sn ok Ok(expr) | 370 | sn ok Ok(expr) |
371 | sn err Err(expr) | ||
360 | sn some Some(expr) | 372 | sn some Some(expr) |
361 | sn dbg dbg!(expr) | 373 | sn dbg dbg!(expr) |
362 | sn dbgr dbg!(&expr) | 374 | sn dbgr dbg!(&expr) |
@@ -380,6 +392,7 @@ fn main() { | |||
380 | sn match match expr {} | 392 | sn match match expr {} |
381 | sn box Box::new(expr) | 393 | sn box Box::new(expr) |
382 | sn ok Ok(expr) | 394 | sn ok Ok(expr) |
395 | sn err Err(expr) | ||
383 | sn some Some(expr) | 396 | sn some Some(expr) |
384 | sn dbg dbg!(expr) | 397 | sn dbg dbg!(expr) |
385 | sn dbgr dbg!(&expr) | 398 | sn dbgr dbg!(&expr) |
@@ -408,6 +421,7 @@ fn main() { | |||
408 | sn match match expr {} | 421 | sn match match expr {} |
409 | sn box Box::new(expr) | 422 | sn box Box::new(expr) |
410 | sn ok Ok(expr) | 423 | sn ok Ok(expr) |
424 | sn err Err(expr) | ||
411 | sn some Some(expr) | 425 | sn some Some(expr) |
412 | sn dbg dbg!(expr) | 426 | sn dbg dbg!(expr) |
413 | sn dbgr dbg!(&expr) | 427 | sn dbgr dbg!(&expr) |
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index 078c83f75..25df13554 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs | |||
@@ -16,7 +16,6 @@ use ide_db::helpers::{ | |||
16 | insert_use::{InsertUseConfig, MergeBehavior}, | 16 | insert_use::{InsertUseConfig, MergeBehavior}, |
17 | SnippetCap, | 17 | SnippetCap, |
18 | }; | 18 | }; |
19 | use itertools::Itertools; | ||
20 | use lsp_types::{ClientCapabilities, MarkupKind}; | 19 | use lsp_types::{ClientCapabilities, MarkupKind}; |
21 | use project_model::{CargoConfig, ProjectJson, ProjectJsonData, ProjectManifest, RustcSource}; | 20 | use project_model::{CargoConfig, ProjectJson, ProjectJsonData, ProjectManifest, RustcSource}; |
22 | use rustc_hash::FxHashSet; | 21 | use rustc_hash::FxHashSet; |
@@ -98,13 +97,15 @@ config_data! { | |||
98 | diagnostics_enableExperimental: bool = "true", | 97 | diagnostics_enableExperimental: bool = "true", |
99 | /// List of rust-analyzer diagnostics to disable. | 98 | /// List of rust-analyzer diagnostics to disable. |
100 | diagnostics_disabled: FxHashSet<String> = "[]", | 99 | diagnostics_disabled: FxHashSet<String> = "[]", |
101 | /// List of warnings that should be displayed with info severity.\n\nThe | 100 | /// List of warnings that should be displayed with info severity. |
102 | /// warnings will be indicated by a blue squiggly underline in code and | 101 | /// |
103 | /// a blue icon in the `Problems Panel`. | 102 | /// The warnings will be indicated by a blue squiggly underline in code |
103 | /// and a blue icon in the `Problems Panel`. | ||
104 | diagnostics_warningsAsHint: Vec<String> = "[]", | 104 | diagnostics_warningsAsHint: Vec<String> = "[]", |
105 | /// List of warnings that should be displayed with hint severity.\n\nThe | 105 | /// List of warnings that should be displayed with hint severity. |
106 | /// warnings will be indicated by faded text or three dots in code and | 106 | /// |
107 | /// will not show up in the `Problems Panel`. | 107 | /// The warnings will be indicated by faded text or three dots in code |
108 | /// and will not show up in the `Problems Panel`. | ||
108 | diagnostics_warningsAsInfo: Vec<String> = "[]", | 109 | diagnostics_warningsAsInfo: Vec<String> = "[]", |
109 | 110 | ||
110 | /// Controls file watching implementation. | 111 | /// Controls file watching implementation. |
@@ -158,7 +159,9 @@ config_data! { | |||
158 | lens_references: bool = "false", | 159 | lens_references: bool = "false", |
159 | 160 | ||
160 | /// Disable project auto-discovery in favor of explicitly specified set | 161 | /// Disable project auto-discovery in favor of explicitly specified set |
161 | /// of projects.\n\nElements must be paths pointing to `Cargo.toml`, | 162 | /// of projects. |
163 | /// | ||
164 | /// Elements must be paths pointing to `Cargo.toml`, | ||
162 | /// `rust-project.json`, or JSON objects in `rust-project.json` format. | 165 | /// `rust-project.json`, or JSON objects in `rust-project.json` format. |
163 | linkedProjects: Vec<ManifestOrProjectJson> = "[]", | 166 | linkedProjects: Vec<ManifestOrProjectJson> = "[]", |
164 | 167 | ||
@@ -177,13 +180,17 @@ config_data! { | |||
177 | /// Command to be executed instead of 'cargo' for runnables. | 180 | /// Command to be executed instead of 'cargo' for runnables. |
178 | runnables_overrideCargo: Option<String> = "null", | 181 | runnables_overrideCargo: Option<String> = "null", |
179 | /// Additional arguments to be passed to cargo for runnables such as | 182 | /// Additional arguments to be passed to cargo for runnables such as |
180 | /// tests or binaries.\nFor example, it may be `--release`. | 183 | /// tests or binaries. For example, it may be `--release`. |
181 | runnables_cargoExtraArgs: Vec<String> = "[]", | 184 | runnables_cargoExtraArgs: Vec<String> = "[]", |
182 | 185 | ||
183 | /// Path to the rust compiler sources, for usage in rustc_private projects, or "discover" | 186 | /// Path to the Cargo.toml of the rust compiler workspace, for usage in rustc_private |
184 | /// to try to automatically find it. Any project which uses rust-analyzer with the rustcPrivate | 187 | /// projects, or "discover" to try to automatically find it. |
188 | /// | ||
189 | /// Any project which uses rust-analyzer with the rustcPrivate | ||
185 | /// crates must set `[package.metadata.rust-analyzer] rustc_private=true` to use it. | 190 | /// crates must set `[package.metadata.rust-analyzer] rustc_private=true` to use it. |
186 | rustcSource : Option<String> = "null", | 191 | /// |
192 | /// This option is not reloaded automatically; you must restart rust-analyzer for it to take effect. | ||
193 | rustcSource: Option<String> = "null", | ||
187 | 194 | ||
188 | /// Additional arguments to `rustfmt`. | 195 | /// Additional arguments to `rustfmt`. |
189 | rustfmt_extraArgs: Vec<String> = "[]", | 196 | rustfmt_extraArgs: Vec<String> = "[]", |
@@ -761,7 +768,8 @@ fn schema(fields: &[(&'static str, &'static str, &[&str], &str)]) -> serde_json: | |||
761 | } | 768 | } |
762 | 769 | ||
763 | fn field_props(field: &str, ty: &str, doc: &[&str], default: &str) -> serde_json::Value { | 770 | fn field_props(field: &str, ty: &str, doc: &[&str], default: &str) -> serde_json::Value { |
764 | let doc = doc.iter().map(|it| it.trim()).join(" "); | 771 | let doc = doc_comment_to_string(doc); |
772 | let doc = doc.trim_end_matches('\n'); | ||
765 | assert!( | 773 | assert!( |
766 | doc.ends_with('.') && doc.starts_with(char::is_uppercase), | 774 | doc.ends_with('.') && doc.starts_with(char::is_uppercase), |
767 | "bad docs for {}: {:?}", | 775 | "bad docs for {}: {:?}", |
@@ -850,11 +858,16 @@ fn manual(fields: &[(&'static str, &'static str, &[&str], &str)]) -> String { | |||
850 | .iter() | 858 | .iter() |
851 | .map(|(field, _ty, doc, default)| { | 859 | .map(|(field, _ty, doc, default)| { |
852 | let name = format!("rust-analyzer.{}", field.replace("_", ".")); | 860 | let name = format!("rust-analyzer.{}", field.replace("_", ".")); |
853 | format!("[[{}]]{} (default: `{}`)::\n{}\n", name, name, default, doc.join(" ")) | 861 | let doc = doc_comment_to_string(*doc); |
862 | format!("[[{}]]{} (default: `{}`)::\n+\n--\n{}--\n", name, name, default, doc) | ||
854 | }) | 863 | }) |
855 | .collect::<String>() | 864 | .collect::<String>() |
856 | } | 865 | } |
857 | 866 | ||
867 | fn doc_comment_to_string(doc: &[&str]) -> String { | ||
868 | doc.iter().map(|it| it.strip_prefix(' ').unwrap_or(it)).map(|it| format!("{}\n", it)).collect() | ||
869 | } | ||
870 | |||
858 | #[cfg(test)] | 871 | #[cfg(test)] |
859 | mod tests { | 872 | mod tests { |
860 | use std::fs; | 873 | use std::fs; |
@@ -897,13 +910,8 @@ mod tests { | |||
897 | #[test] | 910 | #[test] |
898 | fn generate_config_documentation() { | 911 | fn generate_config_documentation() { |
899 | let docs_path = project_root().join("docs/user/generated_config.adoc"); | 912 | let docs_path = project_root().join("docs/user/generated_config.adoc"); |
900 | let current = fs::read_to_string(&docs_path).unwrap(); | ||
901 | let expected = ConfigData::manual(); | 913 | let expected = ConfigData::manual(); |
902 | 914 | ensure_file_contents(&docs_path, &expected); | |
903 | if remove_ws(¤t) != remove_ws(&expected) { | ||
904 | fs::write(&docs_path, expected).unwrap(); | ||
905 | panic!("updated config manual"); | ||
906 | } | ||
907 | } | 915 | } |
908 | 916 | ||
909 | fn remove_ws(text: &str) -> String { | 917 | fn remove_ws(text: &str) -> String { |
diff --git a/crates/syntax/Cargo.toml b/crates/syntax/Cargo.toml index c39095def..33bde099b 100644 --- a/crates/syntax/Cargo.toml +++ b/crates/syntax/Cargo.toml | |||
@@ -25,10 +25,10 @@ serde = { version = "1.0.106", features = ["derive"] } | |||
25 | stdx = { path = "../stdx", version = "0.0.0" } | 25 | stdx = { path = "../stdx", version = "0.0.0" } |
26 | text_edit = { path = "../text_edit", version = "0.0.0" } | 26 | text_edit = { path = "../text_edit", version = "0.0.0" } |
27 | parser = { path = "../parser", version = "0.0.0" } | 27 | parser = { path = "../parser", version = "0.0.0" } |
28 | test_utils = { path = "../test_utils", version = "0.0.0" } | ||
29 | profile = { path = "../profile", version = "0.0.0" } | 28 | profile = { path = "../profile", version = "0.0.0" } |
30 | 29 | ||
31 | [dev-dependencies] | 30 | [dev-dependencies] |
31 | test_utils = { path = "../test_utils" } | ||
32 | walkdir = "2.3.1" | 32 | walkdir = "2.3.1" |
33 | rayon = "1" | 33 | rayon = "1" |
34 | expect-test = "1.1" | 34 | expect-test = "1.1" |