aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide/src/display
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_ide/src/display')
-rw-r--r--crates/ra_ide/src/display/function_signature.rs23
-rw-r--r--crates/ra_ide/src/display/navigation_target.rs85
-rw-r--r--crates/ra_ide/src/display/short_label.rs6
-rw-r--r--crates/ra_ide/src/display/structure.rs19
4 files changed, 73 insertions, 60 deletions
diff --git a/crates/ra_ide/src/display/function_signature.rs b/crates/ra_ide/src/display/function_signature.rs
index db3907fe6..9572debd8 100644
--- a/crates/ra_ide/src/display/function_signature.rs
+++ b/crates/ra_ide/src/display/function_signature.rs
@@ -1,5 +1,7 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2 2
3// FIXME: this modules relies on strings and AST way too much, and it should be
4// rewritten (matklad 2020-05-07)
3use std::{ 5use std::{
4 convert::From, 6 convert::From,
5 fmt::{self, Display}, 7 fmt::{self, Display},
@@ -82,8 +84,8 @@ impl FunctionSignature {
82 let ty = field.signature_ty(db); 84 let ty = field.signature_ty(db);
83 let raw_param = format!("{}", ty.display(db)); 85 let raw_param = format!("{}", ty.display(db));
84 86
85 if let Some(param_type) = raw_param.split(':').nth(1) { 87 if let Some(param_type) = raw_param.split(':').nth(1).and_then(|it| it.get(1..)) {
86 parameter_types.push(param_type[1..].to_string()); 88 parameter_types.push(param_type.to_string());
87 } else { 89 } else {
88 // useful when you have tuple struct 90 // useful when you have tuple struct
89 parameter_types.push(raw_param.clone()); 91 parameter_types.push(raw_param.clone());
@@ -127,8 +129,8 @@ impl FunctionSignature {
127 for field in variant.fields(db).into_iter() { 129 for field in variant.fields(db).into_iter() {
128 let ty = field.signature_ty(db); 130 let ty = field.signature_ty(db);
129 let raw_param = format!("{}", ty.display(db)); 131 let raw_param = format!("{}", ty.display(db));
130 if let Some(param_type) = raw_param.split(':').nth(1) { 132 if let Some(param_type) = raw_param.split(':').nth(1).and_then(|it| it.get(1..)) {
131 parameter_types.push(param_type[1..].to_string()); 133 parameter_types.push(param_type.to_string());
132 } else { 134 } else {
133 // The unwrap_or_else is useful when you have tuple 135 // The unwrap_or_else is useful when you have tuple
134 parameter_types.push(raw_param); 136 parameter_types.push(raw_param);
@@ -195,14 +197,23 @@ impl From<&'_ ast::FnDef> for FunctionSignature {
195 let raw_param = self_param.syntax().text().to_string(); 197 let raw_param = self_param.syntax().text().to_string();
196 198
197 res_types.push( 199 res_types.push(
198 raw_param.split(':').nth(1).unwrap_or_else(|| " Self")[1..].to_string(), 200 raw_param
201 .split(':')
202 .nth(1)
203 .and_then(|it| it.get(1..))
204 .unwrap_or_else(|| "Self")
205 .to_string(),
199 ); 206 );
200 res.push(raw_param); 207 res.push(raw_param);
201 } 208 }
202 209
203 res.extend(param_list.params().map(|param| param.syntax().text().to_string())); 210 res.extend(param_list.params().map(|param| param.syntax().text().to_string()));
204 res_types.extend(param_list.params().map(|param| { 211 res_types.extend(param_list.params().map(|param| {
205 param.syntax().text().to_string().split(':').nth(1).unwrap()[1..].to_string() 212 let param_text = param.syntax().text().to_string();
213 match param_text.split(':').nth(1).and_then(|it| it.get(1..)) {
214 Some(it) => it.to_string(),
215 None => param_text,
216 }
206 })); 217 }));
207 } 218 }
208 (has_self_param, res, res_types) 219 (has_self_param, res, res_types)
diff --git a/crates/ra_ide/src/display/navigation_target.rs b/crates/ra_ide/src/display/navigation_target.rs
index 914a8b471..c7bb1e69f 100644
--- a/crates/ra_ide/src/display/navigation_target.rs
+++ b/crates/ra_ide/src/display/navigation_target.rs
@@ -11,7 +11,7 @@ use ra_syntax::{
11 TextRange, 11 TextRange,
12}; 12};
13 13
14use crate::FileSymbol; 14use crate::{FileRange, FileSymbol};
15 15
16use super::short_label::ShortLabel; 16use super::short_label::ShortLabel;
17 17
@@ -22,10 +22,11 @@ use super::short_label::ShortLabel;
22/// code, like a function or a struct, but this is not strictly required. 22/// code, like a function or a struct, but this is not strictly required.
23#[derive(Debug, Clone, PartialEq, Eq, Hash)] 23#[derive(Debug, Clone, PartialEq, Eq, Hash)]
24pub struct NavigationTarget { 24pub struct NavigationTarget {
25 // FIXME: use FileRange?
25 file_id: FileId, 26 file_id: FileId,
27 full_range: TextRange,
26 name: SmolStr, 28 name: SmolStr,
27 kind: SyntaxKind, 29 kind: SyntaxKind,
28 full_range: TextRange,
29 focus_range: Option<TextRange>, 30 focus_range: Option<TextRange>,
30 container_name: Option<SmolStr>, 31 container_name: Option<SmolStr>,
31 description: Option<String>, 32 description: Option<String>,
@@ -63,6 +64,10 @@ impl NavigationTarget {
63 self.file_id 64 self.file_id
64 } 65 }
65 66
67 pub fn file_range(&self) -> FileRange {
68 FileRange { file_id: self.file_id, range: self.full_range }
69 }
70
66 pub fn full_range(&self) -> TextRange { 71 pub fn full_range(&self) -> TextRange {
67 self.full_range 72 self.full_range
68 } 73 }
@@ -87,15 +92,16 @@ impl NavigationTarget {
87 let name = module.name(db).map(|it| it.to_string().into()).unwrap_or_default(); 92 let name = module.name(db).map(|it| it.to_string().into()).unwrap_or_default();
88 if let Some(src) = module.declaration_source(db) { 93 if let Some(src) = module.declaration_source(db) {
89 let frange = original_range(db, src.as_ref().map(|it| it.syntax())); 94 let frange = original_range(db, src.as_ref().map(|it| it.syntax()));
90 return NavigationTarget::from_syntax( 95 let mut res = NavigationTarget::from_syntax(
91 frange.file_id, 96 frange.file_id,
92 name, 97 name,
93 None, 98 None,
94 frange.range, 99 frange.range,
95 src.value.syntax().kind(), 100 src.value.syntax().kind(),
96 src.value.doc_comment_text(),
97 src.value.short_label(),
98 ); 101 );
102 res.docs = src.value.doc_comment_text();
103 res.description = src.value.short_label();
104 return res;
99 } 105 }
100 module.to_nav(db) 106 module.to_nav(db)
101 } 107 }
@@ -125,11 +131,9 @@ impl NavigationTarget {
125 } 131 }
126 132
127 /// Allows `NavigationTarget` to be created from a `NameOwner` 133 /// Allows `NavigationTarget` to be created from a `NameOwner`
128 fn from_named( 134 pub(crate) fn from_named(
129 db: &RootDatabase, 135 db: &RootDatabase,
130 node: InFile<&dyn ast::NameOwner>, 136 node: InFile<&dyn ast::NameOwner>,
131 docs: Option<String>,
132 description: Option<String>,
133 ) -> NavigationTarget { 137 ) -> NavigationTarget {
134 //FIXME: use `_` instead of empty string 138 //FIXME: use `_` instead of empty string
135 let name = node.value.name().map(|it| it.text().clone()).unwrap_or_default(); 139 let name = node.value.name().map(|it| it.text().clone()).unwrap_or_default();
@@ -143,8 +147,6 @@ impl NavigationTarget {
143 focus_range, 147 focus_range,
144 frange.range, 148 frange.range,
145 node.value.syntax().kind(), 149 node.value.syntax().kind(),
146 docs,
147 description,
148 ) 150 )
149 } 151 }
150 152
@@ -154,8 +156,6 @@ impl NavigationTarget {
154 focus_range: Option<TextRange>, 156 focus_range: Option<TextRange>,
155 full_range: TextRange, 157 full_range: TextRange,
156 kind: SyntaxKind, 158 kind: SyntaxKind,
157 docs: Option<String>,
158 description: Option<String>,
159 ) -> NavigationTarget { 159 ) -> NavigationTarget {
160 NavigationTarget { 160 NavigationTarget {
161 file_id, 161 file_id,
@@ -164,8 +164,8 @@ impl NavigationTarget {
164 full_range, 164 full_range,
165 focus_range, 165 focus_range,
166 container_name: None, 166 container_name: None,
167 description, 167 description: None,
168 docs, 168 docs: None,
169 } 169 }
170 } 170 }
171} 171}
@@ -233,12 +233,11 @@ where
233{ 233{
234 fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { 234 fn to_nav(&self, db: &RootDatabase) -> NavigationTarget {
235 let src = self.source(db); 235 let src = self.source(db);
236 NavigationTarget::from_named( 236 let mut res =
237 db, 237 NavigationTarget::from_named(db, src.as_ref().map(|it| it as &dyn ast::NameOwner));
238 src.as_ref().map(|it| it as &dyn ast::NameOwner), 238 res.docs = src.value.doc_comment_text();
239 src.value.doc_comment_text(), 239 res.description = src.value.short_label();
240 src.value.short_label(), 240 res
241 )
242 } 241 }
243} 242}
244 243
@@ -253,15 +252,7 @@ impl ToNav for hir::Module {
253 } 252 }
254 }; 253 };
255 let frange = original_range(db, src.with_value(syntax)); 254 let frange = original_range(db, src.with_value(syntax));
256 NavigationTarget::from_syntax( 255 NavigationTarget::from_syntax(frange.file_id, name, focus, frange.range, syntax.kind())
257 frange.file_id,
258 name,
259 focus,
260 frange.range,
261 syntax.kind(),
262 None,
263 None,
264 )
265 } 256 }
266} 257}
267 258
@@ -280,8 +271,6 @@ impl ToNav for hir::ImplDef {
280 None, 271 None,
281 frange.range, 272 frange.range,
282 src.value.syntax().kind(), 273 src.value.syntax().kind(),
283 None,
284 None,
285 ) 274 )
286 } 275 }
287} 276}
@@ -291,12 +280,12 @@ impl ToNav for hir::Field {
291 let src = self.source(db); 280 let src = self.source(db);
292 281
293 match &src.value { 282 match &src.value {
294 FieldSource::Named(it) => NavigationTarget::from_named( 283 FieldSource::Named(it) => {
295 db, 284 let mut res = NavigationTarget::from_named(db, src.with_value(it));
296 src.with_value(it), 285 res.docs = it.doc_comment_text();
297 it.doc_comment_text(), 286 res.description = it.short_label();
298 it.short_label(), 287 res
299 ), 288 }
300 FieldSource::Pos(it) => { 289 FieldSource::Pos(it) => {
301 let frange = original_range(db, src.with_value(it.syntax())); 290 let frange = original_range(db, src.with_value(it.syntax()));
302 NavigationTarget::from_syntax( 291 NavigationTarget::from_syntax(
@@ -305,8 +294,6 @@ impl ToNav for hir::Field {
305 None, 294 None,
306 frange.range, 295 frange.range,
307 it.syntax().kind(), 296 it.syntax().kind(),
308 None,
309 None,
310 ) 297 )
311 } 298 }
312 } 299 }
@@ -317,12 +304,10 @@ impl ToNav for hir::MacroDef {
317 fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { 304 fn to_nav(&self, db: &RootDatabase) -> NavigationTarget {
318 let src = self.source(db); 305 let src = self.source(db);
319 log::debug!("nav target {:#?}", src.value.syntax()); 306 log::debug!("nav target {:#?}", src.value.syntax());
320 NavigationTarget::from_named( 307 let mut res =
321 db, 308 NavigationTarget::from_named(db, src.as_ref().map(|it| it as &dyn ast::NameOwner));
322 src.as_ref().map(|it| it as &dyn ast::NameOwner), 309 res.docs = src.value.doc_comment_text();
323 src.value.doc_comment_text(), 310 res
324 None,
325 )
326 } 311 }
327} 312}
328 313
@@ -376,16 +361,20 @@ impl ToNav for hir::Local {
376impl ToNav for hir::TypeParam { 361impl ToNav for hir::TypeParam {
377 fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { 362 fn to_nav(&self, db: &RootDatabase) -> NavigationTarget {
378 let src = self.source(db); 363 let src = self.source(db);
379 let range = match src.value { 364 let full_range = match &src.value {
380 Either::Left(it) => it.syntax().text_range(), 365 Either::Left(it) => it.syntax().text_range(),
381 Either::Right(it) => it.syntax().text_range(), 366 Either::Right(it) => it.syntax().text_range(),
382 }; 367 };
368 let focus_range = match &src.value {
369 Either::Left(_) => None,
370 Either::Right(it) => it.name().map(|it| it.syntax().text_range()),
371 };
383 NavigationTarget { 372 NavigationTarget {
384 file_id: src.file_id.original_file(db), 373 file_id: src.file_id.original_file(db),
385 name: self.name(db).to_string().into(), 374 name: self.name(db).to_string().into(),
386 kind: TYPE_PARAM, 375 kind: TYPE_PARAM,
387 full_range: range, 376 full_range,
388 focus_range: None, 377 focus_range,
389 container_name: None, 378 container_name: None,
390 description: None, 379 description: None,
391 docs: None, 380 docs: None,
diff --git a/crates/ra_ide/src/display/short_label.rs b/crates/ra_ide/src/display/short_label.rs
index 4b081bf6c..d37260e96 100644
--- a/crates/ra_ide/src/display/short_label.rs
+++ b/crates/ra_ide/src/display/short_label.rs
@@ -33,7 +33,11 @@ impl ShortLabel for ast::EnumDef {
33 33
34impl ShortLabel for ast::TraitDef { 34impl ShortLabel for ast::TraitDef {
35 fn short_label(&self) -> Option<String> { 35 fn short_label(&self) -> Option<String> {
36 short_label_from_node(self, "trait ") 36 if self.unsafe_token().is_some() {
37 short_label_from_node(self, "unsafe trait ")
38 } else {
39 short_label_from_node(self, "trait ")
40 }
37 } 41 }
38} 42}
39 43
diff --git a/crates/ra_ide/src/display/structure.rs b/crates/ra_ide/src/display/structure.rs
index 967eee5d2..aad5a8e4d 100644
--- a/crates/ra_ide/src/display/structure.rs
+++ b/crates/ra_ide/src/display/structure.rs
@@ -1,10 +1,6 @@
1//! FIXME: write short doc here
2
3use crate::TextRange;
4
5use ra_syntax::{ 1use ra_syntax::{
6 ast::{self, AttrsOwner, NameOwner, TypeAscriptionOwner, TypeParamsOwner}, 2 ast::{self, AttrsOwner, NameOwner, TypeAscriptionOwner, TypeParamsOwner},
7 match_ast, AstNode, SourceFile, SyntaxKind, SyntaxNode, WalkEvent, 3 match_ast, AstNode, SourceFile, SyntaxKind, SyntaxNode, TextRange, WalkEvent,
8}; 4};
9 5
10#[derive(Debug, Clone)] 6#[derive(Debug, Clone)]
@@ -18,6 +14,19 @@ pub struct StructureNode {
18 pub deprecated: bool, 14 pub deprecated: bool,
19} 15}
20 16
17// Feature: File Structure
18//
19// Provides a tree of the symbols defined in the file. Can be used to
20//
21// * fuzzy search symbol in a file (super useful)
22// * draw breadcrumbs to describe the context around the cursor
23// * draw outline of the file
24//
25// |===
26// | Editor | Shortcut
27//
28// | VS Code | kbd:[Ctrl+Shift+O]
29// |===
21pub fn file_structure(file: &SourceFile) -> Vec<StructureNode> { 30pub fn file_structure(file: &SourceFile) -> Vec<StructureNode> {
22 let mut res = Vec::new(); 31 let mut res = Vec::new();
23 let mut stack = Vec::new(); 32 let mut stack = Vec::new();