Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add multiline #312

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open

Add multiline #312

wants to merge 2 commits into from

Conversation

kenjknox
Copy link

@kenjknox kenjknox commented Sep 23, 2024

Idea is to add the ability to latexify expression blocks:

julia> x = quote
           a = 1
           b = 2
           c = 3
      end

julia> latexify(x, env=:align)
L"\begin{align}
a &= 1 \\
b &= 2 \\
c &= 3
\end{align}
"

Since macros are prefixed with LineNumberNodes when contained in expressions I've switched from my original approach of checking for a LineNumberNode object to using the Base.isexpr function to test whether the initial arguement is a block before splitting. This avoids breaking expressions containing macros, however is it incompatible with Julia 1.6 and earlier.

I have also moved this into the main latexify function, since process_multiline should only be called once on the initial arguements, whereas process_latexify can be called multiple times on the same arguments. Don't want to be splitting nested block expressions without considering whether that is something worth doing!

@gustaphe
Copy link
Collaborator

Okay, this is pretty neat.
Could you not put this function call at or near

## Use the last expression in a block.
## This is somewhat shady but it helps with latexifying functions.
ex.head == :block && return args[end]

which then does not need to break 1.6? This is not performance critical code.

I'm also curious about in what way the previous behavior "helps with latexifying functions", I guess the idea is that

@latexify function f(x)
println("squaring x")
return x^2
end

should only return f(x) = x^2, but that happens anyway thanks to the :function behaviour. And there's no test for whatever is supposed to happen.
Maybe @korsbo has an opinion?

Also, MacroTools, which we are already importing, has a function striplines which removes LineNumberNodes without affecting macro calls. Might look a little cleaner. Or Base.remove_linenums! if we are sure there are no unpleasant side effects.

@kenjknox
Copy link
Author

Thanks @gustaphe. Really appreciate all the insights there!

Hadn't spotted that line in latexoperation.jl but that explains the default behaviour I was seeing: any block expression always returned the last line only. Think that's a good indicator that it's the right place to put the logic for parsing blocks.

Tried latexifying a function definition in my dev module as per your example and you're right that the logic for the :function header ensures that f(x) = x^2 is returned as expected, so there shouldn't be a problem parsing expressions with a :block header in a way that better suits their use.

@kenjknox
Copy link
Author

Had a go there and seems like latexoperations is too far down the line to handle this, because it is intended to only return a string. If you encounter a block at this stage returning the last element is the best you can do.

Possible it could be handled in the latexraw() or recurseexp!() functions, but my initial attempts at this didn't seem to work. May try this again soon, now I have a slightly better idea what the overall structure of the module is. Would be great if I can figure it out since something like:

@latexify function R_d(c_u, L, B, D, q)
    A = L * B
    N_c = π + 2
    s_c = 1 + 0.21B / L + 0.17(D / B)
    d_c = 1 + 0.27(D / B)
    A(N_c * s_c * d_c * c_u + q)
end

Still returns only $R_{d}\left( c_{u}, L, B, D, q \right) = A\left( N_{c} \cdot s_{c} \cdot d_{c} \cdot c_u + q \right)$ because the internal block isn't split.

@gustaphe
Copy link
Collaborator

gustaphe commented Oct 9, 2024

Ah, I see.

Those ternary expressions and the map+filter make the code really difficult to read, can I suggest

...
    ## Split multiline quotes before processing
    args = process_multiline.(args)
...
function process_multiline(x::Expr)
    x.head == :block || return x
    x = MacroTools.striplines(x)
    return x.args
end
process_multiline(x) = x

?

The line that treats :block in latexoperation should probably be removed, if we are certain no :block Exprs get that far.

Could you write a test or two for this functionality?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants