use quillmark_core::{Backend, Diagnostic, Quill, RenderError, Severity};
use std::collections::HashMap;
use std::sync::Arc;
use super::workflow::Workflow;
pub struct Quillmark {
backends: HashMap<String, Arc<dyn Backend>>,
warnings: Vec<Diagnostic>,
}
impl Quillmark {
pub fn new() -> Self {
let mut engine = Self {
backends: HashMap::new(),
warnings: Vec::new(),
};
#[cfg(feature = "typst")]
{
engine.register_backend(Box::new(quillmark_typst::TypstBackend));
}
engine
}
pub fn register_backend(&mut self, backend: Box<dyn Backend>) {
let id = backend.id().to_string();
self.backends.insert(id, Arc::from(backend));
}
pub fn warnings(&self) -> &[Diagnostic] {
&self.warnings
}
pub fn take_warnings(&mut self) -> Vec<Diagnostic> {
std::mem::take(&mut self.warnings)
}
pub fn quill(&self, tree: quillmark_core::FileTreeNode) -> Result<Quill, RenderError> {
let quill = Quill::from_tree(tree).map_err(|e| RenderError::QuillConfig {
diag: Box::new(
Diagnostic::new(
Severity::Error,
format!("Failed to load quill from tree: {}", e),
)
.with_code("quill::load_failed".to_string()),
),
})?;
self.attach_backend(quill)
}
pub fn quill_from_path<P: AsRef<std::path::Path>>(
&self,
path: P,
) -> Result<Quill, RenderError> {
let quill = Quill::from_path(path).map_err(|e| RenderError::QuillConfig {
diag: Box::new(
Diagnostic::new(Severity::Error, format!("Failed to load quill: {}", e))
.with_code("quill::load_failed".to_string()),
),
})?;
self.attach_backend(quill)
}
fn attach_backend(&self, quill: Quill) -> Result<Quill, RenderError> {
let backend_id = quill.backend_id.as_str();
let backend =
self.backends
.get(backend_id)
.ok_or_else(|| RenderError::UnsupportedBackend {
diag: Box::new(
Diagnostic::new(
Severity::Error,
format!("Backend '{}' not registered or not enabled", backend_id),
)
.with_code("engine::backend_not_found".to_string())
.with_hint(format!(
"Available backends: {}",
self.backends.keys().cloned().collect::<Vec<_>>().join(", ")
)),
),
})?;
Ok(quill.with_backend(Arc::clone(backend)))
}
pub fn workflow(&self, quill: &Quill) -> Result<Workflow, RenderError> {
let backend_id = quill.backend_id.as_str();
let backend =
self.backends
.get(backend_id)
.ok_or_else(|| RenderError::UnsupportedBackend {
diag: Box::new(
Diagnostic::new(
Severity::Error,
format!("Backend '{}' not registered or not enabled", backend_id),
)
.with_code("engine::backend_not_found".to_string())
.with_hint(format!(
"Available backends: {}",
self.backends.keys().cloned().collect::<Vec<_>>().join(", ")
)),
),
})?;
Workflow::new(Arc::clone(backend), quill.clone())
}
pub fn registered_backends(&self) -> Vec<&str> {
self.backends.keys().map(|s| s.as_str()).collect()
}
}
impl Default for Quillmark {
fn default() -> Self {
Self::new()
}
}