aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide/src/hover.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_ide/src/hover.rs')
-rw-r--r--crates/ra_ide/src/hover.rs148
1 files changed, 136 insertions, 12 deletions
diff --git a/crates/ra_ide/src/hover.rs b/crates/ra_ide/src/hover.rs
index 9636cd0d6..62df07459 100644
--- a/crates/ra_ide/src/hover.rs
+++ b/crates/ra_ide/src/hover.rs
@@ -13,14 +13,43 @@ use ra_ide_db::{
13use ra_syntax::{ast, match_ast, AstNode, SyntaxKind::*, SyntaxToken, TokenAtOffset}; 13use ra_syntax::{ast, match_ast, AstNode, SyntaxKind::*, SyntaxToken, TokenAtOffset};
14 14
15use crate::{ 15use crate::{
16 display::{macro_label, rust_code_markup, rust_code_markup_with_doc, ShortLabel}, 16 display::{macro_label, rust_code_markup, rust_code_markup_with_doc, ShortLabel, ToNav},
17 FilePosition, RangeInfo, 17 FilePosition, NavigationTarget, RangeInfo,
18}; 18};
19 19
20#[derive(Clone, Debug, PartialEq, Eq)]
21pub struct HoverConfig {
22 pub implementations: bool,
23}
24
25impl Default for HoverConfig {
26 fn default() -> Self {
27 Self { implementations: true }
28 }
29}
30
31impl HoverConfig {
32 pub const NO_ACTIONS: Self = Self { implementations: false };
33
34 pub fn any(&self) -> bool {
35 self.implementations
36 }
37
38 pub fn none(&self) -> bool {
39 !self.any()
40 }
41}
42
43#[derive(Debug, Clone)]
44pub enum HoverAction {
45 Implementaion(FilePosition),
46}
47
20/// Contains the results when hovering over an item 48/// Contains the results when hovering over an item
21#[derive(Debug, Default)] 49#[derive(Debug, Default)]
22pub struct HoverResult { 50pub struct HoverResult {
23 results: Vec<String>, 51 results: Vec<String>,
52 actions: Vec<HoverAction>,
24} 53}
25 54
26impl HoverResult { 55impl HoverResult {
@@ -48,10 +77,20 @@ impl HoverResult {
48 &self.results 77 &self.results
49 } 78 }
50 79
80 pub fn actions(&self) -> &[HoverAction] {
81 &self.actions
82 }
83
84 pub fn push_action(&mut self, action: HoverAction) {
85 self.actions.push(action);
86 }
87
51 /// Returns the results converted into markup 88 /// Returns the results converted into markup
52 /// for displaying in a UI 89 /// for displaying in a UI
90 ///
91 /// Does not process actions!
53 pub fn to_markup(&self) -> String { 92 pub fn to_markup(&self) -> String {
54 self.results.join("\n\n---\n") 93 self.results.join("\n\n___\n")
55 } 94 }
56} 95}
57 96
@@ -82,6 +121,10 @@ pub(crate) fn hover(db: &RootDatabase, position: FilePosition) -> Option<RangeIn
82 res.extend(hover_text_from_name_kind(db, name_kind)); 121 res.extend(hover_text_from_name_kind(db, name_kind));
83 122
84 if !res.is_empty() { 123 if !res.is_empty() {
124 if let Some(action) = show_implementations_action(db, name_kind) {
125 res.push_action(action);
126 }
127
85 return Some(RangeInfo::new(range, res)); 128 return Some(RangeInfo::new(range, res));
86 } 129 }
87 } 130 }
@@ -112,6 +155,26 @@ pub(crate) fn hover(db: &RootDatabase, position: FilePosition) -> Option<RangeIn
112 Some(RangeInfo::new(range, res)) 155 Some(RangeInfo::new(range, res))
113} 156}
114 157
158fn show_implementations_action(db: &RootDatabase, def: Definition) -> Option<HoverAction> {
159 fn to_action(nav_target: NavigationTarget) -> HoverAction {
160 HoverAction::Implementaion(FilePosition {
161 file_id: nav_target.file_id(),
162 offset: nav_target.range().start(),
163 })
164 }
165
166 match def {
167 Definition::ModuleDef(it) => match it {
168 ModuleDef::Adt(Adt::Struct(it)) => Some(to_action(it.to_nav(db))),
169 ModuleDef::Adt(Adt::Union(it)) => Some(to_action(it.to_nav(db))),
170 ModuleDef::Adt(Adt::Enum(it)) => Some(to_action(it.to_nav(db))),
171 ModuleDef::Trait(it) => Some(to_action(it.to_nav(db))),
172 _ => None,
173 },
174 _ => None,
175 }
176}
177
115fn hover_text( 178fn hover_text(
116 docs: Option<String>, 179 docs: Option<String>,
117 desc: Option<String>, 180 desc: Option<String>,
@@ -228,6 +291,8 @@ fn pick_best(tokens: TokenAtOffset<SyntaxToken>) -> Option<SyntaxToken> {
228 291
229#[cfg(test)] 292#[cfg(test)]
230mod tests { 293mod tests {
294 use super::*;
295
231 use ra_db::FileLoader; 296 use ra_db::FileLoader;
232 use ra_syntax::TextRange; 297 use ra_syntax::TextRange;
233 298
@@ -241,7 +306,14 @@ mod tests {
241 s.map(trim_markup) 306 s.map(trim_markup)
242 } 307 }
243 308
244 fn check_hover_result(fixture: &str, expected: &[&str]) -> String { 309 fn assert_impl_action(action: &HoverAction, position: u32) {
310 let offset = match action {
311 HoverAction::Implementaion(pos) => pos.offset,
312 };
313 assert_eq!(offset, position.into());
314 }
315
316 fn check_hover_result(fixture: &str, expected: &[&str]) -> (String, Vec<HoverAction>) {
245 let (analysis, position) = analysis_and_position(fixture); 317 let (analysis, position) = analysis_and_position(fixture);
246 let hover = analysis.hover(position).unwrap().unwrap(); 318 let hover = analysis.hover(position).unwrap().unwrap();
247 let mut results = Vec::from(hover.info.results()); 319 let mut results = Vec::from(hover.info.results());
@@ -256,7 +328,7 @@ mod tests {
256 assert_eq!(hover.info.len(), expected.len()); 328 assert_eq!(hover.info.len(), expected.len());
257 329
258 let content = analysis.db.file_text(position.file_id); 330 let content = analysis.db.file_text(position.file_id);
259 content[hover.range].to_string() 331 (content[hover.range].to_string(), hover.info.actions().to_vec())
260 } 332 }
261 333
262 fn check_hover_no_result(fixture: &str) { 334 fn check_hover_no_result(fixture: &str) {
@@ -746,7 +818,7 @@ fn func(foo: i32) { if true { <|>foo; }; }
746 818
747 #[test] 819 #[test]
748 fn test_hover_through_macro() { 820 fn test_hover_through_macro() {
749 let hover_on = check_hover_result( 821 let (hover_on, _) = check_hover_result(
750 " 822 "
751 //- /lib.rs 823 //- /lib.rs
752 macro_rules! id { 824 macro_rules! id {
@@ -767,7 +839,7 @@ fn func(foo: i32) { if true { <|>foo; }; }
767 839
768 #[test] 840 #[test]
769 fn test_hover_through_expr_in_macro() { 841 fn test_hover_through_expr_in_macro() {
770 let hover_on = check_hover_result( 842 let (hover_on, _) = check_hover_result(
771 " 843 "
772 //- /lib.rs 844 //- /lib.rs
773 macro_rules! id { 845 macro_rules! id {
@@ -785,7 +857,7 @@ fn func(foo: i32) { if true { <|>foo; }; }
785 857
786 #[test] 858 #[test]
787 fn test_hover_through_expr_in_macro_recursive() { 859 fn test_hover_through_expr_in_macro_recursive() {
788 let hover_on = check_hover_result( 860 let (hover_on, _) = check_hover_result(
789 " 861 "
790 //- /lib.rs 862 //- /lib.rs
791 macro_rules! id_deep { 863 macro_rules! id_deep {
@@ -806,7 +878,7 @@ fn func(foo: i32) { if true { <|>foo; }; }
806 878
807 #[test] 879 #[test]
808 fn test_hover_through_func_in_macro_recursive() { 880 fn test_hover_through_func_in_macro_recursive() {
809 let hover_on = check_hover_result( 881 let (hover_on, _) = check_hover_result(
810 " 882 "
811 //- /lib.rs 883 //- /lib.rs
812 macro_rules! id_deep { 884 macro_rules! id_deep {
@@ -830,7 +902,7 @@ fn func(foo: i32) { if true { <|>foo; }; }
830 902
831 #[test] 903 #[test]
832 fn test_hover_through_literal_string_in_macro() { 904 fn test_hover_through_literal_string_in_macro() {
833 let hover_on = check_hover_result( 905 let (hover_on, _) = check_hover_result(
834 r#" 906 r#"
835 //- /lib.rs 907 //- /lib.rs
836 macro_rules! arr { 908 macro_rules! arr {
@@ -849,7 +921,7 @@ fn func(foo: i32) { if true { <|>foo; }; }
849 921
850 #[test] 922 #[test]
851 fn test_hover_through_assert_macro() { 923 fn test_hover_through_assert_macro() {
852 let hover_on = check_hover_result( 924 let (hover_on, _) = check_hover_result(
853 r#" 925 r#"
854 //- /lib.rs 926 //- /lib.rs
855 #[rustc_builtin_macro] 927 #[rustc_builtin_macro]
@@ -925,13 +997,14 @@ fn func(foo: i32) { if true { <|>foo; }; }
925 997
926 #[test] 998 #[test]
927 fn test_hover_trait_show_qualifiers() { 999 fn test_hover_trait_show_qualifiers() {
928 check_hover_result( 1000 let (_, actions) = check_hover_result(
929 " 1001 "
930 //- /lib.rs 1002 //- /lib.rs
931 unsafe trait foo<|>() {} 1003 unsafe trait foo<|>() {}
932 ", 1004 ",
933 &["unsafe trait foo"], 1005 &["unsafe trait foo"],
934 ); 1006 );
1007 assert_impl_action(&actions[0], 13);
935 } 1008 }
936 1009
937 #[test] 1010 #[test]
@@ -1052,4 +1125,55 @@ fn func(foo: i32) { if true { <|>foo; }; }
1052 &["Bar\n```\n\n```rust\nfn foo(&self)\n```\n___\n\nDo the foo"], 1125 &["Bar\n```\n\n```rust\nfn foo(&self)\n```\n___\n\nDo the foo"],
1053 ); 1126 );
1054 } 1127 }
1128
1129 #[test]
1130 fn test_hover_trait_has_impl_action() {
1131 let (_, actions) = check_hover_result(
1132 "
1133 //- /lib.rs
1134 trait foo<|>() {}
1135 ",
1136 &["trait foo"],
1137 );
1138 assert_impl_action(&actions[0], 6);
1139 }
1140
1141 #[test]
1142 fn test_hover_struct_has_impl_action() {
1143 let (_, actions) = check_hover_result(
1144 "
1145 //- /lib.rs
1146 struct foo<|>() {}
1147 ",
1148 &["struct foo"],
1149 );
1150 assert_impl_action(&actions[0], 7);
1151 }
1152
1153 #[test]
1154 fn test_hover_union_has_impl_action() {
1155 let (_, actions) = check_hover_result(
1156 "
1157 //- /lib.rs
1158 union foo<|>() {}
1159 ",
1160 &["union foo"],
1161 );
1162 assert_impl_action(&actions[0], 6);
1163 }
1164
1165 #[test]
1166 fn test_hover_enum_has_impl_action() {
1167 let (_, actions) = check_hover_result(
1168 "
1169 //- /lib.rs
1170 enum foo<|>() {
1171 A,
1172 B
1173 }
1174 ",
1175 &["enum foo"],
1176 );
1177 assert_impl_action(&actions[0], 5);
1178 }
1055} 1179}