Respect item type in documentation lookup

Sometimes, there might be multiple items with the same name, for example
std::u8 is both a module and a primitive.  Previously, we could not
determine which one Source::load_doc would return.  With this patch, we
add the ty parameter that can be used to filter by the item type.
This commit is contained in:
Robin Krahl 2020-08-18 21:43:37 +02:00
parent c672a65d59
commit 5b2003b979
No known key found for this signature in database
GPG Key ID: 8E9B0870524F69D8
4 changed files with 65 additions and 22 deletions

View File

@ -10,6 +10,8 @@ SPDX-License-Identifier: MIT
- Improve handling of different items with same name:
- Add the item type to the item list if multiple matches are found in the
search index.
- Respect the item type when opening the documentation for an item that has
been found in the search index.
## v0.2.0 (2020-08-11)

View File

@ -40,7 +40,13 @@ impl fmt::Display for IndexItem {
if self.description.is_empty() {
write!(f, "{} ({})", &self.name, self.ty.name())
} else {
write!(f, "{} ({}): {}", &self.name, self.ty.name(), &self.description)
write!(
f,
"{} ({}): {}",
&self.name,
self.ty.name(),
&self.description
)
}
}
}

View File

@ -46,7 +46,7 @@ fn main() -> anyhow::Result<()> {
let args = args::Args::load()?;
let sources = load_sources(&args.source_paths, !args.no_default_sources)?;
let doc = if let Some(doc) = find_doc(&sources, &args.keyword)? {
let doc = if let Some(doc) = find_doc(&sources, &args.keyword, None)? {
Some(doc)
} else if !args.no_search {
search_doc(&sources, &args.keyword)?
@ -130,10 +130,11 @@ fn get_sysroot() -> Option<path::PathBuf> {
fn find_doc(
sources: &[Box<dyn source::Source>],
name: &doc::Name,
ty: Option<doc::ItemType>,
) -> anyhow::Result<Option<doc::Doc>> {
let fqn = name.clone().into();
for source in sources {
if let Some(doc) = source.find_doc(&fqn)? {
if let Some(doc) = source.find_doc(&fqn, ty)? {
return Ok(Some(doc));
}
}
@ -150,7 +151,7 @@ fn search_doc(
if let Some(item) = search_item(sources, name)? {
use anyhow::Context;
let doc = find_doc(sources, &item.name)?
let doc = find_doc(sources, &item.name, Some(item.ty))?
.with_context(|| format!("Could not find documentation for {}", &item.name))?;
Ok(Some(doc))
} else {
@ -242,26 +243,32 @@ mod tests {
let path = ensure_docs();
let sources = vec![source::get_source(path).unwrap()];
assert!(super::find_doc(&sources, &"kuchiki".to_owned().into())
assert!(
super::find_doc(&sources, &"kuchiki".to_owned().into(), None)
.unwrap()
.is_some()
);
assert!(
super::find_doc(&sources, &"kuchiki::NodeRef".to_owned().into(), None)
.unwrap()
.is_some()
);
assert!(super::find_doc(
&sources,
&"kuchiki::NodeDataRef::as_node".to_owned().into(),
None
)
.unwrap()
.is_some());
assert!(
super::find_doc(&sources, &"kuchiki::NodeRef".to_owned().into())
super::find_doc(&sources, &"kuchiki::traits".to_owned().into(), None)
.unwrap()
.is_some()
);
assert!(
super::find_doc(&sources, &"kuchiki::NodeDataRef::as_node".to_owned().into())
super::find_doc(&sources, &"kachiki".to_owned().into(), None)
.unwrap()
.is_some()
.is_none()
);
assert!(
super::find_doc(&sources, &"kuchiki::traits".to_owned().into())
.unwrap()
.is_some()
);
assert!(super::find_doc(&sources, &"kachiki".to_owned().into())
.unwrap()
.is_none());
}
}

View File

@ -14,7 +14,11 @@ use crate::parser;
/// Documentation source, for example a local directory.
pub trait Source {
fn find_doc(&self, name: &doc::Fqn) -> anyhow::Result<Option<doc::Doc>>;
fn find_doc(
&self,
name: &doc::Fqn,
ty: Option<doc::ItemType>,
) -> anyhow::Result<Option<doc::Doc>>;
fn load_index(&self) -> anyhow::Result<Option<index::Index>>;
}
@ -34,6 +38,31 @@ impl DirSource {
Self { path }
}
fn find_doc_html(
&self,
path: &path::Path,
name: &doc::Fqn,
ty: Option<doc::ItemType>,
) -> anyhow::Result<Option<doc::Doc>> {
if let Some(ty) = ty {
match ty {
doc::ItemType::Module => self.get_module(&path, name),
doc::ItemType::StructField
| doc::ItemType::Variant
| doc::ItemType::AssocType
| doc::ItemType::AssocConst
| doc::ItemType::Method => self.get_member(&path, name),
_ => self.get_item(&path, name),
}
} else {
self.get_item(&path, name)
.transpose()
.or_else(|| self.get_module(&path, name).transpose())
.or_else(|| self.get_member(&path, name).transpose())
.transpose()
}
}
fn get_crate(&self, name: &str) -> Option<path::PathBuf> {
log::info!(
"Searching crate '{}' in dir source '{}'",
@ -124,19 +153,18 @@ impl DirSource {
}
impl Source for DirSource {
fn find_doc(&self, name: &doc::Fqn) -> anyhow::Result<Option<doc::Doc>> {
fn find_doc(
&self,
name: &doc::Fqn,
ty: Option<doc::ItemType>,
) -> anyhow::Result<Option<doc::Doc>> {
log::info!(
"Searching documentation for '{}' in dir source '{}'",
name,
self.path.display()
);
if let Some(crate_path) = self.get_crate(name.krate()) {
let doc = self
.get_item(&crate_path, name)
.transpose()
.or_else(|| self.get_module(&crate_path, name).transpose())
.or_else(|| self.get_member(&crate_path, name).transpose())
.transpose()?;
let doc = self.find_doc_html(&crate_path, name, ty)?;
if doc.is_some() {
log::info!(
"Found documentation for '{}' in dir source '{}'",