fix(gpt-context): Fixes the layout and the options with the selected files

This commit is contained in:
Christopher 2023-06-18 16:30:57 -04:00
parent 98c894fe6e
commit 93be5cbce3

View File

@ -1,11 +1,14 @@
const vscode = require('vscode'); const vscode = require('vscode');
const path = require('path');
// Represents a file item in the file explorer // Represents a file item in the file explorer
class FileItem { class FileItem {
constructor(uri, checked) { constructor(uri, selected = false) {
this.uri = uri; this.uri = uri;
this.checked = checked || false; this.selected = selected;
}
toggleSelected() {
this.selected = !this.selected;
} }
} }
@ -17,7 +20,6 @@ class FileDataProvider {
constructor() { constructor() {
this._onDidChangeTreeData = new vscode.EventEmitter(); this._onDidChangeTreeData = new vscode.EventEmitter();
this.onDidChangeTreeData = this._onDidChangeTreeData.event; this.onDidChangeTreeData = this._onDidChangeTreeData.event;
this.filterPatterns = ['*.*']; // Default filter pattern
} }
refresh() { refresh() {
@ -27,8 +29,7 @@ class FileDataProvider {
getTreeItem(element) { getTreeItem(element) {
return { return {
label: element.uri.fsPath, label: element.uri.fsPath,
collapsibleState: vscode.TreeItemCollapsibleState.None, collapsibleState: vscode.TreeItemCollapsibleState.None
checked: element.checked
}; };
} }
@ -36,57 +37,33 @@ class FileDataProvider {
if (element) { if (element) {
return []; return [];
} }
return selectedFiles;
}
setFilter(filter) { // Return only the selected files
this.filterPatterns = filter.split(',').map(pattern => pattern.trim()); return selectedFiles.filter(file => file.selected);
this.refresh();
}
filterFiles(files) {
return files.filter(file => {
const extension = path.extname(file.uri.fsPath);
return this.filterPatterns.some(pattern => {
const regex = new RegExp(pattern.replace(/\./g, '\\.').replace(/\*/g, '.*'));
return regex.test(extension);
});
});
} }
} }
// Command for adding files to gpt-contextfiles // Command for adding files to gpt-contextfiles
const addFilesCommand = vscode.commands.registerCommand('extension.addFilesToGPTContext', () => { const addFilesCommand = vscode.commands.registerCommand('extension.addFilesToGPTContext', () => {
const workspaceFolders = vscode.workspace.workspaceFolders; const editor = vscode.window.activeTextEditor;
if (workspaceFolders && workspaceFolders.length > 0) { if (editor) {
const workspacePath = workspaceFolders[0].uri.fsPath; const uri = editor.document.uri;
vscode.workspace.findFiles('**/*', '', 1000).then(files => { const existingFileIndex = selectedFiles.findIndex(file => file.uri.fsPath === uri.fsPath);
const fileItems = files.map(file => new FileItem(file));
selectedFiles.splice(0, selectedFiles.length, ...fileItems); if (existingFileIndex !== -1) {
// File already exists, remove it from the list
selectedFiles.splice(existingFileIndex, 1);
} else {
// Add the file to the list with selected state
selectedFiles.push(new FileItem(uri, true));
}
fileDataProvider.refresh(); fileDataProvider.refresh();
});
} }
}); });
// Refresh the file list when workspace changes (file creation, deletion, renaming)
vscode.workspace.onDidChangeWorkspaceFolders(() => {
vscode.commands.executeCommand('extension.addFilesToGPTContext');
});
vscode.workspace.onDidCreateFiles(() => {
vscode.commands.executeCommand('extension.addFilesToGPTContext');
});
vscode.workspace.onDidDeleteFiles(() => {
vscode.commands.executeCommand('extension.addFilesToGPTContext');
});
vscode.workspace.onDidRenameFiles(() => {
vscode.commands.executeCommand('extension.addFilesToGPTContext');
});
const fileDataProvider = new FileDataProvider(); const fileDataProvider = new FileDataProvider();
// Command for displaying the webview panel // Command for displaying the webview panel
@ -105,46 +82,52 @@ const openGPTContextPanelCommand = vscode.commands.registerCommand('extension.op
panel.webview.onDidReceiveMessage(message => { panel.webview.onDidReceiveMessage(message => {
if (message.command === 'submitQuestion') { if (message.command === 'submitQuestion') {
const question = message.text; const question = message.text;
const selectedFilePaths = selectedFiles const fileContents = selectedFiles
.filter(file => file.checked) .map(file => {
.map(file => file.uri.fsPath); const document = vscode.workspace.textDocuments.find(doc => doc.uri.fsPath === file.uri.fsPath);
const fileContents = selectedFilePaths
.map(filePath => {
const document = vscode.workspace.textDocuments.find(doc => doc.uri.fsPath === filePath);
if (document) { if (document) {
const lines = document.getText().split('\n'); const lines = document.getText().split('\n');
return `${filePath}\n${lines.join('\n')}`; return `${file.uri.fsPath}\n${lines.join('\n')}`;
} }
return ''; return '';
}) })
.join('\n\n'); .join('\n\n');
panel.webview.html = getWebviewContent(fileContents, question); panel.webview.html = getWebviewContent(fileContents, question);
} else if (message.command === 'fileSelectionChanged') { } else if (message.command === 'toggleFileSelection') {
const { filePath, checked } = message; const uri = message.uri;
const file = selectedFiles.find(file => file.uri.fsPath === filePath); const file = selectedFiles.find(file => file.uri.fsPath === uri);
if (file) { if (file) {
file.checked = checked; file.toggleSelected();
fileDataProvider.refresh();
} }
} else if (message.command === 'filterFiles') { } else if (message.command === 'clearSelectedFiles') {
const { filter } = message; selectedFiles.forEach(file => {
fileDataProvider.setFilter(filter); file.selected = false;
});
selectedFiles.length = 0; // Clear the array
fileDataProvider.refresh();
} else if (message.command === 'refreshSelectedFiles') {
fileDataProvider.refresh();
} }
}); });
}); });
// Command for refreshing the selected files
const refreshSelectedFilesCommand = vscode.commands.registerCommand('extension.refreshSelectedFiles', () => {
fileDataProvider.refresh();
});
// Helper function to generate the HTML content for the webview panel // Helper function to generate the HTML content for the webview panel
function getWebviewContent(fileContents, question) { function getWebviewContent(fileContents, question) {
const fileItems = fileDataProvider const fileList = selectedFiles
.filterFiles(selectedFiles) .map(
.map(file => ` file =>
<div> `<div><input type="checkbox" ${
<input type="checkbox" id="${file.uri.fsPath}" name="file" value="${file.uri.fsPath}" ${file.checked ? 'checked' : ''}> file.selected ? 'checked' : ''
<label for="${file.uri.fsPath}">${file.uri.fsPath}</label> } onchange="toggleFileSelection('${file.uri.fsPath}')" /> ${file.uri.fsPath}</div>`
</div> )
`) .join('');
.join('\n');
return ` return `
<html> <html>
@ -154,23 +137,39 @@ function getWebviewContent(fileContents, question) {
<label for="question">Enter your question:</label> <label for="question">Enter your question:</label>
<input type="text" id="question" name="question" required> <input type="text" id="question" name="question" required>
<button type="submit">Submit</button> <button type="submit">Submit</button>
<button type="button" onclick="clearSelectedFiles()">Clear</button>
<button type="button" onclick="refreshSelectedFiles()">Refresh</button>
</form> </form>
<div>
<h3>Select Files:</h3>
<div>
<label for="filter">Filter:</label>
<input type="text" id="filter" name="filter" value="${fileDataProvider.filterPatterns.join(', ')}">
<button id="applyFilter">Apply</button>
</div>
${fileItems}
</div>
${ ${
fileContents ? `<div><pre>${fileContents}</pre></div>` : '' fileContents ? `<div><pre>${fileContents}</pre></div>` : ''
} }
<div>
<h2>Selected Files:</h2>
${fileList}
</div>
<div><pre>${question ? question : ''}</pre></div> <div><pre>${question ? question : ''}</pre></div>
<script> <script>
const vscode = acquireVsCodeApi(); const vscode = acquireVsCodeApi();
function toggleFileSelection(uri) {
vscode.postMessage({
command: 'toggleFileSelection',
uri: uri
});
}
function clearSelectedFiles() {
vscode.postMessage({
command: 'clearSelectedFiles'
});
}
function refreshSelectedFiles() {
vscode.postMessage({
command: 'refreshSelectedFiles'
});
}
const form = document.getElementById('questionForm'); const form = document.getElementById('questionForm');
form.addEventListener('submit', event => { form.addEventListener('submit', event => {
event.preventDefault(); event.preventDefault();
@ -180,29 +179,6 @@ function getWebviewContent(fileContents, question) {
text: question text: question
}); });
}); });
const fileCheckboxes = document.querySelectorAll('input[name="file"]');
fileCheckboxes.forEach(checkbox => {
checkbox.addEventListener('change', event => {
const filePath = event.target.value;
const checked = event.target.checked;
vscode.postMessage({
command: 'fileSelectionChanged',
filePath: filePath,
checked: checked
});
});
});
const applyFilterButton = document.getElementById('applyFilter');
applyFilterButton.addEventListener('click', () => {
const filterInput = document.getElementById('filter');
const filterValue = filterInput.value;
vscode.postMessage({
command: 'filterFiles',
filter: filterValue
});
});
</script> </script>
</body> </body>
</html> </html>
@ -217,6 +193,7 @@ function activate(context) {
// Register the commands // Register the commands
context.subscriptions.push(addFilesCommand); context.subscriptions.push(addFilesCommand);
context.subscriptions.push(openGPTContextPanelCommand); context.subscriptions.push(openGPTContextPanelCommand);
context.subscriptions.push(refreshSelectedFilesCommand);
// Refresh the file data provider when a file is added or removed from the workspace // Refresh the file data provider when a file is added or removed from the workspace
vscode.workspace.onDidChangeWorkspaceFolders(() => { vscode.workspace.onDidChangeWorkspaceFolders(() => {