use std::{borrow::Cow, fs::read_to_string, rc::Rc};
use syn::*;
use crate::{
common::{error, path},
config::Config,
syntax::LayoutTempl,
};
mod attribute;
use attribute::AttrVisitor;
#[derive(Debug)]
pub struct Metadata {
path: Rc<str>,
source: Option<Rc<str>>,
reload: Reload,
block: Option<Ident>,
kind: TemplKind,
}
#[derive(Debug)]
pub enum TemplKind {
Main,
MainWrapper,
Layout,
Import,
}
impl std::fmt::Display for TemplKind {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Main => write!(f, "Main"),
Self::MainWrapper => write!(f, "MainWrapper"),
Self::Layout => write!(f, "Layout"),
Self::Import => write!(f, "Import"),
}
}
}
impl Metadata {
pub fn from_attrs(attrs: &[Attribute], conf: &Config) -> Result<Metadata> {
AttrVisitor::parse(attrs, conf)
}
pub fn clone_as_import(&self, path: impl AsRef<std::path::Path>) -> Metadata {
Self {
path: path::resolve_at(path, self.dir_ref()),
source: None,
reload: self.reload.clone(),
block: None,
kind: TemplKind::Import,
}
}
pub fn clone_as_layout(&self, layout: &LayoutTempl) -> Metadata {
Self {
path: path::resolve_at(layout.path.value(), self.dir_ref()),
source: None, reload: self.reload.clone(), block: None, kind: TemplKind::Layout,
}
}
pub fn resolve_source(&self) -> Result<Cow<'_, str>> {
match self.source.as_deref() {
Some(src) => Ok(src.into()),
None => Ok(error!(
!read_to_string(&*self.path),
"cannot read `{}`: {}", self.path
)
.into()),
}
}
pub(crate) fn dir_ref(&self) -> &std::path::Path {
std::path::Path::new(&*self.path)
.parent()
.unwrap_or(std::path::Path::new("/"))
}
pub(crate) fn is_file(&self) -> bool {
std::path::Path::new(&*self.path).is_file()
}
pub fn block(&self) -> Option<&Ident> {
self.block.as_ref()
}
pub fn path(&self) -> &str {
&self.path
}
pub fn reload(&self) -> &Reload {
&self.reload
}
pub fn kind(&self) -> &TemplKind {
&self.kind
}
pub fn inline(&self) -> Option<&str> {
self.source.as_deref()
}
}
#[derive(Clone)]
pub enum Reload {
Debug,
Always,
Never,
Expr(Rc<Expr>),
}
impl Default for Reload {
fn default() -> Self {
if cfg!(feature = "dev-reload") {
Reload::Debug
} else {
Reload::Never
}
}
}
impl Reload {
pub fn as_bool(&self) -> std::result::Result<bool, &Expr> {
match self {
Reload::Debug => Ok(cfg!(debug_assertions)),
Reload::Always => Ok(true),
Reload::Never => Ok(false),
Reload::Expr(expr) => Err(expr),
}
}
}
impl std::fmt::Debug for Reload {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Debug => write!(f, "Reload::Debug"),
Self::Always => write!(f, "Reload::Always"),
Self::Never => write!(f, "Reload::Never"),
Self::Expr(_) => write!(f, "Reload::<Expr>"),
}
}
}