summaryrefslogtreecommitdiff
path: root/extension/react-app/src/util
diff options
context:
space:
mode:
Diffstat (limited to 'extension/react-app/src/util')
-rw-r--r--extension/react-app/src/util/api.ts43
-rw-r--r--extension/react-app/src/util/editCache.ts89
-rw-r--r--extension/react-app/src/util/index.ts27
3 files changed, 159 insertions, 0 deletions
diff --git a/extension/react-app/src/util/api.ts b/extension/react-app/src/util/api.ts
new file mode 100644
index 00000000..bdec1d20
--- /dev/null
+++ b/extension/react-app/src/util/api.ts
@@ -0,0 +1,43 @@
+import {
+ Configuration,
+ DebugApi,
+ UnittestApi,
+ ChatApi,
+} from "../../../src/client";
+import { useSelector } from "react-redux";
+import { useEffect, useState } from "react";
+import { RootStore } from "../redux/store";
+
+export function useApi() {
+ const apiUrl = useSelector((state: RootStore) => state.config.apiUrl);
+ const vscMachineId = useSelector(
+ (state: RootStore) => state.config.vscMachineId
+ );
+ const [debugApi, setDebugApi] = useState<DebugApi>();
+ const [unittestApi, setUnittestApi] = useState<UnittestApi>();
+ const [chatApi, setChatApi] = useState<ChatApi>();
+
+ useEffect(() => {
+ if (apiUrl && vscMachineId) {
+ let config = new Configuration({
+ basePath: apiUrl,
+ fetchApi: fetch,
+ middleware: [
+ {
+ pre: async (context) => {
+ context.init.headers = {
+ ...context.init.headers,
+ "x-vsc-machine-id": vscMachineId,
+ };
+ },
+ },
+ ],
+ });
+ setDebugApi(new DebugApi(config));
+ setUnittestApi(new UnittestApi(config));
+ setChatApi(new ChatApi(config));
+ }
+ }, [apiUrl, vscMachineId]);
+
+ return { debugApi, unittestApi, chatApi };
+}
diff --git a/extension/react-app/src/util/editCache.ts b/extension/react-app/src/util/editCache.ts
new file mode 100644
index 00000000..b8071127
--- /dev/null
+++ b/extension/react-app/src/util/editCache.ts
@@ -0,0 +1,89 @@
+import { useApi } from "../util/api";
+import { FileEdit, SerializedDebugContext } from "../../../src/client";
+import { useCallback, useEffect, useState } from "react";
+
+export function useEditCache() {
+ const { debugApi } = useApi();
+
+ const fetchNewEdit = useCallback(
+ async (debugContext: SerializedDebugContext) => {
+ return (
+ await debugApi?.editEndpointDebugEditPost({
+ serializedDebugContext: debugContext,
+ })
+ )?.completion;
+ },
+ [debugApi]
+ );
+
+ const [editCache, setEditCache] = useState(new EditCache(fetchNewEdit));
+
+ useEffect(() => {
+ setEditCache(new EditCache(fetchNewEdit));
+ }, [fetchNewEdit]);
+
+ return editCache;
+}
+
+/**
+ * Stores preloaded edits, invalidating based off of debug context changes
+ */
+class EditCache {
+ private _lastDebugContext: SerializedDebugContext | undefined;
+ private _cachedEdits: FileEdit[] | undefined;
+ private _fetchNewEdit: (
+ debugContext: SerializedDebugContext
+ ) => Promise<FileEdit[] | undefined>;
+ private _debounceTimer: NodeJS.Timeout | undefined;
+
+ private _debugContextChanged(debugContext: SerializedDebugContext): boolean {
+ if (!this._lastDebugContext) {
+ return true;
+ }
+
+ return (
+ JSON.stringify(this._lastDebugContext) !== JSON.stringify(debugContext)
+ );
+ }
+
+ private _debugContextComplete(debugContext: SerializedDebugContext): boolean {
+ return debugContext.rangesInFiles.length > 0;
+ }
+
+ public async preloadEdit(debugContext: SerializedDebugContext) {
+ if (this._debounceTimer) {
+ clearTimeout(this._debounceTimer);
+ }
+ if (
+ this._debugContextComplete(debugContext) &&
+ this._debugContextChanged(debugContext)
+ ) {
+ this._debounceTimer = setTimeout(async () => {
+ console.log("Preloading edits");
+ this._cachedEdits = await this._fetchNewEdit(debugContext);
+ this._lastDebugContext = debugContext;
+ }, 200);
+ }
+ }
+
+ public async getEdit(
+ debugContext: SerializedDebugContext
+ ): Promise<FileEdit[]> {
+ if (this._debugContextChanged(debugContext)) {
+ console.log("Cache miss");
+ this._cachedEdits = await this._fetchNewEdit(debugContext);
+ } else {
+ console.log("Cache hit");
+ }
+
+ return this._cachedEdits!;
+ }
+
+ constructor(
+ fetchNewEdit: (
+ debugContext: SerializedDebugContext
+ ) => Promise<FileEdit[] | undefined>
+ ) {
+ this._fetchNewEdit = fetchNewEdit;
+ }
+}
diff --git a/extension/react-app/src/util/index.ts b/extension/react-app/src/util/index.ts
new file mode 100644
index 00000000..458f9d95
--- /dev/null
+++ b/extension/react-app/src/util/index.ts
@@ -0,0 +1,27 @@
+import { RangeInFile } from "../../../src/client";
+
+export function readRangeInVirtualFileSystem(
+ rangeInFile: RangeInFile,
+ filesystem: { [filepath: string]: string }
+): string | undefined {
+ const range = rangeInFile.range;
+
+ let data = filesystem[rangeInFile.filepath];
+ if (data === undefined) {
+ console.log("File not found");
+ return undefined;
+ } else {
+ let lines = data.toString().split("\n");
+ if (range.start.line === range.end.line) {
+ return lines[rangeInFile.range.start.line].slice(
+ rangeInFile.range.start.character,
+ rangeInFile.range.end.character
+ );
+ } else {
+ let firstLine = lines[range.start.line].slice(range.start.character);
+ let lastLine = lines[range.end.line].slice(0, range.end.character);
+ let middleLines = lines.slice(range.start.line + 1, range.end.line);
+ return [firstLine, ...middleLines, lastLine].join("\n");
+ }
+ }
+}