Typstry.jl icon indicating copy to clipboard operation
Typstry.jl copied to clipboard

Leverage mitex plugin to render latex equations

Open co1emi11er2 opened this issue 11 months ago • 12 comments

Currently Rough Implementation

This pull request extends the show_raw method for LaTexStrings. It would be great if we could leverage mitex to render latex equations into typst. It is a rough implementation, but I wanted to spark a discussion.

Try it out and see what you think

Import Typstry (using this branch) and Handcalcs

julia> using Handcalcs

julia> using Typstry

This command adds mitex package to the preamble

julia> context[:preamble] = TypstString(TypstText(context[:preamble] * TypstString(TypstText("#import \"@preview/mitex:0.2.4\": *\n"))))
TypstString(TypstText("#set page(margin: 1em, height: auto, width: auto, fill: white)\n#set text(16pt, font: \"JuliaMono\")\n#import \"@preview/mitex:0.2.4\": *\n"))

Then try the following:

julia> TypstString(
       @handcalcs begin
       x = 5
       y = 20
       z = x^2 + y
       end
       ) |> render;

You should get an output like the following: CleanShot 2025-01-16 at 15 36 09@2x

I currently opened an issue for the [10pt] being rendered. You can see the issue here: https://github.com/mitex-rs/mitex/issues/191

Otherwise mitex works pretty well. It can even render color:

julia> TypstString(
       @handcalcs begin
       x = 5
       y = 20
       z = x^2 + y
       end color = :blue
       ) |> render;

CleanShot 2025-01-16 at 15 39 34@2x

co1emi11er2 avatar Jan 16 '25 21:01 co1emi11er2

Adding @nathanrboyer to this. I know he wanted typst integration with handcalcs. This may be a potential quick fix once it is cleaned up. The true typst backend to handcalcs could still come later on, but I know that is a much bigger undertaking.

co1emi11er2 avatar Jan 16 '25 21:01 co1emi11er2

That's really cool! I hadn't known about mitex either. It might be useful to use a context parameter to import mitex automatically such as:

mitex(tc) && print(io, "#import \"@preview/mitex:0.2.4\": mi\n\"")`

The project's current roadmap is:

  1. Stop conflating a value's format with the mode
  2. Submit JuliaCon proposals
  3. Implement show_typst(::IO, ::TypstContext, ::Expr)

I love the feature you've implemented here and will absolutely merge it, but need to resolve item 1 before implementing new formats. For example, it would be nice to be able to render both a raw text block ``latex ... `` and rendered latex using mitex. However, a consistent but flexible API for choosing between these formats is eluding me. This work is in-progress, challenging to design, and the primary task I'm stuck on. Please let me know if you have thoughts about it.

I'm hoping to complete item 3 prior to JuliaCon, which would clear the way for a Typst backend in Handcalcs.jl :)

jakobjpeters avatar Jan 16 '25 22:01 jakobjpeters

Cool! Yeah I like that context parameter idea.

I agree that being able to render raw text block and choosing mitex option would be good.

I find API is always the hardest part for me. I personally like the way Latexify.jl allows for the changing of settings. You can see it here: https://korsbo.github.io/Latexify.jl/stable/#Setting-your-own-defaults. I ended up doing the same for handcalcs. I looked into preferences.jl but it seemed a little more confusing.

I usually find my favorite API by just imagining what I wish it was without any syntax constraints. In this case for me it would be matching Typst 1 to 1 as best as I can. This may not be what you are looking for, but something like this would be cool for building typst documents:

@typst_report begin

"""
#import \"@preview/mitex:0.2.4\": *

= Header 1
This is normal typst markdown

#align(right)[#text(fill:green)[OK]]

See the equation below:	
"""
# can comment as normal
@mi(@handcalcs begin
x = 5
y = 20
z = x^2 + y^2
end
)

# mitex is a centered math environment.
@mitex(@handcalcs begin
x = 5
y = 20
z = x^2 + y^2
end
)

# this would simply pass the raw text block (unless settings were changed maybe)
@handcalcs begin
x = 5
y = 20
z = x^2 + y^2
end

# some no render function that does not print
@no_render(
a = 5
)

"""
Can I interpolate *a* here: $$(a). What syntax should it be?	
"""

end

This would essentially be the render function that prints each piece. It basically just opens an io and then adds the_expr |> TypstString |> show_typst to each expression.

co1emi11er2 avatar Jan 17 '25 00:01 co1emi11er2

I personally like the way Latexify.jl allows for the changing of settings. You can see it here: https://korsbo.github.io/Latexify.jl/stable/#Setting-your-own-defaults.

I agree this is good design. The next release will use a TypstContext which can be mutated by the user to specify the default behavior.

The two main contenders in terms of how to select between formats is

  • A. Each type has a unique format
    • Pros: Simple to think about and document.
    • Cons:
      • It is ambiguous when to switch between modes. For example, it's pretty clear that a vector should be switched to math mode. However, should TypstString(1; mode = markup) be formatted as 1, #1, or $1$?
      • In some cases, it is difficult to choose what the default format should be. Ideally, this should be consistent for similar or related types. However, some types have a more specific or semantically rich representation that differs from the rest. For example, a Vector should probably be a mathematical vector but a Range is both a Vector and corresponds to Typst's code mode range.
      • Requires implementing more types and having the user perform more type conversions.
  • B. Each type can have multiple formats, specified by a format parameter
    • Pros: Works with preexisting types, is very flexible
    • Cons:
      • More complicated to implement and document, since formats overlap
        • Implementation needs to branch and error for unsupported formats
      • Still requires a default format
      • Is still ambiguous about switching modes

I've tried out both, which unfortunately took a lot of time. I was initially averse to option A because I wanted to avoid creating a bunch of new types. However, B feels pretty messy and doesn't really solve any of the problems with A. Option A also seems to align with your proposal, where a LaTeXString is a raw text block and whatever is returned by mitex is rendered latex. Do you think option A is a good plan? It's currently implemented locally, but has some remaining work.

In the upcoming support for Expr, I intend to implement @typst to support behavior similar to what your example shows. Each element in the block would printed in Typst format and concatenated. This enables a really cool feature where you can choose whether to transpile Julia function calls to Typst function calls or just render it syntactically. The idea to have something like @no_render is new and good!

jakobjpeters avatar Jan 17 '25 00:01 jakobjpeters

This would essentially be the render function that prints each piece. It basically just opens an io and then adds the_expr |> TypstString |> show_typst to each expression.

Missed this the first time, yes exactly!

jakobjpeters avatar Jan 17 '25 01:01 jakobjpeters

I think I like the option A idea. I will try to look into it more these next few days/weeks depending on time. This is awesome work so far! This is the main thing I want to figure out right now. That being how everything will work together: quarto, typst, Pluto, Handcalcs, Jupyter, Drwatson, etc.

At work it’s a pain to get things unblocked due to security measures so it has been hard trying to use quarto somewhat which relies on so many executables. I don’t know how I would ensure all users are able to get everything installed and working. Being able to rely on just Julia and Typst for reports would be so nice.

An interactive Pluto file to typst output would pretty amazing from a user standpoint, but we just have to take it one piece at a time.

co1emi11er2 avatar Jan 17 '25 04:01 co1emi11er2

An interactive Pluto file to typst output

Do you mean rendering a cell or the entire file? Rendering a cell already works in Pluto and Jupyter. It doesn't currently work in Quarto, and I haven't investigated why yet.

jakobjpeters avatar Jan 17 '25 04:01 jakobjpeters

Oh my documentation says it works in Quarto, maybe I fixed it. Guess I'll have to check haha

jakobjpeters avatar Jan 17 '25 04:01 jakobjpeters

At work it’s a pain to get things unblocked due to security measures so it has been hard trying to use quarto somewhat which relies on so many executables. I don’t know how I would ensure all users are able to get everything installed and working. Being able to rely on just Julia and Typst for reports would be so nice.

That's good work you're putting in, keep it up!

jakobjpeters avatar Jan 17 '25 04:01 jakobjpeters

Oh my documentation says it works in Quarto, maybe I fixed it. Guess I'll have to check haha

I haven’t tried your package with it. That is just with Handcalcs/jupyter. It’s just the work hurdles with quarto and relying on the Latex pdf render (currently) that is too difficult currently.

co1emi11er2 avatar Jan 17 '25 04:01 co1emi11er2

An interactive Pluto file to typst output

Do you mean rendering a cell or the entire file? Rendering a cell already works in Pluto and Jupyter. It doesn't currently work in Quarto, and I haven't investigated why yet.

I can currently create an interactive Pluto file using handcalcs, but our calculations must be printed to pdf. There is currently no Pluto -> quarto(pdf) or Pluto -> typst(pdf) that exists

co1emi11er2 avatar Jan 17 '25 04:01 co1emi11er2

By the way, I rewrote history in order to release a small v0.5.0. The bigger changes have been moved to the v0.6.0 branch.

jakobjpeters avatar Mar 02 '25 00:03 jakobjpeters