reflexo_typst2vec/
incr.rs

1use std::sync::Arc;
2
3use reflexo::error::prelude::*;
4use typst::model::Document;
5
6use super::ir::{
7    FlatModule, IncrFontPack, IncrGlyphPack, ItemPack, LayoutRegion, LayoutRegionNode,
8    ModuleMetadata, VecDocument,
9};
10use super::pass::IncrTypst2VecPass;
11use crate::debug_loc::{ElementPoint, SourceSpanOffset};
12
13/// Client side implementation is free from typst details.
14pub use reflexo::vector::incr::{IncrDocClient, IncrDocClientKern};
15
16/// maintains the data of the incremental rendering at server side
17#[derive(Default)]
18pub struct IncrDocServer {
19    /// Expected exact state of the current Compiler.
20    /// Initially it is None meaning no completed compilation.
21    doc_view: Option<VecDocument>,
22
23    /// Maintaining typst -> vector status
24    typst2vec: IncrTypst2VecPass,
25}
26
27impl IncrDocServer {
28    /// Set whether to attach debug info to the spans.
29    pub fn set_should_attach_debug_info(&mut self, should_attach_debug_info: bool) {
30        self.typst2vec
31            .spans
32            .set_should_attach_debug_info(should_attach_debug_info);
33    }
34
35    /// Pack the delta into a binary blob.
36    pub fn pack_delta(&mut self, output: Arc<Document>) -> Vec<u8> {
37        self.typst2vec.spans.reset();
38
39        // Increment the lifetime of all items to touch.
40        self.typst2vec.increment_lifetime();
41
42        // it is important to call gc before building pages
43        let gc_items = self.typst2vec.gc(5 * 2);
44
45        // run typst2vec pass
46        let pages = self.typst2vec.doc(&output.introspector, &output);
47
48        // let new_items = builder.new_items.get_mut().len();
49        // let new_fonts = builder.glyphs.new_fonts.get_mut().len();
50        // let new_glyphs = builder.glyphs.new_glyphs.get_mut().len();
51
52        let delta = self.typst2vec.finalize_delta();
53
54        // max, min lifetime current, gc_items
55        #[cfg(feature = "debug-gc")]
56        {
57            let mi = self
58                .typst2vec
59                .items
60                .clone()
61                .into_iter()
62                .map(|i| i.1 .0)
63                .min()
64                .unwrap_or(0);
65            println!(
66                "gc[{}]: max: {}, min: {}, remove: {}",
67                self.typst2vec.lifetime,
68                self.typst2vec
69                    .items
70                    .clone()
71                    .into_iter()
72                    .map(|i| i.1 .0)
73                    .max()
74                    .unwrap_or(0xffffffff),
75                mi,
76                gc_items.len()
77            );
78
79            // for (fg, (_, item)) in
80            //     self.typst2vec.items.iter().filter(|(_, i)| i.0 == mi) {
81            //     println!("mi {fg:?} => {item:#?}");
82            // }
83        }
84
85        let fonts = IncrFontPack {
86            items: delta.fonts,
87            incremental_base: 0, // todo: correct incremental_base
88        };
89
90        let glyphs = IncrGlyphPack {
91            items: delta.glyphs,
92            incremental_base: 0, // todo: correct incremental_base
93        };
94
95        let pages = LayoutRegionNode::new_pages(pages.clone());
96        let pages = Arc::new(vec![LayoutRegion::new_single(pages)]);
97
98        let delta = FlatModule::new(vec![
99            ModuleMetadata::GarbageCollection(gc_items),
100            ModuleMetadata::Font(Arc::new(fonts)),
101            ModuleMetadata::Glyph(Arc::new(glyphs)),
102            ModuleMetadata::Item(ItemPack(delta.items.clone().into_iter().collect())),
103            ModuleMetadata::Layout(pages),
104        ])
105        .to_bytes();
106
107        // log::info!("svg render time (incremental bin): {:?}", instant.elapsed());
108        [b"diff-v1,", delta.as_slice()].concat()
109    }
110
111    /// Pack the current entirely into a binary blob.
112    pub fn pack_current(&mut self) -> Option<Vec<u8>> {
113        let doc = self.doc_view.as_ref()?;
114
115        let (fonts, glyphs) = self.typst2vec.glyphs.finalize();
116
117        let pages = LayoutRegionNode::new_pages(doc.pages.clone());
118        let pages = Arc::new(vec![LayoutRegion::new_single(pages)]);
119
120        let delta = FlatModule::new(vec![
121            // todo: correct incremental_base
122            ModuleMetadata::Font(Arc::new(fonts.into())),
123            ModuleMetadata::Glyph(Arc::new(glyphs.into())),
124            ModuleMetadata::Item(ItemPack(doc.module.items.clone().into_iter().collect())),
125            ModuleMetadata::Layout(pages),
126        ])
127        .to_bytes();
128        Some([b"new,", delta.as_slice()].concat())
129    }
130
131    /// Gets element paths by the given span.
132    ///
133    /// See [`crate::pass::Span2VecPass::query_element_paths`] for more
134    /// information.
135    pub fn resolve_element_paths_by_span(
136        &mut self,
137        span_offset: SourceSpanOffset,
138    ) -> ZResult<Vec<Vec<ElementPoint>>> {
139        self.typst2vec.spans.query_element_paths(span_offset)
140    }
141
142    /// Gets the span range of the given element path.
143    pub fn resolve_span_by_element_path(
144        &mut self,
145        path: &[ElementPoint],
146    ) -> ZResult<Option<(SourceSpanOffset, SourceSpanOffset)>> {
147        self.typst2vec.spans.query(path)
148    }
149}