diff options
Diffstat (limited to 'crates/ide/src')
36 files changed, 512 insertions, 122 deletions
diff --git a/crates/ide/src/annotations.rs b/crates/ide/src/annotations.rs index 64bc926f1..5ebe7fd0e 100644 --- a/crates/ide/src/annotations.rs +++ b/crates/ide/src/annotations.rs | |||
@@ -19,6 +19,8 @@ use crate::{ | |||
19 | // | 19 | // |
20 | // Provides user with annotations above items for looking up references or impl blocks | 20 | // Provides user with annotations above items for looking up references or impl blocks |
21 | // and running/debugging binaries. | 21 | // and running/debugging binaries. |
22 | // | ||
23 | // image::https://user-images.githubusercontent.com/48062697/113020672-b7c34f00-917a-11eb-8f6e-858735660a0e.png[] | ||
22 | #[derive(Debug)] | 24 | #[derive(Debug)] |
23 | pub struct Annotation { | 25 | pub struct Annotation { |
24 | pub range: TextRange, | 26 | pub range: TextRange, |
diff --git a/crates/ide/src/diagnostics.rs b/crates/ide/src/diagnostics.rs index 22697a537..dd42116a7 100644 --- a/crates/ide/src/diagnostics.rs +++ b/crates/ide/src/diagnostics.rs | |||
@@ -165,7 +165,6 @@ pub(crate) fn diagnostics( | |||
165 | sema.diagnostics_display_range(d.display_source()).range, | 165 | sema.diagnostics_display_range(d.display_source()).range, |
166 | d.message(), | 166 | d.message(), |
167 | ) | 167 | ) |
168 | .with_unused(true) | ||
169 | .with_fix(d.fix(&sema)) | 168 | .with_fix(d.fix(&sema)) |
170 | .with_code(Some(d.code())), | 169 | .with_code(Some(d.code())), |
171 | ); | 170 | ); |
diff --git a/crates/ide/src/diagnostics/fixes.rs b/crates/ide/src/diagnostics/fixes.rs index 2f840909c..5fb3e2d91 100644 --- a/crates/ide/src/diagnostics/fixes.rs +++ b/crates/ide/src/diagnostics/fixes.rs | |||
@@ -210,7 +210,7 @@ fn missing_record_expr_field_fix( | |||
210 | } | 210 | } |
211 | let new_field = make::record_field( | 211 | let new_field = make::record_field( |
212 | None, | 212 | None, |
213 | make::name(record_expr_field.field_name()?.text()), | 213 | make::name(&record_expr_field.field_name()?.text()), |
214 | make::ty(&new_field_type.display_source_code(sema.db, module.into()).ok()?), | 214 | make::ty(&new_field_type.display_source_code(sema.db, module.into()).ok()?), |
215 | ); | 215 | ); |
216 | 216 | ||
diff --git a/crates/ide/src/diagnostics/unlinked_file.rs b/crates/ide/src/diagnostics/unlinked_file.rs index 019b0b440..e174fb767 100644 --- a/crates/ide/src/diagnostics/unlinked_file.rs +++ b/crates/ide/src/diagnostics/unlinked_file.rs | |||
@@ -63,7 +63,7 @@ impl DiagnosticWithFix for UnlinkedFile { | |||
63 | // - `$dir.rs` in the parent folder, where `$dir` is the directory containing `self.file_id` | 63 | // - `$dir.rs` in the parent folder, where `$dir` is the directory containing `self.file_id` |
64 | let parent = our_path.parent()?; | 64 | let parent = our_path.parent()?; |
65 | let mut paths = | 65 | let mut paths = |
66 | vec![parent.join("mod.rs")?, parent.join("main.rs")?, parent.join("lib.rs")?]; | 66 | vec![parent.join("mod.rs")?, parent.join("lib.rs")?, parent.join("main.rs")?]; |
67 | 67 | ||
68 | // `submod/bla.rs` -> `submod.rs` | 68 | // `submod/bla.rs` -> `submod.rs` |
69 | if let Some(newmod) = (|| { | 69 | if let Some(newmod) = (|| { |
diff --git a/crates/ide/src/doc_links.rs b/crates/ide/src/doc_links.rs index 0cee741ac..67e2e5a1c 100644 --- a/crates/ide/src/doc_links.rs +++ b/crates/ide/src/doc_links.rs | |||
@@ -98,6 +98,29 @@ pub(crate) fn remove_links(markdown: &str) -> String { | |||
98 | out | 98 | out |
99 | } | 99 | } |
100 | 100 | ||
101 | /// Retrieve a link to documentation for the given symbol. | ||
102 | pub(crate) fn external_docs( | ||
103 | db: &RootDatabase, | ||
104 | position: &FilePosition, | ||
105 | ) -> Option<DocumentationLink> { | ||
106 | let sema = Semantics::new(db); | ||
107 | let file = sema.parse(position.file_id).syntax().clone(); | ||
108 | let token = pick_best(file.token_at_offset(position.offset))?; | ||
109 | let token = sema.descend_into_macros(token); | ||
110 | |||
111 | let node = token.parent()?; | ||
112 | let definition = match_ast! { | ||
113 | match node { | ||
114 | ast::NameRef(name_ref) => NameRefClass::classify(&sema, &name_ref).map(|d| d.referenced(sema.db)), | ||
115 | ast::Name(name) => NameClass::classify(&sema, &name).map(|d| d.referenced_or_defined(sema.db)), | ||
116 | _ => None, | ||
117 | } | ||
118 | }; | ||
119 | |||
120 | get_doc_link(db, definition?) | ||
121 | } | ||
122 | |||
123 | /// Extracts all links from a given markdown text. | ||
101 | pub(crate) fn extract_definitions_from_markdown( | 124 | pub(crate) fn extract_definitions_from_markdown( |
102 | markdown: &str, | 125 | markdown: &str, |
103 | ) -> Vec<(Range<usize>, String, Option<hir::Namespace>)> { | 126 | ) -> Vec<(Range<usize>, String, Option<hir::Namespace>)> { |
@@ -161,7 +184,7 @@ pub(crate) fn doc_owner_to_def( | |||
161 | ast::Variant(it) => sema.to_def(&it)?.into(), | 184 | ast::Variant(it) => sema.to_def(&it)?.into(), |
162 | ast::Trait(it) => sema.to_def(&it)?.into(), | 185 | ast::Trait(it) => sema.to_def(&it)?.into(), |
163 | ast::Impl(it) => return sema.to_def(&it).map(Definition::SelfType), | 186 | ast::Impl(it) => return sema.to_def(&it).map(Definition::SelfType), |
164 | ast::MacroRules(it) => return sema.to_def(&it).map(Definition::Macro), | 187 | ast::Macro(it) => return sema.to_def(&it).map(Definition::Macro), |
165 | ast::TupleField(it) => return sema.to_def(&it).map(Definition::Field), | 188 | ast::TupleField(it) => return sema.to_def(&it).map(Definition::Field), |
166 | ast::RecordField(it) => return sema.to_def(&it).map(Definition::Field), | 189 | ast::RecordField(it) => return sema.to_def(&it).map(Definition::Field), |
167 | _ => return None, | 190 | _ => return None, |
@@ -178,15 +201,15 @@ pub(crate) fn resolve_doc_path_for_def( | |||
178 | ) -> Option<hir::ModuleDef> { | 201 | ) -> Option<hir::ModuleDef> { |
179 | match def { | 202 | match def { |
180 | Definition::ModuleDef(def) => match def { | 203 | Definition::ModuleDef(def) => match def { |
181 | ModuleDef::Module(it) => it.resolve_doc_path(db, &link, ns), | 204 | hir::ModuleDef::Module(it) => it.resolve_doc_path(db, &link, ns), |
182 | ModuleDef::Function(it) => it.resolve_doc_path(db, &link, ns), | 205 | hir::ModuleDef::Function(it) => it.resolve_doc_path(db, &link, ns), |
183 | ModuleDef::Adt(it) => it.resolve_doc_path(db, &link, ns), | 206 | hir::ModuleDef::Adt(it) => it.resolve_doc_path(db, &link, ns), |
184 | ModuleDef::Variant(it) => it.resolve_doc_path(db, &link, ns), | 207 | hir::ModuleDef::Variant(it) => it.resolve_doc_path(db, &link, ns), |
185 | ModuleDef::Const(it) => it.resolve_doc_path(db, &link, ns), | 208 | hir::ModuleDef::Const(it) => it.resolve_doc_path(db, &link, ns), |
186 | ModuleDef::Static(it) => it.resolve_doc_path(db, &link, ns), | 209 | hir::ModuleDef::Static(it) => it.resolve_doc_path(db, &link, ns), |
187 | ModuleDef::Trait(it) => it.resolve_doc_path(db, &link, ns), | 210 | hir::ModuleDef::Trait(it) => it.resolve_doc_path(db, &link, ns), |
188 | ModuleDef::TypeAlias(it) => it.resolve_doc_path(db, &link, ns), | 211 | hir::ModuleDef::TypeAlias(it) => it.resolve_doc_path(db, &link, ns), |
189 | ModuleDef::BuiltinType(_) => None, | 212 | hir::ModuleDef::BuiltinType(_) => None, |
190 | }, | 213 | }, |
191 | Definition::Macro(it) => it.resolve_doc_path(db, &link, ns), | 214 | Definition::Macro(it) => it.resolve_doc_path(db, &link, ns), |
192 | Definition::Field(it) => it.resolve_doc_path(db, &link, ns), | 215 | Definition::Field(it) => it.resolve_doc_path(db, &link, ns), |
@@ -214,7 +237,7 @@ fn get_doc_link(db: &RootDatabase, definition: Definition) -> Option<String> { | |||
214 | .and_then(|assoc| match assoc.container(db) { | 237 | .and_then(|assoc| match assoc.container(db) { |
215 | AssocItemContainer::Trait(t) => Some(t.into()), | 238 | AssocItemContainer::Trait(t) => Some(t.into()), |
216 | AssocItemContainer::Impl(impld) => { | 239 | AssocItemContainer::Impl(impld) => { |
217 | impld.target_ty(db).as_adt().map(|adt| adt.into()) | 240 | impld.self_ty(db).as_adt().map(|adt| adt.into()) |
218 | } | 241 | } |
219 | }) | 242 | }) |
220 | .unwrap_or_else(|| f.clone().into()), | 243 | .unwrap_or_else(|| f.clone().into()), |
@@ -328,28 +351,6 @@ fn rewrite_url_link(db: &RootDatabase, def: ModuleDef, target: &str) -> Option<S | |||
328 | .map(|url| url.into_string()) | 351 | .map(|url| url.into_string()) |
329 | } | 352 | } |
330 | 353 | ||
331 | /// Retrieve a link to documentation for the given symbol. | ||
332 | pub(crate) fn external_docs( | ||
333 | db: &RootDatabase, | ||
334 | position: &FilePosition, | ||
335 | ) -> Option<DocumentationLink> { | ||
336 | let sema = Semantics::new(db); | ||
337 | let file = sema.parse(position.file_id).syntax().clone(); | ||
338 | let token = pick_best(file.token_at_offset(position.offset))?; | ||
339 | let token = sema.descend_into_macros(token); | ||
340 | |||
341 | let node = token.parent()?; | ||
342 | let definition = match_ast! { | ||
343 | match node { | ||
344 | ast::NameRef(name_ref) => NameRefClass::classify(&sema, &name_ref).map(|d| d.referenced(sema.db)), | ||
345 | ast::Name(name) => NameClass::classify(&sema, &name).map(|d| d.referenced_or_defined(sema.db)), | ||
346 | _ => None, | ||
347 | } | ||
348 | }; | ||
349 | |||
350 | get_doc_link(db, definition?) | ||
351 | } | ||
352 | |||
353 | /// Rewrites a markdown document, applying 'callback' to each link. | 354 | /// Rewrites a markdown document, applying 'callback' to each link. |
354 | fn map_links<'e>( | 355 | fn map_links<'e>( |
355 | events: impl Iterator<Item = Event<'e>>, | 356 | events: impl Iterator<Item = Event<'e>>, |
diff --git a/crates/ide/src/expand_macro.rs b/crates/ide/src/expand_macro.rs index ffb3a6f7d..9eeabbeda 100644 --- a/crates/ide/src/expand_macro.rs +++ b/crates/ide/src/expand_macro.rs | |||
@@ -23,6 +23,8 @@ pub struct ExpandedMacro { | |||
23 | // | 23 | // |
24 | // | VS Code | **Rust Analyzer: Expand macro recursively** | 24 | // | VS Code | **Rust Analyzer: Expand macro recursively** |
25 | // |=== | 25 | // |=== |
26 | // | ||
27 | // image::https://user-images.githubusercontent.com/48062697/113020648-b3973180-917a-11eb-84a9-ecb921293dc5.gif[] | ||
26 | pub(crate) fn expand_macro(db: &RootDatabase, position: FilePosition) -> Option<ExpandedMacro> { | 28 | pub(crate) fn expand_macro(db: &RootDatabase, position: FilePosition) -> Option<ExpandedMacro> { |
27 | let sema = Semantics::new(db); | 29 | let sema = Semantics::new(db); |
28 | let file = sema.parse(position.file_id); | 30 | let file = sema.parse(position.file_id); |
diff --git a/crates/ide/src/extend_selection.rs b/crates/ide/src/extend_selection.rs index 5201ce587..7032889ac 100644 --- a/crates/ide/src/extend_selection.rs +++ b/crates/ide/src/extend_selection.rs | |||
@@ -24,6 +24,8 @@ use crate::FileRange; | |||
24 | // | 24 | // |
25 | // | VS Code | kbd:[Alt+Shift+→], kbd:[Alt+Shift+←] | 25 | // | VS Code | kbd:[Alt+Shift+→], kbd:[Alt+Shift+←] |
26 | // |=== | 26 | // |=== |
27 | // | ||
28 | // image::https://user-images.githubusercontent.com/48062697/113020651-b42fc800-917a-11eb-8a4f-cf1a07859fac.gif[] | ||
27 | pub(crate) fn extend_selection(db: &RootDatabase, frange: FileRange) -> TextRange { | 29 | pub(crate) fn extend_selection(db: &RootDatabase, frange: FileRange) -> TextRange { |
28 | let sema = Semantics::new(db); | 30 | let sema = Semantics::new(db); |
29 | let src = sema.parse(frange.file_id); | 31 | let src = sema.parse(frange.file_id); |
diff --git a/crates/ide/src/file_structure.rs b/crates/ide/src/file_structure.rs index 9f879a66e..19071d6be 100644 --- a/crates/ide/src/file_structure.rs +++ b/crates/ide/src/file_structure.rs | |||
@@ -35,6 +35,9 @@ pub enum StructureNodeKind { | |||
35 | // | 35 | // |
36 | // | VS Code | kbd:[Ctrl+Shift+O] | 36 | // | VS Code | kbd:[Ctrl+Shift+O] |
37 | // |=== | 37 | // |=== |
38 | // | ||
39 | // image::https://user-images.githubusercontent.com/48062697/113020654-b42fc800-917a-11eb-8388-e7dc4d92b02e.gif[] | ||
40 | |||
38 | pub(crate) fn file_structure(file: &SourceFile) -> Vec<StructureNode> { | 41 | pub(crate) fn file_structure(file: &SourceFile) -> Vec<StructureNode> { |
39 | let mut res = Vec::new(); | 42 | let mut res = Vec::new(); |
40 | let mut stack = Vec::new(); | 43 | let mut stack = Vec::new(); |
@@ -172,7 +175,7 @@ fn structure_node(node: &SyntaxNode) -> Option<StructureNode> { | |||
172 | }; | 175 | }; |
173 | Some(node) | 176 | Some(node) |
174 | }, | 177 | }, |
175 | ast::MacroRules(it) => decl(it, StructureNodeKind::SymbolKind(SymbolKind::Macro)), | 178 | ast::Macro(it) => decl(it, StructureNodeKind::SymbolKind(SymbolKind::Macro)), |
176 | _ => None, | 179 | _ => None, |
177 | } | 180 | } |
178 | } | 181 | } |
diff --git a/crates/ide/src/folding_ranges.rs b/crates/ide/src/folding_ranges.rs index 4b1b24562..153726ce8 100644 --- a/crates/ide/src/folding_ranges.rs +++ b/crates/ide/src/folding_ranges.rs | |||
@@ -17,6 +17,8 @@ pub enum FoldKind { | |||
17 | Block, | 17 | Block, |
18 | ArgList, | 18 | ArgList, |
19 | Region, | 19 | Region, |
20 | Consts, | ||
21 | Statics, | ||
20 | } | 22 | } |
21 | 23 | ||
22 | #[derive(Debug)] | 24 | #[derive(Debug)] |
@@ -30,6 +32,8 @@ pub(crate) fn folding_ranges(file: &SourceFile) -> Vec<Fold> { | |||
30 | let mut visited_comments = FxHashSet::default(); | 32 | let mut visited_comments = FxHashSet::default(); |
31 | let mut visited_imports = FxHashSet::default(); | 33 | let mut visited_imports = FxHashSet::default(); |
32 | let mut visited_mods = FxHashSet::default(); | 34 | let mut visited_mods = FxHashSet::default(); |
35 | let mut visited_consts = FxHashSet::default(); | ||
36 | let mut visited_statics = FxHashSet::default(); | ||
33 | // regions can be nested, here is a LIFO buffer | 37 | // regions can be nested, here is a LIFO buffer |
34 | let mut regions_starts: Vec<TextSize> = vec![]; | 38 | let mut regions_starts: Vec<TextSize> = vec![]; |
35 | 39 | ||
@@ -91,6 +95,19 @@ pub(crate) fn folding_ranges(file: &SourceFile) -> Vec<Fold> { | |||
91 | res.push(Fold { range, kind: FoldKind::Mods }) | 95 | res.push(Fold { range, kind: FoldKind::Mods }) |
92 | } | 96 | } |
93 | } | 97 | } |
98 | |||
99 | // Fold groups of consts | ||
100 | if node.kind() == CONST && !visited_consts.contains(&node) { | ||
101 | if let Some(range) = contiguous_range_for_group(&node, &mut visited_consts) { | ||
102 | res.push(Fold { range, kind: FoldKind::Consts }) | ||
103 | } | ||
104 | } | ||
105 | // Fold groups of consts | ||
106 | if node.kind() == STATIC && !visited_statics.contains(&node) { | ||
107 | if let Some(range) = contiguous_range_for_group(&node, &mut visited_statics) { | ||
108 | res.push(Fold { range, kind: FoldKind::Statics }) | ||
109 | } | ||
110 | } | ||
94 | } | 111 | } |
95 | } | 112 | } |
96 | } | 113 | } |
@@ -250,6 +267,8 @@ mod tests { | |||
250 | FoldKind::Block => "block", | 267 | FoldKind::Block => "block", |
251 | FoldKind::ArgList => "arglist", | 268 | FoldKind::ArgList => "arglist", |
252 | FoldKind::Region => "region", | 269 | FoldKind::Region => "region", |
270 | FoldKind::Consts => "consts", | ||
271 | FoldKind::Statics => "statics", | ||
253 | }; | 272 | }; |
254 | assert_eq!(kind, &attr.unwrap()); | 273 | assert_eq!(kind, &attr.unwrap()); |
255 | } | 274 | } |
@@ -457,4 +476,24 @@ calling_function(x,y); | |||
457 | "#, | 476 | "#, |
458 | ) | 477 | ) |
459 | } | 478 | } |
479 | |||
480 | #[test] | ||
481 | fn fold_consecutive_const() { | ||
482 | check( | ||
483 | r#" | ||
484 | <fold consts>const FIRST_CONST: &str = "first"; | ||
485 | const SECOND_CONST: &str = "second";</fold> | ||
486 | "#, | ||
487 | ) | ||
488 | } | ||
489 | |||
490 | #[test] | ||
491 | fn fold_consecutive_static() { | ||
492 | check( | ||
493 | r#" | ||
494 | <fold statics>static FIRST_STATIC: &str = "first"; | ||
495 | static SECOND_STATIC: &str = "second";</fold> | ||
496 | "#, | ||
497 | ) | ||
498 | } | ||
460 | } | 499 | } |
diff --git a/crates/ide/src/goto_definition.rs b/crates/ide/src/goto_definition.rs index a2c97061f..8574d1e3f 100644 --- a/crates/ide/src/goto_definition.rs +++ b/crates/ide/src/goto_definition.rs | |||
@@ -21,6 +21,8 @@ use crate::{ | |||
21 | // | 21 | // |
22 | // | VS Code | kbd:[F12] | 22 | // | VS Code | kbd:[F12] |
23 | // |=== | 23 | // |=== |
24 | // | ||
25 | // image::https://user-images.githubusercontent.com/48062697/113065563-025fbe00-91b1-11eb-83e4-a5a703610b23.gif[] | ||
24 | pub(crate) fn goto_definition( | 26 | pub(crate) fn goto_definition( |
25 | db: &RootDatabase, | 27 | db: &RootDatabase, |
26 | position: FilePosition, | 28 | position: FilePosition, |
@@ -918,6 +920,21 @@ fn f() -> impl Iterator<Item$0 = u8> {} | |||
918 | } | 920 | } |
919 | 921 | ||
920 | #[test] | 922 | #[test] |
923 | #[should_panic = "unresolved reference"] | ||
924 | fn unknown_assoc_ty() { | ||
925 | check( | ||
926 | r#" | ||
927 | trait Iterator { | ||
928 | type Item; | ||
929 | //^^^^ | ||
930 | } | ||
931 | |||
932 | fn f() -> impl Iterator<Invalid$0 = u8> {} | ||
933 | "#, | ||
934 | ) | ||
935 | } | ||
936 | |||
937 | #[test] | ||
921 | fn goto_def_for_assoc_ty_in_path_multiple() { | 938 | fn goto_def_for_assoc_ty_in_path_multiple() { |
922 | check( | 939 | check( |
923 | r#" | 940 | r#" |
diff --git a/crates/ide/src/goto_implementation.rs b/crates/ide/src/goto_implementation.rs index f4d7c14a6..05130a237 100644 --- a/crates/ide/src/goto_implementation.rs +++ b/crates/ide/src/goto_implementation.rs | |||
@@ -16,6 +16,8 @@ use crate::{display::TryToNav, FilePosition, NavigationTarget, RangeInfo}; | |||
16 | // | 16 | // |
17 | // | VS Code | kbd:[Ctrl+F12] | 17 | // | VS Code | kbd:[Ctrl+F12] |
18 | // |=== | 18 | // |=== |
19 | // | ||
20 | // image::https://user-images.githubusercontent.com/48062697/113065566-02f85480-91b1-11eb-9288-aaad8abd8841.gif[] | ||
19 | pub(crate) fn goto_implementation( | 21 | pub(crate) fn goto_implementation( |
20 | db: &RootDatabase, | 22 | db: &RootDatabase, |
21 | position: FilePosition, | 23 | position: FilePosition, |
diff --git a/crates/ide/src/goto_type_definition.rs b/crates/ide/src/goto_type_definition.rs index 2d38cb112..9d34b109b 100644 --- a/crates/ide/src/goto_type_definition.rs +++ b/crates/ide/src/goto_type_definition.rs | |||
@@ -12,6 +12,8 @@ use crate::{display::TryToNav, FilePosition, NavigationTarget, RangeInfo}; | |||
12 | // | 12 | // |
13 | // | VS Code | **Go to Type Definition* | 13 | // | VS Code | **Go to Type Definition* |
14 | // |=== | 14 | // |=== |
15 | // | ||
16 | // image::https://user-images.githubusercontent.com/48062697/113020657-b560f500-917a-11eb-9007-0f809733a338.gif[] | ||
15 | pub(crate) fn goto_type_definition( | 17 | pub(crate) fn goto_type_definition( |
16 | db: &RootDatabase, | 18 | db: &RootDatabase, |
17 | position: FilePosition, | 19 | position: FilePosition, |
diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs index c43089476..5f9edb476 100644 --- a/crates/ide/src/hover.rs +++ b/crates/ide/src/hover.rs | |||
@@ -82,6 +82,8 @@ pub struct HoverResult { | |||
82 | // | 82 | // |
83 | // Shows additional information, like type of an expression or documentation for definition when "focusing" code. | 83 | // Shows additional information, like type of an expression or documentation for definition when "focusing" code. |
84 | // Focusing is usually hovering with a mouse, but can also be triggered with a shortcut. | 84 | // Focusing is usually hovering with a mouse, but can also be triggered with a shortcut. |
85 | // | ||
86 | // image::https://user-images.githubusercontent.com/48062697/113020658-b5f98b80-917a-11eb-9f88-3dbc27320c95.gif[] | ||
85 | pub(crate) fn hover( | 87 | pub(crate) fn hover( |
86 | db: &RootDatabase, | 88 | db: &RootDatabase, |
87 | position: FilePosition, | 89 | position: FilePosition, |
@@ -195,7 +197,7 @@ fn show_implementations_action(db: &RootDatabase, def: Definition) -> Option<Hov | |||
195 | let adt = match def { | 197 | let adt = match def { |
196 | Definition::ModuleDef(ModuleDef::Trait(it)) => return it.try_to_nav(db).map(to_action), | 198 | Definition::ModuleDef(ModuleDef::Trait(it)) => return it.try_to_nav(db).map(to_action), |
197 | Definition::ModuleDef(ModuleDef::Adt(it)) => Some(it), | 199 | Definition::ModuleDef(ModuleDef::Adt(it)) => Some(it), |
198 | Definition::SelfType(it) => it.target_ty(db).as_adt(), | 200 | Definition::SelfType(it) => it.self_ty(db).as_adt(), |
199 | _ => None, | 201 | _ => None, |
200 | }?; | 202 | }?; |
201 | adt.try_to_nav(db).map(to_action) | 203 | adt.try_to_nav(db).map(to_action) |
@@ -318,7 +320,7 @@ fn definition_owner_name(db: &RootDatabase, def: &Definition) -> Option<String> | |||
318 | Definition::ModuleDef(md) => match md { | 320 | Definition::ModuleDef(md) => match md { |
319 | ModuleDef::Function(f) => match f.as_assoc_item(db)?.container(db) { | 321 | ModuleDef::Function(f) => match f.as_assoc_item(db)?.container(db) { |
320 | AssocItemContainer::Trait(t) => Some(t.name(db)), | 322 | AssocItemContainer::Trait(t) => Some(t.name(db)), |
321 | AssocItemContainer::Impl(i) => i.target_ty(db).as_adt().map(|adt| adt.name(db)), | 323 | AssocItemContainer::Impl(i) => i.self_ty(db).as_adt().map(|adt| adt.name(db)), |
322 | }, | 324 | }, |
323 | ModuleDef::Variant(e) => Some(e.parent_enum(db).name(db)), | 325 | ModuleDef::Variant(e) => Some(e.parent_enum(db).name(db)), |
324 | _ => None, | 326 | _ => None, |
@@ -376,7 +378,7 @@ fn hover_for_definition( | |||
376 | }, | 378 | }, |
377 | Definition::Local(it) => hover_for_local(it, db), | 379 | Definition::Local(it) => hover_for_local(it, db), |
378 | Definition::SelfType(impl_def) => { | 380 | Definition::SelfType(impl_def) => { |
379 | impl_def.target_ty(db).as_adt().and_then(|adt| from_hir_fmt(db, adt, mod_path)) | 381 | impl_def.self_ty(db).as_adt().and_then(|adt| from_hir_fmt(db, adt, mod_path)) |
380 | } | 382 | } |
381 | Definition::GenericParam(it) => from_hir_fmt(db, it, None), | 383 | Definition::GenericParam(it) => from_hir_fmt(db, it, None), |
382 | Definition::Label(it) => Some(Markup::fenced_block(&it.name(db))), | 384 | Definition::Label(it) => Some(Markup::fenced_block(&it.name(db))), |
@@ -470,6 +472,7 @@ fn find_std_module(famous_defs: &FamousDefs, name: &str) -> Option<hir::Module> | |||
470 | 472 | ||
471 | fn pick_best(tokens: TokenAtOffset<SyntaxToken>) -> Option<SyntaxToken> { | 473 | fn pick_best(tokens: TokenAtOffset<SyntaxToken>) -> Option<SyntaxToken> { |
472 | return tokens.max_by_key(priority); | 474 | return tokens.max_by_key(priority); |
475 | |||
473 | fn priority(n: &SyntaxToken) -> usize { | 476 | fn priority(n: &SyntaxToken) -> usize { |
474 | match n.kind() { | 477 | match n.kind() { |
475 | IDENT | INT_NUMBER | LIFETIME_IDENT | T![self] | T![super] | T![crate] => 3, | 478 | IDENT | INT_NUMBER | LIFETIME_IDENT | T![self] | T![super] | T![crate] => 3, |
@@ -1235,6 +1238,37 @@ fn f() { fo$0o!(); } | |||
1235 | } | 1238 | } |
1236 | 1239 | ||
1237 | #[test] | 1240 | #[test] |
1241 | fn test_hover_macro2_invocation() { | ||
1242 | check( | ||
1243 | r#" | ||
1244 | /// foo bar | ||
1245 | /// | ||
1246 | /// foo bar baz | ||
1247 | macro foo() {} | ||
1248 | |||
1249 | fn f() { fo$0o!(); } | ||
1250 | "#, | ||
1251 | expect![[r#" | ||
1252 | *foo* | ||
1253 | |||
1254 | ```rust | ||
1255 | test | ||
1256 | ``` | ||
1257 | |||
1258 | ```rust | ||
1259 | macro foo | ||
1260 | ``` | ||
1261 | |||
1262 | --- | ||
1263 | |||
1264 | foo bar | ||
1265 | |||
1266 | foo bar baz | ||
1267 | "#]], | ||
1268 | ) | ||
1269 | } | ||
1270 | |||
1271 | #[test] | ||
1238 | fn test_hover_tuple_field() { | 1272 | fn test_hover_tuple_field() { |
1239 | check( | 1273 | check( |
1240 | r#"struct TS(String, i32$0);"#, | 1274 | r#"struct TS(String, i32$0);"#, |
diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs index 16c04eeee..f73edf8b6 100644 --- a/crates/ide/src/inlay_hints.rs +++ b/crates/ide/src/inlay_hints.rs | |||
@@ -52,6 +52,8 @@ pub struct InlayHint { | |||
52 | // | 52 | // |
53 | // | VS Code | **Rust Analyzer: Toggle inlay hints* | 53 | // | VS Code | **Rust Analyzer: Toggle inlay hints* |
54 | // |=== | 54 | // |=== |
55 | // | ||
56 | // image::https://user-images.githubusercontent.com/48062697/113020660-b5f98b80-917a-11eb-8d70-3be3fd558cdd.png[] | ||
55 | pub(crate) fn inlay_hints( | 57 | pub(crate) fn inlay_hints( |
56 | db: &RootDatabase, | 58 | db: &RootDatabase, |
57 | file_id: FileId, | 59 | file_id: FileId, |
@@ -416,7 +418,7 @@ fn get_string_representation(expr: &ast::Expr) -> Option<String> { | |||
416 | match expr { | 418 | match expr { |
417 | ast::Expr::MethodCallExpr(method_call_expr) => { | 419 | ast::Expr::MethodCallExpr(method_call_expr) => { |
418 | let name_ref = method_call_expr.name_ref()?; | 420 | let name_ref = method_call_expr.name_ref()?; |
419 | match name_ref.text() { | 421 | match name_ref.text().as_str() { |
420 | "clone" => method_call_expr.receiver().map(|rec| rec.to_string()), | 422 | "clone" => method_call_expr.receiver().map(|rec| rec.to_string()), |
421 | name_ref => Some(name_ref.to_owned()), | 423 | name_ref => Some(name_ref.to_owned()), |
422 | } | 424 | } |
diff --git a/crates/ide/src/join_lines.rs b/crates/ide/src/join_lines.rs index 4b25135cd..d584190f7 100644 --- a/crates/ide/src/join_lines.rs +++ b/crates/ide/src/join_lines.rs | |||
@@ -19,6 +19,8 @@ use text_edit::{TextEdit, TextEditBuilder}; | |||
19 | // | 19 | // |
20 | // | VS Code | **Rust Analyzer: Join lines** | 20 | // | VS Code | **Rust Analyzer: Join lines** |
21 | // |=== | 21 | // |=== |
22 | // | ||
23 | // image::https://user-images.githubusercontent.com/48062697/113020661-b6922200-917a-11eb-87c4-b75acc028f11.gif[] | ||
22 | pub(crate) fn join_lines(file: &SourceFile, range: TextRange) -> TextEdit { | 24 | pub(crate) fn join_lines(file: &SourceFile, range: TextRange) -> TextEdit { |
23 | let range = if range.is_empty() { | 25 | let range = if range.is_empty() { |
24 | let syntax = file.syntax(); | 26 | let syntax = file.syntax(); |
diff --git a/crates/ide/src/matching_brace.rs b/crates/ide/src/matching_brace.rs index 4241a6dac..261dcc255 100644 --- a/crates/ide/src/matching_brace.rs +++ b/crates/ide/src/matching_brace.rs | |||
@@ -14,6 +14,8 @@ use syntax::{ | |||
14 | // | 14 | // |
15 | // | VS Code | **Rust Analyzer: Find matching brace** | 15 | // | VS Code | **Rust Analyzer: Find matching brace** |
16 | // |=== | 16 | // |=== |
17 | // | ||
18 | // image::https://user-images.githubusercontent.com/48062697/113065573-04298180-91b1-11eb-8dec-d4e2a202f304.gif[] | ||
17 | pub(crate) fn matching_brace(file: &SourceFile, offset: TextSize) -> Option<TextSize> { | 19 | pub(crate) fn matching_brace(file: &SourceFile, offset: TextSize) -> Option<TextSize> { |
18 | const BRACES: &[SyntaxKind] = | 20 | const BRACES: &[SyntaxKind] = |
19 | &[T!['{'], T!['}'], T!['['], T![']'], T!['('], T![')'], T![<], T![>], T![|], T![|]]; | 21 | &[T!['{'], T!['}'], T!['['], T![']'], T!['('], T![')'], T![<], T![>], T![|], T![|]]; |
diff --git a/crates/ide/src/move_item.rs b/crates/ide/src/move_item.rs index 48690b073..8d37f4f92 100644 --- a/crates/ide/src/move_item.rs +++ b/crates/ide/src/move_item.rs | |||
@@ -4,10 +4,12 @@ use hir::Semantics; | |||
4 | use ide_db::{base_db::FileRange, RootDatabase}; | 4 | use ide_db::{base_db::FileRange, RootDatabase}; |
5 | use itertools::Itertools; | 5 | use itertools::Itertools; |
6 | use syntax::{ | 6 | use syntax::{ |
7 | algo, ast, match_ast, AstNode, NodeOrToken, SyntaxElement, SyntaxKind, SyntaxNode, TextRange, | 7 | algo, ast, match_ast, AstNode, SyntaxElement, SyntaxKind, SyntaxNode, SyntaxToken, TextRange, |
8 | TokenAtOffset, | ||
8 | }; | 9 | }; |
9 | use text_edit::{TextEdit, TextEditBuilder}; | 10 | use text_edit::{TextEdit, TextEditBuilder}; |
10 | 11 | ||
12 | #[derive(Copy, Clone, Debug)] | ||
11 | pub enum Direction { | 13 | pub enum Direction { |
12 | Up, | 14 | Up, |
13 | Down, | 15 | Down, |
@@ -23,6 +25,8 @@ pub enum Direction { | |||
23 | // | VS Code | **Rust Analyzer: Move item up** | 25 | // | VS Code | **Rust Analyzer: Move item up** |
24 | // | VS Code | **Rust Analyzer: Move item down** | 26 | // | VS Code | **Rust Analyzer: Move item down** |
25 | // |=== | 27 | // |=== |
28 | // | ||
29 | // image::https://user-images.githubusercontent.com/48062697/113065576-04298180-91b1-11eb-91ce-4505e99ed598.gif[] | ||
26 | pub(crate) fn move_item( | 30 | pub(crate) fn move_item( |
27 | db: &RootDatabase, | 31 | db: &RootDatabase, |
28 | range: FileRange, | 32 | range: FileRange, |
@@ -31,14 +35,19 @@ pub(crate) fn move_item( | |||
31 | let sema = Semantics::new(db); | 35 | let sema = Semantics::new(db); |
32 | let file = sema.parse(range.file_id); | 36 | let file = sema.parse(range.file_id); |
33 | 37 | ||
34 | let item = file.syntax().covering_element(range.range); | 38 | let item = if range.range.is_empty() { |
39 | SyntaxElement::Token(pick_best(file.syntax().token_at_offset(range.range.start()))?) | ||
40 | } else { | ||
41 | file.syntax().covering_element(range.range) | ||
42 | }; | ||
43 | |||
35 | find_ancestors(item, direction, range.range) | 44 | find_ancestors(item, direction, range.range) |
36 | } | 45 | } |
37 | 46 | ||
38 | fn find_ancestors(item: SyntaxElement, direction: Direction, range: TextRange) -> Option<TextEdit> { | 47 | fn find_ancestors(item: SyntaxElement, direction: Direction, range: TextRange) -> Option<TextEdit> { |
39 | let root = match item { | 48 | let root = match item { |
40 | NodeOrToken::Node(node) => node, | 49 | SyntaxElement::Node(node) => node, |
41 | NodeOrToken::Token(token) => token.parent()?, | 50 | SyntaxElement::Token(token) => token.parent()?, |
42 | }; | 51 | }; |
43 | 52 | ||
44 | let movable = [ | 53 | let movable = [ |
@@ -51,6 +60,11 @@ fn find_ancestors(item: SyntaxElement, direction: Direction, range: TextRange) - | |||
51 | SyntaxKind::PARAM, | 60 | SyntaxKind::PARAM, |
52 | SyntaxKind::LET_STMT, | 61 | SyntaxKind::LET_STMT, |
53 | SyntaxKind::EXPR_STMT, | 62 | SyntaxKind::EXPR_STMT, |
63 | SyntaxKind::IF_EXPR, | ||
64 | SyntaxKind::FOR_EXPR, | ||
65 | SyntaxKind::LOOP_EXPR, | ||
66 | SyntaxKind::WHILE_EXPR, | ||
67 | SyntaxKind::RETURN_EXPR, | ||
54 | SyntaxKind::MATCH_EXPR, | 68 | SyntaxKind::MATCH_EXPR, |
55 | SyntaxKind::MACRO_CALL, | 69 | SyntaxKind::MACRO_CALL, |
56 | SyntaxKind::TYPE_ALIAS, | 70 | SyntaxKind::TYPE_ALIAS, |
@@ -66,6 +80,7 @@ fn find_ancestors(item: SyntaxElement, direction: Direction, range: TextRange) - | |||
66 | SyntaxKind::STATIC, | 80 | SyntaxKind::STATIC, |
67 | SyntaxKind::CONST, | 81 | SyntaxKind::CONST, |
68 | SyntaxKind::MACRO_RULES, | 82 | SyntaxKind::MACRO_RULES, |
83 | SyntaxKind::MACRO_DEF, | ||
69 | ]; | 84 | ]; |
70 | 85 | ||
71 | let ancestor = once(root.clone()) | 86 | let ancestor = once(root.clone()) |
@@ -82,11 +97,11 @@ fn move_in_direction( | |||
82 | ) -> Option<TextEdit> { | 97 | ) -> Option<TextEdit> { |
83 | match_ast! { | 98 | match_ast! { |
84 | match node { | 99 | match node { |
85 | ast::ArgList(it) => swap_sibling_in_list(it.args(), range, direction), | 100 | ast::ArgList(it) => swap_sibling_in_list(node, it.args(), range, direction), |
86 | ast::GenericParamList(it) => swap_sibling_in_list(it.generic_params(), range, direction), | 101 | ast::GenericParamList(it) => swap_sibling_in_list(node, it.generic_params(), range, direction), |
87 | ast::GenericArgList(it) => swap_sibling_in_list(it.generic_args(), range, direction), | 102 | ast::GenericArgList(it) => swap_sibling_in_list(node, it.generic_args(), range, direction), |
88 | ast::VariantList(it) => swap_sibling_in_list(it.variants(), range, direction), | 103 | ast::VariantList(it) => swap_sibling_in_list(node, it.variants(), range, direction), |
89 | ast::TypeBoundList(it) => swap_sibling_in_list(it.bounds(), range, direction), | 104 | ast::TypeBoundList(it) => swap_sibling_in_list(node, it.bounds(), range, direction), |
90 | _ => Some(replace_nodes(node, &match direction { | 105 | _ => Some(replace_nodes(node, &match direction { |
91 | Direction::Up => node.prev_sibling(), | 106 | Direction::Up => node.prev_sibling(), |
92 | Direction::Down => node.next_sibling(), | 107 | Direction::Down => node.next_sibling(), |
@@ -96,19 +111,27 @@ fn move_in_direction( | |||
96 | } | 111 | } |
97 | 112 | ||
98 | fn swap_sibling_in_list<A: AstNode + Clone, I: Iterator<Item = A>>( | 113 | fn swap_sibling_in_list<A: AstNode + Clone, I: Iterator<Item = A>>( |
114 | node: &SyntaxNode, | ||
99 | list: I, | 115 | list: I, |
100 | range: TextRange, | 116 | range: TextRange, |
101 | direction: Direction, | 117 | direction: Direction, |
102 | ) -> Option<TextEdit> { | 118 | ) -> Option<TextEdit> { |
103 | let (l, r) = list | 119 | let list_lookup = list |
104 | .tuple_windows() | 120 | .tuple_windows() |
105 | .filter(|(l, r)| match direction { | 121 | .filter(|(l, r)| match direction { |
106 | Direction::Up => r.syntax().text_range().contains_range(range), | 122 | Direction::Up => r.syntax().text_range().contains_range(range), |
107 | Direction::Down => l.syntax().text_range().contains_range(range), | 123 | Direction::Down => l.syntax().text_range().contains_range(range), |
108 | }) | 124 | }) |
109 | .next()?; | 125 | .next(); |
110 | 126 | ||
111 | Some(replace_nodes(l.syntax(), r.syntax())) | 127 | if let Some((l, r)) = list_lookup { |
128 | Some(replace_nodes(l.syntax(), r.syntax())) | ||
129 | } else { | ||
130 | // Cursor is beyond any movable list item (for example, on curly brace in enum). | ||
131 | // It's not necessary, that parent of list is movable (arg list's parent is not, for example), | ||
132 | // and we have to continue tree traversal to find suitable node. | ||
133 | find_ancestors(SyntaxElement::Node(node.parent()?), direction, range) | ||
134 | } | ||
112 | } | 135 | } |
113 | 136 | ||
114 | fn replace_nodes(first: &SyntaxNode, second: &SyntaxNode) -> TextEdit { | 137 | fn replace_nodes(first: &SyntaxNode, second: &SyntaxNode) -> TextEdit { |
@@ -120,6 +143,18 @@ fn replace_nodes(first: &SyntaxNode, second: &SyntaxNode) -> TextEdit { | |||
120 | edit.finish() | 143 | edit.finish() |
121 | } | 144 | } |
122 | 145 | ||
146 | fn pick_best(tokens: TokenAtOffset<SyntaxToken>) -> Option<SyntaxToken> { | ||
147 | return tokens.max_by_key(priority); | ||
148 | |||
149 | fn priority(n: &SyntaxToken) -> usize { | ||
150 | match n.kind() { | ||
151 | SyntaxKind::IDENT | SyntaxKind::LIFETIME_IDENT => 2, | ||
152 | kind if kind.is_trivia() => 0, | ||
153 | _ => 1, | ||
154 | } | ||
155 | } | ||
156 | } | ||
157 | |||
123 | #[cfg(test)] | 158 | #[cfg(test)] |
124 | mod tests { | 159 | mod tests { |
125 | use crate::fixture; | 160 | use crate::fixture; |
@@ -264,6 +299,107 @@ fn main() { | |||
264 | "#]], | 299 | "#]], |
265 | Direction::Up, | 300 | Direction::Up, |
266 | ); | 301 | ); |
302 | check( | ||
303 | r#" | ||
304 | fn main() { | ||
305 | println!("Hello, world"); | ||
306 | |||
307 | if true { | ||
308 | println!("Test"); | ||
309 | }$0$0 | ||
310 | } | ||
311 | "#, | ||
312 | expect![[r#" | ||
313 | fn main() { | ||
314 | if true { | ||
315 | println!("Test"); | ||
316 | } | ||
317 | |||
318 | println!("Hello, world"); | ||
319 | } | ||
320 | "#]], | ||
321 | Direction::Up, | ||
322 | ); | ||
323 | check( | ||
324 | r#" | ||
325 | fn main() { | ||
326 | println!("Hello, world"); | ||
327 | |||
328 | for i in 0..10 { | ||
329 | println!("Test"); | ||
330 | }$0$0 | ||
331 | } | ||
332 | "#, | ||
333 | expect![[r#" | ||
334 | fn main() { | ||
335 | for i in 0..10 { | ||
336 | println!("Test"); | ||
337 | } | ||
338 | |||
339 | println!("Hello, world"); | ||
340 | } | ||
341 | "#]], | ||
342 | Direction::Up, | ||
343 | ); | ||
344 | check( | ||
345 | r#" | ||
346 | fn main() { | ||
347 | println!("Hello, world"); | ||
348 | |||
349 | loop { | ||
350 | println!("Test"); | ||
351 | }$0$0 | ||
352 | } | ||
353 | "#, | ||
354 | expect![[r#" | ||
355 | fn main() { | ||
356 | loop { | ||
357 | println!("Test"); | ||
358 | } | ||
359 | |||
360 | println!("Hello, world"); | ||
361 | } | ||
362 | "#]], | ||
363 | Direction::Up, | ||
364 | ); | ||
365 | check( | ||
366 | r#" | ||
367 | fn main() { | ||
368 | println!("Hello, world"); | ||
369 | |||
370 | while true { | ||
371 | println!("Test"); | ||
372 | }$0$0 | ||
373 | } | ||
374 | "#, | ||
375 | expect![[r#" | ||
376 | fn main() { | ||
377 | while true { | ||
378 | println!("Test"); | ||
379 | } | ||
380 | |||
381 | println!("Hello, world"); | ||
382 | } | ||
383 | "#]], | ||
384 | Direction::Up, | ||
385 | ); | ||
386 | check( | ||
387 | r#" | ||
388 | fn main() { | ||
389 | println!("Hello, world"); | ||
390 | |||
391 | return 123;$0$0 | ||
392 | } | ||
393 | "#, | ||
394 | expect![[r#" | ||
395 | fn main() { | ||
396 | return 123; | ||
397 | |||
398 | println!("Hello, world"); | ||
399 | } | ||
400 | "#]], | ||
401 | Direction::Up, | ||
402 | ); | ||
267 | } | 403 | } |
268 | 404 | ||
269 | #[test] | 405 | #[test] |
@@ -614,6 +750,115 @@ fn test() { | |||
614 | } | 750 | } |
615 | 751 | ||
616 | #[test] | 752 | #[test] |
753 | fn test_cursor_at_item_start() { | ||
754 | check( | ||
755 | r#" | ||
756 | $0$0#[derive(Debug)] | ||
757 | enum FooBar { | ||
758 | Foo, | ||
759 | Bar, | ||
760 | } | ||
761 | |||
762 | fn main() {} | ||
763 | "#, | ||
764 | expect![[r#" | ||
765 | fn main() {} | ||
766 | |||
767 | #[derive(Debug)] | ||
768 | enum FooBar { | ||
769 | Foo, | ||
770 | Bar, | ||
771 | } | ||
772 | "#]], | ||
773 | Direction::Down, | ||
774 | ); | ||
775 | check( | ||
776 | r#" | ||
777 | $0$0enum FooBar { | ||
778 | Foo, | ||
779 | Bar, | ||
780 | } | ||
781 | |||
782 | fn main() {} | ||
783 | "#, | ||
784 | expect![[r#" | ||
785 | fn main() {} | ||
786 | |||
787 | enum FooBar { | ||
788 | Foo, | ||
789 | Bar, | ||
790 | } | ||
791 | "#]], | ||
792 | Direction::Down, | ||
793 | ); | ||
794 | check( | ||
795 | r#" | ||
796 | struct Test; | ||
797 | |||
798 | trait SomeTrait {} | ||
799 | |||
800 | $0$0impl SomeTrait for Test {} | ||
801 | |||
802 | fn main() {} | ||
803 | "#, | ||
804 | expect![[r#" | ||
805 | struct Test; | ||
806 | |||
807 | impl SomeTrait for Test {} | ||
808 | |||
809 | trait SomeTrait {} | ||
810 | |||
811 | fn main() {} | ||
812 | "#]], | ||
813 | Direction::Up, | ||
814 | ); | ||
815 | } | ||
816 | |||
817 | #[test] | ||
818 | fn test_cursor_at_item_end() { | ||
819 | check( | ||
820 | r#" | ||
821 | enum FooBar { | ||
822 | Foo, | ||
823 | Bar, | ||
824 | }$0$0 | ||
825 | |||
826 | fn main() {} | ||
827 | "#, | ||
828 | expect![[r#" | ||
829 | fn main() {} | ||
830 | |||
831 | enum FooBar { | ||
832 | Foo, | ||
833 | Bar, | ||
834 | } | ||
835 | "#]], | ||
836 | Direction::Down, | ||
837 | ); | ||
838 | check( | ||
839 | r#" | ||
840 | struct Test; | ||
841 | |||
842 | trait SomeTrait {} | ||
843 | |||
844 | impl SomeTrait for Test {}$0$0 | ||
845 | |||
846 | fn main() {} | ||
847 | "#, | ||
848 | expect![[r#" | ||
849 | struct Test; | ||
850 | |||
851 | impl SomeTrait for Test {} | ||
852 | |||
853 | trait SomeTrait {} | ||
854 | |||
855 | fn main() {} | ||
856 | "#]], | ||
857 | Direction::Up, | ||
858 | ); | ||
859 | } | ||
860 | |||
861 | #[test] | ||
617 | fn handles_empty_file() { | 862 | fn handles_empty_file() { |
618 | check(r#"$0$0"#, expect![[r#""#]], Direction::Up); | 863 | check(r#"$0$0"#, expect![[r#""#]], Direction::Up); |
619 | } | 864 | } |
diff --git a/crates/ide/src/parent_module.rs b/crates/ide/src/parent_module.rs index 22b0d6ecb..99365c8a7 100644 --- a/crates/ide/src/parent_module.rs +++ b/crates/ide/src/parent_module.rs | |||
@@ -18,6 +18,8 @@ use crate::NavigationTarget; | |||
18 | // | 18 | // |
19 | // | VS Code | **Rust Analyzer: Locate parent module** | 19 | // | VS Code | **Rust Analyzer: Locate parent module** |
20 | // |=== | 20 | // |=== |
21 | // | ||
22 | // image::https://user-images.githubusercontent.com/48062697/113065580-04c21800-91b1-11eb-9a32-00086161c0bd.gif[] | ||
21 | 23 | ||
22 | /// This returns `Vec` because a module may be included from several places. | 24 | /// This returns `Vec` because a module may be included from several places. |
23 | pub(crate) fn parent_module(db: &RootDatabase, position: FilePosition) -> Vec<NavigationTarget> { | 25 | pub(crate) fn parent_module(db: &RootDatabase, position: FilePosition) -> Vec<NavigationTarget> { |
diff --git a/crates/ide/src/references.rs b/crates/ide/src/references.rs index 95ed8a045..11ca7ec6b 100644 --- a/crates/ide/src/references.rs +++ b/crates/ide/src/references.rs | |||
@@ -48,6 +48,8 @@ pub struct Declaration { | |||
48 | // | 48 | // |
49 | // | VS Code | kbd:[Shift+Alt+F12] | 49 | // | VS Code | kbd:[Shift+Alt+F12] |
50 | // |=== | 50 | // |=== |
51 | // | ||
52 | // image::https://user-images.githubusercontent.com/48062697/113020670-b7c34f00-917a-11eb-8003-370ac5f2b3cb.gif[] | ||
51 | pub(crate) fn find_all_refs( | 53 | pub(crate) fn find_all_refs( |
52 | sema: &Semantics<RootDatabase>, | 54 | sema: &Semantics<RootDatabase>, |
53 | position: FilePosition, | 55 | position: FilePosition, |
diff --git a/crates/ide/src/references/rename.rs b/crates/ide/src/references/rename.rs index 26d6dc9c9..2408a0181 100644 --- a/crates/ide/src/references/rename.rs +++ b/crates/ide/src/references/rename.rs | |||
@@ -70,6 +70,8 @@ pub(crate) fn prepare_rename( | |||
70 | // | 70 | // |
71 | // | VS Code | kbd:[F2] | 71 | // | VS Code | kbd:[F2] |
72 | // |=== | 72 | // |=== |
73 | // | ||
74 | // image::https://user-images.githubusercontent.com/48062697/113065582-055aae80-91b1-11eb-8ade-2b58e6d81883.gif[] | ||
73 | pub(crate) fn rename( | 75 | pub(crate) fn rename( |
74 | db: &RootDatabase, | 76 | db: &RootDatabase, |
75 | position: FilePosition, | 77 | position: FilePosition, |
@@ -307,7 +309,7 @@ fn rename_to_self(sema: &Semantics<RootDatabase>, local: hir::Local) -> RenameRe | |||
307 | hir::AssocItemContainer::Impl(impl_) => impl_, | 309 | hir::AssocItemContainer::Impl(impl_) => impl_, |
308 | }; | 310 | }; |
309 | let first_param_ty = first_param.ty(); | 311 | let first_param_ty = first_param.ty(); |
310 | let impl_ty = impl_.target_ty(sema.db); | 312 | let impl_ty = impl_.self_ty(sema.db); |
311 | let (ty, self_param) = if impl_ty.remove_ref().is_some() { | 313 | let (ty, self_param) = if impl_ty.remove_ref().is_some() { |
312 | // if the impl is a ref to the type we can just match the `&T` with self directly | 314 | // if the impl is a ref to the type we can just match the `&T` with self directly |
313 | (first_param_ty.clone(), "self") | 315 | (first_param_ty.clone(), "self") |
diff --git a/crates/ide/src/runnables.rs b/crates/ide/src/runnables.rs index 7e4c5a078..3eb9e27ee 100644 --- a/crates/ide/src/runnables.rs +++ b/crates/ide/src/runnables.rs | |||
@@ -98,6 +98,7 @@ impl Runnable { | |||
98 | // | 98 | // |
99 | // | VS Code | **Rust Analyzer: Run** | 99 | // | VS Code | **Rust Analyzer: Run** |
100 | // |=== | 100 | // |=== |
101 | // image::https://user-images.githubusercontent.com/48062697/113065583-055aae80-91b1-11eb-958f-d67efcaf6a2f.gif[] | ||
101 | pub(crate) fn runnables(db: &RootDatabase, file_id: FileId) -> Vec<Runnable> { | 102 | pub(crate) fn runnables(db: &RootDatabase, file_id: FileId) -> Vec<Runnable> { |
102 | let sema = Semantics::new(db); | 103 | let sema = Semantics::new(db); |
103 | 104 | ||
@@ -298,7 +299,7 @@ fn module_def_doctest(sema: &Semantics<RootDatabase>, def: hir::ModuleDef) -> Op | |||
298 | // FIXME: this also looks very wrong | 299 | // FIXME: this also looks very wrong |
299 | if let Some(assoc_def) = assoc_def { | 300 | if let Some(assoc_def) = assoc_def { |
300 | if let hir::AssocItemContainer::Impl(imp) = assoc_def.container(sema.db) { | 301 | if let hir::AssocItemContainer::Impl(imp) = assoc_def.container(sema.db) { |
301 | let ty = imp.target_ty(sema.db); | 302 | let ty = imp.self_ty(sema.db); |
302 | if let Some(adt) = ty.as_adt() { | 303 | if let Some(adt) = ty.as_adt() { |
303 | let name = adt.name(sema.db); | 304 | let name = adt.name(sema.db); |
304 | let idx = path.rfind(':').map_or(0, |idx| idx + 1); | 305 | let idx = path.rfind(':').map_or(0, |idx| idx + 1); |
diff --git a/crates/ide/src/status.rs b/crates/ide/src/status.rs index 137c38c0d..49fde1945 100644 --- a/crates/ide/src/status.rs +++ b/crates/ide/src/status.rs | |||
@@ -31,6 +31,7 @@ fn macro_syntax_tree_stats(db: &RootDatabase) -> SyntaxTreeStats { | |||
31 | // | 31 | // |
32 | // | VS Code | **Rust Analyzer: Status** | 32 | // | VS Code | **Rust Analyzer: Status** |
33 | // |=== | 33 | // |=== |
34 | // image::https://user-images.githubusercontent.com/48062697/113065584-05f34500-91b1-11eb-98cc-5c196f76be7f.gif[] | ||
34 | pub(crate) fn status(db: &RootDatabase, file_id: Option<FileId>) -> String { | 35 | pub(crate) fn status(db: &RootDatabase, file_id: Option<FileId>) -> String { |
35 | let mut buf = String::new(); | 36 | let mut buf = String::new(); |
36 | format_to!(buf, "{}\n", FileTextQuery.in_db(db).entries::<FilesStats>()); | 37 | format_to!(buf, "{}\n", FileTextQuery.in_db(db).entries::<FilesStats>()); |
diff --git a/crates/ide/src/syntax_highlighting.rs b/crates/ide/src/syntax_highlighting.rs index e25b698e0..67a10766b 100644 --- a/crates/ide/src/syntax_highlighting.rs +++ b/crates/ide/src/syntax_highlighting.rs | |||
@@ -5,7 +5,7 @@ mod injector; | |||
5 | 5 | ||
6 | mod highlight; | 6 | mod highlight; |
7 | mod format; | 7 | mod format; |
8 | mod macro_rules; | 8 | mod macro_; |
9 | mod inject; | 9 | mod inject; |
10 | 10 | ||
11 | mod html; | 11 | mod html; |
@@ -24,8 +24,8 @@ use syntax::{ | |||
24 | 24 | ||
25 | use crate::{ | 25 | use crate::{ |
26 | syntax_highlighting::{ | 26 | syntax_highlighting::{ |
27 | format::highlight_format_string, highlights::Highlights, | 27 | format::highlight_format_string, highlights::Highlights, macro_::MacroHighlighter, |
28 | macro_rules::MacroRulesHighlighter, tags::Highlight, | 28 | tags::Highlight, |
29 | }, | 29 | }, |
30 | FileId, HlMod, HlTag, | 30 | FileId, HlMod, HlTag, |
31 | }; | 31 | }; |
@@ -93,8 +93,8 @@ fn traverse( | |||
93 | let mut bindings_shadow_count: FxHashMap<Name, u32> = FxHashMap::default(); | 93 | let mut bindings_shadow_count: FxHashMap<Name, u32> = FxHashMap::default(); |
94 | 94 | ||
95 | let mut current_macro_call: Option<ast::MacroCall> = None; | 95 | let mut current_macro_call: Option<ast::MacroCall> = None; |
96 | let mut current_macro_rules: Option<ast::MacroRules> = None; | 96 | let mut current_macro: Option<ast::Macro> = None; |
97 | let mut macro_rules_highlighter = MacroRulesHighlighter::default(); | 97 | let mut macro_highlighter = MacroHighlighter::default(); |
98 | let mut inside_attribute = false; | 98 | let mut inside_attribute = false; |
99 | 99 | ||
100 | // Walk all nodes, keeping track of whether we are inside a macro or not. | 100 | // Walk all nodes, keeping track of whether we are inside a macro or not. |
@@ -129,16 +129,16 @@ fn traverse( | |||
129 | _ => (), | 129 | _ => (), |
130 | } | 130 | } |
131 | 131 | ||
132 | match event.clone().map(|it| it.into_node().and_then(ast::MacroRules::cast)) { | 132 | match event.clone().map(|it| it.into_node().and_then(ast::Macro::cast)) { |
133 | WalkEvent::Enter(Some(mac)) => { | 133 | WalkEvent::Enter(Some(mac)) => { |
134 | macro_rules_highlighter.init(); | 134 | macro_highlighter.init(); |
135 | current_macro_rules = Some(mac); | 135 | current_macro = Some(mac); |
136 | continue; | 136 | continue; |
137 | } | 137 | } |
138 | WalkEvent::Leave(Some(mac)) => { | 138 | WalkEvent::Leave(Some(mac)) => { |
139 | assert_eq!(current_macro_rules, Some(mac)); | 139 | assert_eq!(current_macro, Some(mac)); |
140 | current_macro_rules = None; | 140 | current_macro = None; |
141 | macro_rules_highlighter = MacroRulesHighlighter::default(); | 141 | macro_highlighter = MacroHighlighter::default(); |
142 | } | 142 | } |
143 | _ => (), | 143 | _ => (), |
144 | } | 144 | } |
@@ -164,9 +164,9 @@ fn traverse( | |||
164 | 164 | ||
165 | let range = element.text_range(); | 165 | let range = element.text_range(); |
166 | 166 | ||
167 | if current_macro_rules.is_some() { | 167 | if current_macro.is_some() { |
168 | if let Some(tok) = element.as_token() { | 168 | if let Some(tok) = element.as_token() { |
169 | macro_rules_highlighter.advance(tok); | 169 | macro_highlighter.advance(tok); |
170 | } | 170 | } |
171 | } | 171 | } |
172 | 172 | ||
@@ -200,7 +200,7 @@ fn traverse( | |||
200 | } | 200 | } |
201 | } | 201 | } |
202 | 202 | ||
203 | if let Some(_) = macro_rules_highlighter.highlight(element_to_highlight.clone()) { | 203 | if let Some(_) = macro_highlighter.highlight(element_to_highlight.clone()) { |
204 | continue; | 204 | continue; |
205 | } | 205 | } |
206 | 206 | ||
diff --git a/crates/ide/src/syntax_highlighting/format.rs b/crates/ide/src/syntax_highlighting/format.rs index e503abc93..5bbadb0f4 100644 --- a/crates/ide/src/syntax_highlighting/format.rs +++ b/crates/ide/src/syntax_highlighting/format.rs | |||
@@ -31,7 +31,7 @@ fn is_format_string(string: &ast::String) -> Option<()> { | |||
31 | let parent = string.syntax().parent()?; | 31 | let parent = string.syntax().parent()?; |
32 | 32 | ||
33 | let name = parent.parent().and_then(ast::MacroCall::cast)?.path()?.segment()?.name_ref()?; | 33 | let name = parent.parent().and_then(ast::MacroCall::cast)?.path()?.segment()?.name_ref()?; |
34 | if !matches!(name.text(), "format_args" | "format_args_nl") { | 34 | if !matches!(name.text().as_str(), "format_args" | "format_args_nl") { |
35 | return None; | 35 | return None; |
36 | } | 36 | } |
37 | 37 | ||
diff --git a/crates/ide/src/syntax_highlighting/highlight.rs b/crates/ide/src/syntax_highlighting/highlight.rs index b0cfdd8b7..5ccb84714 100644 --- a/crates/ide/src/syntax_highlighting/highlight.rs +++ b/crates/ide/src/syntax_highlighting/highlight.rs | |||
@@ -1,6 +1,6 @@ | |||
1 | //! Computes color for a single element. | 1 | //! Computes color for a single element. |
2 | 2 | ||
3 | use hir::{AsAssocItem, Semantics, VariantDef}; | 3 | use hir::{AsAssocItem, AssocItemContainer, Semantics, VariantDef}; |
4 | use ide_db::{ | 4 | use ide_db::{ |
5 | defs::{Definition, NameClass, NameRefClass}, | 5 | defs::{Definition, NameClass, NameRefClass}, |
6 | RootDatabase, SymbolKind, | 6 | RootDatabase, SymbolKind, |
@@ -275,12 +275,24 @@ fn highlight_def(db: &RootDatabase, def: Definition) -> Highlight { | |||
275 | hir::ModuleDef::Module(_) => HlTag::Symbol(SymbolKind::Module), | 275 | hir::ModuleDef::Module(_) => HlTag::Symbol(SymbolKind::Module), |
276 | hir::ModuleDef::Function(func) => { | 276 | hir::ModuleDef::Function(func) => { |
277 | let mut h = Highlight::new(HlTag::Symbol(SymbolKind::Function)); | 277 | let mut h = Highlight::new(HlTag::Symbol(SymbolKind::Function)); |
278 | if func.as_assoc_item(db).is_some() { | 278 | if let Some(item) = func.as_assoc_item(db) { |
279 | h |= HlMod::Associated; | 279 | h |= HlMod::Associated; |
280 | if func.self_param(db).is_none() { | 280 | if func.self_param(db).is_none() { |
281 | h |= HlMod::Static | 281 | h |= HlMod::Static |
282 | } | 282 | } |
283 | |||
284 | match item.container(db) { | ||
285 | AssocItemContainer::Impl(i) => { | ||
286 | if i.trait_(db).is_some() { | ||
287 | h |= HlMod::Trait; | ||
288 | } | ||
289 | } | ||
290 | AssocItemContainer::Trait(_t) => { | ||
291 | h |= HlMod::Trait; | ||
292 | } | ||
293 | } | ||
283 | } | 294 | } |
295 | |||
284 | if func.is_unsafe(db) { | 296 | if func.is_unsafe(db) { |
285 | h |= HlMod::Unsafe; | 297 | h |= HlMod::Unsafe; |
286 | } | 298 | } |
@@ -292,9 +304,20 @@ fn highlight_def(db: &RootDatabase, def: Definition) -> Highlight { | |||
292 | hir::ModuleDef::Variant(_) => HlTag::Symbol(SymbolKind::Variant), | 304 | hir::ModuleDef::Variant(_) => HlTag::Symbol(SymbolKind::Variant), |
293 | hir::ModuleDef::Const(konst) => { | 305 | hir::ModuleDef::Const(konst) => { |
294 | let mut h = Highlight::new(HlTag::Symbol(SymbolKind::Const)); | 306 | let mut h = Highlight::new(HlTag::Symbol(SymbolKind::Const)); |
295 | if konst.as_assoc_item(db).is_some() { | 307 | if let Some(item) = konst.as_assoc_item(db) { |
296 | h |= HlMod::Associated | 308 | h |= HlMod::Associated; |
309 | match item.container(db) { | ||
310 | AssocItemContainer::Impl(i) => { | ||
311 | if i.trait_(db).is_some() { | ||
312 | h |= HlMod::Trait; | ||
313 | } | ||
314 | } | ||
315 | AssocItemContainer::Trait(_t) => { | ||
316 | h |= HlMod::Trait; | ||
317 | } | ||
318 | } | ||
297 | } | 319 | } |
320 | |||
298 | return h; | 321 | return h; |
299 | } | 322 | } |
300 | hir::ModuleDef::Trait(_) => HlTag::Symbol(SymbolKind::Trait), | 323 | hir::ModuleDef::Trait(_) => HlTag::Symbol(SymbolKind::Trait), |
@@ -362,6 +385,10 @@ fn highlight_method_call( | |||
362 | if func.is_unsafe(sema.db) || sema.is_unsafe_method_call(&method_call) { | 385 | if func.is_unsafe(sema.db) || sema.is_unsafe_method_call(&method_call) { |
363 | h |= HlMod::Unsafe; | 386 | h |= HlMod::Unsafe; |
364 | } | 387 | } |
388 | if func.as_assoc_item(sema.db).and_then(|it| it.containing_trait(sema.db)).is_some() { | ||
389 | h |= HlMod::Trait | ||
390 | } | ||
391 | |||
365 | if let Some(self_param) = func.self_param(sema.db) { | 392 | if let Some(self_param) = func.self_param(sema.db) { |
366 | match self_param.access(sema.db) { | 393 | match self_param.access(sema.db) { |
367 | hir::Access::Shared => (), | 394 | hir::Access::Shared => (), |
diff --git a/crates/ide/src/syntax_highlighting/inject.rs b/crates/ide/src/syntax_highlighting/inject.rs index 38bf49348..b62d43256 100644 --- a/crates/ide/src/syntax_highlighting/inject.rs +++ b/crates/ide/src/syntax_highlighting/inject.rs | |||
@@ -11,7 +11,8 @@ use syntax::{ | |||
11 | }; | 11 | }; |
12 | 12 | ||
13 | use crate::{ | 13 | use crate::{ |
14 | doc_links::extract_definitions_from_markdown, Analysis, HlMod, HlRange, HlTag, RootDatabase, | 14 | doc_links::{extract_definitions_from_markdown, resolve_doc_path_for_def}, |
15 | Analysis, HlMod, HlRange, HlTag, RootDatabase, | ||
15 | }; | 16 | }; |
16 | 17 | ||
17 | use super::{highlights::Highlights, injector::Injector}; | 18 | use super::{highlights::Highlights, injector::Injector}; |
@@ -109,8 +110,7 @@ fn doc_attributes<'node>( | |||
109 | ast::Impl(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::SelfType(def))), | 110 | ast::Impl(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::SelfType(def))), |
110 | ast::RecordField(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::Field(def))), | 111 | ast::RecordField(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::Field(def))), |
111 | ast::TupleField(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::Field(def))), | 112 | ast::TupleField(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::Field(def))), |
112 | ast::MacroRules(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::Macro(def))), | 113 | ast::Macro(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::Macro(def))), |
113 | // ast::MacroDef(it) => sema.to_def(&it).map(|def| (Box::new(it) as _, def.attrs(sema.db))), | ||
114 | // ast::Use(it) => sema.to_def(&it).map(|def| (Box::new(it) as _, def.attrs(sema.db))), | 114 | // ast::Use(it) => sema.to_def(&it).map(|def| (Box::new(it) as _, def.attrs(sema.db))), |
115 | _ => return None | 115 | _ => return None |
116 | } | 116 | } |
@@ -191,7 +191,7 @@ pub(super) fn doc_comment( | |||
191 | extract_definitions_from_markdown(line) | 191 | extract_definitions_from_markdown(line) |
192 | .into_iter() | 192 | .into_iter() |
193 | .filter_map(|(range, link, ns)| { | 193 | .filter_map(|(range, link, ns)| { |
194 | Some(range).zip(validate_intra_doc_link(sema.db, &def, &link, ns)) | 194 | Some(range).zip(resolve_doc_path_for_def(sema.db, def, &link, ns)) |
195 | }) | 195 | }) |
196 | .map(|(Range { start, end }, def)| { | 196 | .map(|(Range { start, end }, def)| { |
197 | ( | 197 | ( |
@@ -284,33 +284,6 @@ fn find_doc_string_in_attr(attr: &hir::Attr, it: &ast::Attr) -> Option<ast::Stri | |||
284 | } | 284 | } |
285 | } | 285 | } |
286 | 286 | ||
287 | fn validate_intra_doc_link( | ||
288 | db: &RootDatabase, | ||
289 | def: &Definition, | ||
290 | link: &str, | ||
291 | ns: Option<hir::Namespace>, | ||
292 | ) -> Option<hir::ModuleDef> { | ||
293 | match def { | ||
294 | Definition::ModuleDef(def) => match def { | ||
295 | hir::ModuleDef::Module(it) => it.resolve_doc_path(db, &link, ns), | ||
296 | hir::ModuleDef::Function(it) => it.resolve_doc_path(db, &link, ns), | ||
297 | hir::ModuleDef::Adt(it) => it.resolve_doc_path(db, &link, ns), | ||
298 | hir::ModuleDef::Variant(it) => it.resolve_doc_path(db, &link, ns), | ||
299 | hir::ModuleDef::Const(it) => it.resolve_doc_path(db, &link, ns), | ||
300 | hir::ModuleDef::Static(it) => it.resolve_doc_path(db, &link, ns), | ||
301 | hir::ModuleDef::Trait(it) => it.resolve_doc_path(db, &link, ns), | ||
302 | hir::ModuleDef::TypeAlias(it) => it.resolve_doc_path(db, &link, ns), | ||
303 | hir::ModuleDef::BuiltinType(_) => None, | ||
304 | }, | ||
305 | Definition::Macro(it) => it.resolve_doc_path(db, &link, ns), | ||
306 | Definition::Field(it) => it.resolve_doc_path(db, &link, ns), | ||
307 | Definition::SelfType(_) | ||
308 | | Definition::Local(_) | ||
309 | | Definition::GenericParam(_) | ||
310 | | Definition::Label(_) => None, | ||
311 | } | ||
312 | } | ||
313 | |||
314 | fn module_def_to_hl_tag(def: hir::ModuleDef) -> HlTag { | 287 | fn module_def_to_hl_tag(def: hir::ModuleDef) -> HlTag { |
315 | let symbol = match def { | 288 | let symbol = match def { |
316 | hir::ModuleDef::Module(_) => SymbolKind::Module, | 289 | hir::ModuleDef::Module(_) => SymbolKind::Module, |
diff --git a/crates/ide/src/syntax_highlighting/macro_rules.rs b/crates/ide/src/syntax_highlighting/macro_.rs index 44620e912..819704294 100644 --- a/crates/ide/src/syntax_highlighting/macro_rules.rs +++ b/crates/ide/src/syntax_highlighting/macro_.rs | |||
@@ -4,18 +4,18 @@ use syntax::{SyntaxElement, SyntaxKind, SyntaxToken, TextRange, T}; | |||
4 | use crate::{HlRange, HlTag}; | 4 | use crate::{HlRange, HlTag}; |
5 | 5 | ||
6 | #[derive(Default)] | 6 | #[derive(Default)] |
7 | pub(super) struct MacroRulesHighlighter { | 7 | pub(super) struct MacroHighlighter { |
8 | state: Option<MacroMatcherParseState>, | 8 | state: Option<MacroMatcherParseState>, |
9 | } | 9 | } |
10 | 10 | ||
11 | impl MacroRulesHighlighter { | 11 | impl MacroHighlighter { |
12 | pub(super) fn init(&mut self) { | 12 | pub(super) fn init(&mut self) { |
13 | self.state = Some(MacroMatcherParseState::default()); | 13 | self.state = Some(MacroMatcherParseState::default()); |
14 | } | 14 | } |
15 | 15 | ||
16 | pub(super) fn advance(&mut self, token: &SyntaxToken) { | 16 | pub(super) fn advance(&mut self, token: &SyntaxToken) { |
17 | if let Some(state) = self.state.as_mut() { | 17 | if let Some(state) = self.state.as_mut() { |
18 | update_macro_rules_state(state, token); | 18 | update_macro_state(state, token); |
19 | } | 19 | } |
20 | } | 20 | } |
21 | 21 | ||
@@ -74,9 +74,9 @@ impl RuleState { | |||
74 | } | 74 | } |
75 | } | 75 | } |
76 | 76 | ||
77 | fn update_macro_rules_state(state: &mut MacroMatcherParseState, tok: &SyntaxToken) { | 77 | fn update_macro_state(state: &mut MacroMatcherParseState, tok: &SyntaxToken) { |
78 | if !state.in_invoc_body { | 78 | if !state.in_invoc_body { |
79 | if tok.kind() == T!['{'] { | 79 | if tok.kind() == T!['{'] || tok.kind() == T!['('] { |
80 | state.in_invoc_body = true; | 80 | state.in_invoc_body = true; |
81 | } | 81 | } |
82 | return; | 82 | return; |
diff --git a/crates/ide/src/syntax_highlighting/tags.rs b/crates/ide/src/syntax_highlighting/tags.rs index 93db79b89..1cec991aa 100644 --- a/crates/ide/src/syntax_highlighting/tags.rs +++ b/crates/ide/src/syntax_highlighting/tags.rs | |||
@@ -58,6 +58,8 @@ pub enum HlMod { | |||
58 | Associated, | 58 | Associated, |
59 | /// Used for intra doc links in doc injection. | 59 | /// Used for intra doc links in doc injection. |
60 | IntraDocLink, | 60 | IntraDocLink, |
61 | /// Used for items in traits and trait impls. | ||
62 | Trait, | ||
61 | 63 | ||
62 | /// Keep this last! | 64 | /// Keep this last! |
63 | Unsafe, | 65 | Unsafe, |
@@ -158,6 +160,7 @@ impl HlMod { | |||
158 | HlMod::Callable, | 160 | HlMod::Callable, |
159 | HlMod::Static, | 161 | HlMod::Static, |
160 | HlMod::Associated, | 162 | HlMod::Associated, |
163 | HlMod::Trait, | ||
161 | HlMod::Unsafe, | 164 | HlMod::Unsafe, |
162 | ]; | 165 | ]; |
163 | 166 | ||
@@ -174,6 +177,7 @@ impl HlMod { | |||
174 | HlMod::IntraDocLink => "intra_doc_link", | 177 | HlMod::IntraDocLink => "intra_doc_link", |
175 | HlMod::Mutable => "mutable", | 178 | HlMod::Mutable => "mutable", |
176 | HlMod::Static => "static", | 179 | HlMod::Static => "static", |
180 | HlMod::Trait => "trait", | ||
177 | HlMod::Unsafe => "unsafe", | 181 | HlMod::Unsafe => "unsafe", |
178 | } | 182 | } |
179 | } | 183 | } |
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html b/crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html index 4635ea927..8cde3906c 100644 --- a/crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html +++ b/crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html | |||
@@ -47,12 +47,12 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd | |||
47 | <span class="brace">}</span> | 47 | <span class="brace">}</span> |
48 | 48 | ||
49 | <span class="keyword">trait</span> <span class="trait declaration">t</span> <span class="brace">{</span> | 49 | <span class="keyword">trait</span> <span class="trait declaration">t</span> <span class="brace">{</span> |
50 | <span class="keyword">fn</span> <span class="function declaration static associated">t_is_static</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span> | 50 | <span class="keyword">fn</span> <span class="function declaration static associated trait">t_is_static</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span> |
51 | <span class="keyword">fn</span> <span class="function declaration associated">t_is_not_static</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword declaration">self</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span> | 51 | <span class="keyword">fn</span> <span class="function declaration associated trait">t_is_not_static</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword declaration">self</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span> |
52 | <span class="brace">}</span> | 52 | <span class="brace">}</span> |
53 | 53 | ||
54 | <span class="keyword">impl</span> <span class="trait">t</span> <span class="keyword">for</span> <span class="struct">foo</span> <span class="brace">{</span> | 54 | <span class="keyword">impl</span> <span class="trait">t</span> <span class="keyword">for</span> <span class="struct">foo</span> <span class="brace">{</span> |
55 | <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration static associated">is_static</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span> | 55 | <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration static associated trait">is_static</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span> |
56 | <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration associated">is_not_static</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword declaration">self</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span> | 56 | <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration associated trait">is_not_static</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword declaration">self</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span> |
57 | <span class="brace">}</span> | 57 | <span class="brace">}</span> |
58 | </code></pre> \ No newline at end of file | 58 | </code></pre> \ No newline at end of file |
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html b/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html index 9215ddd9e..7c6694a27 100644 --- a/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html +++ b/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html | |||
@@ -42,7 +42,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd | |||
42 | <span class="keyword">fn</span> <span class="function declaration">main</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span> | 42 | <span class="keyword">fn</span> <span class="function declaration">main</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span> |
43 | <span class="function">fixture</span><span class="parenthesis">(</span><span class="string_literal">r#"</span> | 43 | <span class="function">fixture</span><span class="parenthesis">(</span><span class="string_literal">r#"</span> |
44 | <span class="keyword">trait</span> <span class="trait declaration">Foo</span> <span class="brace">{</span> | 44 | <span class="keyword">trait</span> <span class="trait declaration">Foo</span> <span class="brace">{</span> |
45 | <span class="keyword">fn</span> <span class="function declaration static associated">foo</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span> | 45 | <span class="keyword">fn</span> <span class="function declaration static associated trait">foo</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span> |
46 | <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"2 + 2 = {}"</span><span class="comma">,</span> <span class="numeric_literal">4</span><span class="parenthesis">)</span><span class="semicolon">;</span> | 46 | <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"2 + 2 = {}"</span><span class="comma">,</span> <span class="numeric_literal">4</span><span class="parenthesis">)</span><span class="semicolon">;</span> |
47 | <span class="brace">}</span> | 47 | <span class="brace">}</span> |
48 | <span class="brace">}</span><span class="string_literal">"#</span> | 48 | <span class="brace">}</span><span class="string_literal">"#</span> |
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html b/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html index 6a6555208..72910421d 100644 --- a/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html +++ b/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html | |||
@@ -62,11 +62,11 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd | |||
62 | <span class="brace">}</span> | 62 | <span class="brace">}</span> |
63 | 63 | ||
64 | <span class="keyword">trait</span> <span class="trait declaration">DoTheAutoref</span> <span class="brace">{</span> | 64 | <span class="keyword">trait</span> <span class="trait declaration">DoTheAutoref</span> <span class="brace">{</span> |
65 | <span class="keyword">fn</span> <span class="function declaration associated">calls_autoref</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword declaration">self</span><span class="parenthesis">)</span><span class="semicolon">;</span> | 65 | <span class="keyword">fn</span> <span class="function declaration associated trait">calls_autoref</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword declaration">self</span><span class="parenthesis">)</span><span class="semicolon">;</span> |
66 | <span class="brace">}</span> | 66 | <span class="brace">}</span> |
67 | 67 | ||
68 | <span class="keyword">impl</span> <span class="trait">DoTheAutoref</span> <span class="keyword">for</span> <span class="builtin_type">u16</span> <span class="brace">{</span> | 68 | <span class="keyword">impl</span> <span class="trait">DoTheAutoref</span> <span class="keyword">for</span> <span class="builtin_type">u16</span> <span class="brace">{</span> |
69 | <span class="keyword">fn</span> <span class="function declaration associated">calls_autoref</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword declaration">self</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span> | 69 | <span class="keyword">fn</span> <span class="function declaration associated trait">calls_autoref</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword declaration">self</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span> |
70 | <span class="brace">}</span> | 70 | <span class="brace">}</span> |
71 | 71 | ||
72 | <span class="keyword">fn</span> <span class="function declaration">main</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span> | 72 | <span class="keyword">fn</span> <span class="function declaration">main</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span> |
@@ -96,6 +96,6 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd | |||
96 | <span class="keyword">let</span> <span class="struct">Packed</span> <span class="brace">{</span> <span class="field">a</span><span class="colon">:</span> <span class="keyword unsafe">ref</span> <span class="variable declaration">_a</span> <span class="brace">}</span> <span class="operator">=</span> <span class="variable">packed</span><span class="semicolon">;</span> | 96 | <span class="keyword">let</span> <span class="struct">Packed</span> <span class="brace">{</span> <span class="field">a</span><span class="colon">:</span> <span class="keyword unsafe">ref</span> <span class="variable declaration">_a</span> <span class="brace">}</span> <span class="operator">=</span> <span class="variable">packed</span><span class="semicolon">;</span> |
97 | 97 | ||
98 | <span class="comment">// unsafe auto ref of packed field</span> | 98 | <span class="comment">// unsafe auto ref of packed field</span> |
99 | <span class="variable">packed</span><span class="operator">.</span><span class="field">a</span><span class="operator">.</span><span class="function associated unsafe">calls_autoref</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span> | 99 | <span class="variable">packed</span><span class="operator">.</span><span class="field">a</span><span class="operator">.</span><span class="function associated trait unsafe">calls_autoref</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span> |
100 | <span class="brace">}</span> | 100 | <span class="brace">}</span> |
101 | <span class="brace">}</span></code></pre> \ No newline at end of file | 101 | <span class="brace">}</span></code></pre> \ No newline at end of file |
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlighting.html b/crates/ide/src/syntax_highlighting/test_data/highlighting.html index 8b2dd3b70..973173254 100644 --- a/crates/ide/src/syntax_highlighting/test_data/highlighting.html +++ b/crates/ide/src/syntax_highlighting/test_data/highlighting.html | |||
@@ -41,7 +41,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd | |||
41 | <span class="keyword">mod</span> <span class="module declaration">inner</span> <span class="brace">{</span><span class="brace">}</span> | 41 | <span class="keyword">mod</span> <span class="module declaration">inner</span> <span class="brace">{</span><span class="brace">}</span> |
42 | 42 | ||
43 | <span class="attribute attribute">#</span><span class="attribute attribute">[</span><span class="function attribute">rustc_builtin_macro</span><span class="attribute attribute">]</span> | 43 | <span class="attribute attribute">#</span><span class="attribute attribute">[</span><span class="function attribute">rustc_builtin_macro</span><span class="attribute attribute">]</span> |
44 | <span class="keyword">macro</span> <span class="unresolved_reference declaration">Copy</span> <span class="brace">{</span><span class="brace">}</span> | 44 | <span class="keyword">macro</span> <span class="macro declaration">Copy</span> <span class="brace">{</span><span class="brace">}</span> |
45 | 45 | ||
46 | <span class="comment">// Needed for function consuming vs normal</span> | 46 | <span class="comment">// Needed for function consuming vs normal</span> |
47 | <span class="keyword">pub</span> <span class="keyword">mod</span> <span class="module declaration">marker</span> <span class="brace">{</span> | 47 | <span class="keyword">pub</span> <span class="keyword">mod</span> <span class="module declaration">marker</span> <span class="brace">{</span> |
@@ -67,11 +67,11 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd | |||
67 | <span class="brace">}</span> | 67 | <span class="brace">}</span> |
68 | 68 | ||
69 | <span class="keyword">trait</span> <span class="trait declaration">Bar</span> <span class="brace">{</span> | 69 | <span class="keyword">trait</span> <span class="trait declaration">Bar</span> <span class="brace">{</span> |
70 | <span class="keyword">fn</span> <span class="function declaration associated">bar</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword declaration">self</span><span class="parenthesis">)</span> <span class="operator">-></span> <span class="builtin_type">i32</span><span class="semicolon">;</span> | 70 | <span class="keyword">fn</span> <span class="function declaration associated trait">bar</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword declaration">self</span><span class="parenthesis">)</span> <span class="operator">-></span> <span class="builtin_type">i32</span><span class="semicolon">;</span> |
71 | <span class="brace">}</span> | 71 | <span class="brace">}</span> |
72 | 72 | ||
73 | <span class="keyword">impl</span> <span class="trait">Bar</span> <span class="keyword">for</span> <span class="struct">Foo</span> <span class="brace">{</span> | 73 | <span class="keyword">impl</span> <span class="trait">Bar</span> <span class="keyword">for</span> <span class="struct">Foo</span> <span class="brace">{</span> |
74 | <span class="keyword">fn</span> <span class="function declaration associated">bar</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword declaration">self</span><span class="parenthesis">)</span> <span class="operator">-></span> <span class="builtin_type">i32</span> <span class="brace">{</span> | 74 | <span class="keyword">fn</span> <span class="function declaration associated trait">bar</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword declaration">self</span><span class="parenthesis">)</span> <span class="operator">-></span> <span class="builtin_type">i32</span> <span class="brace">{</span> |
75 | <span class="self_keyword">self</span><span class="operator">.</span><span class="field">x</span> | 75 | <span class="self_keyword">self</span><span class="operator">.</span><span class="field">x</span> |
76 | <span class="brace">}</span> | 76 | <span class="brace">}</span> |
77 | <span class="brace">}</span> | 77 | <span class="brace">}</span> |
@@ -158,6 +158,16 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd | |||
158 | <span class="parenthesis">(</span><span class="punctuation">$</span>type<span class="colon">:</span>ty<span class="parenthesis">)</span> <span class="operator">=</span><span class="angle">></span> <span class="parenthesis">(</span><span class="punctuation">$</span>type<span class="parenthesis">)</span> | 158 | <span class="parenthesis">(</span><span class="punctuation">$</span>type<span class="colon">:</span>ty<span class="parenthesis">)</span> <span class="operator">=</span><span class="angle">></span> <span class="parenthesis">(</span><span class="punctuation">$</span>type<span class="parenthesis">)</span> |
159 | <span class="brace">}</span> | 159 | <span class="brace">}</span> |
160 | 160 | ||
161 | <span class="keyword">macro</span> <span class="macro declaration">with_args</span><span class="parenthesis">(</span><span class="punctuation">$</span>i<span class="colon">:</span>ident<span class="parenthesis">)</span> <span class="brace">{</span> | ||
162 | <span class="punctuation">$</span>i | ||
163 | <span class="brace">}</span> | ||
164 | |||
165 | <span class="keyword">macro</span> <span class="macro declaration">without_args</span> <span class="brace">{</span> | ||
166 | <span class="parenthesis">(</span><span class="punctuation">$</span>i<span class="colon">:</span>ident<span class="parenthesis">)</span> <span class="operator">=</span><span class="angle">></span> <span class="brace">{</span> | ||
167 | <span class="punctuation">$</span>i | ||
168 | <span class="brace">}</span> | ||
169 | <span class="brace">}</span> | ||
170 | |||
161 | <span class="comment">// comment</span> | 171 | <span class="comment">// comment</span> |
162 | <span class="keyword">fn</span> <span class="function declaration">main</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span> | 172 | <span class="keyword">fn</span> <span class="function declaration">main</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span> |
163 | <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"Hello, {}!"</span><span class="comma">,</span> <span class="numeric_literal">92</span><span class="parenthesis">)</span><span class="semicolon">;</span> | 173 | <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"Hello, {}!"</span><span class="comma">,</span> <span class="numeric_literal">92</span><span class="parenthesis">)</span><span class="semicolon">;</span> |
diff --git a/crates/ide/src/syntax_highlighting/tests.rs b/crates/ide/src/syntax_highlighting/tests.rs index 7b2922b0d..369ae0972 100644 --- a/crates/ide/src/syntax_highlighting/tests.rs +++ b/crates/ide/src/syntax_highlighting/tests.rs | |||
@@ -129,6 +129,16 @@ macro_rules! keyword_frag { | |||
129 | ($type:ty) => ($type) | 129 | ($type:ty) => ($type) |
130 | } | 130 | } |
131 | 131 | ||
132 | macro with_args($i:ident) { | ||
133 | $i | ||
134 | } | ||
135 | |||
136 | macro without_args { | ||
137 | ($i:ident) => { | ||
138 | $i | ||
139 | } | ||
140 | } | ||
141 | |||
132 | // comment | 142 | // comment |
133 | fn main() { | 143 | fn main() { |
134 | println!("Hello, {}!", 92); | 144 | println!("Hello, {}!", 92); |
diff --git a/crates/ide/src/syntax_tree.rs b/crates/ide/src/syntax_tree.rs index 8979de528..633878d1c 100644 --- a/crates/ide/src/syntax_tree.rs +++ b/crates/ide/src/syntax_tree.rs | |||
@@ -14,6 +14,7 @@ use syntax::{ | |||
14 | // | 14 | // |
15 | // | VS Code | **Rust Analyzer: Show Syntax Tree** | 15 | // | VS Code | **Rust Analyzer: Show Syntax Tree** |
16 | // |=== | 16 | // |=== |
17 | // image::https://user-images.githubusercontent.com/48062697/113065586-068bdb80-91b1-11eb-9507-fee67f9f45a0.gif[] | ||
17 | pub(crate) fn syntax_tree( | 18 | pub(crate) fn syntax_tree( |
18 | db: &RootDatabase, | 19 | db: &RootDatabase, |
19 | file_id: FileId, | 20 | file_id: FileId, |
diff --git a/crates/ide/src/typing/on_enter.rs b/crates/ide/src/typing/on_enter.rs index 978c479de..9144681bf 100644 --- a/crates/ide/src/typing/on_enter.rs +++ b/crates/ide/src/typing/on_enter.rs | |||
@@ -32,6 +32,8 @@ use text_edit::TextEdit; | |||
32 | // "when": "editorTextFocus && !suggestWidgetVisible && editorLangId == rust" | 32 | // "when": "editorTextFocus && !suggestWidgetVisible && editorLangId == rust" |
33 | // } | 33 | // } |
34 | // ---- | 34 | // ---- |
35 | // | ||
36 | // image::https://user-images.githubusercontent.com/48062697/113065578-04c21800-91b1-11eb-82b8-22b8c481e645.gif[] | ||
35 | pub(crate) fn on_enter(db: &RootDatabase, position: FilePosition) -> Option<TextEdit> { | 37 | pub(crate) fn on_enter(db: &RootDatabase, position: FilePosition) -> Option<TextEdit> { |
36 | let parse = db.parse(position.file_id); | 38 | let parse = db.parse(position.file_id); |
37 | let file = parse.tree(); | 39 | let file = parse.tree(); |
diff --git a/crates/ide/src/view_hir.rs b/crates/ide/src/view_hir.rs index f8f3fae3d..7312afe53 100644 --- a/crates/ide/src/view_hir.rs +++ b/crates/ide/src/view_hir.rs | |||
@@ -10,6 +10,7 @@ use syntax::{algo::find_node_at_offset, ast, AstNode}; | |||
10 | // | 10 | // |
11 | // | VS Code | **Rust Analyzer: View Hir** | 11 | // | VS Code | **Rust Analyzer: View Hir** |
12 | // |=== | 12 | // |=== |
13 | // image::https://user-images.githubusercontent.com/48062697/113065588-068bdb80-91b1-11eb-9a78-0b4ef1e972fb.gif[] | ||
13 | pub(crate) fn view_hir(db: &RootDatabase, position: FilePosition) -> String { | 14 | pub(crate) fn view_hir(db: &RootDatabase, position: FilePosition) -> String { |
14 | body_hir(db, position).unwrap_or_else(|| "Not inside a function body".to_string()) | 15 | body_hir(db, position).unwrap_or_else(|| "Not inside a function body".to_string()) |
15 | } | 16 | } |