- 将 messageArea.ts 拆分为多个独立模块 - 新增 messageRenderer.ts:消息渲染逻辑 - 新增 messageStyles.ts:样式定义 - 新增 questionHandler.ts:问题处理 - 新增 segmentRenderer.ts:分段渲染 - 新增 textFormatter.ts:文本格式化 - 新增 toolHelpers.ts:工具辅助函数
186 lines
6.9 KiB
TypeScript
186 lines
6.9 KiB
TypeScript
/**
|
||
* 消息区域模块
|
||
* 功能:消息区域入口,整合样式和脚本
|
||
* 依赖:messageStyles, toolHelpers, textFormatter, questionHandler, messageRenderer
|
||
* 使用场景:webview 内容生成
|
||
*/
|
||
|
||
import {
|
||
collapseIconSvg,
|
||
fileWriteIconSvg,
|
||
fileReadIconSvg,
|
||
fileDeleteIconSvg,
|
||
syntaxCheckIconSvg,
|
||
SearchCode,
|
||
saveKnowledgeIconSvg,
|
||
simulationIconSvg,
|
||
waveformIconSvg,
|
||
knowledgeLoadIconSvg,
|
||
stateTransitionIconSvg,
|
||
userQuestionIconSvg,
|
||
updateStageIconSvg,
|
||
successIconSvg,
|
||
} from "../constants/toolIcons";
|
||
import { getMessageAreaStyles } from "./messageStyles";
|
||
import { getQuestionHandlerScript } from "./questionHandler";
|
||
import { getMessageRendererScript } from "./messageRenderer";
|
||
import { getSegmentRendererScript } from "./segmentRenderer";
|
||
|
||
export function getMessageAreaContent(): string {
|
||
return `<div id="messages" class="messages"></div>`;
|
||
}
|
||
|
||
export { getMessageAreaStyles };
|
||
|
||
export function getMessageAreaScript(): string {
|
||
return `
|
||
const collapseIconSvg = \`${collapseIconSvg}\`;
|
||
const fileWriteIconSvg = \`${fileWriteIconSvg}\`;
|
||
const fileReadIconSvg = \`${fileReadIconSvg}\`;
|
||
const fileDeleteIconSvg = \`${fileDeleteIconSvg}\`;
|
||
const syntaxCheckIconSvg = \`${syntaxCheckIconSvg}\`;
|
||
const searchCodeIconSvg = \`${SearchCode}\`;
|
||
const saveKnowledgeIconSvg = \`${saveKnowledgeIconSvg}\`;
|
||
const simulationIconSvg = \`${simulationIconSvg}\`;
|
||
const waveformIconSvg = \`${waveformIconSvg}\`;
|
||
const knowledgeLoadIconSvg = \`${knowledgeLoadIconSvg}\`;
|
||
const stateTransitionIconSvg = \`${stateTransitionIconSvg}\`;
|
||
const userQuestionIconSvg = \`${userQuestionIconSvg}\`;
|
||
const updateStageIconSvg = \`${updateStageIconSvg}\`;
|
||
const successIconSvg = \`${successIconSvg}\`;
|
||
|
||
function getToolIcon(toolName) {
|
||
const iconMap = {
|
||
'file_read': fileReadIconSvg,
|
||
'file_write': fileWriteIconSvg,
|
||
'file_delete': fileDeleteIconSvg,
|
||
'file_list': searchCodeIconSvg,
|
||
'syntax_check': syntaxCheckIconSvg,
|
||
'simulation': simulationIconSvg,
|
||
'waveform_summary': waveformIconSvg,
|
||
'knowledge_save': saveKnowledgeIconSvg,
|
||
'knowledge_load': knowledgeLoadIconSvg,
|
||
'queryKnowledgeSummary': knowledgeLoadIconSvg,
|
||
'queryRules': knowledgeLoadIconSvg,
|
||
'setModule': fileWriteIconSvg,
|
||
'addSignal': fileWriteIconSvg,
|
||
'addSignalExample': fileWriteIconSvg,
|
||
'validateKnowledgeGraph': syntaxCheckIconSvg,
|
||
'querySignals': searchCodeIconSvg,
|
||
'addPlan': fileWriteIconSvg,
|
||
'addEdge': fileWriteIconSvg,
|
||
'showPlan': searchCodeIconSvg,
|
||
'addRule': fileWriteIconSvg,
|
||
'updateNode': fileWriteIconSvg,
|
||
'addStateTransition': stateTransitionIconSvg,
|
||
'askUser': userQuestionIconSvg,
|
||
'updatePhase': updateStageIconSvg,
|
||
'iverilog': successIconSvg,
|
||
};
|
||
return iconMap[toolName] || '';
|
||
}
|
||
|
||
function getToolDisplayName(toolName) {
|
||
const toolNameMap = {
|
||
'file_read': '已完成文件读取',
|
||
'file_write': '已完成文件写入',
|
||
'file_delete': '已完成文件删除',
|
||
'file_list': '已检索代码文件',
|
||
'syntax_check': '已完成语法检查',
|
||
'simulation': '已完成仿真',
|
||
'waveform_summary': '已完成波形分析',
|
||
'knowledge_save': '已保存知识库',
|
||
'knowledge_load': '已加载知识库',
|
||
'queryKnowledgeSummary': '已查询知识摘要',
|
||
'queryRules': '已查询规则',
|
||
'setModule': '已设置模块',
|
||
'addSignal': '信号分析完成',
|
||
'addSignalExample': '信号示例处理完成',
|
||
'validateKnowledgeGraph': '已验证知识图谱',
|
||
'querySignals': '已查询信号',
|
||
'addPlan': '已添加计划',
|
||
'addEdge': '已添加边',
|
||
'showPlan': '已显示计划',
|
||
'addRule': '已添加规则',
|
||
'updateNode': '已更新节点',
|
||
'addStateTransition': '已添加状态转换',
|
||
'spawnExplorer': '代码探索',
|
||
'spawnDebugger': '波形调试',
|
||
'askUser': '用户提问',
|
||
'updatePhase': '已更新阶段',
|
||
'iverilog': '已完成编译',
|
||
};
|
||
return toolNameMap[toolName] || toolName;
|
||
}
|
||
|
||
function parseMultiVcdPaths(toolResult) {
|
||
if (!toolResult) return [];
|
||
const result = String(toolResult);
|
||
const vcdListMatch = result.match(/VCD 文件列表:[\\s\\S]*?(?=\\n\\n|$)/);
|
||
if (!vcdListMatch) return [];
|
||
const paths = [];
|
||
const lineRegex = /- (\\w+): ([^\\n]+)/g;
|
||
let match;
|
||
while ((match = lineRegex.exec(vcdListMatch[0])) !== null) {
|
||
const name = match[1];
|
||
const pathOrError = match[2].trim();
|
||
if (!pathOrError.startsWith('失败')) {
|
||
paths.push({ name: name + '.vcd', path: pathOrError });
|
||
}
|
||
}
|
||
return paths;
|
||
}
|
||
|
||
function formatText(text) {
|
||
if (!text) return '';
|
||
let html = text;
|
||
const codeBlocks = [];
|
||
html = html.replace(/\`\`\`(\\w+)?\\n([\\s\\S]*?)\`\`\`/g, function(match, lang, code) {
|
||
const language = lang || 'plaintext';
|
||
const escapedCode = code.trim()
|
||
.replace(/&/g, '&')
|
||
.replace(/</g, '<')
|
||
.replace(/>/g, '>');
|
||
const placeholder = \`___CODE_BLOCK_\${codeBlocks.length}___\`;
|
||
codeBlocks.push('<pre><code class="language-' + language + '">' + escapedCode + '</code></pre>');
|
||
return placeholder;
|
||
});
|
||
const inlineCodes = [];
|
||
html = html.replace(/\`([^\`]+)\`/g, function(match, code) {
|
||
const escapedCode = code
|
||
.replace(/&/g, '&')
|
||
.replace(/</g, '<')
|
||
.replace(/>/g, '>');
|
||
const placeholder = \`___INLINE_CODE_\${inlineCodes.length}___\`;
|
||
inlineCodes.push('<code>' + escapedCode + '</code>');
|
||
return placeholder;
|
||
});
|
||
html = html
|
||
.replace(/&/g, '&')
|
||
.replace(/</g, '<')
|
||
.replace(/>/g, '>');
|
||
html = html.replace(/^### (.+)$/gm, '<h3>$1</h3>');
|
||
html = html.replace(/^## (.+)$/gm, '<h2>$1</h2>');
|
||
html = html.replace(/^# (.+)$/gm, '<h1>$1</h1>');
|
||
html = html.replace(/\\*\\*(.+?)\\*\\*/g, '<strong>$1</strong>');
|
||
html = html.replace(/\\*(.+?)\\*/g, '<em>$1</em>');
|
||
html = html.replace(/^[\\-\\*] (.+)$/gm, '<li>$1</li>');
|
||
html = html.replace(/(<li>.*<\\/li>\\n?)+/g, '<ul>$&</ul>');
|
||
html = html.replace(/^\\d+\\. (.+)$/gm, '<li>$1</li>');
|
||
html = html.replace(/\\[([^\\]]+)\\]\\(([^\\)]+)\\)/g, '<a href="$2" target="_blank">$1</a>');
|
||
html = html.replace(/\\n/g, '<br>');
|
||
codeBlocks.forEach((block, index) => {
|
||
html = html.replace(\`___CODE_BLOCK_\${index}___\`, block);
|
||
});
|
||
inlineCodes.forEach((code, index) => {
|
||
html = html.replace(\`___INLINE_CODE_\${index}___\`, code);
|
||
});
|
||
return html;
|
||
}
|
||
|
||
${getQuestionHandlerScript()}
|
||
${getMessageRendererScript()}
|
||
${getSegmentRendererScript()}
|
||
`;
|
||
}
|