mirror of
https://github.com/Iheuzio/gpt-contextfiles.git
synced 2025-07-18 14:00:48 +00:00
Compare commits
21 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
a1a8c44824 | ||
|
8261a1291e | ||
|
f96b85d43c | ||
|
1af14cabd3 | ||
|
08a84fbfcd | ||
|
dd67a60fc7 | ||
|
dcbc1ff9de | ||
|
fbf7632a4a | ||
|
4e29badfc3 | ||
|
a22fff22c3 | ||
|
55af7f8c26 | ||
|
95a11f8bf9 | ||
|
d177199470 | ||
|
6977f004d2 | ||
|
3dffeccaa9 | ||
|
384ac4fc80 | ||
|
d8eb37e674 | ||
|
f3fa6a3d0b | ||
|
fd9ac838c4 | ||
|
68a714b80a | ||
|
6994b23aa2 |
21
CHANGELOG.md
21
CHANGELOG.md
@ -4,6 +4,27 @@ Version History
|
||||
|
||||
## [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]
|
||||
|
||||
## What's Changed
|
||||
|
@ -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
|
||||
|
||||
If you wish to change the model, you must change the model in the extension.js file
|
||||
If you wish to change the model, you must change the model in the `./src/gptContext.js` file
|
||||
|
||||
# Examples
|
||||
|
||||
@ -39,6 +39,8 @@ Other features:
|
||||

|
||||
- Click copy to to copy the snippet of code into your file for fast coding
|
||||
|
||||

|
||||
|
||||
# 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:
|
||||
|
BIN
images/demo-copying-quotes.gif
Normal file
BIN
images/demo-copying-quotes.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 12 MiB |
4
package-lock.json
generated
4
package-lock.json
generated
@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "gpt-contextfiles",
|
||||
"version": "0.2.1",
|
||||
"version": "0.2.3",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "gpt-contextfiles",
|
||||
"version": "0.2.1",
|
||||
"version": "0.2.3",
|
||||
"dependencies": {
|
||||
"openai": "^3.3.0"
|
||||
},
|
||||
|
@ -2,7 +2,7 @@
|
||||
"name": "gpt-contextfiles",
|
||||
"displayName": "GPT-ContextFiles",
|
||||
"description": "Choose the files to pass into GPT to provide a question with multiple files",
|
||||
"version": "0.2.1",
|
||||
"version": "0.2.3",
|
||||
"engines": {
|
||||
"vscode": "^1.79.0"
|
||||
},
|
||||
@ -39,7 +39,7 @@
|
||||
"onCommand:extension.openGPTContextPanel",
|
||||
"onCommand:extension.gpt-context-sidebar"
|
||||
],
|
||||
"main": "./extension.js",
|
||||
"main": "./src/extension.js",
|
||||
"contributes": {
|
||||
"commands": [
|
||||
{
|
||||
|
84
src/commands.js
Normal file
84
src/commands.js
Normal file
@ -0,0 +1,84 @@
|
||||
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
|
||||
};
|
52
src/extension.js
Normal file
52
src/extension.js
Normal file
@ -0,0 +1,52 @@
|
||||
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;
|
38
src/fileDataProvider.js
Normal file
38
src/fileDataProvider.js
Normal file
@ -0,0 +1,38 @@
|
||||
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
|
||||
};
|
12
src/fileItem.js
Normal file
12
src/fileItem.js
Normal file
@ -0,0 +1,12 @@
|
||||
class FileItem {
|
||||
constructor(uri, selected = false) {
|
||||
this.uri = uri;
|
||||
this.selected = selected;
|
||||
}
|
||||
|
||||
toggleSelected() {
|
||||
this.selected = !this.selected;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = FileItem;
|
63
src/gptContext.js
Normal file
63
src/gptContext.js
Normal file
@ -0,0 +1,63 @@
|
||||
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
|
||||
};
|
@ -1,179 +1,6 @@
|
||||
const vscode = require('vscode');
|
||||
const { Configuration, OpenAIApi } = require("openai");
|
||||
const { selectedFiles } = require('./fileDataProvider');
|
||||
|
||||
// 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 = '') {
|
||||
const fileList = selectedFiles
|
||||
.map(
|
||||
@ -200,20 +27,20 @@ function getWebviewContent(apiResponse = '', question = '') {
|
||||
color: #d4d4d4;
|
||||
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||||
}
|
||||
|
||||
|
||||
.textbox {
|
||||
width: 100%;
|
||||
height: 200px;
|
||||
resize: both;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
|
||||
.buttons {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
|
||||
.button {
|
||||
flex-grow: 1;
|
||||
background-color: #007acc;
|
||||
@ -225,28 +52,30 @@ function getWebviewContent(apiResponse = '', question = '') {
|
||||
outline: none;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
|
||||
#response {
|
||||
white-space: pre-wrap;
|
||||
background: #343434;
|
||||
border-radius: 5px;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
|
||||
#file-list {
|
||||
margin-top: 20px;
|
||||
border
|
||||
}
|
||||
|
||||
|
||||
.form-group {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin-bottom: 20px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
|
||||
.form-group label {
|
||||
margin-bottom: 5px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
|
||||
.form-group input[type="text"] {
|
||||
padding: 10px;
|
||||
font-size: 14px;
|
||||
@ -255,17 +84,17 @@ function getWebviewContent(apiResponse = '', question = '') {
|
||||
background-color: #2d2d2d;
|
||||
color: #d4d4d4;
|
||||
}
|
||||
|
||||
|
||||
.form-group input[type="text"]::placeholder {
|
||||
color: #d4d4d4;
|
||||
}
|
||||
|
||||
|
||||
.form-group .button-options {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
|
||||
.form-group .button-options button {
|
||||
padding: 10px;
|
||||
font-size: 14px;
|
||||
@ -275,107 +104,107 @@ function getWebviewContent(apiResponse = '', question = '') {
|
||||
background-color: #007acc;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
|
||||
.form-group .button-options button:hover {
|
||||
background-color: #005f8c;
|
||||
}
|
||||
|
||||
|
||||
.form-group .button-options button:active {
|
||||
background-color: #004d73;
|
||||
}
|
||||
|
||||
|
||||
.form-group .button-options button:focus {
|
||||
box-shadow: 0 0 0 2px rgba(0, 122, 204, 0.5);
|
||||
}
|
||||
|
||||
|
||||
.file-list {
|
||||
margin-top: 20px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
|
||||
.file-list h2 {
|
||||
margin-bottom: 10px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
|
||||
.file-list .file-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 5px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
|
||||
.file-list .file-item input[type="checkbox"] {
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
|
||||
.file-list .file-item label {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
|
||||
.file-list .file-item .file-path {
|
||||
overflow-wrap: break-word;
|
||||
}
|
||||
|
||||
|
||||
.file-list .file-item .file-path:hover {
|
||||
text-decoration: underline;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
|
||||
.file-list .file-item .file-path:active {
|
||||
color: #007acc;
|
||||
}
|
||||
|
||||
|
||||
.file-list .file-item .file-path:focus {
|
||||
box-shadow: 0 0 0 2px rgba(0, 122, 204, 0.5);
|
||||
}
|
||||
|
||||
|
||||
.collapsible {
|
||||
background-color: #2d2d2d;
|
||||
color: #d4d4d4;
|
||||
cursor: pointer;
|
||||
padding: 10px;
|
||||
width: 100%;
|
||||
width: 98%;
|
||||
border: none;
|
||||
outline: none;
|
||||
text-align: left;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
|
||||
.collapsible:hover {
|
||||
background-color: #3c3c3c;
|
||||
}
|
||||
|
||||
|
||||
.collapsible:active {
|
||||
background-color: #4c4c4c;
|
||||
}
|
||||
|
||||
|
||||
.collapsible:focus {
|
||||
box-shadow: 0 0 0 2px rgba(0, 122, 204, 0.5);
|
||||
}
|
||||
|
||||
|
||||
.content {
|
||||
padding: 0 10px;
|
||||
display: none;
|
||||
overflow: hidden;
|
||||
background-color: #f1f1f1;
|
||||
width: 100%;
|
||||
width: 98%;
|
||||
}
|
||||
|
||||
|
||||
.content p {
|
||||
margin-top: 0;
|
||||
font-size: 14px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
|
||||
.active,
|
||||
.collapsible:hover {
|
||||
background-color: #555;
|
||||
}
|
||||
|
||||
|
||||
.active:after {
|
||||
content: "\\2212";
|
||||
}
|
||||
|
||||
|
||||
.collapsible:after {
|
||||
content: "\\002B";
|
||||
color: #d4d4d4;
|
||||
@ -383,11 +212,11 @@ function getWebviewContent(apiResponse = '', question = '') {
|
||||
float: right;
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
|
||||
.active:after {
|
||||
content: "\\2212";
|
||||
}
|
||||
|
||||
|
||||
.collapsible:after {
|
||||
content: "\\002B";
|
||||
color: #d4d4d4;
|
||||
@ -395,7 +224,7 @@ function getWebviewContent(apiResponse = '', question = '') {
|
||||
float: right;
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
|
||||
#rendered {
|
||||
background-color: #2d2d2d;
|
||||
word-wrap: wrap;
|
||||
@ -403,23 +232,25 @@ function getWebviewContent(apiResponse = '', question = '') {
|
||||
border: 1px solid white;
|
||||
border-radius: 5px;
|
||||
padding: 10px;
|
||||
color: white;
|
||||
}
|
||||
|
||||
|
||||
#question-rep {
|
||||
font-weight: bold;
|
||||
background-color: #2d2d2d;
|
||||
word-wrap: wrap;
|
||||
border: 1px solid white;
|
||||
border-radius: 5px;
|
||||
padding: 10px;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
|
||||
div#api-response.content.active {
|
||||
background-color: #313131;
|
||||
}
|
||||
|
||||
|
||||
#code-block {
|
||||
padding: 10px 0 10px 10px;
|
||||
padding-
|
||||
border-radius: 5px;
|
||||
background-color: black;
|
||||
border: none;
|
||||
@ -427,12 +258,12 @@ function getWebviewContent(apiResponse = '', question = '') {
|
||||
color: inherit;
|
||||
cursor: pointer;
|
||||
outline: inherit;
|
||||
width: 100%;
|
||||
width: 98%;
|
||||
text-align: left;
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
|
||||
#copy-button {
|
||||
padding: 5px;
|
||||
border-radius: 5px;
|
||||
@ -447,12 +278,12 @@ function getWebviewContent(apiResponse = '', question = '') {
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
|
||||
#copy-button:hover {
|
||||
background-color: #fff;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
|
||||
</style>
|
||||
</head>
|
||||
|
||||
@ -473,13 +304,19 @@ function getWebviewContent(apiResponse = '', question = '') {
|
||||
</div>
|
||||
<div class="content" id="api-response">
|
||||
<div id="question-rep">
|
||||
<p>${question ? '> ' + question : null}</p>
|
||||
<p>${
|
||||
question = question.replace(/</g, '<').replace(/>/g, '>'),
|
||||
question ? '> ' + question : null
|
||||
}</p>
|
||||
</div>
|
||||
${
|
||||
apiResponse ? `
|
||||
<div id="rendered">
|
||||
<p id="responses">
|
||||
<pre id="response">${apiResponse.replace(/```([^```]+)```/g, '<div id="code-block"><code>$1</code><button onclick="copyCode(event)" id="copy-button">copy</button></div>')}</pre>
|
||||
<pre id="response">${
|
||||
apiResponse = apiResponse.replace(/</g, '<').replace(/>/g, '>'),
|
||||
apiResponse.replace(/```([^```]+)```/g, '<div id="code-block"><code>$1</code><button onclick="copyCode(event)" id="copy-button">copy</button></div>')
|
||||
}</pre>
|
||||
</p>
|
||||
</div>
|
||||
` : null
|
||||
@ -584,53 +421,6 @@ function getWebviewContent(apiResponse = '', question = '') {
|
||||
`;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 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;
|
||||
module.exports = {
|
||||
getWebviewContent
|
||||
};
|
Loading…
Reference in New Issue
Block a user