diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2020-08-25 10:11:26 +0100 |
---|---|---|
committer | GitHub <[email protected]> | 2020-08-25 10:11:26 +0100 |
commit | 96cbad9fb5a67dd6cd83fe217716d932300122b5 (patch) | |
tree | b62378abb477d2cdfedf462c1b25b6d9fecc9f75 /crates/hir/src/code_model.rs | |
parent | b4bc34649857cfcf7fcb39b9af02342fb7b8c89e (diff) | |
parent | b835f06cecd2189cb32a431fdb85245fbf53032a (diff) |
Merge #4873
4873: Resolve links in hover documentation r=matklad a=zacps
This PR resolves links in hover documentation. Both the upcoming intra-doc-links style and the old "path-based" style.
## Todo
* [x] More tests
* [ ] Benchmark (Is there an easy way to benchmark this?)
* [x] ~~Resolve issues with the markdown parser/get rid of it~~ Migrate to `pulldown_cmark_to_cmark`
* [x] Reorganise code (Tips appreciated)
---
Fixes #503
Co-authored-by: Zac Pullar-Strecker <[email protected]>
Diffstat (limited to 'crates/hir/src/code_model.rs')
-rw-r--r-- | crates/hir/src/code_model.rs | 103 |
1 files changed, 101 insertions, 2 deletions
diff --git a/crates/hir/src/code_model.rs b/crates/hir/src/code_model.rs index 3d92d0c0d..94dd7f6f5 100644 --- a/crates/hir/src/code_model.rs +++ b/crates/hir/src/code_model.rs | |||
@@ -20,7 +20,7 @@ use hir_def::{ | |||
20 | type_ref::{Mutability, TypeRef}, | 20 | type_ref::{Mutability, TypeRef}, |
21 | AdtId, AssocContainerId, ConstId, DefWithBodyId, EnumId, FunctionId, GenericDefId, HasModule, | 21 | AdtId, AssocContainerId, ConstId, DefWithBodyId, EnumId, FunctionId, GenericDefId, HasModule, |
22 | ImplId, LocalEnumVariantId, LocalFieldId, LocalModuleId, Lookup, ModuleId, StaticId, StructId, | 22 | ImplId, LocalEnumVariantId, LocalFieldId, LocalModuleId, Lookup, ModuleId, StaticId, StructId, |
23 | TraitId, TypeAliasId, TypeParamId, UnionId, | 23 | TraitId, TypeAliasId, TypeParamId, UnionId, VariantId, |
24 | }; | 24 | }; |
25 | use hir_expand::{ | 25 | use hir_expand::{ |
26 | diagnostics::DiagnosticSink, | 26 | diagnostics::DiagnosticSink, |
@@ -39,9 +39,11 @@ use syntax::{ | |||
39 | ast::{self, AttrsOwner, NameOwner}, | 39 | ast::{self, AttrsOwner, NameOwner}, |
40 | AstNode, SmolStr, | 40 | AstNode, SmolStr, |
41 | }; | 41 | }; |
42 | use tt::{Ident, Leaf, Literal, TokenTree}; | ||
42 | 43 | ||
43 | use crate::{ | 44 | use crate::{ |
44 | db::{DefDatabase, HirDatabase}, | 45 | db::{DefDatabase, HirDatabase}, |
46 | doc_links::Resolvable, | ||
45 | has_source::HasSource, | 47 | has_source::HasSource, |
46 | HirDisplay, InFile, Name, | 48 | HirDisplay, InFile, Name, |
47 | }; | 49 | }; |
@@ -122,6 +124,31 @@ impl Crate { | |||
122 | pub fn all(db: &dyn HirDatabase) -> Vec<Crate> { | 124 | pub fn all(db: &dyn HirDatabase) -> Vec<Crate> { |
123 | db.crate_graph().iter().map(|id| Crate { id }).collect() | 125 | db.crate_graph().iter().map(|id| Crate { id }).collect() |
124 | } | 126 | } |
127 | |||
128 | /// Try to get the root URL of the documentation of a crate. | ||
129 | pub fn get_html_root_url(self: &Crate, db: &dyn HirDatabase) -> Option<String> { | ||
130 | // Look for #![doc(html_root_url = "...")] | ||
131 | let attrs = db.attrs(AttrDef::from(self.root_module(db)).into()); | ||
132 | let doc_attr_q = attrs.by_key("doc"); | ||
133 | |||
134 | if !doc_attr_q.exists() { | ||
135 | return None; | ||
136 | } | ||
137 | |||
138 | let doc_url = doc_attr_q.tt_values().map(|tt| { | ||
139 | let name = tt.token_trees.iter() | ||
140 | .skip_while(|tt| !matches!(tt, TokenTree::Leaf(Leaf::Ident(Ident{text: ref ident, ..})) if ident == "html_root_url")) | ||
141 | .skip(2) | ||
142 | .next(); | ||
143 | |||
144 | match name { | ||
145 | Some(TokenTree::Leaf(Leaf::Literal(Literal{ref text, ..}))) => Some(text), | ||
146 | _ => None | ||
147 | } | ||
148 | }).flat_map(|t| t).next(); | ||
149 | |||
150 | doc_url.map(|s| s.trim_matches('"').trim_end_matches("/").to_owned() + "/") | ||
151 | } | ||
125 | } | 152 | } |
126 | 153 | ||
127 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 154 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
@@ -198,7 +225,6 @@ impl ModuleDef { | |||
198 | ModuleDef::Function(it) => Some(it.name(db)), | 225 | ModuleDef::Function(it) => Some(it.name(db)), |
199 | ModuleDef::EnumVariant(it) => Some(it.name(db)), | 226 | ModuleDef::EnumVariant(it) => Some(it.name(db)), |
200 | ModuleDef::TypeAlias(it) => Some(it.name(db)), | 227 | ModuleDef::TypeAlias(it) => Some(it.name(db)), |
201 | |||
202 | ModuleDef::Module(it) => it.name(db), | 228 | ModuleDef::Module(it) => it.name(db), |
203 | ModuleDef::Const(it) => it.name(db), | 229 | ModuleDef::Const(it) => it.name(db), |
204 | ModuleDef::Static(it) => it.name(db), | 230 | ModuleDef::Static(it) => it.name(db), |
@@ -1771,3 +1797,76 @@ pub trait HasVisibility { | |||
1771 | vis.is_visible_from(db.upcast(), module.id) | 1797 | vis.is_visible_from(db.upcast(), module.id) |
1772 | } | 1798 | } |
1773 | } | 1799 | } |
1800 | |||
1801 | impl Resolvable for ModuleDef { | ||
1802 | fn resolver<D: DefDatabase + HirDatabase>(&self, db: &D) -> Option<Resolver> { | ||
1803 | Some(match self { | ||
1804 | ModuleDef::Module(m) => ModuleId::from(m.clone()).resolver(db), | ||
1805 | ModuleDef::Function(f) => FunctionId::from(f.clone()).resolver(db), | ||
1806 | ModuleDef::Adt(adt) => AdtId::from(adt.clone()).resolver(db), | ||
1807 | ModuleDef::EnumVariant(ev) => { | ||
1808 | GenericDefId::from(GenericDef::from(ev.clone())).resolver(db) | ||
1809 | } | ||
1810 | ModuleDef::Const(c) => GenericDefId::from(GenericDef::from(c.clone())).resolver(db), | ||
1811 | ModuleDef::Static(s) => StaticId::from(s.clone()).resolver(db), | ||
1812 | ModuleDef::Trait(t) => TraitId::from(t.clone()).resolver(db), | ||
1813 | ModuleDef::TypeAlias(t) => ModuleId::from(t.module(db)).resolver(db), | ||
1814 | // FIXME: This should be a resolver relative to `std/core` | ||
1815 | ModuleDef::BuiltinType(_t) => None?, | ||
1816 | }) | ||
1817 | } | ||
1818 | |||
1819 | fn try_into_module_def(self) -> Option<ModuleDef> { | ||
1820 | Some(self) | ||
1821 | } | ||
1822 | } | ||
1823 | |||
1824 | impl Resolvable for TypeParam { | ||
1825 | fn resolver<D: DefDatabase + HirDatabase>(&self, db: &D) -> Option<Resolver> { | ||
1826 | Some(Into::<ModuleId>::into(self.module(db)).resolver(db)) | ||
1827 | } | ||
1828 | |||
1829 | fn try_into_module_def(self) -> Option<ModuleDef> { | ||
1830 | None | ||
1831 | } | ||
1832 | } | ||
1833 | |||
1834 | impl Resolvable for MacroDef { | ||
1835 | fn resolver<D: DefDatabase + HirDatabase>(&self, db: &D) -> Option<Resolver> { | ||
1836 | Some(Into::<ModuleId>::into(self.module(db)?).resolver(db)) | ||
1837 | } | ||
1838 | |||
1839 | fn try_into_module_def(self) -> Option<ModuleDef> { | ||
1840 | None | ||
1841 | } | ||
1842 | } | ||
1843 | |||
1844 | impl Resolvable for Field { | ||
1845 | fn resolver<D: DefDatabase + HirDatabase>(&self, db: &D) -> Option<Resolver> { | ||
1846 | Some(Into::<VariantId>::into(Into::<VariantDef>::into(self.parent_def(db))).resolver(db)) | ||
1847 | } | ||
1848 | |||
1849 | fn try_into_module_def(self) -> Option<ModuleDef> { | ||
1850 | None | ||
1851 | } | ||
1852 | } | ||
1853 | |||
1854 | impl Resolvable for ImplDef { | ||
1855 | fn resolver<D: DefDatabase + HirDatabase>(&self, db: &D) -> Option<Resolver> { | ||
1856 | Some(Into::<ModuleId>::into(self.module(db)).resolver(db)) | ||
1857 | } | ||
1858 | |||
1859 | fn try_into_module_def(self) -> Option<ModuleDef> { | ||
1860 | None | ||
1861 | } | ||
1862 | } | ||
1863 | |||
1864 | impl Resolvable for Local { | ||
1865 | fn resolver<D: DefDatabase + HirDatabase>(&self, db: &D) -> Option<Resolver> { | ||
1866 | Some(Into::<ModuleId>::into(self.module(db)).resolver(db)) | ||
1867 | } | ||
1868 | |||
1869 | fn try_into_module_def(self) -> Option<ModuleDef> { | ||
1870 | None | ||
1871 | } | ||
1872 | } | ||