@@ -28,16 +28,22 @@ marked.use(
28
28
} )
29
29
) ;
30
30
31
- export function handleWrappedFencedCodeBlocks ( content : string ) {
31
+ interface ProcessedContent {
32
+ processedContent : string ;
33
+ fences : string [ ] ;
34
+ }
35
+
36
+ export function processNestedCodeBlocks ( content : string ) : ProcessedContent {
32
37
// Early exit if no code blocks
33
38
if ( content . split ( '```' ) . length < 3 ) {
34
- return content ;
39
+ return { processedContent : content , fences : [ ] } ;
35
40
}
36
41
37
42
const lines = content . split ( '\n' ) ;
38
43
const stack : string [ ] = [ ] ; // Stack of language tags to track nesting
39
44
let result = '' ;
40
45
let currentBlock : string [ ] = [ ] ;
46
+ const fences : string [ ] = [ ] ; // Store all fence info for later use
41
47
42
48
for ( const line of lines ) {
43
49
const strippedLine = line . trim ( ) ;
@@ -48,6 +54,7 @@ export function handleWrappedFencedCodeBlocks(content: string) {
48
54
const remainingContent = lines . slice ( lines . indexOf ( line ) + 1 ) . join ( '\n' ) ;
49
55
if ( remainingContent . includes ( '```' ) && remainingContent . split ( '```' ) . length > 2 ) {
50
56
stack . push ( lang ) ;
57
+ fences . push ( lang ) ; // Store fence info
51
58
result += '~~~' + lang + '\n' ;
52
59
} else {
53
60
result += line + '\n' ;
@@ -77,7 +84,10 @@ export function handleWrappedFencedCodeBlocks(content: string) {
77
84
}
78
85
}
79
86
80
- return result . trim ( ) ;
87
+ return {
88
+ processedContent : result . trim ( ) ,
89
+ fences
90
+ } ;
81
91
}
82
92
83
93
export function transformThinkingTags ( content : string ) {
@@ -103,15 +113,13 @@ export const ChatMessage: FC<Props> = ({ message }) => {
103
113
const processContent = async ( ) => {
104
114
try {
105
115
// Transform thinking tags before markdown parsing
106
- let processedContent = transformThinkingTags ( content ) ;
116
+ const processedContent = transformThinkingTags ( content ) ;
107
117
108
118
// Handle wrapped fenced code blocks
109
- processedContent = handleWrappedFencedCodeBlocks ( processedContent ) ;
110
-
111
- // Find start fences for codeblocks (hljs doesn't include paths like "```save PATH")
112
- const fences = [ ...processedContent . matchAll ( / ( ~ ~ ~ | ` ` ` ) [ ^ \n ] + / g) ] . map ( ( s : RegExpExecArray ) => s [ 0 ] . replace ( / ( ~ ~ ~ | ` ` ` ) / g, "" ) ) ;
119
+ // Process nested code blocks and collect fence info
120
+ const { processedContent : transformedContent , fences } = processNestedCodeBlocks ( processedContent ) ;
113
121
114
- let parsedResult = await marked . parse ( processedContent , {
122
+ let parsedResult = await marked . parse ( transformedContent , {
115
123
async : true ,
116
124
} ) ;
117
125
0 commit comments