import * as vscode from "vscode"; import { decorationManager, showAnswerInTextEditor, showGutterSpinner, writeAndShowUnitTest, } from "./decorations"; import { acceptSuggestionCommand, rejectSuggestionCommand, suggestionDownCommand, suggestionUpCommand, } from "./suggestions"; import * as bridge from "./bridge"; import { debugPanelWebview, setupDebugPanel } from "./debugPanel"; // import { openCapturedTerminal } from "./terminal/terminalEmulator"; import { getRightViewColumn } from "./util/vscode"; import { findSuspiciousCode, runPythonScript, writeUnitTestForFunction, } from "./bridge"; import { sendTelemetryEvent, TelemetryEvent } from "./telemetry"; import { getLanguageLibrary } from "./languages"; import { SerializedDebugContext } from "./client"; import { addFileSystemToDebugContext } from "./util/util"; import { ideProtocolClient } from "./activation/activate"; // Copy everything over from extension.ts const commandsMap: { [command: string]: (...args: any) => any } = { "continue.askQuestion": (data: any, webviewView: vscode.WebviewView) => { if (!vscode.workspace.workspaceFolders) { return; } answerQuestion( data.question, vscode.workspace.workspaceFolders[0].uri.fsPath, webviewView.webview ); }, "continue.askQuestionFromInput": () => { vscode.window .showInputBox({ placeHolder: "Ask away!" }) .then((question) => { if (!question || !vscode.workspace.workspaceFolders) { return; } sendTelemetryEvent(TelemetryEvent.UniversalPromptQuery, { query: question, }); answerQuestion( question, vscode.workspace.workspaceFolders[0].uri.fsPath ); }); }, "continue.suggestionDown": suggestionDownCommand, "continue.suggestionUp": suggestionUpCommand, "continue.acceptSuggestion": acceptSuggestionCommand, "continue.rejectSuggestion": rejectSuggestionCommand, "continue.openContinueGUI": () => { ideProtocolClient.openGUI(); }, "continue.focusContinueInput": async () => { if (!debugPanelWebview) { await ideProtocolClient.openGUI(); } debugPanelWebview?.postMessage({ type: "focusContinueInput", }); }, "continue.openCapturedTerminal": () => { // Happens in webview resolution function // openCapturedTerminal(); }, "continue.findSuspiciousCode": async ( debugContext: SerializedDebugContext ) => { vscode.window.withProgress( { location: vscode.ProgressLocation.Notification, title: "Finding suspicious code", cancellable: false, }, async (progress, token) => { let suspiciousCode = await findSuspiciousCode(debugContext); debugContext.rangesInFiles = suspiciousCode; let { filesystem } = addFileSystemToDebugContext(debugContext); debugPanelWebview?.postMessage({ type: "findSuspiciousCode", codeLocations: suspiciousCode, filesystem, }); } ); }, "continue.debugTest": async (fileAndFunctionSpecifier: string) => { sendTelemetryEvent(TelemetryEvent.AutoDebugThisTest); let editor = vscode.window.activeTextEditor; if (editor) editor.document.save(); let { stdout } = await runPythonScript("run_unit_test.py", [ fileAndFunctionSpecifier, ]); let traceback = getLanguageLibrary( fileAndFunctionSpecifier.split("::")[0] ).parseFirstStacktrace(stdout); if (!traceback) { vscode.window.showInformationMessage("The test passes!"); return; } vscode.commands.executeCommand("continue.openContinueGUI").then(() => { setTimeout(() => { debugPanelWebview?.postMessage({ type: "traceback", value: traceback, }); }, 500); }); }, }; const textEditorCommandsMap: { [command: string]: (...args: any) => {} } = { "continue.writeUnitTest": async (editor: vscode.TextEditor) => { let position = editor.selection.active; let gutterSpinnerKey = showGutterSpinner(editor, position.line); try { let test = await writeUnitTestForFunction( editor.document.fileName, position ); writeAndShowUnitTest(editor.document.fileName, test); } catch { } finally { decorationManager.deleteDecoration(gutterSpinnerKey); } }, "continue.writeDocstring": async (editor: vscode.TextEditor, _) => { sendTelemetryEvent(TelemetryEvent.GenerateDocstring); let gutterSpinnerKey = showGutterSpinner( editor, editor.selection.active.line ); const { lineno, docstring } = await bridge.writeDocstringForFunction( editor.document.fileName, editor.selection.active ); // Can't use the edit given above after an async call editor.edit((edit) => { edit.insert(new vscode.Position(lineno, 0), docstring); decorationManager.deleteDecoration(gutterSpinnerKey); }); }, }; export function registerAllCommands(context: vscode.ExtensionContext) { for (const [command, callback] of Object.entries(commandsMap)) { context.subscriptions.push( vscode.commands.registerCommand(command, callback) ); } for (const [command, callback] of Object.entries(textEditorCommandsMap)) { context.subscriptions.push( vscode.commands.registerTextEditorCommand(command, callback) ); } } async function answerQuestion( question: string, workspacePath: string, webview: vscode.Webview | undefined = undefined ) { vscode.window.withProgress( { location: vscode.ProgressLocation.Notification, title: "Anwering question...", cancellable: false, }, async (progress, token) => { try { let resp = await bridge.askQuestion(question, workspacePath); // Send the answer back to the webview if (webview) { webview.postMessage({ type: "answerQuestion", answer: resp.answer, }); } showAnswerInTextEditor(resp.filename, resp.range, resp.answer); } catch (error: any) { if (webview) { webview.postMessage({ type: "answerQuestion", answer: error, }); } } } ); } // async function suggestFixForAllWorkspaceProblems() { // Something like this, just figure out the loops for diagnostics vs problems // let problems = vscode.languages.getDiagnostics(); // let codeSuggestions = await Promise.all(problems.map((problem) => { // return bridge.suggestFixForProblem(problem[0].fsPath, problem[1]); // })); // for (const [uri, diagnostics] of problems) { // for (let i = 0; i < diagnostics.length; i++) { // let diagnostic = diagnostics[i]; // let suggestedCode = codeSuggestions[i]; // // If you're going to do this for a bunch of files at once, it will show the unsaved icon in the tab // // BUT it would be better to have a single window to review all edits // showSuggestion(uri.fsPath, diagnostic.range, suggestedCode) // } // } // }