-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
feat(code-highlighter): add showLineNumber / wrapLongLines / showCopyButton props #2003
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
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -522,4 +522,82 @@ describe('CodeHighlighter', () => { | |
| process.env.NODE_ENV = originalEnv; | ||
| }); | ||
| }); | ||
|
|
||
| describe('flexible config', () => { | ||
| it('should show line numbers when showLineNumber is true', async () => { | ||
| const { container } = render( | ||
| <CodeHighlighter lang="javascript" showLineNumber> | ||
| {`console.log("test");`} | ||
| </CodeHighlighter>, | ||
| ); | ||
| await waitFor(() => { | ||
| expect(container.querySelector('pre')).toBeInTheDocument(); | ||
| }); | ||
| expect(container.querySelector('.linenumber')).toBeInTheDocument(); | ||
| }); | ||
|
|
||
| it('should not show line numbers by default', async () => { | ||
| const { container } = render( | ||
| <CodeHighlighter lang="javascript">{`console.log("test");`}</CodeHighlighter>, | ||
| ); | ||
| await waitFor(() => { | ||
| expect(container.querySelector('pre')).toBeInTheDocument(); | ||
| }); | ||
| expect(container.querySelector('.linenumber')).not.toBeInTheDocument(); | ||
| }); | ||
|
|
||
| it('should pass wrapLongLines to SyntaxHighlighter', async () => { | ||
| const { container } = render( | ||
| <CodeHighlighter lang="javascript" wrapLongLines> | ||
| {`console.log("test");`} | ||
| </CodeHighlighter>, | ||
| ); | ||
| await waitFor(() => { | ||
| expect(container.querySelector('code')).toBeInTheDocument(); | ||
| }); | ||
| // wrapLongLines sets whiteSpace: pre-wrap on the rendered code element | ||
| expect(container.querySelector('code')?.style.whiteSpace).toBe('pre-wrap'); | ||
| }); | ||
|
Comment on lines
+549
to
+560
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win 🧩 Analysis chain🏁 Script executed: #!/usr/bin/env bash
set -euo pipefail
rg -n -A14 -B4 'should pass wrapLongLines' \
packages/x/components/code-highlighter/__tests__/index.test.tsxRepository: ant-design/x Length of output: 931 🏁 Script executed: #!/usr/bin/env bash
set -euo pipefail
echo "== files =="
git ls-files packages/x/components/code-highlight | head -50
echo "== component outline =="
ast-grep outline packages/x/components/code-highlight -view expanded || true
echo "== relevant source snippets =="
for f in $(git ls-files packages/x/components/code-highlight | grep -E '\.(tsx|ts|jsx|js)$' | head -20); do
if rg -n "function CodeHighlighter|const CodeHighlighter|SyntaxHighlighter|wrapLongLines|fallback|Suspense|react-syntax-highlighter" "$f" >/dev/null; then
echo "--- $f ---"
rg -n -A30 -B30 "function CodeHighlighter|const CodeHighlighter|SyntaxHighlighter|wrapLongLines|fallback|Suspense|react-syntax-highlighter" "$f" | sed -n '1,220p'
fi
done
echo "== test imports and surrounding tests =="
sed -n '1,90p;510,580p' packages/x/components/code-highlight/__tests__/index.test.tsxRepository: ant-design/x Length of output: 529 🏁 Script executed: #!/usr/bin/env bash
set -euo pipefail
echo "== all code-highlight paths =="
git ls-files | grep -E '(^|/)code[-_]highlight' || true
echo "== exact test file =="
git ls-files | grep 'CodeHighlighter.*test\.tsx$' || true
git ls-files | grep 'index\.test\.tsx$' | grep -i 'highlight' || true
echo "== files matching CodeHighlighter =="
git ls-files | xargs rg -l "CodeHighlighter" || true
echo "== package directory snapshot =="
for d in $(git ls-files | sed -n 's#^packages/[^/]*$#&`#p`' | sort | head -50); do
true
done
git ls-files packages | grep code-highlight || trueRepository: ant-design/x Length of output: 3521 🏁 Script executed: #!/bin/bash
set -euo pipefail
echo "== CodeHighlighter.tsx size =="
wc -l packages/x/components/code-highlighter/CodeHighlighter.tsx
echo
echo "== CodeHighlighter.tsx outline =="
ast-grep outline packages/x/components/code-highlighter/CodeHighlighter.tsx --view expanded || true
echo
echo "== CodeHighlighter.tsx relevant lines =="
sed -n '1,260p' packages/x/components/code-highlighter/CodeHighlighter.tsx | cat -n
echo
echo "== Tests relevant section =="
sed -n '530,565p' packages/x/components/code-highlighter/__tests__/index.test.tsx | cat -nRepository: ant-design/x Length of output: 9625 🌐 Web query:
💡 Result: In react-syntax-highlighter, the wrapLongLines prop is a boolean used to control how code blocks handle long lines [1][2]. When set to true, it applies white-space: pre-wrap to the code element, allowing text to wrap within the container instead of overflowing [1][3]. When set to false (the default), it uses white-space: pre [1][2]. Key technical details and behaviors include: 1. Automatic Line Wrapping: Enabling wrapLongLines effectively overrides the need to manually apply white-space styling via CSS or codeTagProps [3]. It also forces each line of code to be wrapped in its own span element, similar to how wrapLines={true} behaves [3]. 2. Interaction with showLineNumbers: When both wrapLongLines and showLineNumbers are enabled, the library applies display: flex to the line elements to ensure line numbers remain correctly aligned with their corresponding code [3]. 3. Known Issues and Workarounds: - Flexbox Conflicts: Users have reported that the library's internal use of display: flex can sometimes interfere with custom styling provided via lineProps [4]. If you need to override these styles, it is often necessary to use more specific CSS or target the wrapper elements directly [4][5]. - Prism.js Inconsistencies: Some users have noted that wrapLongLines may not behave as expected with Prism.js in certain versions [6]. A common workaround for persistent wrapping issues is to force the style directly using the codeTagProps prop: codeTagProps={{ style: { whiteSpace: 'pre-wrap' } }} [6]. - Layout Alignment: When using wrapLongLines and showLineNumbers together, long lines may occasionally cause layout misalignment. Recent updates have introduced word-break: break-word and nested structures to help mitigate these visual issues [7]. Citations:
等待最终高亮 DOM 再检查
🤖 Prompt for AI AgentsSource: MCP tools |
||
|
|
||
| it('should show copy button by default', async () => { | ||
| const { container } = render( | ||
| <CodeHighlighter lang="javascript">{`console.log("test");`}</CodeHighlighter>, | ||
| ); | ||
| await waitFor(() => { | ||
| expect(container.querySelector('.ant-codeHighlighter-header')).toBeInTheDocument(); | ||
| }); | ||
| expect( | ||
| container.querySelector('.ant-codeHighlighter-header .ant-actions-copy'), | ||
| ).toBeInTheDocument(); | ||
| }); | ||
|
|
||
| it('should hide copy button when showCopyButton is false', async () => { | ||
| const { container } = render( | ||
| <CodeHighlighter lang="javascript" showCopyButton={false}> | ||
| {`console.log("test");`} | ||
| </CodeHighlighter>, | ||
| ); | ||
| await waitFor(() => { | ||
| expect(container.querySelector('.ant-codeHighlighter-header')).toBeInTheDocument(); | ||
| }); | ||
| expect( | ||
| container.querySelector('.ant-codeHighlighter-header .ant-actions-copy'), | ||
| ).not.toBeInTheDocument(); | ||
| }); | ||
|
|
||
| it('should not affect custom header when showCopyButton is false', async () => { | ||
| const { container } = render( | ||
| <CodeHighlighter | ||
| lang="javascript" | ||
| showCopyButton={false} | ||
| header={<div className="myCustomHeader">custom</div>} | ||
| > | ||
| {`console.log("test");`} | ||
| </CodeHighlighter>, | ||
| ); | ||
| await waitFor(() => { | ||
| expect(container.querySelector('.myCustomHeader')).toBeInTheDocument(); | ||
| }); | ||
| }); | ||
| }); | ||
| }); | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,53 @@ | ||
| import { CodeHighlighter } from '@ant-design/x'; | ||
| import React from 'react'; | ||
|
|
||
| const App: React.FC = () => { | ||
| const code = `import React from 'react'; | ||
| import { Button } from 'antd'; | ||
|
|
||
| const App = () => ( | ||
| <div> | ||
| <Button type="primary">Primary Button</Button> | ||
| </div> | ||
| ); | ||
|
|
||
| export default App;`; | ||
|
|
||
| const longLineCode = `const aVeryLongVariableName = someFunction(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10); | ||
| console.log(aVeryLongVariableName);`; | ||
|
|
||
| return ( | ||
| <div> | ||
| <h3 style={{ marginBottom: 8 }}>显示行号</h3> | ||
| <p style={{ marginBottom: 8, color: '#666' }}> | ||
| 通过 <code>showLineNumber</code> 显示代码行号。 | ||
| </p> | ||
| <CodeHighlighter lang="javascript" showLineNumber> | ||
| {code} | ||
| </CodeHighlighter> | ||
|
|
||
| <h3 style={{ margin: '8px 0' }}>自动换行</h3> | ||
| <p style={{ marginBottom: 8, color: '#666' }}> | ||
| 通过 <code>wrapLongLines</code> 让超长行自动换行,无需横向滚动。 | ||
| </p> | ||
| <CodeHighlighter lang="javascript" wrapLongLines> | ||
| {longLineCode} | ||
| </CodeHighlighter> | ||
|
|
||
| <h3 style={{ margin: '8px 0' }}>隐藏复制按钮</h3> | ||
| <p style={{ marginBottom: 8, color: '#666' }}> | ||
| 通过 <code>showCopyButton={'{false}'}</code> 隐藏默认 Header 中的复制按钮。 | ||
| </p> | ||
| <CodeHighlighter lang="javascript" showCopyButton={false}> | ||
| {code} | ||
| </CodeHighlighter> | ||
|
|
||
| <h3 style={{ margin: '8px 0' }}>组合使用</h3> | ||
| <CodeHighlighter lang="javascript" showLineNumber wrapLongLines showCopyButton={false}> | ||
| {longLineCode} | ||
| </CodeHighlighter> | ||
| </div> | ||
| ); | ||
| }; | ||
|
|
||
| export default App; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
Repository: ant-design/x
Length of output: 1051
🏁 Script executed:
Repository: ant-design/x
Length of output: 20968
🌐 Web query:
react-syntax-highlighter v16.1.0 wrapLongLines codeTagProps white-space pre-wrap pre💡 Result:
In react-syntax-highlighter, the wrapLongLines prop is the intended mechanism for controlling line wrapping, as it explicitly toggles the white-space CSS property on the code tag [1][2][3]. When wrapLongLines is set to true, the library automatically applies white-space: pre-wrap to the code element [1][3]. Conversely, when it is false (the default), it applies white-space: pre [3]. It is recommended to use the wrapLongLines prop instead of manually overriding white-space via codeTagProps [3]. Manually setting white-space: pre-wrap via codeTagProps may be overridden by the library's internal styling, which explicitly sets white-space: pre by default [3]. If you encounter issues where lines are not wrapping despite using wrapLongLines (especially when combined with showLineNumbers), it is often due to the internal structure of the generated code block, which may require additional CSS adjustments such as adding flex-wrap: wrap to the line-level elements [4].
Citations:
wrapLongLinesprop doesn't wrap long lines with Prism.js react-syntax-highlighter/react-syntax-highlighter#597让
Suspensefallback 遵守wrapLongLines。当前代码在
wrapLongLines={false}时仍使用whiteSpace: 'pre-wrap'作为 fallback;异步语言模块加载期间,fallback 会渲染换行,随后再切换为 react-syntax-highlighter 的pre样式。fallback 应与最终高亮使用相同的换行配置。修正建议
🤖 Prompt for AI Agents
Source: MCP tools