Skip to content

Commit b1ebce5

Browse files
fazxesclaude
andcommitted
fix(editor): add syntax highlighting for .mjs, .cjs, .mts, .cts files
Root cause: Duplicate inline language map in use-chat-messages.ts was overriding the shared detection, falling back to 'text' for unknown extensions like .mjs. Changes: - Replace inline langMap with shared getLanguageFromPath() in use-chat-messages.ts - Add mjs/cjs/mts/cts to all language detection maps - Add mts/cts to Rust LSP detection (lsp/src/lib.rs) - Extend CodeMirror languages map with more aliases - Add typescriptreact/javascriptreact to status bar display names - Update language tab refresh on existing tab switch 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent b6cf5d1 commit b1ebce5

7 files changed

Lines changed: 145 additions & 41 deletions

File tree

‎apps/agent/src/components/editor/CodeMirrorEditor.tsx‎

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,22 +69,51 @@ const readOnlyCompartment = new Compartment();
6969
type LanguageFactory = () => Extension;
7070

7171
const languages: Record<string, LanguageFactory> = {
72+
// JavaScript variants (including ES modules .mjs/.cjs)
7273
javascript: () => javascript(),
74+
js: () => javascript(),
7375
javascriptreact: () => javascript({ jsx: true }),
7476
jsx: () => javascript({ jsx: true }),
77+
78+
// TypeScript variants (including .mts/.cts)
7579
typescript: () => javascript({ typescript: true }),
80+
ts: () => javascript({ typescript: true }),
7681
typescriptreact: () => javascript({ typescript: true, jsx: true }),
7782
tsx: () => javascript({ typescript: true, jsx: true }),
83+
84+
// Python
7885
python: () => python(),
86+
py: () => python(),
87+
88+
// Systems languages
7989
rust: () => rust(),
90+
rs: () => rust(),
8091
go: () => go(),
92+
93+
// Data formats
8194
json: () => json(),
95+
jsonc: () => json(),
96+
97+
// Web markup
8298
html: () => html(),
99+
htm: () => html(),
100+
xml: () => html(), // HTML parser handles XML reasonably
101+
102+
// Styles
83103
css: () => css(),
84104
scss: () => css(),
105+
sass: () => css(),
85106
less: () => css(),
107+
108+
// Documentation
86109
markdown: () => markdown(),
87110
md: () => markdown(),
111+
mdx: () => markdown(),
112+
113+
// Config files (use JSON for similar syntax or markdown for readable configs)
114+
yaml: () => markdown(), // YAML is readable like markdown
115+
yml: () => markdown(),
116+
toml: () => markdown(),
88117
};
89118

90119
// ============================================

‎apps/agent/src/components/layout/status-bar.tsx‎

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -44,18 +44,33 @@ function truncateBranch(branch: string, maxLength: number = MAX_BRANCH_LENGTH):
4444
*/
4545
function getLanguageDisplayName(language: string): string {
4646
const displayNames: Record<string, string> = {
47+
// TypeScript/JavaScript
4748
typescript: 'TypeScript',
49+
typescriptreact: 'TypeScript JSX',
4850
tsx: 'TypeScript JSX',
4951
javascript: 'JavaScript',
52+
javascriptreact: 'JavaScript JSX',
5053
jsx: 'JavaScript JSX',
54+
// Data formats
5155
json: 'JSON',
56+
jsonc: 'JSON',
57+
// Markup
5258
markdown: 'Markdown',
59+
mdx: 'Markdown',
60+
html: 'HTML',
61+
xml: 'XML',
62+
svg: 'SVG',
63+
// Styles
5364
css: 'CSS',
5465
scss: 'SCSS',
66+
sass: 'SCSS',
5567
less: 'Less',
56-
html: 'HTML',
57-
xml: 'XML',
68+
// Config
5869
yaml: 'YAML',
70+
yml: 'YAML',
71+
toml: 'TOML',
72+
ini: 'INI',
73+
// Languages
5974
python: 'Python',
6075
ruby: 'Ruby',
6176
go: 'Go',
@@ -67,19 +82,25 @@ function getLanguageDisplayName(language: string): string {
6782
php: 'PHP',
6883
swift: 'Swift',
6984
kotlin: 'Kotlin',
85+
scala: 'Scala',
86+
// Shell
7087
bash: 'Shell Script',
88+
shell: 'Shell Script',
89+
sh: 'Shell Script',
90+
zsh: 'Shell Script',
91+
// Other
7192
sql: 'SQL',
7293
graphql: 'GraphQL',
7394
vue: 'Vue',
7495
svelte: 'Svelte',
75-
toml: 'TOML',
76-
ini: 'INI',
7796
dockerfile: 'Dockerfile',
7897
makefile: 'Makefile',
7998
dotenv: 'Environment',
99+
// Plain text variants
80100
plaintext: 'Plain Text',
101+
text: 'Plain Text',
81102
};
82-
return displayNames[language] ?? language;
103+
return displayNames[language.toLowerCase()] ?? language;
83104
}
84105

85106
/**

‎apps/agent/src/hooks/use-chat-messages.ts‎

Lines changed: 2 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -648,31 +648,8 @@ export function useChatMessages(options: UseChatMessagesOptions = {}): UseChatMe
648648
break;
649649

650650
case 'file:content': {
651-
const ext = message.path.split('.').pop()?.toLowerCase() ?? '';
652-
const langMap: Record<string, string> = {
653-
ts: 'typescript',
654-
tsx: 'tsx',
655-
js: 'javascript',
656-
jsx: 'jsx',
657-
css: 'css',
658-
scss: 'scss',
659-
less: 'less',
660-
html: 'html',
661-
json: 'json',
662-
md: 'markdown',
663-
py: 'python',
664-
rs: 'rust',
665-
go: 'go',
666-
java: 'java',
667-
c: 'c',
668-
cpp: 'cpp',
669-
h: 'c',
670-
sh: 'bash',
671-
yml: 'yaml',
672-
yaml: 'yaml',
673-
xml: 'xml',
674-
};
675-
const language = langMap[ext] ?? 'text';
651+
// Use shared language detection (supports mjs, cjs, mts, cts, etc.)
652+
const language = getLanguageFromPath(message.path);
676653
const fileViewerStore = useFileViewerStore.getState();
677654
fileViewerStore.setFileContent(message.path, message.content, language);
678655
break;

‎apps/agent/src/lib/diff-utils.ts‎

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,43 +53,65 @@ export function getLanguageFromPath(filePath: string): string {
5353
const extension = filePath.split('.').pop()?.toLowerCase() ?? '';
5454

5555
const languageMap: Record<string, string> = {
56+
// TypeScript variants
5657
ts: 'typescript',
57-
tsx: 'typescript',
58+
tsx: 'typescriptreact',
59+
mts: 'typescript',
60+
cts: 'typescript',
61+
// JavaScript variants
5862
js: 'javascript',
59-
jsx: 'javascript',
63+
jsx: 'javascriptreact',
6064
mjs: 'javascript',
6165
cjs: 'javascript',
66+
// Languages
6267
py: 'python',
68+
pyw: 'python',
69+
pyi: 'python',
6370
rb: 'ruby',
6471
go: 'go',
6572
rs: 'rust',
6673
java: 'java',
6774
kt: 'kotlin',
75+
kts: 'kotlin',
6876
c: 'c',
6977
cpp: 'cpp',
78+
cc: 'cpp',
79+
cxx: 'cpp',
7080
h: 'c',
7181
hpp: 'cpp',
82+
hxx: 'cpp',
7283
cs: 'csharp',
7384
php: 'php',
7485
swift: 'swift',
7586
scala: 'scala',
7687
r: 'r',
7788
sql: 'sql',
89+
// Data formats
7890
json: 'json',
91+
jsonc: 'json',
7992
yaml: 'yaml',
8093
yml: 'yaml',
8194
xml: 'xml',
95+
svg: 'xml',
96+
// Web
8297
html: 'html',
8398
htm: 'html',
99+
// Styles
84100
css: 'css',
85101
scss: 'scss',
102+
sass: 'scss',
86103
less: 'less',
104+
// Docs
87105
md: 'markdown',
106+
mdx: 'markdown',
88107
markdown: 'markdown',
108+
// Shell
89109
sh: 'shell',
90110
bash: 'shell',
91111
zsh: 'shell',
112+
fish: 'shell',
92113
ps1: 'powershell',
114+
// Config
93115
dockerfile: 'dockerfile',
94116
makefile: 'makefile',
95117
toml: 'toml',

‎apps/agent/src/stores/file-viewer-store.ts‎

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -110,41 +110,69 @@ type FileViewerStore = FileViewerState & FileViewerActions;
110110
export function getLanguageFromPath(path: string): string {
111111
const ext = path.split('.').pop()?.toLowerCase() ?? '';
112112
const languageMap: Record<string, string> = {
113+
// TypeScript variants
113114
ts: 'typescript',
114-
tsx: 'tsx',
115+
tsx: 'typescriptreact',
116+
mts: 'typescript',
117+
cts: 'typescript',
118+
// JavaScript variants
115119
js: 'javascript',
116-
jsx: 'jsx',
120+
jsx: 'javascriptreact',
121+
mjs: 'javascript',
122+
cjs: 'javascript',
123+
// Data formats
117124
json: 'json',
125+
jsonc: 'json',
126+
json5: 'json',
127+
// Markup & docs
118128
md: 'markdown',
129+
mdx: 'markdown',
130+
// Styles
119131
css: 'css',
120132
scss: 'scss',
133+
sass: 'scss',
121134
less: 'less',
135+
// Web
122136
html: 'html',
137+
htm: 'html',
123138
xml: 'xml',
139+
svg: 'xml',
140+
// Config
124141
yaml: 'yaml',
125142
yml: 'yaml',
143+
toml: 'toml',
144+
ini: 'ini',
145+
// Languages
126146
py: 'python',
147+
pyw: 'python',
148+
pyi: 'python',
127149
rb: 'ruby',
128150
go: 'go',
129151
rs: 'rust',
130152
java: 'java',
131153
c: 'c',
132154
cpp: 'cpp',
155+
cc: 'cpp',
156+
cxx: 'cpp',
133157
h: 'c',
134158
hpp: 'cpp',
159+
hxx: 'cpp',
135160
cs: 'csharp',
136161
php: 'php',
137162
swift: 'swift',
138163
kt: 'kotlin',
164+
kts: 'kotlin',
165+
// Shell
139166
sh: 'bash',
140167
bash: 'bash',
141168
zsh: 'bash',
169+
fish: 'bash',
170+
// Other
142171
sql: 'sql',
143172
graphql: 'graphql',
173+
gql: 'graphql',
144174
vue: 'vue',
145175
svelte: 'svelte',
146-
toml: 'toml',
147-
ini: 'ini',
148176
dockerfile: 'dockerfile',
149177
makefile: 'makefile',
150178
};
@@ -178,9 +206,11 @@ export const useFileViewerStore = create<FileViewerStore>()(
178206
const existingTab = state.openTabs.find((tab) => tab.path === path);
179207

180208
if (existingTab) {
181-
// Just switch to existing tab, reset to file view mode
209+
// Switch to existing tab, reset to file view mode
182210
state.activeTabPath = path;
183211
existingTab.viewMode = 'file';
212+
// Update language in case detection was improved
213+
existingTab.language = getLanguageFromPath(path);
184214
} else {
185215
// Create new tab
186216
const fileContent = content ?? '';

‎apps/agent/src/types/file.ts‎

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -255,35 +255,60 @@ export function isCodeFile(path: string): boolean {
255255

256256
export function getLanguageFromExtension(extension: string): string | undefined {
257257
const languageMap: Record<string, string> = {
258+
// JavaScript variants
258259
js: 'javascript',
259-
jsx: 'javascript',
260+
jsx: 'javascriptreact',
261+
mjs: 'javascript',
262+
cjs: 'javascript',
263+
// TypeScript variants
260264
ts: 'typescript',
261-
tsx: 'typescript',
265+
tsx: 'typescriptreact',
266+
mts: 'typescript',
267+
cts: 'typescript',
268+
// Languages
262269
py: 'python',
270+
pyw: 'python',
271+
pyi: 'python',
263272
java: 'java',
264273
c: 'c',
265274
cpp: 'cpp',
275+
cc: 'cpp',
276+
cxx: 'cpp',
277+
h: 'c',
278+
hpp: 'cpp',
266279
cs: 'csharp',
267280
go: 'go',
268281
rs: 'rust',
269282
rb: 'ruby',
270283
php: 'php',
271284
swift: 'swift',
272285
kt: 'kotlin',
286+
kts: 'kotlin',
273287
scala: 'scala',
288+
// Web
274289
html: 'html',
290+
htm: 'html',
291+
// Styles
275292
css: 'css',
276293
scss: 'scss',
277-
sass: 'sass',
294+
sass: 'scss',
278295
less: 'less',
296+
// Data formats
279297
json: 'json',
298+
jsonc: 'json',
280299
xml: 'xml',
300+
svg: 'xml',
281301
yaml: 'yaml',
282302
yml: 'yaml',
303+
toml: 'toml',
304+
// Docs
283305
md: 'markdown',
306+
mdx: 'markdown',
307+
// Shell
284308
sh: 'bash',
285309
bash: 'bash',
286310
zsh: 'bash',
311+
fish: 'bash',
287312
};
288313

289314
return languageMap[extension.toLowerCase()];

‎crates/common/lsp/src/lib.rs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -311,7 +311,7 @@ pub fn language_from_path(path: &Path) -> Option<&'static str> {
311311
// Rust
312312
Some("rs") => Some("rust"),
313313
// TypeScript/JavaScript
314-
Some("ts") => Some("typescript"),
314+
Some("ts" | "mts" | "cts") => Some("typescript"),
315315
Some("tsx") => Some("typescriptreact"),
316316
Some("js" | "mjs" | "cjs") => Some("javascript"),
317317
Some("jsx") => Some("javascriptreact"),

0 commit comments

Comments
 (0)