diff options
Diffstat (limited to 'crates/ide')
36 files changed, 800 insertions, 273 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/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..c5dc14a23 100644 --- a/crates/ide/src/doc_links.rs +++ b/crates/ide/src/doc_links.rs | |||
@@ -1,6 +1,9 @@ | |||
1 | //! Extracts, resolves and rewrites links and intra-doc links in markdown documentation. | 1 | //! Extracts, resolves and rewrites links and intra-doc links in markdown documentation. |
2 | 2 | ||
3 | use std::{convert::TryFrom, iter::once, ops::Range}; | 3 | use std::{ |
4 | convert::{TryFrom, TryInto}, | ||
5 | iter::once, | ||
6 | }; | ||
4 | 7 | ||
5 | use itertools::Itertools; | 8 | use itertools::Itertools; |
6 | use pulldown_cmark::{BrokenLink, CowStr, Event, InlineStr, LinkType, Options, Parser, Tag}; | 9 | use pulldown_cmark::{BrokenLink, CowStr, Event, InlineStr, LinkType, Options, Parser, Tag}; |
@@ -16,8 +19,7 @@ use ide_db::{ | |||
16 | RootDatabase, | 19 | RootDatabase, |
17 | }; | 20 | }; |
18 | use syntax::{ | 21 | use syntax::{ |
19 | ast, match_ast, AstNode, AstToken, SyntaxKind::*, SyntaxNode, SyntaxToken, TextRange, TextSize, | 22 | ast, match_ast, AstNode, SyntaxKind::*, SyntaxNode, SyntaxToken, TextRange, TokenAtOffset, T, |
20 | TokenAtOffset, T, | ||
21 | }; | 23 | }; |
22 | 24 | ||
23 | use crate::{FilePosition, Semantics}; | 25 | use crate::{FilePosition, Semantics}; |
@@ -26,12 +28,7 @@ pub(crate) type DocumentationLink = String; | |||
26 | 28 | ||
27 | /// Rewrite documentation links in markdown to point to an online host (e.g. docs.rs) | 29 | /// Rewrite documentation links in markdown to point to an online host (e.g. docs.rs) |
28 | pub(crate) fn rewrite_links(db: &RootDatabase, markdown: &str, definition: &Definition) -> String { | 30 | pub(crate) fn rewrite_links(db: &RootDatabase, markdown: &str, definition: &Definition) -> String { |
29 | let mut cb = |link: BrokenLink| { | 31 | let mut cb = broken_link_clone_cb; |
30 | Some(( | ||
31 | /*url*/ link.reference.to_owned().into(), | ||
32 | /*title*/ link.reference.to_owned().into(), | ||
33 | )) | ||
34 | }; | ||
35 | let doc = Parser::new_with_broken_link_callback(markdown, Options::empty(), Some(&mut cb)); | 32 | let doc = Parser::new_with_broken_link_callback(markdown, Options::empty(), Some(&mut cb)); |
36 | 33 | ||
37 | let doc = map_links(doc, |target, title: &str| { | 34 | let doc = map_links(doc, |target, title: &str| { |
@@ -98,76 +95,52 @@ pub(crate) fn remove_links(markdown: &str) -> String { | |||
98 | out | 95 | out |
99 | } | 96 | } |
100 | 97 | ||
98 | /// Retrieve a link to documentation for the given symbol. | ||
99 | pub(crate) fn external_docs( | ||
100 | db: &RootDatabase, | ||
101 | position: &FilePosition, | ||
102 | ) -> Option<DocumentationLink> { | ||
103 | let sema = Semantics::new(db); | ||
104 | let file = sema.parse(position.file_id).syntax().clone(); | ||
105 | let token = pick_best(file.token_at_offset(position.offset))?; | ||
106 | let token = sema.descend_into_macros(token); | ||
107 | |||
108 | let node = token.parent()?; | ||
109 | let definition = match_ast! { | ||
110 | match node { | ||
111 | ast::NameRef(name_ref) => NameRefClass::classify(&sema, &name_ref).map(|d| d.referenced(sema.db)), | ||
112 | ast::Name(name) => NameClass::classify(&sema, &name).map(|d| d.referenced_or_defined(sema.db)), | ||
113 | _ => None, | ||
114 | } | ||
115 | }; | ||
116 | |||
117 | get_doc_link(db, definition?) | ||
118 | } | ||
119 | |||
120 | /// Extracts all links from a given markdown text. | ||
101 | pub(crate) fn extract_definitions_from_markdown( | 121 | pub(crate) fn extract_definitions_from_markdown( |
102 | markdown: &str, | 122 | markdown: &str, |
103 | ) -> Vec<(Range<usize>, String, Option<hir::Namespace>)> { | 123 | ) -> Vec<(TextRange, String, Option<hir::Namespace>)> { |
104 | let mut res = vec![]; | 124 | Parser::new_with_broken_link_callback( |
105 | let mut cb = |link: BrokenLink| { | 125 | markdown, |
106 | // These allocations are actually unnecessary but the lifetimes on BrokenLinkCallback are wrong | 126 | Options::empty(), |
107 | // this is fixed in the repo but not on the crates.io release yet | 127 | Some(&mut broken_link_clone_cb), |
108 | Some(( | 128 | ) |
109 | /*url*/ link.reference.to_owned().into(), | 129 | .into_offset_iter() |
110 | /*title*/ link.reference.to_owned().into(), | 130 | .filter_map(|(event, range)| { |
111 | )) | ||
112 | }; | ||
113 | let doc = Parser::new_with_broken_link_callback(markdown, Options::empty(), Some(&mut cb)); | ||
114 | for (event, range) in doc.into_offset_iter() { | ||
115 | if let Event::Start(Tag::Link(_, target, title)) = event { | 131 | if let Event::Start(Tag::Link(_, target, title)) = event { |
116 | let link = if target.is_empty() { title } else { target }; | 132 | let link = if target.is_empty() { title } else { target }; |
117 | let (link, ns) = parse_intra_doc_link(&link); | 133 | let (link, ns) = parse_intra_doc_link(&link); |
118 | res.push((range, link.to_string(), ns)); | 134 | Some(( |
119 | } | 135 | TextRange::new(range.start.try_into().ok()?, range.end.try_into().ok()?), |
120 | } | 136 | link.to_string(), |
121 | res | 137 | ns, |
122 | } | 138 | )) |
123 | 139 | } else { | |
124 | /// Extracts a link from a comment at the given position returning the spanning range, link and | 140 | None |
125 | /// optionally it's namespace. | ||
126 | pub(crate) fn extract_positioned_link_from_comment( | ||
127 | position: TextSize, | ||
128 | comment: &ast::Comment, | ||
129 | ) -> Option<(TextRange, String, Option<hir::Namespace>)> { | ||
130 | let doc_comment = comment.doc_comment()?; | ||
131 | let comment_start = | ||
132 | comment.syntax().text_range().start() + TextSize::from(comment.prefix().len() as u32); | ||
133 | let def_links = extract_definitions_from_markdown(doc_comment); | ||
134 | let (range, def_link, ns) = | ||
135 | def_links.into_iter().find_map(|(Range { start, end }, def_link, ns)| { | ||
136 | let range = TextRange::at( | ||
137 | comment_start + TextSize::from(start as u32), | ||
138 | TextSize::from((end - start) as u32), | ||
139 | ); | ||
140 | range.contains(position).then(|| (range, def_link, ns)) | ||
141 | })?; | ||
142 | Some((range, def_link, ns)) | ||
143 | } | ||
144 | |||
145 | /// Turns a syntax node into it's [`Definition`] if it can hold docs. | ||
146 | pub(crate) fn doc_owner_to_def( | ||
147 | sema: &Semantics<RootDatabase>, | ||
148 | item: &SyntaxNode, | ||
149 | ) -> Option<Definition> { | ||
150 | let res: hir::ModuleDef = match_ast! { | ||
151 | match item { | ||
152 | ast::SourceFile(_it) => sema.scope(item).module()?.into(), | ||
153 | ast::Fn(it) => sema.to_def(&it)?.into(), | ||
154 | ast::Struct(it) => sema.to_def(&it)?.into(), | ||
155 | ast::Enum(it) => sema.to_def(&it)?.into(), | ||
156 | ast::Union(it) => sema.to_def(&it)?.into(), | ||
157 | ast::Trait(it) => sema.to_def(&it)?.into(), | ||
158 | ast::Const(it) => sema.to_def(&it)?.into(), | ||
159 | ast::Static(it) => sema.to_def(&it)?.into(), | ||
160 | ast::TypeAlias(it) => sema.to_def(&it)?.into(), | ||
161 | ast::Variant(it) => sema.to_def(&it)?.into(), | ||
162 | ast::Trait(it) => sema.to_def(&it)?.into(), | ||
163 | ast::Impl(it) => return sema.to_def(&it).map(Definition::SelfType), | ||
164 | ast::MacroRules(it) => return sema.to_def(&it).map(Definition::Macro), | ||
165 | ast::TupleField(it) => return sema.to_def(&it).map(Definition::Field), | ||
166 | ast::RecordField(it) => return sema.to_def(&it).map(Definition::Field), | ||
167 | _ => return None, | ||
168 | } | 141 | } |
169 | }; | 142 | }) |
170 | Some(Definition::ModuleDef(res)) | 143 | .collect() |
171 | } | 144 | } |
172 | 145 | ||
173 | pub(crate) fn resolve_doc_path_for_def( | 146 | pub(crate) fn resolve_doc_path_for_def( |
@@ -178,15 +151,15 @@ pub(crate) fn resolve_doc_path_for_def( | |||
178 | ) -> Option<hir::ModuleDef> { | 151 | ) -> Option<hir::ModuleDef> { |
179 | match def { | 152 | match def { |
180 | Definition::ModuleDef(def) => match def { | 153 | Definition::ModuleDef(def) => match def { |
181 | ModuleDef::Module(it) => it.resolve_doc_path(db, &link, ns), | 154 | hir::ModuleDef::Module(it) => it.resolve_doc_path(db, &link, ns), |
182 | ModuleDef::Function(it) => it.resolve_doc_path(db, &link, ns), | 155 | hir::ModuleDef::Function(it) => it.resolve_doc_path(db, &link, ns), |
183 | ModuleDef::Adt(it) => it.resolve_doc_path(db, &link, ns), | 156 | hir::ModuleDef::Adt(it) => it.resolve_doc_path(db, &link, ns), |
184 | ModuleDef::Variant(it) => it.resolve_doc_path(db, &link, ns), | 157 | hir::ModuleDef::Variant(it) => it.resolve_doc_path(db, &link, ns), |
185 | ModuleDef::Const(it) => it.resolve_doc_path(db, &link, ns), | 158 | hir::ModuleDef::Const(it) => it.resolve_doc_path(db, &link, ns), |
186 | ModuleDef::Static(it) => it.resolve_doc_path(db, &link, ns), | 159 | hir::ModuleDef::Static(it) => it.resolve_doc_path(db, &link, ns), |
187 | ModuleDef::Trait(it) => it.resolve_doc_path(db, &link, ns), | 160 | hir::ModuleDef::Trait(it) => it.resolve_doc_path(db, &link, ns), |
188 | ModuleDef::TypeAlias(it) => it.resolve_doc_path(db, &link, ns), | 161 | hir::ModuleDef::TypeAlias(it) => it.resolve_doc_path(db, &link, ns), |
189 | ModuleDef::BuiltinType(_) => None, | 162 | hir::ModuleDef::BuiltinType(_) => None, |
190 | }, | 163 | }, |
191 | Definition::Macro(it) => it.resolve_doc_path(db, &link, ns), | 164 | Definition::Macro(it) => it.resolve_doc_path(db, &link, ns), |
192 | Definition::Field(it) => it.resolve_doc_path(db, &link, ns), | 165 | Definition::Field(it) => it.resolve_doc_path(db, &link, ns), |
@@ -197,6 +170,42 @@ pub(crate) fn resolve_doc_path_for_def( | |||
197 | } | 170 | } |
198 | } | 171 | } |
199 | 172 | ||
173 | pub(crate) fn doc_attributes( | ||
174 | sema: &Semantics<RootDatabase>, | ||
175 | node: &SyntaxNode, | ||
176 | ) -> Option<(hir::AttrsWithOwner, Definition)> { | ||
177 | match_ast! { | ||
178 | match node { | ||
179 | ast::SourceFile(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::ModuleDef(hir::ModuleDef::Module(def)))), | ||
180 | ast::Module(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::ModuleDef(hir::ModuleDef::Module(def)))), | ||
181 | ast::Fn(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::ModuleDef(hir::ModuleDef::Function(def)))), | ||
182 | ast::Struct(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::ModuleDef(hir::ModuleDef::Adt(hir::Adt::Struct(def))))), | ||
183 | ast::Union(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::ModuleDef(hir::ModuleDef::Adt(hir::Adt::Union(def))))), | ||
184 | ast::Enum(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::ModuleDef(hir::ModuleDef::Adt(hir::Adt::Enum(def))))), | ||
185 | ast::Variant(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::ModuleDef(hir::ModuleDef::Variant(def)))), | ||
186 | ast::Trait(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::ModuleDef(hir::ModuleDef::Trait(def)))), | ||
187 | ast::Static(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::ModuleDef(hir::ModuleDef::Static(def)))), | ||
188 | ast::Const(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::ModuleDef(hir::ModuleDef::Const(def)))), | ||
189 | ast::TypeAlias(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::ModuleDef(hir::ModuleDef::TypeAlias(def)))), | ||
190 | ast::Impl(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::SelfType(def))), | ||
191 | ast::RecordField(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::Field(def))), | ||
192 | ast::TupleField(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::Field(def))), | ||
193 | ast::Macro(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::Macro(def))), | ||
194 | // ast::Use(it) => sema.to_def(&it).map(|def| (Box::new(it) as _, def.attrs(sema.db))), | ||
195 | _ => return None | ||
196 | } | ||
197 | } | ||
198 | } | ||
199 | |||
200 | fn broken_link_clone_cb<'a, 'b>(link: BrokenLink<'a>) -> Option<(CowStr<'b>, CowStr<'b>)> { | ||
201 | // These allocations are actually unnecessary but the lifetimes on BrokenLinkCallback are wrong | ||
202 | // this is fixed in the repo but not on the crates.io release yet | ||
203 | Some(( | ||
204 | /*url*/ link.reference.to_owned().into(), | ||
205 | /*title*/ link.reference.to_owned().into(), | ||
206 | )) | ||
207 | } | ||
208 | |||
200 | // FIXME: | 209 | // FIXME: |
201 | // BUG: For Option::Some | 210 | // BUG: For Option::Some |
202 | // Returns https://doc.rust-lang.org/nightly/core/prelude/v1/enum.Option.html#variant.Some | 211 | // Returns https://doc.rust-lang.org/nightly/core/prelude/v1/enum.Option.html#variant.Some |
@@ -214,7 +223,7 @@ fn get_doc_link(db: &RootDatabase, definition: Definition) -> Option<String> { | |||
214 | .and_then(|assoc| match assoc.container(db) { | 223 | .and_then(|assoc| match assoc.container(db) { |
215 | AssocItemContainer::Trait(t) => Some(t.into()), | 224 | AssocItemContainer::Trait(t) => Some(t.into()), |
216 | AssocItemContainer::Impl(impld) => { | 225 | AssocItemContainer::Impl(impld) => { |
217 | impld.target_ty(db).as_adt().map(|adt| adt.into()) | 226 | impld.self_ty(db).as_adt().map(|adt| adt.into()) |
218 | } | 227 | } |
219 | }) | 228 | }) |
220 | .unwrap_or_else(|| f.clone().into()), | 229 | .unwrap_or_else(|| f.clone().into()), |
@@ -328,28 +337,6 @@ fn rewrite_url_link(db: &RootDatabase, def: ModuleDef, target: &str) -> Option<S | |||
328 | .map(|url| url.into_string()) | 337 | .map(|url| url.into_string()) |
329 | } | 338 | } |
330 | 339 | ||
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. | 340 | /// Rewrites a markdown document, applying 'callback' to each link. |
354 | fn map_links<'e>( | 341 | fn map_links<'e>( |
355 | events: impl Iterator<Item = Event<'e>>, | 342 | 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..ca8ccb2da 100644 --- a/crates/ide/src/goto_definition.rs +++ b/crates/ide/src/goto_definition.rs | |||
@@ -1,5 +1,5 @@ | |||
1 | use either::Either; | 1 | use either::Either; |
2 | use hir::Semantics; | 2 | use hir::{InFile, Semantics}; |
3 | use ide_db::{ | 3 | use ide_db::{ |
4 | defs::{NameClass, NameRefClass}, | 4 | defs::{NameClass, NameRefClass}, |
5 | RootDatabase, | 5 | RootDatabase, |
@@ -8,7 +8,7 @@ use syntax::{ast, match_ast, AstNode, AstToken, SyntaxKind::*, SyntaxToken, Toke | |||
8 | 8 | ||
9 | use crate::{ | 9 | use crate::{ |
10 | display::TryToNav, | 10 | display::TryToNav, |
11 | doc_links::{doc_owner_to_def, extract_positioned_link_from_comment, resolve_doc_path_for_def}, | 11 | doc_links::{doc_attributes, extract_definitions_from_markdown, resolve_doc_path_for_def}, |
12 | FilePosition, NavigationTarget, RangeInfo, | 12 | FilePosition, NavigationTarget, RangeInfo, |
13 | }; | 13 | }; |
14 | 14 | ||
@@ -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, |
@@ -30,9 +32,16 @@ pub(crate) fn goto_definition( | |||
30 | let original_token = pick_best(file.token_at_offset(position.offset))?; | 32 | let original_token = pick_best(file.token_at_offset(position.offset))?; |
31 | let token = sema.descend_into_macros(original_token.clone()); | 33 | let token = sema.descend_into_macros(original_token.clone()); |
32 | let parent = token.parent()?; | 34 | let parent = token.parent()?; |
33 | if let Some(comment) = ast::Comment::cast(token) { | 35 | if let Some(_) = ast::Comment::cast(token) { |
34 | let (_, link, ns) = extract_positioned_link_from_comment(position.offset, &comment)?; | 36 | let (attributes, def) = doc_attributes(&sema, &parent)?; |
35 | let def = doc_owner_to_def(&sema, &parent)?; | 37 | |
38 | let (docs, doc_mapping) = attributes.docs_with_rangemap(db)?; | ||
39 | let (_, link, ns) = | ||
40 | extract_definitions_from_markdown(docs.as_str()).into_iter().find(|(range, ..)| { | ||
41 | doc_mapping.map(range.clone()).map_or(false, |InFile { file_id, value: range }| { | ||
42 | file_id == position.file_id.into() && range.contains(position.offset) | ||
43 | }) | ||
44 | })?; | ||
36 | let nav = resolve_doc_path_for_def(db, def, &link, ns)?.try_to_nav(db)?; | 45 | let nav = resolve_doc_path_for_def(db, def, &link, ns)?.try_to_nav(db)?; |
37 | return Some(RangeInfo::new(original_token.text_range(), vec![nav])); | 46 | return Some(RangeInfo::new(original_token.text_range(), vec![nav])); |
38 | } | 47 | } |
@@ -918,6 +927,21 @@ fn f() -> impl Iterator<Item$0 = u8> {} | |||
918 | } | 927 | } |
919 | 928 | ||
920 | #[test] | 929 | #[test] |
930 | #[should_panic = "unresolved reference"] | ||
931 | fn unknown_assoc_ty() { | ||
932 | check( | ||
933 | r#" | ||
934 | trait Iterator { | ||
935 | type Item; | ||
936 | //^^^^ | ||
937 | } | ||
938 | |||
939 | fn f() -> impl Iterator<Invalid$0 = u8> {} | ||
940 | "#, | ||
941 | ) | ||
942 | } | ||
943 | |||
944 | #[test] | ||
921 | fn goto_def_for_assoc_ty_in_path_multiple() { | 945 | fn goto_def_for_assoc_ty_in_path_multiple() { |
922 | check( | 946 | check( |
923 | r#" | 947 | r#" |
@@ -1143,4 +1167,25 @@ fn fn_macro() {} | |||
1143 | "#, | 1167 | "#, |
1144 | ) | 1168 | ) |
1145 | } | 1169 | } |
1170 | |||
1171 | #[test] | ||
1172 | fn goto_intra_doc_links() { | ||
1173 | check( | ||
1174 | r#" | ||
1175 | |||
1176 | pub mod theitem { | ||
1177 | /// This is the item. Cool! | ||
1178 | pub struct TheItem; | ||
1179 | //^^^^^^^ | ||
1180 | } | ||
1181 | |||
1182 | /// Gives you a [`TheItem$0`]. | ||
1183 | /// | ||
1184 | /// [`TheItem`]: theitem::TheItem | ||
1185 | pub fn gimme() -> theitem::TheItem { | ||
1186 | theitem::TheItem | ||
1187 | } | ||
1188 | "#, | ||
1189 | ); | ||
1190 | } | ||
1146 | } | 1191 | } |
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..9de653739 100644 --- a/crates/ide/src/hover.rs +++ b/crates/ide/src/hover.rs | |||
@@ -1,6 +1,6 @@ | |||
1 | use either::Either; | 1 | use either::Either; |
2 | use hir::{ | 2 | use hir::{ |
3 | AsAssocItem, AssocItemContainer, GenericParam, HasAttrs, HasSource, HirDisplay, Module, | 3 | AsAssocItem, AssocItemContainer, GenericParam, HasAttrs, HasSource, HirDisplay, InFile, Module, |
4 | ModuleDef, Semantics, | 4 | ModuleDef, Semantics, |
5 | }; | 5 | }; |
6 | use ide_db::{ | 6 | use ide_db::{ |
@@ -16,8 +16,8 @@ use syntax::{ast, match_ast, AstNode, AstToken, SyntaxKind::*, SyntaxToken, Toke | |||
16 | use crate::{ | 16 | use crate::{ |
17 | display::{macro_label, TryToNav}, | 17 | display::{macro_label, TryToNav}, |
18 | doc_links::{ | 18 | doc_links::{ |
19 | doc_owner_to_def, extract_positioned_link_from_comment, remove_links, | 19 | doc_attributes, extract_definitions_from_markdown, remove_links, resolve_doc_path_for_def, |
20 | resolve_doc_path_for_def, rewrite_links, | 20 | rewrite_links, |
21 | }, | 21 | }, |
22 | markdown_remove::remove_markdown, | 22 | markdown_remove::remove_markdown, |
23 | markup::Markup, | 23 | markup::Markup, |
@@ -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, |
@@ -114,11 +116,19 @@ pub(crate) fn hover( | |||
114 | ), | 116 | ), |
115 | 117 | ||
116 | _ => ast::Comment::cast(token.clone()) | 118 | _ => ast::Comment::cast(token.clone()) |
117 | .and_then(|comment| { | 119 | .and_then(|_| { |
120 | let (attributes, def) = doc_attributes(&sema, &node)?; | ||
121 | let (docs, doc_mapping) = attributes.docs_with_rangemap(db)?; | ||
118 | let (idl_range, link, ns) = | 122 | let (idl_range, link, ns) = |
119 | extract_positioned_link_from_comment(position.offset, &comment)?; | 123 | extract_definitions_from_markdown(docs.as_str()).into_iter().find_map(|(range, link, ns)| { |
124 | let InFile { file_id, value: range } = doc_mapping.map(range.clone())?; | ||
125 | if file_id == position.file_id.into() && range.contains(position.offset) { | ||
126 | Some((range, link, ns)) | ||
127 | } else { | ||
128 | None | ||
129 | } | ||
130 | })?; | ||
120 | range = Some(idl_range); | 131 | range = Some(idl_range); |
121 | let def = doc_owner_to_def(&sema, &node)?; | ||
122 | resolve_doc_path_for_def(db, def, &link, ns) | 132 | resolve_doc_path_for_def(db, def, &link, ns) |
123 | }) | 133 | }) |
124 | .map(Definition::ModuleDef), | 134 | .map(Definition::ModuleDef), |
@@ -195,7 +205,7 @@ fn show_implementations_action(db: &RootDatabase, def: Definition) -> Option<Hov | |||
195 | let adt = match def { | 205 | let adt = match def { |
196 | Definition::ModuleDef(ModuleDef::Trait(it)) => return it.try_to_nav(db).map(to_action), | 206 | Definition::ModuleDef(ModuleDef::Trait(it)) => return it.try_to_nav(db).map(to_action), |
197 | Definition::ModuleDef(ModuleDef::Adt(it)) => Some(it), | 207 | Definition::ModuleDef(ModuleDef::Adt(it)) => Some(it), |
198 | Definition::SelfType(it) => it.target_ty(db).as_adt(), | 208 | Definition::SelfType(it) => it.self_ty(db).as_adt(), |
199 | _ => None, | 209 | _ => None, |
200 | }?; | 210 | }?; |
201 | adt.try_to_nav(db).map(to_action) | 211 | adt.try_to_nav(db).map(to_action) |
@@ -318,7 +328,7 @@ fn definition_owner_name(db: &RootDatabase, def: &Definition) -> Option<String> | |||
318 | Definition::ModuleDef(md) => match md { | 328 | Definition::ModuleDef(md) => match md { |
319 | ModuleDef::Function(f) => match f.as_assoc_item(db)?.container(db) { | 329 | ModuleDef::Function(f) => match f.as_assoc_item(db)?.container(db) { |
320 | AssocItemContainer::Trait(t) => Some(t.name(db)), | 330 | AssocItemContainer::Trait(t) => Some(t.name(db)), |
321 | AssocItemContainer::Impl(i) => i.target_ty(db).as_adt().map(|adt| adt.name(db)), | 331 | AssocItemContainer::Impl(i) => i.self_ty(db).as_adt().map(|adt| adt.name(db)), |
322 | }, | 332 | }, |
323 | ModuleDef::Variant(e) => Some(e.parent_enum(db).name(db)), | 333 | ModuleDef::Variant(e) => Some(e.parent_enum(db).name(db)), |
324 | _ => None, | 334 | _ => None, |
@@ -376,7 +386,7 @@ fn hover_for_definition( | |||
376 | }, | 386 | }, |
377 | Definition::Local(it) => hover_for_local(it, db), | 387 | Definition::Local(it) => hover_for_local(it, db), |
378 | Definition::SelfType(impl_def) => { | 388 | Definition::SelfType(impl_def) => { |
379 | impl_def.target_ty(db).as_adt().and_then(|adt| from_hir_fmt(db, adt, mod_path)) | 389 | impl_def.self_ty(db).as_adt().and_then(|adt| from_hir_fmt(db, adt, mod_path)) |
380 | } | 390 | } |
381 | Definition::GenericParam(it) => from_hir_fmt(db, it, None), | 391 | Definition::GenericParam(it) => from_hir_fmt(db, it, None), |
382 | Definition::Label(it) => Some(Markup::fenced_block(&it.name(db))), | 392 | Definition::Label(it) => Some(Markup::fenced_block(&it.name(db))), |
@@ -470,6 +480,7 @@ fn find_std_module(famous_defs: &FamousDefs, name: &str) -> Option<hir::Module> | |||
470 | 480 | ||
471 | fn pick_best(tokens: TokenAtOffset<SyntaxToken>) -> Option<SyntaxToken> { | 481 | fn pick_best(tokens: TokenAtOffset<SyntaxToken>) -> Option<SyntaxToken> { |
472 | return tokens.max_by_key(priority); | 482 | return tokens.max_by_key(priority); |
483 | |||
473 | fn priority(n: &SyntaxToken) -> usize { | 484 | fn priority(n: &SyntaxToken) -> usize { |
474 | match n.kind() { | 485 | match n.kind() { |
475 | IDENT | INT_NUMBER | LIFETIME_IDENT | T![self] | T![super] | T![crate] => 3, | 486 | IDENT | INT_NUMBER | LIFETIME_IDENT | T![self] | T![super] | T![crate] => 3, |
@@ -1235,6 +1246,37 @@ fn f() { fo$0o!(); } | |||
1235 | } | 1246 | } |
1236 | 1247 | ||
1237 | #[test] | 1248 | #[test] |
1249 | fn test_hover_macro2_invocation() { | ||
1250 | check( | ||
1251 | r#" | ||
1252 | /// foo bar | ||
1253 | /// | ||
1254 | /// foo bar baz | ||
1255 | macro foo() {} | ||
1256 | |||
1257 | fn f() { fo$0o!(); } | ||
1258 | "#, | ||
1259 | expect![[r#" | ||
1260 | *foo* | ||
1261 | |||
1262 | ```rust | ||
1263 | test | ||
1264 | ``` | ||
1265 | |||
1266 | ```rust | ||
1267 | macro foo | ||
1268 | ``` | ||
1269 | |||
1270 | --- | ||
1271 | |||
1272 | foo bar | ||
1273 | |||
1274 | foo bar baz | ||
1275 | "#]], | ||
1276 | ) | ||
1277 | } | ||
1278 | |||
1279 | #[test] | ||
1238 | fn test_hover_tuple_field() { | 1280 | fn test_hover_tuple_field() { |
1239 | check( | 1281 | check( |
1240 | r#"struct TS(String, i32$0);"#, | 1282 | r#"struct TS(String, i32$0);"#, |
@@ -3780,24 +3822,139 @@ fn main() { | |||
3780 | fn hover_intra_doc_links() { | 3822 | fn hover_intra_doc_links() { |
3781 | check( | 3823 | check( |
3782 | r#" | 3824 | r#" |
3783 | /// This is the [`foo`](foo$0) function. | 3825 | |
3784 | fn foo() {} | 3826 | pub mod theitem { |
3827 | /// This is the item. Cool! | ||
3828 | pub struct TheItem; | ||
3829 | } | ||
3830 | |||
3831 | /// Gives you a [`TheItem$0`]. | ||
3832 | /// | ||
3833 | /// [`TheItem`]: theitem::TheItem | ||
3834 | pub fn gimme() -> theitem::TheItem { | ||
3835 | theitem::TheItem | ||
3836 | } | ||
3785 | "#, | 3837 | "#, |
3786 | expect![[r#" | 3838 | expect![[r#" |
3787 | *[`foo`](foo)* | 3839 | *[`TheItem`]* |
3788 | 3840 | ||
3789 | ```rust | 3841 | ```rust |
3790 | test | 3842 | test::theitem |
3791 | ``` | 3843 | ``` |
3792 | 3844 | ||
3793 | ```rust | 3845 | ```rust |
3794 | fn foo() | 3846 | pub struct TheItem |
3795 | ``` | 3847 | ``` |
3796 | 3848 | ||
3797 | --- | 3849 | --- |
3798 | 3850 | ||
3799 | This is the [`foo`](https://docs.rs/test/*/test/fn.foo.html) function. | 3851 | This is the item. Cool! |
3852 | "#]], | ||
3853 | ); | ||
3854 | } | ||
3855 | |||
3856 | #[test] | ||
3857 | fn hover_generic_assoc() { | ||
3858 | check( | ||
3859 | r#" | ||
3860 | fn foo<T: A>() where T::Assoc$0: {} | ||
3861 | |||
3862 | trait A { | ||
3863 | type Assoc; | ||
3864 | }"#, | ||
3865 | expect![[r#" | ||
3866 | *Assoc* | ||
3867 | |||
3868 | ```rust | ||
3869 | test | ||
3870 | ``` | ||
3871 | |||
3872 | ```rust | ||
3873 | type Assoc | ||
3874 | ``` | ||
3875 | "#]], | ||
3876 | ); | ||
3877 | check( | ||
3878 | r#" | ||
3879 | fn foo<T: A>() { | ||
3880 | let _: <T>::Assoc$0; | ||
3881 | } | ||
3882 | |||
3883 | trait A { | ||
3884 | type Assoc; | ||
3885 | }"#, | ||
3886 | expect![[r#" | ||
3887 | *Assoc* | ||
3888 | |||
3889 | ```rust | ||
3890 | test | ||
3891 | ``` | ||
3892 | |||
3893 | ```rust | ||
3894 | type Assoc | ||
3895 | ``` | ||
3896 | "#]], | ||
3897 | ); | ||
3898 | check( | ||
3899 | r#" | ||
3900 | trait A where | ||
3901 | Self::Assoc$0: , | ||
3902 | { | ||
3903 | type Assoc; | ||
3904 | }"#, | ||
3905 | expect![[r#" | ||
3906 | *Assoc* | ||
3907 | |||
3908 | ```rust | ||
3909 | test | ||
3910 | ``` | ||
3911 | |||
3912 | ```rust | ||
3913 | type Assoc | ||
3914 | ``` | ||
3800 | "#]], | 3915 | "#]], |
3801 | ); | 3916 | ); |
3802 | } | 3917 | } |
3918 | |||
3919 | #[test] | ||
3920 | fn string_shadowed_with_inner_items() { | ||
3921 | check( | ||
3922 | r#" | ||
3923 | //- /main.rs crate:main deps:alloc | ||
3924 | |||
3925 | /// Custom `String` type. | ||
3926 | struct String; | ||
3927 | |||
3928 | fn f() { | ||
3929 | let _: String$0; | ||
3930 | |||
3931 | fn inner() {} | ||
3932 | } | ||
3933 | |||
3934 | //- /alloc.rs crate:alloc | ||
3935 | #[prelude_import] | ||
3936 | pub use string::*; | ||
3937 | |||
3938 | mod string { | ||
3939 | /// This is `alloc::String`. | ||
3940 | pub struct String; | ||
3941 | } | ||
3942 | "#, | ||
3943 | expect![[r#" | ||
3944 | *String* | ||
3945 | |||
3946 | ```rust | ||
3947 | main | ||
3948 | ``` | ||
3949 | |||
3950 | ```rust | ||
3951 | struct String | ||
3952 | ``` | ||
3953 | |||
3954 | --- | ||
3955 | |||
3956 | Custom `String` type. | ||
3957 | "#]], | ||
3958 | ) | ||
3959 | } | ||
3803 | } | 3960 | } |
diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs index 25f96222c..d5ef054d8 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, |
@@ -232,7 +234,7 @@ fn hint_iterator( | |||
232 | hir::AssocItem::TypeAlias(alias) if alias.name(db) == known::Item => Some(alias), | 234 | hir::AssocItem::TypeAlias(alias) if alias.name(db) == known::Item => Some(alias), |
233 | _ => None, | 235 | _ => None, |
234 | })?; | 236 | })?; |
235 | if let Some(ty) = ty.normalize_trait_assoc_type(db, iter_trait, &[], assoc_type_item) { | 237 | if let Some(ty) = ty.normalize_trait_assoc_type(db, &[], assoc_type_item) { |
236 | const LABEL_START: &str = "impl Iterator<Item = "; | 238 | const LABEL_START: &str = "impl Iterator<Item = "; |
237 | const LABEL_END: &str = ">"; | 239 | const LABEL_END: &str = ">"; |
238 | 240 | ||
diff --git a/crates/ide/src/join_lines.rs b/crates/ide/src/join_lines.rs index 4b25135cd..fe2a349e6 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(); |
@@ -86,8 +88,11 @@ fn remove_newline(edit: &mut TextEditBuilder, token: &SyntaxToken, offset: TextS | |||
86 | } | 88 | } |
87 | 89 | ||
88 | // The node is between two other nodes | 90 | // The node is between two other nodes |
89 | let prev = token.prev_sibling_or_token().unwrap(); | 91 | let (prev, next) = match (token.prev_sibling_or_token(), token.next_sibling_or_token()) { |
90 | let next = token.next_sibling_or_token().unwrap(); | 92 | (Some(prev), Some(next)) => (prev, next), |
93 | _ => return, | ||
94 | }; | ||
95 | |||
91 | if is_trailing_comma(prev.kind(), next.kind()) { | 96 | if is_trailing_comma(prev.kind(), next.kind()) { |
92 | // Removes: trailing comma, newline (incl. surrounding whitespace) | 97 | // Removes: trailing comma, newline (incl. surrounding whitespace) |
93 | edit.delete(TextRange::new(prev.text_range().start(), token.text_range().end())); | 98 | edit.delete(TextRange::new(prev.text_range().start(), token.text_range().end())); |
@@ -827,4 +832,15 @@ $0hello world | |||
827 | "#, | 832 | "#, |
828 | ); | 833 | ); |
829 | } | 834 | } |
835 | #[test] | ||
836 | fn join_last_line_empty() { | ||
837 | check_join_lines( | ||
838 | r#" | ||
839 | fn main() {$0} | ||
840 | "#, | ||
841 | r#" | ||
842 | fn main() {$0} | ||
843 | "#, | ||
844 | ); | ||
845 | } | ||
830 | } | 846 | } |
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..9df8d21af 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 | }; |
@@ -48,6 +48,9 @@ pub struct HlRange { | |||
48 | // | 48 | // |
49 | // The general rule is that a reference to an entity gets colored the same way as the entity itself. | 49 | // The general rule is that a reference to an entity gets colored the same way as the entity itself. |
50 | // We also give special modifier for `mut` and `&mut` local variables. | 50 | // We also give special modifier for `mut` and `&mut` local variables. |
51 | // | ||
52 | // image::https://user-images.githubusercontent.com/48062697/113164457-06cfb980-9239-11eb-819b-0f93e646acf8.png[] | ||
53 | // image::https://user-images.githubusercontent.com/48062697/113187625-f7f50100-9250-11eb-825e-91c58f236071.png[] | ||
51 | pub(crate) fn highlight( | 54 | pub(crate) fn highlight( |
52 | db: &RootDatabase, | 55 | db: &RootDatabase, |
53 | file_id: FileId, | 56 | file_id: FileId, |
@@ -93,8 +96,8 @@ fn traverse( | |||
93 | let mut bindings_shadow_count: FxHashMap<Name, u32> = FxHashMap::default(); | 96 | let mut bindings_shadow_count: FxHashMap<Name, u32> = FxHashMap::default(); |
94 | 97 | ||
95 | let mut current_macro_call: Option<ast::MacroCall> = None; | 98 | let mut current_macro_call: Option<ast::MacroCall> = None; |
96 | let mut current_macro_rules: Option<ast::MacroRules> = None; | 99 | let mut current_macro: Option<ast::Macro> = None; |
97 | let mut macro_rules_highlighter = MacroRulesHighlighter::default(); | 100 | let mut macro_highlighter = MacroHighlighter::default(); |
98 | let mut inside_attribute = false; | 101 | let mut inside_attribute = false; |
99 | 102 | ||
100 | // Walk all nodes, keeping track of whether we are inside a macro or not. | 103 | // Walk all nodes, keeping track of whether we are inside a macro or not. |
@@ -129,16 +132,16 @@ fn traverse( | |||
129 | _ => (), | 132 | _ => (), |
130 | } | 133 | } |
131 | 134 | ||
132 | match event.clone().map(|it| it.into_node().and_then(ast::MacroRules::cast)) { | 135 | match event.clone().map(|it| it.into_node().and_then(ast::Macro::cast)) { |
133 | WalkEvent::Enter(Some(mac)) => { | 136 | WalkEvent::Enter(Some(mac)) => { |
134 | macro_rules_highlighter.init(); | 137 | macro_highlighter.init(); |
135 | current_macro_rules = Some(mac); | 138 | current_macro = Some(mac); |
136 | continue; | 139 | continue; |
137 | } | 140 | } |
138 | WalkEvent::Leave(Some(mac)) => { | 141 | WalkEvent::Leave(Some(mac)) => { |
139 | assert_eq!(current_macro_rules, Some(mac)); | 142 | assert_eq!(current_macro, Some(mac)); |
140 | current_macro_rules = None; | 143 | current_macro = None; |
141 | macro_rules_highlighter = MacroRulesHighlighter::default(); | 144 | macro_highlighter = MacroHighlighter::default(); |
142 | } | 145 | } |
143 | _ => (), | 146 | _ => (), |
144 | } | 147 | } |
@@ -164,9 +167,9 @@ fn traverse( | |||
164 | 167 | ||
165 | let range = element.text_range(); | 168 | let range = element.text_range(); |
166 | 169 | ||
167 | if current_macro_rules.is_some() { | 170 | if current_macro.is_some() { |
168 | if let Some(tok) = element.as_token() { | 171 | if let Some(tok) = element.as_token() { |
169 | macro_rules_highlighter.advance(tok); | 172 | macro_highlighter.advance(tok); |
170 | } | 173 | } |
171 | } | 174 | } |
172 | 175 | ||
@@ -200,7 +203,7 @@ fn traverse( | |||
200 | } | 203 | } |
201 | } | 204 | } |
202 | 205 | ||
203 | if let Some(_) = macro_rules_highlighter.highlight(element_to_highlight.clone()) { | 206 | if let Some(_) = macro_highlighter.highlight(element_to_highlight.clone()) { |
204 | continue; | 207 | continue; |
205 | } | 208 | } |
206 | 209 | ||
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..04fafd244 100644 --- a/crates/ide/src/syntax_highlighting/inject.rs +++ b/crates/ide/src/syntax_highlighting/inject.rs | |||
@@ -1,17 +1,18 @@ | |||
1 | //! "Recursive" Syntax highlighting for code in doctests and fixtures. | 1 | //! "Recursive" Syntax highlighting for code in doctests and fixtures. |
2 | 2 | ||
3 | use std::{mem, ops::Range}; | 3 | use std::mem; |
4 | 4 | ||
5 | use either::Either; | 5 | use either::Either; |
6 | use hir::{HasAttrs, InFile, Semantics}; | 6 | use hir::{InFile, Semantics}; |
7 | use ide_db::{call_info::ActiveParameter, defs::Definition, SymbolKind}; | 7 | use ide_db::{call_info::ActiveParameter, SymbolKind}; |
8 | use syntax::{ | 8 | use syntax::{ |
9 | ast::{self, AstNode}, | 9 | ast::{self, AstNode}, |
10 | match_ast, AstToken, NodeOrToken, SyntaxNode, SyntaxToken, TextRange, TextSize, | 10 | AstToken, NodeOrToken, SyntaxNode, SyntaxToken, TextRange, TextSize, |
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::{doc_attributes, 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}; |
@@ -89,34 +90,6 @@ const RUSTDOC_FENCE_TOKENS: &[&'static str] = &[ | |||
89 | "edition2021", | 90 | "edition2021", |
90 | ]; | 91 | ]; |
91 | 92 | ||
92 | fn doc_attributes<'node>( | ||
93 | sema: &Semantics<RootDatabase>, | ||
94 | node: &'node SyntaxNode, | ||
95 | ) -> Option<(hir::AttrsWithOwner, Definition)> { | ||
96 | match_ast! { | ||
97 | match node { | ||
98 | ast::SourceFile(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::ModuleDef(hir::ModuleDef::Module(def)))), | ||
99 | ast::Module(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::ModuleDef(hir::ModuleDef::Module(def)))), | ||
100 | ast::Fn(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::ModuleDef(hir::ModuleDef::Function(def)))), | ||
101 | ast::Struct(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::ModuleDef(hir::ModuleDef::Adt(hir::Adt::Struct(def))))), | ||
102 | ast::Union(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::ModuleDef(hir::ModuleDef::Adt(hir::Adt::Union(def))))), | ||
103 | ast::Enum(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::ModuleDef(hir::ModuleDef::Adt(hir::Adt::Enum(def))))), | ||
104 | ast::Variant(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::ModuleDef(hir::ModuleDef::Variant(def)))), | ||
105 | ast::Trait(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::ModuleDef(hir::ModuleDef::Trait(def)))), | ||
106 | ast::Static(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::ModuleDef(hir::ModuleDef::Static(def)))), | ||
107 | ast::Const(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::ModuleDef(hir::ModuleDef::Const(def)))), | ||
108 | ast::TypeAlias(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::ModuleDef(hir::ModuleDef::TypeAlias(def)))), | ||
109 | 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::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::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))), | ||
115 | _ => return None | ||
116 | } | ||
117 | } | ||
118 | } | ||
119 | |||
120 | /// Injection of syntax highlighting of doctests. | 93 | /// Injection of syntax highlighting of doctests. |
121 | pub(super) fn doc_comment( | 94 | pub(super) fn doc_comment( |
122 | hl: &mut Highlights, | 95 | hl: &mut Highlights, |
@@ -139,8 +112,28 @@ pub(super) fn doc_comment( | |||
139 | // Replace the original, line-spanning comment ranges by new, only comment-prefix | 112 | // Replace the original, line-spanning comment ranges by new, only comment-prefix |
140 | // spanning comment ranges. | 113 | // spanning comment ranges. |
141 | let mut new_comments = Vec::new(); | 114 | let mut new_comments = Vec::new(); |
142 | let mut intra_doc_links = Vec::new(); | ||
143 | let mut string; | 115 | let mut string; |
116 | |||
117 | if let Some((docs, doc_mapping)) = attributes.docs_with_rangemap(sema.db) { | ||
118 | extract_definitions_from_markdown(docs.as_str()) | ||
119 | .into_iter() | ||
120 | .filter_map(|(range, link, ns)| { | ||
121 | let def = resolve_doc_path_for_def(sema.db, def, &link, ns)?; | ||
122 | let InFile { file_id, value: range } = doc_mapping.map(range)?; | ||
123 | (file_id == node.file_id).then(|| (range, def)) | ||
124 | }) | ||
125 | .for_each(|(range, def)| { | ||
126 | hl.add(HlRange { | ||
127 | range, | ||
128 | highlight: module_def_to_hl_tag(def) | ||
129 | | HlMod::Documentation | ||
130 | | HlMod::Injected | ||
131 | | HlMod::IntraDocLink, | ||
132 | binding_hash: None, | ||
133 | }) | ||
134 | }); | ||
135 | } | ||
136 | |||
144 | for attr in attributes.by_key("doc").attrs() { | 137 | for attr in attributes.by_key("doc").attrs() { |
145 | let InFile { file_id, value: src } = attrs_source_map.source_of(&attr); | 138 | let InFile { file_id, value: src } = attrs_source_map.source_of(&attr); |
146 | if file_id != node.file_id { | 139 | if file_id != node.file_id { |
@@ -186,25 +179,7 @@ pub(super) fn doc_comment( | |||
186 | is_doctest = is_codeblock && is_rust; | 179 | is_doctest = is_codeblock && is_rust; |
187 | continue; | 180 | continue; |
188 | } | 181 | } |
189 | None if !is_doctest => { | 182 | None if !is_doctest => continue, |
190 | intra_doc_links.extend( | ||
191 | extract_definitions_from_markdown(line) | ||
192 | .into_iter() | ||
193 | .filter_map(|(range, link, ns)| { | ||
194 | Some(range).zip(validate_intra_doc_link(sema.db, &def, &link, ns)) | ||
195 | }) | ||
196 | .map(|(Range { start, end }, def)| { | ||
197 | ( | ||
198 | def, | ||
199 | TextRange::at( | ||
200 | prev_range_start + TextSize::from(start as u32), | ||
201 | TextSize::from((end - start) as u32), | ||
202 | ), | ||
203 | ) | ||
204 | }), | ||
205 | ); | ||
206 | continue; | ||
207 | } | ||
208 | None => (), | 183 | None => (), |
209 | } | 184 | } |
210 | 185 | ||
@@ -223,17 +198,6 @@ pub(super) fn doc_comment( | |||
223 | } | 198 | } |
224 | } | 199 | } |
225 | 200 | ||
226 | for (def, range) in intra_doc_links { | ||
227 | hl.add(HlRange { | ||
228 | range, | ||
229 | highlight: module_def_to_hl_tag(def) | ||
230 | | HlMod::Documentation | ||
231 | | HlMod::Injected | ||
232 | | HlMod::IntraDocLink, | ||
233 | binding_hash: None, | ||
234 | }); | ||
235 | } | ||
236 | |||
237 | if new_comments.is_empty() { | 201 | if new_comments.is_empty() { |
238 | return; // no need to run an analysis on an empty file | 202 | return; // no need to run an analysis on an empty file |
239 | } | 203 | } |
@@ -284,33 +248,6 @@ fn find_doc_string_in_attr(attr: &hir::Attr, it: &ast::Attr) -> Option<ast::Stri | |||
284 | } | 248 | } |
285 | } | 249 | } |
286 | 250 | ||
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 { | 251 | fn module_def_to_hl_tag(def: hir::ModuleDef) -> HlTag { |
315 | let symbol = match def { | 252 | let symbol = match def { |
316 | hir::ModuleDef::Module(_) => SymbolKind::Module, | 253 | 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_doctest.html b/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html index 045162eb8..b6d1cac4e 100644 --- a/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html +++ b/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html | |||
@@ -100,10 +100,18 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd | |||
100 | <span class="brace">}</span> | 100 | <span class="brace">}</span> |
101 | 101 | ||
102 | <span class="comment documentation">/// </span><span class="struct documentation intra_doc_link injected">[`Foo`](Foo)</span><span class="comment documentation"> is a struct</span> | 102 | <span class="comment documentation">/// </span><span class="struct documentation intra_doc_link injected">[`Foo`](Foo)</span><span class="comment documentation"> is a struct</span> |
103 | <span class="comment documentation">/// </span><span class="function documentation intra_doc_link injected">[`all_the_links`](all_the_links)</span><span class="comment documentation"> is this function</span> | 103 | <span class="comment documentation">/// This function is > </span><span class="function documentation intra_doc_link injected">[`all_the_links`](all_the_links)</span><span class="comment documentation"> <</span> |
104 | <span class="comment documentation">/// [`noop`](noop) is a macro below</span> | 104 | <span class="comment documentation">/// [`noop`](noop) is a macro below</span> |
105 | <span class="comment documentation">/// </span><span class="struct documentation intra_doc_link injected">[`Item`]</span><span class="comment documentation"> is a struct in the module </span><span class="module documentation intra_doc_link injected">[`module`]</span> | ||
106 | <span class="comment documentation">///</span> | ||
107 | <span class="comment documentation">/// [`Item`]: module::Item</span> | ||
108 | <span class="comment documentation">/// [mix_and_match]: ThisShouldntResolve</span> | ||
105 | <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration">all_the_links</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span> | 109 | <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration">all_the_links</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span> |
106 | 110 | ||
111 | <span class="keyword">pub</span> <span class="keyword">mod</span> <span class="module declaration">module</span> <span class="brace">{</span> | ||
112 | <span class="keyword">pub</span> <span class="keyword">struct</span> <span class="struct declaration">Item</span><span class="semicolon">;</span> | ||
113 | <span class="brace">}</span> | ||
114 | |||
107 | <span class="comment documentation">/// ```</span> | 115 | <span class="comment documentation">/// ```</span> |
108 | <span class="comment documentation">/// </span><span class="macro injected">noop!</span><span class="parenthesis injected">(</span><span class="numeric_literal injected">1</span><span class="parenthesis injected">)</span><span class="semicolon injected">;</span> | 116 | <span class="comment documentation">/// </span><span class="macro injected">noop!</span><span class="parenthesis injected">(</span><span class="numeric_literal injected">1</span><span class="parenthesis injected">)</span><span class="semicolon injected">;</span> |
109 | <span class="comment documentation">/// ```</span> | 117 | <span class="comment documentation">/// ```</span> |
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..1b02857ec 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); |
@@ -534,10 +544,18 @@ impl Foo { | |||
534 | } | 544 | } |
535 | 545 | ||
536 | /// [`Foo`](Foo) is a struct | 546 | /// [`Foo`](Foo) is a struct |
537 | /// [`all_the_links`](all_the_links) is this function | 547 | /// This function is > [`all_the_links`](all_the_links) < |
538 | /// [`noop`](noop) is a macro below | 548 | /// [`noop`](noop) is a macro below |
549 | /// [`Item`] is a struct in the module [`module`] | ||
550 | /// | ||
551 | /// [`Item`]: module::Item | ||
552 | /// [mix_and_match]: ThisShouldntResolve | ||
539 | pub fn all_the_links() {} | 553 | pub fn all_the_links() {} |
540 | 554 | ||
555 | pub mod module { | ||
556 | pub struct Item; | ||
557 | } | ||
558 | |||
541 | /// ``` | 559 | /// ``` |
542 | /// noop!(1); | 560 | /// noop!(1); |
543 | /// ``` | 561 | /// ``` |
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.rs b/crates/ide/src/typing.rs index e10b7d98e..11408d445 100644 --- a/crates/ide/src/typing.rs +++ b/crates/ide/src/typing.rs | |||
@@ -49,6 +49,9 @@ pub(crate) const TRIGGER_CHARS: &str = ".=>"; | |||
49 | // ---- | 49 | // ---- |
50 | // "editor.formatOnType": true, | 50 | // "editor.formatOnType": true, |
51 | // ---- | 51 | // ---- |
52 | // | ||
53 | // image::https://user-images.githubusercontent.com/48062697/113166163-69758500-923a-11eb-81ee-eb33ec380399.gif[] | ||
54 | // image::https://user-images.githubusercontent.com/48062697/113171066-105c2000-923f-11eb-87ab-f4a263346567.gif[] | ||
52 | pub(crate) fn on_char_typed( | 55 | pub(crate) fn on_char_typed( |
53 | db: &RootDatabase, | 56 | db: &RootDatabase, |
54 | position: FilePosition, | 57 | position: FilePosition, |
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 | } |