Skip to content

fix: \sout in text mode#4173

Merged
edemaine merged 8 commits intoKaTeX:mainfrom
ronkok:sout
Mar 24, 2026
Merged

fix: \sout in text mode#4173
edemaine merged 8 commits intoKaTeX:mainfrom
ronkok:sout

Conversation

@ronkok
Copy link
Copy Markdown
Collaborator

@ronkok ronkok commented Mar 20, 2026

Make \sout work in text mode. Fixes #4166.

This PR makes \sout work in both text mode and math mode. That way, it's not a breaking change.

@edemaine, If you would prefer to put math mode behind a strict setting, let me know. I would prefer to avoid a breaking change.

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Mar 20, 2026

Greptile Summary

This PR fixes \sout (strikethrough) so it works in text mode (e.g. \text{\sout{abc}}), which matches the behavior of LaTeX's ulem package where \sout is strictly a text-mode command. The change is backward compatible: math-mode usage (\sout{abc}) continues to work when strict is unset or false, while strict-mode users now get a proper warning/error indicating non-standard usage.

Key changes:

  • \sout is extracted from the \cancel/\bcancel/\xcancel/\phase group into its own defineFunction block with allowedInText: true and a reportNonstrict call for math-mode usage under strict settings
  • Existing build tests for \sout in math mode are updated to use nonstrictSettings, and a new test verifies that strict math-mode parsing fails
  • Screenshotter fixtures and reference images updated to use \text{\sout{...}}
  • Documentation and a11y tests updated to reflect the canonical text-mode usage
  • The reportNonstrict guard uses an outer parser.settings.strict check that is slightly inconsistent with how other functions (accent.ts, kern.ts) call reportNonstrict directly without a guard — though functionally there is no difference

Confidence Score: 4/5

  • Safe to merge — backward compatible, well-tested for the new strict-mode path, and consistent with LaTeX semantics.
  • The core implementation is correct: \sout is allowed in text mode and continues working in non-strict math mode (no breaking change). The strict-mode failure path is unit-tested. The only notable gaps are the redundant strict guard style inconsistency (P2) and no dedicated parse/build unit test for the text-mode path specifically (covered visually by screenshotter and a11y tests). Neither of these blocks merge.
  • src/functions/enclose.ts — minor guard style inconsistency on the reportNonstrict call

Important Files Changed

Filename Overview
src/functions/enclose.ts Separates \sout from the cancel group, adds allowedInText: true, and uses reportNonstrict to warn/error when \sout is used in math mode with strict settings — core implementation of the fix.
test/katex-spec.ts Existing \sout build tests now use nonstrictSettings (correct since math-mode \sout is now a nonstrict feature), and a new describe block verifies that strict math-mode usage fails to parse.
contrib/render-a11y-string/test/render-a11y-string-spec.ts Test updated to use \text{\sout{a}}; the snapshot now includes "start text / end text" wrappers, which is correct for the canonical text-mode usage.
test/screenshotter/ss_data.yaml StrikeThrough and StrikeThroughColor screenshotter fixtures updated to use \text{\sout{...}}; screenshots updated accordingly, consistent with the canonical usage change.
docs/supported.md Documentation entry for \sout updated from math-mode $\sout{abc}$ to text-mode $\text{\sout{abc}}$ example.
docs/support_table.md Support table entry for \sout updated from direct math-mode form to \text{\sout{abc}}, consistent with the supported.md change.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A["\\sout{...} encountered"] --> B{parser.mode?}
    B -->|text| C["handler: no strict check\nReturn enclose node"]
    B -->|math| D{parser.settings.strict?}
    D -->|false / falsy| E["Silently return enclose node\n(non-breaking backward compat)"]
    D -->|'warn'| F["reportNonstrict → console.warn\nReturn enclose node"]
    D -->|true / 'error'| G["reportNonstrict → throw ParseError\n(\\sout not valid in math mode)"]
    D -->|'ignore'| H["reportNonstrict → returns early\nReturn enclose node"]
    C --> I[htmlBuilder / mathmlBuilder\nshared with cancel group]
    E --> I
    F --> I
    H --> I
Loading

Reviews (2): Last reviewed commit: "Merge branch 'main' into sout" | Re-trigger Greptile

@edemaine
Copy link
Copy Markdown
Member

Thanks! It looks like your changes are from an old commit though.

@edemaine, If you would prefer to put math mode behind a strict setting, let me know. I would prefer to avoid a breaking change.

I would prefer to match LaTeX's behavior, yes. So math mode should trigger strict, unless some LaTeX package adds it. I don't think it's breaking given that the default strict behavior is warn.

@ronkok
Copy link
Copy Markdown
Collaborator Author

ronkok commented Mar 21, 2026

The latest commit writes an error message if \sout is invoked while in math mode. I've also written a couple of unit tests to verify the desired behavior.

@ronkok
Copy link
Copy Markdown
Collaborator Author

ronkok commented Mar 21, 2026

I've edited the screenshotter input to put the \sout in text mode, so the letters should now be upright instead of italic.

Unfortunately, screenshotter is failing and I am also getting an error message that there are merge conflicts. Both failures are inscrutable to me. I think that I have taken this PR as far as I can.

@edemaine
Copy link
Copy Markdown
Member

edemaine commented Mar 21, 2026

OK, I can pick it up from here. Next time, synchronize your fork and pull the latest main before making a branch.

@ronkok
Copy link
Copy Markdown
Collaborator Author

ronkok commented Mar 21, 2026

I did pull the latest main before running git branch sout. Before I did that, I did not check if a sout branch already existed. The message about sout being an old branch surprised me. Still confuses me.

@codecov
Copy link
Copy Markdown

codecov bot commented Mar 22, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 93.30%. Comparing base (314f856) to head (dd4c465).
⚠️ Report is 105 commits behind head on main.

Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main    #4173      +/-   ##
==========================================
+ Coverage   93.15%   93.30%   +0.14%     
==========================================
  Files          91       91              
  Lines        6795     6810      +15     
  Branches     1582     1589       +7     
==========================================
+ Hits         6330     6354      +24     
- Misses        429      454      +25     
+ Partials       36        2      -34     
Files with missing lines Coverage Δ
src/functions/enclose.ts 98.54% <100.00%> (ø)

... and 15 files with indirect coverage changes


Continue to review full report in Codecov by Sentry.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update f3977a0...dd4c465. Read the comment docs.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

allowedInText: true,
},
handler({parser, funcName}, args) {
if (parser.mode === "math" && parser.settings.strict) {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe it's worth to create type guard like hasHtmlDomChildren?

Something like
export const isMathMode = (mode: Mode): mode is "math" => mode === "math";

I'm not sure if it's worth it, as for now it could be reused only once in https://github.com/KaTeX/KaTeX/blob/main/src/functions/kern.ts#L31

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm... I'm not sure I see advantage to a type guard - until we see a context where narrowing would help inference.

@grigoriy-reshetniak
Copy link
Copy Markdown
Collaborator

Looks good!

@edemaine
Copy link
Copy Markdown
Member

@greptileai Another review?

@edemaine edemaine merged commit e748578 into KaTeX:main Mar 24, 2026
9 checks passed
@edemaine
Copy link
Copy Markdown
Member

By the way, I noticed that Greptile now edits the original review instead of posting a new one. Took me a while to find. 🙂

Thanks @ronkok for implementing this!

@edemaine
Copy link
Copy Markdown
Member

🎉 This PR is included in version 0.16.41 🎉

The release is available on:

Your semantic-release bot 📦🚀

grigoriy-reshetniak pushed a commit to grigoriy-reshetniak/KaTeX that referenced this pull request Mar 24, 2026
## [0.16.41](KaTeX/KaTeX@v0.16.40...v0.16.41) (2026-03-24)

### Bug Fixes

* \sout in text mode ([KaTeX#4173](KaTeX#4173)) ([e748578](KaTeX@e748578))
dadezzz pushed a commit to dadezzz/ice-notes that referenced this pull request Mar 31, 2026
This PR contains the following updates:

| Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) |
|---|---|---|---|
| [katex](https://katex.org) ([source](https://github.com/KaTeX/KaTeX)) | [`0.16.40` → `0.16.44`](https://renovatebot.com/diffs/npm/katex/0.16.40/0.16.44) | ![age](https://developer.mend.io/api/mc/badges/age/npm/katex/0.16.44?slim=true) | ![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/katex/0.16.40/0.16.44?slim=true) |

---

### Release Notes

<details>
<summary>KaTeX/KaTeX (katex)</summary>

### [`v0.16.44`](https://github.com/KaTeX/KaTeX/blob/HEAD/CHANGELOG.md#01644-2026-03-27)

[Compare Source](KaTeX/KaTeX@v0.16.43...v0.16.44)

##### Bug Fixes

- remove extra \jot space at bottom of align/gather/etc. ([#&#8203;4184](KaTeX/KaTeX#4184)) ([3870ee9](KaTeX/KaTeX@3870ee9))

### [`v0.16.43`](https://github.com/KaTeX/KaTeX/blob/HEAD/CHANGELOG.md#01643-2026-03-26)

[Compare Source](KaTeX/KaTeX@v0.16.42...v0.16.43)

##### Bug Fixes

- use makeEm() consistently to truncate long CSS decimals ([#&#8203;4181](KaTeX/KaTeX#4181)) ([0967dcc](KaTeX/KaTeX@0967dcc))

### [`v0.16.42`](https://github.com/KaTeX/KaTeX/blob/HEAD/CHANGELOG.md#01642-2026-03-24)

[Compare Source](KaTeX/KaTeX@v0.16.41...v0.16.42)

##### Features

- \underbracket and \overbracket ([#&#8203;4147](KaTeX/KaTeX#4147)) ([5be9abb](KaTeX/KaTeX@5be9abb))

### [`v0.16.41`](https://github.com/KaTeX/KaTeX/blob/HEAD/CHANGELOG.md#01641-2026-03-24)

[Compare Source](KaTeX/KaTeX@v0.16.40...v0.16.41)

##### Bug Fixes

- \sout in text mode ([#&#8203;4173](KaTeX/KaTeX#4173)) ([e748578](KaTeX/KaTeX@e748578))

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My44Ni4wIiwidXBkYXRlZEluVmVyIjoiNDMuOTkuMSIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOltdfQ==-->

Co-authored-by: Renovate Bot <renovate@zarantonello.dev>
Co-committed-by: Renovate Bot <renovate@zarantonello.dev>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

\sout should be a text-mode command, not a math mode one

3 participants