LDemetrios / Typst4k

2 stars 0 forks source link

Table/Grid typst rendering #1

Closed einsweniger closed 6 days ago

einsweniger commented 3 months ago

Hi! I've ran into some problems when using tables or grids. I understand that your project is in a very early stage, so I'm not quite sure how important this is, to you.

summary:

  1. There is no distinction between a table and a grid, or rather there is important parts missing
  2. The produced Syntax is not valid typst code
  3. in general, Typst varargs do not seem supported, yet and will probably cause problems further down the road.

details:

1. Table vs. Grid

The datamodel file contains grid and all necessary parts, but the parts relevant to table are missing, basically all grid.* parts should also be available as table.*, which could just be copied. For example, the generated definitions contains TTable and TCell, but using TCell will not be accepted by typst, since table will only accept table.cell as child nodes.

2/3. Generated/Vararg code :

Code generation will add an array of for the children argument, which typst does not accept, as they should be present as positional arguments, not as an Array.

I've "fixed" this in my project by shimming the TContent.repr() call as such:

/**
 * Adds exception for TTable output. 
 * Everything else (for now) is handled by the default (else) `TContent::repr` function
 */
internal fun TContent.reprShim(): CharSequence = when (this) {
    is TTable -> buildString {
        val tableProps = RT.structRepr(
            "table",
            Triple(false, "columns", columns),
            Triple(false, "rows", rows),
            Triple(false, "gutter", gutter),
            Triple(false, "column-gutter", columnGutter),
            Triple(false, "row-gutter", rowGutter),
            Triple(false, "fill", fill),
            Triple(false, "align", align),
            Triple(false, "stroke", stroke),
            Triple(false, "inset", inset),
            // this will be handled by the lines below
            // Triple(false, null, children),
        ).dropLast(1) // remove the closing parenthesis and add a comma

        // join all children with a comma (and add newlines for debugging
        val childNodes = children.joinToString(separator = ",\n  ", prefix = ",\n  ", postfix = "\n") {
            // delegate the child rendering back to typst4k code and wrap dem in "table.cell"
            RT.structRepr(
                "table.cell",
                Triple(false, null, it)
            )
        }
        append(tableProps)
        // finally close the table call by adding the removed paren back in
        append(childNodes+")")
    }
    else -> repr()
}

As I recall, there's several typst functions, that accept vararg parameters. I'm not quite sure about your project plans: Do you want to primarily rely on code generation from the datamodel file or would you write some edge-cases by hand? Depending on the answer, I could probably provide a PR if you'll accept it, otherwise this is just what I have encountered so far. Thank you for the project, saved me at least some days of writing that myself!

LDemetrios commented 2 weeks ago

Hello! I am very sorry for being absent for so long, I thought I had settings for notifying me when issue appears... Apparently I hadn't.

I understand that your project is in a very early stage, so I'm not quite sure how important this is, to you.

Originally I wanted to use it in Typst plugins, as Kotlin can compile to wasm, but wasmi used in Typst doesn't support languages with gc yet. But there are other things I can think of using this project, so I will update it from time to time.

in general, Typst varargs do not seem supported, yet and will probably cause problems further down the road.

Now to the issue itself. I think, varargs are supported by my model, it should add .. before the array. I'll take a look in a few days, it really could be just a missing word somewhere. Otherwise, of course, PRs are welcome (I'll try not disappear again, haha). I would actually prefer using generated code as much as possible, but there obviously are cases where it's impossible.

The produced Syntax is not valid typst code

I will also consider having some automatic tests involving feeding the repr to the Typst compiler. It's actually not great that I didn't think about it earlier...

LDemetrios commented 2 weeks ago

It appears that I'm missing ... along with req pos children in both grid and table, here's how it should be:

class table(
    req pos ... children: array<content>,
    columns: auto|int|relative|fraction|array<*>,
    rows: auto|int|relative|fraction|array<*>,
...

Speaking of difference between table and grid. According to docs:

they have the same set of parameters, with the same characteristics.

I've started automated testing, some things in math, lists and cells also fail, where composite identifiers are used.

LDemetrios commented 6 days ago

Hopefully all the problems mentioned should be gone with the last update.

The produced syntax is not valid typst code

I'm now in tests feeding the repr to the actual Typst compiler, and besides few issues with set rules or other complicated stuff, it should work.

basically all grid. parts should also be available as table., which could just be copied.

No, they couldn't, but can be and are now. There was a problem, because table.cell and grid.cell and so on has the same func() representation on the Rust side. I added serial_name method to Element in my fork of typst compiler, so now it should work as intended. Note that I want to have equally the ability to repr values, and to query them. Querying requires compiler support.

Code generation will add an array of for the children argument

As I mentioned earlier, this is fixed just adding ... along with pos req modifiers in the model.

I consider the issue to be closed, please comment to confirm or refute. In the case of the latter, I'll reopen the issue