Skip to content

Commit

Permalink
add cancel button, update test suite, fix broken link
Browse files Browse the repository at this point in the history
  • Loading branch information
Talamantez committed Nov 22, 2024
1 parent fe5d18f commit 43ee4a0
Show file tree
Hide file tree
Showing 7 changed files with 382 additions and 270 deletions.
9 changes: 7 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,14 @@
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [1.1.8] - 2024-11-18

## [1.1.9] - 2024-11-21
### Changed
- Fixed broken link in readme

## [1.1.8] - 2024-11-21
### Changed
- Added Cancel Button
- Added Cancel Button, updated test suite

## [1.1.7] - 2024-11-18
### Changed
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,6 @@ Please consider learning more about their mission and supporting their fundraise

## Call for Feature Requests

What's working? What's not? What are your other painpoints in your AI workflow? Want to chat about fresh baked lemon cupcakes? Don't be shy. [Open an Issue!](https://github.com/username/repository/issues/new)
What's working? What's not? What are your other painpoints in your AI workflow? Want to chat about fresh baked lemon cupcakes? Don't be shy. [Open an Issue!](https://github.com/talamantez/claude-vscode/issues/new)

[![Buy Me A Coffee](https://img.shields.io/badge/Buy%20Me%20A%20Coffee-Support-yellow?style=flat&logo=buy-me-a-coffee)](https://www.buymeacoffee.com/conscious.robot)
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "claude-vscode-assistant",
"displayName": "Claude AI Assistant",
"version": "1.1.8",
"version": "1.1.9",
"description": "Claude AI assistant for Visual Studio Code",
"publisher": "conscious-robot",
"repository": {
Expand Down
51 changes: 51 additions & 0 deletions src/config.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,66 @@
// src/config.ts
import * as vscode from 'vscode';
import { waitForExtensionReady } from './utils';

export interface Configuration {
model: string;
apiKey?: string;
}

// Extension timing configuration
export const Timeouts = {
CLEANUP: 1000, // 1 second for cleanup operations
DEFAULT_ACTIVATION: 100, // 100ms default safety delay
get ACTIVATION(): number {
return parseInt(process.env.VSCODE_CLAUDE_ACTIVATION_TIMEOUT || '', 10) || this.DEFAULT_ACTIVATION;
},
STATUS_BAR_PRIORITY: 100
} as const;

export function getConfiguration(): Configuration {
const config = vscode.workspace.getConfiguration('claude-vscode');
return {
model: config.get('model') || 'claude-3-opus-20240229',
apiKey: config.get('apiKey')
};
}

export async function unregisterCommands(): Promise<void> {
const allCommands = await vscode.commands.getCommands();
const ourCommands = [
'claude-vscode.support',
'claude-vscode.askClaude',
'claude-vscode.documentCode'
];

// First try normal unregistration
for (const cmd of ourCommands) {
if (allCommands.includes(cmd)) {
try {
await vscode.commands.executeCommand('workbench.action.unregisterCommand', cmd);
} catch (err) {
console.warn(`Failed to unregister command ${cmd}:`, err);
}
}
}

// Wait for commands to unregister
await waitForExtensionReady(Timeouts.ACTIVATION);

// Force cleanup in case normal unregistration failed
const remainingCommands = await vscode.commands.getCommands();
for (const cmd of ourCommands) {
if (remainingCommands.includes(cmd)) {
try {
// Force dispose any existing command registration
const existingDisposable = vscode.commands.registerCommand(cmd, () => {});
existingDisposable.dispose();
} catch (err) {
console.warn(`Failed force cleanup of command ${cmd}:`, err);
}
}
}

// Final wait to ensure cleanup
await waitForExtensionReady(Timeouts.ACTIVATION);
}
81 changes: 41 additions & 40 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,14 @@
import * as vscode from 'vscode';
import { ClaudeApiService, DefaultClaudeApiService } from './services/claude-api';
import { ClaudeResponse } from './api';
import { Timeouts } from './config';
import { waitForExtensionReady, ensureAllEditorsClosed, unregisterCommands } from './utils';

// Global state management
let registeredCommands: vscode.Disposable[] = [];
let apiService: ClaudeApiService;
let cancellationTokenSource: vscode.CancellationTokenSource | undefined;

// Constants
const CLEANUP_TIMEOUT = 1000; // 1 second
const STATUS_BAR_PRIORITY = 100;

/**
* Formats the response from Claude into a markdown document
*/
Expand Down Expand Up @@ -89,7 +87,7 @@ async function handleClaudeRequest(mode: 'general' | 'document') {

const statusBarItem = vscode.window.createStatusBarItem(
vscode.StatusBarAlignment.Right,
STATUS_BAR_PRIORITY
Timeouts.STATUS_BAR_PRIORITY
);
statusBarItem.text = "$(sync~spin) Asking Claude...";
statusBarItem.show();
Expand Down Expand Up @@ -132,7 +130,7 @@ async function handleClaudeRequest(mode: 'general' | 'document') {
export async function cleanupPanelsAndEditors(): Promise<void> {
try {
await vscode.commands.executeCommand('workbench.action.closeAllEditors');
await new Promise(resolve => setTimeout(resolve, CLEANUP_TIMEOUT));
await new Promise(resolve => setTimeout(resolve, Timeouts.CLEANUP));

// Remove activePanels cleanup code, just keep tab cleanup
vscode.window.tabGroups.all.forEach(group => {
Expand Down Expand Up @@ -162,46 +160,41 @@ export async function activate(context: vscode.ExtensionContext, service?: Claud
console.log('Claude extension activating...');

try {
// Cleanup any existing commands first
registeredCommands.forEach(cmd => {
try {
cmd.dispose();
} catch (error) {
console.warn('Error disposing command:', error);
}
});
registeredCommands = [];

// Ensure previous commands are disposed and add safety timeout
await deactivate();
await new Promise(resolve => setTimeout(resolve, Timeouts.ACTIVATION)); // Wait for cleanup

// Initialize API service
apiService = service || new DefaultClaudeApiService();

// Support command for donations
const supportCommand = vscode.commands.registerCommand('claude-vscode.support', () => {
vscode.env.openExternal(vscode.Uri.parse('https://buy.stripe.com/aEUcQc7Cb3VE22I3cc'));
});
// Register commands after cleanup
const commands = [
// Support command for donations
vscode.commands.registerCommand('claude-vscode.support', () => {
vscode.env.openExternal(vscode.Uri.parse('https://buy.stripe.com/aEUcQc7Cb3VE22I3cc'));
}),

// Main commands
const askCommand = vscode.commands.registerCommand(
'claude-vscode.askClaude',
() => handleClaudeRequest('general')
);
// Main commands
vscode.commands.registerCommand('claude-vscode.askClaude', () =>
handleClaudeRequest('general')
),

const documentCommand = vscode.commands.registerCommand(
'claude-vscode.documentCode',
() => handleClaudeRequest('document')
);
vscode.commands.registerCommand('claude-vscode.documentCode', () =>
handleClaudeRequest('document')
)
];

// Store commands
registeredCommands = [supportCommand, askCommand, documentCommand];
// Store commands and add to subscriptions
registeredCommands = commands;
context.subscriptions.push(...commands);

// Add to subscriptions
context.subscriptions.push(...registeredCommands);

console.log('Claude extension activated');

// Return activation promise
console.log('Claude extension activated successfully');
return Promise.resolve();

} catch (error) {
console.error('Error during activation:', error);
// Ensure cleanup on activation failure
await deactivate();
throw error;
}
}
Expand All @@ -213,16 +206,24 @@ export async function deactivate() {
console.log('Claude extension deactivating...');

try {
registeredCommands.forEach(cmd => cmd.dispose());
// Dispose all registered commands
for (const cmd of registeredCommands) {
try {
cmd.dispose();
} catch (err) {
console.warn('Error disposing command:', err);
}
}
registeredCommands = [];

// Clean up panels and editors
await cleanupPanelsAndEditors();

console.log('Claude extension deactivated');
console.log('Claude extension deactivated successfully');
} catch (error) {
console.error('Error during deactivation:', error);
throw error;
} finally {
console.log('Thank you for supporting the Open Source!')
console.log('Thank you for supporting the Open Source!');
}
}
51 changes: 51 additions & 0 deletions src/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// src/utils.ts
import * as vscode from 'vscode';
import { Timeouts } from './config';

/**
* Waits for the extension to be ready after state changes
* @param timeout Optional custom timeout (defaults to 3x activation timeout)
*/
export async function waitForExtensionReady(timeout?: number): Promise<void> {
const waitTime = timeout || Math.max(Timeouts.ACTIVATION * 3, 500);
await new Promise(resolve => setTimeout(resolve, waitTime));
}

/**
* Ensures all editor windows are closed
* @param retries Number of retry attempts
* @param delay Delay between retries in ms
*/
export async function ensureAllEditorsClosed(retries = 3, delay = 500): Promise<void> {
for (let i = 0; i < retries; i++) {
if (vscode.window.visibleTextEditors.length === 0) return;
await vscode.commands.executeCommand('workbench.action.closeAllEditors');
await new Promise(resolve => setTimeout(resolve, delay));
}
if (vscode.window.visibleTextEditors.length > 0) {
throw new Error('Failed to close all editors');
}
}

/**
* Unregisters our extension's commands from VS Code
*/
export async function unregisterCommands(): Promise<void> {
const allCommands = await vscode.commands.getCommands();
const ourCommands = [
'claude-vscode.support',
'claude-vscode.askClaude',
'claude-vscode.documentCode'
];

for (const cmd of ourCommands) {
if (allCommands.includes(cmd)) {
try {
await vscode.commands.executeCommand('workbench.action.unregisterCommand', cmd);
} catch (err) {
console.warn(`Failed to unregister command ${cmd}:`, err);
}
}
}
await waitForExtensionReady(Timeouts.ACTIVATION);
}
Loading

0 comments on commit 43ee4a0

Please sign in to comment.