@@ -104,12 +104,27 @@ const BLOCK_MATH_PAIR = /\$\$([\s\S]+?)\$\$/g;
104104const HAS_ENV = / \\ (?: b e g i n | e n d ) \{ / ;
105105
106106function rewriteMath ( segment : string ) : string {
107- return segment . replace ( BLOCK_MATH_PAIR , ( full , inner : string ) => {
107+ return segment . replace ( BLOCK_MATH_PAIR , ( full , inner : string , offset : number ) => {
108108 const hasNewline = inner . includes ( '\n' ) ;
109109 const hasEnv = HAS_ENV . test ( inner ) ;
110- if ( ! hasNewline && ! hasEnv ) {
111- // Single-line, no env — leave as-is. May be inline display, which
112- // is its own quirk but not what this preprocessor is for.
110+
111+ // "Alone on its own line" — preceded by start-of-segment or `\n`
112+ // (allowing trailing spaces in between), and followed by `\n` or
113+ // end-of-segment. This is what the user intends when they paste
114+ // `$$ E = mc^2 $$` on a line by itself — remark-math otherwise
115+ // treats compact `$$x$$` as inline display, no `.katex-display`
116+ // gets emitted, and our math-align toggle has nothing to act on.
117+ //
118+ // We only normalize the alone-on-line case so legitimate inline
119+ // uses like `prefix text $$x$$ suffix text` stay unchanged.
120+ const beforeText = segment . slice ( 0 , offset ) ;
121+ const afterText = segment . slice ( offset + full . length ) ;
122+ const aloneOnLine = / ( ^ | \n ) [ \t ] * $ / . test ( beforeText ) && / ^ [ \t ] * ( \n | $ ) / . test ( afterText ) ;
123+
124+ if ( ! hasNewline && ! hasEnv && ! aloneOnLine ) {
125+ // Mid-line, single-line `$$x$$` — leave as-is. Treated as inline
126+ // display by remark-math (which is its own quirk, but not the
127+ // preprocessor's job).
113128 return full ;
114129 }
115130 // Strip whitespace at the boundaries; remark-math is whitespace-strict
0 commit comments