Merge pull request #594 from samhvw8/feat/code-action-with-current-task

feat(code-actions): add "Fix Code in Current Task" action
This commit is contained in:
Matt Rubens
2025-01-27 09:43:46 -05:00
committed by GitHub
4 changed files with 89 additions and 20 deletions

View File

@@ -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

View File

@@ -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", () => {

View File

@@ -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<string, string | any[]>,
): Promise<void> {
public static async getInstance(): Promise<ClineProvider | undefined> {
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<boolean> {
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<string, string | any[]>,
): Promise<void> {
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)
}

View File

@@ -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",