From 19e6da3956dcc3afa1ebf323419afcb8fcc4fae1 Mon Sep 17 00:00:00 2001
From: "codegen-sh[bot]" <131295404+codegen-sh[bot]@users.noreply.github.com>
Date: Fri, 25 Apr 2025 05:31:17 +0000
Subject: [PATCH 1/4] Implement VSCode Extension for Codegen
---
codegen-vscode-extension/README.md | 78 +++++
.../media/codegen-icon.svg | 5 +
codegen-vscode-extension/media/main.css | 237 +++++++++++++++
codegen-vscode-extension/media/main.js | 170 +++++++++++
codegen-vscode-extension/package.json | 132 ++++++++
.../src/api/codegenAPI.ts | 136 +++++++++
codegen-vscode-extension/src/commands.ts | 287 ++++++++++++++++++
codegen-vscode-extension/src/extension.ts | 36 +++
.../src/providers/chatViewProvider.ts | 154 ++++++++++
codegen-vscode-extension/src/utils.ts | 102 +++++++
codegen-vscode-extension/tsconfig.json | 15 +
codegen-vscode-extension/webpack.config.js | 34 +++
12 files changed, 1386 insertions(+)
create mode 100644 codegen-vscode-extension/README.md
create mode 100644 codegen-vscode-extension/media/codegen-icon.svg
create mode 100644 codegen-vscode-extension/media/main.css
create mode 100644 codegen-vscode-extension/media/main.js
create mode 100644 codegen-vscode-extension/package.json
create mode 100644 codegen-vscode-extension/src/api/codegenAPI.ts
create mode 100644 codegen-vscode-extension/src/commands.ts
create mode 100644 codegen-vscode-extension/src/extension.ts
create mode 100644 codegen-vscode-extension/src/providers/chatViewProvider.ts
create mode 100644 codegen-vscode-extension/src/utils.ts
create mode 100644 codegen-vscode-extension/tsconfig.json
create mode 100644 codegen-vscode-extension/webpack.config.js
diff --git a/codegen-vscode-extension/README.md b/codegen-vscode-extension/README.md
new file mode 100644
index 000000000..666ea4750
--- /dev/null
+++ b/codegen-vscode-extension/README.md
@@ -0,0 +1,78 @@
+# Codegen VSCode Extension
+
+A VSCode extension for Codegen - AI-powered code generation and assistance.
+
+## Features
+
+- **Ask Questions**: Get answers to your programming questions directly in VSCode
+- **Generate Code**: Generate code snippets based on your descriptions
+- **Explain Code**: Get explanations for selected code
+- **Improve Code**: Get suggestions to improve your code
+- **Fix Code**: Get help fixing bugs in your code
+
+## Requirements
+
+- VSCode 1.78.0 or higher
+- A Codegen API key (get one at [codegen.sh](https://codegen.sh))
+
+## Installation
+
+1. Install the extension from the VSCode Marketplace
+2. Set your Codegen API key in the extension settings
+3. Start using Codegen in your development workflow!
+
+## Extension Settings
+
+This extension contributes the following settings:
+
+* `codegen.apiKey`: Your Codegen API key
+* `codegen.endpoint`: The endpoint for the Codegen API (defaults to https://api.codegen.sh)
+
+## Commands
+
+The extension provides the following commands:
+
+* `codegen.askQuestion`: Ask Codegen a question
+* `codegen.generateCode`: Generate code with Codegen
+* `codegen.explainCode`: Explain selected code
+* `codegen.improveCode`: Improve selected code
+* `codegen.fixCode`: Fix selected code
+
+## Usage
+
+### Ask a Question
+
+1. Open the command palette (`Ctrl+Shift+P` or `Cmd+Shift+P` on macOS)
+2. Type "Ask Codegen a Question" and press Enter
+3. Enter your question and press Enter
+4. View the response in the Codegen Chat view
+
+### Generate Code
+
+1. Open the command palette
+2. Type "Generate Code with Codegen" and press Enter
+3. Describe the code you want to generate
+4. The generated code will be inserted at your cursor position
+
+### Explain Code
+
+1. Select the code you want to explain
+2. Right-click and select "Explain Selected Code" from the context menu
+3. View the explanation in the Codegen Chat view
+
+### Improve Code
+
+1. Select the code you want to improve
+2. Right-click and select "Improve Selected Code" from the context menu
+3. Review the suggested improvements and apply them if desired
+
+### Fix Code
+
+1. Select the code you want to fix
+2. Right-click and select "Fix Selected Code" from the context menu
+3. Optionally provide the error message you're getting
+4. Review the suggested fixes and apply them if desired
+
+## License
+
+MIT
diff --git a/codegen-vscode-extension/media/codegen-icon.svg b/codegen-vscode-extension/media/codegen-icon.svg
new file mode 100644
index 000000000..53aa599b8
--- /dev/null
+++ b/codegen-vscode-extension/media/codegen-icon.svg
@@ -0,0 +1,5 @@
+
diff --git a/codegen-vscode-extension/media/main.css b/codegen-vscode-extension/media/main.css
new file mode 100644
index 000000000..fcb28f268
--- /dev/null
+++ b/codegen-vscode-extension/media/main.css
@@ -0,0 +1,237 @@
+:root {
+ --container-padding: 10px;
+ --input-padding-vertical: 6px;
+ --input-padding-horizontal: 8px;
+ --input-margin-vertical: 4px;
+ --input-margin-horizontal: 0;
+}
+
+body {
+ padding: 0;
+ margin: 0;
+ color: var(--vscode-foreground);
+ font-size: var(--vscode-font-size);
+ font-weight: var(--vscode-font-weight);
+ font-family: var(--vscode-font-family);
+ background-color: var(--vscode-editor-background);
+}
+
+#chat-container {
+ display: flex;
+ flex-direction: column;
+ height: 100vh;
+ padding: var(--container-padding);
+ box-sizing: border-box;
+}
+
+#messages {
+ flex: 1;
+ overflow-y: auto;
+ margin-bottom: 10px;
+ padding-right: 8px;
+}
+
+.message {
+ margin-bottom: 10px;
+ padding: 8px 12px;
+ border-radius: 6px;
+ max-width: 90%;
+ word-wrap: break-word;
+}
+
+.user-message {
+ background-color: var(--vscode-button-background);
+ color: var(--vscode-button-foreground);
+ align-self: flex-end;
+ margin-left: auto;
+}
+
+.assistant-message {
+ background-color: var(--vscode-editor-inactiveSelectionBackground);
+ color: var(--vscode-editor-foreground);
+ align-self: flex-start;
+}
+
+.message-content {
+ margin-bottom: 5px;
+}
+
+.code-block {
+ background-color: var(--vscode-editor-background);
+ border: 1px solid var(--vscode-editor-lineHighlightBorder);
+ border-radius: 3px;
+ padding: 8px;
+ margin-top: 5px;
+ font-family: var(--vscode-editor-font-family);
+ font-size: var(--vscode-editor-font-size);
+ white-space: pre-wrap;
+ overflow-x: auto;
+}
+
+.code-actions {
+ display: flex;
+ justify-content: flex-end;
+ margin-top: 5px;
+}
+
+.code-action-button {
+ background-color: var(--vscode-button-secondaryBackground);
+ color: var(--vscode-button-secondaryForeground);
+ border: none;
+ padding: 4px 8px;
+ border-radius: 2px;
+ cursor: pointer;
+ font-size: 12px;
+ margin-left: 5px;
+}
+
+.code-action-button:hover {
+ background-color: var(--vscode-button-secondaryHoverBackground);
+}
+
+.timestamp {
+ font-size: 10px;
+ color: var(--vscode-descriptionForeground);
+ text-align: right;
+ margin-top: 2px;
+}
+
+#input-container {
+ display: flex;
+ padding: 8px 0;
+}
+
+#message-input {
+ flex: 1;
+ height: 60px;
+ padding: var(--input-padding-vertical) var(--input-padding-horizontal);
+ border: 1px solid var(--vscode-input-border);
+ background-color: var(--vscode-input-background);
+ color: var(--vscode-input-foreground);
+ resize: none;
+ font-family: var(--vscode-font-family);
+ font-size: var(--vscode-font-size);
+ border-radius: 2px;
+}
+
+#message-input:focus {
+ outline: 1px solid var(--vscode-focusBorder);
+}
+
+#send-button {
+ margin-left: 8px;
+ padding: 0 14px;
+ background-color: var(--vscode-button-background);
+ color: var(--vscode-button-foreground);
+ border: none;
+ cursor: pointer;
+ border-radius: 2px;
+}
+
+#send-button:hover {
+ background-color: var(--vscode-button-hoverBackground);
+}
+
+#loading {
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ background-color: rgba(0, 0, 0, 0.3);
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ z-index: 1000;
+}
+
+.hidden {
+ display: none !important;
+}
+
+.spinner {
+ width: 40px;
+ height: 40px;
+ border: 4px solid rgba(255, 255, 255, 0.3);
+ border-radius: 50%;
+ border-top-color: var(--vscode-button-background);
+ animation: spin 1s ease-in-out infinite;
+}
+
+@keyframes spin {
+ to {
+ transform: rotate(360deg);
+ }
+}
+
+/* Markdown styling */
+.markdown h1, .markdown h2, .markdown h3, .markdown h4, .markdown h5, .markdown h6 {
+ margin-top: 16px;
+ margin-bottom: 8px;
+ font-weight: 600;
+}
+
+.markdown p {
+ margin-top: 0;
+ margin-bottom: 8px;
+}
+
+.markdown ul, .markdown ol {
+ padding-left: 20px;
+ margin-top: 0;
+ margin-bottom: 8px;
+}
+
+.markdown code {
+ font-family: var(--vscode-editor-font-family);
+ background-color: var(--vscode-textCodeBlock-background);
+ padding: 2px 4px;
+ border-radius: 3px;
+}
+
+.markdown pre {
+ background-color: var(--vscode-textCodeBlock-background);
+ padding: 8px;
+ border-radius: 3px;
+ overflow-x: auto;
+ margin-top: 8px;
+ margin-bottom: 8px;
+}
+
+.markdown pre code {
+ background-color: transparent;
+ padding: 0;
+}
+
+.markdown a {
+ color: var(--vscode-textLink-foreground);
+ text-decoration: none;
+}
+
+.markdown a:hover {
+ text-decoration: underline;
+}
+
+.markdown blockquote {
+ border-left: 3px solid var(--vscode-textBlockQuote-border);
+ padding-left: 8px;
+ margin-left: 0;
+ margin-right: 0;
+ color: var(--vscode-textBlockQuote-foreground);
+}
+
+.markdown table {
+ border-collapse: collapse;
+ width: 100%;
+ margin-bottom: 16px;
+}
+
+.markdown th, .markdown td {
+ border: 1px solid var(--vscode-editor-lineHighlightBorder);
+ padding: 6px 13px;
+}
+
+.markdown th {
+ background-color: var(--vscode-editor-inactiveSelectionBackground);
+ font-weight: 600;
+}
diff --git a/codegen-vscode-extension/media/main.js b/codegen-vscode-extension/media/main.js
new file mode 100644
index 000000000..76183cebd
--- /dev/null
+++ b/codegen-vscode-extension/media/main.js
@@ -0,0 +1,170 @@
+(function() {
+ // Get VS Code API
+ const vscode = acquireVsCodeApi();
+
+ // DOM elements
+ const messagesContainer = document.getElementById('messages');
+ const messageInput = document.getElementById('message-input');
+ const sendButton = document.getElementById('send-button');
+ const loadingElement = document.getElementById('loading');
+
+ // Store messages
+ let messages = [];
+
+ // Initialize
+ window.addEventListener('message', event => {
+ const message = event.data;
+
+ switch (message.command) {
+ case 'updateMessages':
+ messages = message.messages;
+ renderMessages();
+ break;
+ case 'showLoading':
+ toggleLoading(message.value);
+ break;
+ }
+ });
+
+ // Send message when button is clicked
+ sendButton.addEventListener('click', () => {
+ sendMessage();
+ });
+
+ // Send message when Enter is pressed (without Shift)
+ messageInput.addEventListener('keydown', (e) => {
+ if (e.key === 'Enter' && !e.shiftKey) {
+ e.preventDefault();
+ sendMessage();
+ }
+ });
+
+ // Send message to extension
+ function sendMessage() {
+ const text = messageInput.value.trim();
+ if (text) {
+ vscode.postMessage({
+ command: 'sendMessage',
+ text: text
+ });
+ messageInput.value = '';
+ }
+ }
+
+ // Render all messages
+ function renderMessages() {
+ messagesContainer.innerHTML = '';
+
+ messages.forEach(message => {
+ const messageElement = document.createElement('div');
+ messageElement.className = `message ${message.role}-message`;
+
+ // Message content
+ const contentElement = document.createElement('div');
+ contentElement.className = 'message-content markdown';
+ contentElement.innerHTML = formatMarkdown(message.content);
+ messageElement.appendChild(contentElement);
+
+ // Code block (if any)
+ if (message.code) {
+ const codeElement = document.createElement('div');
+ codeElement.className = 'code-block';
+ codeElement.textContent = message.code;
+ messageElement.appendChild(codeElement);
+
+ // Code actions
+ const actionsElement = document.createElement('div');
+ actionsElement.className = 'code-actions';
+
+ // Insert code button
+ const insertButton = document.createElement('button');
+ insertButton.className = 'code-action-button';
+ insertButton.textContent = 'Insert Code';
+ insertButton.addEventListener('click', () => {
+ vscode.postMessage({
+ command: 'insertCode',
+ code: message.code
+ });
+ });
+ actionsElement.appendChild(insertButton);
+
+ // Copy code button
+ const copyButton = document.createElement('button');
+ copyButton.className = 'code-action-button';
+ copyButton.textContent = 'Copy';
+ copyButton.addEventListener('click', () => {
+ navigator.clipboard.writeText(message.code);
+ copyButton.textContent = 'Copied!';
+ setTimeout(() => {
+ copyButton.textContent = 'Copy';
+ }, 2000);
+ });
+ actionsElement.appendChild(copyButton);
+
+ messageElement.appendChild(actionsElement);
+ }
+
+ // Timestamp
+ const timestampElement = document.createElement('div');
+ timestampElement.className = 'timestamp';
+ timestampElement.textContent = formatTimestamp(message.timestamp);
+ messageElement.appendChild(timestampElement);
+
+ messagesContainer.appendChild(messageElement);
+ });
+
+ // Scroll to bottom
+ messagesContainer.scrollTop = messagesContainer.scrollHeight;
+ }
+
+ // Format timestamp
+ function formatTimestamp(timestamp) {
+ const date = new Date(timestamp);
+ return date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
+ }
+
+ // Toggle loading indicator
+ function toggleLoading(show) {
+ if (show) {
+ loadingElement.classList.remove('hidden');
+ } else {
+ loadingElement.classList.add('hidden');
+ }
+ }
+
+ // Format markdown to HTML
+ function formatMarkdown(text) {
+ // This is a very simple markdown parser
+ // In a real extension, you might want to use a library like marked.js
+
+ // Code blocks
+ text = text.replace(/```(\w*)\n([\s\S]*?)\n```/g, '
$2
');
+
+ // Inline code
+ text = text.replace(/`([^`]+)`/g, '$1');
+
+ // Headers
+ text = text.replace(/^### (.*$)/gm, '$1
');
+ text = text.replace(/^## (.*$)/gm, '$1
');
+ text = text.replace(/^# (.*$)/gm, '$1
');
+
+ // Bold
+ text = text.replace(/\*\*(.*?)\*\*/g, '$1');
+
+ // Italic
+ text = text.replace(/\*(.*?)\*/g, '$1');
+
+ // Lists
+ text = text.replace(/^\s*\*\s(.*$)/gm, '$1');
+ text = text.replace(/(.*<\/li>)/g, '');
+
+ // Links
+ text = text.replace(/\[(.*?)\]\((.*?)\)/g, '$1');
+
+ // Paragraphs
+ text = text.replace(/\n\n/g, '');
+ text = '
' + text + '
';
+
+ return text;
+ }
+})();
diff --git a/codegen-vscode-extension/package.json b/codegen-vscode-extension/package.json
new file mode 100644
index 000000000..f57e7e552
--- /dev/null
+++ b/codegen-vscode-extension/package.json
@@ -0,0 +1,132 @@
+{
+ "name": "codegen-vscode-extension",
+ "displayName": "Codegen",
+ "description": "VSCode extension for Codegen - AI-powered code generation and assistance",
+ "version": "0.1.0",
+ "engines": {
+ "vscode": "^1.78.0"
+ },
+ "categories": [
+ "Programming Languages",
+ "Machine Learning",
+ "Other"
+ ],
+ "activationEvents": [
+ "onStartupFinished"
+ ],
+ "main": "./dist/extension.js",
+ "contributes": {
+ "commands": [
+ {
+ "command": "codegen.askQuestion",
+ "title": "Ask Codegen a Question",
+ "category": "Codegen"
+ },
+ {
+ "command": "codegen.generateCode",
+ "title": "Generate Code with Codegen",
+ "category": "Codegen"
+ },
+ {
+ "command": "codegen.explainCode",
+ "title": "Explain Selected Code",
+ "category": "Codegen"
+ },
+ {
+ "command": "codegen.improveCode",
+ "title": "Improve Selected Code",
+ "category": "Codegen"
+ },
+ {
+ "command": "codegen.fixCode",
+ "title": "Fix Selected Code",
+ "category": "Codegen"
+ }
+ ],
+ "viewsContainers": {
+ "activitybar": [
+ {
+ "id": "codegen-sidebar",
+ "title": "Codegen",
+ "icon": "media/codegen-icon.svg"
+ }
+ ]
+ },
+ "views": {
+ "codegen-sidebar": [
+ {
+ "type": "webview",
+ "id": "codegen.chatView",
+ "name": "Codegen Chat"
+ }
+ ]
+ },
+ "configuration": {
+ "title": "Codegen",
+ "properties": {
+ "codegen.apiKey": {
+ "type": "string",
+ "default": "",
+ "description": "API key for Codegen services"
+ },
+ "codegen.endpoint": {
+ "type": "string",
+ "default": "https://api.codegen.sh",
+ "description": "Endpoint for Codegen API"
+ }
+ }
+ },
+ "menus": {
+ "editor/context": [
+ {
+ "command": "codegen.explainCode",
+ "when": "editorHasSelection",
+ "group": "codegen"
+ },
+ {
+ "command": "codegen.improveCode",
+ "when": "editorHasSelection",
+ "group": "codegen"
+ },
+ {
+ "command": "codegen.fixCode",
+ "when": "editorHasSelection",
+ "group": "codegen"
+ },
+ {
+ "command": "codegen.generateCode",
+ "group": "codegen"
+ }
+ ]
+ }
+ },
+ "scripts": {
+ "vscode:prepublish": "npm run package",
+ "compile": "webpack",
+ "watch": "webpack --watch",
+ "package": "webpack --mode production --devtool source-map --config ./webpack.config.js",
+ "compile-tests": "tsc -p . --outDir out",
+ "watch-tests": "tsc -p . -w --outDir out",
+ "lint": "eslint src --ext ts",
+ "test": "node ./out/test/runTest.js"
+ },
+ "devDependencies": {
+ "@types/glob": "^8.1.0",
+ "@types/mocha": "^10.0.1",
+ "@types/node": "16.x",
+ "@types/vscode": "^1.78.0",
+ "@typescript-eslint/eslint-plugin": "^5.59.1",
+ "@typescript-eslint/parser": "^5.59.1",
+ "@vscode/test-electron": "^2.3.0",
+ "eslint": "^8.39.0",
+ "glob": "^8.1.0",
+ "mocha": "^10.2.0",
+ "ts-loader": "^9.4.2",
+ "typescript": "^5.0.4",
+ "webpack": "^5.81.0",
+ "webpack-cli": "^5.0.2"
+ },
+ "dependencies": {
+ "axios": "^1.4.0"
+ }
+}
diff --git a/codegen-vscode-extension/src/api/codegenAPI.ts b/codegen-vscode-extension/src/api/codegenAPI.ts
new file mode 100644
index 000000000..9a98c6185
--- /dev/null
+++ b/codegen-vscode-extension/src/api/codegenAPI.ts
@@ -0,0 +1,136 @@
+import axios, { AxiosInstance } from 'axios';
+import * as vscode from 'vscode';
+
+export interface CodegenResponse {
+ text: string;
+ code?: string;
+ language?: string;
+}
+
+export class CodegenAPI {
+ private client: AxiosInstance;
+ private apiKey: string = '';
+ private endpoint: string = '';
+
+ constructor() {
+ this.loadConfiguration();
+
+ this.client = axios.create({
+ baseURL: this.endpoint,
+ headers: {
+ 'Content-Type': 'application/json',
+ 'Authorization': `Bearer ${this.apiKey}`
+ }
+ });
+
+ // Listen for configuration changes
+ vscode.workspace.onDidChangeConfiguration(e => {
+ if (e.affectsConfiguration('codegen.apiKey') || e.affectsConfiguration('codegen.endpoint')) {
+ this.loadConfiguration();
+ this.updateClient();
+ }
+ });
+ }
+
+ private loadConfiguration() {
+ const config = vscode.workspace.getConfiguration('codegen');
+ this.apiKey = config.get('apiKey') || '';
+ this.endpoint = config.get('endpoint') || 'https://api.codegen.sh';
+ }
+
+ private updateClient() {
+ this.client = axios.create({
+ baseURL: this.endpoint,
+ headers: {
+ 'Content-Type': 'application/json',
+ 'Authorization': `Bearer ${this.apiKey}`
+ }
+ });
+ }
+
+ public async validateApiKey(): Promise {
+ if (!this.apiKey) {
+ return false;
+ }
+
+ try {
+ // Make a simple request to validate the API key
+ await this.client.get('/api/validate');
+ return true;
+ } catch (error) {
+ console.error('API key validation failed:', error);
+ return false;
+ }
+ }
+
+ public async askQuestion(question: string, context?: string): Promise {
+ try {
+ const response = await this.client.post('/api/ask', {
+ question,
+ context
+ });
+
+ return response.data;
+ } catch (error) {
+ console.error('Error asking question:', error);
+ throw new Error('Failed to get response from Codegen API');
+ }
+ }
+
+ public async generateCode(prompt: string, language?: string): Promise {
+ try {
+ const response = await this.client.post('/api/generate', {
+ prompt,
+ language
+ });
+
+ return response.data;
+ } catch (error) {
+ console.error('Error generating code:', error);
+ throw new Error('Failed to generate code from Codegen API');
+ }
+ }
+
+ public async explainCode(code: string, language?: string): Promise {
+ try {
+ const response = await this.client.post('/api/explain', {
+ code,
+ language
+ });
+
+ return response.data;
+ } catch (error) {
+ console.error('Error explaining code:', error);
+ throw new Error('Failed to explain code from Codegen API');
+ }
+ }
+
+ public async improveCode(code: string, language?: string): Promise {
+ try {
+ const response = await this.client.post('/api/improve', {
+ code,
+ language
+ });
+
+ return response.data;
+ } catch (error) {
+ console.error('Error improving code:', error);
+ throw new Error('Failed to improve code from Codegen API');
+ }
+ }
+
+ public async fixCode(code: string, error?: string, language?: string): Promise {
+ try {
+ const response = await this.client.post('/api/fix', {
+ code,
+ error,
+ language
+ });
+
+ return response.data;
+ } catch (error) {
+ console.error('Error fixing code:', error);
+ throw new Error('Failed to fix code from Codegen API');
+ }
+ }
+}
diff --git a/codegen-vscode-extension/src/commands.ts b/codegen-vscode-extension/src/commands.ts
new file mode 100644
index 000000000..7a7c6682a
--- /dev/null
+++ b/codegen-vscode-extension/src/commands.ts
@@ -0,0 +1,287 @@
+import * as vscode from 'vscode';
+import { CodegenAPI } from './api/codegenAPI';
+import { ChatViewProvider } from './providers/chatViewProvider';
+import { getSelectedText, getDocumentLanguage, insertText } from './utils';
+
+export function registerCommands(
+ context: vscode.ExtensionContext,
+ api: CodegenAPI,
+ chatViewProvider: ChatViewProvider
+) {
+ // Ask a question
+ context.subscriptions.push(
+ vscode.commands.registerCommand('codegen.askQuestion', async () => {
+ const question = await vscode.window.showInputBox({
+ prompt: 'What would you like to ask Codegen?',
+ placeHolder: 'Ask a programming question...'
+ });
+
+ if (!question) {
+ return;
+ }
+
+ try {
+ vscode.window.withProgress({
+ location: vscode.ProgressLocation.Notification,
+ title: 'Asking Codegen...',
+ cancellable: false
+ }, async (progress) => {
+ progress.report({ increment: 0 });
+
+ const response = await api.askQuestion(question);
+
+ progress.report({ increment: 100 });
+
+ // Send to chat view
+ chatViewProvider.addMessage('user', question);
+ chatViewProvider.addMessage('assistant', response.text);
+
+ // Show the chat view
+ vscode.commands.executeCommand('codegen.chatView.focus');
+
+ return response;
+ });
+ } catch (error) {
+ vscode.window.showErrorMessage(`Error: ${error.message}`);
+ }
+ })
+ );
+
+ // Generate code
+ context.subscriptions.push(
+ vscode.commands.registerCommand('codegen.generateCode', async () => {
+ const prompt = await vscode.window.showInputBox({
+ prompt: 'Describe the code you want to generate',
+ placeHolder: 'Generate a function that...'
+ });
+
+ if (!prompt) {
+ return;
+ }
+
+ const editor = vscode.window.activeTextEditor;
+ const language = editor ? getDocumentLanguage(editor.document) : undefined;
+
+ try {
+ vscode.window.withProgress({
+ location: vscode.ProgressLocation.Notification,
+ title: 'Generating code...',
+ cancellable: false
+ }, async (progress) => {
+ progress.report({ increment: 0 });
+
+ const response = await api.generateCode(prompt, language);
+
+ progress.report({ increment: 100 });
+
+ if (editor && response.code) {
+ // Insert the generated code at the cursor position
+ insertText(editor, response.code);
+ }
+
+ // Send to chat view
+ chatViewProvider.addMessage('user', `Generate code: ${prompt}`);
+ chatViewProvider.addMessage('assistant', response.text, response.code);
+
+ return response;
+ });
+ } catch (error) {
+ vscode.window.showErrorMessage(`Error: ${error.message}`);
+ }
+ })
+ );
+
+ // Explain code
+ context.subscriptions.push(
+ vscode.commands.registerCommand('codegen.explainCode', async () => {
+ const editor = vscode.window.activeTextEditor;
+ if (!editor) {
+ vscode.window.showErrorMessage('No active editor');
+ return;
+ }
+
+ const selectedText = getSelectedText(editor);
+ if (!selectedText) {
+ vscode.window.showErrorMessage('No code selected');
+ return;
+ }
+
+ const language = getDocumentLanguage(editor.document);
+
+ try {
+ vscode.window.withProgress({
+ location: vscode.ProgressLocation.Notification,
+ title: 'Explaining code...',
+ cancellable: false
+ }, async (progress) => {
+ progress.report({ increment: 0 });
+
+ const response = await api.explainCode(selectedText, language);
+
+ progress.report({ increment: 100 });
+
+ // Send to chat view
+ chatViewProvider.addMessage('user', `Explain this code:\n\`\`\`${language}\n${selectedText}\n\`\`\``);
+ chatViewProvider.addMessage('assistant', response.text);
+
+ // Show the chat view
+ vscode.commands.executeCommand('codegen.chatView.focus');
+
+ return response;
+ });
+ } catch (error) {
+ vscode.window.showErrorMessage(`Error: ${error.message}`);
+ }
+ })
+ );
+
+ // Improve code
+ context.subscriptions.push(
+ vscode.commands.registerCommand('codegen.improveCode', async () => {
+ const editor = vscode.window.activeTextEditor;
+ if (!editor) {
+ vscode.window.showErrorMessage('No active editor');
+ return;
+ }
+
+ const selectedText = getSelectedText(editor);
+ if (!selectedText) {
+ vscode.window.showErrorMessage('No code selected');
+ return;
+ }
+
+ const language = getDocumentLanguage(editor.document);
+
+ try {
+ vscode.window.withProgress({
+ location: vscode.ProgressLocation.Notification,
+ title: 'Improving code...',
+ cancellable: false
+ }, async (progress) => {
+ progress.report({ increment: 0 });
+
+ const response = await api.improveCode(selectedText, language);
+
+ progress.report({ increment: 100 });
+
+ if (response.code) {
+ // Show diff and ask if user wants to apply changes
+ const document = editor.document;
+ const selection = editor.selection;
+
+ const diffEditor = await vscode.diff.createTextDocumentAndEditorEdit(
+ document,
+ selection,
+ response.code
+ );
+
+ // Add buttons to apply or discard changes
+ const applyChanges = 'Apply Changes';
+ const discardChanges = 'Discard';
+
+ const choice = await vscode.window.showInformationMessage(
+ 'Review the suggested improvements',
+ applyChanges,
+ discardChanges
+ );
+
+ if (choice === applyChanges) {
+ // Replace the selected text with the improved code
+ editor.edit(editBuilder => {
+ editBuilder.replace(selection, response.code || '');
+ });
+ }
+ }
+
+ // Send to chat view
+ chatViewProvider.addMessage('user', `Improve this code:\n\`\`\`${language}\n${selectedText}\n\`\`\``);
+ chatViewProvider.addMessage('assistant', response.text, response.code);
+
+ return response;
+ });
+ } catch (error) {
+ vscode.window.showErrorMessage(`Error: ${error.message}`);
+ }
+ })
+ );
+
+ // Fix code
+ context.subscriptions.push(
+ vscode.commands.registerCommand('codegen.fixCode', async () => {
+ const editor = vscode.window.activeTextEditor;
+ if (!editor) {
+ vscode.window.showErrorMessage('No active editor');
+ return;
+ }
+
+ const selectedText = getSelectedText(editor);
+ if (!selectedText) {
+ vscode.window.showErrorMessage('No code selected');
+ return;
+ }
+
+ const language = getDocumentLanguage(editor.document);
+
+ // Ask for error message
+ const errorMessage = await vscode.window.showInputBox({
+ prompt: 'What error are you getting? (optional)',
+ placeHolder: 'Error message or description of the issue'
+ });
+
+ try {
+ vscode.window.withProgress({
+ location: vscode.ProgressLocation.Notification,
+ title: 'Fixing code...',
+ cancellable: false
+ }, async (progress) => {
+ progress.report({ increment: 0 });
+
+ const response = await api.fixCode(selectedText, errorMessage, language);
+
+ progress.report({ increment: 100 });
+
+ if (response.code) {
+ // Show diff and ask if user wants to apply changes
+ const document = editor.document;
+ const selection = editor.selection;
+
+ const diffEditor = await vscode.diff.createTextDocumentAndEditorEdit(
+ document,
+ selection,
+ response.code
+ );
+
+ // Add buttons to apply or discard changes
+ const applyChanges = 'Apply Changes';
+ const discardChanges = 'Discard';
+
+ const choice = await vscode.window.showInformationMessage(
+ 'Review the suggested fixes',
+ applyChanges,
+ discardChanges
+ );
+
+ if (choice === applyChanges) {
+ // Replace the selected text with the fixed code
+ editor.edit(editBuilder => {
+ editBuilder.replace(selection, response.code || '');
+ });
+ }
+ }
+
+ // Send to chat view
+ const userMessage = errorMessage
+ ? `Fix this code (error: ${errorMessage}):\n\`\`\`${language}\n${selectedText}\n\`\`\``
+ : `Fix this code:\n\`\`\`${language}\n${selectedText}\n\`\`\``;
+
+ chatViewProvider.addMessage('user', userMessage);
+ chatViewProvider.addMessage('assistant', response.text, response.code);
+
+ return response;
+ });
+ } catch (error) {
+ vscode.window.showErrorMessage(`Error: ${error.message}`);
+ }
+ })
+ );
+}
diff --git a/codegen-vscode-extension/src/extension.ts b/codegen-vscode-extension/src/extension.ts
new file mode 100644
index 000000000..101ad8344
--- /dev/null
+++ b/codegen-vscode-extension/src/extension.ts
@@ -0,0 +1,36 @@
+import * as vscode from 'vscode';
+import { ChatViewProvider } from './providers/chatViewProvider';
+import { CodegenAPI } from './api/codegenAPI';
+import { registerCommands } from './commands';
+
+export function activate(context: vscode.ExtensionContext) {
+ console.log('Codegen extension is now active!');
+
+ // Initialize the API client
+ const api = new CodegenAPI();
+
+ // Register the chat view provider
+ const chatViewProvider = new ChatViewProvider(context.extensionUri, api);
+ context.subscriptions.push(
+ vscode.window.registerWebviewViewProvider(
+ 'codegen.chatView',
+ chatViewProvider,
+ { webviewOptions: { retainContextWhenHidden: true } }
+ )
+ );
+
+ // Register commands
+ registerCommands(context, api, chatViewProvider);
+
+ // Status bar item
+ const statusBarItem = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Right, 100);
+ statusBarItem.text = '$(sparkle) Codegen';
+ statusBarItem.tooltip = 'Codegen AI Assistant';
+ statusBarItem.command = 'codegen.askQuestion';
+ statusBarItem.show();
+ context.subscriptions.push(statusBarItem);
+}
+
+export function deactivate() {
+ // Clean up resources
+}
diff --git a/codegen-vscode-extension/src/providers/chatViewProvider.ts b/codegen-vscode-extension/src/providers/chatViewProvider.ts
new file mode 100644
index 000000000..3ad0e5f91
--- /dev/null
+++ b/codegen-vscode-extension/src/providers/chatViewProvider.ts
@@ -0,0 +1,154 @@
+import * as vscode from 'vscode';
+import { CodegenAPI } from '../api/codegenAPI';
+
+interface ChatMessage {
+ role: 'user' | 'assistant';
+ content: string;
+ code?: string;
+ timestamp: number;
+}
+
+export class ChatViewProvider implements vscode.WebviewViewProvider {
+ public static readonly viewType = 'codegen.chatView';
+ private _view?: vscode.WebviewView;
+ private _messages: ChatMessage[] = [];
+
+ constructor(
+ private readonly _extensionUri: vscode.Uri,
+ private readonly _api: CodegenAPI
+ ) {}
+
+ public resolveWebviewView(
+ webviewView: vscode.WebviewView,
+ context: vscode.WebviewViewResolveContext,
+ _token: vscode.CancellationToken
+ ) {
+ this._view = webviewView;
+
+ webviewView.webview.options = {
+ enableScripts: true,
+ localResourceRoots: [this._extensionUri]
+ };
+
+ webviewView.webview.html = this._getHtmlForWebview(webviewView.webview);
+
+ // Handle messages from the webview
+ webviewView.webview.onDidReceiveMessage(async (message) => {
+ switch (message.command) {
+ case 'sendMessage':
+ await this._handleUserMessage(message.text);
+ break;
+ case 'clearChat':
+ this._messages = [];
+ this._updateWebview();
+ break;
+ case 'insertCode':
+ this._insertCodeToEditor(message.code);
+ break;
+ }
+ });
+
+ // Update the webview with existing messages
+ this._updateWebview();
+ }
+
+ public addMessage(role: 'user' | 'assistant', content: string, code?: string) {
+ this._messages.push({
+ role,
+ content,
+ code,
+ timestamp: Date.now()
+ });
+
+ this._updateWebview();
+ }
+
+ private async _handleUserMessage(text: string) {
+ // Add user message to chat
+ this.addMessage('user', text);
+
+ try {
+ // Show loading indicator
+ this._view?.webview.postMessage({ command: 'showLoading', value: true });
+
+ // Get response from API
+ const response = await this._api.askQuestion(text);
+
+ // Add assistant message to chat
+ this.addMessage('assistant', response.text, response.code);
+
+ // Hide loading indicator
+ this._view?.webview.postMessage({ command: 'showLoading', value: false });
+ } catch (error) {
+ // Hide loading indicator
+ this._view?.webview.postMessage({ command: 'showLoading', value: false });
+
+ // Show error message
+ this.addMessage('assistant', `Error: ${error.message}`);
+ }
+ }
+
+ private _updateWebview() {
+ if (this._view) {
+ this._view.webview.postMessage({
+ command: 'updateMessages',
+ messages: this._messages
+ });
+ }
+ }
+
+ private _insertCodeToEditor(code: string) {
+ const editor = vscode.window.activeTextEditor;
+ if (editor) {
+ editor.edit(editBuilder => {
+ editBuilder.insert(editor.selection.active, code);
+ });
+ }
+ }
+
+ private _getHtmlForWebview(webview: vscode.Webview) {
+ // Create URIs for scripts and styles
+ const scriptUri = webview.asWebviewUri(
+ vscode.Uri.joinPath(this._extensionUri, 'media', 'main.js')
+ );
+ const styleUri = webview.asWebviewUri(
+ vscode.Uri.joinPath(this._extensionUri, 'media', 'main.css')
+ );
+
+ // Use a nonce to allow only specific scripts to be run
+ const nonce = this._getNonce();
+
+ return `
+
+
+
+
+
+
+ Codegen Chat
+
+
+
+
+
+ `;
+ }
+
+ private _getNonce() {
+ let text = '';
+ const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
+ for (let i = 0; i < 32; i++) {
+ text += possible.charAt(Math.floor(Math.random() * possible.length));
+ }
+ return text;
+ }
+}
diff --git a/codegen-vscode-extension/src/utils.ts b/codegen-vscode-extension/src/utils.ts
new file mode 100644
index 000000000..f802e69b0
--- /dev/null
+++ b/codegen-vscode-extension/src/utils.ts
@@ -0,0 +1,102 @@
+import * as vscode from 'vscode';
+
+/**
+ * Get the selected text from the editor
+ */
+export function getSelectedText(editor: vscode.TextEditor): string {
+ const selection = editor.selection;
+ if (selection.isEmpty) {
+ return '';
+ }
+ return editor.document.getText(selection);
+}
+
+/**
+ * Get the language of the document
+ */
+export function getDocumentLanguage(document: vscode.TextDocument): string {
+ return document.languageId;
+}
+
+/**
+ * Insert text at the current cursor position
+ */
+export function insertText(editor: vscode.TextEditor, text: string): void {
+ const selection = editor.selection;
+ editor.edit(editBuilder => {
+ editBuilder.insert(selection.active, text);
+ });
+}
+
+/**
+ * Get the current file path
+ */
+export function getCurrentFilePath(): string | undefined {
+ const editor = vscode.window.activeTextEditor;
+ if (!editor) {
+ return undefined;
+ }
+ return editor.document.uri.fsPath;
+}
+
+/**
+ * Get the current workspace folder
+ */
+export function getCurrentWorkspaceFolder(): vscode.WorkspaceFolder | undefined {
+ const editor = vscode.window.activeTextEditor;
+ if (!editor) {
+ return undefined;
+ }
+ return vscode.workspace.getWorkspaceFolder(editor.document.uri);
+}
+
+/**
+ * Get the current project name
+ */
+export function getCurrentProjectName(): string | undefined {
+ const workspaceFolder = getCurrentWorkspaceFolder();
+ if (!workspaceFolder) {
+ return undefined;
+ }
+ return workspaceFolder.name;
+}
+
+/**
+ * Get the current file name
+ */
+export function getCurrentFileName(): string | undefined {
+ const editor = vscode.window.activeTextEditor;
+ if (!editor) {
+ return undefined;
+ }
+ return editor.document.fileName.split(/[\\/]/).pop();
+}
+
+/**
+ * Get the current line of code
+ */
+export function getCurrentLine(editor: vscode.TextEditor): string {
+ const position = editor.selection.active;
+ const line = editor.document.lineAt(position.line);
+ return line.text;
+}
+
+/**
+ * Get the current function or class
+ * This is a simple implementation and might not work for all languages
+ */
+export function getCurrentFunction(editor: vscode.TextEditor): string | undefined {
+ const document = editor.document;
+ const position = editor.selection.active;
+
+ // Simple implementation - search backwards for function or class definition
+ for (let i = position.line; i >= 0; i--) {
+ const line = document.lineAt(i).text.trim();
+ if (line.startsWith('function ') || line.startsWith('class ') ||
+ line.startsWith('def ') || line.match(/^[a-zA-Z0-9_]+\s*\([^)]*\)\s*{/)) {
+ return line;
+ }
+ }
+
+ return undefined;
+}
diff --git a/codegen-vscode-extension/tsconfig.json b/codegen-vscode-extension/tsconfig.json
new file mode 100644
index 000000000..09724c930
--- /dev/null
+++ b/codegen-vscode-extension/tsconfig.json
@@ -0,0 +1,15 @@
+{
+ "compilerOptions": {
+ "module": "commonjs",
+ "target": "ES2020",
+ "outDir": "out",
+ "lib": ["ES2020", "DOM"],
+ "sourceMap": true,
+ "rootDir": "src",
+ "strict": true,
+ "esModuleInterop": true,
+ "skipLibCheck": true,
+ "forceConsistentCasingInFileNames": true
+ },
+ "exclude": ["node_modules", ".vscode-test"]
+}
diff --git a/codegen-vscode-extension/webpack.config.js b/codegen-vscode-extension/webpack.config.js
new file mode 100644
index 000000000..d2df6e2d3
--- /dev/null
+++ b/codegen-vscode-extension/webpack.config.js
@@ -0,0 +1,34 @@
+const path = require('path');
+
+const config = {
+ target: 'node',
+ entry: './src/extension.ts',
+ output: {
+ path: path.resolve(__dirname, 'dist'),
+ filename: 'extension.js',
+ libraryTarget: 'commonjs2',
+ devtoolModuleFilenameTemplate: '../[resource-path]'
+ },
+ devtool: 'source-map',
+ externals: {
+ vscode: 'commonjs vscode'
+ },
+ resolve: {
+ extensions: ['.ts', '.js']
+ },
+ module: {
+ rules: [
+ {
+ test: /\.ts$/,
+ exclude: /node_modules/,
+ use: [
+ {
+ loader: 'ts-loader'
+ }
+ ]
+ }
+ ]
+ }
+};
+
+module.exports = config;
From 5f8d8113cee27626d0912928aa25123f8a0e2d49 Mon Sep 17 00:00:00 2001
From: "codegen-sh[bot]" <131295404+codegen-sh[bot]@users.noreply.github.com>
Date: Fri, 25 Apr 2025 05:32:18 +0000
Subject: [PATCH 2/4] Automated pre-commit update
---
codegen-vscode-extension/README.md | 44 +-
codegen-vscode-extension/media/main.css | 283 ++++----
codegen-vscode-extension/media/main.js | 341 +++++-----
codegen-vscode-extension/package.json | 254 ++++----
.../src/api/codegenAPI.ts | 279 ++++----
codegen-vscode-extension/src/commands.ts | 607 ++++++++++--------
codegen-vscode-extension/src/extension.ts | 57 +-
.../src/providers/chatViewProvider.ts | 257 ++++----
codegen-vscode-extension/src/utils.ts | 106 +--
codegen-vscode-extension/tsconfig.json | 26 +-
codegen-vscode-extension/webpack.config.js | 58 +-
11 files changed, 1196 insertions(+), 1116 deletions(-)
diff --git a/codegen-vscode-extension/README.md b/codegen-vscode-extension/README.md
index 666ea4750..f213f58c4 100644
--- a/codegen-vscode-extension/README.md
+++ b/codegen-vscode-extension/README.md
@@ -18,60 +18,60 @@ A VSCode extension for Codegen - AI-powered code generation and assistance.
## Installation
1. Install the extension from the VSCode Marketplace
-2. Set your Codegen API key in the extension settings
-3. Start using Codegen in your development workflow!
+1. Set your Codegen API key in the extension settings
+1. Start using Codegen in your development workflow!
## Extension Settings
This extension contributes the following settings:
-* `codegen.apiKey`: Your Codegen API key
-* `codegen.endpoint`: The endpoint for the Codegen API (defaults to https://api.codegen.sh)
+- `codegen.apiKey`: Your Codegen API key
+- `codegen.endpoint`: The endpoint for the Codegen API (defaults to https://api.codegen.sh)
## Commands
The extension provides the following commands:
-* `codegen.askQuestion`: Ask Codegen a question
-* `codegen.generateCode`: Generate code with Codegen
-* `codegen.explainCode`: Explain selected code
-* `codegen.improveCode`: Improve selected code
-* `codegen.fixCode`: Fix selected code
+- `codegen.askQuestion`: Ask Codegen a question
+- `codegen.generateCode`: Generate code with Codegen
+- `codegen.explainCode`: Explain selected code
+- `codegen.improveCode`: Improve selected code
+- `codegen.fixCode`: Fix selected code
## Usage
### Ask a Question
1. Open the command palette (`Ctrl+Shift+P` or `Cmd+Shift+P` on macOS)
-2. Type "Ask Codegen a Question" and press Enter
-3. Enter your question and press Enter
-4. View the response in the Codegen Chat view
+1. Type "Ask Codegen a Question" and press Enter
+1. Enter your question and press Enter
+1. View the response in the Codegen Chat view
### Generate Code
1. Open the command palette
-2. Type "Generate Code with Codegen" and press Enter
-3. Describe the code you want to generate
-4. The generated code will be inserted at your cursor position
+1. Type "Generate Code with Codegen" and press Enter
+1. Describe the code you want to generate
+1. The generated code will be inserted at your cursor position
### Explain Code
1. Select the code you want to explain
-2. Right-click and select "Explain Selected Code" from the context menu
-3. View the explanation in the Codegen Chat view
+1. Right-click and select "Explain Selected Code" from the context menu
+1. View the explanation in the Codegen Chat view
### Improve Code
1. Select the code you want to improve
-2. Right-click and select "Improve Selected Code" from the context menu
-3. Review the suggested improvements and apply them if desired
+1. Right-click and select "Improve Selected Code" from the context menu
+1. Review the suggested improvements and apply them if desired
### Fix Code
1. Select the code you want to fix
-2. Right-click and select "Fix Selected Code" from the context menu
-3. Optionally provide the error message you're getting
-4. Review the suggested fixes and apply them if desired
+1. Right-click and select "Fix Selected Code" from the context menu
+1. Optionally provide the error message you're getting
+1. Review the suggested fixes and apply them if desired
## License
diff --git a/codegen-vscode-extension/media/main.css b/codegen-vscode-extension/media/main.css
index fcb28f268..010ce8d54 100644
--- a/codegen-vscode-extension/media/main.css
+++ b/codegen-vscode-extension/media/main.css
@@ -1,237 +1,244 @@
:root {
- --container-padding: 10px;
- --input-padding-vertical: 6px;
- --input-padding-horizontal: 8px;
- --input-margin-vertical: 4px;
- --input-margin-horizontal: 0;
+ --container-padding: 10px;
+ --input-padding-vertical: 6px;
+ --input-padding-horizontal: 8px;
+ --input-margin-vertical: 4px;
+ --input-margin-horizontal: 0;
}
body {
- padding: 0;
- margin: 0;
- color: var(--vscode-foreground);
- font-size: var(--vscode-font-size);
- font-weight: var(--vscode-font-weight);
- font-family: var(--vscode-font-family);
- background-color: var(--vscode-editor-background);
+ padding: 0;
+ margin: 0;
+ color: var(--vscode-foreground);
+ font-size: var(--vscode-font-size);
+ font-weight: var(--vscode-font-weight);
+ font-family: var(--vscode-font-family);
+ background-color: var(--vscode-editor-background);
}
#chat-container {
- display: flex;
- flex-direction: column;
- height: 100vh;
- padding: var(--container-padding);
- box-sizing: border-box;
+ display: flex;
+ flex-direction: column;
+ height: 100vh;
+ padding: var(--container-padding);
+ box-sizing: border-box;
}
#messages {
- flex: 1;
- overflow-y: auto;
- margin-bottom: 10px;
- padding-right: 8px;
+ flex: 1;
+ overflow-y: auto;
+ margin-bottom: 10px;
+ padding-right: 8px;
}
.message {
- margin-bottom: 10px;
- padding: 8px 12px;
- border-radius: 6px;
- max-width: 90%;
- word-wrap: break-word;
+ margin-bottom: 10px;
+ padding: 8px 12px;
+ border-radius: 6px;
+ max-width: 90%;
+ word-wrap: break-word;
}
.user-message {
- background-color: var(--vscode-button-background);
- color: var(--vscode-button-foreground);
- align-self: flex-end;
- margin-left: auto;
+ background-color: var(--vscode-button-background);
+ color: var(--vscode-button-foreground);
+ align-self: flex-end;
+ margin-left: auto;
}
.assistant-message {
- background-color: var(--vscode-editor-inactiveSelectionBackground);
- color: var(--vscode-editor-foreground);
- align-self: flex-start;
+ background-color: var(--vscode-editor-inactiveSelectionBackground);
+ color: var(--vscode-editor-foreground);
+ align-self: flex-start;
}
.message-content {
- margin-bottom: 5px;
+ margin-bottom: 5px;
}
.code-block {
- background-color: var(--vscode-editor-background);
- border: 1px solid var(--vscode-editor-lineHighlightBorder);
- border-radius: 3px;
- padding: 8px;
- margin-top: 5px;
- font-family: var(--vscode-editor-font-family);
- font-size: var(--vscode-editor-font-size);
- white-space: pre-wrap;
- overflow-x: auto;
+ background-color: var(--vscode-editor-background);
+ border: 1px solid var(--vscode-editor-lineHighlightBorder);
+ border-radius: 3px;
+ padding: 8px;
+ margin-top: 5px;
+ font-family: var(--vscode-editor-font-family);
+ font-size: var(--vscode-editor-font-size);
+ white-space: pre-wrap;
+ overflow-x: auto;
}
.code-actions {
- display: flex;
- justify-content: flex-end;
- margin-top: 5px;
+ display: flex;
+ justify-content: flex-end;
+ margin-top: 5px;
}
.code-action-button {
- background-color: var(--vscode-button-secondaryBackground);
- color: var(--vscode-button-secondaryForeground);
- border: none;
- padding: 4px 8px;
- border-radius: 2px;
- cursor: pointer;
- font-size: 12px;
- margin-left: 5px;
+ background-color: var(--vscode-button-secondaryBackground);
+ color: var(--vscode-button-secondaryForeground);
+ border: none;
+ padding: 4px 8px;
+ border-radius: 2px;
+ cursor: pointer;
+ font-size: 12px;
+ margin-left: 5px;
}
.code-action-button:hover {
- background-color: var(--vscode-button-secondaryHoverBackground);
+ background-color: var(--vscode-button-secondaryHoverBackground);
}
.timestamp {
- font-size: 10px;
- color: var(--vscode-descriptionForeground);
- text-align: right;
- margin-top: 2px;
+ font-size: 10px;
+ color: var(--vscode-descriptionForeground);
+ text-align: right;
+ margin-top: 2px;
}
#input-container {
- display: flex;
- padding: 8px 0;
+ display: flex;
+ padding: 8px 0;
}
#message-input {
- flex: 1;
- height: 60px;
- padding: var(--input-padding-vertical) var(--input-padding-horizontal);
- border: 1px solid var(--vscode-input-border);
- background-color: var(--vscode-input-background);
- color: var(--vscode-input-foreground);
- resize: none;
- font-family: var(--vscode-font-family);
- font-size: var(--vscode-font-size);
- border-radius: 2px;
+ flex: 1;
+ height: 60px;
+ padding: var(--input-padding-vertical) var(--input-padding-horizontal);
+ border: 1px solid var(--vscode-input-border);
+ background-color: var(--vscode-input-background);
+ color: var(--vscode-input-foreground);
+ resize: none;
+ font-family: var(--vscode-font-family);
+ font-size: var(--vscode-font-size);
+ border-radius: 2px;
}
#message-input:focus {
- outline: 1px solid var(--vscode-focusBorder);
+ outline: 1px solid var(--vscode-focusBorder);
}
#send-button {
- margin-left: 8px;
- padding: 0 14px;
- background-color: var(--vscode-button-background);
- color: var(--vscode-button-foreground);
- border: none;
- cursor: pointer;
- border-radius: 2px;
+ margin-left: 8px;
+ padding: 0 14px;
+ background-color: var(--vscode-button-background);
+ color: var(--vscode-button-foreground);
+ border: none;
+ cursor: pointer;
+ border-radius: 2px;
}
#send-button:hover {
- background-color: var(--vscode-button-hoverBackground);
+ background-color: var(--vscode-button-hoverBackground);
}
#loading {
- position: absolute;
- top: 0;
- left: 0;
- right: 0;
- bottom: 0;
- background-color: rgba(0, 0, 0, 0.3);
- display: flex;
- justify-content: center;
- align-items: center;
- z-index: 1000;
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ background-color: rgba(0, 0, 0, 0.3);
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ z-index: 1000;
}
.hidden {
- display: none !important;
+ display: none !important;
}
.spinner {
- width: 40px;
- height: 40px;
- border: 4px solid rgba(255, 255, 255, 0.3);
- border-radius: 50%;
- border-top-color: var(--vscode-button-background);
- animation: spin 1s ease-in-out infinite;
+ width: 40px;
+ height: 40px;
+ border: 4px solid rgba(255, 255, 255, 0.3);
+ border-radius: 50%;
+ border-top-color: var(--vscode-button-background);
+ animation: spin 1s ease-in-out infinite;
}
@keyframes spin {
- to {
- transform: rotate(360deg);
- }
+ to {
+ transform: rotate(360deg);
+ }
}
/* Markdown styling */
-.markdown h1, .markdown h2, .markdown h3, .markdown h4, .markdown h5, .markdown h6 {
- margin-top: 16px;
- margin-bottom: 8px;
- font-weight: 600;
+.markdown h1,
+.markdown h2,
+.markdown h3,
+.markdown h4,
+.markdown h5,
+.markdown h6 {
+ margin-top: 16px;
+ margin-bottom: 8px;
+ font-weight: 600;
}
.markdown p {
- margin-top: 0;
- margin-bottom: 8px;
+ margin-top: 0;
+ margin-bottom: 8px;
}
-.markdown ul, .markdown ol {
- padding-left: 20px;
- margin-top: 0;
- margin-bottom: 8px;
+.markdown ul,
+.markdown ol {
+ padding-left: 20px;
+ margin-top: 0;
+ margin-bottom: 8px;
}
.markdown code {
- font-family: var(--vscode-editor-font-family);
- background-color: var(--vscode-textCodeBlock-background);
- padding: 2px 4px;
- border-radius: 3px;
+ font-family: var(--vscode-editor-font-family);
+ background-color: var(--vscode-textCodeBlock-background);
+ padding: 2px 4px;
+ border-radius: 3px;
}
.markdown pre {
- background-color: var(--vscode-textCodeBlock-background);
- padding: 8px;
- border-radius: 3px;
- overflow-x: auto;
- margin-top: 8px;
- margin-bottom: 8px;
+ background-color: var(--vscode-textCodeBlock-background);
+ padding: 8px;
+ border-radius: 3px;
+ overflow-x: auto;
+ margin-top: 8px;
+ margin-bottom: 8px;
}
.markdown pre code {
- background-color: transparent;
- padding: 0;
+ background-color: transparent;
+ padding: 0;
}
.markdown a {
- color: var(--vscode-textLink-foreground);
- text-decoration: none;
+ color: var(--vscode-textLink-foreground);
+ text-decoration: none;
}
.markdown a:hover {
- text-decoration: underline;
+ text-decoration: underline;
}
.markdown blockquote {
- border-left: 3px solid var(--vscode-textBlockQuote-border);
- padding-left: 8px;
- margin-left: 0;
- margin-right: 0;
- color: var(--vscode-textBlockQuote-foreground);
+ border-left: 3px solid var(--vscode-textBlockQuote-border);
+ padding-left: 8px;
+ margin-left: 0;
+ margin-right: 0;
+ color: var(--vscode-textBlockQuote-foreground);
}
.markdown table {
- border-collapse: collapse;
- width: 100%;
- margin-bottom: 16px;
+ border-collapse: collapse;
+ width: 100%;
+ margin-bottom: 16px;
}
-.markdown th, .markdown td {
- border: 1px solid var(--vscode-editor-lineHighlightBorder);
- padding: 6px 13px;
+.markdown th,
+.markdown td {
+ border: 1px solid var(--vscode-editor-lineHighlightBorder);
+ padding: 6px 13px;
}
.markdown th {
- background-color: var(--vscode-editor-inactiveSelectionBackground);
- font-weight: 600;
+ background-color: var(--vscode-editor-inactiveSelectionBackground);
+ font-weight: 600;
}
diff --git a/codegen-vscode-extension/media/main.js b/codegen-vscode-extension/media/main.js
index 76183cebd..b0479a700 100644
--- a/codegen-vscode-extension/media/main.js
+++ b/codegen-vscode-extension/media/main.js
@@ -1,170 +1,173 @@
-(function() {
- // Get VS Code API
- const vscode = acquireVsCodeApi();
-
- // DOM elements
- const messagesContainer = document.getElementById('messages');
- const messageInput = document.getElementById('message-input');
- const sendButton = document.getElementById('send-button');
- const loadingElement = document.getElementById('loading');
-
- // Store messages
- let messages = [];
-
- // Initialize
- window.addEventListener('message', event => {
- const message = event.data;
-
- switch (message.command) {
- case 'updateMessages':
- messages = message.messages;
- renderMessages();
- break;
- case 'showLoading':
- toggleLoading(message.value);
- break;
- }
- });
-
- // Send message when button is clicked
- sendButton.addEventListener('click', () => {
- sendMessage();
- });
-
- // Send message when Enter is pressed (without Shift)
- messageInput.addEventListener('keydown', (e) => {
- if (e.key === 'Enter' && !e.shiftKey) {
- e.preventDefault();
- sendMessage();
- }
- });
-
- // Send message to extension
- function sendMessage() {
- const text = messageInput.value.trim();
- if (text) {
- vscode.postMessage({
- command: 'sendMessage',
- text: text
- });
- messageInput.value = '';
- }
- }
-
- // Render all messages
- function renderMessages() {
- messagesContainer.innerHTML = '';
-
- messages.forEach(message => {
- const messageElement = document.createElement('div');
- messageElement.className = `message ${message.role}-message`;
-
- // Message content
- const contentElement = document.createElement('div');
- contentElement.className = 'message-content markdown';
- contentElement.innerHTML = formatMarkdown(message.content);
- messageElement.appendChild(contentElement);
-
- // Code block (if any)
- if (message.code) {
- const codeElement = document.createElement('div');
- codeElement.className = 'code-block';
- codeElement.textContent = message.code;
- messageElement.appendChild(codeElement);
-
- // Code actions
- const actionsElement = document.createElement('div');
- actionsElement.className = 'code-actions';
-
- // Insert code button
- const insertButton = document.createElement('button');
- insertButton.className = 'code-action-button';
- insertButton.textContent = 'Insert Code';
- insertButton.addEventListener('click', () => {
- vscode.postMessage({
- command: 'insertCode',
- code: message.code
- });
- });
- actionsElement.appendChild(insertButton);
-
- // Copy code button
- const copyButton = document.createElement('button');
- copyButton.className = 'code-action-button';
- copyButton.textContent = 'Copy';
- copyButton.addEventListener('click', () => {
- navigator.clipboard.writeText(message.code);
- copyButton.textContent = 'Copied!';
- setTimeout(() => {
- copyButton.textContent = 'Copy';
- }, 2000);
- });
- actionsElement.appendChild(copyButton);
-
- messageElement.appendChild(actionsElement);
- }
-
- // Timestamp
- const timestampElement = document.createElement('div');
- timestampElement.className = 'timestamp';
- timestampElement.textContent = formatTimestamp(message.timestamp);
- messageElement.appendChild(timestampElement);
-
- messagesContainer.appendChild(messageElement);
- });
-
- // Scroll to bottom
- messagesContainer.scrollTop = messagesContainer.scrollHeight;
- }
-
- // Format timestamp
- function formatTimestamp(timestamp) {
- const date = new Date(timestamp);
- return date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
- }
-
- // Toggle loading indicator
- function toggleLoading(show) {
- if (show) {
- loadingElement.classList.remove('hidden');
- } else {
- loadingElement.classList.add('hidden');
- }
- }
-
- // Format markdown to HTML
- function formatMarkdown(text) {
- // This is a very simple markdown parser
- // In a real extension, you might want to use a library like marked.js
-
- // Code blocks
- text = text.replace(/```(\w*)\n([\s\S]*?)\n```/g, '$2
');
-
- // Inline code
- text = text.replace(/`([^`]+)`/g, '$1');
-
- // Headers
- text = text.replace(/^### (.*$)/gm, '$1
');
- text = text.replace(/^## (.*$)/gm, '$1
');
- text = text.replace(/^# (.*$)/gm, '$1
');
-
- // Bold
- text = text.replace(/\*\*(.*?)\*\*/g, '$1');
-
- // Italic
- text = text.replace(/\*(.*?)\*/g, '$1');
-
- // Lists
- text = text.replace(/^\s*\*\s(.*$)/gm, '$1');
- text = text.replace(/(.*<\/li>)/g, '');
-
- // Links
- text = text.replace(/\[(.*?)\]\((.*?)\)/g, '$1');
-
- // Paragraphs
- text = text.replace(/\n\n/g, '');
- text = '
' + text + '
';
-
- return text;
- }
+(() => {
+ // Get VS Code API
+ const vscode = acquireVsCodeApi();
+
+ // DOM elements
+ const messagesContainer = document.getElementById("messages");
+ const messageInput = document.getElementById("message-input");
+ const sendButton = document.getElementById("send-button");
+ const loadingElement = document.getElementById("loading");
+
+ // Store messages
+ let messages = [];
+
+ // Initialize
+ window.addEventListener("message", (event) => {
+ const message = event.data;
+
+ switch (message.command) {
+ case "updateMessages":
+ messages = message.messages;
+ renderMessages();
+ break;
+ case "showLoading":
+ toggleLoading(message.value);
+ break;
+ }
+ });
+
+ // Send message when button is clicked
+ sendButton.addEventListener("click", () => {
+ sendMessage();
+ });
+
+ // Send message when Enter is pressed (without Shift)
+ messageInput.addEventListener("keydown", (e) => {
+ if (e.key === "Enter" && !e.shiftKey) {
+ e.preventDefault();
+ sendMessage();
+ }
+ });
+
+ // Send message to extension
+ function sendMessage() {
+ const text = messageInput.value.trim();
+ if (text) {
+ vscode.postMessage({
+ command: "sendMessage",
+ text: text,
+ });
+ messageInput.value = "";
+ }
+ }
+
+ // Render all messages
+ function renderMessages() {
+ messagesContainer.innerHTML = "";
+
+ messages.forEach((message) => {
+ const messageElement = document.createElement("div");
+ messageElement.className = `message ${message.role}-message`;
+
+ // Message content
+ const contentElement = document.createElement("div");
+ contentElement.className = "message-content markdown";
+ contentElement.innerHTML = formatMarkdown(message.content);
+ messageElement.appendChild(contentElement);
+
+ // Code block (if any)
+ if (message.code) {
+ const codeElement = document.createElement("div");
+ codeElement.className = "code-block";
+ codeElement.textContent = message.code;
+ messageElement.appendChild(codeElement);
+
+ // Code actions
+ const actionsElement = document.createElement("div");
+ actionsElement.className = "code-actions";
+
+ // Insert code button
+ const insertButton = document.createElement("button");
+ insertButton.className = "code-action-button";
+ insertButton.textContent = "Insert Code";
+ insertButton.addEventListener("click", () => {
+ vscode.postMessage({
+ command: "insertCode",
+ code: message.code,
+ });
+ });
+ actionsElement.appendChild(insertButton);
+
+ // Copy code button
+ const copyButton = document.createElement("button");
+ copyButton.className = "code-action-button";
+ copyButton.textContent = "Copy";
+ copyButton.addEventListener("click", () => {
+ navigator.clipboard.writeText(message.code);
+ copyButton.textContent = "Copied!";
+ setTimeout(() => {
+ copyButton.textContent = "Copy";
+ }, 2000);
+ });
+ actionsElement.appendChild(copyButton);
+
+ messageElement.appendChild(actionsElement);
+ }
+
+ // Timestamp
+ const timestampElement = document.createElement("div");
+ timestampElement.className = "timestamp";
+ timestampElement.textContent = formatTimestamp(message.timestamp);
+ messageElement.appendChild(timestampElement);
+
+ messagesContainer.appendChild(messageElement);
+ });
+
+ // Scroll to bottom
+ messagesContainer.scrollTop = messagesContainer.scrollHeight;
+ }
+
+ // Format timestamp
+ function formatTimestamp(timestamp) {
+ const date = new Date(timestamp);
+ return date.toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" });
+ }
+
+ // Toggle loading indicator
+ function toggleLoading(show) {
+ if (show) {
+ loadingElement.classList.remove("hidden");
+ } else {
+ loadingElement.classList.add("hidden");
+ }
+ }
+
+ // Format markdown to HTML
+ function formatMarkdown(text) {
+ // This is a very simple markdown parser
+ // In a real extension, you might want to use a library like marked.js
+
+ // Code blocks
+ text = text.replace(
+ /```(\w*)\n([\s\S]*?)\n```/g,
+ "$2
",
+ );
+
+ // Inline code
+ text = text.replace(/`([^`]+)`/g, "$1");
+
+ // Headers
+ text = text.replace(/^### (.*$)/gm, "$1
");
+ text = text.replace(/^## (.*$)/gm, "$1
");
+ text = text.replace(/^# (.*$)/gm, "$1
");
+
+ // Bold
+ text = text.replace(/\*\*(.*?)\*\*/g, "$1");
+
+ // Italic
+ text = text.replace(/\*(.*?)\*/g, "$1");
+
+ // Lists
+ text = text.replace(/^\s*\*\s(.*$)/gm, "$1");
+ text = text.replace(/(.*<\/li>)/g, "");
+
+ // Links
+ text = text.replace(/\[(.*?)\]\((.*?)\)/g, '$1');
+
+ // Paragraphs
+ text = text.replace(/\n\n/g, "");
+ text = "
" + text + "
";
+
+ return text;
+ }
})();
diff --git a/codegen-vscode-extension/package.json b/codegen-vscode-extension/package.json
index f57e7e552..18475fd69 100644
--- a/codegen-vscode-extension/package.json
+++ b/codegen-vscode-extension/package.json
@@ -1,132 +1,126 @@
{
- "name": "codegen-vscode-extension",
- "displayName": "Codegen",
- "description": "VSCode extension for Codegen - AI-powered code generation and assistance",
- "version": "0.1.0",
- "engines": {
- "vscode": "^1.78.0"
- },
- "categories": [
- "Programming Languages",
- "Machine Learning",
- "Other"
- ],
- "activationEvents": [
- "onStartupFinished"
- ],
- "main": "./dist/extension.js",
- "contributes": {
- "commands": [
- {
- "command": "codegen.askQuestion",
- "title": "Ask Codegen a Question",
- "category": "Codegen"
- },
- {
- "command": "codegen.generateCode",
- "title": "Generate Code with Codegen",
- "category": "Codegen"
- },
- {
- "command": "codegen.explainCode",
- "title": "Explain Selected Code",
- "category": "Codegen"
- },
- {
- "command": "codegen.improveCode",
- "title": "Improve Selected Code",
- "category": "Codegen"
- },
- {
- "command": "codegen.fixCode",
- "title": "Fix Selected Code",
- "category": "Codegen"
- }
- ],
- "viewsContainers": {
- "activitybar": [
- {
- "id": "codegen-sidebar",
- "title": "Codegen",
- "icon": "media/codegen-icon.svg"
- }
- ]
- },
- "views": {
- "codegen-sidebar": [
- {
- "type": "webview",
- "id": "codegen.chatView",
- "name": "Codegen Chat"
- }
- ]
- },
- "configuration": {
- "title": "Codegen",
- "properties": {
- "codegen.apiKey": {
- "type": "string",
- "default": "",
- "description": "API key for Codegen services"
- },
- "codegen.endpoint": {
- "type": "string",
- "default": "https://api.codegen.sh",
- "description": "Endpoint for Codegen API"
- }
- }
- },
- "menus": {
- "editor/context": [
- {
- "command": "codegen.explainCode",
- "when": "editorHasSelection",
- "group": "codegen"
- },
- {
- "command": "codegen.improveCode",
- "when": "editorHasSelection",
- "group": "codegen"
- },
- {
- "command": "codegen.fixCode",
- "when": "editorHasSelection",
- "group": "codegen"
- },
- {
- "command": "codegen.generateCode",
- "group": "codegen"
- }
- ]
- }
- },
- "scripts": {
- "vscode:prepublish": "npm run package",
- "compile": "webpack",
- "watch": "webpack --watch",
- "package": "webpack --mode production --devtool source-map --config ./webpack.config.js",
- "compile-tests": "tsc -p . --outDir out",
- "watch-tests": "tsc -p . -w --outDir out",
- "lint": "eslint src --ext ts",
- "test": "node ./out/test/runTest.js"
- },
- "devDependencies": {
- "@types/glob": "^8.1.0",
- "@types/mocha": "^10.0.1",
- "@types/node": "16.x",
- "@types/vscode": "^1.78.0",
- "@typescript-eslint/eslint-plugin": "^5.59.1",
- "@typescript-eslint/parser": "^5.59.1",
- "@vscode/test-electron": "^2.3.0",
- "eslint": "^8.39.0",
- "glob": "^8.1.0",
- "mocha": "^10.2.0",
- "ts-loader": "^9.4.2",
- "typescript": "^5.0.4",
- "webpack": "^5.81.0",
- "webpack-cli": "^5.0.2"
- },
- "dependencies": {
- "axios": "^1.4.0"
- }
+ "name": "codegen-vscode-extension",
+ "displayName": "Codegen",
+ "description": "VSCode extension for Codegen - AI-powered code generation and assistance",
+ "version": "0.1.0",
+ "engines": {
+ "vscode": "^1.78.0"
+ },
+ "categories": ["Programming Languages", "Machine Learning", "Other"],
+ "activationEvents": ["onStartupFinished"],
+ "main": "./dist/extension.js",
+ "contributes": {
+ "commands": [
+ {
+ "command": "codegen.askQuestion",
+ "title": "Ask Codegen a Question",
+ "category": "Codegen"
+ },
+ {
+ "command": "codegen.generateCode",
+ "title": "Generate Code with Codegen",
+ "category": "Codegen"
+ },
+ {
+ "command": "codegen.explainCode",
+ "title": "Explain Selected Code",
+ "category": "Codegen"
+ },
+ {
+ "command": "codegen.improveCode",
+ "title": "Improve Selected Code",
+ "category": "Codegen"
+ },
+ {
+ "command": "codegen.fixCode",
+ "title": "Fix Selected Code",
+ "category": "Codegen"
+ }
+ ],
+ "viewsContainers": {
+ "activitybar": [
+ {
+ "id": "codegen-sidebar",
+ "title": "Codegen",
+ "icon": "media/codegen-icon.svg"
+ }
+ ]
+ },
+ "views": {
+ "codegen-sidebar": [
+ {
+ "type": "webview",
+ "id": "codegen.chatView",
+ "name": "Codegen Chat"
+ }
+ ]
+ },
+ "configuration": {
+ "title": "Codegen",
+ "properties": {
+ "codegen.apiKey": {
+ "type": "string",
+ "default": "",
+ "description": "API key for Codegen services"
+ },
+ "codegen.endpoint": {
+ "type": "string",
+ "default": "https://api.codegen.sh",
+ "description": "Endpoint for Codegen API"
+ }
+ }
+ },
+ "menus": {
+ "editor/context": [
+ {
+ "command": "codegen.explainCode",
+ "when": "editorHasSelection",
+ "group": "codegen"
+ },
+ {
+ "command": "codegen.improveCode",
+ "when": "editorHasSelection",
+ "group": "codegen"
+ },
+ {
+ "command": "codegen.fixCode",
+ "when": "editorHasSelection",
+ "group": "codegen"
+ },
+ {
+ "command": "codegen.generateCode",
+ "group": "codegen"
+ }
+ ]
+ }
+ },
+ "scripts": {
+ "vscode:prepublish": "npm run package",
+ "compile": "webpack",
+ "watch": "webpack --watch",
+ "package": "webpack --mode production --devtool source-map --config ./webpack.config.js",
+ "compile-tests": "tsc -p . --outDir out",
+ "watch-tests": "tsc -p . -w --outDir out",
+ "lint": "eslint src --ext ts",
+ "test": "node ./out/test/runTest.js"
+ },
+ "devDependencies": {
+ "@types/glob": "^8.1.0",
+ "@types/mocha": "^10.0.1",
+ "@types/node": "16.x",
+ "@types/vscode": "^1.78.0",
+ "@typescript-eslint/eslint-plugin": "^5.59.1",
+ "@typescript-eslint/parser": "^5.59.1",
+ "@vscode/test-electron": "^2.3.0",
+ "eslint": "^8.39.0",
+ "glob": "^8.1.0",
+ "mocha": "^10.2.0",
+ "ts-loader": "^9.4.2",
+ "typescript": "^5.0.4",
+ "webpack": "^5.81.0",
+ "webpack-cli": "^5.0.2"
+ },
+ "dependencies": {
+ "axios": "^1.4.0"
+ }
}
diff --git a/codegen-vscode-extension/src/api/codegenAPI.ts b/codegen-vscode-extension/src/api/codegenAPI.ts
index 9a98c6185..f201c20e0 100644
--- a/codegen-vscode-extension/src/api/codegenAPI.ts
+++ b/codegen-vscode-extension/src/api/codegenAPI.ts
@@ -1,136 +1,155 @@
-import axios, { AxiosInstance } from 'axios';
-import * as vscode from 'vscode';
+import axios, { type AxiosInstance } from "axios";
+import * as vscode from "vscode";
export interface CodegenResponse {
- text: string;
- code?: string;
- language?: string;
+ text: string;
+ code?: string;
+ language?: string;
}
export class CodegenAPI {
- private client: AxiosInstance;
- private apiKey: string = '';
- private endpoint: string = '';
-
- constructor() {
- this.loadConfiguration();
-
- this.client = axios.create({
- baseURL: this.endpoint,
- headers: {
- 'Content-Type': 'application/json',
- 'Authorization': `Bearer ${this.apiKey}`
- }
- });
-
- // Listen for configuration changes
- vscode.workspace.onDidChangeConfiguration(e => {
- if (e.affectsConfiguration('codegen.apiKey') || e.affectsConfiguration('codegen.endpoint')) {
- this.loadConfiguration();
- this.updateClient();
- }
- });
- }
-
- private loadConfiguration() {
- const config = vscode.workspace.getConfiguration('codegen');
- this.apiKey = config.get('apiKey') || '';
- this.endpoint = config.get('endpoint') || 'https://api.codegen.sh';
- }
-
- private updateClient() {
- this.client = axios.create({
- baseURL: this.endpoint,
- headers: {
- 'Content-Type': 'application/json',
- 'Authorization': `Bearer ${this.apiKey}`
- }
- });
- }
-
- public async validateApiKey(): Promise {
- if (!this.apiKey) {
- return false;
- }
-
- try {
- // Make a simple request to validate the API key
- await this.client.get('/api/validate');
- return true;
- } catch (error) {
- console.error('API key validation failed:', error);
- return false;
- }
- }
-
- public async askQuestion(question: string, context?: string): Promise {
- try {
- const response = await this.client.post('/api/ask', {
- question,
- context
- });
-
- return response.data;
- } catch (error) {
- console.error('Error asking question:', error);
- throw new Error('Failed to get response from Codegen API');
- }
- }
-
- public async generateCode(prompt: string, language?: string): Promise {
- try {
- const response = await this.client.post('/api/generate', {
- prompt,
- language
- });
-
- return response.data;
- } catch (error) {
- console.error('Error generating code:', error);
- throw new Error('Failed to generate code from Codegen API');
- }
- }
-
- public async explainCode(code: string, language?: string): Promise {
- try {
- const response = await this.client.post('/api/explain', {
- code,
- language
- });
-
- return response.data;
- } catch (error) {
- console.error('Error explaining code:', error);
- throw new Error('Failed to explain code from Codegen API');
- }
- }
-
- public async improveCode(code: string, language?: string): Promise {
- try {
- const response = await this.client.post('/api/improve', {
- code,
- language
- });
-
- return response.data;
- } catch (error) {
- console.error('Error improving code:', error);
- throw new Error('Failed to improve code from Codegen API');
- }
- }
-
- public async fixCode(code: string, error?: string, language?: string): Promise {
- try {
- const response = await this.client.post('/api/fix', {
- code,
- error,
- language
- });
-
- return response.data;
- } catch (error) {
- console.error('Error fixing code:', error);
- throw new Error('Failed to fix code from Codegen API');
- }
- }
+ private client: AxiosInstance;
+ private apiKey = "";
+ private endpoint = "";
+
+ constructor() {
+ this.loadConfiguration();
+
+ this.client = axios.create({
+ baseURL: this.endpoint,
+ headers: {
+ "Content-Type": "application/json",
+ Authorization: `Bearer ${this.apiKey}`,
+ },
+ });
+
+ // Listen for configuration changes
+ vscode.workspace.onDidChangeConfiguration((e) => {
+ if (
+ e.affectsConfiguration("codegen.apiKey") ||
+ e.affectsConfiguration("codegen.endpoint")
+ ) {
+ this.loadConfiguration();
+ this.updateClient();
+ }
+ });
+ }
+
+ private loadConfiguration() {
+ const config = vscode.workspace.getConfiguration("codegen");
+ this.apiKey = config.get("apiKey") || "";
+ this.endpoint = config.get("endpoint") || "https://api.codegen.sh";
+ }
+
+ private updateClient() {
+ this.client = axios.create({
+ baseURL: this.endpoint,
+ headers: {
+ "Content-Type": "application/json",
+ Authorization: `Bearer ${this.apiKey}`,
+ },
+ });
+ }
+
+ public async validateApiKey(): Promise {
+ if (!this.apiKey) {
+ return false;
+ }
+
+ try {
+ // Make a simple request to validate the API key
+ await this.client.get("/api/validate");
+ return true;
+ } catch (error) {
+ console.error("API key validation failed:", error);
+ return false;
+ }
+ }
+
+ public async askQuestion(
+ question: string,
+ context?: string,
+ ): Promise {
+ try {
+ const response = await this.client.post("/api/ask", {
+ question,
+ context,
+ });
+
+ return response.data;
+ } catch (error) {
+ console.error("Error asking question:", error);
+ throw new Error("Failed to get response from Codegen API");
+ }
+ }
+
+ public async generateCode(
+ prompt: string,
+ language?: string,
+ ): Promise {
+ try {
+ const response = await this.client.post("/api/generate", {
+ prompt,
+ language,
+ });
+
+ return response.data;
+ } catch (error) {
+ console.error("Error generating code:", error);
+ throw new Error("Failed to generate code from Codegen API");
+ }
+ }
+
+ public async explainCode(
+ code: string,
+ language?: string,
+ ): Promise {
+ try {
+ const response = await this.client.post("/api/explain", {
+ code,
+ language,
+ });
+
+ return response.data;
+ } catch (error) {
+ console.error("Error explaining code:", error);
+ throw new Error("Failed to explain code from Codegen API");
+ }
+ }
+
+ public async improveCode(
+ code: string,
+ language?: string,
+ ): Promise {
+ try {
+ const response = await this.client.post("/api/improve", {
+ code,
+ language,
+ });
+
+ return response.data;
+ } catch (error) {
+ console.error("Error improving code:", error);
+ throw new Error("Failed to improve code from Codegen API");
+ }
+ }
+
+ public async fixCode(
+ code: string,
+ error?: string,
+ language?: string,
+ ): Promise {
+ try {
+ const response = await this.client.post("/api/fix", {
+ code,
+ error,
+ language,
+ });
+
+ return response.data;
+ } catch (error) {
+ console.error("Error fixing code:", error);
+ throw new Error("Failed to fix code from Codegen API");
+ }
+ }
}
diff --git a/codegen-vscode-extension/src/commands.ts b/codegen-vscode-extension/src/commands.ts
index 7a7c6682a..e605d4e0e 100644
--- a/codegen-vscode-extension/src/commands.ts
+++ b/codegen-vscode-extension/src/commands.ts
@@ -1,287 +1,328 @@
-import * as vscode from 'vscode';
-import { CodegenAPI } from './api/codegenAPI';
-import { ChatViewProvider } from './providers/chatViewProvider';
-import { getSelectedText, getDocumentLanguage, insertText } from './utils';
+import * as vscode from "vscode";
+import type { CodegenAPI } from "./api/codegenAPI";
+import type { ChatViewProvider } from "./providers/chatViewProvider";
+import { getDocumentLanguage, getSelectedText, insertText } from "./utils";
export function registerCommands(
- context: vscode.ExtensionContext,
- api: CodegenAPI,
- chatViewProvider: ChatViewProvider
+ context: vscode.ExtensionContext,
+ api: CodegenAPI,
+ chatViewProvider: ChatViewProvider,
) {
- // Ask a question
- context.subscriptions.push(
- vscode.commands.registerCommand('codegen.askQuestion', async () => {
- const question = await vscode.window.showInputBox({
- prompt: 'What would you like to ask Codegen?',
- placeHolder: 'Ask a programming question...'
- });
-
- if (!question) {
- return;
- }
-
- try {
- vscode.window.withProgress({
- location: vscode.ProgressLocation.Notification,
- title: 'Asking Codegen...',
- cancellable: false
- }, async (progress) => {
- progress.report({ increment: 0 });
-
- const response = await api.askQuestion(question);
-
- progress.report({ increment: 100 });
-
- // Send to chat view
- chatViewProvider.addMessage('user', question);
- chatViewProvider.addMessage('assistant', response.text);
-
- // Show the chat view
- vscode.commands.executeCommand('codegen.chatView.focus');
-
- return response;
- });
- } catch (error) {
- vscode.window.showErrorMessage(`Error: ${error.message}`);
- }
- })
- );
-
- // Generate code
- context.subscriptions.push(
- vscode.commands.registerCommand('codegen.generateCode', async () => {
- const prompt = await vscode.window.showInputBox({
- prompt: 'Describe the code you want to generate',
- placeHolder: 'Generate a function that...'
- });
-
- if (!prompt) {
- return;
- }
-
- const editor = vscode.window.activeTextEditor;
- const language = editor ? getDocumentLanguage(editor.document) : undefined;
-
- try {
- vscode.window.withProgress({
- location: vscode.ProgressLocation.Notification,
- title: 'Generating code...',
- cancellable: false
- }, async (progress) => {
- progress.report({ increment: 0 });
-
- const response = await api.generateCode(prompt, language);
-
- progress.report({ increment: 100 });
-
- if (editor && response.code) {
- // Insert the generated code at the cursor position
- insertText(editor, response.code);
- }
-
- // Send to chat view
- chatViewProvider.addMessage('user', `Generate code: ${prompt}`);
- chatViewProvider.addMessage('assistant', response.text, response.code);
-
- return response;
- });
- } catch (error) {
- vscode.window.showErrorMessage(`Error: ${error.message}`);
- }
- })
- );
-
- // Explain code
- context.subscriptions.push(
- vscode.commands.registerCommand('codegen.explainCode', async () => {
- const editor = vscode.window.activeTextEditor;
- if (!editor) {
- vscode.window.showErrorMessage('No active editor');
- return;
- }
-
- const selectedText = getSelectedText(editor);
- if (!selectedText) {
- vscode.window.showErrorMessage('No code selected');
- return;
- }
-
- const language = getDocumentLanguage(editor.document);
-
- try {
- vscode.window.withProgress({
- location: vscode.ProgressLocation.Notification,
- title: 'Explaining code...',
- cancellable: false
- }, async (progress) => {
- progress.report({ increment: 0 });
-
- const response = await api.explainCode(selectedText, language);
-
- progress.report({ increment: 100 });
-
- // Send to chat view
- chatViewProvider.addMessage('user', `Explain this code:\n\`\`\`${language}\n${selectedText}\n\`\`\``);
- chatViewProvider.addMessage('assistant', response.text);
-
- // Show the chat view
- vscode.commands.executeCommand('codegen.chatView.focus');
-
- return response;
- });
- } catch (error) {
- vscode.window.showErrorMessage(`Error: ${error.message}`);
- }
- })
- );
-
- // Improve code
- context.subscriptions.push(
- vscode.commands.registerCommand('codegen.improveCode', async () => {
- const editor = vscode.window.activeTextEditor;
- if (!editor) {
- vscode.window.showErrorMessage('No active editor');
- return;
- }
-
- const selectedText = getSelectedText(editor);
- if (!selectedText) {
- vscode.window.showErrorMessage('No code selected');
- return;
- }
-
- const language = getDocumentLanguage(editor.document);
-
- try {
- vscode.window.withProgress({
- location: vscode.ProgressLocation.Notification,
- title: 'Improving code...',
- cancellable: false
- }, async (progress) => {
- progress.report({ increment: 0 });
-
- const response = await api.improveCode(selectedText, language);
-
- progress.report({ increment: 100 });
-
- if (response.code) {
- // Show diff and ask if user wants to apply changes
- const document = editor.document;
- const selection = editor.selection;
-
- const diffEditor = await vscode.diff.createTextDocumentAndEditorEdit(
- document,
- selection,
- response.code
- );
-
- // Add buttons to apply or discard changes
- const applyChanges = 'Apply Changes';
- const discardChanges = 'Discard';
-
- const choice = await vscode.window.showInformationMessage(
- 'Review the suggested improvements',
- applyChanges,
- discardChanges
- );
-
- if (choice === applyChanges) {
- // Replace the selected text with the improved code
- editor.edit(editBuilder => {
- editBuilder.replace(selection, response.code || '');
- });
- }
- }
-
- // Send to chat view
- chatViewProvider.addMessage('user', `Improve this code:\n\`\`\`${language}\n${selectedText}\n\`\`\``);
- chatViewProvider.addMessage('assistant', response.text, response.code);
-
- return response;
- });
- } catch (error) {
- vscode.window.showErrorMessage(`Error: ${error.message}`);
- }
- })
- );
-
- // Fix code
- context.subscriptions.push(
- vscode.commands.registerCommand('codegen.fixCode', async () => {
- const editor = vscode.window.activeTextEditor;
- if (!editor) {
- vscode.window.showErrorMessage('No active editor');
- return;
- }
-
- const selectedText = getSelectedText(editor);
- if (!selectedText) {
- vscode.window.showErrorMessage('No code selected');
- return;
- }
-
- const language = getDocumentLanguage(editor.document);
-
- // Ask for error message
- const errorMessage = await vscode.window.showInputBox({
- prompt: 'What error are you getting? (optional)',
- placeHolder: 'Error message or description of the issue'
- });
-
- try {
- vscode.window.withProgress({
- location: vscode.ProgressLocation.Notification,
- title: 'Fixing code...',
- cancellable: false
- }, async (progress) => {
- progress.report({ increment: 0 });
-
- const response = await api.fixCode(selectedText, errorMessage, language);
-
- progress.report({ increment: 100 });
-
- if (response.code) {
- // Show diff and ask if user wants to apply changes
- const document = editor.document;
- const selection = editor.selection;
-
- const diffEditor = await vscode.diff.createTextDocumentAndEditorEdit(
- document,
- selection,
- response.code
- );
-
- // Add buttons to apply or discard changes
- const applyChanges = 'Apply Changes';
- const discardChanges = 'Discard';
-
- const choice = await vscode.window.showInformationMessage(
- 'Review the suggested fixes',
- applyChanges,
- discardChanges
- );
-
- if (choice === applyChanges) {
- // Replace the selected text with the fixed code
- editor.edit(editBuilder => {
- editBuilder.replace(selection, response.code || '');
- });
- }
- }
-
- // Send to chat view
- const userMessage = errorMessage
- ? `Fix this code (error: ${errorMessage}):\n\`\`\`${language}\n${selectedText}\n\`\`\``
- : `Fix this code:\n\`\`\`${language}\n${selectedText}\n\`\`\``;
-
- chatViewProvider.addMessage('user', userMessage);
- chatViewProvider.addMessage('assistant', response.text, response.code);
-
- return response;
- });
- } catch (error) {
- vscode.window.showErrorMessage(`Error: ${error.message}`);
- }
- })
- );
+ // Ask a question
+ context.subscriptions.push(
+ vscode.commands.registerCommand("codegen.askQuestion", async () => {
+ const question = await vscode.window.showInputBox({
+ prompt: "What would you like to ask Codegen?",
+ placeHolder: "Ask a programming question...",
+ });
+
+ if (!question) {
+ return;
+ }
+
+ try {
+ vscode.window.withProgress(
+ {
+ location: vscode.ProgressLocation.Notification,
+ title: "Asking Codegen...",
+ cancellable: false,
+ },
+ async (progress) => {
+ progress.report({ increment: 0 });
+
+ const response = await api.askQuestion(question);
+
+ progress.report({ increment: 100 });
+
+ // Send to chat view
+ chatViewProvider.addMessage("user", question);
+ chatViewProvider.addMessage("assistant", response.text);
+
+ // Show the chat view
+ vscode.commands.executeCommand("codegen.chatView.focus");
+
+ return response;
+ },
+ );
+ } catch (error) {
+ vscode.window.showErrorMessage(`Error: ${error.message}`);
+ }
+ }),
+ );
+
+ // Generate code
+ context.subscriptions.push(
+ vscode.commands.registerCommand("codegen.generateCode", async () => {
+ const prompt = await vscode.window.showInputBox({
+ prompt: "Describe the code you want to generate",
+ placeHolder: "Generate a function that...",
+ });
+
+ if (!prompt) {
+ return;
+ }
+
+ const editor = vscode.window.activeTextEditor;
+ const language = editor
+ ? getDocumentLanguage(editor.document)
+ : undefined;
+
+ try {
+ vscode.window.withProgress(
+ {
+ location: vscode.ProgressLocation.Notification,
+ title: "Generating code...",
+ cancellable: false,
+ },
+ async (progress) => {
+ progress.report({ increment: 0 });
+
+ const response = await api.generateCode(prompt, language);
+
+ progress.report({ increment: 100 });
+
+ if (editor && response.code) {
+ // Insert the generated code at the cursor position
+ insertText(editor, response.code);
+ }
+
+ // Send to chat view
+ chatViewProvider.addMessage("user", `Generate code: ${prompt}`);
+ chatViewProvider.addMessage(
+ "assistant",
+ response.text,
+ response.code,
+ );
+
+ return response;
+ },
+ );
+ } catch (error) {
+ vscode.window.showErrorMessage(`Error: ${error.message}`);
+ }
+ }),
+ );
+
+ // Explain code
+ context.subscriptions.push(
+ vscode.commands.registerCommand("codegen.explainCode", async () => {
+ const editor = vscode.window.activeTextEditor;
+ if (!editor) {
+ vscode.window.showErrorMessage("No active editor");
+ return;
+ }
+
+ const selectedText = getSelectedText(editor);
+ if (!selectedText) {
+ vscode.window.showErrorMessage("No code selected");
+ return;
+ }
+
+ const language = getDocumentLanguage(editor.document);
+
+ try {
+ vscode.window.withProgress(
+ {
+ location: vscode.ProgressLocation.Notification,
+ title: "Explaining code...",
+ cancellable: false,
+ },
+ async (progress) => {
+ progress.report({ increment: 0 });
+
+ const response = await api.explainCode(selectedText, language);
+
+ progress.report({ increment: 100 });
+
+ // Send to chat view
+ chatViewProvider.addMessage(
+ "user",
+ `Explain this code:\n\`\`\`${language}\n${selectedText}\n\`\`\``,
+ );
+ chatViewProvider.addMessage("assistant", response.text);
+
+ // Show the chat view
+ vscode.commands.executeCommand("codegen.chatView.focus");
+
+ return response;
+ },
+ );
+ } catch (error) {
+ vscode.window.showErrorMessage(`Error: ${error.message}`);
+ }
+ }),
+ );
+
+ // Improve code
+ context.subscriptions.push(
+ vscode.commands.registerCommand("codegen.improveCode", async () => {
+ const editor = vscode.window.activeTextEditor;
+ if (!editor) {
+ vscode.window.showErrorMessage("No active editor");
+ return;
+ }
+
+ const selectedText = getSelectedText(editor);
+ if (!selectedText) {
+ vscode.window.showErrorMessage("No code selected");
+ return;
+ }
+
+ const language = getDocumentLanguage(editor.document);
+
+ try {
+ vscode.window.withProgress(
+ {
+ location: vscode.ProgressLocation.Notification,
+ title: "Improving code...",
+ cancellable: false,
+ },
+ async (progress) => {
+ progress.report({ increment: 0 });
+
+ const response = await api.improveCode(selectedText, language);
+
+ progress.report({ increment: 100 });
+
+ if (response.code) {
+ // Show diff and ask if user wants to apply changes
+ const document = editor.document;
+ const selection = editor.selection;
+
+ const diffEditor =
+ await vscode.diff.createTextDocumentAndEditorEdit(
+ document,
+ selection,
+ response.code,
+ );
+
+ // Add buttons to apply or discard changes
+ const applyChanges = "Apply Changes";
+ const discardChanges = "Discard";
+
+ const choice = await vscode.window.showInformationMessage(
+ "Review the suggested improvements",
+ applyChanges,
+ discardChanges,
+ );
+
+ if (choice === applyChanges) {
+ // Replace the selected text with the improved code
+ editor.edit((editBuilder) => {
+ editBuilder.replace(selection, response.code || "");
+ });
+ }
+ }
+
+ // Send to chat view
+ chatViewProvider.addMessage(
+ "user",
+ `Improve this code:\n\`\`\`${language}\n${selectedText}\n\`\`\``,
+ );
+ chatViewProvider.addMessage(
+ "assistant",
+ response.text,
+ response.code,
+ );
+
+ return response;
+ },
+ );
+ } catch (error) {
+ vscode.window.showErrorMessage(`Error: ${error.message}`);
+ }
+ }),
+ );
+
+ // Fix code
+ context.subscriptions.push(
+ vscode.commands.registerCommand("codegen.fixCode", async () => {
+ const editor = vscode.window.activeTextEditor;
+ if (!editor) {
+ vscode.window.showErrorMessage("No active editor");
+ return;
+ }
+
+ const selectedText = getSelectedText(editor);
+ if (!selectedText) {
+ vscode.window.showErrorMessage("No code selected");
+ return;
+ }
+
+ const language = getDocumentLanguage(editor.document);
+
+ // Ask for error message
+ const errorMessage = await vscode.window.showInputBox({
+ prompt: "What error are you getting? (optional)",
+ placeHolder: "Error message or description of the issue",
+ });
+
+ try {
+ vscode.window.withProgress(
+ {
+ location: vscode.ProgressLocation.Notification,
+ title: "Fixing code...",
+ cancellable: false,
+ },
+ async (progress) => {
+ progress.report({ increment: 0 });
+
+ const response = await api.fixCode(
+ selectedText,
+ errorMessage,
+ language,
+ );
+
+ progress.report({ increment: 100 });
+
+ if (response.code) {
+ // Show diff and ask if user wants to apply changes
+ const document = editor.document;
+ const selection = editor.selection;
+
+ const diffEditor =
+ await vscode.diff.createTextDocumentAndEditorEdit(
+ document,
+ selection,
+ response.code,
+ );
+
+ // Add buttons to apply or discard changes
+ const applyChanges = "Apply Changes";
+ const discardChanges = "Discard";
+
+ const choice = await vscode.window.showInformationMessage(
+ "Review the suggested fixes",
+ applyChanges,
+ discardChanges,
+ );
+
+ if (choice === applyChanges) {
+ // Replace the selected text with the fixed code
+ editor.edit((editBuilder) => {
+ editBuilder.replace(selection, response.code || "");
+ });
+ }
+ }
+
+ // Send to chat view
+ const userMessage = errorMessage
+ ? `Fix this code (error: ${errorMessage}):\n\`\`\`${language}\n${selectedText}\n\`\`\``
+ : `Fix this code:\n\`\`\`${language}\n${selectedText}\n\`\`\``;
+
+ chatViewProvider.addMessage("user", userMessage);
+ chatViewProvider.addMessage(
+ "assistant",
+ response.text,
+ response.code,
+ );
+
+ return response;
+ },
+ );
+ } catch (error) {
+ vscode.window.showErrorMessage(`Error: ${error.message}`);
+ }
+ }),
+ );
}
diff --git a/codegen-vscode-extension/src/extension.ts b/codegen-vscode-extension/src/extension.ts
index 101ad8344..fa01b5d29 100644
--- a/codegen-vscode-extension/src/extension.ts
+++ b/codegen-vscode-extension/src/extension.ts
@@ -1,36 +1,39 @@
-import * as vscode from 'vscode';
-import { ChatViewProvider } from './providers/chatViewProvider';
-import { CodegenAPI } from './api/codegenAPI';
-import { registerCommands } from './commands';
+import * as vscode from "vscode";
+import { CodegenAPI } from "./api/codegenAPI";
+import { registerCommands } from "./commands";
+import { ChatViewProvider } from "./providers/chatViewProvider";
export function activate(context: vscode.ExtensionContext) {
- console.log('Codegen extension is now active!');
+ console.log("Codegen extension is now active!");
- // Initialize the API client
- const api = new CodegenAPI();
-
- // Register the chat view provider
- const chatViewProvider = new ChatViewProvider(context.extensionUri, api);
- context.subscriptions.push(
- vscode.window.registerWebviewViewProvider(
- 'codegen.chatView',
- chatViewProvider,
- { webviewOptions: { retainContextWhenHidden: true } }
- )
- );
+ // Initialize the API client
+ const api = new CodegenAPI();
- // Register commands
- registerCommands(context, api, chatViewProvider);
+ // Register the chat view provider
+ const chatViewProvider = new ChatViewProvider(context.extensionUri, api);
+ context.subscriptions.push(
+ vscode.window.registerWebviewViewProvider(
+ "codegen.chatView",
+ chatViewProvider,
+ { webviewOptions: { retainContextWhenHidden: true } },
+ ),
+ );
- // Status bar item
- const statusBarItem = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Right, 100);
- statusBarItem.text = '$(sparkle) Codegen';
- statusBarItem.tooltip = 'Codegen AI Assistant';
- statusBarItem.command = 'codegen.askQuestion';
- statusBarItem.show();
- context.subscriptions.push(statusBarItem);
+ // Register commands
+ registerCommands(context, api, chatViewProvider);
+
+ // Status bar item
+ const statusBarItem = vscode.window.createStatusBarItem(
+ vscode.StatusBarAlignment.Right,
+ 100,
+ );
+ statusBarItem.text = "$(sparkle) Codegen";
+ statusBarItem.tooltip = "Codegen AI Assistant";
+ statusBarItem.command = "codegen.askQuestion";
+ statusBarItem.show();
+ context.subscriptions.push(statusBarItem);
}
export function deactivate() {
- // Clean up resources
+ // Clean up resources
}
diff --git a/codegen-vscode-extension/src/providers/chatViewProvider.ts b/codegen-vscode-extension/src/providers/chatViewProvider.ts
index 3ad0e5f91..d10774f39 100644
--- a/codegen-vscode-extension/src/providers/chatViewProvider.ts
+++ b/codegen-vscode-extension/src/providers/chatViewProvider.ts
@@ -1,124 +1,128 @@
-import * as vscode from 'vscode';
-import { CodegenAPI } from '../api/codegenAPI';
+import * as vscode from "vscode";
+import type { CodegenAPI } from "../api/codegenAPI";
interface ChatMessage {
- role: 'user' | 'assistant';
- content: string;
- code?: string;
- timestamp: number;
+ role: "user" | "assistant";
+ content: string;
+ code?: string;
+ timestamp: number;
}
export class ChatViewProvider implements vscode.WebviewViewProvider {
- public static readonly viewType = 'codegen.chatView';
- private _view?: vscode.WebviewView;
- private _messages: ChatMessage[] = [];
-
- constructor(
- private readonly _extensionUri: vscode.Uri,
- private readonly _api: CodegenAPI
- ) {}
-
- public resolveWebviewView(
- webviewView: vscode.WebviewView,
- context: vscode.WebviewViewResolveContext,
- _token: vscode.CancellationToken
- ) {
- this._view = webviewView;
-
- webviewView.webview.options = {
- enableScripts: true,
- localResourceRoots: [this._extensionUri]
- };
-
- webviewView.webview.html = this._getHtmlForWebview(webviewView.webview);
-
- // Handle messages from the webview
- webviewView.webview.onDidReceiveMessage(async (message) => {
- switch (message.command) {
- case 'sendMessage':
- await this._handleUserMessage(message.text);
- break;
- case 'clearChat':
- this._messages = [];
- this._updateWebview();
- break;
- case 'insertCode':
- this._insertCodeToEditor(message.code);
- break;
- }
- });
-
- // Update the webview with existing messages
- this._updateWebview();
- }
-
- public addMessage(role: 'user' | 'assistant', content: string, code?: string) {
- this._messages.push({
- role,
- content,
- code,
- timestamp: Date.now()
- });
-
- this._updateWebview();
- }
-
- private async _handleUserMessage(text: string) {
- // Add user message to chat
- this.addMessage('user', text);
-
- try {
- // Show loading indicator
- this._view?.webview.postMessage({ command: 'showLoading', value: true });
-
- // Get response from API
- const response = await this._api.askQuestion(text);
-
- // Add assistant message to chat
- this.addMessage('assistant', response.text, response.code);
-
- // Hide loading indicator
- this._view?.webview.postMessage({ command: 'showLoading', value: false });
- } catch (error) {
- // Hide loading indicator
- this._view?.webview.postMessage({ command: 'showLoading', value: false });
-
- // Show error message
- this.addMessage('assistant', `Error: ${error.message}`);
- }
- }
-
- private _updateWebview() {
- if (this._view) {
- this._view.webview.postMessage({
- command: 'updateMessages',
- messages: this._messages
- });
- }
- }
-
- private _insertCodeToEditor(code: string) {
- const editor = vscode.window.activeTextEditor;
- if (editor) {
- editor.edit(editBuilder => {
- editBuilder.insert(editor.selection.active, code);
- });
- }
- }
-
- private _getHtmlForWebview(webview: vscode.Webview) {
- // Create URIs for scripts and styles
- const scriptUri = webview.asWebviewUri(
- vscode.Uri.joinPath(this._extensionUri, 'media', 'main.js')
- );
- const styleUri = webview.asWebviewUri(
- vscode.Uri.joinPath(this._extensionUri, 'media', 'main.css')
- );
-
- // Use a nonce to allow only specific scripts to be run
- const nonce = this._getNonce();
-
- return `
+ public static readonly viewType = "codegen.chatView";
+ private _view?: vscode.WebviewView;
+ private _messages: ChatMessage[] = [];
+
+ constructor(
+ private readonly _extensionUri: vscode.Uri,
+ private readonly _api: CodegenAPI,
+ ) {}
+
+ public resolveWebviewView(
+ webviewView: vscode.WebviewView,
+ context: vscode.WebviewViewResolveContext,
+ _token: vscode.CancellationToken,
+ ) {
+ this._view = webviewView;
+
+ webviewView.webview.options = {
+ enableScripts: true,
+ localResourceRoots: [this._extensionUri],
+ };
+
+ webviewView.webview.html = this._getHtmlForWebview(webviewView.webview);
+
+ // Handle messages from the webview
+ webviewView.webview.onDidReceiveMessage(async (message) => {
+ switch (message.command) {
+ case "sendMessage":
+ await this._handleUserMessage(message.text);
+ break;
+ case "clearChat":
+ this._messages = [];
+ this._updateWebview();
+ break;
+ case "insertCode":
+ this._insertCodeToEditor(message.code);
+ break;
+ }
+ });
+
+ // Update the webview with existing messages
+ this._updateWebview();
+ }
+
+ public addMessage(
+ role: "user" | "assistant",
+ content: string,
+ code?: string,
+ ) {
+ this._messages.push({
+ role,
+ content,
+ code,
+ timestamp: Date.now(),
+ });
+
+ this._updateWebview();
+ }
+
+ private async _handleUserMessage(text: string) {
+ // Add user message to chat
+ this.addMessage("user", text);
+
+ try {
+ // Show loading indicator
+ this._view?.webview.postMessage({ command: "showLoading", value: true });
+
+ // Get response from API
+ const response = await this._api.askQuestion(text);
+
+ // Add assistant message to chat
+ this.addMessage("assistant", response.text, response.code);
+
+ // Hide loading indicator
+ this._view?.webview.postMessage({ command: "showLoading", value: false });
+ } catch (error) {
+ // Hide loading indicator
+ this._view?.webview.postMessage({ command: "showLoading", value: false });
+
+ // Show error message
+ this.addMessage("assistant", `Error: ${error.message}`);
+ }
+ }
+
+ private _updateWebview() {
+ if (this._view) {
+ this._view.webview.postMessage({
+ command: "updateMessages",
+ messages: this._messages,
+ });
+ }
+ }
+
+ private _insertCodeToEditor(code: string) {
+ const editor = vscode.window.activeTextEditor;
+ if (editor) {
+ editor.edit((editBuilder) => {
+ editBuilder.insert(editor.selection.active, code);
+ });
+ }
+ }
+
+ private _getHtmlForWebview(webview: vscode.Webview) {
+ // Create URIs for scripts and styles
+ const scriptUri = webview.asWebviewUri(
+ vscode.Uri.joinPath(this._extensionUri, "media", "main.js"),
+ );
+ const styleUri = webview.asWebviewUri(
+ vscode.Uri.joinPath(this._extensionUri, "media", "main.css"),
+ );
+
+ // Use a nonce to allow only specific scripts to be run
+ const nonce = this._getNonce();
+
+ return `
@@ -141,14 +145,15 @@ export class ChatViewProvider implements vscode.WebviewViewProvider {
`;
- }
-
- private _getNonce() {
- let text = '';
- const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
- for (let i = 0; i < 32; i++) {
- text += possible.charAt(Math.floor(Math.random() * possible.length));
- }
- return text;
- }
+ }
+
+ private _getNonce() {
+ let text = "";
+ const possible =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
+ for (let i = 0; i < 32; i++) {
+ text += possible.charAt(Math.floor(Math.random() * possible.length));
+ }
+ return text;
+ }
}
diff --git a/codegen-vscode-extension/src/utils.ts b/codegen-vscode-extension/src/utils.ts
index f802e69b0..f0478eba0 100644
--- a/codegen-vscode-extension/src/utils.ts
+++ b/codegen-vscode-extension/src/utils.ts
@@ -1,102 +1,110 @@
-import * as vscode from 'vscode';
+import * as vscode from "vscode";
/**
* Get the selected text from the editor
*/
export function getSelectedText(editor: vscode.TextEditor): string {
- const selection = editor.selection;
- if (selection.isEmpty) {
- return '';
- }
- return editor.document.getText(selection);
+ const selection = editor.selection;
+ if (selection.isEmpty) {
+ return "";
+ }
+ return editor.document.getText(selection);
}
/**
* Get the language of the document
*/
export function getDocumentLanguage(document: vscode.TextDocument): string {
- return document.languageId;
+ return document.languageId;
}
/**
* Insert text at the current cursor position
*/
export function insertText(editor: vscode.TextEditor, text: string): void {
- const selection = editor.selection;
- editor.edit(editBuilder => {
- editBuilder.insert(selection.active, text);
- });
+ const selection = editor.selection;
+ editor.edit((editBuilder) => {
+ editBuilder.insert(selection.active, text);
+ });
}
/**
* Get the current file path
*/
export function getCurrentFilePath(): string | undefined {
- const editor = vscode.window.activeTextEditor;
- if (!editor) {
- return undefined;
- }
- return editor.document.uri.fsPath;
+ const editor = vscode.window.activeTextEditor;
+ if (!editor) {
+ return undefined;
+ }
+ return editor.document.uri.fsPath;
}
/**
* Get the current workspace folder
*/
-export function getCurrentWorkspaceFolder(): vscode.WorkspaceFolder | undefined {
- const editor = vscode.window.activeTextEditor;
- if (!editor) {
- return undefined;
- }
- return vscode.workspace.getWorkspaceFolder(editor.document.uri);
+export function getCurrentWorkspaceFolder():
+ | vscode.WorkspaceFolder
+ | undefined {
+ const editor = vscode.window.activeTextEditor;
+ if (!editor) {
+ return undefined;
+ }
+ return vscode.workspace.getWorkspaceFolder(editor.document.uri);
}
/**
* Get the current project name
*/
export function getCurrentProjectName(): string | undefined {
- const workspaceFolder = getCurrentWorkspaceFolder();
- if (!workspaceFolder) {
- return undefined;
- }
- return workspaceFolder.name;
+ const workspaceFolder = getCurrentWorkspaceFolder();
+ if (!workspaceFolder) {
+ return undefined;
+ }
+ return workspaceFolder.name;
}
/**
* Get the current file name
*/
export function getCurrentFileName(): string | undefined {
- const editor = vscode.window.activeTextEditor;
- if (!editor) {
- return undefined;
- }
- return editor.document.fileName.split(/[\\/]/).pop();
+ const editor = vscode.window.activeTextEditor;
+ if (!editor) {
+ return undefined;
+ }
+ return editor.document.fileName.split(/[\\/]/).pop();
}
/**
* Get the current line of code
*/
export function getCurrentLine(editor: vscode.TextEditor): string {
- const position = editor.selection.active;
- const line = editor.document.lineAt(position.line);
- return line.text;
+ const position = editor.selection.active;
+ const line = editor.document.lineAt(position.line);
+ return line.text;
}
/**
* Get the current function or class
* This is a simple implementation and might not work for all languages
*/
-export function getCurrentFunction(editor: vscode.TextEditor): string | undefined {
- const document = editor.document;
- const position = editor.selection.active;
-
- // Simple implementation - search backwards for function or class definition
- for (let i = position.line; i >= 0; i--) {
- const line = document.lineAt(i).text.trim();
- if (line.startsWith('function ') || line.startsWith('class ') ||
- line.startsWith('def ') || line.match(/^[a-zA-Z0-9_]+\s*\([^)]*\)\s*{/)) {
- return line;
- }
- }
-
- return undefined;
+export function getCurrentFunction(
+ editor: vscode.TextEditor,
+): string | undefined {
+ const document = editor.document;
+ const position = editor.selection.active;
+
+ // Simple implementation - search backwards for function or class definition
+ for (let i = position.line; i >= 0; i--) {
+ const line = document.lineAt(i).text.trim();
+ if (
+ line.startsWith("function ") ||
+ line.startsWith("class ") ||
+ line.startsWith("def ") ||
+ line.match(/^[a-zA-Z0-9_]+\s*\([^)]*\)\s*{/)
+ ) {
+ return line;
+ }
+ }
+
+ return undefined;
}
diff --git a/codegen-vscode-extension/tsconfig.json b/codegen-vscode-extension/tsconfig.json
index 09724c930..0749ae80f 100644
--- a/codegen-vscode-extension/tsconfig.json
+++ b/codegen-vscode-extension/tsconfig.json
@@ -1,15 +1,15 @@
{
- "compilerOptions": {
- "module": "commonjs",
- "target": "ES2020",
- "outDir": "out",
- "lib": ["ES2020", "DOM"],
- "sourceMap": true,
- "rootDir": "src",
- "strict": true,
- "esModuleInterop": true,
- "skipLibCheck": true,
- "forceConsistentCasingInFileNames": true
- },
- "exclude": ["node_modules", ".vscode-test"]
+ "compilerOptions": {
+ "module": "commonjs",
+ "target": "ES2020",
+ "outDir": "out",
+ "lib": ["ES2020", "DOM"],
+ "sourceMap": true,
+ "rootDir": "src",
+ "strict": true,
+ "esModuleInterop": true,
+ "skipLibCheck": true,
+ "forceConsistentCasingInFileNames": true
+ },
+ "exclude": ["node_modules", ".vscode-test"]
}
diff --git a/codegen-vscode-extension/webpack.config.js b/codegen-vscode-extension/webpack.config.js
index d2df6e2d3..8fbf295ab 100644
--- a/codegen-vscode-extension/webpack.config.js
+++ b/codegen-vscode-extension/webpack.config.js
@@ -1,34 +1,34 @@
-const path = require('path');
+const path = require("path");
const config = {
- target: 'node',
- entry: './src/extension.ts',
- output: {
- path: path.resolve(__dirname, 'dist'),
- filename: 'extension.js',
- libraryTarget: 'commonjs2',
- devtoolModuleFilenameTemplate: '../[resource-path]'
- },
- devtool: 'source-map',
- externals: {
- vscode: 'commonjs vscode'
- },
- resolve: {
- extensions: ['.ts', '.js']
- },
- module: {
- rules: [
- {
- test: /\.ts$/,
- exclude: /node_modules/,
- use: [
- {
- loader: 'ts-loader'
- }
- ]
- }
- ]
- }
+ target: "node",
+ entry: "./src/extension.ts",
+ output: {
+ path: path.resolve(__dirname, "dist"),
+ filename: "extension.js",
+ libraryTarget: "commonjs2",
+ devtoolModuleFilenameTemplate: "../[resource-path]",
+ },
+ devtool: "source-map",
+ externals: {
+ vscode: "commonjs vscode",
+ },
+ resolve: {
+ extensions: [".ts", ".js"],
+ },
+ module: {
+ rules: [
+ {
+ test: /\.ts$/,
+ exclude: /node_modules/,
+ use: [
+ {
+ loader: "ts-loader",
+ },
+ ],
+ },
+ ],
+ },
};
module.exports = config;
From 5dfcbcc505ea51051d1c48bbec99c8d4fc6bb51f Mon Sep 17 00:00:00 2001
From: "codegen-sh[bot]" <131295404+codegen-sh[bot]@users.noreply.github.com>
Date: Wed, 30 Apr 2025 19:48:41 +0000
Subject: [PATCH 3/4] Add auto-expand functionality for chat messages
---
codegen-vscode-extension/media/main.css | 45 +++++++++++++++++++++
codegen-vscode-extension/media/main.js | 52 +++++++++++++++++++++++++
2 files changed, 97 insertions(+)
diff --git a/codegen-vscode-extension/media/main.css b/codegen-vscode-extension/media/main.css
index 010ce8d54..86a842023 100644
--- a/codegen-vscode-extension/media/main.css
+++ b/codegen-vscode-extension/media/main.css
@@ -4,6 +4,7 @@
--input-padding-horizontal: 8px;
--input-margin-vertical: 4px;
--input-margin-horizontal: 0;
+ --message-max-height: 150px; /* Added for collapsed messages */
}
body {
@@ -37,6 +38,8 @@ body {
border-radius: 6px;
max-width: 90%;
word-wrap: break-word;
+ cursor: pointer; /* Added to indicate clickable */
+ transition: max-height 0.3s ease; /* Added for smooth transition */
}
.user-message {
@@ -54,6 +57,7 @@ body {
.message-content {
margin-bottom: 5px;
+ overflow: hidden; /* Added for collapsed state */
}
.code-block {
@@ -242,3 +246,44 @@ body {
background-color: var(--vscode-editor-inactiveSelectionBackground);
font-weight: 600;
}
+
+/* Added for collapsed messages */
+.message-content.collapsed {
+ max-height: var(--message-max-height);
+ overflow: hidden;
+ position: relative;
+}
+
+/* Added gradient fade for collapsed messages */
+.message-content.collapsed::after {
+ content: "";
+ position: absolute;
+ bottom: 0;
+ left: 0;
+ width: 100%;
+ height: 40px;
+ background: linear-gradient(
+ to bottom,
+ transparent,
+ var(--vscode-editor-inactiveSelectionBackground)
+ );
+ pointer-events: none;
+}
+
+/* Adjust gradient color for user messages */
+.user-message .message-content.collapsed::after {
+ background: linear-gradient(
+ to bottom,
+ transparent,
+ var(--vscode-button-background)
+ );
+}
+
+/* Added expand indicator */
+.expand-indicator {
+ text-align: center;
+ font-size: 12px;
+ color: var(--vscode-descriptionForeground);
+ margin-top: 4px;
+ user-select: none;
+}
diff --git a/codegen-vscode-extension/media/main.js b/codegen-vscode-extension/media/main.js
index b0479a700..abc1efee4 100644
--- a/codegen-vscode-extension/media/main.js
+++ b/codegen-vscode-extension/media/main.js
@@ -51,6 +51,30 @@
}
}
+ // Check if content needs to be collapsed
+ function shouldCollapseContent(contentElement) {
+ // Get the computed max-height value from CSS variable
+ const maxHeight = parseInt(
+ getComputedStyle(document.documentElement).getPropertyValue('--message-max-height')
+ );
+
+ // If the content is taller than the max height, it should be collapsed
+ return contentElement.scrollHeight > maxHeight;
+ }
+
+ // Toggle message expansion
+ function toggleMessageExpansion(contentElement, indicatorElement) {
+ if (contentElement.classList.contains("collapsed")) {
+ // Expand
+ contentElement.classList.remove("collapsed");
+ indicatorElement.textContent = "Click to collapse";
+ } else {
+ // Collapse
+ contentElement.classList.add("collapsed");
+ indicatorElement.textContent = "Click to expand";
+ }
+ }
+
// Render all messages
function renderMessages() {
messagesContainer.innerHTML = "";
@@ -65,6 +89,34 @@
contentElement.innerHTML = formatMarkdown(message.content);
messageElement.appendChild(contentElement);
+ // Add expand indicator element
+ const expandIndicator = document.createElement("div");
+ expandIndicator.className = "expand-indicator";
+ messageElement.appendChild(expandIndicator);
+
+ // Check if content should be collapsed (after adding to DOM to get accurate height)
+ setTimeout(() => {
+ if (shouldCollapseContent(contentElement)) {
+ contentElement.classList.add("collapsed");
+ expandIndicator.textContent = "Click to expand";
+ } else {
+ expandIndicator.style.display = "none"; // Hide indicator if not needed
+ }
+ }, 0);
+
+ // Add click event to toggle expansion
+ messageElement.addEventListener("click", (e) => {
+ // Don't toggle if clicking on code action buttons
+ if (e.target.closest(".code-action-button")) {
+ return;
+ }
+
+ // Toggle expansion
+ if (shouldCollapseContent(contentElement)) {
+ toggleMessageExpansion(contentElement, expandIndicator);
+ }
+ });
+
// Code block (if any)
if (message.code) {
const codeElement = document.createElement("div");
From d37a4854ce4d2054094613f9795b3877f62b999d Mon Sep 17 00:00:00 2001
From: "codegen-sh[bot]" <131295404+codegen-sh[bot]@users.noreply.github.com>
Date: Wed, 30 Apr 2025 19:49:42 +0000
Subject: [PATCH 4/4] Automated pre-commit update
---
codegen-vscode-extension/media/main.js | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
diff --git a/codegen-vscode-extension/media/main.js b/codegen-vscode-extension/media/main.js
index abc1efee4..fa098d2c7 100644
--- a/codegen-vscode-extension/media/main.js
+++ b/codegen-vscode-extension/media/main.js
@@ -54,10 +54,12 @@
// Check if content needs to be collapsed
function shouldCollapseContent(contentElement) {
// Get the computed max-height value from CSS variable
- const maxHeight = parseInt(
- getComputedStyle(document.documentElement).getPropertyValue('--message-max-height')
+ const maxHeight = Number.parseInt(
+ getComputedStyle(document.documentElement).getPropertyValue(
+ "--message-max-height",
+ ),
);
-
+
// If the content is taller than the max height, it should be collapsed
return contentElement.scrollHeight > maxHeight;
}
@@ -110,7 +112,7 @@
if (e.target.closest(".code-action-button")) {
return;
}
-
+
// Toggle expansion
if (shouldCollapseContent(contentElement)) {
toggleMessageExpansion(contentElement, expandIndicator);