let selectedCodeForContext = ''; let contextFilePath = ''; // 存储当前上下文文件路径 const vscode = acquireVsCodeApi(); document.addEventListener('DOMContentLoaded', () => { const chatForm = document.getElementById('chat-form'); const userInput = document.getElementById('user-input'); const chatBox = document.getElementById('chat-box'); const loading = document.getElementById('loading'); // 初始化隐藏工作区 const workspaceContainer = document.querySelector('.workspace-container'); if (workspaceContainer) { workspaceContainer.style.display = 'none'; } chatForm.addEventListener('submit', (e) => { e.preventDefault(); const text = userInput.value.trim(); if (!text) return; vscode.postMessage({ command: 'ask', text, fileContent: selectedCodeForContext, fileContentPath: contextFilePath // 添加文件路径 }); // addMessage('user', text); showLoading(); userInput.value = ''; }); // 判断内容是否为 Markdown(简单判断) function isMarkdown(content) { if (!content || content.trim() === '') return false; const markdownPatterns = [ /^#/m, // 标题 # /\*\*[^*]+\*\*/g, // 加粗 **text** /__[^_]+__/g, // 加粗 __text__ /^- /gm, // 无序列表 /^\* /gm, // 无序列表 /^\d+\. /gm, // 有序列表 /```/g // 代码块 ]; return markdownPatterns.some(pattern => pattern.test(content)); } // 处理添加消息 function addMessage(role, content, codeDiff) { const msgDiv = document.createElement('div'); msgDiv.className = `message ${role}`; // 渲染内容 if (isMarkdown(content)) { console.log("content:", content); msgDiv.innerHTML = marked.parse(content); console.log("msgDiv.innerHTML:", msgDiv.innerHTML); } else { const div = document.createElement('div'); div.textContent = content; msgDiv.appendChild(div); } // 如果有代码差异,添加查看差异按钮 if (codeDiff) { const diffButton = document.createElement('button'); diffButton.className = 'diff-button'; diffButton.textContent = '查看代码差异'; diffButton.onclick = () => showCodeDiff(codeDiff); msgDiv.appendChild(diffButton); } // 如果是AI消息且包含代码块,添加"创建文件"按钮 if (role === 'ai') { const codeBlocks = msgDiv.querySelectorAll('pre code'); codeBlocks.forEach((block, index) => { const createFileButton = document.createElement('button'); createFileButton.className = 'create-file-button'; createFileButton.textContent = `生成代码文件`; createFileButton.onclick = () => createNewFileFromCode(block.textContent, index); msgDiv.appendChild(createFileButton); }); } chatBox.appendChild(msgDiv); // 高亮代码块 const codeBlocks = msgDiv.querySelectorAll('pre code'); codeBlocks.forEach(block => { if (hljs) { hljs.highlightElement(block); } }); // 滚动到底部 chatBox.scrollTop = chatBox.scrollHeight; } // 显示代码差异 function showCodeDiff(codeDiff) { const diffModal = document.getElementById('diff-modal'); const diffContent = document.getElementById('diff-content'); diffContent.innerHTML = ''; // 显示添加的行 if (codeDiff.added && codeDiff.added.length > 0) { codeDiff.added.forEach((line, index) => { const diffRow = document.createElement('div'); diffRow.className = 'diff-row'; // 修复行号显示问题 const lineNumber = document.createElement('div'); lineNumber.className = 'diff-line-number'; lineNumber.textContent = index + 1; // 使用索引+1作为行号 const diffLine = document.createElement('div'); diffLine.className = 'diff-line diff-added'; diffLine.textContent = `+ ${line}`; diffRow.appendChild(lineNumber); diffRow.appendChild(diffLine); diffContent.appendChild(diffRow); }); } // 显示删除的行 if (codeDiff.removed && codeDiff.removed.length > 0) { codeDiff.removed.forEach((line, index) => { const diffRow = document.createElement('div'); diffRow.className = 'diff-row'; // 修复行号显示问题 const lineNumber = document.createElement('div'); lineNumber.className = 'diff-line-number'; lineNumber.textContent = index + 1; // 使用索引+1作为行号 const diffLine = document.createElement('div'); diffLine.className = 'diff-line diff-removed'; diffLine.textContent = `- ${line}`; diffRow.appendChild(lineNumber); diffRow.appendChild(diffLine); diffContent.appendChild(diffRow); }); } // 添加接受和拒绝按钮的事件监听 document.getElementById('accept-changes-btn').onclick = () => acceptChanges(codeDiff.modifiedCode); document.getElementById('reject-changes-btn').onclick = () => rejectChanges(); diffModal.classList.remove('hidden'); } // 接受代码变更 function acceptChanges(modifiedCode) { if (contextFilePath) { // 发送消息到插件以接受变更 vscode.postMessage({ command: 'acceptChanges', filePath: contextFilePath, modifiedContent: modifiedCode }); // 关闭模态框 document.getElementById('diff-modal').classList.add('hidden'); } } // 拒绝代码变更 function rejectChanges() { if (contextFilePath) { // 发送消息到插件以拒绝变更 vscode.postMessage({ command: 'rejectChanges', filePath: contextFilePath }); // 关闭模态框 document.getElementById('diff-modal').classList.add('hidden'); } } function showLoading() { loading.classList.remove('hidden'); } function hideLoading() { loading.classList.add('hidden'); } // 更新工作区文件列表 function updateWorkspaceFiles(files) { const workspaceContainer = document.querySelector('.workspace-container'); const workspaceFilesContainer = document.getElementById('workspace-files'); // 如果没有文件变更,则隐藏工作区 if (!files || Object.keys(files).length === 0) { workspaceContainer.style.display = 'none'; return; } // 显示工作区 workspaceContainer.style.display = 'block'; workspaceFilesContainer.innerHTML = ''; Object.keys(files).forEach(filePath => { const fileChange = files[filePath]; const fileItem = document.createElement('div'); fileItem.className = 'workspace-file-item'; // 获取文件名 const fileName = filePath.split(/[\/\\]/).pop(); // 根据状态设置不同的显示样式 let statusText = ''; let statusClass = ''; switch (fileChange.status) { case 'accepted': statusText = '✓ 已接受'; statusClass = 'status-accepted'; break; case 'rejected': statusText = '✗ 已拒绝'; statusClass = 'status-rejected'; break; default: statusText = '待处理'; statusClass = 'status-pending'; } fileItem.innerHTML = ` 📄 ${fileName} ${statusText} `; fileItem.addEventListener('click', () => { // 发送消息到插件以打开文件 vscode.postMessage({ command: 'openWorkspaceFile', filePath: filePath }); }); workspaceFilesContainer.appendChild(fileItem); }); } window.addEventListener('message', (event) => { const message = event.data; console.log(message) if (message.command === 'addMessage') { addMessage(message.role, message.content,message.codeDiff); } else if (message.command === 'hideLoading') { hideLoading(); } else if (message.command === 'addToInput') { userInput.value = message.content; // 插入选中内容到输入框 selectedCodeForContext = message.content; userInput.focus(); // 自动聚焦输入框 } else if (message.command === 'fileList') { const fileListContainer = document.getElementById('file-list'); if (message.error) { fileListContainer.innerHTML = `
错误: ${message.error}
`; return; } if (!message.files || message.files.length === 0) { fileListContainer.innerHTML = '
未找到文件
'; return; } // 渲染文件列表 fileListContainer.innerHTML = ''; message.files.forEach(file => { const fileItem = document.createElement('div'); fileItem.className = 'file-item'; fileItem.innerHTML = ` ${file.isDirectory ? '📁' : '📄'} ${file.relativePath} `; fileItem.addEventListener('click', () => { // 选择文件 vscode.postMessage({ command: 'selectFileByPath', filePath: file.path }); // 关闭模态框 document.getElementById('file-browser-modal').classList.add('hidden'); // 清空文件搜索输入框 document.getElementById('file-search-input').value = ''; // 保存当前上下文文件路径 contextFilePath = file.path; }); fileListContainer.appendChild(fileItem); }); } else if (message.command === 'setContextFile') { const contextPlaceholder = document.getElementById('context-placeholder'); const contextTab = document.getElementById('context-tab'); const fileNameElement = document.getElementById('context-file-name'); const fullPath = message.fileName; const fileName = fullPath.split(/[\/\\]/).pop(); fileNameElement.innerText = fileName; fileNameElement.title = fullPath; selectedCodeForContext = message.fileContent; contextFilePath = fullPath; // 保存上下文文件路径 // 隐藏占位符,显示文件标签 contextPlaceholder.classList.add('hidden'); contextTab.classList.remove('hidden'); } else if (message.command === 'updateWorkspaceFiles') { // 更新工作区文件列表 updateWorkspaceFiles(message.files); } else if (message.command === 'restoreState') { // 恢复面板状态 currentSessionHistory = message.history || []; // 恢复显示历史消息 currentSessionHistory.forEach(msg => { addMessage(msg.role, msg.content, null); }); // 恢复工作区变更 if (message.workspaceChanges) { updateWorkspaceFiles(message.workspaceChanges); } } }); // 打开文件浏览器 document.getElementById('select-context-btn').addEventListener('click', () => { // 显示模态框 document.getElementById('file-browser-modal').classList.remove('hidden'); // 请求文件列表 vscode.postMessage({ command: 'getFileList' }); }); // 关闭模态框 document.getElementById('close-modal').addEventListener('click', () => { document.getElementById('file-browser-modal').classList.add('hidden'); }); // 点击模态框外部关闭 document.getElementById('file-browser-modal').addEventListener('click', (e) => { if (e.target.id === 'file-browser-modal') { document.getElementById('file-browser-modal').classList.add('hidden'); } }); // 文件搜索功能 document.getElementById('file-search-input').addEventListener('input', (e) => { const searchTerm = e.target.value.toLowerCase(); const fileItems = document.querySelectorAll('.file-item'); fileItems.forEach(item => { const fileName = item.querySelector('.file-name').textContent.toLowerCase(); if (fileName.includes(searchTerm)) { item.style.display = ''; } else { item.style.display = 'none'; } }); }); // 添加关闭按钮事件监听 document.getElementById('close-context-btn').addEventListener('click', () => { const contextPlaceholder = document.getElementById('context-placeholder'); const contextTab = document.getElementById('context-tab'); contextTab.classList.add('hidden'); contextPlaceholder.classList.remove('hidden'); selectedCodeForContext = ''; contextFilePath = ''; }); // 关闭差异模态框 document.getElementById('close-diff-modal').addEventListener('click', () => { document.getElementById('diff-modal').classList.add('hidden'); }); // 点击模态框外部关闭 document.getElementById('diff-modal').addEventListener('click', (e) => { if (e.target.id === 'diff-modal') { document.getElementById('diff-modal').classList.add('hidden'); } }); // 从代码创建新文件 function createNewFileFromCode(codeContent, index) { // 简单的语言检测 const language = detectLanguage(codeContent); // 请求创建文件 const fileName = `new_file_${index + 1}${getFileExtension(language)}`; vscode.postMessage({ command: 'createNewFile', fileName: fileName, content: codeContent, language: language }); } // 简单的语言检测 function detectLanguage(code) { // 可以根据代码特征进行简单判断 if (code.includes('import React') || code.includes('from react')) { return 'javascript'; // React代码 } else if (code.includes('public class') || code.includes('private static')) { return 'java'; } else if (code.includes('def ') && code.includes(':')) { return 'python'; } else if (code.includes('function ') || code.includes('const ') || code.includes('let ')) { return 'javascript'; } else if (code.includes('interface ') && code.includes('export ')) { return 'typescript'; } else if (code.includes('