use inker::{
DocumentDiagnostic, DocumentProvenance, DocumentTrustState, Engine, EngineDocument,
EngineError, EngineInput,
};
use crate::GemtextEngine;
pub const ENGINE_ID: &str = "nematic.titan";
pub struct TitanEngine {
gemtext: GemtextEngine,
}
impl TitanEngine {
pub fn new() -> Self {
Self {
gemtext: GemtextEngine::new(),
}
}
}
impl Default for TitanEngine {
fn default() -> Self {
Self::new()
}
}
impl Engine for TitanEngine {
fn engine_id(&self) -> &str {
ENGINE_ID
}
fn render(&self, input: &EngineInput) -> Result<EngineDocument, EngineError> {
let mut doc = self.gemtext.render(input)?;
doc.provenance = DocumentProvenance {
source_kind: Some(self.engine_id().to_string()),
canonical_uri: Some(input.address.clone()),
fetched_at: None,
source_label: Some("nematic.gemtext".to_string()),
};
doc.trust = DocumentTrustState::Unknown;
doc.diagnostics
.push(DocumentDiagnostic::UnsupportedConstruct(
"titan upload/request construction is handled by the transport layer, not this \
render engine; only the server's Gemini response body is rendered here"
.to_string(),
));
Ok(doc)
}
}
#[cfg(test)]
mod tests {
use super::*;
fn render(body: &str) -> EngineDocument {
TitanEngine::new()
.render(&EngineInput::new("titan://example.test/", body))
.expect("render")
}
#[test]
fn engine_id_is_stable() {
assert_eq!(TitanEngine::new().engine_id(), "nematic.titan");
}
#[test]
fn response_body_parses_as_gemtext() {
let doc = render("# Uploaded\n\n=> titan://example.test/page Saved page\n");
assert_eq!(doc.title.as_deref(), Some("Uploaded"));
assert_eq!(doc.outgoing_links(), vec!["titan://example.test/page"]);
}
#[test]
fn provenance_records_titan_with_gemtext_label() {
let doc = render("body\n");
assert_eq!(doc.provenance.source_kind.as_deref(), Some("nematic.titan"));
assert_eq!(
doc.provenance.source_label.as_deref(),
Some("nematic.gemtext")
);
}
#[test]
fn upload_scope_boundary_emits_diagnostic() {
let doc = render("hi\n");
let has_note = doc.diagnostics.iter().any(|d| {
matches!(
d,
DocumentDiagnostic::UnsupportedConstruct(msg)
if msg.contains("upload") && msg.contains("transport")
)
});
assert!(has_note, "expected titan upload-scope diagnostic");
}
}