tinymist_task/compute/
text.rs

1use core::fmt;
2use std::sync::Arc;
3
4use crate::ExportTextTask;
5use tinymist_std::error::prelude::*;
6use tinymist_std::typst::{TypstDocument, TypstPagedDocument};
7use tinymist_world::{CompilerFeat, ExportComputation, WorldComputeGraph};
8
9pub struct TextExport;
10
11impl TextExport {
12    pub fn run_on_doc(doc: &TypstDocument) -> Result<String> {
13        Ok(format!("{}", FullTextDigest(doc)))
14    }
15}
16
17impl<F: CompilerFeat> ExportComputation<F, TypstPagedDocument> for TextExport {
18    type Output = String;
19    type Config = ExportTextTask;
20
21    fn run(
22        _g: &Arc<WorldComputeGraph<F>>,
23        doc: &Arc<TypstPagedDocument>,
24        _config: &ExportTextTask,
25    ) -> Result<String> {
26        Self::run_on_doc(&TypstDocument::Paged(doc.clone()))
27    }
28}
29
30/// A full text digest of a document.
31struct FullTextDigest<'a>(&'a TypstDocument);
32
33impl FullTextDigest<'_> {
34    fn export_frame(f: &mut fmt::Formatter<'_>, doc: &typst::layout::Frame) -> fmt::Result {
35        for (_, item) in doc.items() {
36            Self::export_item(f, item)?;
37        }
38        #[cfg(not(feature = "no-content-hint"))]
39        {
40            use std::fmt::Write;
41            let c = doc.content_hint();
42            if c != '\0' {
43                f.write_char(c)?;
44            }
45        }
46
47        Ok(())
48    }
49
50    fn export_item(f: &mut fmt::Formatter<'_>, item: &typst::layout::FrameItem) -> fmt::Result {
51        use typst::layout::FrameItem::*;
52        match item {
53            Group(g) => Self::export_frame(f, &g.frame),
54            Text(t) => f.write_str(t.text.as_str()),
55            Link(..) | Tag(..) | Shape(..) | Image(..) => Ok(()),
56        }
57    }
58
59    fn export_element(f: &mut fmt::Formatter<'_>, elem: &typst::html::HtmlElement) -> fmt::Result {
60        for child in elem.children.iter() {
61            Self::export_html_node(f, child)?;
62        }
63        Ok(())
64    }
65
66    fn export_html_node(f: &mut fmt::Formatter<'_>, node: &typst::html::HtmlNode) -> fmt::Result {
67        use typst::html::HtmlNode::*;
68        match node {
69            Tag(_) => Ok(()),
70            Element(elem) => Self::export_element(f, elem),
71            Text(t, _) => f.write_str(t.as_str()),
72            Frame(frame) => Self::export_frame(f, frame),
73        }
74    }
75}
76
77impl fmt::Display for FullTextDigest<'_> {
78    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
79        match &self.0 {
80            TypstDocument::Paged(paged_doc) => {
81                for page in paged_doc.pages.iter() {
82                    Self::export_frame(f, &page.frame)?;
83                }
84                Ok(())
85            }
86            TypstDocument::Html(html_doc) => {
87                Self::export_element(f, &html_doc.root)?;
88                Ok(())
89            }
90        }
91    }
92}