summaryrefslogtreecommitdiff
path: root/extension/src/debugPanel.ts
diff options
context:
space:
mode:
authorNate Sesti <sestinj@gmail.com>2023-05-23 23:45:12 -0400
committerNate Sesti <sestinj@gmail.com>2023-05-23 23:45:12 -0400
commitf53768612b1e2268697b5444e502032ef9f3fb3c (patch)
tree4ed49b73e6bd3c2f8fceffa9643973033f87af95 /extension/src/debugPanel.ts
downloadsncontinue-f53768612b1e2268697b5444e502032ef9f3fb3c.tar.gz
sncontinue-f53768612b1e2268697b5444e502032ef9f3fb3c.tar.bz2
sncontinue-f53768612b1e2268697b5444e502032ef9f3fb3c.zip
copying from old repo
Diffstat (limited to 'extension/src/debugPanel.ts')
-rw-r--r--extension/src/debugPanel.ts378
1 files changed, 378 insertions, 0 deletions
diff --git a/extension/src/debugPanel.ts b/extension/src/debugPanel.ts
new file mode 100644
index 00000000..66829836
--- /dev/null
+++ b/extension/src/debugPanel.ts
@@ -0,0 +1,378 @@
+import * as vscode from "vscode";
+import {
+ debugApi,
+ getContinueServerUrl,
+ runPythonScript,
+ unittestApi,
+} from "./bridge";
+import { writeAndShowUnitTest } from "./decorations";
+import { showSuggestion } from "./suggestions";
+import { getLanguageLibrary } from "./languages";
+import {
+ getExtensionUri,
+ getNonce,
+ openEditorAndRevealRange,
+} from "./util/vscode";
+import { sendTelemetryEvent, TelemetryEvent } from "./telemetry";
+import { RangeInFile, SerializedDebugContext } from "./client";
+import { addFileSystemToDebugContext } from "./util/util";
+
+class StreamManager {
+ private _fullText: string = "";
+ private _insertionPoint: vscode.Position | undefined;
+
+ private _addToEditor(update: string) {
+ let editor =
+ vscode.window.activeTextEditor || vscode.window.visibleTextEditors[0];
+
+ if (typeof this._insertionPoint === "undefined") {
+ if (editor?.selection.isEmpty) {
+ this._insertionPoint = editor?.selection.active;
+ } else {
+ this._insertionPoint = editor?.selection.end;
+ }
+ }
+ editor?.edit((editBuilder) => {
+ if (this._insertionPoint) {
+ editBuilder.insert(this._insertionPoint, update);
+ this._insertionPoint = this._insertionPoint.translate(
+ Array.from(update.matchAll(/\n/g)).length,
+ update.length
+ );
+ }
+ });
+ }
+
+ public closeStream() {
+ this._fullText = "";
+ this._insertionPoint = undefined;
+ this._codeBlockStatus = "closed";
+ this._pendingBackticks = 0;
+ }
+
+ private _codeBlockStatus: "open" | "closed" | "language-descriptor" =
+ "closed";
+ private _pendingBackticks: number = 0;
+ public onStreamUpdate(update: string) {
+ let textToInsert = "";
+ for (let i = 0; i < update.length; i++) {
+ switch (this._codeBlockStatus) {
+ case "closed":
+ if (update[i] === "`" && this._fullText.endsWith("``")) {
+ this._codeBlockStatus = "language-descriptor";
+ }
+ break;
+ case "language-descriptor":
+ if (update[i] === " " || update[i] === "\n") {
+ this._codeBlockStatus = "open";
+ }
+ break;
+ case "open":
+ if (update[i] === "`") {
+ if (this._fullText.endsWith("``")) {
+ this._codeBlockStatus = "closed";
+ this._pendingBackticks = 0;
+ } else {
+ this._pendingBackticks += 1;
+ }
+ } else {
+ textToInsert += "`".repeat(this._pendingBackticks) + update[i];
+ this._pendingBackticks = 0;
+ }
+ break;
+ }
+ this._fullText += update[i];
+ }
+ this._addToEditor(textToInsert);
+ }
+}
+
+let streamManager = new StreamManager();
+
+export let debugPanelWebview: vscode.Webview | undefined;
+export function setupDebugPanel(
+ panel: vscode.WebviewPanel,
+ context: vscode.ExtensionContext | undefined,
+ sessionId: string
+): string {
+ debugPanelWebview = panel.webview;
+ panel.onDidDispose(() => {
+ debugPanelWebview = undefined;
+ });
+
+ let extensionUri = getExtensionUri();
+ let scriptUri: string;
+ let styleMainUri: string;
+
+ const isProduction = true; // context?.extensionMode === vscode.ExtensionMode.Development;
+ if (!isProduction) {
+ scriptUri = "http://localhost:5173/src/main.tsx";
+ styleMainUri = "http://localhost:5173/src/main.css";
+ } else {
+ scriptUri = debugPanelWebview
+ .asWebviewUri(
+ vscode.Uri.joinPath(extensionUri, "react-app/dist/assets/index.js")
+ )
+ .toString();
+ styleMainUri = debugPanelWebview
+ .asWebviewUri(
+ vscode.Uri.joinPath(extensionUri, "react-app/dist/assets/index.css")
+ )
+ .toString();
+ }
+
+ const nonce = getNonce();
+
+ vscode.window.onDidChangeTextEditorSelection((e) => {
+ if (e.selections[0].isEmpty) {
+ return;
+ }
+
+ let rangeInFile: RangeInFile = {
+ range: e.selections[0],
+ filepath: e.textEditor.document.fileName,
+ };
+ let filesystem = {
+ [rangeInFile.filepath]: e.textEditor.document.getText(),
+ };
+ panel.webview.postMessage({
+ type: "highlightedCode",
+ rangeInFile,
+ filesystem,
+ });
+
+ panel.webview.postMessage({
+ type: "workspacePath",
+ value: vscode.workspace.workspaceFolders?.[0].uri.fsPath,
+ });
+ });
+
+ panel.webview.onDidReceiveMessage(async (data) => {
+ switch (data.type) {
+ case "onLoad": {
+ panel.webview.postMessage({
+ type: "onLoad",
+ vscMachineId: vscode.env.machineId,
+ apiUrl: getContinueServerUrl(),
+ sessionId,
+ });
+ break;
+ }
+ case "listTenThings": {
+ sendTelemetryEvent(TelemetryEvent.GenerateIdeas);
+ let resp = await debugApi.listtenDebugListPost({
+ serializedDebugContext: data.debugContext,
+ });
+ panel.webview.postMessage({
+ type: "listTenThings",
+ value: resp.completion,
+ });
+ break;
+ }
+ case "suggestFix": {
+ let completion: string;
+ let codeSelection = data.debugContext.rangesInFiles?.at(0);
+ if (codeSelection) {
+ completion = (
+ await debugApi.inlineDebugInlinePost({
+ inlineBody: {
+ filecontents: await vscode.workspace.fs
+ .readFile(vscode.Uri.file(codeSelection.filepath))
+ .toString(),
+ startline: codeSelection.range.start.line,
+ endline: codeSelection.range.end.line,
+ traceback: data.debugContext.traceback,
+ },
+ })
+ ).completion;
+ } else if (data.debugContext.traceback) {
+ completion = (
+ await debugApi.suggestionDebugSuggestionGet({
+ traceback: data.debugContext.traceback,
+ })
+ ).completion;
+ } else {
+ break;
+ }
+ panel.webview.postMessage({
+ type: "suggestFix",
+ value: completion,
+ });
+ break;
+ }
+ case "findSuspiciousCode": {
+ let traceback = getLanguageLibrary(".py").parseFirstStacktrace(
+ data.debugContext.traceback
+ );
+ if (traceback === undefined) return;
+ vscode.commands.executeCommand(
+ "continue.findSuspiciousCode",
+ data.debugContext
+ );
+ break;
+ }
+ case "queryEmbeddings": {
+ let { results } = await runPythonScript("index.py query", [
+ data.query,
+ 2,
+ vscode.workspace.workspaceFolders?.[0].uri.fsPath,
+ ]);
+ panel.webview.postMessage({
+ type: "queryEmbeddings",
+ results,
+ });
+ break;
+ }
+ case "openFile": {
+ openEditorAndRevealRange(data.path, undefined, vscode.ViewColumn.One);
+ break;
+ }
+ case "streamUpdate": {
+ // Write code at the position of the cursor
+ streamManager.onStreamUpdate(data.update);
+ break;
+ }
+ case "closeStream": {
+ streamManager.closeStream();
+ break;
+ }
+ case "explainCode": {
+ sendTelemetryEvent(TelemetryEvent.ExplainCode);
+ let debugContext: SerializedDebugContext = addFileSystemToDebugContext(
+ data.debugContext
+ );
+ let resp = await debugApi.explainDebugExplainPost({
+ serializedDebugContext: debugContext,
+ });
+ panel.webview.postMessage({
+ type: "explainCode",
+ value: resp.completion,
+ });
+ break;
+ }
+ case "withProgress": {
+ // This message allows withProgress to be used in the webview
+ if (data.done) {
+ // Will be caught in the listener created below
+ break;
+ }
+ let title = data.title;
+ vscode.window.withProgress(
+ {
+ location: vscode.ProgressLocation.Notification,
+ title,
+ cancellable: false,
+ },
+ async () => {
+ return new Promise<void>((resolve, reject) => {
+ let listener = panel.webview.onDidReceiveMessage(async (data) => {
+ if (
+ data.type === "withProgress" &&
+ data.done &&
+ data.title === title
+ ) {
+ listener.dispose();
+ resolve();
+ }
+ });
+ });
+ }
+ );
+ break;
+ }
+ case "makeEdit": {
+ sendTelemetryEvent(TelemetryEvent.SuggestFix);
+ let suggestedEdits = data.edits;
+
+ if (
+ typeof suggestedEdits === "undefined" ||
+ suggestedEdits.length === 0
+ ) {
+ vscode.window.showInformationMessage(
+ "Continue couldn't find a fix for this error."
+ );
+ return;
+ }
+
+ for (let i = 0; i < suggestedEdits.length; i++) {
+ let edit = suggestedEdits[i];
+ await showSuggestion(
+ edit.filepath,
+ new vscode.Range(
+ edit.range.start.line,
+ edit.range.start.character,
+ edit.range.end.line,
+ edit.range.end.character
+ ),
+ edit.replacement
+ );
+ }
+ break;
+ }
+ case "generateUnitTest": {
+ sendTelemetryEvent(TelemetryEvent.CreateTest);
+ vscode.window.withProgress(
+ {
+ location: vscode.ProgressLocation.Notification,
+ title: "Generating Unit Test...",
+ cancellable: false,
+ },
+ async () => {
+ for (let i = 0; i < data.debugContext.rangesInFiles?.length; i++) {
+ let codeSelection = data.debugContext.rangesInFiles?.at(i);
+ if (
+ codeSelection &&
+ codeSelection.filepath &&
+ codeSelection.range
+ ) {
+ try {
+ let filecontents = (
+ await vscode.workspace.fs.readFile(
+ vscode.Uri.file(codeSelection.filepath)
+ )
+ ).toString();
+ let resp =
+ await unittestApi.failingtestUnittestFailingtestPost({
+ failingTestBody: {
+ fp: {
+ filecontents,
+ lineno: codeSelection.range.end.line,
+ },
+ description: data.debugContext.description || "",
+ },
+ });
+
+ if (resp.completion) {
+ let decorationKey = await writeAndShowUnitTest(
+ codeSelection.filepath,
+ resp.completion
+ );
+ break;
+ }
+ } catch {}
+ }
+ }
+ }
+ );
+
+ break;
+ }
+ }
+ });
+
+ return `<!DOCTYPE html>
+ <html lang="en">
+ <head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <script>const vscode = acquireVsCodeApi();</script>
+ <link href="${styleMainUri}" rel="stylesheet">
+
+ <title>Continue</title>
+ </head>
+ <body>
+ <div id="root"></div>
+ <script type="module" nonce="${nonce}" src="${scriptUri}"></script>
+ </body>
+ </html>`;
+}