(code, language)
| 248 | * @param {string} language - Language identifier from markdown fence (e.g., "javascript", "python") |
| 249 | */ |
| 250 | export async function highlightCodeBlock(code, language) { |
| 251 | if (!code) return ""; |
| 252 | |
| 253 | const themeId = settings?.value?.editorTheme || "one_dark"; |
| 254 | const langKey = (language || "text").toLowerCase(); |
| 255 | |
| 256 | const cacheKey = `block:${themeId}:${langKey}:${code}`; |
| 257 | if (highlightCache.has(cacheKey)) { |
| 258 | return highlightCache.get(cacheKey); |
| 259 | } |
| 260 | |
| 261 | try { |
| 262 | const parser = await getParserForLanguage(langKey); |
| 263 | if (parser) { |
| 264 | const tree = parser.parse(code); |
| 265 | let result = ""; |
| 266 | |
| 267 | highlightCode( |
| 268 | code, |
| 269 | tree, |
| 270 | classHighlighter, |
| 271 | (text, classes) => { |
| 272 | if (classes) { |
| 273 | result += `<span class="${classes}">${escapeHtml(text)}</span>`; |
| 274 | } else { |
| 275 | result += escapeHtml(text); |
| 276 | } |
| 277 | }, |
| 278 | () => { |
| 279 | result += "\n"; |
| 280 | }, |
| 281 | ); |
| 282 | |
| 283 | if (result) { |
| 284 | setCache(cacheKey, result); |
| 285 | return result; |
| 286 | } |
| 287 | } |
| 288 | } catch (e) { |
| 289 | console.warn("Code block highlighting failed for", language, e); |
| 290 | } |
| 291 | |
| 292 | const escaped = escapeHtml(code); |
| 293 | setCache(cacheKey, escaped); |
| 294 | return escaped; |
| 295 | } |
| 296 | |
| 297 | export function clearHighlightCache() { |
| 298 | highlightCache.clear(); |
no test coverage detected