Fix: Missing or inconsistent syntax highlighting across UI components (#3656)

* fix: Missing or inconsistent syntax highlighting across UI components

- Change file listings to use 'shellsession' for terminal-like highlighting
- Use 'markdown' for code definitions and instructions
- Add file extension-based language detection for new files
- Ensure consistent 'diff' highlighting for all diff content
- Use 'xml' language for error messages
- Make language property required in CodeAccordian
- Set default fallback to 'txt' instead of undefined

Fixes: #3655
Signed-off-by: Eric Wheeler <roo-code@z.ewheeler.org>

* chore: make language property required in CodeBlock

- Updated CodeBlockProps interface to make language property required
- Updated mock implementation to match the interface change
- Ensured CodeAccordian always provides a fallback language value

Signed-off-by: Eric Wheeler <roo-code@z.ewheeler.org>

---------

Signed-off-by: Eric Wheeler <roo-code@z.ewheeler.org>
Co-authored-by: Eric Wheeler <roo-code@z.ewheeler.org>
This commit is contained in:
KJ7LNW 2025-05-20 19:29:57 -07:00 committed by GitHub
parent ad9c87a04f
commit 9317765fb1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 54 additions and 58 deletions

View file

@ -13,6 +13,7 @@ import { useExtensionState } from "@src/context/ExtensionStateContext"
import { findMatchingResourceOrTemplate } from "@src/utils/mcp"
import { vscode } from "@src/utils/vscode"
import { removeLeadingNonAlphanumeric } from "@src/utils/removeLeadingNonAlphanumeric"
import { getLanguageFromPath } from "@src/utils/getLanguageFromPath"
import { Button } from "@src/components/ui"
import { ToolUseBlock, ToolUseBlockHeader } from "../common/ToolUseBlock"
@ -293,7 +294,7 @@ export const ChatRowContent = ({
<CodeAccordian
path={tool.path}
code={tool.content ?? tool.diff}
language={tool.tool === "appliedDiff" ? "diff" : undefined}
language="diff"
progressStatus={message.progressStatus}
isLoading={message.partial}
isExpanded={isExpanded}
@ -341,6 +342,7 @@ export const ChatRowContent = ({
<CodeAccordian
path={tool.path}
code={tool.diff}
language="diff"
progressStatus={message.progressStatus}
isLoading={message.partial}
isExpanded={isExpanded}
@ -358,6 +360,7 @@ export const ChatRowContent = ({
<CodeAccordian
path={tool.path}
code={tool.content}
language={getLanguageFromPath(tool.path || "") || "log"}
isLoading={message.partial}
isExpanded={isExpanded}
onToggleExpand={onToggleExpand}
@ -403,6 +406,7 @@ export const ChatRowContent = ({
</div>
<CodeAccordian
code={tool.content}
language="markdown"
isLoading={message.partial}
isExpanded={isExpanded}
onToggleExpand={onToggleExpand}
@ -443,7 +447,7 @@ export const ChatRowContent = ({
<CodeAccordian
path={tool.path}
code={tool.content}
language="shell-session"
language="shellsession"
isExpanded={isExpanded}
onToggleExpand={onToggleExpand}
/>
@ -463,6 +467,7 @@ export const ChatRowContent = ({
<CodeAccordian
path={tool.path}
code={tool.content}
language="markdown"
isExpanded={isExpanded}
onToggleExpand={onToggleExpand}
/>
@ -492,7 +497,7 @@ export const ChatRowContent = ({
<CodeAccordian
path={tool.path! + (tool.filePattern ? `/(${tool.filePattern})` : "")}
code={tool.content}
language="log"
language="shellsession"
isExpanded={isExpanded}
onToggleExpand={onToggleExpand}
/>
@ -712,7 +717,7 @@ export const ChatRowContent = ({
backgroundColor: "var(--vscode-editor-background)",
borderTop: "none",
}}>
<CodeBlock source={`${"```"}plaintext\n${message.text || ""}\n${"```"}`} />
<CodeBlock source={message.text || ""} language="xml" />
</div>
)}
</div>

View file

@ -11,7 +11,7 @@ import CodeBlock from "./CodeBlock"
interface CodeAccordianProps {
path?: string
code?: string
language?: string | undefined
language: string
progressStatus?: ToolProgressStatus
isLoading?: boolean
isExpanded: boolean
@ -29,7 +29,7 @@ const CodeAccordian = ({
isFeedback,
onToggleExpand,
}: CodeAccordianProps) => {
const inferredLanguage = useMemo(() => language ?? (path ? getLanguageFromPath(path) : undefined), [path, language])
const inferredLanguage = useMemo(() => language ?? (path ? getLanguageFromPath(path) : "txt"), [path, language])
const source = useMemo(() => code.trim(), [code])
const hasHeader = Boolean(path || isFeedback)

View file

@ -30,7 +30,7 @@ minWidth: "max-content",
interface CodeBlockProps {
source?: string
rawSource?: string // Add rawSource prop for copying raw text
language?: string
language: string
preStyle?: React.CSSProperties
initialWordWrap?: boolean
collapsedHeight?: number
@ -637,57 +637,48 @@ const CodeBlock = memo(
ref={copyButtonWrapperRef}
onMouseOver={() => updateCodeBlockButtonPosition()}
style={{ gap: 0 }}>
{language && (
<LanguageSelect
value={currentLanguage}
style={{
width: `calc(${currentLanguage?.length || 0}ch + 9px)`,
}}
onClick={(e) => {
e.currentTarget.focus()
}}
onChange={(e) => {
const newLang = normalizeLanguage(e.target.value)
userChangedLanguageRef.current = true
setCurrentLanguage(newLang)
if (onLanguageChange) {
onLanguageChange(newLang)
}
}}>
{
// Display original language at top of list for quick selection
language && (
<option
value={normalizeLanguage(language)}
style={{ fontWeight: "bold", textAlign: "left", fontSize: "1.2em" }}>
{normalizeLanguage(language)}
</option>
)
<LanguageSelect
value={currentLanguage}
style={{
width: `calc(${currentLanguage?.length || 0}ch + 9px)`,
}}
onClick={(e) => {
e.currentTarget.focus()
}}
onChange={(e) => {
const newLang = normalizeLanguage(e.target.value)
userChangedLanguageRef.current = true
setCurrentLanguage(newLang)
if (onLanguageChange) {
onLanguageChange(newLang)
}
{
// Display all available languages in alphabetical order
Object.keys(bundledLanguages)
.sort()
.map((lang) => {
const normalizedLang = normalizeLanguage(lang)
return (
<option
key={normalizedLang}
value={normalizedLang}
style={{
fontWeight:
normalizedLang === currentLanguage ? "bold" : "normal",
textAlign: "left",
fontSize:
normalizedLang === currentLanguage ? "1.2em" : "inherit",
}}>
{normalizedLang}
</option>
)
})
}
</LanguageSelect>
)}
}}>
<option
value={normalizeLanguage(language)}
style={{ fontWeight: "bold", textAlign: "left", fontSize: "1.2em" }}>
{normalizeLanguage(language)}
</option>
{
// Display all available languages in alphabetical order
Object.keys(bundledLanguages)
.sort()
.map((lang) => {
const normalizedLang = normalizeLanguage(lang)
return (
<option
key={normalizedLang}
value={normalizedLang}
style={{
fontWeight: normalizedLang === currentLanguage ? "bold" : "normal",
textAlign: "left",
fontSize: normalizedLang === currentLanguage ? "1.2em" : "inherit",
}}>
{normalizedLang}
</option>
)
})
}
</LanguageSelect>
{showCollapseButton && (
<CodeBlockButton
onClick={() => {

View file

@ -2,7 +2,7 @@ import * as React from "react"
interface CodeBlockProps {
children?: React.ReactNode
language?: string
language: string
}
const CodeBlock: React.FC<CodeBlockProps> = () => <div data-testid="mock-code-block">Mocked Code Block</div>