feat: AI-Powered Quick Fix Integration
- Implemented a new Quick Fix command in commands.ts and package.json - Added the collapseFileExcludeSelectRange function for code analysis - Registered the Quick Fix provider to suggest fixes via AI analysis
This commit is contained in:
parent
af730793bd
commit
d50aa4b1b4
@ -734,6 +734,11 @@
|
||||
"command": "DevChat.codecomplete_callback",
|
||||
"title": "Codecomplete Callback",
|
||||
"category": "DevChat"
|
||||
},
|
||||
{
|
||||
"command": "DevChat.quickFix",
|
||||
"title": "DevChat Quick Fix",
|
||||
"category": "DevChat"
|
||||
}
|
||||
],
|
||||
"keybindings": [
|
||||
@ -788,6 +793,10 @@
|
||||
{
|
||||
"command": "DevChat.Chat",
|
||||
"when": "false"
|
||||
},
|
||||
{
|
||||
"command": "DevChat.quickFix",
|
||||
"when": "false"
|
||||
}
|
||||
],
|
||||
"explorer/context": [
|
||||
|
@ -69,3 +69,88 @@ export async function collapseFile(
|
||||
|
||||
return lines.join("\n");
|
||||
}
|
||||
|
||||
|
||||
export async function collapseFileExculdeSelectRange(
|
||||
filepath: string,
|
||||
contents: string,
|
||||
startRow: number,
|
||||
endRow: number) : Promise< string > {
|
||||
const ast = await getAst(filepath, contents);
|
||||
if (!ast) {
|
||||
return "";
|
||||
}
|
||||
|
||||
const functionRanges = await findFunctionRanges(filepath, ast.rootNode);
|
||||
return await collapseAllCodeBlockExculdeSelectRange(functionRanges, filepath, contents, startRow, endRow);
|
||||
}
|
||||
|
||||
export async function collapseAllCodeBlockExculdeSelectRange(
|
||||
functions: FunctionRange[],
|
||||
filepath: string,
|
||||
contents: string,
|
||||
startRow: number,
|
||||
endRow: number) {
|
||||
const commentPrefix = await getCommentPrefix(filepath);
|
||||
const lines = contents.split("\n");
|
||||
|
||||
let disableCollapseRanges: FunctionRange[] = [];
|
||||
for (const func of functions) {
|
||||
if (func.define.start.row > endRow || func.define.end.row < startRow) {
|
||||
continue;
|
||||
}
|
||||
|
||||
disableCollapseRanges.push(func);
|
||||
}
|
||||
|
||||
// visit functions in reverse order
|
||||
for (const func of functions.reverse()) {
|
||||
const funcDefine = func.define;
|
||||
const funcBody = func.body;
|
||||
|
||||
if (funcBody.start === funcBody.end) {
|
||||
continue;
|
||||
}
|
||||
if (func.name === "__init__" || func.name === "constructor") {
|
||||
continue;
|
||||
}
|
||||
|
||||
let bodyStartLine = funcBody.start.row;
|
||||
let bodyEndLine = funcBody.end.row;
|
||||
if (funcDefine.start.row === funcBody.start.row) {
|
||||
bodyStartLine = funcBody.start.row + 1;
|
||||
bodyEndLine = funcBody.end.row - 1;
|
||||
}
|
||||
// whether line before body start column is empty
|
||||
const lineBeforeBodyStart = lines[funcBody.start.row].slice(0, funcBody.start.column);
|
||||
if (lineBeforeBodyStart.trim() !== "") {
|
||||
bodyStartLine = funcBody.start.row + 1;
|
||||
bodyEndLine = funcBody.end.row - 1;
|
||||
}
|
||||
|
||||
if (bodyEndLine - bodyStartLine <= 3) {
|
||||
continue;
|
||||
}
|
||||
let inDisableRange = false;
|
||||
for (const disableRange of disableCollapseRanges) {
|
||||
if (funcDefine === disableRange.define) {
|
||||
inDisableRange = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (inDisableRange) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// replace lines from bodyStartLine to bodyEndLine with "..."
|
||||
// 获取bodyStartLine这一行的缩进字符,需要在"..."之前添加对应的缩进
|
||||
let indent = lines[bodyStartLine].search(/\S/);
|
||||
if (indent === -1) {
|
||||
indent = lines[bodyStartLine].length;
|
||||
}
|
||||
const indentStr = " ".repeat(indent);
|
||||
lines.splice(bodyStartLine, bodyEndLine - bodyStartLine + 1, `${indentStr}${commentPrefix}Code omitted...`);
|
||||
}
|
||||
|
||||
return lines.join("\n");
|
||||
}
|
@ -422,3 +422,25 @@ export function registerFixCommand(context: vscode.ExtensionContext) {
|
||||
vscode.commands.registerCommand("devchat.fix_chinese", callback)
|
||||
);
|
||||
}
|
||||
|
||||
export function registerQuickFixCommand(context: vscode.ExtensionContext) {
|
||||
let disposable = vscode.commands.registerCommand(
|
||||
"DevChat.quickFix",
|
||||
async (diagnosticMessage: string, code: string, surroundingCode: string) => {
|
||||
ensureChatPanel(context);
|
||||
if (!ExtensionContextHolder.provider?.view()) {
|
||||
// wait 2 seconds
|
||||
await new Promise((resolve, reject) => {
|
||||
setTimeout(() => {
|
||||
resolve(true);
|
||||
}, 2000);
|
||||
});
|
||||
}
|
||||
|
||||
const prompt = `current edit file is:\n\`\`\`\n${code}\n\`\`\`\n\nThere is an error in the above code:\n\`\`\`\n${surroundingCode}\n\`\`\`\n\nHow do I fix this problem in the above code?: ${diagnosticMessage}`;
|
||||
chatWithDevChat(ExtensionContextHolder.provider?.view()!, prompt);
|
||||
}
|
||||
);
|
||||
|
||||
context.subscriptions.push(disposable);
|
||||
}
|
60
src/contributes/quickFixProvider.ts
Normal file
60
src/contributes/quickFixProvider.ts
Normal file
@ -0,0 +1,60 @@
|
||||
import * as vscode from "vscode";
|
||||
import { collapseFileExculdeSelectRange } from "./codecomplete/ast/collapseBlock";
|
||||
|
||||
class DevChatQuickFixProvider implements vscode.CodeActionProvider {
|
||||
public static readonly providedCodeActionKinds = [
|
||||
vscode.CodeActionKind.QuickFix,
|
||||
];
|
||||
|
||||
provideCodeActions(
|
||||
document: vscode.TextDocument,
|
||||
range: vscode.Range | vscode.Selection,
|
||||
context: vscode.CodeActionContext,
|
||||
token: vscode.CancellationToken,
|
||||
): vscode.ProviderResult<(vscode.Command | vscode.CodeAction)[]> {
|
||||
if (context.diagnostics.length === 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const diagnostic = context.diagnostics[0];
|
||||
const quickFix = new vscode.CodeAction(
|
||||
"Ask DevChat",
|
||||
vscode.CodeActionKind.QuickFix,
|
||||
);
|
||||
quickFix.isPreferred = false;
|
||||
|
||||
return new Promise(async (resolve) => {
|
||||
const code = await collapseFileExculdeSelectRange(document.uri.fsPath, document.getText(), range.start.line, range.end.line);
|
||||
|
||||
const surroundingRange = new vscode.Range(
|
||||
Math.max(0, range.start.line - 3),
|
||||
0,
|
||||
Math.min(document.lineCount, range.end.line + 3),
|
||||
0,
|
||||
);
|
||||
|
||||
quickFix.command = {
|
||||
command: "DevChat.quickFix",
|
||||
title: "DevChat Quick Fix",
|
||||
arguments: [
|
||||
diagnostic.message,
|
||||
code,
|
||||
document.getText(surroundingRange)
|
||||
],
|
||||
};
|
||||
|
||||
resolve([quickFix]);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export default function registerQuickFixProvider() {
|
||||
vscode.languages.registerCodeActionsProvider(
|
||||
{ language: "*" },
|
||||
new DevChatQuickFixProvider(),
|
||||
{
|
||||
providedCodeActionKinds: DevChatQuickFixProvider.providedCodeActionKinds,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
@ -16,7 +16,7 @@ import {
|
||||
registerCommentCommand,
|
||||
registerFixCommand,
|
||||
registerExplainCommand,
|
||||
|
||||
registerQuickFixCommand,
|
||||
} from './contributes/commands';
|
||||
import { regLanguageContext } from './contributes/context';
|
||||
import { regDevChatView } from './contributes/views';
|
||||
@ -33,6 +33,7 @@ import { stopDevChatBase } from './handler/sendMessageBase';
|
||||
import { DevChatConfig } from './util/config';
|
||||
import { InlineCompletionProvider, registerCodeCompleteCallbackCommand } from "./contributes/codecomplete/codecomplete";
|
||||
import { indexDir } from "./contributes/codecomplete/astIndex";
|
||||
import registerQuickFixProvider from "./contributes/quickFixProvider";
|
||||
|
||||
|
||||
async function migrateConfig() {
|
||||
@ -159,10 +160,12 @@ async function activate(context: vscode.ExtensionContext) {
|
||||
registerDevChatChatCommand(context);
|
||||
registerCodeLensRangeCommand(context);
|
||||
registerCodeLensProvider(context);
|
||||
registerQuickFixCommand(context);
|
||||
|
||||
startRpcServer();
|
||||
logger.channel()?.info(`registerHandleUri:`);
|
||||
registerHandleUri(context);
|
||||
registerQuickFixProvider();
|
||||
|
||||
const workspaceDir = UiUtilWrapper.workspaceFoldersFirstPath();
|
||||
if (workspaceDir) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user