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

Equivalent of \let via macros options #3737

Closed
edemaine opened this issue Oct 22, 2022 · 5 comments · Fixed by #3738
Closed

Equivalent of \let via macros options #3737

edemaine opened this issue Oct 22, 2022 · 5 comments · Fixed by #3738

Comments

@edemaine
Copy link
Member

edemaine commented Oct 22, 2022

Describe the bug:
It's certainly not convenient to do the equivalent of \let\Oldint=\int via a user-constructued macros option. In fact, it may not be possible.

To Reproduce:
Steps to reproduce the behavior, in Node or browser console:

  1. macros = {};
  2. katex.renderToString("\\let\\Oldint=\\int\\def\\int{\\Oldint\\limits}", {macros, globalGroup: true});
  3. Object.values(macros).forEach((val) => val.tokens.forEach((token) => delete token.loc)) — remove loc pointers which prevent serialization
  4. console.log(JSON.stringify(macros))
    {"\\Oldint":{"tokens":[{"text":"\\int","noexpand":true}],"numArgs":0,"unexpandable":false},"\\int":{"tokens":[{"text":"\\limits"},{"text":"\\Oldint"}],"numArgs":0,"delimiters":[[]]}}
  5. katex.renderToString("\\int", {macros}) works fine
  6. But katex.renderToString("\\int", {macros: {"\\Oldint":{"tokens":[{"text":"\\int","noexpand":true}],"numArgs":0,"unexpandable":false},"\\int":{"tokens":[{"text":"\\limits"},{"text":"\\Oldint"}],"numArgs":0,"delimiters":[[]]}}}) causes an infinite loop (!).

Expected behavior:
Manually constructing the macros object in the same shape as produced by \let should simulate the behavior of \let.

We might also want to document this shape, or otherwise make it easier to request \let behavior for built-in commands.

Also, an infinite loop should not be possible, even with invalid macros input. I would expect maxExpand to hit a limit here if nothing else.

Screenshots:
If applicable, add screenshots to help explain your problem.

Environment (please complete the following information):

  • KaTeX Version: 0.16.2
  • Device: Desktop
  • OS: Windows 10
  • Browser: Chrome or Node
  • Version: 106.0.5249.119 or v18.7.0

Additional context:
From #3736

@edemaine edemaine added the bug label Oct 22, 2022
edemaine added a commit that referenced this issue Oct 22, 2022
Issue #3737 turned out to be how we handled the return value of `expandOnce`.
We assumed that, if the return value isn't an `Array`, it's an
`instanceof Token`.  This isn't necessary true with a user's `macros`
object, and given that we don't currently export `Token`, it's pretty
difficult to bypass.

Given that we never actually use the array return values from
`expandOnce`, I changed the return value for `expandOnce` to either a
`number` (to indicate the number of expanded tokens, so you could still
look up the tokens in the stack if you wanted to) or `false`
(to indicate no expansion happened).  We can't use `0` for the latter
because an actual expansion might result in zero tokens.
The resulting code is arguably cleaner.

I also documented that `macros` can have object expansions, and
specified how to simulate `\let`.

Fixes #3737
@MrOddlyFormal
Copy link

Is this fixed?
I tried the snippet in the KaTeX demo on the website, but didn't work.

@edemaine
Copy link
Member Author

No, it's not fixed yet in release. #3738 fixes it, but it's currently under review. Thanks for the reminder to respond to the review though. 🙂

@MrOddlyFormal
Copy link

@edemaine happy to help 😉

@pedrolimasi
Copy link

@MrOddlyFormal in case you're trying to use \let to redefine \int to \int\limits (like I originally posted), few months ago I stumbled on a workaround:

There's an undocumented \intop that produces the same behavior as \int\limits. It seems to have been inspired by the esint package. If you have access to the macros object, all you have to do is to map \int to \intop.

edemaine added a commit that referenced this issue Apr 17, 2023
* fix: Support `\let` via `macros` option

Issue #3737 turned out to be how we handled the return value of `expandOnce`.
We assumed that, if the return value isn't an `Array`, it's an
`instanceof Token`.  This isn't necessary true with a user's `macros`
object, and given that we don't currently export `Token`, it's pretty
difficult to bypass.

Given that we never actually use the array return values from
`expandOnce`, I changed the return value for `expandOnce` to either a
`number` (to indicate the number of expanded tokens, so you could still
look up the tokens in the stack if you wanted to) or `false`
(to indicate no expansion happened).  We can't use `0` for the latter
because an actual expansion might result in zero tokens.
The resulting code is arguably cleaner.

I also documented that `macros` can have object expansions, and
specified how to simulate `\let`.

Fixes #3737

* Revise macros documentation according to comments
KaTeX-bot added a commit that referenced this issue Apr 17, 2023
## [0.16.6](v0.16.5...v0.16.6) (2023-04-17)

### Bug Fixes

* Support `\let` via `macros` option ([#3738](#3738)) ([bdb0be2](bdb0be2)), closes [#3737](#3737) [#3737](#3737)
@KaTeX-bot
Copy link
Member

🎉 This issue has been resolved in version 0.16.6 🎉

The release is available on:

Your semantic-release bot 📦🚀

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

Successfully merging a pull request may close this issue.

4 participants