Add MVP table support

finchie
Nov 11, 2023, 4:13 PM
Q3IYM4WFHTO2IQLR2ZJ52FIE7U4RYIHQHXTPCK2HENSPVI7CPUZAC

Dependencies

  • [2] I3NG5A4W Add support for content sequences
  • [3] 2N3KOCP7 Create MVP Pandoc->Rust compiler
  • [4] I5IZPMTH Handle empty expressions
  • [5] BA5Y6VSE Output Rust code using `syn`
  • [6] BSJYWOYS Implement MVP Typst embedding
  • [7] JCYJWUI3 Add support for various text formats
  • [8] MPTQGIIJ Improve `typst_rust_gen` function names
  • [9] YKL5NCLH Import items from `syn`
  • [10] CQEA2ZDI Parse evaluated Typst code instead of AST
  • [11] HEIF2O2E Migrate from `pandoc` to `typst` for AST processing

Change contents

  • replacement in docs/test.typ at line 1
    [3.242][3.0:23](),[3.23][2.0:111]()
    #let add(x, y) = x + y
    #let verbose_add(x, y) = {
    [the number is] + repr(add(x, y))
    };
    Sum is #add(2, 3)
    Verbose: #verbose_add(3, 4)
    [3.242]
    #table(
    columns: 2,
    rows: 2,
    [1],
    [2],
    [3],
    [4]
    )
  • replacement in crates/typser/src/lib.rs at line 168
    [3.73][2.112:145]()
    dbg!(typst_ast.scope());
    [3.73]
    [3.73]
    dbg!(typst_ast.scope(), typst_ast.clone().content());
  • edit in crates/typser/src/lib.rs at line 320
    [3.669][3.1959:1961](),[3.3798][3.1959:1961](),[3.4305][3.1959:1961](),[3.1959][3.1959:1961](),[3.4011][3.2142:2143](),[3.2142][3.2142:2143](),[3.2143][3.41:115](),[3.115][3.209:227](),[3.209][3.209:227](),[3.227][3.116:214](),[3.214][3.319:369](),[3.319][3.319:369](),[3.242][3.242:373](),[3.373][3.2211:2221](),[3.390][3.2211:2221](),[3.510][3.2211:2221](),[3.1942][3.2211:2221](),[3.4145][3.2211:2221](),[3.2211][3.2211:2221](),[3.2221][3.1943:1958](),[3.1958][3.511:536](),[3.536][3.1988:2008](),[3.1988][3.1988:2008](),[3.448][3.2380:2390](),[3.2008][3.2380:2390](),[3.4310][3.2380:2390](),[3.2380][3.2380:2390](),[3.2390][3.2009:2015]()
    }
    fn typst_expr_to_xilem(value: &typst::eval::Value) -> Option<syn::Expr> {
    match value {
    typst::eval::Value::Str(string) => Some(syn::Expr::Lit(literal_string(string.as_str()))),
    typst::eval::Value::Content(content) => {
    let supported_content = content::SupportedContent::downcast(content)?;
    Some(supported_content.to_xilem()?)
    }
    _ => {
    dbg!(value);
    todo!()
    }
    }
  • replacement in crates/typser/src/lib.rs at line 331
    [3.604][3.604:729](),[3.729][3.374:411](),[3.411][3.747:792](),[3.747][3.747:792](),[3.792][3.2339:2355](),[3.2339][3.2339:2355](),[3.2389][3.412:461](),[3.461][2.146:187]()
    let children = if let Some(typst::eval::Value::Array(array)) = root.get_by_name("children") {
    array
    } else {
    dbg!(root);
    todo!();
    };
    let xilem_expressions = children
    .iter()
    // Remove any empty expressions (`None`)
    .filter_map(typst_expr_to_xilem)
    [3.604]
    [3.2389]
    let typed_content = content::SupportedContent::downcast(&root);
    let xilem_expressions = typed_content
    .to_xilem()
    .into_iter()
  • edit in crates/typser/src/content.rs at line 2
    [3.2967]
    [3.2967]
    use typst_library::layout::TableElem;
  • replacement in crates/typser/src/content.rs at line 6
    [3.3054][2.188:250]()
    use crate::{literal_string, split_tuple, xilem_html_element};
    [3.3054]
    [3.3103]
    use crate::{literal_string, xilem_html_element};
  • edit in crates/typser/src/content.rs at line 14
    [3.3233]
    [3.3233]
    Table(&'a TableElem),
  • replacement in crates/typser/src/content.rs at line 18
    [3.3268][3.3268:3326](),[3.3326][3.495:542](),[3.542][2.293:354]()
    pub fn downcast(value: &'a Content) -> Option<Self> {
    if value.is_empty() {
    None
    } else if let Some(sequence) = value.to_sequence() {
    [3.3268]
    [2.354]
    pub fn downcast(value: &'a Content) -> Self {
    if let Some(sequence) = value.to_sequence() {
  • replacement in crates/typser/src/content.rs at line 21
    [2.390][2.390:461]()
    .filter_map(|child| SupportedContent::downcast(child))
    [2.390]
    [2.461]
    .map(|child| SupportedContent::downcast(child))
  • replacement in crates/typser/src/content.rs at line 23
    [2.499][2.499:542]()
    Some(Self::Sequence(children))
    [2.499]
    [3.542]
    Self::Sequence(children)
  • replacement in crates/typser/src/content.rs at line 25
    [3.608][3.3385:3426](),[3.3385][3.3385:3426]()
    Some(Self::Heading(heading))
    [3.608]
    [3.3426]
    Self::Heading(heading)
  • replacement in crates/typser/src/content.rs at line 27
    [3.3486][3.3486:3521]()
    Some(Self::Text(text))
    [3.3486]
    [3.3521]
    Self::Text(text)
  • replacement in crates/typser/src/content.rs at line 29
    [3.3583][3.3583:3620]()
    Some(Self::Space(space))
    [3.3583]
    [3.3620]
    Self::Space(space)
    } else if let Some(table) = value.to::<TableElem>() {
    Self::Table(table)
  • replacement in crates/typser/src/content.rs at line 38
    [3.3696][3.3696:3772](),[3.3772][2.543:881]()
    pub fn to_xilem(&self) -> Option<syn::Expr> {
    Some(match self {
    SupportedContent::Sequence(sequence) => {
    let children = split_tuple(
    sequence
    .iter()
    .filter_map(SupportedContent::to_xilem)
    .collect::<Vec<_>>(),
    );
    syn::Expr::Tuple(syn::ExprTuple {
    [3.3696]
    [2.881]
    pub fn to_xilem(&self) -> Vec<syn::Expr> {
    match self {
    SupportedContent::Sequence(sequence) => sequence
    .iter()
    .map(SupportedContent::to_xilem)
    .flatten()
    .collect::<Vec<_>>(),
    SupportedContent::Heading(heading) => {
    let body_text = Self::downcast(heading.body());
    vec![xilem_html_element("h1", body_text.to_xilem())]
    }
    SupportedContent::Text(text) => {
    vec![syn::Expr::Lit(literal_string(text.text().as_str()))]
    }
    SupportedContent::Space(_space) => vec![syn::Expr::Lit(literal_string(" "))],
    SupportedContent::Table(table) => vec![xilem_html_element(
    "table",
    vec![syn::Expr::Tuple(syn::ExprTuple {
  • replacement in crates/typser/src/content.rs at line 58
    [2.983][2.983:1105](),[2.1105][3.3772:4166](),[3.3772][3.3772:4166]()
    elems: syn::punctuated::Punctuated::from_iter(children.into_iter()),
    })
    }
    SupportedContent::Heading(heading) => {
    let body_text = Self::downcast(heading.body())?;
    xilem_html_element("h1", vec![body_text.to_xilem()?])
    }
    SupportedContent::Text(text) => syn::Expr::Lit(literal_string(text.text().as_str())),
    SupportedContent::Space(_space) => syn::Expr::Lit(literal_string(" ")),
    })
    [2.983]
    [3.4166]
    elems: syn::punctuated::Punctuated::from_iter(
    table
    .children()
    .into_iter()
    .map(|content| SupportedContent::downcast(content))
    .map(|supported| supported.to_xilem())
    .flatten()
    .collect::<Vec<_>>()
    .chunks(2) // TODO: a slightly more sophisticated layout algorithm
    .map(|chunk| {
    xilem_html_element(
    "tr",
    vec![syn::Expr::Tuple(syn::ExprTuple {
    attrs: Vec::new(),
    paren_token: syn::token::Paren::default(),
    elems: syn::punctuated::Punctuated::from_iter(
    chunk.into_iter().map(|item| item.to_owned()),
    ),
    })],
    )
    }),
    ),
    })],
    )],
    }