use std::collections::BTreeMap;
use std::path;
use std::path::{Path, PathBuf};
use crate::directives::directive_options::{DirectiveOption, DirectiveVisibility, IndexEntryType};
use crate::directives::{
extract_doc_from_attrs,
order_items,
Directive,
FileDirectives,
UseDirective,
};
use crate::formats::{Format, MdContent, MdDirective, RstContent, RstDirective};
use crate::utils::{FileTopLevelDirective, SourceCodeFile};
use crate::RuntimeConfiguration;
#[derive(Clone, Debug)]
pub struct CrateDirective {
pub(crate) name: String,
pub(crate) options: Vec<DirectiveOption>,
pub(crate) content: Vec<String>,
pub(crate) doc_file: PathBuf,
pub(crate) file_directives: FileDirectives,
}
impl CrateDirective {
const DIRECTIVE_NAME: &'static str = "crate";
pub(crate) fn new(rc: &RuntimeConfiguration, source_code_file: &SourceCodeFile) -> Self {
let ast = source_code_file.ast();
let file_directives =
FileDirectives::from_ast_items(rc, &ast.items, &source_code_file.to_parent_directory());
CrateDirective {
name: source_code_file.item.clone(),
options: vec![DirectiveOption::Index(IndexEntryType::Normal)],
content: extract_doc_from_attrs(&ast.attrs),
doc_file: rc.get_doc_file_name(&source_code_file.path),
file_directives,
}
}
pub(crate) fn filter_items(&mut self, max_visibility: &DirectiveVisibility) -> Vec<Directive> {
self.identify_impl_parents();
let mut excluded_items = vec![];
self.file_directives.modules.retain_mut(|module| {
excluded_items.extend(module.filter_items(max_visibility));
module.directive_visibility() <= max_visibility
});
let mut reexports = vec![];
for use_ in &mut self.file_directives.uses {
if use_.reexport.is_some() && use_.directive_visibility() <= max_visibility {
reexports.push(use_)
}
}
let mut not_documented = vec![];
let mut inlined = BTreeMap::new();
'item_loop: for mut item in excluded_items {
for reexport in &mut reexports {
if reexport.contains(item.name()) {
if !matches!(item, Directive::Impl(_)) {
let (k, v) = reexport.inline(item.name()).unwrap();
inlined.insert(k, v);
}
item.change_parent(&self.name);
item.add_content(reexport.content.clone());
self.file_directives.items.push(item);
continue 'item_loop;
}
}
not_documented.push(item);
}
self.file_directives
.uses
.push(UseDirective::for_use_paths(inlined));
not_documented
}
pub(crate) fn identify_impl_parents(&mut self) {
let mut impls = vec![];
impls.append(&mut self.file_directives.impls);
for module in &mut self.file_directives.modules {
impls.extend(module.collect_impls());
}
self.file_directives.claim_impls(&self.name, impls);
}
}
impl RstDirective for CrateDirective {
fn get_rst_text(self, level: usize, max_visibility: &DirectiveVisibility) -> Vec<String> {
let content_indent = Self::make_content_indent(level);
let mut text =
Self::make_rst_header(Self::DIRECTIVE_NAME, &self.name, &self.options, level);
text.extend(self.content.get_rst_text(&content_indent));
let doc_file_parent = self.doc_file.parent().unwrap().to_str().unwrap();
text.extend(Self::make_rst_toctree(
&content_indent,
"Modules",
Some(1),
self.file_directives.modules.iter().map(|m| {
m.doc_file
.to_str()
.unwrap()
.trim_start_matches(doc_file_parent)
.trim_start_matches(path::MAIN_SEPARATOR)
}),
));
let mut reexports = vec![];
for use_ in self.file_directives.uses {
if use_.reexport.is_some() && use_.directive_visibility() <= max_visibility {
for path in use_.paths.values() {
reexports.push((path.clone(), use_.content.clone()));
}
}
text.extend(use_.get_rst_text(level + 1, max_visibility));
}
text.extend(Self::make_rst_list(
&content_indent,
"Re-exports",
&reexports,
));
for (name, items) in order_items(self.file_directives.items) {
text.extend(Self::make_rst_section(name, level, items, max_visibility));
}
text
}
}
impl MdDirective for CrateDirective {
fn get_md_text(self, fence_size: usize, max_visibility: &DirectiveVisibility) -> Vec<String> {
let fence = Self::make_fence(fence_size);
let mut text =
Self::make_md_header(Self::DIRECTIVE_NAME, &self.name, &self.options, &fence);
text.extend(self.content.get_md_text());
let doc_file_parent = self.doc_file.parent().unwrap().to_str().unwrap();
text.extend(Self::make_md_toctree(
3,
"Modules",
Some(1),
self.file_directives.modules.iter().map(|m| {
m.doc_file
.to_str()
.unwrap()
.trim_start_matches(doc_file_parent)
.trim_start_matches(path::MAIN_SEPARATOR)
}),
));
let mut reexports = vec![];
for use_ in self.file_directives.uses {
if use_.reexport.is_some() && use_.directive_visibility() <= max_visibility {
for path in use_.paths.values() {
reexports.push((path.clone(), use_.content.clone()));
}
}
text.extend(use_.get_md_text(3, max_visibility));
}
text.extend(Self::make_md_list(3, "Re-exports", &reexports));
for (name, items) in order_items(self.file_directives.items) {
text.extend(Self::make_md_section(
name,
fence_size,
items,
max_visibility,
));
}
text
}
fn fence_size(&self) -> usize {
Self::calc_fence_size(&self.file_directives.items)
}
}
impl FileTopLevelDirective for CrateDirective {
fn get_doc_file(&self) -> &Path {
&self.doc_file
}
fn get_text(self, format: &Format, max_visibility: &DirectiveVisibility) -> Vec<String> {
let mut text = format.make_title(&format!("Crate {}", format.make_inline_code(&self.name)));
text.extend(format.format_directive(self, max_visibility));
text
}
}