Compare commits

..

No commits in common. "main" and "0.2.1" have entirely different histories.
main ... 0.2.1

11 changed files with 278 additions and 340 deletions

View File

@ -4,27 +4,6 @@ Version History
## [Unreleased] ## [Unreleased]
## [Release 0.2.3]
## What's Changed
* fix(display-html): html is now properly displayed by @Iheuzio in https://github.com/Iheuzio/gpt-contextfiles/pull/38
* Release 0.2.3 by @Iheuzio in https://github.com/Iheuzio/gpt-contextfiles/pull/39
**Full Changelog**: https://github.com/Iheuzio/gpt-contextfiles/compare/0.2.2...0.2.3
## [Release 0.2.2]
## What's Changed
* Fix/organize files by @Iheuzio in https://github.com/Iheuzio/gpt-contextfiles/pull/32
* Fix/style rendered by @Iheuzio in https://github.com/Iheuzio/gpt-contextfiles/pull/33
* fix(style-rendered): padding around response by @Iheuzio in https://github.com/Iheuzio/gpt-contextfiles/pull/34
* update(readme-fix): added new features to readme by @Iheuzio in https://github.com/Iheuzio/gpt-contextfiles/pull/35
* Release 0.2.2 by @Iheuzio in https://github.com/Iheuzio/gpt-contextfiles/pull/36
**Full Changelog**: https://github.com/Iheuzio/gpt-contextfiles/compare/0.2.1...0.2.2
## [Release 0.2.1] ## [Release 0.2.1]
## What's Changed ## What's Changed

View File

@ -10,7 +10,7 @@ https://openai.com/pricing
> However, being orientated with managing files this project defaults to the 16k context with GPT-3.5-turbo-16k > However, being orientated with managing files this project defaults to the 16k context with GPT-3.5-turbo-16k
If you wish to change the model, you must change the model in the `./src/gptContext.js` file If you wish to change the model, you must change the model in the extension.js file
# Examples # Examples
@ -39,8 +39,6 @@ Other features:
![Copy button demonstration](./images/copy-image.png) ![Copy button demonstration](./images/copy-image.png)
- Click copy to to copy the snippet of code into your file for fast coding - Click copy to to copy the snippet of code into your file for fast coding
![Copy individual code](./images/demo-copying-quotes.gif)
# How it works # How it works
We can select two files we want to pass through, however we can uncheck one of them for later debugging and enter our question: We can select two files we want to pass through, however we can uncheck one of them for later debugging and enter our question:

View File

@ -1,6 +1,179 @@
const vscode = require('vscode'); const vscode = require('vscode');
const { selectedFiles } = require('./fileDataProvider'); const { Configuration, OpenAIApi } = require("openai");
// move these into the script so that instead of echoing the question and the contents,
// it will echo the question, followed by the answer from the response when the submit button is pressed.
const configuration = new Configuration({
apiKey: process.env.OPENAI_API_KEY,
});
const openai = new OpenAIApi(configuration);
// Represents a file item in the file explorer
class FileItem {
constructor(uri, selected = false) {
this.uri = uri;
this.selected = selected;
}
toggleSelected() {
this.selected = !this.selected;
}
}
// Represents the selected files in the file explorer
const selectedFiles = [];
// Tree data provider for the selected files
class FileDataProvider {
constructor() {
this._onDidChangeTreeData = new vscode.EventEmitter();
this.onDidChangeTreeData = this._onDidChangeTreeData.event;
}
refresh() {
this._onDidChangeTreeData.fire();
}
getTreeItem(element) {
return {
label: element.uri.fsPath,
collapsibleState: vscode.TreeItemCollapsibleState.None
};
}
getChildren(element) {
if (element) {
return [];
}
// Return only the selected files
return selectedFiles.filter(file => file.selected);
}
}
// Command for adding files to gpt-contextfiles
const addFilesCommand = vscode.commands.registerCommand('extension.addFilesToGPTContext', () => {
const editor = vscode.window.activeTextEditor;
if (editor) {
const uri = editor.document.uri;
const existingFileIndex = selectedFiles.findIndex(file => file.uri.fsPath === uri.fsPath);
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();
}
});
const fileDataProvider = new FileDataProvider();
// Function to handle question submission
async function handleQuestionSubmission(panel, question, selectedUris) {
// Update the selectedFiles array based on the selectedUris
selectedFiles.forEach(file => {
file.selected = selectedUris.includes(file.uri.fsPath);
});
fileDataProvider.refresh();
const fileContents = selectedFiles
.filter(file => file.selected)
.map(file => {
const document = vscode.workspace.textDocuments.find(doc => doc.uri.fsPath === file.uri.fsPath);
if (document) {
const lines = document.getText().split('\n');
const formattedLines = lines.map(line => `\t${line}`).join('\n');
return `${file.uri.fsPath}:\n\`\`\`\n${formattedLines}\n\`\`\``;
}
return '';
})
.join('\n\n');
// Call OpenAI API with the question and file contents
try {
const chatCompletion = await openai.createChatCompletion({
model: "gpt-3.5-turbo-16k",
messages: [
{ role: "system", content: "Answer the coding questions, only provide the code and documentation, explaining the solution after providing the code." },
{ role: "user", content: question + "\n" + fileContents},
],
});
// Extract the answer from the OpenAI response
const answer = chatCompletion.data.choices[0].message.content;
// Update the webview content to display only the OpenAI response
panel.webview.html = getWebviewContent(answer, question);
} catch (error) {
// Handle any errors from the OpenAI API
console.error("Failed to get OpenAI response:", error);
panel.webview.html = getWebviewContent(`Failed to get response from OpenAI API. Error: ${error.message}`, question);
}
}
// Command for displaying the webview panel
const openGPTContextPanelCommand = vscode.commands.registerCommand('extension.openGPTContextPanel', () => {
const panel = vscode.window.createWebviewPanel(
'gptContextPanel',
'GPT Context',
vscode.ViewColumn.One,
{
enableScripts: true
}
);
panel.webview.html = getWebviewContent();
panel.webview.onDidReceiveMessage(async message => {
if (message.command === 'submitQuestion') {
await handleQuestionSubmission(panel, message.text, message.selectedUris);
} else if (message.command === 'toggleFileSelection') {
const uri = message.uri;
const file = selectedFiles.find(file => file.uri.fsPath === uri);
if (file) {
file.toggleSelected();
fileDataProvider.refresh();
}
} else if (message.command === 'clearSelectedFiles') {
const clearedFiles = selectedFiles.filter(file => file.selected === false);
selectedFiles.length = 0; // Clear the array
clearedFiles.forEach(file => {
fileDataProvider.refresh();
});
panel.webview.html = getWebviewContent();
} else if (message.command === 'refreshFiles') {
fileDataProvider.refresh();
panel.webview.html = getWebviewContent();
}
});
});
// Command for refreshing the selected files
const refreshSelectedFilesCommand = vscode.commands.registerCommand('extension.refreshSelectedFiles', () => {
fileDataProvider.refresh();
});
// Command for clearing the selected files
const clearSelectedFilesCommand = vscode.commands.registerCommand('extension.clearSelectedFiles', () => {
selectedFiles.forEach(file => {
file.selected = false;
});
fileDataProvider.refresh();
});
// Command for refreshing all files
const refreshFilesCommand = vscode.commands.registerCommand('extension.refreshFiles', () => {
fileDataProvider.refresh();
});
// Helper function to generate the HTML content for the webview panel
function getWebviewContent(apiResponse = '', question = '') { function getWebviewContent(apiResponse = '', question = '') {
const fileList = selectedFiles const fileList = selectedFiles
.map( .map(
@ -27,20 +200,20 @@ function getWebviewContent(apiResponse = '', question = '') {
color: #d4d4d4; color: #d4d4d4;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
} }
.textbox { .textbox {
width: 100%; width: 100%;
height: 200px; height: 200px;
resize: both; resize: both;
padding: 10px; padding: 10px;
} }
.buttons { .buttons {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
width: 50%; width: 50%;
} }
.button { .button {
flex-grow: 1; flex-grow: 1;
background-color: #007acc; background-color: #007acc;
@ -52,30 +225,28 @@ function getWebviewContent(apiResponse = '', question = '') {
outline: none; outline: none;
font-size: 14px; font-size: 14px;
} }
#response { #response {
white-space: pre-wrap; white-space: pre-wrap;
background: #343434;
border-radius: 5px;
padding: 10px;
} }
#file-list { #file-list {
margin-top: 20px; margin-top: 20px;
border
} }
.form-group { .form-group {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
margin-bottom: 20px; margin-bottom: 20px;
width: 100%; width: 100%;
} }
.form-group label { .form-group label {
margin-bottom: 5px; margin-bottom: 5px;
font-size: 14px; font-size: 14px;
} }
.form-group input[type="text"] { .form-group input[type="text"] {
padding: 10px; padding: 10px;
font-size: 14px; font-size: 14px;
@ -84,17 +255,17 @@ function getWebviewContent(apiResponse = '', question = '') {
background-color: #2d2d2d; background-color: #2d2d2d;
color: #d4d4d4; color: #d4d4d4;
} }
.form-group input[type="text"]::placeholder { .form-group input[type="text"]::placeholder {
color: #d4d4d4; color: #d4d4d4;
} }
.form-group .button-options { .form-group .button-options {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
margin-top: 10px; margin-top: 10px;
} }
.form-group .button-options button { .form-group .button-options button {
padding: 10px; padding: 10px;
font-size: 14px; font-size: 14px;
@ -104,107 +275,107 @@ function getWebviewContent(apiResponse = '', question = '') {
background-color: #007acc; background-color: #007acc;
color: #fff; color: #fff;
} }
.form-group .button-options button:hover { .form-group .button-options button:hover {
background-color: #005f8c; background-color: #005f8c;
} }
.form-group .button-options button:active { .form-group .button-options button:active {
background-color: #004d73; background-color: #004d73;
} }
.form-group .button-options button:focus { .form-group .button-options button:focus {
box-shadow: 0 0 0 2px rgba(0, 122, 204, 0.5); box-shadow: 0 0 0 2px rgba(0, 122, 204, 0.5);
} }
.file-list { .file-list {
margin-top: 20px; margin-top: 20px;
width: 100%; width: 100%;
} }
.file-list h2 { .file-list h2 {
margin-bottom: 10px; margin-bottom: 10px;
font-size: 14px; font-size: 14px;
} }
.file-list .file-item { .file-list .file-item {
display: flex; display: flex;
align-items: center; align-items: center;
margin-bottom: 5px; margin-bottom: 5px;
font-size: 14px; font-size: 14px;
} }
.file-list .file-item input[type="checkbox"] { .file-list .file-item input[type="checkbox"] {
margin-right: 5px; margin-right: 5px;
} }
.file-list .file-item label { .file-list .file-item label {
margin-bottom: 0; margin-bottom: 0;
} }
.file-list .file-item .file-path { .file-list .file-item .file-path {
overflow-wrap: break-word; overflow-wrap: break-word;
} }
.file-list .file-item .file-path:hover { .file-list .file-item .file-path:hover {
text-decoration: underline; text-decoration: underline;
cursor: pointer; cursor: pointer;
} }
.file-list .file-item .file-path:active { .file-list .file-item .file-path:active {
color: #007acc; color: #007acc;
} }
.file-list .file-item .file-path:focus { .file-list .file-item .file-path:focus {
box-shadow: 0 0 0 2px rgba(0, 122, 204, 0.5); box-shadow: 0 0 0 2px rgba(0, 122, 204, 0.5);
} }
.collapsible { .collapsible {
background-color: #2d2d2d; background-color: #2d2d2d;
color: #d4d4d4; color: #d4d4d4;
cursor: pointer; cursor: pointer;
padding: 10px; padding: 10px;
width: 98%; width: 100%;
border: none; border: none;
outline: none; outline: none;
text-align: left; text-align: left;
font-size: 14px; font-size: 14px;
} }
.collapsible:hover { .collapsible:hover {
background-color: #3c3c3c; background-color: #3c3c3c;
} }
.collapsible:active { .collapsible:active {
background-color: #4c4c4c; background-color: #4c4c4c;
} }
.collapsible:focus { .collapsible:focus {
box-shadow: 0 0 0 2px rgba(0, 122, 204, 0.5); box-shadow: 0 0 0 2px rgba(0, 122, 204, 0.5);
} }
.content { .content {
padding: 0 10px; padding: 0 10px;
display: none; display: none;
overflow: hidden; overflow: hidden;
background-color: #f1f1f1; background-color: #f1f1f1;
width: 98%; width: 100%;
} }
.content p { .content p {
margin-top: 0;
font-size: 14px; font-size: 14px;
margin: 0;
} }
.active, .active,
.collapsible:hover { .collapsible:hover {
background-color: #555; background-color: #555;
} }
.active:after { .active:after {
content: "\\2212"; content: "\\2212";
} }
.collapsible:after { .collapsible:after {
content: "\\002B"; content: "\\002B";
color: #d4d4d4; color: #d4d4d4;
@ -212,11 +383,11 @@ function getWebviewContent(apiResponse = '', question = '') {
float: right; float: right;
margin-left: 5px; margin-left: 5px;
} }
.active:after { .active:after {
content: "\\2212"; content: "\\2212";
} }
.collapsible:after { .collapsible:after {
content: "\\002B"; content: "\\002B";
color: #d4d4d4; color: #d4d4d4;
@ -224,7 +395,7 @@ function getWebviewContent(apiResponse = '', question = '') {
float: right; float: right;
margin-left: 5px; margin-left: 5px;
} }
#rendered { #rendered {
background-color: #2d2d2d; background-color: #2d2d2d;
word-wrap: wrap; word-wrap: wrap;
@ -232,25 +403,23 @@ function getWebviewContent(apiResponse = '', question = '') {
border: 1px solid white; border: 1px solid white;
border-radius: 5px; border-radius: 5px;
padding: 10px; padding: 10px;
color: white;
} }
#question-rep { #question-rep {
font-weight: bold; font-weight: bold;
background-color: #2d2d2d; background-color: #2d2d2d;
word-wrap: wrap; word-wrap: wrap;
border: 1px solid white; border: 1px solid white;
border-radius: 5px; border-radius: 5px;
padding: 10px;
margin-top: 20px;
} }
div#api-response.content.active { div#api-response.content.active {
background-color: #313131; background-color: #313131;
} }
#code-block { #code-block {
padding: 10px 0 10px 10px; padding: 10px 0 10px 10px;
padding-
border-radius: 5px; border-radius: 5px;
background-color: black; background-color: black;
border: none; border: none;
@ -258,12 +427,12 @@ function getWebviewContent(apiResponse = '', question = '') {
color: inherit; color: inherit;
cursor: pointer; cursor: pointer;
outline: inherit; outline: inherit;
width: 98%; width: 100%;
text-align: left; text-align: left;
display: inline-block; display: inline-block;
position: relative; position: relative;
} }
#copy-button { #copy-button {
padding: 5px; padding: 5px;
border-radius: 5px; border-radius: 5px;
@ -278,12 +447,12 @@ function getWebviewContent(apiResponse = '', question = '') {
top: 0; top: 0;
right: 0; right: 0;
} }
#copy-button:hover { #copy-button:hover {
background-color: #fff; background-color: #fff;
color: #000; color: #000;
} }
</style> </style>
</head> </head>
@ -304,19 +473,13 @@ function getWebviewContent(apiResponse = '', question = '') {
</div> </div>
<div class="content" id="api-response"> <div class="content" id="api-response">
<div id="question-rep"> <div id="question-rep">
<p>${ <p>${question ? '> ' + question : null}</p>
question = question.replace(/</g, '&lt;').replace(/>/g, '&gt;'),
question ? '> ' + question : null
}</p>
</div> </div>
${ ${
apiResponse ? ` apiResponse ? `
<div id="rendered"> <div id="rendered">
<p id="responses"> <p id="responses">
<pre id="response">${ <pre id="response">${apiResponse.replace(/```([^```]+)```/g, '<div id="code-block"><code>$1</code><button onclick="copyCode(event)" id="copy-button">copy</button></div>')}</pre>
apiResponse = apiResponse.replace(/</g, '&lt;').replace(/>/g, '&gt;'),
apiResponse.replace(/```([^```]+)```/g, '<div id="code-block"><code>$1</code><button onclick="copyCode(event)" id="copy-button">copy</button></div>')
}</pre>
</p> </p>
</div> </div>
` : null ` : null
@ -421,6 +584,53 @@ function getWebviewContent(apiResponse = '', question = '') {
`; `;
} }
module.exports = {
getWebviewContent
}; // Activates the extension
function activate(context) {
context.subscriptions.push(addFilesCommand);
context.subscriptions.push(openGPTContextPanelCommand);
context.subscriptions.push(refreshSelectedFilesCommand);
context.subscriptions.push(clearSelectedFilesCommand);
context.subscriptions.push(refreshFilesCommand);
vscode.window.registerTreeDataProvider('selectedFiles', fileDataProvider);
const provider = {
resolveWebviewView(webviewView) {
webviewView.webview.options = {
enableScripts: true
};
webviewView.webview.html = getWebviewContent();
webviewView.webview.onDidReceiveMessage(async message => {
if (message.command === 'toggleFileSelection') {
const uri = message.uri;
const file = selectedFiles.find(file => file.uri.fsPath === uri);
if (file) {
file.toggleSelected();
fileDataProvider.refresh();
}
} else if (message.command === 'clearSelectedFiles') {
const clearedFiles = selectedFiles.filter(file => file.selected === false);
selectedFiles.length = 0; // Clear the array
clearedFiles.forEach(file => {
fileDataProvider.refresh();
});
webviewView.webview.html = getWebviewContent();
} else if (message.command === 'refreshFiles') {
fileDataProvider.refresh();
webviewView.webview.html = getWebviewContent();
} else if (message.command === 'submitQuestion') {
await handleQuestionSubmission(webviewView, message.text, message.selectedUris);
} else if (message.command === 'codeCopied') {
vscode.window.showInformationMessage('Code copied to clipboard');
}
});
}
};
context.subscriptions.push(vscode.window.registerWebviewViewProvider('gpt-context-sidebar', provider));
}
exports.activate = activate;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 MiB

4
package-lock.json generated
View File

@ -1,12 +1,12 @@
{ {
"name": "gpt-contextfiles", "name": "gpt-contextfiles",
"version": "0.2.3", "version": "0.2.1",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "gpt-contextfiles", "name": "gpt-contextfiles",
"version": "0.2.3", "version": "0.2.1",
"dependencies": { "dependencies": {
"openai": "^3.3.0" "openai": "^3.3.0"
}, },

View File

@ -2,7 +2,7 @@
"name": "gpt-contextfiles", "name": "gpt-contextfiles",
"displayName": "GPT-ContextFiles", "displayName": "GPT-ContextFiles",
"description": "Choose the files to pass into GPT to provide a question with multiple files", "description": "Choose the files to pass into GPT to provide a question with multiple files",
"version": "0.2.3", "version": "0.2.1",
"engines": { "engines": {
"vscode": "^1.79.0" "vscode": "^1.79.0"
}, },
@ -39,7 +39,7 @@
"onCommand:extension.openGPTContextPanel", "onCommand:extension.openGPTContextPanel",
"onCommand:extension.gpt-context-sidebar" "onCommand:extension.gpt-context-sidebar"
], ],
"main": "./src/extension.js", "main": "./extension.js",
"contributes": { "contributes": {
"commands": [ "commands": [
{ {

View File

@ -1,84 +0,0 @@
const vscode = require('vscode');
const { selectedFiles, fileDataProvider, handleQuestionSubmission } = require('./gptContext');
const FileItem = require('./fileItem');
const { getWebviewContent } = require('./webviewPanel');
const addFilesCommand = vscode.commands.registerCommand('extension.addFilesToGPTContext', () => {
const editor = vscode.window.activeTextEditor;
if (editor) {
const uri = editor.document.uri;
const existingFileIndex = selectedFiles.findIndex(file => file.uri.fsPath === uri.fsPath);
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();
}
});
const openGPTContextPanelCommand = vscode.commands.registerCommand('extension.openGPTContextPanel', () => {
const panel = vscode.window.createWebviewPanel(
'gptContextPanel',
'GPT Context',
vscode.ViewColumn.One,
{
enableScripts: true
}
);
panel.webview.html = getWebviewContent();
panel.webview.onDidReceiveMessage(async message => {
if (message.command === 'submitQuestion') {
await handleQuestionSubmission(panel, message.text, message.selectedUris);
} else if (message.command === 'toggleFileSelection') {
const uri = message.uri;
const file = selectedFiles.find(file => file.uri.fsPath === uri);
if (file) {
file.toggleSelected();
fileDataProvider.refresh();
}
} else if (message.command === 'clearSelectedFiles') {
const clearedFiles = selectedFiles.filter(file => file.selected === false);
selectedFiles.length = 0; // Clear the array
clearedFiles.forEach(file => {
fileDataProvider.refresh();
});
panel.webview.html = getWebviewContent();
} else if (message.command === 'refreshFiles') {
fileDataProvider.refresh();
panel.webview.html = getWebviewContent();
}
});
});
const refreshSelectedFilesCommand = vscode.commands.registerCommand('extension.refreshSelectedFiles', () => {
fileDataProvider.refresh();
});
// Command for clearing the selected files
const clearSelectedFilesCommand = vscode.commands.registerCommand('extension.clearSelectedFiles', () => {
selectedFiles.forEach(file => {
file.selected = false;
});
fileDataProvider.refresh();
});
// Command for refreshing all files
const refreshFilesCommand = vscode.commands.registerCommand('extension.refreshFiles', () => {
fileDataProvider.refresh();
});
module.exports = {
addFilesCommand,
openGPTContextPanelCommand,
refreshSelectedFilesCommand,
clearSelectedFilesCommand,
refreshFilesCommand
};

View File

@ -1,52 +0,0 @@
const vscode = require('vscode');
const { addFilesCommand, openGPTContextPanelCommand, refreshSelectedFilesCommand, clearSelectedFilesCommand, refreshFilesCommand } = require('./commands');
const { getWebviewContent } = require('./webviewPanel');
const { selectedFiles, fileDataProvider, handleQuestionSubmission } = require('./gptContext');
function activate(context) {
context.subscriptions.push(addFilesCommand);
context.subscriptions.push(openGPTContextPanelCommand);
context.subscriptions.push(refreshSelectedFilesCommand);
context.subscriptions.push(clearSelectedFilesCommand);
context.subscriptions.push(refreshFilesCommand);
vscode.window.registerTreeDataProvider('selectedFiles', fileDataProvider);
const provider = {
resolveWebviewView(webviewView) {
webviewView.webview.options = {
enableScripts: true
};
webviewView.webview.html = getWebviewContent();
webviewView.webview.onDidReceiveMessage(async message => {
if (message.command === 'toggleFileSelection') {
const uri = message.uri;
const file = selectedFiles.find(file => file.uri.fsPath === uri);
if (file) {
file.toggleSelected();
fileDataProvider.refresh();
}
} else if (message.command === 'clearSelectedFiles') {
const clearedFiles = selectedFiles.filter(file => file.selected === false);
selectedFiles.length = 0; // Clear the array
clearedFiles.forEach(file => {
fileDataProvider.refresh();
});
webviewView.webview.html = getWebviewContent();
} else if (message.command === 'refreshFiles') {
fileDataProvider.refresh();
webviewView.webview.html = getWebviewContent();
} else if (message.command === 'submitQuestion') {
await handleQuestionSubmission(webviewView, message.text, message.selectedUris);
} else if (message.command === 'codeCopied') {
vscode.window.showInformationMessage('Code copied to clipboard');
}
});
}
};
context.subscriptions.push(vscode.window.registerWebviewViewProvider('gpt-context-sidebar', provider));
}
exports.activate = activate;

View File

@ -1,38 +0,0 @@
const vscode = require('vscode');
const FileItem = require('./fileItem.js');
// Represents the selected files in the file explorer
const selectedFiles = [];
// Tree data provider for the selected files
class FileDataProvider {
constructor() {
this._onDidChangeTreeData = new vscode.EventEmitter();
this.onDidChangeTreeData = this._onDidChangeTreeData.event;
}
refresh() {
this._onDidChangeTreeData.fire();
}
getTreeItem(element) {
return {
label: element.uri.fsPath,
collapsibleState: vscode.TreeItemCollapsibleState.None
};
}
getChildren(element) {
if (element) {
return [];
}
// Return only the selected files
return selectedFiles.filter(file => file.selected);
}
}
module.exports = {
FileDataProvider,
selectedFiles
};

View File

@ -1,12 +0,0 @@
class FileItem {
constructor(uri, selected = false) {
this.uri = uri;
this.selected = selected;
}
toggleSelected() {
this.selected = !this.selected;
}
}
module.exports = FileItem;

View File

@ -1,63 +0,0 @@
const vscode = require('vscode');
const { Configuration, OpenAIApi } = require("openai");
const FileDataProvider = require('./fileDataProvider');
const { getWebviewContent } = require('./webviewPanel');
const configuration = new Configuration({
apiKey: process.env.OPENAI_API_KEY,
});
const openai = new OpenAIApi(configuration);
const selectedFiles = FileDataProvider.selectedFiles;
const fileDataProvider = new FileDataProvider.FileDataProvider();
async function handleQuestionSubmission(panel, question, selectedUris) {
// Update the selectedFiles array based on the selectedUris
selectedFiles.forEach(file => {
file.selected = selectedUris.includes(file.uri.fsPath);
});
fileDataProvider.refresh();
const fileContents = selectedFiles
.filter(file => file.selected)
.map(file => {
const document = vscode.workspace.textDocuments.find(doc => doc.uri.fsPath === file.uri.fsPath);
if (document) {
const lines = document.getText().split('\n');
const formattedLines = lines.map(line => `\t${line}`).join('\n');
return `${file.uri.fsPath}:\n\`\`\`\n${formattedLines}\n\`\`\``;
}
return '';
})
.join('\n\n');
// Call OpenAI API with the question and file contents
try {
const chatCompletion = await openai.createChatCompletion({
model: "gpt-3.5-turbo-16k",
messages: [
{ role: "system", content: "Answer the coding questions, only provide the code and documentation, explaining the solution after providing the code. Put codeblocks inside ``` code ``` with file names above each snippet." },
{ role: "user", content: question + "\n" + fileContents},
],
});
// Extract the answer from the OpenAI response
const answer = chatCompletion.data.choices[0].message.content;
// Update the webview content to display only the OpenAI response
panel.webview.html = getWebviewContent(answer, question);
} catch (error) {
// Handle any errors from the OpenAI API
console.error("Failed to get OpenAI response:", error);
panel.webview.html = getWebviewContent(`Failed to get response from OpenAI API. Error: ${error.message}`, question);
}
}
module.exports = {
handleQuestionSubmission,
fileDataProvider,
selectedFiles
};