import { Pipe, PipeTransform } from '@angular/core'; import { DomSanitizer, SafeHtml } from '@angular/platform-browser'; import { marked } from 'marked'; import Prism from 'prismjs'; // 导入需要的语言支持 import 'prismjs/components/prism-clike'; import 'prismjs/components/prism-markup'; import 'prismjs/components/prism-javascript'; import 'prismjs/components/prism-typescript'; import 'prismjs/components/prism-python'; import 'prismjs/components/prism-go'; import 'prismjs/components/prism-java'; import 'prismjs/components/prism-csharp'; import 'prismjs/components/prism-php'; import 'prismjs/components/prism-ruby'; import 'prismjs/components/prism-bash'; import 'prismjs/components/prism-sql'; import 'prismjs/components/prism-json'; import 'prismjs/components/prism-yaml'; import 'prismjs/components/prism-markdown'; @Pipe({ name: 'markdown', standalone: true }) export class MarkdownPipe implements PipeTransform { constructor(private sanitizer: DomSanitizer) {} transform(value: string): SafeHtml { if (!value) { return ''; } // 预处理:将标签替换为美化版本 const processedContent = this.preprocessTags(value); // 配置marked(使用基本配置) marked.setOptions({ gfm: true, breaks: true }); // 解析markdown let html = marked.parse(processedContent) as string; // 后处理:添加代码高亮和样式 html = this.postprocessCodeBlocks(html); // 安全注入HTML return this.sanitizer.bypassSecurityTrustHtml(html); } /** * 预处理:将文本标签替换为美化版本和可折叠区域 */ private preprocessTags(content: string): string { // 处理 [思考] 标签及其内容 content = this.processTagWithContent(content, '思考', '💭', 'thinking'); // 处理 [工具] 标签及其内容 content = this.processTagWithContent(content, '工具', '🛠️', 'tool'); // 处理 [错误] 标签 content = content.replace(/\[错误\]/g, '❌ 错误'); return content; } /** * 处理标签及其后的内容,转换为可折叠区域 */ private processTagWithContent(content: string, tagName: string, emoji: string, cssClass: string): string { // 正则表达式匹配 [标签] 及其后的内容(直到下一个标签或字符串结束) const pattern = new RegExp(`\\[${tagName}\\]\\s*([\\s\\S]*?)(?=\\n\\s*\\[|$)`, 'g'); return content.replace(pattern, (match, tagContent) => { // 清理内容前后的空白 const trimmedContent = tagContent.trim(); if (!trimmedContent) { return `
${emoji} ${tagName}
`; } return `
${emoji} ${tagName}${trimmedContent}
`; }); } /** * 后处理:添加代码高亮和样式 */ private postprocessCodeBlocks(html: string): string { // 使用正则表达式匹配代码块 const codeBlockRegex = /
([\s\S]*?)<\/code><\/pre>/gi;
    
    html = html.replace(codeBlockRegex, (match, lang, code) => {
      const language = lang || 'plaintext';
      
      try {
        // 使用Prism高亮代码
        const highlighted = Prism.highlight(code, Prism.languages[language] || Prism.languages['plaintext'], language);
        return `
${highlighted}
`; } catch (e) { // 如果高亮失败,返回原始代码块 return `
${code}
`; } }); return html; } }