Skip to content

Commit 207f035

Browse files
Merge pull request #21322 from asukaminato0721/4318
impl Display type hint inlay hints at the end of the line #4318
2 parents 0ee81de + 38b8e8c commit 207f035

9 files changed

Lines changed: 250 additions & 18 deletions

File tree

crates/ide/src/inlay_hints.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,7 @@ fn hints(
303303
pub struct InlayHintsConfig<'a> {
304304
pub render_colons: bool,
305305
pub type_hints: bool,
306+
pub type_hints_placement: TypeHintsPlacement,
306307
pub sized_bound: bool,
307308
pub discriminant_hints: DiscriminantHints,
308309
pub parameter_hints: bool,
@@ -332,6 +333,12 @@ pub struct InlayHintsConfig<'a> {
332333
pub ra_fixture: RaFixtureConfig<'a>,
333334
}
334335

336+
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
337+
pub enum TypeHintsPlacement {
338+
Inline,
339+
EndOfLine,
340+
}
341+
335342
impl InlayHintsConfig<'_> {
336343
fn lazy_text_edit(&self, finish: impl FnOnce() -> TextEdit) -> LazyProperty<TextEdit> {
337344
if self.fields_to_resolve.resolve_text_edits {
@@ -908,12 +915,15 @@ mod tests {
908915
use crate::inlay_hints::{AdjustmentHints, AdjustmentHintsMode};
909916
use crate::{LifetimeElisionHints, fixture, inlay_hints::InlayHintsConfig};
910917

911-
use super::{ClosureReturnTypeHints, GenericParameterHints, InlayFieldsToResolve};
918+
use super::{
919+
ClosureReturnTypeHints, GenericParameterHints, InlayFieldsToResolve, TypeHintsPlacement,
920+
};
912921

913922
pub(super) const DISABLED_CONFIG: InlayHintsConfig<'_> = InlayHintsConfig {
914923
discriminant_hints: DiscriminantHints::Never,
915924
render_colons: false,
916925
type_hints: false,
926+
type_hints_placement: TypeHintsPlacement::Inline,
917927
parameter_hints: false,
918928
parameter_hints_for_missing_arguments: false,
919929
sized_bound: false,
@@ -947,6 +957,7 @@ mod tests {
947957
};
948958
pub(super) const TEST_CONFIG: InlayHintsConfig<'_> = InlayHintsConfig {
949959
type_hints: true,
960+
type_hints_placement: TypeHintsPlacement::Inline,
950961
parameter_hints: true,
951962
chaining_hints: true,
952963
closure_return_type_hints: ClosureReturnTypeHints::WithBlock,

crates/ide/src/inlay_hints/bind_pat.rs

Lines changed: 90 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,12 @@ use ide_db::{RootDatabase, famous_defs::FamousDefs};
88

99
use itertools::Itertools;
1010
use syntax::{
11+
TextRange,
1112
ast::{self, AstNode, HasGenericArgs, HasName},
1213
match_ast,
1314
};
1415

16+
use super::TypeHintsPlacement;
1517
use crate::{
1618
InlayHint, InlayHintPosition, InlayHintsConfig, InlayKind,
1719
inlay_hints::{closure_has_block_body, label_of_ty, ty_to_text_edit},
@@ -29,6 +31,7 @@ pub(super) fn hints(
2931
}
3032

3133
let parent = pat.syntax().parent()?;
34+
let mut enclosing_let_stmt = None;
3235
let type_ascriptable = match_ast! {
3336
match parent {
3437
ast::Param(it) => {
@@ -41,6 +44,7 @@ pub(super) fn hints(
4144
Some(it.colon_token())
4245
},
4346
ast::LetStmt(it) => {
47+
enclosing_let_stmt = Some(it.clone());
4448
if config.hide_closure_initialization_hints
4549
&& let Some(ast::Expr::ClosureExpr(closure)) = it.initializer()
4650
&& closure_has_block_body(&closure) {
@@ -101,16 +105,26 @@ pub(super) fn hints(
101105
Some(name) => name.syntax().text_range(),
102106
None => pat.syntax().text_range(),
103107
};
108+
let mut range = match type_ascriptable {
109+
Some(Some(t)) => text_range.cover(t.text_range()),
110+
_ => text_range,
111+
};
112+
113+
let mut pad_left = !render_colons;
114+
if matches!(config.type_hints_placement, TypeHintsPlacement::EndOfLine)
115+
&& let Some(let_stmt) = enclosing_let_stmt
116+
{
117+
let stmt_range = let_stmt.syntax().text_range();
118+
range = TextRange::new(range.start(), stmt_range.end());
119+
pad_left = true;
120+
}
104121
acc.push(InlayHint {
105-
range: match type_ascriptable {
106-
Some(Some(t)) => text_range.cover(t.text_range()),
107-
_ => text_range,
108-
},
122+
range,
109123
kind: InlayKind::Type,
110124
label,
111125
text_edit,
112126
position: InlayHintPosition::After,
113-
pad_left: !render_colons,
127+
pad_left,
114128
pad_right: false,
115129
resolve_parent: Some(pat.syntax().text_range()),
116130
});
@@ -182,6 +196,7 @@ mod tests {
182196

183197
use crate::{ClosureReturnTypeHints, fixture, inlay_hints::InlayHintsConfig};
184198

199+
use super::TypeHintsPlacement;
185200
use crate::inlay_hints::tests::{
186201
DISABLED_CONFIG, TEST_CONFIG, check, check_edit, check_expect, check_no_edit,
187202
check_with_config,
@@ -204,6 +219,76 @@ fn main() {
204219
);
205220
}
206221

222+
#[test]
223+
fn type_hints_end_of_line_placement() {
224+
let mut config = InlayHintsConfig { type_hints: true, ..DISABLED_CONFIG };
225+
config.type_hints_placement = TypeHintsPlacement::EndOfLine;
226+
check_expect(
227+
config,
228+
r#"
229+
fn main() {
230+
let foo = 92_i32;
231+
}
232+
"#,
233+
expect![[r#"
234+
[
235+
(
236+
20..33,
237+
[
238+
"i32",
239+
],
240+
),
241+
]
242+
"#]],
243+
);
244+
}
245+
246+
#[test]
247+
fn type_hints_end_of_line_placement_chain_expr() {
248+
let mut config = InlayHintsConfig { type_hints: true, ..DISABLED_CONFIG };
249+
config.type_hints_placement = TypeHintsPlacement::EndOfLine;
250+
check_expect(
251+
config,
252+
r#"
253+
fn main() {
254+
struct Builder;
255+
impl Builder {
256+
fn iter(self) -> Builder { Builder }
257+
fn map(self) -> Builder { Builder }
258+
}
259+
fn make() -> Builder { Builder }
260+
261+
let foo = make()
262+
.iter()
263+
.map();
264+
}
265+
"#,
266+
expect![[r#"
267+
[
268+
(
269+
192..236,
270+
[
271+
InlayHintLabelPart {
272+
text: "Builder",
273+
linked_location: Some(
274+
Computed(
275+
FileRangeWrapper {
276+
file_id: FileId(
277+
0,
278+
),
279+
range: 23..30,
280+
},
281+
),
282+
),
283+
tooltip: "",
284+
},
285+
],
286+
),
287+
]
288+
"#]],
289+
);
290+
}
291+
207292
#[test]
208293
fn type_hints_bindings_after_at() {
209294
check_types(

crates/ide/src/inlay_hints/chaining.rs

Lines changed: 97 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,13 @@
22
use hir::DisplayTarget;
33
use ide_db::famous_defs::FamousDefs;
44
use syntax::{
5-
Direction, NodeOrToken, SyntaxKind, T,
5+
Direction, NodeOrToken, SyntaxKind, T, TextRange,
66
ast::{self, AstNode},
77
};
88

99
use crate::{InlayHint, InlayHintPosition, InlayHintsConfig, InlayKind};
1010

11-
use super::label_of_ty;
11+
use super::{TypeHintsPlacement, label_of_ty};
1212

1313
pub(super) fn hints(
1414
acc: &mut Vec<InlayHint>,
@@ -40,13 +40,14 @@ pub(super) fn hints(
4040

4141
// Chaining can be defined as an expression whose next sibling tokens are newline and dot
4242
// Ignoring extra whitespace and comments
43-
let next = tokens.next()?.kind();
44-
if next == SyntaxKind::WHITESPACE {
45-
let mut next_next = tokens.next()?.kind();
46-
while next_next == SyntaxKind::WHITESPACE {
47-
next_next = tokens.next()?.kind();
43+
let next_token = tokens.next()?;
44+
if next_token.kind() == SyntaxKind::WHITESPACE {
45+
let newline_token = next_token;
46+
let mut next_next = tokens.next()?;
47+
while next_next.kind() == SyntaxKind::WHITESPACE {
48+
next_next = tokens.next()?;
4849
}
49-
if next_next == T![.] {
50+
if next_next.kind() == T![.] {
5051
let ty = sema.type_of_expr(desc_expr)?.original;
5152
if ty.is_unknown() {
5253
return None;
@@ -58,8 +59,18 @@ pub(super) fn hints(
5859
return None;
5960
}
6061
let label = label_of_ty(famous_defs, config, &ty, display_target)?;
62+
let range = {
63+
let mut range = expr.syntax().text_range();
64+
if config.type_hints_placement == TypeHintsPlacement::EndOfLine {
65+
range = TextRange::new(
66+
range.start(),
67+
newline_token.text_range().start().max(range.end()),
68+
);
69+
}
70+
range
71+
};
6172
acc.push(InlayHint {
62-
range: expr.syntax().text_range(),
73+
range,
6374
kind: InlayKind::Chaining,
6475
label,
6576
text_edit: None,
@@ -79,7 +90,7 @@ mod tests {
7990
use ide_db::text_edit::{TextRange, TextSize};
8091

8192
use crate::{
82-
InlayHintsConfig, fixture,
93+
InlayHintsConfig, TypeHintsPlacement, fixture,
8394
inlay_hints::{
8495
LazyProperty,
8596
tests::{DISABLED_CONFIG, TEST_CONFIG, check_expect, check_with_config},
@@ -686,4 +697,80 @@ fn main() {
686697
"#]],
687698
);
688699
}
700+
701+
#[test]
702+
fn chaining_hints_end_of_line_placement() {
703+
check_expect(
704+
InlayHintsConfig {
705+
chaining_hints: true,
706+
type_hints_placement: TypeHintsPlacement::EndOfLine,
707+
..DISABLED_CONFIG
708+
},
709+
r#"
710+
fn main() {
711+
let baz = make()
712+
.into_bar()
713+
.into_baz();
714+
}
715+
716+
struct Foo;
717+
struct Bar;
718+
struct Baz;
719+
720+
impl Foo {
721+
fn into_bar(self) -> Bar { Bar }
722+
}
723+
724+
impl Bar {
725+
fn into_baz(self) -> Baz { Baz }
726+
}
727+
728+
fn make() -> Foo {
729+
Foo
730+
}
731+
"#,
732+
expect![[r#"
733+
[
734+
(
735+
26..52,
736+
[
737+
InlayHintLabelPart {
738+
text: "Bar",
739+
linked_location: Some(
740+
Computed(
741+
FileRangeWrapper {
742+
file_id: FileId(
743+
0,
744+
),
745+
range: 96..99,
746+
},
747+
),
748+
),
749+
tooltip: "",
750+
},
751+
],
752+
),
753+
(
754+
26..32,
755+
[
756+
InlayHintLabelPart {
757+
text: "Foo",
758+
linked_location: Some(
759+
Computed(
760+
FileRangeWrapper {
761+
file_id: FileId(
762+
0,
763+
),
764+
range: 84..87,
765+
},
766+
),
767+
),
768+
tooltip: "",
769+
},
770+
],
771+
),
772+
]
773+
"#]],
774+
);
775+
}
689776
}

crates/ide/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ pub use crate::{
9696
AdjustmentHints, AdjustmentHintsMode, ClosureReturnTypeHints, DiscriminantHints,
9797
GenericParameterHints, InlayFieldsToResolve, InlayHint, InlayHintLabel, InlayHintLabelPart,
9898
InlayHintPosition, InlayHintsConfig, InlayKind, InlayTooltip, LazyProperty,
99-
LifetimeElisionHints,
99+
LifetimeElisionHints, TypeHintsPlacement,
100100
},
101101
join_lines::JoinLinesConfig,
102102
markup::Markup,

crates/ide/src/static_index.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use crate::navigation_target::UpmappingResult;
1717
use crate::{
1818
Analysis, Fold, HoverConfig, HoverResult, InlayHint, InlayHintsConfig, TryToNav,
1919
hover::{SubstTyLen, hover_for_definition},
20-
inlay_hints::{AdjustmentHintsMode, InlayFieldsToResolve},
20+
inlay_hints::{AdjustmentHintsMode, InlayFieldsToResolve, TypeHintsPlacement},
2121
moniker::{MonikerResult, SymbolInformationKind, def_to_kind, def_to_moniker},
2222
parent_module::crates_for,
2323
};
@@ -168,6 +168,7 @@ impl StaticIndex<'_> {
168168
render_colons: true,
169169
discriminant_hints: crate::DiscriminantHints::Fieldless,
170170
type_hints: true,
171+
type_hints_placement: TypeHintsPlacement::Inline,
171172
sized_bound: false,
172173
parameter_hints: true,
173174
parameter_hints_for_missing_arguments: false,

crates/rust-analyzer/src/cli/analysis_stats.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1367,6 +1367,7 @@ impl flags::AnalysisStats {
13671367
&InlayHintsConfig {
13681368
render_colons: false,
13691369
type_hints: true,
1370+
type_hints_placement: ide::TypeHintsPlacement::Inline,
13701371
sized_bound: false,
13711372
discriminant_hints: ide::DiscriminantHints::Always,
13721373
parameter_hints: true,

0 commit comments

Comments
 (0)