use super::*;
#[derive(Debug, Clone, EnumDiscriminants)]
#[strum_discriminants(name(ItemKind))]
#[strum_discriminants(derive(IntoStaticStr))]
#[strum_discriminants(strum(serialize_all = "kebab-case"))]
pub(crate) enum Item<'src> {
Alias(Alias<'src, Namepath<'src>>),
Assignment(Assignment<'src>),
Comment(&'src str),
Function(FunctionDefinition<'src>),
Import {
absolute: Option<PathBuf>,
attributes: AttributeSet<'src>,
optional: bool,
relative: StringLiteral<'src>,
},
Module {
absolute: Option<PathBuf>,
attributes: AttributeSet<'src>,
doc: Option<String>,
name: Name<'src>,
optional: bool,
relative: Option<StringLiteral<'src>>,
},
Newline,
Recipe(UnresolvedRecipe<'src>),
Setting(Set<'src>),
Unexport {
attributes: AttributeSet<'src>,
name: Name<'src>,
},
}
impl<'src> Item<'src> {
fn attributes(&self) -> Option<&AttributeSet<'src>> {
match self {
Self::Alias(alias) => Some(&alias.attributes),
Self::Assignment(assignment) => Some(&assignment.attributes),
Self::Comment(_) | Self::Newline => None,
Self::Function(function) => Some(&function.attributes),
Self::Import { attributes, .. }
| Self::Module { attributes, .. }
| Self::Unexport { attributes, .. } => Some(attributes),
Self::Recipe(recipe) => Some(&recipe.attributes),
Self::Setting(set) => Some(&set.attributes),
}
}
pub(crate) fn is_enabled(&self) -> bool {
self.attributes().is_none_or(AttributeSet::is_enabled)
}
fn doc_comment(&self) -> Option<&str> {
match self {
Self::Module {
attributes, doc, ..
} => {
if attributes.contains(AttributeKind::Doc) {
None
} else {
doc.as_deref()
}
}
Self::Recipe(recipe) => {
if recipe.attributes.contains(AttributeKind::Doc) {
None
} else {
recipe.doc.as_deref()
}
}
_ => None,
}
}
}
impl ColorDisplay for Item<'_> {
fn fmt(&self, f: &mut Formatter, color: Color) -> fmt::Result {
if let Some(doc) = self.doc_comment() {
if doc.is_empty() {
writeln!(f, "#")?;
} else {
writeln!(f, "# {doc}")?;
}
}
if let Some(attributes) = self.attributes() {
for attribute in attributes {
writeln!(f, "[{attribute}]")?;
}
}
match self {
Self::Alias(alias) => write!(f, "{alias}"),
Self::Assignment(assignment) => write!(f, "{assignment}"),
Self::Comment(comment) => write!(f, "{comment}"),
Self::Function(function) => {
write!(f, "{}(", function.name)?;
for (i, (parameter, _number)) in function.parameters.iter().enumerate() {
if i > 0 {
write!(f, ", ")?;
}
write!(f, "{parameter}")?;
}
write!(f, ") := {}", function.body)
}
Self::Import {
relative, optional, ..
} => {
write!(f, "import")?;
if *optional {
write!(f, "?")?;
}
write!(f, " {relative}")
}
Self::Module {
name,
optional,
relative,
..
} => {
write!(f, "mod")?;
if *optional {
write!(f, "?")?;
}
write!(f, " {name}")?;
if let Some(path) = relative {
write!(f, " {path}")?;
}
Ok(())
}
Self::Newline => Ok(()),
Self::Recipe(recipe) => write!(f, "{}", recipe.color_display(color)),
Self::Setting(set) => write!(f, "{set}"),
Self::Unexport { name, .. } => write!(f, "unexport {name}"),
}
}
}
impl ItemKind {
pub(crate) fn article(self) -> &'static str {
match self {
Self::Alias | Self::Assignment | Self::Import | Self::Unexport => "an",
Self::Comment
| Self::Function
| Self::Module
| Self::Newline
| Self::Recipe
| Self::Setting => "a",
}
}
fn name(self) -> &'static str {
self.into()
}
}
impl Display for ItemKind {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "{}", self.name())
}
}