mirror of
https://github.com/pacnpal/Roo-Code.git
synced 2025-12-20 12:21:13 -05:00
fix comment on pr
This commit is contained in:
188
package.json
188
package.json
@@ -72,102 +72,102 @@
|
|||||||
"title": "New Task",
|
"title": "New Task",
|
||||||
"icon": "$(add)"
|
"icon": "$(add)"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"command": "roo-cline.mcpButtonClicked",
|
"command": "roo-cline.mcpButtonClicked",
|
||||||
"title": "MCP Servers",
|
"title": "MCP Servers",
|
||||||
"icon": "$(server)"
|
"icon": "$(server)"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"command": "roo-cline.promptsButtonClicked",
|
"command": "roo-cline.promptsButtonClicked",
|
||||||
"title": "Prompts",
|
"title": "Prompts",
|
||||||
"icon": "$(notebook)"
|
"icon": "$(notebook)"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"command": "roo-cline.historyButtonClicked",
|
"command": "roo-cline.historyButtonClicked",
|
||||||
"title": "History",
|
"title": "History",
|
||||||
"icon": "$(history)"
|
"icon": "$(history)"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"command": "roo-cline.popoutButtonClicked",
|
"command": "roo-cline.popoutButtonClicked",
|
||||||
"title": "Open in Editor",
|
"title": "Open in Editor",
|
||||||
"icon": "$(link-external)"
|
"icon": "$(link-external)"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"command": "roo-cline.settingsButtonClicked",
|
"command": "roo-cline.settingsButtonClicked",
|
||||||
"title": "Settings",
|
"title": "Settings",
|
||||||
"icon": "$(settings-gear)"
|
"icon": "$(settings-gear)"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"command": "roo-cline.openInNewTab",
|
"command": "roo-cline.openInNewTab",
|
||||||
"title": "Open In New Tab",
|
"title": "Open In New Tab",
|
||||||
"category": "Roo Code"
|
"category": "Roo Code"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"command": "roo-cline.explainCode",
|
"command": "roo-cline.explainCode",
|
||||||
"title": "Explain Code",
|
"title": "Explain Code",
|
||||||
"category": "Roo Cline"
|
"category": "Roo Code"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"command": "roo-cline.fixCode",
|
"command": "roo-cline.fixCode",
|
||||||
"title": "Fix Code",
|
"title": "Fix Code",
|
||||||
"category": "Roo Cline"
|
"category": "Roo Code"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"command": "roo-cline.improveCode",
|
"command": "roo-cline.improveCode",
|
||||||
"title": "Improve Code",
|
"title": "Improve Code",
|
||||||
"category": "Roo Cline"
|
"category": "Roo Code"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"menus": {
|
"menus": {
|
||||||
"editor/context": [
|
"editor/context": [
|
||||||
{
|
{
|
||||||
"command": "roo-cline.explainCode",
|
"command": "roo-cline.explainCode",
|
||||||
"when": "editorHasSelection",
|
"when": "editorHasSelection",
|
||||||
"group": "Roo Cline@1"
|
"group": "Roo Code@1"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"command": "roo-cline.fixCode",
|
"command": "roo-cline.fixCode",
|
||||||
"when": "editorHasSelection",
|
"when": "editorHasSelection",
|
||||||
"group": "Roo Cline@2"
|
"group": "Roo Code@2"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"command": "roo-cline.improveCode",
|
"command": "roo-cline.improveCode",
|
||||||
"when": "editorHasSelection",
|
"when": "editorHasSelection",
|
||||||
"group": "Roo Cline@3"
|
"group": "Roo Code@3"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"view/title": [
|
"view/title": [
|
||||||
{
|
{
|
||||||
"command": "roo-cline.plusButtonClicked",
|
"command": "roo-cline.plusButtonClicked",
|
||||||
"group": "navigation@1",
|
"group": "navigation@1",
|
||||||
"when": "view == roo-cline.SidebarProvider"
|
"when": "view == roo-cline.SidebarProvider"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"command": "roo-cline.promptsButtonClicked",
|
"command": "roo-cline.promptsButtonClicked",
|
||||||
"group": "navigation@2",
|
"group": "navigation@2",
|
||||||
"when": "view == roo-cline.SidebarProvider"
|
"when": "view == roo-cline.SidebarProvider"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"command": "roo-cline.mcpButtonClicked",
|
"command": "roo-cline.mcpButtonClicked",
|
||||||
"group": "navigation@3",
|
"group": "navigation@3",
|
||||||
"when": "view == roo-cline.SidebarProvider"
|
"when": "view == roo-cline.SidebarProvider"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"command": "roo-cline.historyButtonClicked",
|
"command": "roo-cline.historyButtonClicked",
|
||||||
"group": "navigation@4",
|
"group": "navigation@4",
|
||||||
"when": "view == roo-cline.SidebarProvider"
|
"when": "view == roo-cline.SidebarProvider"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"command": "roo-cline.popoutButtonClicked",
|
"command": "roo-cline.popoutButtonClicked",
|
||||||
"group": "navigation@5",
|
"group": "navigation@5",
|
||||||
"when": "view == roo-cline.SidebarProvider"
|
"when": "view == roo-cline.SidebarProvider"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"command": "roo-cline.settingsButtonClicked",
|
"command": "roo-cline.settingsButtonClicked",
|
||||||
"group": "navigation@6",
|
"group": "navigation@6",
|
||||||
"when": "view == roo-cline.SidebarProvider"
|
"when": "view == roo-cline.SidebarProvider"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"configuration": {
|
"configuration": {
|
||||||
"title": "Roo Code",
|
"title": "Roo Code",
|
||||||
|
|||||||
@@ -1,181 +1,179 @@
|
|||||||
import * as vscode from 'vscode';
|
import * as vscode from "vscode"
|
||||||
import * as path from 'path';
|
import * as path from "path"
|
||||||
|
|
||||||
export const ACTION_NAMES = {
|
export const ACTION_NAMES = {
|
||||||
EXPLAIN: 'Roo Cline: Explain Code',
|
EXPLAIN: "Roo Code: Explain Code",
|
||||||
FIX: 'Roo Cline: Fix Code',
|
FIX: "Roo Code: Fix Code",
|
||||||
IMPROVE: 'Roo Cline: Improve Code'
|
IMPROVE: "Roo Code: Improve Code",
|
||||||
} as const;
|
} as const
|
||||||
|
|
||||||
const COMMAND_IDS = {
|
const COMMAND_IDS = {
|
||||||
EXPLAIN: 'roo-cline.explainCode',
|
EXPLAIN: "roo-cline.explainCode",
|
||||||
FIX: 'roo-cline.fixCode',
|
FIX: "roo-cline.fixCode",
|
||||||
IMPROVE: 'roo-cline.improveCode'
|
IMPROVE: "roo-cline.improveCode",
|
||||||
} as const;
|
} as const
|
||||||
|
|
||||||
interface DiagnosticData {
|
interface DiagnosticData {
|
||||||
message: string;
|
message: string
|
||||||
severity: vscode.DiagnosticSeverity;
|
severity: vscode.DiagnosticSeverity
|
||||||
code?: string | number | { value: string | number; target: vscode.Uri };
|
code?: string | number | { value: string | number; target: vscode.Uri }
|
||||||
source?: string;
|
source?: string
|
||||||
range: vscode.Range;
|
range: vscode.Range
|
||||||
}
|
}
|
||||||
|
|
||||||
interface EffectiveRange {
|
interface EffectiveRange {
|
||||||
range: vscode.Range;
|
range: vscode.Range
|
||||||
text: string;
|
text: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export class CodeActionProvider implements vscode.CodeActionProvider {
|
export class CodeActionProvider implements vscode.CodeActionProvider {
|
||||||
public static readonly providedCodeActionKinds = [
|
public static readonly providedCodeActionKinds = [
|
||||||
vscode.CodeActionKind.QuickFix,
|
vscode.CodeActionKind.QuickFix,
|
||||||
vscode.CodeActionKind.RefactorRewrite,
|
vscode.CodeActionKind.RefactorRewrite,
|
||||||
];
|
]
|
||||||
|
|
||||||
// Cache file paths for performance
|
// Cache file paths for performance
|
||||||
private readonly filePathCache = new WeakMap<vscode.TextDocument, string>();
|
private readonly filePathCache = new WeakMap<vscode.TextDocument, string>()
|
||||||
|
|
||||||
private getEffectiveRange(
|
private getEffectiveRange(
|
||||||
document: vscode.TextDocument,
|
document: vscode.TextDocument,
|
||||||
range: vscode.Range | vscode.Selection
|
range: vscode.Range | vscode.Selection,
|
||||||
): EffectiveRange | null {
|
): EffectiveRange | null {
|
||||||
try {
|
try {
|
||||||
const selectedText = document.getText(range);
|
const selectedText = document.getText(range)
|
||||||
if (selectedText) {
|
if (selectedText) {
|
||||||
return { range, text: selectedText };
|
return { range, text: selectedText }
|
||||||
}
|
}
|
||||||
|
|
||||||
const currentLine = document.lineAt(range.start.line);
|
const currentLine = document.lineAt(range.start.line)
|
||||||
if (!currentLine.text.trim()) {
|
if (!currentLine.text.trim()) {
|
||||||
return null;
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
// Optimize range creation by checking bounds first
|
// Optimize range creation by checking bounds first
|
||||||
const startLine = Math.max(0, currentLine.lineNumber - 1);
|
const startLine = Math.max(0, currentLine.lineNumber - 1)
|
||||||
const endLine = Math.min(document.lineCount - 1, currentLine.lineNumber + 1);
|
const endLine = Math.min(document.lineCount - 1, currentLine.lineNumber + 1)
|
||||||
|
|
||||||
// Only create new positions if needed
|
|
||||||
const effectiveRange = new vscode.Range(
|
|
||||||
startLine === currentLine.lineNumber ? range.start : new vscode.Position(startLine, 0),
|
|
||||||
endLine === currentLine.lineNumber ? range.end : new vscode.Position(endLine, document.lineAt(endLine).text.length)
|
|
||||||
);
|
|
||||||
|
|
||||||
return {
|
// Only create new positions if needed
|
||||||
range: effectiveRange,
|
const effectiveRange = new vscode.Range(
|
||||||
text: document.getText(effectiveRange)
|
startLine === currentLine.lineNumber ? range.start : new vscode.Position(startLine, 0),
|
||||||
};
|
endLine === currentLine.lineNumber
|
||||||
} catch (error) {
|
? range.end
|
||||||
console.error('Error getting effective range:', error);
|
: new vscode.Position(endLine, document.lineAt(endLine).text.length),
|
||||||
return null;
|
)
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private getFilePath(document: vscode.TextDocument): string {
|
return {
|
||||||
// Check cache first
|
range: effectiveRange,
|
||||||
let filePath = this.filePathCache.get(document);
|
text: document.getText(effectiveRange),
|
||||||
if (filePath) {
|
}
|
||||||
return filePath;
|
} catch (error) {
|
||||||
}
|
console.error("Error getting effective range:", error)
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
private getFilePath(document: vscode.TextDocument): string {
|
||||||
const workspaceFolder = vscode.workspace.getWorkspaceFolder(document.uri);
|
// Check cache first
|
||||||
if (!workspaceFolder) {
|
let filePath = this.filePathCache.get(document)
|
||||||
filePath = document.uri.fsPath;
|
if (filePath) {
|
||||||
} else {
|
return filePath
|
||||||
const relativePath = path.relative(workspaceFolder.uri.fsPath, document.uri.fsPath);
|
}
|
||||||
filePath = (!relativePath || relativePath.startsWith('..')) ? document.uri.fsPath : relativePath;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cache the result
|
try {
|
||||||
this.filePathCache.set(document, filePath);
|
const workspaceFolder = vscode.workspace.getWorkspaceFolder(document.uri)
|
||||||
return filePath;
|
if (!workspaceFolder) {
|
||||||
} catch (error) {
|
filePath = document.uri.fsPath
|
||||||
console.error('Error getting file path:', error);
|
} else {
|
||||||
return document.uri.fsPath;
|
const relativePath = path.relative(workspaceFolder.uri.fsPath, document.uri.fsPath)
|
||||||
}
|
filePath = !relativePath || relativePath.startsWith("..") ? document.uri.fsPath : relativePath
|
||||||
}
|
}
|
||||||
|
|
||||||
private createDiagnosticData(diagnostic: vscode.Diagnostic): DiagnosticData {
|
// Cache the result
|
||||||
return {
|
this.filePathCache.set(document, filePath)
|
||||||
message: diagnostic.message,
|
return filePath
|
||||||
severity: diagnostic.severity,
|
} catch (error) {
|
||||||
code: diagnostic.code,
|
console.error("Error getting file path:", error)
|
||||||
source: diagnostic.source,
|
return document.uri.fsPath
|
||||||
range: diagnostic.range // Reuse the range object
|
}
|
||||||
};
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private createAction(
|
private createDiagnosticData(diagnostic: vscode.Diagnostic): DiagnosticData {
|
||||||
title: string,
|
return {
|
||||||
kind: vscode.CodeActionKind,
|
message: diagnostic.message,
|
||||||
command: string,
|
severity: diagnostic.severity,
|
||||||
args: any[]
|
code: diagnostic.code,
|
||||||
): vscode.CodeAction {
|
source: diagnostic.source,
|
||||||
const action = new vscode.CodeAction(title, kind);
|
range: diagnostic.range, // Reuse the range object
|
||||||
action.command = { command, title, arguments: args };
|
}
|
||||||
return action;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private hasIntersectingRange(range1: vscode.Range, range2: vscode.Range): boolean {
|
private createAction(title: string, kind: vscode.CodeActionKind, command: string, args: any[]): vscode.CodeAction {
|
||||||
// Optimize range intersection check
|
const action = new vscode.CodeAction(title, kind)
|
||||||
return !(
|
action.command = { command, title, arguments: args }
|
||||||
range2.end.line < range1.start.line ||
|
return action
|
||||||
range2.start.line > range1.end.line ||
|
}
|
||||||
(range2.end.line === range1.start.line && range2.end.character < range1.start.character) ||
|
|
||||||
(range2.start.line === range1.end.line && range2.start.character > range1.end.character)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public provideCodeActions(
|
private hasIntersectingRange(range1: vscode.Range, range2: vscode.Range): boolean {
|
||||||
document: vscode.TextDocument,
|
// Optimize range intersection check
|
||||||
range: vscode.Range | vscode.Selection,
|
return !(
|
||||||
context: vscode.CodeActionContext
|
range2.end.line < range1.start.line ||
|
||||||
): vscode.ProviderResult<(vscode.CodeAction | vscode.Command)[]> {
|
range2.start.line > range1.end.line ||
|
||||||
try {
|
(range2.end.line === range1.start.line && range2.end.character < range1.start.character) ||
|
||||||
const effectiveRange = this.getEffectiveRange(document, range);
|
(range2.start.line === range1.end.line && range2.start.character > range1.end.character)
|
||||||
if (!effectiveRange) {
|
)
|
||||||
return [];
|
}
|
||||||
}
|
|
||||||
|
|
||||||
const filePath = this.getFilePath(document);
|
public provideCodeActions(
|
||||||
const actions: vscode.CodeAction[] = [];
|
document: vscode.TextDocument,
|
||||||
|
range: vscode.Range | vscode.Selection,
|
||||||
|
context: vscode.CodeActionContext,
|
||||||
|
): vscode.ProviderResult<(vscode.CodeAction | vscode.Command)[]> {
|
||||||
|
try {
|
||||||
|
const effectiveRange = this.getEffectiveRange(document, range)
|
||||||
|
if (!effectiveRange) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
|
||||||
// Create actions using helper method
|
const filePath = this.getFilePath(document)
|
||||||
actions.push(this.createAction(
|
const actions: vscode.CodeAction[] = []
|
||||||
ACTION_NAMES.EXPLAIN,
|
|
||||||
vscode.CodeActionKind.QuickFix,
|
|
||||||
COMMAND_IDS.EXPLAIN,
|
|
||||||
[filePath, effectiveRange.text]
|
|
||||||
));
|
|
||||||
|
|
||||||
// Only process diagnostics if they exist
|
// Create actions using helper method
|
||||||
if (context.diagnostics.length > 0) {
|
actions.push(
|
||||||
const relevantDiagnostics = context.diagnostics.filter(d =>
|
this.createAction(ACTION_NAMES.EXPLAIN, vscode.CodeActionKind.QuickFix, COMMAND_IDS.EXPLAIN, [
|
||||||
this.hasIntersectingRange(effectiveRange.range, d.range)
|
filePath,
|
||||||
);
|
effectiveRange.text,
|
||||||
|
]),
|
||||||
|
)
|
||||||
|
|
||||||
if (relevantDiagnostics.length > 0) {
|
// Only process diagnostics if they exist
|
||||||
const diagnosticMessages = relevantDiagnostics.map(this.createDiagnosticData);
|
if (context.diagnostics.length > 0) {
|
||||||
actions.push(this.createAction(
|
const relevantDiagnostics = context.diagnostics.filter((d) =>
|
||||||
ACTION_NAMES.FIX,
|
this.hasIntersectingRange(effectiveRange.range, d.range),
|
||||||
vscode.CodeActionKind.QuickFix,
|
)
|
||||||
COMMAND_IDS.FIX,
|
|
||||||
[filePath, effectiveRange.text, diagnosticMessages]
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
actions.push(this.createAction(
|
if (relevantDiagnostics.length > 0) {
|
||||||
ACTION_NAMES.IMPROVE,
|
const diagnosticMessages = relevantDiagnostics.map(this.createDiagnosticData)
|
||||||
vscode.CodeActionKind.RefactorRewrite,
|
actions.push(
|
||||||
COMMAND_IDS.IMPROVE,
|
this.createAction(ACTION_NAMES.FIX, vscode.CodeActionKind.QuickFix, COMMAND_IDS.FIX, [
|
||||||
[filePath, effectiveRange.text]
|
filePath,
|
||||||
));
|
effectiveRange.text,
|
||||||
|
diagnosticMessages,
|
||||||
|
]),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return actions;
|
actions.push(
|
||||||
} catch (error) {
|
this.createAction(ACTION_NAMES.IMPROVE, vscode.CodeActionKind.RefactorRewrite, COMMAND_IDS.IMPROVE, [
|
||||||
console.error('Error providing code actions:', error);
|
filePath,
|
||||||
return [];
|
effectiveRange.text,
|
||||||
}
|
]),
|
||||||
}
|
)
|
||||||
}
|
|
||||||
|
return actions
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error providing code actions:", error)
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,145 +1,147 @@
|
|||||||
import * as vscode from 'vscode';
|
import * as vscode from "vscode"
|
||||||
import { CodeActionProvider } from '../CodeActionProvider';
|
import { CodeActionProvider } from "../CodeActionProvider"
|
||||||
|
|
||||||
// Mock VSCode API
|
// Mock VSCode API
|
||||||
jest.mock('vscode', () => ({
|
jest.mock("vscode", () => ({
|
||||||
CodeAction: jest.fn().mockImplementation((title, kind) => ({
|
CodeAction: jest.fn().mockImplementation((title, kind) => ({
|
||||||
title,
|
title,
|
||||||
kind,
|
kind,
|
||||||
command: undefined
|
command: undefined,
|
||||||
})),
|
})),
|
||||||
CodeActionKind: {
|
CodeActionKind: {
|
||||||
QuickFix: { value: 'quickfix' },
|
QuickFix: { value: "quickfix" },
|
||||||
RefactorRewrite: { value: 'refactor.rewrite' }
|
RefactorRewrite: { value: "refactor.rewrite" },
|
||||||
},
|
},
|
||||||
Range: jest.fn().mockImplementation((startLine, startChar, endLine, endChar) => ({
|
Range: jest.fn().mockImplementation((startLine, startChar, endLine, endChar) => ({
|
||||||
start: { line: startLine, character: startChar },
|
start: { line: startLine, character: startChar },
|
||||||
end: { line: endLine, character: endChar }
|
end: { line: endLine, character: endChar },
|
||||||
})),
|
})),
|
||||||
Position: jest.fn().mockImplementation((line, character) => ({
|
Position: jest.fn().mockImplementation((line, character) => ({
|
||||||
line,
|
line,
|
||||||
character
|
character,
|
||||||
})),
|
})),
|
||||||
workspace: {
|
workspace: {
|
||||||
getWorkspaceFolder: jest.fn()
|
getWorkspaceFolder: jest.fn(),
|
||||||
},
|
},
|
||||||
DiagnosticSeverity: {
|
DiagnosticSeverity: {
|
||||||
Error: 0,
|
Error: 0,
|
||||||
Warning: 1,
|
Warning: 1,
|
||||||
Information: 2,
|
Information: 2,
|
||||||
Hint: 3
|
Hint: 3,
|
||||||
}
|
},
|
||||||
}));
|
}))
|
||||||
|
|
||||||
describe('CodeActionProvider', () => {
|
describe("CodeActionProvider", () => {
|
||||||
let provider: CodeActionProvider;
|
let provider: CodeActionProvider
|
||||||
let mockDocument: any;
|
let mockDocument: any
|
||||||
let mockRange: any;
|
let mockRange: any
|
||||||
let mockContext: any;
|
let mockContext: any
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
provider = new CodeActionProvider();
|
provider = new CodeActionProvider()
|
||||||
|
|
||||||
// Mock document
|
|
||||||
mockDocument = {
|
|
||||||
getText: jest.fn(),
|
|
||||||
lineAt: jest.fn(),
|
|
||||||
lineCount: 10,
|
|
||||||
uri: { fsPath: '/test/file.ts' }
|
|
||||||
};
|
|
||||||
|
|
||||||
// Mock range
|
// Mock document
|
||||||
mockRange = new vscode.Range(0, 0, 0, 10);
|
mockDocument = {
|
||||||
|
getText: jest.fn(),
|
||||||
|
lineAt: jest.fn(),
|
||||||
|
lineCount: 10,
|
||||||
|
uri: { fsPath: "/test/file.ts" },
|
||||||
|
}
|
||||||
|
|
||||||
// Mock context
|
// Mock range
|
||||||
mockContext = {
|
mockRange = new vscode.Range(0, 0, 0, 10)
|
||||||
diagnostics: []
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('getEffectiveRange', () => {
|
// Mock context
|
||||||
it('should return selected text when available', () => {
|
mockContext = {
|
||||||
mockDocument.getText.mockReturnValue('selected text');
|
diagnostics: [],
|
||||||
|
}
|
||||||
const result = (provider as any).getEffectiveRange(mockDocument, mockRange);
|
})
|
||||||
|
|
||||||
expect(result).toEqual({
|
|
||||||
range: mockRange,
|
|
||||||
text: 'selected text'
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return null for empty line', () => {
|
describe("getEffectiveRange", () => {
|
||||||
mockDocument.getText.mockReturnValue('');
|
it("should return selected text when available", () => {
|
||||||
mockDocument.lineAt.mockReturnValue({ text: '', lineNumber: 0 });
|
mockDocument.getText.mockReturnValue("selected text")
|
||||||
|
|
||||||
const result = (provider as any).getEffectiveRange(mockDocument, mockRange);
|
|
||||||
|
|
||||||
expect(result).toBeNull();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('getFilePath', () => {
|
const result = (provider as any).getEffectiveRange(mockDocument, mockRange)
|
||||||
it('should return relative path when in workspace', () => {
|
|
||||||
const mockWorkspaceFolder = {
|
|
||||||
uri: { fsPath: '/test' }
|
|
||||||
};
|
|
||||||
(vscode.workspace.getWorkspaceFolder as jest.Mock).mockReturnValue(mockWorkspaceFolder);
|
|
||||||
|
|
||||||
const result = (provider as any).getFilePath(mockDocument);
|
|
||||||
|
|
||||||
expect(result).toBe('file.ts');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return absolute path when not in workspace', () => {
|
expect(result).toEqual({
|
||||||
(vscode.workspace.getWorkspaceFolder as jest.Mock).mockReturnValue(null);
|
range: mockRange,
|
||||||
|
text: "selected text",
|
||||||
const result = (provider as any).getFilePath(mockDocument);
|
})
|
||||||
|
})
|
||||||
expect(result).toBe('/test/file.ts');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('provideCodeActions', () => {
|
it("should return null for empty line", () => {
|
||||||
beforeEach(() => {
|
mockDocument.getText.mockReturnValue("")
|
||||||
mockDocument.getText.mockReturnValue('test code');
|
mockDocument.lineAt.mockReturnValue({ text: "", lineNumber: 0 })
|
||||||
mockDocument.lineAt.mockReturnValue({ text: 'test code', lineNumber: 0 });
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should provide explain and improve actions by default', () => {
|
const result = (provider as any).getEffectiveRange(mockDocument, mockRange)
|
||||||
const actions = provider.provideCodeActions(mockDocument, mockRange, mockContext);
|
|
||||||
|
|
||||||
expect(actions).toHaveLength(2);
|
|
||||||
expect((actions as any)[0].title).toBe('Roo Cline: Explain Code');
|
|
||||||
expect((actions as any)[1].title).toBe('Roo Cline: Improve Code');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should provide fix action when diagnostics exist', () => {
|
expect(result).toBeNull()
|
||||||
mockContext.diagnostics = [{
|
})
|
||||||
message: 'test error',
|
})
|
||||||
severity: vscode.DiagnosticSeverity.Error,
|
|
||||||
range: mockRange
|
|
||||||
}];
|
|
||||||
|
|
||||||
const actions = provider.provideCodeActions(mockDocument, mockRange, mockContext);
|
|
||||||
|
|
||||||
expect(actions).toHaveLength(3);
|
|
||||||
expect((actions as any).some((a: any) => a.title === 'Roo Cline: Fix Code')).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should handle errors gracefully', () => {
|
describe("getFilePath", () => {
|
||||||
const consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
|
it("should return relative path when in workspace", () => {
|
||||||
mockDocument.getText.mockImplementation(() => {
|
const mockWorkspaceFolder = {
|
||||||
throw new Error('Test error');
|
uri: { fsPath: "/test" },
|
||||||
});
|
}
|
||||||
mockDocument.lineAt.mockReturnValue({ text: 'test', lineNumber: 0 });
|
;(vscode.workspace.getWorkspaceFolder as jest.Mock).mockReturnValue(mockWorkspaceFolder)
|
||||||
|
|
||||||
const actions = provider.provideCodeActions(mockDocument, mockRange, mockContext);
|
const result = (provider as any).getFilePath(mockDocument)
|
||||||
|
|
||||||
expect(actions).toEqual([]);
|
expect(result).toBe("file.ts")
|
||||||
expect(consoleErrorSpy).toHaveBeenCalledWith('Error getting effective range:', expect.any(Error));
|
})
|
||||||
|
|
||||||
consoleErrorSpy.mockRestore();
|
it("should return absolute path when not in workspace", () => {
|
||||||
});
|
;(vscode.workspace.getWorkspaceFolder as jest.Mock).mockReturnValue(null)
|
||||||
});
|
|
||||||
});
|
const result = (provider as any).getFilePath(mockDocument)
|
||||||
|
|
||||||
|
expect(result).toBe("/test/file.ts")
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("provideCodeActions", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
mockDocument.getText.mockReturnValue("test code")
|
||||||
|
mockDocument.lineAt.mockReturnValue({ text: "test code", lineNumber: 0 })
|
||||||
|
})
|
||||||
|
|
||||||
|
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")
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should provide fix action when diagnostics exist", () => {
|
||||||
|
mockContext.diagnostics = [
|
||||||
|
{
|
||||||
|
message: "test error",
|
||||||
|
severity: vscode.DiagnosticSeverity.Error,
|
||||||
|
range: mockRange,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
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)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should handle errors gracefully", () => {
|
||||||
|
const consoleErrorSpy = jest.spyOn(console, "error").mockImplementation(() => {})
|
||||||
|
mockDocument.getText.mockImplementation(() => {
|
||||||
|
throw new Error("Test error")
|
||||||
|
})
|
||||||
|
mockDocument.lineAt.mockReturnValue({ text: "test", lineNumber: 0 })
|
||||||
|
|
||||||
|
const actions = provider.provideCodeActions(mockDocument, mockRange, mockContext)
|
||||||
|
|
||||||
|
expect(actions).toEqual([])
|
||||||
|
expect(consoleErrorSpy).toHaveBeenCalledWith("Error getting effective range:", expect.any(Error))
|
||||||
|
|
||||||
|
consoleErrorSpy.mockRestore()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|||||||
@@ -201,7 +201,7 @@ export function activate(context: vscode.ExtensionContext) {
|
|||||||
context,
|
context,
|
||||||
"roo-cline.explainCode",
|
"roo-cline.explainCode",
|
||||||
"EXPLAIN",
|
"EXPLAIN",
|
||||||
"Any specific questions about this code?",
|
"What would you like Roo to explain?",
|
||||||
"E.g. How does the error handling work?",
|
"E.g. How does the error handling work?",
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -209,7 +209,7 @@ export function activate(context: vscode.ExtensionContext) {
|
|||||||
context,
|
context,
|
||||||
"roo-cline.fixCode",
|
"roo-cline.fixCode",
|
||||||
"FIX",
|
"FIX",
|
||||||
"Any specific concerns about fixing this code?",
|
"What would you like Roo to fix?",
|
||||||
"E.g. Maintain backward compatibility",
|
"E.g. Maintain backward compatibility",
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -217,7 +217,7 @@ export function activate(context: vscode.ExtensionContext) {
|
|||||||
context,
|
context,
|
||||||
"roo-cline.improveCode",
|
"roo-cline.improveCode",
|
||||||
"IMPROVE",
|
"IMPROVE",
|
||||||
"Any specific aspects you want to improve?",
|
"What would you like Roo to improve?",
|
||||||
"E.g. Focus on performance optimization",
|
"E.g. Focus on performance optimization",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ const dotenv = require("dotenv")
|
|||||||
const testEnvPath = path.join(__dirname, ".test_env")
|
const testEnvPath = path.join(__dirname, ".test_env")
|
||||||
dotenv.config({ path: testEnvPath })
|
dotenv.config({ path: testEnvPath })
|
||||||
|
|
||||||
suite("Roo Cline Extension Test Suite", () => {
|
suite("Roo Code Extension Test Suite", () => {
|
||||||
vscode.window.showInformationMessage("Starting Roo Cline extension tests.")
|
vscode.window.showInformationMessage("Starting Roo Code extension tests.")
|
||||||
|
|
||||||
test("Extension should be present", () => {
|
test("Extension should be present", () => {
|
||||||
const extension = vscode.extensions.getExtension("RooVeterinaryInc.roo-cline")
|
const extension = vscode.extensions.getExtension("RooVeterinaryInc.roo-cline")
|
||||||
@@ -117,16 +117,16 @@ suite("Roo Cline Extension Test Suite", () => {
|
|||||||
|
|
||||||
// Test core commands are registered
|
// Test core commands are registered
|
||||||
const expectedCommands = [
|
const expectedCommands = [
|
||||||
'roo-cline.plusButtonClicked',
|
"roo-cline.plusButtonClicked",
|
||||||
'roo-cline.mcpButtonClicked',
|
"roo-cline.mcpButtonClicked",
|
||||||
'roo-cline.historyButtonClicked',
|
"roo-cline.historyButtonClicked",
|
||||||
'roo-cline.popoutButtonClicked',
|
"roo-cline.popoutButtonClicked",
|
||||||
'roo-cline.settingsButtonClicked',
|
"roo-cline.settingsButtonClicked",
|
||||||
'roo-cline.openInNewTab',
|
"roo-cline.openInNewTab",
|
||||||
'roo-cline.explainCode',
|
"roo-cline.explainCode",
|
||||||
'roo-cline.fixCode',
|
"roo-cline.fixCode",
|
||||||
'roo-cline.improveCode'
|
"roo-cline.improveCode",
|
||||||
];
|
]
|
||||||
|
|
||||||
for (const cmd of expectedCommands) {
|
for (const cmd of expectedCommands) {
|
||||||
assert.strictEqual(commands.includes(cmd), true, `Command ${cmd} should be registered`)
|
assert.strictEqual(commands.includes(cmd), true, `Command ${cmd} should be registered`)
|
||||||
@@ -136,7 +136,7 @@ suite("Roo Cline Extension Test Suite", () => {
|
|||||||
test("Views should be registered", () => {
|
test("Views should be registered", () => {
|
||||||
const view = vscode.window.createWebviewPanel(
|
const view = vscode.window.createWebviewPanel(
|
||||||
"roo-cline.SidebarProvider",
|
"roo-cline.SidebarProvider",
|
||||||
"Roo Cline",
|
"Roo Code",
|
||||||
vscode.ViewColumn.One,
|
vscode.ViewColumn.One,
|
||||||
{},
|
{},
|
||||||
)
|
)
|
||||||
@@ -184,17 +184,12 @@ suite("Roo Cline Extension Test Suite", () => {
|
|||||||
|
|
||||||
// Create webview panel with development options
|
// Create webview panel with development options
|
||||||
const extensionUri = extension.extensionUri
|
const extensionUri = extension.extensionUri
|
||||||
const panel = vscode.window.createWebviewPanel(
|
const panel = vscode.window.createWebviewPanel("roo-cline.SidebarProvider", "Roo Code", vscode.ViewColumn.One, {
|
||||||
"roo-cline.SidebarProvider",
|
enableScripts: true,
|
||||||
"Roo Cline",
|
enableCommandUris: true,
|
||||||
vscode.ViewColumn.One,
|
retainContextWhenHidden: true,
|
||||||
{
|
localResourceRoots: [extensionUri],
|
||||||
enableScripts: true,
|
})
|
||||||
enableCommandUris: true,
|
|
||||||
retainContextWhenHidden: true,
|
|
||||||
localResourceRoots: [extensionUri],
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Initialize webview with development context
|
// Initialize webview with development context
|
||||||
|
|||||||
Reference in New Issue
Block a user