aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2020-03-24 23:28:57 +0000
committerGitHub <[email protected]>2020-03-24 23:28:57 +0000
commit6ad1a0711631d8017791a6dfe85bbe205d6c7414 (patch)
treece2d6448ff8770c8fe73086eefb85dab38d298d8
parentfae627174aecae0b4f4d2c087a856eda1a97a1ac (diff)
parent7b35da04bf56a5461321a6dca515dcd29f44b57f (diff)
Merge #3710
3710: Inlay hints for method chaining pattern r=matklad a=M-J-Hooper This PR adds inlay hints on method call chains: ![image](https://user-images.githubusercontent.com/13765376/77472008-8dc2a880-6e13-11ea-9c18-2c2e2b809799.png) It is not only explicit `MethodCall`s where this can be helpful. The heuristic used here is that whenever any expression is followed by a new line and then a dot, it resembles a call chain and type information can be #useful. Changes: - A new `InlayKind` for chaining. - New option for disabling this type of hints. - Tree traversal rules for identifying the chaining hints. - VSCode decorators in the extension layer (and associated types). Notes: - IntelliJ has additional rules and configuration on this topic. Eg. minimum length of chain to start displaying hints and only displaying distinct types in the chain. - I am checking for chaining on every `ast::Expr` in the tree; Are there performance concerns there? This is my first contribution (to RA and to Rust in general) so would appreciate any feedback. The only issue I can find the references this feature is #2741. Co-authored-by: Matt Hooper <[email protected]>
-rw-r--r--crates/ra_ide/src/inlay_hints.rs176
-rw-r--r--crates/rust-analyzer/src/config.rs3
-rw-r--r--crates/rust-analyzer/src/conv.rs1
-rw-r--r--crates/rust-analyzer/src/main_loop.rs1
-rw-r--r--crates/rust-analyzer/src/req.rs1
-rw-r--r--docs/user/features.md2
-rw-r--r--editors/code/package.json5
-rw-r--r--editors/code/src/client.ts1
-rw-r--r--editors/code/src/config.ts1
-rw-r--r--editors/code/src/inlay_hints.ts32
-rw-r--r--editors/code/src/rust-analyzer-api.ts4
11 files changed, 218 insertions, 9 deletions
diff --git a/crates/ra_ide/src/inlay_hints.rs b/crates/ra_ide/src/inlay_hints.rs
index ecd615cf4..f4f0751c0 100644
--- a/crates/ra_ide/src/inlay_hints.rs
+++ b/crates/ra_ide/src/inlay_hints.rs
@@ -5,7 +5,7 @@ use ra_ide_db::RootDatabase;
5use ra_prof::profile; 5use ra_prof::profile;
6use ra_syntax::{ 6use ra_syntax::{
7 ast::{self, ArgListOwner, AstNode, TypeAscriptionOwner}, 7 ast::{self, ArgListOwner, AstNode, TypeAscriptionOwner},
8 match_ast, SmolStr, TextRange, 8 match_ast, Direction, NodeOrToken, SmolStr, SyntaxKind, TextRange,
9}; 9};
10 10
11use crate::{FileId, FunctionSignature}; 11use crate::{FileId, FunctionSignature};
@@ -14,12 +14,13 @@ use crate::{FileId, FunctionSignature};
14pub struct InlayHintsOptions { 14pub struct InlayHintsOptions {
15 pub type_hints: bool, 15 pub type_hints: bool,
16 pub parameter_hints: bool, 16 pub parameter_hints: bool,
17 pub chaining_hints: bool,
17 pub max_length: Option<usize>, 18 pub max_length: Option<usize>,
18} 19}
19 20
20impl Default for InlayHintsOptions { 21impl Default for InlayHintsOptions {
21 fn default() -> Self { 22 fn default() -> Self {
22 Self { type_hints: true, parameter_hints: true, max_length: None } 23 Self { type_hints: true, parameter_hints: true, chaining_hints: true, max_length: None }
23 } 24 }
24} 25}
25 26
@@ -27,6 +28,7 @@ impl Default for InlayHintsOptions {
27pub enum InlayKind { 28pub enum InlayKind {
28 TypeHint, 29 TypeHint,
29 ParameterHint, 30 ParameterHint,
31 ChainingHint,
30} 32}
31 33
32#[derive(Debug)] 34#[derive(Debug)]
@@ -47,6 +49,10 @@ pub(crate) fn inlay_hints(
47 49
48 let mut res = Vec::new(); 50 let mut res = Vec::new();
49 for node in file.syntax().descendants() { 51 for node in file.syntax().descendants() {
52 if let Some(expr) = ast::Expr::cast(node.clone()) {
53 get_chaining_hints(&mut res, &sema, options, expr);
54 }
55
50 match_ast! { 56 match_ast! {
51 match node { 57 match node {
52 ast::CallExpr(it) => { get_param_name_hints(&mut res, &sema, options, ast::Expr::from(it)); }, 58 ast::CallExpr(it) => { get_param_name_hints(&mut res, &sema, options, ast::Expr::from(it)); },
@@ -59,6 +65,46 @@ pub(crate) fn inlay_hints(
59 res 65 res
60} 66}
61 67
68fn get_chaining_hints(
69 acc: &mut Vec<InlayHint>,
70 sema: &Semantics<RootDatabase>,
71 options: &InlayHintsOptions,
72 expr: ast::Expr,
73) -> Option<()> {
74 if !options.chaining_hints {
75 return None;
76 }
77
78 let ty = sema.type_of_expr(&expr)?;
79 if ty.is_unknown() {
80 return None;
81 }
82
83 let mut tokens = expr
84 .syntax()
85 .siblings_with_tokens(Direction::Next)
86 .filter_map(NodeOrToken::into_token)
87 .filter(|t| match t.kind() {
88 SyntaxKind::WHITESPACE if !t.text().contains('\n') => false,
89 SyntaxKind::COMMENT => false,
90 _ => true,
91 });
92
93 // Chaining can be defined as an expression whose next sibling tokens are newline and dot
94 // Ignoring extra whitespace and comments
95 let next = tokens.next()?.kind();
96 let next_next = tokens.next()?.kind();
97 if next == SyntaxKind::WHITESPACE && next_next == SyntaxKind::DOT {
98 let label = ty.display_truncated(sema.db, options.max_length).to_string();
99 acc.push(InlayHint {
100 range: expr.syntax().text_range(),
101 kind: InlayKind::ChainingHint,
102 label: label.into(),
103 });
104 }
105 Some(())
106}
107
62fn get_param_name_hints( 108fn get_param_name_hints(
63 acc: &mut Vec<InlayHint>, 109 acc: &mut Vec<InlayHint>,
64 sema: &Semantics<RootDatabase>, 110 sema: &Semantics<RootDatabase>,
@@ -238,7 +284,7 @@ mod tests {
238 let _x = foo(4, 4); 284 let _x = foo(4, 4);
239 }"#, 285 }"#,
240 ); 286 );
241 assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsOptions{ parameter_hints: true, type_hints: false, max_length: None}).unwrap(), @r###" 287 assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsOptions{ parameter_hints: true, type_hints: false, chaining_hints: false, max_length: None}).unwrap(), @r###"
242 [ 288 [
243 InlayHint { 289 InlayHint {
244 range: [106; 107), 290 range: [106; 107),
@@ -262,7 +308,7 @@ mod tests {
262 let _x = foo(4, 4); 308 let _x = foo(4, 4);
263 }"#, 309 }"#,
264 ); 310 );
265 assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsOptions{ type_hints: false, parameter_hints: false, max_length: None}).unwrap(), @r###"[]"###); 311 assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsOptions{ type_hints: false, parameter_hints: false, chaining_hints: false, max_length: None}).unwrap(), @r###"[]"###);
266 } 312 }
267 313
268 #[test] 314 #[test]
@@ -274,7 +320,7 @@ mod tests {
274 let _x = foo(4, 4); 320 let _x = foo(4, 4);
275 }"#, 321 }"#,
276 ); 322 );
277 assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsOptions{ type_hints: true, parameter_hints: false, max_length: None}).unwrap(), @r###" 323 assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsOptions{ type_hints: true, parameter_hints: false, chaining_hints: false, max_length: None}).unwrap(), @r###"
278 [ 324 [
279 InlayHint { 325 InlayHint {
280 range: [97; 99), 326 range: [97; 99),
@@ -1052,4 +1098,124 @@ fn main() {
1052 "### 1098 "###
1053 ); 1099 );
1054 } 1100 }
1101
1102 #[test]
1103 fn chaining_hints_ignore_comments() {
1104 let (analysis, file_id) = single_file(
1105 r#"
1106 struct A(B);
1107 impl A { fn into_b(self) -> B { self.0 } }
1108 struct B(C);
1109 impl B { fn into_c(self) -> C { self.0 } }
1110 struct C;
1111
1112 fn main() {
1113 let c = A(B(C))
1114 .into_b() // This is a comment
1115 .into_c();
1116 }"#,
1117 );
1118 assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsOptions{ parameter_hints: false, type_hints: false, chaining_hints: true, max_length: None}).unwrap(), @r###"
1119 [
1120 InlayHint {
1121 range: [232; 269),
1122 kind: ChainingHint,
1123 label: "B",
1124 },
1125 InlayHint {
1126 range: [232; 239),
1127 kind: ChainingHint,
1128 label: "A",
1129 },
1130 ]"###);
1131 }
1132
1133 #[test]
1134 fn chaining_hints_without_newlines() {
1135 let (analysis, file_id) = single_file(
1136 r#"
1137 struct A(B);
1138 impl A { fn into_b(self) -> B { self.0 } }
1139 struct B(C);
1140 impl B { fn into_c(self) -> C { self.0 } }
1141 struct C;
1142
1143 fn main() {
1144 let c = A(B(C)).into_b().into_c();
1145 }"#,
1146 );
1147 assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsOptions{ parameter_hints: false, type_hints: false, chaining_hints: true, max_length: None}).unwrap(), @r###"[]"###);
1148 }
1149
1150 #[test]
1151 fn struct_access_chaining_hints() {
1152 let (analysis, file_id) = single_file(
1153 r#"
1154 struct A { pub b: B }
1155 struct B { pub c: C }
1156 struct C(pub bool);
1157
1158 fn main() {
1159 let x = A { b: B { c: C(true) } }
1160 .b
1161 .c
1162 .0;
1163 }"#,
1164 );
1165 assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsOptions{ parameter_hints: false, type_hints: false, chaining_hints: true, max_length: None}).unwrap(), @r###"
1166 [
1167 InlayHint {
1168 range: [150; 221),
1169 kind: ChainingHint,
1170 label: "C",
1171 },
1172 InlayHint {
1173 range: [150; 198),
1174 kind: ChainingHint,
1175 label: "B",
1176 },
1177 InlayHint {
1178 range: [150; 175),
1179 kind: ChainingHint,
1180 label: "A",
1181 },
1182 ]"###);
1183 }
1184
1185 #[test]
1186 fn generic_chaining_hints() {
1187 let (analysis, file_id) = single_file(
1188 r#"
1189 struct A<T>(T);
1190 struct B<T>(T);
1191 struct C<T>(T);
1192 struct X<T,R>(T, R);
1193
1194 impl<T> A<T> {
1195 fn new(t: T) -> Self { A(t) }
1196 fn into_b(self) -> B<T> { B(self.0) }
1197 }
1198 impl<T> B<T> {
1199 fn into_c(self) -> C<T> { C(self.0) }
1200 }
1201 fn main() {
1202 let c = A::new(X(42, true))
1203 .into_b()
1204 .into_c();
1205 }"#,
1206 );
1207 assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsOptions{ parameter_hints: false, type_hints: false, chaining_hints: true, max_length: None}).unwrap(), @r###"
1208 [
1209 InlayHint {
1210 range: [403; 452),
1211 kind: ChainingHint,
1212 label: "B<X<i32, bool>>",
1213 },
1214 InlayHint {
1215 range: [403; 422),
1216 kind: ChainingHint,
1217 label: "A<X<i32, bool>>",
1218 },
1219 ]"###);
1220 }
1055} 1221}
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs
index 103b2b53c..628ed107e 100644
--- a/crates/rust-analyzer/src/config.rs
+++ b/crates/rust-analyzer/src/config.rs
@@ -34,6 +34,8 @@ pub struct ServerConfig {
34 pub inlay_hints_type: bool, 34 pub inlay_hints_type: bool,
35 #[serde(deserialize_with = "nullable_bool_true")] 35 #[serde(deserialize_with = "nullable_bool_true")]
36 pub inlay_hints_parameter: bool, 36 pub inlay_hints_parameter: bool,
37 #[serde(deserialize_with = "nullable_bool_true")]
38 pub inlay_hints_chaining: bool,
37 pub inlay_hints_max_length: Option<usize>, 39 pub inlay_hints_max_length: Option<usize>,
38 40
39 pub cargo_watch_enable: bool, 41 pub cargo_watch_enable: bool,
@@ -66,6 +68,7 @@ impl Default for ServerConfig {
66 lru_capacity: None, 68 lru_capacity: None,
67 inlay_hints_type: true, 69 inlay_hints_type: true,
68 inlay_hints_parameter: true, 70 inlay_hints_parameter: true,
71 inlay_hints_chaining: true,
69 inlay_hints_max_length: None, 72 inlay_hints_max_length: None,
70 cargo_watch_enable: true, 73 cargo_watch_enable: true,
71 cargo_watch_args: Vec::new(), 74 cargo_watch_args: Vec::new(),
diff --git a/crates/rust-analyzer/src/conv.rs b/crates/rust-analyzer/src/conv.rs
index fd4657d7e..6edc03fe0 100644
--- a/crates/rust-analyzer/src/conv.rs
+++ b/crates/rust-analyzer/src/conv.rs
@@ -332,6 +332,7 @@ impl ConvWith<&LineIndex> for InlayHint {
332 kind: match self.kind { 332 kind: match self.kind {
333 InlayKind::ParameterHint => req::InlayKind::ParameterHint, 333 InlayKind::ParameterHint => req::InlayKind::ParameterHint,
334 InlayKind::TypeHint => req::InlayKind::TypeHint, 334 InlayKind::TypeHint => req::InlayKind::TypeHint,
335 InlayKind::ChainingHint => req::InlayKind::ChainingHint,
335 }, 336 },
336 } 337 }
337 } 338 }
diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs
index a8a5894d2..7825b0077 100644
--- a/crates/rust-analyzer/src/main_loop.rs
+++ b/crates/rust-analyzer/src/main_loop.rs
@@ -183,6 +183,7 @@ pub fn main_loop(
183 inlay_hints: InlayHintsOptions { 183 inlay_hints: InlayHintsOptions {
184 type_hints: config.inlay_hints_type, 184 type_hints: config.inlay_hints_type,
185 parameter_hints: config.inlay_hints_parameter, 185 parameter_hints: config.inlay_hints_parameter,
186 chaining_hints: config.inlay_hints_chaining,
186 max_length: config.inlay_hints_max_length, 187 max_length: config.inlay_hints_max_length,
187 }, 188 },
188 cargo_watch: CheckOptions { 189 cargo_watch: CheckOptions {
diff --git a/crates/rust-analyzer/src/req.rs b/crates/rust-analyzer/src/req.rs
index 9e27d3f1c..8557294f6 100644
--- a/crates/rust-analyzer/src/req.rs
+++ b/crates/rust-analyzer/src/req.rs
@@ -200,6 +200,7 @@ pub struct InlayHintsParams {
200pub enum InlayKind { 200pub enum InlayKind {
201 TypeHint, 201 TypeHint,
202 ParameterHint, 202 ParameterHint,
203 ChainingHint,
203} 204}
204 205
205#[derive(Debug, Deserialize, Serialize)] 206#[derive(Debug, Deserialize, Serialize)]
diff --git a/docs/user/features.md b/docs/user/features.md
index 45360c633..56d2969fd 100644
--- a/docs/user/features.md
+++ b/docs/user/features.md
@@ -185,6 +185,7 @@ These contain extended information on the hovered language item.
185Two types of inlay hints are displayed currently: 185Two types of inlay hints are displayed currently:
186 186
187* type hints, displaying the minimal information on the type of the expression (if the information is available) 187* type hints, displaying the minimal information on the type of the expression (if the information is available)
188* method chaining hints, type information for multi-line method chains
188* parameter name hints, displaying the names of the parameters in the corresponding methods 189* parameter name hints, displaying the names of the parameters in the corresponding methods
189 190
190#### VS Code 191#### VS Code
@@ -192,6 +193,7 @@ Two types of inlay hints are displayed currently:
192In VS Code, the following settings can be used to configure the inlay hints: 193In VS Code, the following settings can be used to configure the inlay hints:
193 194
194* `rust-analyzer.inlayHints.typeHints` - enable hints for inferred types. 195* `rust-analyzer.inlayHints.typeHints` - enable hints for inferred types.
196* `rust-analyzer.inlayHints.chainingHints` - enable hints for inferred types on method chains.
195* `rust-analyzer.inlayHints.parameterHints` - enable hints for function parameters. 197* `rust-analyzer.inlayHints.parameterHints` - enable hints for function parameters.
196* `rust-analyzer.inlayHints.maxLength` — shortens the hints if their length exceeds the value specified. If no value is specified (`null`), no shortening is applied. 198* `rust-analyzer.inlayHints.maxLength` — shortens the hints if their length exceeds the value specified. If no value is specified (`null`), no shortening is applied.
197 199
diff --git a/editors/code/package.json b/editors/code/package.json
index 1d113ebb6..37e083220 100644
--- a/editors/code/package.json
+++ b/editors/code/package.json
@@ -333,6 +333,11 @@
333 "default": true, 333 "default": true,
334 "description": "Whether to show inlay type hints" 334 "description": "Whether to show inlay type hints"
335 }, 335 },
336 "rust-analyzer.inlayHints.chainingHints": {
337 "type": "boolean",
338 "default": true,
339 "description": "Whether to show inlay type hints for method chains"
340 },
336 "rust-analyzer.inlayHints.parameterHints": { 341 "rust-analyzer.inlayHints.parameterHints": {
337 "type": "boolean", 342 "type": "boolean",
338 "default": true, 343 "default": true,
diff --git a/editors/code/src/client.ts b/editors/code/src/client.ts
index 82ca749f3..98f2f232f 100644
--- a/editors/code/src/client.ts
+++ b/editors/code/src/client.ts
@@ -32,6 +32,7 @@ export async function createClient(config: Config, serverPath: string): Promise<
32 32
33 inlayHintsType: config.inlayHints.typeHints, 33 inlayHintsType: config.inlayHints.typeHints,
34 inlayHintsParameter: config.inlayHints.parameterHints, 34 inlayHintsParameter: config.inlayHints.parameterHints,
35 inlayHintsChaining: config.inlayHints.chainingHints,
35 inlayHintsMaxLength: config.inlayHints.maxLength, 36 inlayHintsMaxLength: config.inlayHints.maxLength,
36 37
37 cargoWatchEnable: cargoWatchOpts.enable, 38 cargoWatchEnable: cargoWatchOpts.enable,
diff --git a/editors/code/src/config.ts b/editors/code/src/config.ts
index 7668c20b7..637aea27d 100644
--- a/editors/code/src/config.ts
+++ b/editors/code/src/config.ts
@@ -88,6 +88,7 @@ export class Config {
88 return { 88 return {
89 typeHints: this.cfg.get<boolean>("inlayHints.typeHints")!, 89 typeHints: this.cfg.get<boolean>("inlayHints.typeHints")!,
90 parameterHints: this.cfg.get<boolean>("inlayHints.parameterHints")!, 90 parameterHints: this.cfg.get<boolean>("inlayHints.parameterHints")!,
91 chainingHints: this.cfg.get<boolean>("inlayHints.chainingHints")!,
91 maxLength: this.cfg.get<null | number>("inlayHints.maxLength")!, 92 maxLength: this.cfg.get<null | number>("inlayHints.maxLength")!,
92 }; 93 };
93 } 94 }
diff --git a/editors/code/src/inlay_hints.ts b/editors/code/src/inlay_hints.ts
index 17d0dfa33..542d1f367 100644
--- a/editors/code/src/inlay_hints.ts
+++ b/editors/code/src/inlay_hints.ts
@@ -10,7 +10,11 @@ export function activateInlayHints(ctx: Ctx) {
10 const maybeUpdater = { 10 const maybeUpdater = {
11 updater: null as null | HintsUpdater, 11 updater: null as null | HintsUpdater,
12 onConfigChange() { 12 onConfigChange() {
13 if (!ctx.config.inlayHints.typeHints && !ctx.config.inlayHints.parameterHints) { 13 if (
14 !ctx.config.inlayHints.typeHints &&
15 !ctx.config.inlayHints.parameterHints &&
16 !ctx.config.inlayHints.chainingHints
17 ) {
14 return this.dispose(); 18 return this.dispose();
15 } 19 }
16 if (!this.updater) this.updater = new HintsUpdater(ctx); 20 if (!this.updater) this.updater = new HintsUpdater(ctx);
@@ -63,6 +67,22 @@ const paramHints = {
63 } 67 }
64}; 68};
65 69
70const chainingHints = {
71 decorationType: vscode.window.createTextEditorDecorationType({
72 after: {
73 color: new vscode.ThemeColor('rust_analyzer.inlayHint'),
74 fontStyle: "normal",
75 }
76 }),
77
78 toDecoration(hint: ra.InlayHint.ChainingHint, conv: lc.Protocol2CodeConverter): vscode.DecorationOptions {
79 return {
80 range: conv.asRange(hint.range),
81 renderOptions: { after: { contentText: ` ${hint.label}` } }
82 };
83 }
84};
85
66class HintsUpdater implements Disposable { 86class HintsUpdater implements Disposable {
67 private sourceFiles = new Map<string, RustSourceFile>(); // map Uri -> RustSourceFile 87 private sourceFiles = new Map<string, RustSourceFile>(); // map Uri -> RustSourceFile
68 private readonly disposables: Disposable[] = []; 88 private readonly disposables: Disposable[] = [];
@@ -95,7 +115,7 @@ class HintsUpdater implements Disposable {
95 115
96 dispose() { 116 dispose() {
97 this.sourceFiles.forEach(file => file.inlaysRequest?.cancel()); 117 this.sourceFiles.forEach(file => file.inlaysRequest?.cancel());
98 this.ctx.visibleRustEditors.forEach(editor => this.renderDecorations(editor, { param: [], type: [] })); 118 this.ctx.visibleRustEditors.forEach(editor => this.renderDecorations(editor, { param: [], type: [], chaining: [] }));
99 this.disposables.forEach(d => d.dispose()); 119 this.disposables.forEach(d => d.dispose());
100 } 120 }
101 121
@@ -154,10 +174,11 @@ class HintsUpdater implements Disposable {
154 private renderDecorations(editor: RustEditor, decorations: InlaysDecorations) { 174 private renderDecorations(editor: RustEditor, decorations: InlaysDecorations) {
155 editor.setDecorations(typeHints.decorationType, decorations.type); 175 editor.setDecorations(typeHints.decorationType, decorations.type);
156 editor.setDecorations(paramHints.decorationType, decorations.param); 176 editor.setDecorations(paramHints.decorationType, decorations.param);
177 editor.setDecorations(chainingHints.decorationType, decorations.chaining);
157 } 178 }
158 179
159 private hintsToDecorations(hints: ra.InlayHint[]): InlaysDecorations { 180 private hintsToDecorations(hints: ra.InlayHint[]): InlaysDecorations {
160 const decorations: InlaysDecorations = { type: [], param: [] }; 181 const decorations: InlaysDecorations = { type: [], param: [], chaining: [] };
161 const conv = this.ctx.client.protocol2CodeConverter; 182 const conv = this.ctx.client.protocol2CodeConverter;
162 183
163 for (const hint of hints) { 184 for (const hint of hints) {
@@ -170,6 +191,10 @@ class HintsUpdater implements Disposable {
170 decorations.param.push(paramHints.toDecoration(hint, conv)); 191 decorations.param.push(paramHints.toDecoration(hint, conv));
171 continue; 192 continue;
172 } 193 }
194 case ra.InlayHint.Kind.ChainingHint: {
195 decorations.chaining.push(chainingHints.toDecoration(hint, conv));
196 continue;
197 }
173 } 198 }
174 } 199 }
175 return decorations; 200 return decorations;
@@ -196,6 +221,7 @@ class HintsUpdater implements Disposable {
196interface InlaysDecorations { 221interface InlaysDecorations {
197 type: vscode.DecorationOptions[]; 222 type: vscode.DecorationOptions[];
198 param: vscode.DecorationOptions[]; 223 param: vscode.DecorationOptions[];
224 chaining: vscode.DecorationOptions[];
199} 225}
200 226
201interface RustSourceFile { 227interface RustSourceFile {
diff --git a/editors/code/src/rust-analyzer-api.ts b/editors/code/src/rust-analyzer-api.ts
index 9846f7343..400ac3714 100644
--- a/editors/code/src/rust-analyzer-api.ts
+++ b/editors/code/src/rust-analyzer-api.ts
@@ -86,12 +86,13 @@ export interface Runnable {
86} 86}
87export const runnables = request<RunnablesParams, Vec<Runnable>>("runnables"); 87export const runnables = request<RunnablesParams, Vec<Runnable>>("runnables");
88 88
89export type InlayHint = InlayHint.TypeHint | InlayHint.ParamHint; 89export type InlayHint = InlayHint.TypeHint | InlayHint.ParamHint | InlayHint.ChainingHint;
90 90
91export namespace InlayHint { 91export namespace InlayHint {
92 export const enum Kind { 92 export const enum Kind {
93 TypeHint = "TypeHint", 93 TypeHint = "TypeHint",
94 ParamHint = "ParameterHint", 94 ParamHint = "ParameterHint",
95 ChainingHint = "ChainingHint",
95 } 96 }
96 interface Common { 97 interface Common {
97 range: lc.Range; 98 range: lc.Range;
@@ -99,6 +100,7 @@ export namespace InlayHint {
99 } 100 }
100 export type TypeHint = Common & { kind: Kind.TypeHint }; 101 export type TypeHint = Common & { kind: Kind.TypeHint };
101 export type ParamHint = Common & { kind: Kind.ParamHint }; 102 export type ParamHint = Common & { kind: Kind.ParamHint };
103 export type ChainingHint = Common & { kind: Kind.ChainingHint };
102} 104}
103export interface InlayHintsParams { 105export interface InlayHintsParams {
104 textDocument: lc.TextDocumentIdentifier; 106 textDocument: lc.TextDocumentIdentifier;