use comemo::{Track, Tracked, TrackedMut};
use ecow::EcoVec;
use typst_library::World;
use typst_library::diag::{At, SourceResult};
use typst_library::engine::{Engine, Route, Sink, Traced};
use typst_library::foundations::{Content, StyleChain};
use typst_library::introspection::{Introspector, Locator, LocatorLink, SplitLocator};
use typst_library::routines::{Arenas, FragmentKind, Pair, RealizationKind, Routines};
use typst_library::text::SmartQuoter;
use crate::convert::{ConversionLevel, Whitespace};
use crate::{HtmlElem, HtmlNode};
#[typst_macros::time(name = "html block fragment")]
pub fn html_block_fragment(
engine: &mut Engine,
content: &Content,
locator: Locator,
styles: StyleChain,
whitespace: Whitespace,
) -> SourceResult<EcoVec<HtmlNode>> {
html_block_fragment_impl(
engine.routines,
engine.world,
engine.introspector,
engine.traced,
TrackedMut::reborrow_mut(&mut engine.sink),
engine.route.track(),
content,
locator.track(),
styles,
whitespace,
)
}
#[comemo::memoize]
#[allow(clippy::too_many_arguments)]
fn html_block_fragment_impl(
routines: &Routines,
world: Tracked<dyn World + '_>,
introspector: Tracked<Introspector>,
traced: Tracked<Traced>,
sink: TrackedMut<Sink>,
route: Tracked<Route>,
content: &Content,
locator: Tracked<Locator>,
styles: StyleChain,
whitespace: Whitespace,
) -> SourceResult<EcoVec<HtmlNode>> {
let link = LocatorLink::new(locator);
let mut locator = Locator::link(&link).split();
let mut engine = Engine {
routines,
world,
introspector,
traced,
sink,
route: Route::extend(route),
};
engine.route.check_html_depth().at(content.span())?;
let arenas = Arenas::default();
let children = realize_fragment(&mut engine, &mut locator, &arenas, content, styles)?;
crate::convert::convert_to_nodes(
&mut engine,
&mut locator,
children.iter().copied(),
ConversionLevel::Block,
whitespace,
)
}
#[typst_macros::time(name = "html inline fragment")]
pub fn html_inline_fragment(
engine: &mut Engine,
content: &Content,
locator: &mut SplitLocator,
quoter: &mut SmartQuoter,
styles: StyleChain,
whitespace: Whitespace,
) -> SourceResult<EcoVec<HtmlNode>> {
engine.route.increase();
engine.route.check_html_depth().at(content.span())?;
let arenas = Arenas::default();
let children = realize_fragment(engine, locator, &arenas, content, styles)?;
let result = crate::convert::convert_to_nodes(
engine,
locator,
children.iter().copied(),
ConversionLevel::Inline(quoter),
whitespace,
);
engine.route.decrease();
result
}
fn realize_fragment<'a>(
engine: &mut Engine,
locator: &mut SplitLocator,
arenas: &'a Arenas,
content: &'a Content,
styles: StyleChain<'a>,
) -> SourceResult<Vec<Pair<'a>>> {
(engine.routines.realize)(
RealizationKind::HtmlFragment {
kind: &mut FragmentKind::Block,
is_inline: HtmlElem::is_inline,
},
engine,
locator,
arenas,
content,
styles,
)
}