diff options
author | Lukas Wirth <[email protected]> | 2021-03-30 17:27:16 +0100 |
---|---|---|
committer | Lukas Wirth <[email protected]> | 2021-03-30 17:27:16 +0100 |
commit | bb56b7a75cfae8297535d55fbddbee9875cbc756 (patch) | |
tree | d367c18dddc65d4442679680ea728f5b06280ea5 /crates/ide/src/doc_links.rs | |
parent | 9a327311e4a9b9102528751e052c63266c00c6bd (diff) |
Use new new docs string source mapping in goto_def and hover
Diffstat (limited to 'crates/ide/src/doc_links.rs')
-rw-r--r-- | crates/ide/src/doc_links.rs | 117 |
1 files changed, 43 insertions, 74 deletions
diff --git a/crates/ide/src/doc_links.rs b/crates/ide/src/doc_links.rs index 69442278b..9a9a41113 100644 --- a/crates/ide/src/doc_links.rs +++ b/crates/ide/src/doc_links.rs | |||
@@ -15,10 +15,7 @@ use ide_db::{ | |||
15 | defs::{Definition, NameClass, NameRefClass}, | 15 | defs::{Definition, NameClass, NameRefClass}, |
16 | RootDatabase, | 16 | RootDatabase, |
17 | }; | 17 | }; |
18 | use syntax::{ | 18 | use syntax::{ast, match_ast, AstNode, SyntaxKind::*, SyntaxNode, SyntaxToken, TokenAtOffset, T}; |
19 | ast, match_ast, AstNode, AstToken, SyntaxKind::*, SyntaxNode, SyntaxToken, TextRange, TextSize, | ||
20 | TokenAtOffset, T, | ||
21 | }; | ||
22 | 19 | ||
23 | use crate::{FilePosition, Semantics}; | 20 | use crate::{FilePosition, Semantics}; |
24 | 21 | ||
@@ -119,77 +116,22 @@ pub(crate) fn external_docs( | |||
119 | pub(crate) fn extract_definitions_from_markdown( | 116 | pub(crate) fn extract_definitions_from_markdown( |
120 | markdown: &str, | 117 | markdown: &str, |
121 | ) -> Vec<(Range<usize>, String, Option<hir::Namespace>)> { | 118 | ) -> Vec<(Range<usize>, String, Option<hir::Namespace>)> { |
122 | extract_definitions_from_markdown_(markdown, &mut broken_link_clone_cb).collect() | 119 | Parser::new_with_broken_link_callback( |
123 | } | 120 | markdown, |
124 | 121 | Options::empty(), | |
125 | fn extract_definitions_from_markdown_<'a>( | 122 | Some(&mut broken_link_clone_cb), |
126 | markdown: &'a str, | 123 | ) |
127 | cb: &'a mut dyn FnMut(BrokenLink<'_>) -> Option<(CowStr<'a>, CowStr<'a>)>, | 124 | .into_offset_iter() |
128 | ) -> impl Iterator<Item = (Range<usize>, String, Option<hir::Namespace>)> + 'a { | 125 | .filter_map(|(event, range)| { |
129 | Parser::new_with_broken_link_callback(markdown, Options::empty(), Some(cb)) | 126 | if let Event::Start(Tag::Link(_, target, title)) = event { |
130 | .into_offset_iter() | 127 | let link = if target.is_empty() { title } else { target }; |
131 | .filter_map(|(event, range)| { | 128 | let (link, ns) = parse_intra_doc_link(&link); |
132 | if let Event::Start(Tag::Link(_, target, title)) = event { | 129 | Some((range, link.to_string(), ns)) |
133 | let link = if target.is_empty() { title } else { target }; | 130 | } else { |
134 | let (link, ns) = parse_intra_doc_link(&link); | 131 | None |
135 | Some((range, link.to_string(), ns)) | ||
136 | } else { | ||
137 | None | ||
138 | } | ||
139 | }) | ||
140 | } | ||
141 | |||
142 | /// Extracts a link from a comment at the given position returning the spanning range, link and | ||
143 | /// optionally it's namespace. | ||
144 | pub(crate) fn extract_positioned_link_from_comment( | ||
145 | position: TextSize, | ||
146 | comment: &ast::Comment, | ||
147 | docs: hir::Documentation, | ||
148 | ) -> Option<(TextRange, String, Option<hir::Namespace>)> { | ||
149 | let doc_comment = comment.doc_comment()?.to_string() + "\n" + docs.as_str(); | ||
150 | let comment_start = | ||
151 | comment.syntax().text_range().start() + TextSize::from(comment.prefix().len() as u32); | ||
152 | let len = comment.syntax().text_range().len().into(); | ||
153 | let mut cb = broken_link_clone_cb; | ||
154 | // because pulldown_cmarks lifetimes are wrong we gotta dance around a few temporaries here | ||
155 | let res = extract_definitions_from_markdown_(&doc_comment, &mut cb) | ||
156 | .take_while(|&(Range { end, .. }, ..)| end < len) | ||
157 | .find_map(|(Range { start, end }, def_link, ns)| { | ||
158 | let range = TextRange::at( | ||
159 | comment_start + TextSize::from(start as u32), | ||
160 | TextSize::from((end - start) as u32), | ||
161 | ); | ||
162 | range.contains(position).then(|| (range, def_link, ns)) | ||
163 | }); | ||
164 | res | ||
165 | } | ||
166 | |||
167 | /// Turns a syntax node into it's [`Definition`] if it can hold docs. | ||
168 | pub(crate) fn doc_owner_to_def( | ||
169 | sema: &Semantics<RootDatabase>, | ||
170 | item: &SyntaxNode, | ||
171 | ) -> Option<Definition> { | ||
172 | let res: hir::ModuleDef = match_ast! { | ||
173 | match item { | ||
174 | ast::SourceFile(_it) => sema.scope(item).module()?.into(), | ||
175 | ast::Fn(it) => sema.to_def(&it)?.into(), | ||
176 | ast::Struct(it) => sema.to_def(&it)?.into(), | ||
177 | ast::Enum(it) => sema.to_def(&it)?.into(), | ||
178 | ast::Union(it) => sema.to_def(&it)?.into(), | ||
179 | ast::Trait(it) => sema.to_def(&it)?.into(), | ||
180 | ast::Const(it) => sema.to_def(&it)?.into(), | ||
181 | ast::Static(it) => sema.to_def(&it)?.into(), | ||
182 | ast::TypeAlias(it) => sema.to_def(&it)?.into(), | ||
183 | ast::Variant(it) => sema.to_def(&it)?.into(), | ||
184 | ast::Trait(it) => sema.to_def(&it)?.into(), | ||
185 | ast::Impl(it) => return sema.to_def(&it).map(Definition::SelfType), | ||
186 | ast::Macro(it) => return sema.to_def(&it).map(Definition::Macro), | ||
187 | ast::TupleField(it) => return sema.to_def(&it).map(Definition::Field), | ||
188 | ast::RecordField(it) => return sema.to_def(&it).map(Definition::Field), | ||
189 | _ => return None, | ||
190 | } | 132 | } |
191 | }; | 133 | }) |
192 | Some(Definition::ModuleDef(res)) | 134 | .collect() |
193 | } | 135 | } |
194 | 136 | ||
195 | pub(crate) fn resolve_doc_path_for_def( | 137 | pub(crate) fn resolve_doc_path_for_def( |
@@ -219,6 +161,33 @@ pub(crate) fn resolve_doc_path_for_def( | |||
219 | } | 161 | } |
220 | } | 162 | } |
221 | 163 | ||
164 | pub(crate) fn doc_attributes( | ||
165 | sema: &Semantics<RootDatabase>, | ||
166 | node: &SyntaxNode, | ||
167 | ) -> Option<(hir::AttrsWithOwner, Definition)> { | ||
168 | match_ast! { | ||
169 | match node { | ||
170 | ast::SourceFile(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::ModuleDef(hir::ModuleDef::Module(def)))), | ||
171 | ast::Module(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::ModuleDef(hir::ModuleDef::Module(def)))), | ||
172 | ast::Fn(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::ModuleDef(hir::ModuleDef::Function(def)))), | ||
173 | ast::Struct(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::ModuleDef(hir::ModuleDef::Adt(hir::Adt::Struct(def))))), | ||
174 | ast::Union(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::ModuleDef(hir::ModuleDef::Adt(hir::Adt::Union(def))))), | ||
175 | ast::Enum(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::ModuleDef(hir::ModuleDef::Adt(hir::Adt::Enum(def))))), | ||
176 | ast::Variant(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::ModuleDef(hir::ModuleDef::Variant(def)))), | ||
177 | ast::Trait(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::ModuleDef(hir::ModuleDef::Trait(def)))), | ||
178 | ast::Static(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::ModuleDef(hir::ModuleDef::Static(def)))), | ||
179 | ast::Const(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::ModuleDef(hir::ModuleDef::Const(def)))), | ||
180 | ast::TypeAlias(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::ModuleDef(hir::ModuleDef::TypeAlias(def)))), | ||
181 | ast::Impl(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::SelfType(def))), | ||
182 | ast::RecordField(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::Field(def))), | ||
183 | ast::TupleField(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::Field(def))), | ||
184 | ast::Macro(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::Macro(def))), | ||
185 | // ast::Use(it) => sema.to_def(&it).map(|def| (Box::new(it) as _, def.attrs(sema.db))), | ||
186 | _ => return None | ||
187 | } | ||
188 | } | ||
189 | } | ||
190 | |||
222 | fn broken_link_clone_cb<'a, 'b>(link: BrokenLink<'a>) -> Option<(CowStr<'b>, CowStr<'b>)> { | 191 | fn broken_link_clone_cb<'a, 'b>(link: BrokenLink<'a>) -> Option<(CowStr<'b>, CowStr<'b>)> { |
223 | // These allocations are actually unnecessary but the lifetimes on BrokenLinkCallback are wrong | 192 | // These allocations are actually unnecessary but the lifetimes on BrokenLinkCallback are wrong |
224 | // this is fixed in the repo but not on the crates.io release yet | 193 | // this is fixed in the repo but not on the crates.io release yet |