diff options
Diffstat (limited to 'extension/react-app/src/util')
-rw-r--r-- | extension/react-app/src/util/api.ts | 43 | ||||
-rw-r--r-- | extension/react-app/src/util/editCache.ts | 89 | ||||
-rw-r--r-- | extension/react-app/src/util/index.ts | 27 |
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"); + } + } +} |