use std::{fmt, sync::Arc};
use cargo_metadata::PackageName;
use miette::NamedSource;
use pulldown_cmark::Event;
use snafu::{Snafu, ensure};
use crate::{
config::badge::BadgeMap,
source::{SourceFile, SourceFilePath, Spanned},
sync::{
PackageSyncContext,
contents::Contents,
marker::resolve::{ResolveMarkerError, Resolver},
},
};
mod parse;
mod resolve;
mod scan;
const MAGIC: &str = "cargo-sync-rdme";
#[derive(Debug, Snafu, miette::Diagnostic)]
#[snafu(display(
"failed to parse `<!-- {MAGIC} ... -->` markers in markdown file for package `{package}`: {markdown}",
markdown = markdown.workspace_path,
))]
pub(crate) struct ParseMarkersError {
package: PackageName,
markdown: SourceFilePath,
#[source_code]
source_code: NamedSource<Arc<str>>,
#[related]
errors: Vec<ResolveMarkerError>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub(super) enum ResolvedReplaceSpecifier<'a> {
Title,
Badge {
group: Option<&'a str>,
badges: &'a BadgeMap,
},
Rustdoc,
}
impl fmt::Display for ResolvedReplaceSpecifier<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Title => write!(f, "title"),
Self::Badge { group, .. } => {
if let Some(name) = group {
write!(f, "badge:{name}")
} else {
write!(f, "badge")
}
}
Self::Rustdoc => write!(f, "rustdoc"),
}
}
}
pub(super) fn parse_markers<'cx>(
cx: &'cx PackageSyncContext<'_>,
markdown: &SourceFile,
) -> Result<Vec<Spanned<ResolvedReplaceSpecifier<'cx>>>, Box<ParseMarkersError>> {
let mut resolver = Resolver::new(cx, markdown.text());
let mut specifiers = vec![];
let mut errors = vec![];
while let Some(res) = resolver.try_next().transpose() {
match res {
Ok(specifier) => specifiers.push(specifier),
Err(err) => errors.push(err),
}
}
ensure!(
errors.is_empty(),
ParseMarkersSnafu {
package: cx,
markdown,
source_code: markdown.to_named_source(),
errors
}
);
Ok(specifiers)
}
pub(super) fn make_marked_contents(contents: &Contents<'_>) -> String {
let specifier = contents.specifier();
let text = contents.text();
if text.is_empty() {
format!("<!-- {MAGIC} {specifier} -->")
} else {
format!("<!-- {MAGIC} {specifier} [[ -->\n{text}<!-- {MAGIC} ]] -->")
}
}
pub(super) fn escape_marker(event: &mut Event<'_>) {
parse::escape_marker_comment(event);
}