feat(extension): 添加选择文件作为上下文功能

- 在 extension.ts 中注册选择文件命令
- 在 Webview 中添加文件选择按钮和上下文显示区域
- 实现文件选择逻辑,将选中文件内容发送到 Webview
- 在 Webview 中处理接收到的文件内容,显示文件名和内容
-
master
钟良源 7 months ago
parent c0e32c9b83
commit aac6da5ce0

@ -8,7 +8,6 @@ document.addEventListener('DOMContentLoaded', () => {
const loading = document.getElementById('loading');
chatForm.addEventListener('submit', (e) => {
console.log(1111)
e.preventDefault();
const text = userInput.value.trim();
if (!text) return;
@ -21,7 +20,6 @@ document.addEventListener('DOMContentLoaded', () => {
// addMessage('user', text);
showLoading();
userInput.value = '';
});
@ -48,9 +46,9 @@ document.addEventListener('DOMContentLoaded', () => {
// 渲染内容
if (isMarkdown(content)) {
console.log("content:",content)
console.log("content:", content)
msgDiv.innerHTML = marked.parse(content);
console.log("msgDiv.innerHTML:",msgDiv.innerHTML )
console.log("msgDiv.innerHTML:", msgDiv.innerHTML)
} else {
const div = document.createElement('div');
div.textContent = content;
@ -79,7 +77,7 @@ document.addEventListener('DOMContentLoaded', () => {
window.addEventListener('message', (event) => {
const message = event.data;
console.log(message)
console.log(message)
if (message.command === 'addMessage') {
addMessage(message.role, message.content);
} else if (message.command === 'hideLoading') {
@ -88,7 +86,36 @@ document.addEventListener('DOMContentLoaded', () => {
userInput.value = message.content; // 插入选中内容到输入框
selectedCodeForContext = message.content;
userInput.focus(); // 自动聚焦输入框
} 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;
// 隐藏占位符,显示文件标签
contextPlaceholder.classList.add('hidden');
contextTab.classList.remove('hidden');
}
});
document.getElementById('select-context-btn').addEventListener('click', () => {
vscode.postMessage({
command: 'selectContextFile'
});
});
// 添加关闭按钮事件监听
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 = '';
});
});

@ -23,7 +23,7 @@ body {
.user,
.ai {
align-self: flex-end;
color:#000000;
color: #000000;
margin: 7px 3px;
padding: 7px;
border-radius: 10px;
@ -75,9 +75,9 @@ body {
#chat-form {
display: flex;
padding: 10px;
padding: 3px 10px;
background-color: #282c34;
border-top: 1px solid #444;
/* border-top: 1px solid #444; */
}
#user-input {
@ -112,3 +112,98 @@ body {
.hidden {
display: none;
}
.context-container {
display: flex;
align-items: center;
margin: 10px 0;
gap: 10px; /* 元素间的间距 */
padding: 1px 10px;
}
.context-tab {
display: flex;
align-items: center;
padding: 6px 10px;
background-color: #e9e9e9;
border-radius: 4px;
font-size: 13px;
min-width: 0; /* 允许收缩 */
flex: 0 1 auto; /* 不要占据多余空间 */
color: #000000;
cursor: default;
}
.context-tab.hidden {
display: none;
}
.file-name {
flex: 1;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
margin-right: 10px;
}
.context-placeholder {
display: flex;
align-items: center;
padding: 6px 2px;
color: #666;
font-size: 13px;
min-width: 0;
}
.placeholder-text {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.context-placeholder.hidden {
display: none;
}
.close-btn {
background: none;
border: none;
font-size: 18px;
cursor: pointer;
color: #666;
padding: 0;
width: 20px;
height: 20px;
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
}
.close-btn:hover {
color: #ff0000;
background-color: rgba(0,0,0,0.1);
border-radius: 50%;
}
.select-context-btn {
width: 24px;
height: 24px;
padding: 0;
background-color: #007acc;
color: white;
border: none;
border-radius: 50%;
font-size: 16px;
font-weight: bold;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
}
.select-context-btn:hover {
background-color: #005a9e;
}

@ -47,8 +47,33 @@ export function activate(context: vscode.ExtensionContext) {
}
});
// 注册选择文件命令
const selectFileCommand = vscode.commands.registerCommand('ai-chat.selectFileAsContext', async () => {
const uris = await vscode.window.showOpenDialog({
canSelectFiles: true,
canSelectFolders: false,
canSelectMany: false, // 单选
title: "选择一个文件作为上下文"
});
if (uris && uris.length > 0) {
const selectedFileUri = uris[0];
const fileContent = await vscode.workspace.fs.readFile(selectedFileUri);
const decodedContent = new TextDecoder("utf-8").decode(fileContent);
// 发送文件内容到 Webview
if (panel && panel.webview) {
panel.webview.postMessage({
command: 'setContextFile',
fileName: selectedFileUri.fsPath,
fileContent: decodedContent
});
}
}
});
// 添加到 subscriptions
context.subscriptions.push(statusBarItem, openWebviewCommand, addToChatCommand);
context.subscriptions.push(statusBarItem, openWebviewCommand, addToChatCommand,selectFileCommand);
}
function openWebview(
@ -117,6 +142,27 @@ function openWebview(
panel.webview.postMessage({ command: 'hideLoading' });
break;
case 'selectContextFile':
// 执行文件选择逻辑
const uris = await vscode.window.showOpenDialog({
canSelectFiles: true,
canSelectFolders: false,
canSelectMany: false,
title: "选择一个文件作为上下文"
});
if (uris && uris.length > 0) {
const selectedFileUri = uris[0];
const fileContent = await vscode.workspace.fs.readFile(selectedFileUri);
const decodedContent = new TextDecoder("utf-8").decode(fileContent);
panel.webview.postMessage({
command: 'setContextFile',
fileName: selectedFileUri.fsPath,
fileContent: decodedContent
});
}
break;
}
},
undefined,
@ -187,8 +233,22 @@ function getWebviewContent(styleUri: vscode.Uri, scriptUri: vscode.Uri,highlight
</head>
<body>
<div class="chat-container">
<!---->
<div id="chat-box"></div>
<!---->
<div class="context-container">
<button id="select-context-btn" class="select-context-btn" title="选择上下文文件">+</button>
<div id="context-placeholder" class="context-placeholder">
<span class="placeholder-text"></span>
</div>
<div id="context-tab" class="context-tab hidden">
<span id="context-file-name" class="file-name"></span>
<button id="close-context-btn" class="close-btn" title="清除上下文">×</button>
</div>
</div>
<!-- -->
<form id="chat-form">
<input type="text" id="user-input" placeholder="输入你的问题..." required />

Loading…
Cancel
Save