Skip to content

Commit 96cbad9

Browse files
bors[bot]zacps
andauthored
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 <zacmps@gmail.com>
2 parents b4bc346 + b835f06 commit 96cbad9

File tree

12 files changed

+1015
-61
lines changed

12 files changed

+1015
-61
lines changed

Cargo.lock

Lines changed: 45 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/hir/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ rustc-hash = "1.1.0"
1515
either = "1.5.3"
1616
arrayvec = "0.5.1"
1717
itertools = "0.9.0"
18+
url = "2.1.1"
1819

1920
stdx = { path = "../stdx", version = "0.0.0" }
2021
syntax = { path = "../syntax", version = "0.0.0" }
@@ -23,3 +24,4 @@ profile = { path = "../profile", version = "0.0.0" }
2324
hir_expand = { path = "../hir_expand", version = "0.0.0" }
2425
hir_def = { path = "../hir_def", version = "0.0.0" }
2526
hir_ty = { path = "../hir_ty", version = "0.0.0" }
27+
tt = { path = "../tt", version = "0.0.0" }

crates/hir/src/code_model.rs

Lines changed: 101 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ use hir_def::{
2020
type_ref::{Mutability, TypeRef},
2121
AdtId, AssocContainerId, ConstId, DefWithBodyId, EnumId, FunctionId, GenericDefId, HasModule,
2222
ImplId, LocalEnumVariantId, LocalFieldId, LocalModuleId, Lookup, ModuleId, StaticId, StructId,
23-
TraitId, TypeAliasId, TypeParamId, UnionId,
23+
TraitId, TypeAliasId, TypeParamId, UnionId, VariantId,
2424
};
2525
use hir_expand::{
2626
diagnostics::DiagnosticSink,
@@ -39,9 +39,11 @@ use syntax::{
3939
ast::{self, AttrsOwner, NameOwner},
4040
AstNode, SmolStr,
4141
};
42+
use tt::{Ident, Leaf, Literal, TokenTree};
4243

4344
use crate::{
4445
db::{DefDatabase, HirDatabase},
46+
doc_links::Resolvable,
4547
has_source::HasSource,
4648
HirDisplay, InFile, Name,
4749
};
@@ -122,6 +124,31 @@ impl Crate {
122124
pub fn all(db: &dyn HirDatabase) -> Vec<Crate> {
123125
db.crate_graph().iter().map(|id| Crate { id }).collect()
124126
}
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+
}
125152
}
126153

127154
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
@@ -198,7 +225,6 @@ impl ModuleDef {
198225
ModuleDef::Function(it) => Some(it.name(db)),
199226
ModuleDef::EnumVariant(it) => Some(it.name(db)),
200227
ModuleDef::TypeAlias(it) => Some(it.name(db)),
201-
202228
ModuleDef::Module(it) => it.name(db),
203229
ModuleDef::Const(it) => it.name(db),
204230
ModuleDef::Static(it) => it.name(db),
@@ -1771,3 +1797,76 @@ pub trait HasVisibility {
17711797
vis.is_visible_from(db.upcast(), module.id)
17721798
}
17731799
}
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+
}

0 commit comments

Comments
 (0)