From 5b2003b979dfbf4beaa5c05678a498648a4ef927 Mon Sep 17 00:00:00 2001 From: Robin Krahl Date: Tue, 18 Aug 2020 21:43:37 +0200 Subject: [PATCH] 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. --- CHANGELOG.md | 2 ++ src/index.rs | 8 +++++++- src/main.rs | 33 ++++++++++++++++++++------------- src/source.rs | 44 ++++++++++++++++++++++++++++++++++++-------- 4 files changed, 65 insertions(+), 22 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 40d993d..70c4c6a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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) diff --git a/src/index.rs b/src/index.rs index 9544cfe..e04dd5f 100644 --- a/src/index.rs +++ b/src/index.rs @@ -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 + ) } } } diff --git a/src/main.rs b/src/main.rs index 68eb3ea..7686fce 100644 --- a/src/main.rs +++ b/src/main.rs @@ -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 { fn find_doc( sources: &[Box], name: &doc::Name, + ty: Option, ) -> anyhow::Result> { 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()) - .unwrap() - .is_some()); assert!( - super::find_doc(&sources, &"kuchiki::NodeRef".to_owned().into()) + super::find_doc(&sources, &"kuchiki".to_owned().into(), None) .unwrap() .is_some() ); assert!( - super::find_doc(&sources, &"kuchiki::NodeDataRef::as_node".to_owned().into()) + 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::traits".to_owned().into(), None) .unwrap() .is_some() ); assert!( - super::find_doc(&sources, &"kuchiki::traits".to_owned().into()) + super::find_doc(&sources, &"kachiki".to_owned().into(), None) .unwrap() - .is_some() + .is_none() ); - assert!(super::find_doc(&sources, &"kachiki".to_owned().into()) - .unwrap() - .is_none()); } } diff --git a/src/source.rs b/src/source.rs index 133cab9..260e9f7 100644 --- a/src/source.rs +++ b/src/source.rs @@ -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>; + fn find_doc( + &self, + name: &doc::Fqn, + ty: Option, + ) -> anyhow::Result>; fn load_index(&self) -> anyhow::Result>; } @@ -34,6 +38,31 @@ impl DirSource { Self { path } } + fn find_doc_html( + &self, + path: &path::Path, + name: &doc::Fqn, + ty: Option, + ) -> anyhow::Result> { + 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 { 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> { + fn find_doc( + &self, + name: &doc::Fqn, + ty: Option, + ) -> anyhow::Result> { 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 '{}'",