Base files for creation of extension

This commit is contained in:
Christopher 2023-06-18 15:42:52 -04:00
commit 98c894fe6e
15 changed files with 2521 additions and 0 deletions

25
.eslintrc.json Normal file
View File

@ -0,0 +1,25 @@
{
"env": {
"browser": false,
"commonjs": true,
"es6": true,
"node": true,
"mocha": true
},
"parserOptions": {
"ecmaVersion": 2018,
"ecmaFeatures": {
"jsx": true
},
"sourceType": "module"
},
"rules": {
"no-const-assign": "warn",
"no-this-before-super": "warn",
"no-undef": "warn",
"no-unreachable": "warn",
"no-unused-vars": "warn",
"constructor-super": "warn",
"valid-typeof": "warn"
}
}

3
.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
node_modules
.vscode-test/
*.vsix

7
.vscode/extensions.json vendored Normal file
View File

@ -0,0 +1,7 @@
{
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the extensions.json format
"recommendations": [
"dbaeumer.vscode-eslint"
]
}

26
.vscode/launch.json vendored Normal file
View File

@ -0,0 +1,26 @@
// A launch configuration that launches the extension inside a new window
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
{
"version": "0.2.0",
"configurations": [
{
"name": "Run Extension",
"type": "extensionHost",
"request": "launch",
"args": [
"--extensionDevelopmentPath=${workspaceFolder}"
]
},
{
"name": "Extension Tests",
"type": "extensionHost",
"request": "launch",
"args": [
"--extensionDevelopmentPath=${workspaceFolder}",
"--extensionTestsPath=${workspaceFolder}/test/suite/index"
]
}
]
}

9
.vscodeignore Normal file
View File

@ -0,0 +1,9 @@
.vscode/**
.vscode-test/**
test/**
.gitignore
.yarnrc
vsc-extension-quickstart.md
**/jsconfig.json
**/*.map
**/.eslintrc.json

9
CHANGELOG.md Normal file
View File

@ -0,0 +1,9 @@
# Change Log
All notable changes to the "gpt-contextfiles" extension will be documented in this file.
Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how to structure this file.
## [Unreleased]
- Initial release

65
README.md Normal file
View File

@ -0,0 +1,65 @@
# gpt-contextfiles README
This is the README for your extension "gpt-contextfiles". After writing up a brief description, we recommend including the following sections.
## Features
Describe specific features of your extension including screenshots of your extension in action. Image paths are relative to this README file.
For example if there is an image subfolder under your extension project workspace:
\!\[feature X\]\(images/feature-x.png\)
> Tip: Many popular extensions utilize animations. This is an excellent way to show off your extension! We recommend short, focused animations that are easy to follow.
## Requirements
If you have any requirements or dependencies, add a section describing those and how to install and configure them.
## Extension Settings
Include if your extension adds any VS Code settings through the `contributes.configuration` extension point.
For example:
This extension contributes the following settings:
* `myExtension.enable`: Enable/disable this extension.
* `myExtension.thing`: Set to `blah` to do something.
## Known Issues
Calling out known issues can help limit users opening duplicate issues against your extension.
## Release Notes
Users appreciate release notes as you update your extension.
### 1.0.0
Initial release of ...
### 1.0.1
Fixed issue #.
### 1.1.0
Added features X, Y, and Z.
---
## Working with Markdown
You can author your README using Visual Studio Code. Here are some useful editor keyboard shortcuts:
* Split the editor (`Cmd+\` on macOS or `Ctrl+\` on Windows and Linux)
* Toggle preview (`Shift+Cmd+V` on macOS or `Shift+Ctrl+V` on Windows and Linux)
* Press `Ctrl+Space` (Windows, Linux, macOS) to see a list of Markdown snippets
## For more information
* [Visual Studio Code's Markdown Support](http://code.visualstudio.com/docs/languages/markdown)
* [Markdown Syntax Reference](https://help.github.com/articles/markdown-basics/)
**Enjoy!**

234
extension.js Normal file
View File

@ -0,0 +1,234 @@
const vscode = require('vscode');
const path = require('path');
// Represents a file item in the file explorer
class FileItem {
constructor(uri, checked) {
this.uri = uri;
this.checked = checked || false;
}
}
// 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;
this.filterPatterns = ['*.*']; // Default filter pattern
}
refresh() {
this._onDidChangeTreeData.fire();
}
getTreeItem(element) {
return {
label: element.uri.fsPath,
collapsibleState: vscode.TreeItemCollapsibleState.None,
checked: element.checked
};
}
getChildren(element) {
if (element) {
return [];
}
return selectedFiles;
}
setFilter(filter) {
this.filterPatterns = filter.split(',').map(pattern => pattern.trim());
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
const addFilesCommand = vscode.commands.registerCommand('extension.addFilesToGPTContext', () => {
const workspaceFolders = vscode.workspace.workspaceFolders;
if (workspaceFolders && workspaceFolders.length > 0) {
const workspacePath = workspaceFolders[0].uri.fsPath;
vscode.workspace.findFiles('**/*', '', 1000).then(files => {
const fileItems = files.map(file => new FileItem(file));
selectedFiles.splice(0, selectedFiles.length, ...fileItems);
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();
// 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(message => {
if (message.command === 'submitQuestion') {
const question = message.text;
const selectedFilePaths = selectedFiles
.filter(file => file.checked)
.map(file => file.uri.fsPath);
const fileContents = selectedFilePaths
.map(filePath => {
const document = vscode.workspace.textDocuments.find(doc => doc.uri.fsPath === filePath);
if (document) {
const lines = document.getText().split('\n');
return `${filePath}\n${lines.join('\n')}`;
}
return '';
})
.join('\n\n');
panel.webview.html = getWebviewContent(fileContents, question);
} else if (message.command === 'fileSelectionChanged') {
const { filePath, checked } = message;
const file = selectedFiles.find(file => file.uri.fsPath === filePath);
if (file) {
file.checked = checked;
}
} else if (message.command === 'filterFiles') {
const { filter } = message;
fileDataProvider.setFilter(filter);
}
});
});
// Helper function to generate the HTML content for the webview panel
function getWebviewContent(fileContents, question) {
const fileItems = fileDataProvider
.filterFiles(selectedFiles)
.map(file => `
<div>
<input type="checkbox" id="${file.uri.fsPath}" name="file" value="${file.uri.fsPath}" ${file.checked ? 'checked' : ''}>
<label for="${file.uri.fsPath}">${file.uri.fsPath}</label>
</div>
`)
.join('\n');
return `
<html>
<body>
<h1>GPT Context</h1>
<form id="questionForm">
<label for="question">Enter your question:</label>
<input type="text" id="question" name="question" required>
<button type="submit">Submit</button>
</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>` : ''
}
<div><pre>${question ? question : ''}</pre></div>
<script>
const vscode = acquireVsCodeApi();
const form = document.getElementById('questionForm');
form.addEventListener('submit', event => {
event.preventDefault();
const question = document.getElementById('question').value;
vscode.postMessage({
command: 'submitQuestion',
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>
</body>
</html>
`;
}
// Activates the extension
function activate(context) {
// Register the file data provider
vscode.window.registerTreeDataProvider('gpt-contextfiles', fileDataProvider);
// Register the commands
context.subscriptions.push(addFilesCommand);
context.subscriptions.push(openGPTContextPanelCommand);
// Refresh the file data provider when a file is added or removed from the workspace
vscode.workspace.onDidChangeWorkspaceFolders(() => {
fileDataProvider.refresh();
});
// Refresh the file data provider when a file is created, deleted, or renamed within the workspace
vscode.workspace.onDidChangeTextDocument(() => {
fileDataProvider.refresh();
});
}
module.exports = {
activate
};

13
jsconfig.json Normal file
View File

@ -0,0 +1,13 @@
{
"compilerOptions": {
"module": "commonjs",
"target": "ES2020",
"checkJs": true, /* Typecheck .js files. */
"lib": [
"ES2020"
]
},
"exclude": [
"node_modules"
]
}

1953
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

56
package.json Normal file
View File

@ -0,0 +1,56 @@
{
"name": "gpt-contextfiles",
"displayName": "GPT-ContextFiles",
"description": "Choose the files to pass into GPT to provide a question with multiple files (doesn't check context)",
"version": "0.0.1",
"engines": {
"vscode": "^1.79.0"
},
"categories": [
"Other"
],
"activationEvents": [
"onCommand:extension.addFilesToGPTContext",
"onCommand:extension.openGPTContextPanel"
],
"main": "./extension.js",
"contributes": {
"commands": [
{
"command": "extension.addFilesToGPTContext",
"title": "Add Files to GPT Context",
"category": "Explorer"
},
{
"command": "extension.openGPTContextPanel",
"title": "Open GPT Context Panel"
}
],
"menus": {
"explorer/context": [
{
"when": "resourceLangId == javascript",
"command": "extension.addFilesToGPTContext",
"group": "navigation"
}
]
}
},
"scripts": {
"lint": "eslint .",
"pretest": "npm run lint",
"test": "node ./test/runTest.js"
},
"devDependencies": {
"@types/vscode": "^1.79.0",
"@types/glob": "^8.1.0",
"@types/mocha": "^10.0.1",
"@types/node": "20.2.5",
"eslint": "^8.41.0",
"glob": "^8.1.0",
"mocha": "^10.2.0",
"typescript": "^5.1.3",
"@vscode/test-electron": "^2.3.2"
}
}

23
test/runTest.js Normal file
View File

@ -0,0 +1,23 @@
const path = require('path');
const { runTests } = require('@vscode/test-electron');
async function main() {
try {
// The folder containing the Extension Manifest package.json
// Passed to `--extensionDevelopmentPath`
const extensionDevelopmentPath = path.resolve(__dirname, '../');
// The path to the extension test script
// Passed to --extensionTestsPath
const extensionTestsPath = path.resolve(__dirname, './suite/index');
// Download VS Code, unzip it and run the integration test
await runTests({ extensionDevelopmentPath, extensionTestsPath });
} catch (err) {
console.error('Failed to run tests', err);
process.exit(1);
}
}
main();

View File

@ -0,0 +1,15 @@
const assert = require('assert');
// You can import and use all API from the 'vscode' module
// as well as import your extension to test it
const vscode = require('vscode');
// const myExtension = require('../extension');
suite('Extension Test Suite', () => {
vscode.window.showInformationMessage('Start all tests.');
test('Sample test', () => {
assert.strictEqual(-1, [1, 2, 3].indexOf(5));
assert.strictEqual(-1, [1, 2, 3].indexOf(0));
});
});

42
test/suite/index.js Normal file
View File

@ -0,0 +1,42 @@
const path = require('path');
const Mocha = require('mocha');
const glob = require('glob');
function run() {
// Create the mocha test
const mocha = new Mocha({
ui: 'tdd',
color: true
});
const testsRoot = path.resolve(__dirname, '..');
return new Promise((c, e) => {
glob('**/**.test.js', { cwd: testsRoot }, (err, files) => {
if (err) {
return e(err);
}
// Add files to the test suite
files.forEach(f => mocha.addFile(path.resolve(testsRoot, f)));
try {
// Run the mocha test
mocha.run(failures => {
if (failures > 0) {
e(new Error(`${failures} tests failed.`));
} else {
c();
}
});
} catch (err) {
console.error(err);
e(err);
}
});
});
}
module.exports = {
run
};

View File

@ -0,0 +1,41 @@
# Welcome to your VS Code Extension
## What's in the folder
* This folder contains all of the files necessary for your extension.
* `package.json` - this is the manifest file in which you declare your extension and command.
* The sample plugin registers a command and defines its title and command name. With this information VS Code can show the command in the command palette. It doesnt yet need to load the plugin.
* `extension.js` - this is the main file where you will provide the implementation of your command.
* The file exports one function, `activate`, which is called the very first time your extension is activated (in this case by executing the command). Inside the `activate` function we call `registerCommand`.
* We pass the function containing the implementation of the command as the second parameter to `registerCommand`.
## Get up and running straight away
* Press `F5` to open a new window with your extension loaded.
* Run your command from the command palette by pressing (`Ctrl+Shift+P` or `Cmd+Shift+P` on Mac) and typing `Hello World`.
* Set breakpoints in your code inside `extension.js` to debug your extension.
* Find output from your extension in the debug console.
## Make changes
* You can relaunch the extension from the debug toolbar after changing code in `extension.js`.
* You can also reload (`Ctrl+R` or `Cmd+R` on Mac) the VS Code window with your extension to load your changes.
## Explore the API
* You can open the full set of our API when you open the file `node_modules/@types/vscode/index.d.ts`.
## Run tests
* Open the debug viewlet (`Ctrl+Shift+D` or `Cmd+Shift+D` on Mac) and from the launch configuration dropdown pick `Extension Tests`.
* Press `F5` to run the tests in a new window with your extension loaded.
* See the output of the test result in the debug console.
* Make changes to `src/test/suite/extension.test.js` or create new test files inside the `test/suite` folder.
* The provided test runner will only consider files matching the name pattern `**.test.ts`.
* You can create folders inside the `test` folder to structure your tests any way you want.
## Go further
* [Follow UX guidelines](https://code.visualstudio.com/api/ux-guidelines/overview) to create extensions that seamlessly integrate with VS Code's native interface and patterns.
* [Publish your extension](https://code.visualstudio.com/api/working-with-extensions/publishing-extension) on the VS Code extension marketplace.
* Automate builds by setting up [Continuous Integration](https://code.visualstudio.com/api/working-with-extensions/continuous-integration).