Implement basic doc item data structures
This patch adds the doc and source module with the basic data structures for the documentation items: - A Source loads the documentation items from e. g. the file system. - The documentation items (modules, traits, etc.) are grouped by crates. It also adds a simple Source implementation, DirSource, that reads the data from a local directory.
This commit is contained in:
parent
11b6d27b8a
commit
e6f299635e
48
src/doc.rs
Normal file
48
src/doc.rs
Normal file
@ -0,0 +1,48 @@
|
||||
// SPDX-FileCopyrightText: 2020 Robin Krahl <robin.krahl@ireas.org>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
use std::path;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct Crate {
|
||||
pub name: String,
|
||||
pub path: path::PathBuf,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct Item {
|
||||
pub path: path::PathBuf,
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct Doc {
|
||||
pub title: String,
|
||||
pub description: Option<String>,
|
||||
pub definition: Option<String>,
|
||||
}
|
||||
|
||||
impl Crate {
|
||||
pub fn new(name: String, path: path::PathBuf) -> Self {
|
||||
Crate { name, path }
|
||||
}
|
||||
|
||||
pub fn find_item(&self, _item: &[&str]) -> anyhow::Result<Option<Item>> {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
impl Item {
|
||||
pub fn load_doc(&self) -> anyhow::Result<Doc> {
|
||||
Ok(Doc::new(self.name.clone()))
|
||||
}
|
||||
}
|
||||
|
||||
impl Doc {
|
||||
pub fn new(title: String) -> Self {
|
||||
Self {
|
||||
title,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
}
|
39
src/main.rs
39
src/main.rs
@ -1,6 +1,9 @@
|
||||
// SPDX-FileCopyrightText: 2020 Robin Krahl <robin.krahl@ireas.org>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
mod doc;
|
||||
mod source;
|
||||
|
||||
use structopt::StructOpt;
|
||||
|
||||
/// Command-line interface for rustdoc documentation
|
||||
@ -19,6 +22,40 @@ struct Opt {
|
||||
|
||||
fn main() -> anyhow::Result<()> {
|
||||
let opt = Opt::from_args();
|
||||
println!("Documentation for {}", &opt.keyword);
|
||||
|
||||
let sources = load_sources(&opt.source_paths)?;
|
||||
let doc = find_doc(&sources, &opt.keyword)?;
|
||||
println!("{}", doc.title);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn load_sources(sources: &[String]) -> anyhow::Result<Vec<Box<dyn source::Source>>> {
|
||||
let mut vec: Vec<Box<dyn source::Source>> = Vec::new();
|
||||
for s in sources {
|
||||
vec.push(source::get_source(s)?);
|
||||
}
|
||||
// The last source should be searched first --> reverse source vector
|
||||
vec.reverse();
|
||||
Ok(vec)
|
||||
}
|
||||
|
||||
fn find_doc(sources: &[Box<dyn source::Source>], keyword: &str) -> anyhow::Result<doc::Doc> {
|
||||
use anyhow::Context;
|
||||
|
||||
let parts: Vec<&str> = keyword.split("::").collect();
|
||||
let crate_ = find_crate(sources, parts[0])?;
|
||||
let item = crate_
|
||||
.find_item(&parts[1..])?
|
||||
.with_context(|| format!("Could not find the item {}", keyword))?;
|
||||
item.load_doc()
|
||||
}
|
||||
|
||||
fn find_crate(sources: &[Box<dyn source::Source>], name: &str) -> anyhow::Result<doc::Crate> {
|
||||
use anyhow::Context;
|
||||
|
||||
sources
|
||||
.iter()
|
||||
.filter_map(|s| s.find_crate(name))
|
||||
.next()
|
||||
.with_context(|| format!("Could not find the crate {}", name))
|
||||
}
|
||||
|
82
src/source.rs
Normal file
82
src/source.rs
Normal file
@ -0,0 +1,82 @@
|
||||
// SPDX-FileCopyrightText: 2020 Robin Krahl <robin.krahl@ireas.org>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
//! Handles documentation sources, for example local directories.
|
||||
|
||||
use std::path;
|
||||
|
||||
use anyhow::anyhow;
|
||||
|
||||
use crate::doc;
|
||||
|
||||
/// Documentation source, for example a local directory.
|
||||
pub trait Source {
|
||||
fn find_crate(&self, name: &str) -> Option<doc::Crate>;
|
||||
}
|
||||
|
||||
/// Local directory containing documentation data.
|
||||
///
|
||||
/// The directory must contain documentation for one or more crates in subdirectories. Suitable
|
||||
/// directories are the `doc` directory generated by `cargo doc` or the root directory of the Rust
|
||||
/// documentation.
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct DirSource {
|
||||
path: path::PathBuf,
|
||||
}
|
||||
|
||||
impl DirSource {
|
||||
fn new(path: path::PathBuf) -> Self {
|
||||
Self { path }
|
||||
}
|
||||
}
|
||||
|
||||
impl Source for DirSource {
|
||||
fn find_crate(&self, name: &str) -> Option<doc::Crate> {
|
||||
let crate_path = self.path.join(name);
|
||||
if crate_path.join("all.html").is_file() {
|
||||
Some(doc::Crate::new(name.to_owned(), crate_path))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_source<P: AsRef<path::Path>>(path: P) -> anyhow::Result<Box<dyn Source>> {
|
||||
if path.as_ref().is_dir() {
|
||||
Ok(Box::new(DirSource::new(path.as_ref().to_path_buf())))
|
||||
} else {
|
||||
Err(anyhow!(
|
||||
"This source is not supported: {}",
|
||||
path.as_ref().display()
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::path;
|
||||
|
||||
use super::Source;
|
||||
|
||||
#[test]
|
||||
fn dir_source_find_crate() {
|
||||
fn assert_crate(source: &dyn super::Source, path: &path::PathBuf, name: &str) {
|
||||
assert_eq!(
|
||||
source.find_crate(name),
|
||||
Some(super::doc::Crate::new(name.to_owned(), path.join(name)))
|
||||
);
|
||||
}
|
||||
|
||||
let doc = path::PathBuf::from("./target/doc");
|
||||
assert!(
|
||||
doc.is_dir(),
|
||||
"You have to run `cargo doc` before running this test case."
|
||||
);
|
||||
|
||||
let source = super::DirSource::new(doc.clone());
|
||||
|
||||
assert_crate(&source, &doc, "clap");
|
||||
assert_crate(&source, &doc, "lazy_static");
|
||||
assert_eq!(source.find_crate("lazystatic"), None);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user