From 1b26f91ea7378d11062aa5299d48686ea197b4bc Mon Sep 17 00:00:00 2001 From: sam hoang Date: Sun, 12 Jan 2025 21:20:02 +0700 Subject: [PATCH] refactor(code-actions): implement parameter object pattern for prompt generation - Extract prompt templates into constants - Add createPrompt utility for template string handling - Consolidate code action handling in ClineProvider - Update tests to use new parameter object pattern --- .../prompts/__tests__/code-actions.test.ts | 21 +++++-- src/core/prompts/code-actions.ts | 59 +++++++++++++------ src/core/webview/ClineProvider.ts | 14 +++++ src/extension.ts | 25 +++----- 4 files changed, 79 insertions(+), 40 deletions(-) diff --git a/src/core/prompts/__tests__/code-actions.test.ts b/src/core/prompts/__tests__/code-actions.test.ts index ad4c281..0ddb6bd 100644 --- a/src/core/prompts/__tests__/code-actions.test.ts +++ b/src/core/prompts/__tests__/code-actions.test.ts @@ -6,7 +6,10 @@ describe('Code Action Prompts', () => { describe('explainCodePrompt', () => { it('should format explain prompt correctly', () => { - const prompt = explainCodePrompt(testFilePath, testCode); + const prompt = explainCodePrompt({ + filePath: testFilePath, + selectedText: testCode + }); expect(prompt).toContain(`@/${testFilePath}`); expect(prompt).toContain(testCode); @@ -18,7 +21,10 @@ describe('Code Action Prompts', () => { describe('fixCodePrompt', () => { it('should format fix prompt without diagnostics', () => { - const prompt = fixCodePrompt(testFilePath, testCode); + const prompt = fixCodePrompt({ + filePath: testFilePath, + selectedText: testCode + }); expect(prompt).toContain(`@/${testFilePath}`); expect(prompt).toContain(testCode); @@ -39,7 +45,11 @@ describe('Code Action Prompts', () => { } ]; - const prompt = fixCodePrompt(testFilePath, testCode, diagnostics); + const prompt = fixCodePrompt({ + filePath: testFilePath, + selectedText: testCode, + diagnostics + }); expect(prompt).toContain('Current problems detected:'); expect(prompt).toContain('[eslint] Missing semicolon (semi)'); @@ -50,7 +60,10 @@ describe('Code Action Prompts', () => { describe('improveCodePrompt', () => { it('should format improve prompt correctly', () => { - const prompt = improveCodePrompt(testFilePath, testCode); + const prompt = improveCodePrompt({ + filePath: testFilePath, + selectedText: testCode + }); expect(prompt).toContain(`@/${testFilePath}`); expect(prompt).toContain(testCode); diff --git a/src/core/prompts/code-actions.ts b/src/core/prompts/code-actions.ts index 3fd03ae..2b9445d 100644 --- a/src/core/prompts/code-actions.ts +++ b/src/core/prompts/code-actions.ts @@ -1,8 +1,29 @@ -export const explainCodePrompt = (filePath: string, selectedText: string) => ` -Explain the following code from file path @/${filePath}: +type PromptParams = Record; + +const generateDiagnosticText = (diagnostics?: any[]) => { + if (!diagnostics?.length) return ''; + return `\nCurrent problems detected:\n${diagnostics.map(d => + `- [${d.source || 'Error'}] ${d.message}${d.code ? ` (${d.code})` : ''}` + ).join('\n')}`; +}; + +const createPrompt = (template: string, params: PromptParams): string => { + let result = template; + for (const [key, value] of Object.entries(params)) { + if (key === 'diagnostics') { + result = result.replaceAll('${diagnosticText}', generateDiagnosticText(value as any[])); + } else { + result = result.replaceAll(`\${${key}}`, value as string); + } + } + return result; +}; + +const EXPLAIN_TEMPLATE = ` +Explain the following code from file path @/\${filePath}: \`\`\` -${selectedText} +\${selectedText} \`\`\` Please provide a clear and concise explanation of what this code does, including: @@ -11,18 +32,12 @@ Please provide a clear and concise explanation of what this code does, including 3. Important patterns or techniques used `; -export const fixCodePrompt = (filePath: string, selectedText: string, diagnostics?: any[]) => { - const diagnosticText = diagnostics && diagnostics.length > 0 - ? `\nCurrent problems detected: -${diagnostics.map(d => `- [${d.source || 'Error'}] ${d.message}${d.code ? ` (${d.code})` : ''}`).join('\n')}` - : ''; - - return ` -Fix any issues in the following code from file path @/${filePath} -${diagnosticText} +const FIX_TEMPLATE = ` +Fix any issues in the following code from file path @/\${filePath} +\${diagnosticText} \`\`\` -${selectedText} +\${selectedText} \`\`\` Please: @@ -31,13 +46,12 @@ Please: 3. Provide corrected code 4. Explain what was fixed and why `; -}; -export const improveCodePrompt = (filePath: string, selectedText: string) => ` -Improve the following code from file path @/${filePath}: +const IMPROVE_TEMPLATE = ` +Improve the following code from file path @/\${filePath}: \`\`\` -${selectedText} +\${selectedText} \`\`\` Please suggest improvements for: @@ -47,4 +61,13 @@ Please suggest improvements for: 4. Error handling and edge cases Provide the improved code along with explanations for each enhancement. -`; \ No newline at end of file +`; + +export const explainCodePrompt = (params: PromptParams) => + createPrompt(EXPLAIN_TEMPLATE, params); + +export const fixCodePrompt = (params: PromptParams) => + createPrompt(FIX_TEMPLATE, params); + +export const improveCodePrompt = (params: PromptParams) => + createPrompt(IMPROVE_TEMPLATE, params); \ No newline at end of file diff --git a/src/core/webview/ClineProvider.ts b/src/core/webview/ClineProvider.ts index b3e5235..17289f5 100644 --- a/src/core/webview/ClineProvider.ts +++ b/src/core/webview/ClineProvider.ts @@ -181,6 +181,20 @@ export class ClineProvider implements vscode.WebviewViewProvider { return findLast(Array.from(this.activeInstances), (instance) => instance.view?.visible === true) } + public static async handleCodeAction( + promptGenerator: (params: Record) => string, + params: Record + ): Promise { + const visibleProvider = ClineProvider.getVisibleInstance() + if (!visibleProvider) { + return + } + + const prompt = promptGenerator(params) + + await visibleProvider.initClineWithTask(prompt) + } + resolveWebviewView( webviewView: vscode.WebviewView | vscode.WebviewPanel, //context: vscode.WebviewViewResolveContext, used to recreate a deallocated webview, but we don't need this since we use retainContextWhenHidden diff --git a/src/extension.ts b/src/extension.ts index e6cfde7..6c8c9e7 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -174,34 +174,23 @@ export function activate(context: vscode.ExtensionContext) { // Register code action commands context.subscriptions.push( vscode.commands.registerCommand("roo-cline.explainCode", async (filePath: string, selectedText: string) => { - const visibleProvider = ClineProvider.getVisibleInstance() - if (!visibleProvider) { - return - } - const prompt = explainCodePrompt(filePath, selectedText) - await visibleProvider.initClineWithTask(prompt) + await ClineProvider.handleCodeAction(explainCodePrompt, { filePath, selectedText }) }) ); context.subscriptions.push( vscode.commands.registerCommand("roo-cline.fixCode", async (filePath: string, selectedText: string, diagnostics?: any[]) => { - const visibleProvider = ClineProvider.getVisibleInstance() - if (!visibleProvider) { - return - } - const prompt = fixCodePrompt(filePath, selectedText, diagnostics) - await visibleProvider.initClineWithTask(prompt) + await ClineProvider.handleCodeAction(fixCodePrompt, { + filePath, + selectedText, + ...(diagnostics ? { diagnostics } : {}) + }) }) ); context.subscriptions.push( vscode.commands.registerCommand("roo-cline.improveCode", async (filePath: string, selectedText: string) => { - const visibleProvider = ClineProvider.getVisibleInstance() - if (!visibleProvider) { - return - } - const prompt = improveCodePrompt(filePath, selectedText) - await visibleProvider.initClineWithTask(prompt) + await ClineProvider.handleCodeAction(improveCodePrompt, { filePath, selectedText }) }) );