aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2019-11-20 05:38:25 +0000
committerGitHub <[email protected]>2019-11-20 05:38:25 +0000
commiteec68e6f451ee7675ce2cb29b696df091e6aed13 (patch)
treef83c828be31f5ac3950bf41c027a30365cfc7bd6 /crates
parent0e61ba3750df7e3e19eda21b6486bf70d6dffc72 (diff)
parentbf5ac4fe3952ee0db9fe18a185e39a209c58e79b (diff)
Merge pull request #2297 from kiljacken/master
Add fancy truncation of type hints.
Diffstat (limited to 'crates')
-rw-r--r--crates/ra_hir/src/ty.rs20
-rw-r--r--crates/ra_hir/src/ty/display.rs43
-rw-r--r--crates/ra_ide_api/src/inlay_hints.rs74
-rw-r--r--crates/ra_ide_api/src/lib.rs10
-rw-r--r--crates/ra_lsp_server/src/config.rs3
-rw-r--r--crates/ra_lsp_server/src/main_loop.rs1
-rw-r--r--crates/ra_lsp_server/src/main_loop/handlers.rs2
-rw-r--r--crates/ra_lsp_server/src/world.rs1
8 files changed, 132 insertions, 22 deletions
diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs
index b7f50b714..776613c7c 100644
--- a/crates/ra_hir/src/ty.rs
+++ b/crates/ra_hir/src/ty.rs
@@ -800,6 +800,10 @@ impl HirDisplay for &Ty {
800 800
801impl HirDisplay for ApplicationTy { 801impl HirDisplay for ApplicationTy {
802 fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result { 802 fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result {
803 if f.should_truncate() {
804 return write!(f, "…");
805 }
806
803 match self.ctor { 807 match self.ctor {
804 TypeCtor::Bool => write!(f, "bool")?, 808 TypeCtor::Bool => write!(f, "bool")?,
805 TypeCtor::Char => write!(f, "char")?, 809 TypeCtor::Char => write!(f, "char")?,
@@ -901,6 +905,10 @@ impl HirDisplay for ApplicationTy {
901 905
902impl HirDisplay for ProjectionTy { 906impl HirDisplay for ProjectionTy {
903 fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result { 907 fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result {
908 if f.should_truncate() {
909 return write!(f, "…");
910 }
911
904 let trait_name = self 912 let trait_name = self
905 .associated_ty 913 .associated_ty
906 .parent_trait(f.db) 914 .parent_trait(f.db)
@@ -919,6 +927,10 @@ impl HirDisplay for ProjectionTy {
919 927
920impl HirDisplay for Ty { 928impl HirDisplay for Ty {
921 fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result { 929 fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result {
930 if f.should_truncate() {
931 return write!(f, "…");
932 }
933
922 match self { 934 match self {
923 Ty::Apply(a_ty) => a_ty.hir_fmt(f)?, 935 Ty::Apply(a_ty) => a_ty.hir_fmt(f)?,
924 Ty::Projection(p_ty) => p_ty.hir_fmt(f)?, 936 Ty::Projection(p_ty) => p_ty.hir_fmt(f)?,
@@ -1001,6 +1013,10 @@ impl HirDisplay for Ty {
1001 1013
1002impl TraitRef { 1014impl TraitRef {
1003 fn hir_fmt_ext(&self, f: &mut HirFormatter<impl HirDatabase>, use_as: bool) -> fmt::Result { 1015 fn hir_fmt_ext(&self, f: &mut HirFormatter<impl HirDatabase>, use_as: bool) -> fmt::Result {
1016 if f.should_truncate() {
1017 return write!(f, "…");
1018 }
1019
1004 self.substs[0].hir_fmt(f)?; 1020 self.substs[0].hir_fmt(f)?;
1005 if use_as { 1021 if use_as {
1006 write!(f, " as ")?; 1022 write!(f, " as ")?;
@@ -1031,6 +1047,10 @@ impl HirDisplay for &GenericPredicate {
1031 1047
1032impl HirDisplay for GenericPredicate { 1048impl HirDisplay for GenericPredicate {
1033 fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result { 1049 fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result {
1050 if f.should_truncate() {
1051 return write!(f, "…");
1052 }
1053
1034 match self { 1054 match self {
1035 GenericPredicate::Implemented(trait_ref) => trait_ref.hir_fmt(f)?, 1055 GenericPredicate::Implemented(trait_ref) => trait_ref.hir_fmt(f)?,
1036 GenericPredicate::Projection(projection_pred) => { 1056 GenericPredicate::Projection(projection_pred) => {
diff --git a/crates/ra_hir/src/ty/display.rs b/crates/ra_hir/src/ty/display.rs
index 7910429d7..9bb3ece6c 100644
--- a/crates/ra_hir/src/ty/display.rs
+++ b/crates/ra_hir/src/ty/display.rs
@@ -7,15 +7,30 @@ use crate::db::HirDatabase;
7pub struct HirFormatter<'a, 'b, DB> { 7pub struct HirFormatter<'a, 'b, DB> {
8 pub db: &'a DB, 8 pub db: &'a DB,
9 fmt: &'a mut fmt::Formatter<'b>, 9 fmt: &'a mut fmt::Formatter<'b>,
10 buf: String,
11 curr_size: usize,
12 max_size: Option<usize>,
10} 13}
11 14
12pub trait HirDisplay { 15pub trait HirDisplay {
13 fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result; 16 fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result;
17
14 fn display<'a, DB>(&'a self, db: &'a DB) -> HirDisplayWrapper<'a, DB, Self> 18 fn display<'a, DB>(&'a self, db: &'a DB) -> HirDisplayWrapper<'a, DB, Self>
15 where 19 where
16 Self: Sized, 20 Self: Sized,
17 { 21 {
18 HirDisplayWrapper(db, self) 22 HirDisplayWrapper(db, self, None)
23 }
24
25 fn display_truncated<'a, DB>(
26 &'a self,
27 db: &'a DB,
28 max_size: Option<usize>,
29 ) -> HirDisplayWrapper<'a, DB, Self>
30 where
31 Self: Sized,
32 {
33 HirDisplayWrapper(db, self, max_size)
19 } 34 }
20} 35}
21 36
@@ -41,11 +56,25 @@ where
41 56
42 /// This allows using the `write!` macro directly with a `HirFormatter`. 57 /// This allows using the `write!` macro directly with a `HirFormatter`.
43 pub fn write_fmt(&mut self, args: fmt::Arguments) -> fmt::Result { 58 pub fn write_fmt(&mut self, args: fmt::Arguments) -> fmt::Result {
44 fmt::write(self.fmt, args) 59 // We write to a buffer first to track output size
60 self.buf.clear();
61 fmt::write(&mut self.buf, args)?;
62 self.curr_size += self.buf.len();
63
64 // Then we write to the internal formatter from the buffer
65 self.fmt.write_str(&self.buf)
66 }
67
68 pub fn should_truncate(&self) -> bool {
69 if let Some(max_size) = self.max_size {
70 self.curr_size >= max_size
71 } else {
72 false
73 }
45 } 74 }
46} 75}
47 76
48pub struct HirDisplayWrapper<'a, DB, T>(&'a DB, &'a T); 77pub struct HirDisplayWrapper<'a, DB, T>(&'a DB, &'a T, Option<usize>);
49 78
50impl<'a, DB, T> fmt::Display for HirDisplayWrapper<'a, DB, T> 79impl<'a, DB, T> fmt::Display for HirDisplayWrapper<'a, DB, T>
51where 80where
@@ -53,6 +82,12 @@ where
53 T: HirDisplay, 82 T: HirDisplay,
54{ 83{
55 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 84 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
56 self.1.hir_fmt(&mut HirFormatter { db: self.0, fmt: f }) 85 self.1.hir_fmt(&mut HirFormatter {
86 db: self.0,
87 fmt: f,
88 buf: String::with_capacity(20),
89 curr_size: 0,
90 max_size: self.2,
91 })
57 } 92 }
58} 93}
diff --git a/crates/ra_ide_api/src/inlay_hints.rs b/crates/ra_ide_api/src/inlay_hints.rs
index 0cd959848..24a7ca5e7 100644
--- a/crates/ra_ide_api/src/inlay_hints.rs
+++ b/crates/ra_ide_api/src/inlay_hints.rs
@@ -19,10 +19,15 @@ pub struct InlayHint {
19 pub label: SmolStr, 19 pub label: SmolStr,
20} 20}
21 21
22pub(crate) fn inlay_hints(db: &RootDatabase, file_id: FileId, file: &SourceFile) -> Vec<InlayHint> { 22pub(crate) fn inlay_hints(
23 db: &RootDatabase,
24 file_id: FileId,
25 file: &SourceFile,
26 max_inlay_hint_length: Option<usize>,
27) -> Vec<InlayHint> {
23 file.syntax() 28 file.syntax()
24 .descendants() 29 .descendants()
25 .map(|node| get_inlay_hints(db, file_id, &node).unwrap_or_default()) 30 .map(|node| get_inlay_hints(db, file_id, &node, max_inlay_hint_length).unwrap_or_default())
26 .flatten() 31 .flatten()
27 .collect() 32 .collect()
28} 33}
@@ -31,6 +36,7 @@ fn get_inlay_hints(
31 db: &RootDatabase, 36 db: &RootDatabase,
32 file_id: FileId, 37 file_id: FileId,
33 node: &SyntaxNode, 38 node: &SyntaxNode,
39 max_inlay_hint_length: Option<usize>,
34) -> Option<Vec<InlayHint>> { 40) -> Option<Vec<InlayHint>> {
35 let analyzer = SourceAnalyzer::new(db, hir::Source::new(file_id.into(), node), None); 41 let analyzer = SourceAnalyzer::new(db, hir::Source::new(file_id.into(), node), None);
36 match_ast! { 42 match_ast! {
@@ -40,7 +46,7 @@ fn get_inlay_hints(
40 return None; 46 return None;
41 } 47 }
42 let pat = it.pat()?; 48 let pat = it.pat()?;
43 Some(get_pat_type_hints(db, &analyzer, pat, false)) 49 Some(get_pat_type_hints(db, &analyzer, pat, false, max_inlay_hint_length))
44 }, 50 },
45 ast::LambdaExpr(it) => { 51 ast::LambdaExpr(it) => {
46 it.param_list().map(|param_list| { 52 it.param_list().map(|param_list| {
@@ -48,22 +54,22 @@ fn get_inlay_hints(
48 .params() 54 .params()
49 .filter(|closure_param| closure_param.ascribed_type().is_none()) 55 .filter(|closure_param| closure_param.ascribed_type().is_none())
50 .filter_map(|closure_param| closure_param.pat()) 56 .filter_map(|closure_param| closure_param.pat())
51 .map(|root_pat| get_pat_type_hints(db, &analyzer, root_pat, false)) 57 .map(|root_pat| get_pat_type_hints(db, &analyzer, root_pat, false, max_inlay_hint_length))
52 .flatten() 58 .flatten()
53 .collect() 59 .collect()
54 }) 60 })
55 }, 61 },
56 ast::ForExpr(it) => { 62 ast::ForExpr(it) => {
57 let pat = it.pat()?; 63 let pat = it.pat()?;
58 Some(get_pat_type_hints(db, &analyzer, pat, false)) 64 Some(get_pat_type_hints(db, &analyzer, pat, false, max_inlay_hint_length))
59 }, 65 },
60 ast::IfExpr(it) => { 66 ast::IfExpr(it) => {
61 let pat = it.condition()?.pat()?; 67 let pat = it.condition()?.pat()?;
62 Some(get_pat_type_hints(db, &analyzer, pat, true)) 68 Some(get_pat_type_hints(db, &analyzer, pat, true, max_inlay_hint_length))
63 }, 69 },
64 ast::WhileExpr(it) => { 70 ast::WhileExpr(it) => {
65 let pat = it.condition()?.pat()?; 71 let pat = it.condition()?.pat()?;
66 Some(get_pat_type_hints(db, &analyzer, pat, true)) 72 Some(get_pat_type_hints(db, &analyzer, pat, true, max_inlay_hint_length))
67 }, 73 },
68 ast::MatchArmList(it) => { 74 ast::MatchArmList(it) => {
69 Some( 75 Some(
@@ -71,7 +77,7 @@ fn get_inlay_hints(
71 .arms() 77 .arms()
72 .map(|match_arm| match_arm.pats()) 78 .map(|match_arm| match_arm.pats())
73 .flatten() 79 .flatten()
74 .map(|root_pat| get_pat_type_hints(db, &analyzer, root_pat, true)) 80 .map(|root_pat| get_pat_type_hints(db, &analyzer, root_pat, true, max_inlay_hint_length))
75 .flatten() 81 .flatten()
76 .collect(), 82 .collect(),
77 ) 83 )
@@ -86,6 +92,7 @@ fn get_pat_type_hints(
86 analyzer: &SourceAnalyzer, 92 analyzer: &SourceAnalyzer,
87 root_pat: ast::Pat, 93 root_pat: ast::Pat,
88 skip_root_pat_hint: bool, 94 skip_root_pat_hint: bool,
95 max_inlay_hint_length: Option<usize>,
89) -> Vec<InlayHint> { 96) -> Vec<InlayHint> {
90 let original_pat = &root_pat.clone(); 97 let original_pat = &root_pat.clone();
91 98
@@ -99,7 +106,7 @@ fn get_pat_type_hints(
99 .map(|(range, pat_type)| InlayHint { 106 .map(|(range, pat_type)| InlayHint {
100 range, 107 range,
101 kind: InlayKind::TypeHint, 108 kind: InlayKind::TypeHint,
102 label: pat_type.display(db).to_string().into(), 109 label: pat_type.display_truncated(db, max_inlay_hint_length).to_string().into(),
103 }) 110 })
104 .collect() 111 .collect()
105} 112}
@@ -209,7 +216,7 @@ fn main() {
209}"#, 216}"#,
210 ); 217 );
211 218
212 assert_debug_snapshot!(analysis.inlay_hints(file_id).unwrap(), @r###" 219 assert_debug_snapshot!(analysis.inlay_hints(file_id, None).unwrap(), @r###"
213 [ 220 [
214 InlayHint { 221 InlayHint {
215 range: [193; 197), 222 range: [193; 197),
@@ -278,7 +285,7 @@ fn main() {
278}"#, 285}"#,
279 ); 286 );
280 287
281 assert_debug_snapshot!(analysis.inlay_hints(file_id).unwrap(), @r###" 288 assert_debug_snapshot!(analysis.inlay_hints(file_id, None).unwrap(), @r###"
282 [ 289 [
283 InlayHint { 290 InlayHint {
284 range: [21; 30), 291 range: [21; 30),
@@ -307,7 +314,7 @@ fn main() {
307}"#, 314}"#,
308 ); 315 );
309 316
310 assert_debug_snapshot!(analysis.inlay_hints(file_id).unwrap(), @r###" 317 assert_debug_snapshot!(analysis.inlay_hints(file_id, None).unwrap(), @r###"
311 [ 318 [
312 InlayHint { 319 InlayHint {
313 range: [21; 30), 320 range: [21; 30),
@@ -355,7 +362,7 @@ fn main() {
355}"#, 362}"#,
356 ); 363 );
357 364
358 assert_debug_snapshot!(analysis.inlay_hints(file_id).unwrap(), @r###" 365 assert_debug_snapshot!(analysis.inlay_hints(file_id, None).unwrap(), @r###"
359 [ 366 [
360 InlayHint { 367 InlayHint {
361 range: [166; 170), 368 range: [166; 170),
@@ -418,7 +425,7 @@ fn main() {
418}"#, 425}"#,
419 ); 426 );
420 427
421 assert_debug_snapshot!(analysis.inlay_hints(file_id).unwrap(), @r###" 428 assert_debug_snapshot!(analysis.inlay_hints(file_id, None).unwrap(), @r###"
422 [ 429 [
423 InlayHint { 430 InlayHint {
424 range: [166; 170), 431 range: [166; 170),
@@ -481,7 +488,7 @@ fn main() {
481}"#, 488}"#,
482 ); 489 );
483 490
484 assert_debug_snapshot!(analysis.inlay_hints(file_id).unwrap(), @r###" 491 assert_debug_snapshot!(analysis.inlay_hints(file_id, None).unwrap(), @r###"
485 [ 492 [
486 InlayHint { 493 InlayHint {
487 range: [311; 315), 494 range: [311; 315),
@@ -507,4 +514,41 @@ fn main() {
507 "### 514 "###
508 ); 515 );
509 } 516 }
517
518 #[test]
519 fn hint_truncation() {
520 let (analysis, file_id) = single_file(
521 r#"
522struct Smol<T>(T);
523
524struct VeryLongOuterName<T>(T);
525
526fn main() {
527 let a = Smol(0u32);
528 let b = VeryLongOuterName(0usize);
529 let c = Smol(Smol(0u32))
530}"#,
531 );
532
533 assert_debug_snapshot!(analysis.inlay_hints(file_id, Some(8)).unwrap(), @r###"
534 [
535 InlayHint {
536 range: [74; 75),
537 kind: TypeHint,
538 label: "Smol<u32>",
539 },
540 InlayHint {
541 range: [98; 99),
542 kind: TypeHint,
543 label: "VeryLongOuterName<…>",
544 },
545 InlayHint {
546 range: [137; 138),
547 kind: TypeHint,
548 label: "Smol<Smol<…>>",
549 },
550 ]
551 "###
552 );
553 }
510} 554}
diff --git a/crates/ra_ide_api/src/lib.rs b/crates/ra_ide_api/src/lib.rs
index 57ed97147..62ad996bc 100644
--- a/crates/ra_ide_api/src/lib.rs
+++ b/crates/ra_ide_api/src/lib.rs
@@ -344,8 +344,14 @@ impl Analysis {
344 } 344 }
345 345
346 /// Returns a list of the places in the file where type hints can be displayed. 346 /// Returns a list of the places in the file where type hints can be displayed.
347 pub fn inlay_hints(&self, file_id: FileId) -> Cancelable<Vec<InlayHint>> { 347 pub fn inlay_hints(
348 self.with_db(|db| inlay_hints::inlay_hints(db, file_id, &db.parse(file_id).tree())) 348 &self,
349 file_id: FileId,
350 max_inlay_hint_length: Option<usize>,
351 ) -> Cancelable<Vec<InlayHint>> {
352 self.with_db(|db| {
353 inlay_hints::inlay_hints(db, file_id, &db.parse(file_id).tree(), max_inlay_hint_length)
354 })
349 } 355 }
350 356
351 /// Returns the set of folding ranges. 357 /// Returns the set of folding ranges.
diff --git a/crates/ra_lsp_server/src/config.rs b/crates/ra_lsp_server/src/config.rs
index 9871a3b37..8045f3d60 100644
--- a/crates/ra_lsp_server/src/config.rs
+++ b/crates/ra_lsp_server/src/config.rs
@@ -29,6 +29,8 @@ pub struct ServerConfig {
29 29
30 pub lru_capacity: Option<usize>, 30 pub lru_capacity: Option<usize>,
31 31
32 pub max_inlay_hint_length: Option<usize>,
33
32 /// For internal usage to make integrated tests faster. 34 /// For internal usage to make integrated tests faster.
33 #[serde(deserialize_with = "nullable_bool_true")] 35 #[serde(deserialize_with = "nullable_bool_true")]
34 pub with_sysroot: bool, 36 pub with_sysroot: bool,
@@ -44,6 +46,7 @@ impl Default for ServerConfig {
44 exclude_globs: Vec::new(), 46 exclude_globs: Vec::new(),
45 use_client_watching: false, 47 use_client_watching: false,
46 lru_capacity: None, 48 lru_capacity: None,
49 max_inlay_hint_length: None,
47 with_sysroot: true, 50 with_sysroot: true,
48 feature_flags: FxHashMap::default(), 51 feature_flags: FxHashMap::default(),
49 } 52 }
diff --git a/crates/ra_lsp_server/src/main_loop.rs b/crates/ra_lsp_server/src/main_loop.rs
index f828efdee..0dc0aeee8 100644
--- a/crates/ra_lsp_server/src/main_loop.rs
+++ b/crates/ra_lsp_server/src/main_loop.rs
@@ -123,6 +123,7 @@ pub fn main_loop(
123 .and_then(|it| it.folding_range.as_ref()) 123 .and_then(|it| it.folding_range.as_ref())
124 .and_then(|it| it.line_folding_only) 124 .and_then(|it| it.line_folding_only)
125 .unwrap_or(false), 125 .unwrap_or(false),
126 max_inlay_hint_length: config.max_inlay_hint_length,
126 } 127 }
127 }; 128 };
128 129
diff --git a/crates/ra_lsp_server/src/main_loop/handlers.rs b/crates/ra_lsp_server/src/main_loop/handlers.rs
index 0461bf385..e552f2106 100644
--- a/crates/ra_lsp_server/src/main_loop/handlers.rs
+++ b/crates/ra_lsp_server/src/main_loop/handlers.rs
@@ -888,7 +888,7 @@ pub fn handle_inlay_hints(
888 let analysis = world.analysis(); 888 let analysis = world.analysis();
889 let line_index = analysis.file_line_index(file_id)?; 889 let line_index = analysis.file_line_index(file_id)?;
890 Ok(analysis 890 Ok(analysis
891 .inlay_hints(file_id)? 891 .inlay_hints(file_id, world.options.max_inlay_hint_length)?
892 .into_iter() 892 .into_iter()
893 .map(|api_type| InlayHint { 893 .map(|api_type| InlayHint {
894 label: api_type.label.to_string(), 894 label: api_type.label.to_string(),
diff --git a/crates/ra_lsp_server/src/world.rs b/crates/ra_lsp_server/src/world.rs
index 51824e7a3..9bdea70c7 100644
--- a/crates/ra_lsp_server/src/world.rs
+++ b/crates/ra_lsp_server/src/world.rs
@@ -28,6 +28,7 @@ pub struct Options {
28 pub publish_decorations: bool, 28 pub publish_decorations: bool,
29 pub supports_location_link: bool, 29 pub supports_location_link: bool,
30 pub line_folding_only: bool, 30 pub line_folding_only: bool,
31 pub max_inlay_hint_length: Option<usize>,
31} 32}
32 33
33/// `WorldState` is the primary mutable state of the language server 34/// `WorldState` is the primary mutable state of the language server