Skip to content

fix: terminal IME raw Latin on Linux (#1375), display-math tag overlap (#1402); v0.9.73 - #1404

Merged
xiaolai merged 5 commits into
mainfrom
fix/1375-ime-orphan-ascii-commit
Sep 13, 2026
Merged

xiaolai merged 5 commits into
mainfrom
fix/1375-ime-orphan-ascii-commit

Conversation

@xiaolai

@xiaolai xiaolai commented Sep 13, 2026

Copy link
Copy Markdown
Owner

Summary

Two user-reported fixes and the 0.9.73 version bump, in one PR so the release pays one CI cycle.

Commit What
fix(terminal) #1375: in the integrated terminal on Linux (WebKitGTK + fcitx5 + Rime), Enter in Chinese mode committed nothing when the text was raw Latin (claude, raw pinyin)
chore bump to 0.9.73 (five version files + Cargo.lock)
fix(math) #1402: \tag{1} on display math rendered on top of the last term; #1376's fix had never reached the rendering path
test(math) real-WebKit geometry test for the #1402 fix

Policy Gates (Required)

Linked Issue

Type of Change

  • Bug fix
  • Feature
  • Docs
  • Refactor
  • Test-only
  • Other: version bump to 0.9.73

What Changed

#1375: orphan compositionend with ASCII text

On WebKitGTK with fcitx5, compositionstart never fires (#948's instrumented trace). WebKit's Editor::setComposition inserts the confirmed text as insertFromComposition (isComposing: true) and then dispatches compositionend with no start guard, so every commit is an orphan end. The gate's input() path and xterm's _inputEvent both ignore insertFromComposition, so the orphan end is the only carrier, and imeGateMachine.compositionEnd committed its e.data only when non-ASCII. Chinese got through; raw Latin was dropped.

  • An orphan end now commits its e.data even when ASCII, unless xterm's keydown path already wrote that keystroke in the same task (the write-derived ownership rule input() uses; the claim is read, not spent).
  • The F2 hazard (a stale textarea) stays excluded: an orphan end never reads the textarea diff.
  • The old test "still ignores ASCII from an ORPHAN compositionend" encoded a premise that is false on WebKitGTK; it is replaced by a suite replaying the WebKitGTK sequence.
  • Not addressed: IME flicker and the initially misplaced candidate window inside Claude Code / Codex CLI. fcitx5 documents a Wayland client-side popup limitation that may explain them; the reporter is asked for a GDK_BACKEND=x11 experiment.

#1402: display-math \tag overlap, class-wide

KaTeX places the tag with position: absolute; right: 0 inside .katex-html, which fills .katex-display. VMark's math previews are flex containers, so .katex-display shrink-wraps to the equation and right: 0 lands on the last term. #1376's fix set width: 100% under .math-block-preview, a class no renderer produces; every $$…$$ block renders into .code-block-preview.latex-preview or .code-block-live-preview.

  • The rule moves unscoped into styles/katexFixes.css, loaded by main.tsx and the export CSS bundle, so every display-math container (current, future, export) gets it. The redundant scoped width in latex.css is removed.
  • displayMathTag.test.ts asserts the class, not a selector: unscoped rule present and loaded by app and export; flex containers derived from the renderers; no stylesheet narrows .katex-display; no hand-placed tag.
  • displayMathTag.webkit.test.ts measures it: real stylesheets, real renderLatex + sanitizeKatex, both containers. A constructed case forces width: auto and asserts the probe sees the overlap.

Validation

Check Result
#1375 new cases before the fix 6 failed with expected [] (the drop)
#1375 Terminal suite after 55 files, 972 tests green
#1375 mutation: remove the ownership check exactly the no-double case fails
#1402 stylesheet test before the fix the unscoped-rule assertion failed; 5 passed
#1402 related suite after (vitest related, both stylesheets) 84 files, 5,479 tests green
#1402 mutation: width: auto on .code-block-preview.latex-preview .katex-display the stylesheet scan fails naming that rule
#1402 real WebKit, with the fix 3/3 (tag at the block edge in both containers; constructed overlap detected)
#1402 real WebKit, rule removed both container cases fail; constructed case passes
pnpm lint:test-types held (the new WebKit test adds no errors)
pnpm check:predelta (final tree) 44/44 gates, exit 0

The WebKit test first landed in src/plugins/latex/, where CI's lint:deps rejected its import of code-preview.css as a cross-plugin edge (plugin-isolation). It now lives in src/plugins/codePreview/, the fence-preview hub the rule licenses to import the latex plugin; lint:deps is clean and the test still passes 3/3.

UI Evidence (if applicable)

No screenshot attached. The #1402 layout is asserted by displayMathTag.webkit.test.ts, which runs in CI's webkit job. The reporter's before/expected screenshots are in #1402.

PR Checklist

  • The PR avoids unrelated refactors or cleanup.
  • The issue context is clear (linked issue or explanation above).
  • Docs/changelog were updated if behavior or usage changed. Not applicable: bug fixes with no documented behavior change; release notes are generated.
  • I am ready to address review feedback.

On WebKitGTK with fcitx5, compositionstart never fires (the instrumented
trace in #948), so every IME commit arrives as an orphan compositionend.
WebKit's Editor::setComposition inserts the confirmed text as
insertFromComposition with isComposing=true, then dispatches compositionend
with no start guard. Neither the gate's input path nor xterm's _inputEvent
takes an insertFromComposition insert, so the orphan end is the only carrier.

The gate committed an orphan end's e.data only when it was non-ASCII. Chinese
commits got through; the raw Latin text Rime's Enter confirms (claude, raw
pinyin) was dropped, and the textarea clear left xterm's finalizer nothing to
send.

An orphan end now commits its e.data even when ASCII, unless xterm's keydown
path already wrote that keystroke in the same task (the same write-derived
ownership rule input() uses; the claim is read, not spent). The F2 hazard the
old rule guarded, a stale textarea, stays excluded because an orphan end never
reads the textarea diff.

Tests replay the WebKitGTK sequence: raw Latin and pinyin commit, CJK commits
once, same word in a later task commits again, a same-task re-fire does not,
a keystroke xterm already wrote is not doubled, an expired claim does not
block, and a started composition's ASCII result still commits. Mutating the
ownership check fails exactly the no-double case.

The flicker and misplaced candidate window reported in the same issue are
not addressed here.

Refs #1375
…ge (#1402)

A display equation with \tag{1} rendered its number on top of the last term.

KaTeX places the tag with position: absolute; right: 0 inside .katex-html,
which fills .katex-display. VMark's math previews are flex containers, so
.katex-display becomes a flex item and shrink-wraps to the equation; right: 0
then resolves to the equation's own edge.

This is #1376 again. That fix set width: 100% under .math-block-preview, a
class no renderer produces: every $$ block is a $$math$$ code block drawn by
codePreview into .code-block-preview.latex-preview (rendered) or
.code-block-live-preview (editing), both flex. Its test pinned the dead
selector and stayed green while users still saw the overlap.

The rule now lives unscoped in styles/katexFixes.css, which both main.tsx and
the export CSS bundle load, so every display-math container gets it. The
redundant scoped width in latex.css is removed. Centring is unchanged: KaTeX
centres display math with its own text-align: center.

displayMathTag.test.ts asserts the class instead of a selector: the unscoped
rule exists and is loaded by app and export; the flex containers are derived
from the renderers that create them; no stylesheet under src gives
.katex-display another width; no rule re-places the tag by hand. Against the
old CSS the unscoped-rule assertion failed.

Closes #1402
Refs #1376
The node-tier displayMathTag.test.ts can only read stylesheets, because jsdom
computes no layout. That is how #1376 shipped as fixed while users still saw
the overlap: its rule and its test both named a class nothing renders.

This real-WebKit test loads the stylesheets the app loads (katex.min.css,
katexFixes.css, code-preview.css), renders through the preview's own
renderLatex and sanitizeKatex, and measures inside both containers codePreview
creates (.code-block-preview.latex-preview and .code-block-live-preview): the
tag's right edge meets the container's content edge and its left edge clears
the equation.

The failure is constructed, not assumed: one case forces .katex-display back
to width: auto and asserts the probe sees the overlap, so a measurement that
always reported "at the edge" cannot make the other cases pass vacuously.

KaTeX 0.18 names the elements .katex-tag and .katex-base; the first run failed
loudly on the older .tag / .base selectors before measuring anything.

Refs #1402
Refs #1376
CI's lint:deps rejected the test at src/plugins/latex/: importing
plugins/codePreview/code-preview.css from the latex plugin is a cross-plugin
edge under the plugin-isolation rule.

The test measures codePreview's containers, and codePreview is the
fence-preview hub the rule licenses to import the latex plugin, so it now lives
beside code-preview.css and imports it relatively. Content is unchanged apart
from the header, which records why it lives there.

The test was committed after the local check:predelta run, and only a
hand-picked subset of gates saw it; lint:deps was not in that subset.

Refs #1402
@xiaolai
xiaolai merged commit af945bf into main Sep 13, 2026
18 checks passed
@xiaolai
xiaolai deleted the fix/1375-ime-orphan-ascii-commit branch September 13, 2026 13:04
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.

[Bug] latex数学公式不能正确渲染公式编号 \tag{}

1 participant