fix(cli): support LaTeX-style arrows in markdown renderer

This commit is contained in:
Bryan Morgan
2026-02-08 14:49:40 -05:00
parent 4a48d7cf93
commit 3a2a72786c
3 changed files with 71 additions and 27 deletions

View File

@@ -1,25 +0,0 @@
/**
* @license
* Copyright 2025 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
import { getPlainTextLength } from './InlineMarkdownRenderer.js';
import { describe, it, expect } from 'vitest';
describe('getPlainTextLength', () => {
it.each([
['**Primary Go', 12],
['*Primary Go', 11],
['**Primary Go**', 10],
['*Primary Go*', 10],
['**', 2],
['*', 1],
['compile-time**', 14],
])(
'should measure markdown text length correctly for "%s"',
(input, expected) => {
expect(getPlainTextLength(input)).toBe(expected);
},
);
});

View File

@@ -0,0 +1,53 @@
/**
* @license
* Copyright 2025 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
import { describe, it, expect } from 'vitest';
import { RenderInline, getPlainTextLength } from './InlineMarkdownRenderer.js';
import { renderWithProviders } from '../../test-utils/render.js';
import { Text } from 'ink';
describe('InlineMarkdownRenderer', () => {
describe('getPlainTextLength', () => {
it.each([
['**Primary Go', 12],
['*Primary Go', 11],
['**Primary Go**', 10],
['*Primary Go*', 10],
['**', 2],
['*', 1],
['compile-time**', 14],
['$\\rightarrow$', 1],
['Sign Out $\\rightarrow$ Sign In', 18],
])(
'should measure markdown text length correctly for "%s"',
(input, expected) => {
expect(getPlainTextLength(input)).toBe(expected);
},
);
});
describe('<RenderInline />', () => {
it('renders LaTeX rightarrow correctly', () => {
const text = 'Sign Out $\\rightarrow$ Sign In';
const { lastFrame } = renderWithProviders(
<Text>
<RenderInline text={text} />
</Text>,
);
expect(lastFrame()).toContain('Sign Out → Sign In');
});
it('renders other LaTeX arrows correctly', () => {
const text = '$\\leftarrow$ $\\uparrow$ $\\downarrow$';
const { lastFrame } = renderWithProviders(
<Text>
<RenderInline text={text} />
</Text>,
);
expect(lastFrame()).toContain('← ↑ ↓');
});
});
});

View File

@@ -36,7 +36,7 @@ const RenderInlineInternal: React.FC<RenderInlineProps> = ({
const nodes: React.ReactNode[] = [];
let lastIndex = 0;
const inlineRegex =
/(\*\*.*?\*\*|\*.*?\*|_.*?_|~~.*?~~|\[.*?\]\(.*?\)|`+.+?`+|<u>.*?<\/u>|https?:\/\/\S+)/g;
/(\*\*.*?\*\*|\*.*?\*|_.*?_|~~.*?~~|\[.*?\]\(.*?\)|`+.+?`+|<u>.*?<\/u>|https?:\/\/\S+|\$\\[a-z]+\$)/g;
let match;
while ((match = inlineRegex.exec(text)) !== null) {
@@ -143,6 +143,21 @@ const RenderInlineInternal: React.FC<RenderInlineProps> = ({
{fullMatch}
</Text>
);
} else if (fullMatch.startsWith('$') && fullMatch.endsWith('$')) {
const latexMap: Record<string, string> = {
'$\\rightarrow$': '→',
'$\\leftarrow$': '←',
'$\\uparrow$': '↑',
'$\\downarrow$': '↓',
};
const replacement = latexMap[fullMatch];
if (replacement) {
renderedNode = (
<Text key={key} color={baseColor}>
{replacement}
</Text>
);
}
}
} catch (e) {
debugLogger.warn('Error parsing inline markdown part:', fullMatch, e);
@@ -184,6 +199,7 @@ export const getPlainTextLength = (text: string): number => {
.replace(/~~(.*?)~~/g, '$1')
.replace(/`(.*?)`/g, '$1')
.replace(/<u>(.*?)<\/u>/g, '$1')
.replace(/.*\[(.*?)\]\(.*\)/g, '$1');
.replace(/.*\[(.*?)\]\(.*\)/g, '$1')
.replace(/\$\\(rightarrow|leftarrow|uparrow|downarrow)\$/g, '→');
return stringWidth(cleanText);
};