Skip to content

Commit 1b55d1a

Browse files
Copilotdwjohnston
andcommitted
Fix syntax highlighting for React/TypeScript files by adding language detection
Co-authored-by: dwjohnston <2467377+dwjohnston@users.noreply.github.com>
1 parent 2754b7b commit 1b55d1a

4 files changed

Lines changed: 164 additions & 4 deletions

File tree

src/library/GithubPermalink/GithubPermalinkBase.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { SyntaxHighlight } from "../SyntaxHighlight/SyntaxHighlight";
66
import { formatForLineExclusions } from "./formatLineExclusions";
77
import { CopySvg } from "../images/CopySvg";
88
import { CopyButton } from "../common/CopyButton/CopyButton";
9+
import { getLanguageFromPath } from "../utils/getLanguageFromPath";
910

1011
export type GithubPermalinkBaseProps = {
1112
className?: string;
@@ -26,6 +27,7 @@ export function GithubPermalinkBase(props: GithubPermalinkBaseProps) {
2627
if (data.status === "ok") {
2728

2829
const formatedLineExclusions = formatForLineExclusions(data, excludeLines);
30+
const language = getLanguageFromPath(data.path);
2931

3032
const clipboard = formatedLineExclusions.reduce((acc, cur) => {
3133
if (cur.isExclude) {
@@ -41,11 +43,11 @@ export function GithubPermalinkBase(props: GithubPermalinkBaseProps) {
4143

4244
{formatedLineExclusions.map((v) => {
4345
if (v.isExclude) {
44-
return <SyntaxHighlight className="hide-line-numbers" text={excludeText} startingLineNumber={v.from} key={v.from}/>
46+
return <SyntaxHighlight className="hide-line-numbers" text={excludeText} startingLineNumber={v.from} language={language} key={v.from}/>
4547

4648
}
4749

48-
return <SyntaxHighlight text={v.lines.join("\n")} startingLineNumber={v.from} key={v.from}/>
50+
return <SyntaxHighlight text={v.lines.join("\n")} startingLineNumber={v.from} language={language} key={v.from}/>
4951

5052
})}
5153

src/library/SyntaxHighlight/SyntaxHighlight.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -126,9 +126,10 @@ export function SyntaxHighlight(props: {
126126
text: string;
127127
startingLineNumber?: number;
128128
className?: string;
129+
language?: string;
129130
}) {
130131

131-
const { startingLineNumber, text, className } = props;
132+
const { startingLineNumber, text, className, language = "javascript" } = props;
132133

133134
const isDarkMode = useMediaQuery({ query: "(prefers-color-scheme: dark)" })
134135

@@ -141,6 +142,6 @@ export function SyntaxHighlight(props: {
141142
}, [])
142143

143144

144-
return <ReactSyntaxHighlighter className={className} style={ready ? isDarkMode ? tomorrowNight : github : noTheme} language="javascript" showLineNumbers={startingLineNumber !== undefined} startingLineNumber={startingLineNumber}>{text}</ReactSyntaxHighlighter>
145+
return <ReactSyntaxHighlighter className={className} style={ready ? isDarkMode ? tomorrowNight : github : noTheme} language={language} showLineNumbers={startingLineNumber !== undefined} startingLineNumber={startingLineNumber}>{text}</ReactSyntaxHighlighter>
145146

146147
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import { describe, it, expect } from 'vitest';
2+
import { getLanguageFromPath } from './getLanguageFromPath';
3+
4+
describe('getLanguageFromPath', () => {
5+
it('should return typescript for .tsx files', () => {
6+
expect(getLanguageFromPath('ReactRenders3.tsx')).toBe('typescript');
7+
});
8+
9+
it('should return typescript for .ts files', () => {
10+
expect(getLanguageFromPath('component.ts')).toBe('typescript');
11+
});
12+
13+
it('should return javascript for .js files', () => {
14+
expect(getLanguageFromPath('script.js')).toBe('javascript');
15+
});
16+
17+
it('should return javascript for .jsx files', () => {
18+
expect(getLanguageFromPath('component.jsx')).toBe('javascript');
19+
});
20+
21+
it('should return python for .py files', () => {
22+
expect(getLanguageFromPath('script.py')).toBe('python');
23+
});
24+
25+
it('should return go for .go files', () => {
26+
expect(getLanguageFromPath('main.go')).toBe('go');
27+
});
28+
29+
it('should return html for .html files', () => {
30+
expect(getLanguageFromPath('index.html')).toBe('html');
31+
});
32+
33+
it('should return css for .css files', () => {
34+
expect(getLanguageFromPath('styles.css')).toBe('css');
35+
});
36+
37+
it('should return json for .json files', () => {
38+
expect(getLanguageFromPath('package.json')).toBe('json');
39+
});
40+
41+
it('should return markdown for .md files', () => {
42+
expect(getLanguageFromPath('README.md')).toBe('markdown');
43+
});
44+
45+
it('should return yaml for .yaml files', () => {
46+
expect(getLanguageFromPath('config.yaml')).toBe('yaml');
47+
});
48+
49+
it('should return yaml for .yml files', () => {
50+
expect(getLanguageFromPath('config.yml')).toBe('yaml');
51+
});
52+
53+
it('should return javascript as fallback for unknown extensions', () => {
54+
expect(getLanguageFromPath('file.unknown')).toBe('javascript');
55+
});
56+
57+
it('should return javascript as fallback for files without extension', () => {
58+
expect(getLanguageFromPath('README')).toBe('javascript');
59+
});
60+
61+
it('should handle paths with multiple dots', () => {
62+
expect(getLanguageFromPath('src/components/MyComponent.tsx')).toBe('typescript');
63+
});
64+
65+
it('should handle case insensitive extensions', () => {
66+
expect(getLanguageFromPath('Component.TSX')).toBe('typescript');
67+
expect(getLanguageFromPath('Script.JS')).toBe('javascript');
68+
});
69+
});
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
/**
2+
* Maps file extensions to syntax highlighting languages supported by react-syntax-highlighter
3+
*/
4+
export function getLanguageFromPath(filePath: string): string {
5+
const extension = filePath.split('.').pop()?.toLowerCase();
6+
7+
switch (extension) {
8+
case 'js':
9+
case 'jsx':
10+
case 'mjs':
11+
case 'cjs':
12+
return 'javascript';
13+
case 'ts':
14+
case 'tsx':
15+
return 'typescript';
16+
case 'py':
17+
case 'python':
18+
return 'python';
19+
case 'java':
20+
return 'java';
21+
case 'cpp':
22+
case 'cc':
23+
case 'cxx':
24+
case 'c++':
25+
return 'cpp';
26+
case 'c':
27+
case 'h':
28+
return 'c';
29+
case 'cs':
30+
return 'csharp';
31+
case 'php':
32+
return 'php';
33+
case 'rb':
34+
case 'ruby':
35+
return 'ruby';
36+
case 'go':
37+
return 'go';
38+
case 'rs':
39+
return 'rust';
40+
case 'swift':
41+
return 'swift';
42+
case 'kt':
43+
case 'kts':
44+
return 'kotlin';
45+
case 'scala':
46+
return 'scala';
47+
case 'sh':
48+
case 'bash':
49+
return 'bash';
50+
case 'ps1':
51+
return 'powershell';
52+
case 'sql':
53+
return 'sql';
54+
case 'html':
55+
case 'htm':
56+
return 'html';
57+
case 'css':
58+
return 'css';
59+
case 'scss':
60+
case 'sass':
61+
return 'scss';
62+
case 'json':
63+
return 'json';
64+
case 'xml':
65+
return 'xml';
66+
case 'yaml':
67+
case 'yml':
68+
return 'yaml';
69+
case 'md':
70+
case 'markdown':
71+
return 'markdown';
72+
case 'dockerfile':
73+
return 'dockerfile';
74+
case 'r':
75+
return 'r';
76+
case 'dart':
77+
return 'dart';
78+
case 'lua':
79+
return 'lua';
80+
case 'perl':
81+
case 'pl':
82+
return 'perl';
83+
case 'vim':
84+
return 'vim';
85+
default:
86+
return 'javascript'; // fallback to javascript for unknown extensions
87+
}
88+
}

0 commit comments

Comments
 (0)