diff --git a/src/core/CodeActionProvider.ts b/src/core/CodeActionProvider.ts index d3b980a..1f977a4 100644 --- a/src/core/CodeActionProvider.ts +++ b/src/core/CodeActionProvider.ts @@ -1,5 +1,6 @@ import * as vscode from "vscode" import * as path from "path" +import { ClineProvider } from "./webview/ClineProvider" export const ACTION_NAMES = { EXPLAIN: "Roo Code: Explain Code", @@ -113,6 +114,18 @@ export class CodeActionProvider implements vscode.CodeActionProvider { return action } + private createActionPair( + baseTitle: string, + kind: vscode.CodeActionKind, + baseCommand: string, + args: any[], + ): vscode.CodeAction[] { + return [ + this.createAction(`${baseTitle} in New Task`, kind, baseCommand, args), + this.createAction(`${baseTitle} in Current Task`, kind, `${baseCommand}InCurrentTask`, args), + ] + } + private hasIntersectingRange(range1: vscode.Range, range2: vscode.Range): boolean { // Optimize range intersection check return !( @@ -138,8 +151,9 @@ export class CodeActionProvider implements vscode.CodeActionProvider { const actions: vscode.CodeAction[] = [] // Create actions using helper method + // Add explain actions actions.push( - this.createAction(ACTION_NAMES.EXPLAIN, vscode.CodeActionKind.QuickFix, COMMAND_IDS.EXPLAIN, [ + ...this.createActionPair(ACTION_NAMES.EXPLAIN, vscode.CodeActionKind.QuickFix, COMMAND_IDS.EXPLAIN, [ filePath, effectiveRange.text, ]), @@ -154,7 +168,7 @@ export class CodeActionProvider implements vscode.CodeActionProvider { if (relevantDiagnostics.length > 0) { const diagnosticMessages = relevantDiagnostics.map(this.createDiagnosticData) actions.push( - this.createAction(ACTION_NAMES.FIX, vscode.CodeActionKind.QuickFix, COMMAND_IDS.FIX, [ + ...this.createActionPair(ACTION_NAMES.FIX, vscode.CodeActionKind.QuickFix, COMMAND_IDS.FIX, [ filePath, effectiveRange.text, diagnosticMessages, @@ -163,11 +177,14 @@ export class CodeActionProvider implements vscode.CodeActionProvider { } } + // Add improve actions actions.push( - this.createAction(ACTION_NAMES.IMPROVE, vscode.CodeActionKind.RefactorRewrite, COMMAND_IDS.IMPROVE, [ - filePath, - effectiveRange.text, - ]), + ...this.createActionPair( + ACTION_NAMES.IMPROVE, + vscode.CodeActionKind.RefactorRewrite, + COMMAND_IDS.IMPROVE, + [filePath, effectiveRange.text], + ), ) return actions diff --git a/src/core/__tests__/CodeActionProvider.test.ts b/src/core/__tests__/CodeActionProvider.test.ts index d0bfc8e..0fb9ad1 100644 --- a/src/core/__tests__/CodeActionProvider.test.ts +++ b/src/core/__tests__/CodeActionProvider.test.ts @@ -1,5 +1,5 @@ import * as vscode from "vscode" -import { CodeActionProvider } from "../CodeActionProvider" +import { CodeActionProvider, ACTION_NAMES } from "../CodeActionProvider" // Mock VSCode API jest.mock("vscode", () => ({ @@ -109,9 +109,11 @@ describe("CodeActionProvider", () => { it("should provide explain and improve actions by default", () => { const actions = provider.provideCodeActions(mockDocument, mockRange, mockContext) - expect(actions).toHaveLength(2) - expect((actions as any)[0].title).toBe("Roo Code: Explain Code") - expect((actions as any)[1].title).toBe("Roo Code: Improve Code") + expect(actions).toHaveLength(4) + expect((actions as any)[0].title).toBe(`${ACTION_NAMES.EXPLAIN} in New Task`) + expect((actions as any)[1].title).toBe(`${ACTION_NAMES.EXPLAIN} in Current Task`) + expect((actions as any)[2].title).toBe(`${ACTION_NAMES.IMPROVE} in New Task`) + expect((actions as any)[3].title).toBe(`${ACTION_NAMES.IMPROVE} in Current Task`) }) it("should provide fix action when diagnostics exist", () => { @@ -125,8 +127,9 @@ describe("CodeActionProvider", () => { const actions = provider.provideCodeActions(mockDocument, mockRange, mockContext) - expect(actions).toHaveLength(3) - expect((actions as any).some((a: any) => a.title === "Roo Code: Fix Code")).toBe(true) + expect(actions).toHaveLength(6) + expect((actions as any).some((a: any) => a.title === `${ACTION_NAMES.FIX} in New Task`)).toBe(true) + expect((actions as any).some((a: any) => a.title === `${ACTION_NAMES.FIX} in Current Task`)).toBe(true) }) it("should handle errors gracefully", () => { diff --git a/src/core/webview/ClineProvider.ts b/src/core/webview/ClineProvider.ts index 808a50e..d532c27 100644 --- a/src/core/webview/ClineProvider.ts +++ b/src/core/webview/ClineProvider.ts @@ -188,10 +188,7 @@ export class ClineProvider implements vscode.WebviewViewProvider { return findLast(Array.from(this.activeInstances), (instance) => instance.view?.visible === true) } - public static async handleCodeAction( - promptType: keyof typeof ACTION_NAMES, - params: Record, - ): Promise { + public static async getInstance(): Promise { let visibleProvider = ClineProvider.getVisibleInstance() // If no visible provider, try to show the sidebar view @@ -207,10 +204,46 @@ export class ClineProvider implements vscode.WebviewViewProvider { return } + return visibleProvider + } + + public static async isActiveTask(): Promise { + const visibleProvider = await ClineProvider.getInstance() + if (!visibleProvider) { + return false + } + + if (visibleProvider.cline) { + return true + } + + return false + } + + public static async handleCodeAction( + command: string, + promptType: keyof typeof ACTION_NAMES, + params: Record, + ): Promise { + const visibleProvider = await ClineProvider.getInstance() + if (!visibleProvider) { + return + } + const { customSupportPrompts } = await visibleProvider.getState() const prompt = supportPrompt.create(promptType, params, customSupportPrompts) + if (visibleProvider.cline && command.endsWith("InCurrentTask")) { + await visibleProvider.postMessageToWebview({ + type: "invoke", + invoke: "sendMessage", + text: prompt, + }) + + return + } + await visibleProvider.initClineWithTask(prompt) } diff --git a/src/extension.ts b/src/extension.ts index 5e0dbb0..332759a 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -171,6 +171,7 @@ export function activate(context: vscode.ExtensionContext) { context: vscode.ExtensionContext, command: string, promptType: keyof typeof ACTION_NAMES, + inNewTask: boolean, inputPrompt?: string, inputPlaceholder?: string, ) => { @@ -194,14 +195,29 @@ export function activate(context: vscode.ExtensionContext) { ...(userInput ? { userInput } : {}), } - await ClineProvider.handleCodeAction(promptType, params) + await ClineProvider.handleCodeAction(command, promptType, params) }, ), ) } + // Helper function to register both versions of a code action + const registerCodeActionPair = ( + context: vscode.ExtensionContext, + baseCommand: string, + promptType: keyof typeof ACTION_NAMES, + inputPrompt?: string, + inputPlaceholder?: string, + ) => { + // Register new task version + registerCodeAction(context, baseCommand, promptType, true, inputPrompt, inputPlaceholder) + + // Register current task version + registerCodeAction(context, `${baseCommand}InCurrentTask`, promptType, false, inputPrompt, inputPlaceholder) + } + // Register code action commands - registerCodeAction( + registerCodeActionPair( context, "roo-cline.explainCode", "EXPLAIN", @@ -209,7 +225,7 @@ export function activate(context: vscode.ExtensionContext) { "E.g. How does the error handling work?", ) - registerCodeAction( + registerCodeActionPair( context, "roo-cline.fixCode", "FIX", @@ -217,7 +233,7 @@ export function activate(context: vscode.ExtensionContext) { "E.g. Maintain backward compatibility", ) - registerCodeAction( + registerCodeActionPair( context, "roo-cline.improveCode", "IMPROVE",