-
-
Notifications
You must be signed in to change notification settings - Fork 60
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
Refactor Latexify.jl #161
base: master
Are you sure you want to change the base?
Refactor Latexify.jl #161
Conversation
In this breaking change, I stop re-routing all calls to latexraw via latexify. This was previously done to enable recursive recipe application. I'm now developing a more performant alterantive.
Codecov ReportBase: 60.21% // Head: 58.77% // Decreases project coverage by
Additional details and impacted files@@ Coverage Diff @@
## master #161 +/- ##
==========================================
- Coverage 60.21% 58.77% -1.45%
==========================================
Files 23 24 +1
Lines 734 798 +64
==========================================
+ Hits 442 469 +27
- Misses 292 329 +37
Help us with your feedback. Take ten seconds to tell us how you rate us. Have a feature suggestion? Share it here. ☔ View full report at Codecov. |
Nice! I look forward to trying this out. Just a quick thing: |
An example of how external packages might do extensions. module MyTest
using Latexify
struct MyType
args1
args2
end
my_instructions = [
function mymultiplication(io, ex, prevop, config)
## Recipe overrides everything and pirates evilly
if operation(ex) == :*
decend(io, arguments(ex)[1], operation(ex))
write(io, " EvilMult! ")
decend(io, arguments(ex)[2], operation(ex))
return true
end
end,
function mydivision(io, ex, prevop, config)
## Recipe only applied when called below a `MyType`
if operation(ex) == :/ && getconfig(:MyType, false)
decend(io, arguments(ex)[1], operation(ex))
write(io, " \\div ")
decend(io, arguments(ex)[2], operation(ex))
return true
end
end,
function mytype(io, ex, prevop, config)
if ex isa MyType
setconfig!(:MyType => true)
decend(io, Latexify.Equation(ex.args1))
return true
end
end,
]
append!(Latexify.USER_INSTRUCTIONS, my_instructions)
end
using Latexify
t = MyTest.MyType(:(1 + x/y * x), :(x))
## Both multiplication and division are non-default.
latexify(t)
## Multiplication has been affected but not division!
latexify(Latexify.Inline(:(a+x/y+b*x))) It's not ready yet but it just shows what one might be capable of. One could of course still just set new default configs and such without having to redefine entire operations but the world is your oyster here in a way that it never was before. Maybe of interest to you @gustaphe Input is always welcomed! [Edit: just a note that this only works in my local branch which has not yet been merged into this one.] |
I have some questions:
For a simple wrapper: struct Wrapper{T}
x::T
end would the main way to do it be push!(Latexify.USER_INSTRUCTIONS,
function wrapper(io, ex, prevop, config)
ex isa Wrapper || return false
write(io, "\\wrapper{")
descend(io, ex.x)
write(io, "}")
return true
end
) or to overload Can |
Currently there is a global config that keeps these ones. I first thought I might be able to not pass Currently, then global config is reset every top-level call. |
I used to use a |
pretty much this. One should not overload |
Technically possible but not what I want. A conditional can check values and not just types so it'll be more powerful. Trying to place all possible information in type annotations might make things both ugly and slow to compile (overspecialisation galore). Edit: Also, I don't care at all about runtime right now - it's already fast enough. So I don't want to offload too much of the branching to the compiler. Specialisation is great in most applications but it's not something I want here since there is already an imbalance towards slow compilation but fast runtime. |
One might still make some syntactic sugar for this though. I think it's good if there is a full-featured but maybe a bit complex function API for this, but we could have some convenience function/macro to hide many of the details for the simplest and most common use-cases. |
Yeah, I see why you're not only checking applicability, but I would imagine many recipes would become simpler if it was part of the chain. But yes, push!(Latexify.USER_INSTRUCTION,
function f(io, x, prevop, config)
x isa MyType || return false
descend(io, x.x)
return true
end
) and the user won't need to know that they are not actually using multiple dispatch... |
- Rename decend -> descend - Fix top-level matching for environments. - Add some precompilation. - Unify call signatures by changing config position. - Let config be a passed argument. This ensures that modifications are constrained to calls below the modifying call. - WIP: some macro prototyping.
Maybe we should think about splitting Latexify.jl into a few separate packages. With this refactor, we could have the default list of conversion functions in one package, the basic plumbing and utilities in another, rendering in a third, etc. Latexify.jl could then be a meta-package that just pulls in all the parts. I wonder if this might help deal with breaking releases. It has always been a bit problematic that even minute changes to the output formatting breaks tests. Separating formatting from the more high-level functionalities might provide a way of letting formatting be included in SemVer without having to bump the major version every other PR. I have not really thought this through. I'm mostly writing so that I don't forget until I can actually take some time to do this. |
Thanks past me, that was helpful 😄 |
Allows for tracing the call path along the different latexify rules.
Add matchers, tests and fix bugs.
The core is almost there now.
This PR is massively breaking for latexrecipes so we'll need to either bridge the gap by letting the old machinery translate into the new or we need to PR/add support for the most critical parts of the ecosystem. Support should be on par with what we already have right now (a low bar for DataFrames, for example).
Other items
The most major pieces of work left is figuring out the interface external packages to extend latexify and to get Symbolics.jl up to snuff. |
A reminder of what does not work.
Completely change the logic behind
latexraw
. And update the rest accordingly.This has a large impact on extensibility and it will break many recipes. However, it will enable far more powerful extensibility.