diff options
author | Nate Sesti <sestinj@gmail.com> | 2023-07-12 13:22:40 -0700 |
---|---|---|
committer | Nate Sesti <sestinj@gmail.com> | 2023-07-12 13:22:40 -0700 |
commit | 93ac6b52c9e5067c9703d096104c99f4f29e8eb5 (patch) | |
tree | 485af72e86415407f11ce0c91390d097eae05bc6 /extension | |
parent | 51f620524cd8d658058b4a07d8e8f8e1b3be49bd (diff) | |
download | sncontinue-93ac6b52c9e5067c9703d096104c99f4f29e8eb5.tar.gz sncontinue-93ac6b52c9e5067c9703d096104c99f4f29e8eb5.tar.bz2 sncontinue-93ac6b52c9e5067c9703d096104c99f4f29e8eb5.zip |
purging unecessary files
Diffstat (limited to 'extension')
-rw-r--r-- | extension/react-app/src/App.tsx | 13 | ||||
-rw-r--r-- | extension/react-app/src/pages/gui.tsx (renamed from extension/react-app/src/tabs/gui.tsx) | 0 | ||||
-rw-r--r-- | extension/react-app/src/tabs/additionalContext.tsx | 18 | ||||
-rw-r--r-- | extension/react-app/src/tabs/chat/MessageDiv.tsx | 75 | ||||
-rw-r--r-- | extension/react-app/src/tabs/chat/index.tsx | 267 | ||||
-rw-r--r-- | extension/react-app/src/tabs/main.tsx | 189 | ||||
-rw-r--r-- | extension/react-app/src/tabs/welcome.tsx | 22 | ||||
-rw-r--r-- | extension/src/bridge.ts | 215 |
8 files changed, 6 insertions, 793 deletions
diff --git a/extension/react-app/src/App.tsx b/extension/react-app/src/App.tsx index 8785f88f..c9bd42e0 100644 --- a/extension/react-app/src/App.tsx +++ b/extension/react-app/src/App.tsx @@ -1,8 +1,5 @@ import DebugPanel from "./components/DebugPanel"; -import MainTab from "./tabs/main"; -import WelcomeTab from "./tabs/welcome"; -import ChatTab from "./tabs/chat"; -import GUI from "./tabs/gui"; +import GUI from "./pages/gui"; import { createContext } from "react"; import useContinueGUIProtocol from "./hooks/useWebsocket"; import ContinueGUIClientProtocol from "./hooks/useContinueGUIProtocol"; @@ -18,13 +15,7 @@ function App() { <GUIClientContext.Provider value={client}> <DebugPanel tabs={[ - { - element: <GUI />, - title: "GUI", - }, - // { element: <MainTab />, title: "Debug Panel" }, - // { element: <WelcomeTab />, title: "Welcome" }, - // { element: <ChatTab />, title: "Chat" }, + { element: <GUI />, title: "GUI" } ]} /> </GUIClientContext.Provider> diff --git a/extension/react-app/src/tabs/gui.tsx b/extension/react-app/src/pages/gui.tsx index b6a18dc8..b6a18dc8 100644 --- a/extension/react-app/src/tabs/gui.tsx +++ b/extension/react-app/src/pages/gui.tsx diff --git a/extension/react-app/src/tabs/additionalContext.tsx b/extension/react-app/src/tabs/additionalContext.tsx deleted file mode 100644 index 98fce9f1..00000000 --- a/extension/react-app/src/tabs/additionalContext.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import React from "react"; -import { H3, TextArea } from "../components"; - -function AdditionalContextTab() { - return ( - <div className="mx-5"> - <H3>Additional Context</H3> - <TextArea - rows={8} - placeholder="Copy and paste information related to the bug from GitHub Issues, Slack threads, or other notes here." - className="additionalContextTextarea" - ></TextArea> - <br></br> - </div> - ); -} - -export default AdditionalContextTab; diff --git a/extension/react-app/src/tabs/chat/MessageDiv.tsx b/extension/react-app/src/tabs/chat/MessageDiv.tsx deleted file mode 100644 index 3543dd93..00000000 --- a/extension/react-app/src/tabs/chat/MessageDiv.tsx +++ /dev/null @@ -1,75 +0,0 @@ -import React, { useEffect } from "react"; -import { ChatMessage } from "../../redux/store"; -import styled from "styled-components"; -import { - buttonColor, - defaultBorderRadius, - secondaryDark, -} from "../../components"; -import VSCodeFileLink from "../../components/VSCodeFileLink"; -import ReactMarkdown from "react-markdown"; -import "../../highlight/dark.min.css"; -import hljs from "highlight.js"; -import { useSelector } from "react-redux"; -import { selectIsStreaming } from "../../redux/selectors/chatSelectors"; - -const Container = styled.div` - padding-left: 8px; - padding-right: 8px; - border-radius: 8px; - margin: 3px; - width: fit-content; - max-width: 75%; - overflow-y: scroll; - word-wrap: break-word; - -ms-word-wrap: break-word; - height: fit-content; - overflow: hidden; - background-color: ${(props) => { - if (props.role === "user") { - return buttonColor; - } else { - return secondaryDark; - } - }}; - float: ${(props) => { - if (props.role === "user") { - return "right"; - } else { - return "left"; - } - }}; - display: block; - - & pre { - border: 1px solid gray; - border-radius: ${defaultBorderRadius}; - } -`; - -function MessageDiv(props: ChatMessage) { - const [richContent, setRichContent] = React.useState<JSX.Element[]>([]); - const isStreaming = useSelector(selectIsStreaming); - - useEffect(() => { - if (!isStreaming) { - hljs.highlightAll(); - } - }, [richContent, isStreaming]); - - useEffect(() => { - setRichContent([ - <ReactMarkdown key={1} children={props.content}></ReactMarkdown>, - ]); - }, [props.content]); - - return ( - <> - <div className="overflow-auto"> - <Container role={props.role}>{richContent}</Container> - </div> - </> - ); -} - -export default MessageDiv; diff --git a/extension/react-app/src/tabs/chat/index.tsx b/extension/react-app/src/tabs/chat/index.tsx deleted file mode 100644 index a93ad4f9..00000000 --- a/extension/react-app/src/tabs/chat/index.tsx +++ /dev/null @@ -1,267 +0,0 @@ -import React, { useCallback, useEffect, useRef, useState } from "react"; -import { useDispatch, useSelector } from "react-redux"; -import { selectChatMessages } from "../../redux/selectors/chatSelectors"; -import MessageDiv from "./MessageDiv"; -import styled from "styled-components"; -import { addMessage, setIsStreaming } from "../../redux/slices/chatSlice"; -import { AnyAction, Dispatch } from "@reduxjs/toolkit"; -import { closeStream, streamUpdate } from "../../redux/slices/chatSlice"; -import { ChatMessage, RootStore } from "../../redux/store"; -import { postVscMessage, vscRequest } from "../../vscode"; -import { defaultBorderRadius, Loader } from "../../components"; -import { selectHighlightedCode } from "../../redux/selectors/miscSelectors"; -import { readRangeInVirtualFileSystem } from "../../util"; -import { selectDebugContext } from "../../redux/selectors/debugContextSelectors"; - -let textEntryBarHeight = "30px"; - -const ChatContainer = styled.div` - display: grid; - grid-template-rows: 1fr auto; - height: 100%; -`; - -const BottomDiv = styled.div` - display: grid; - grid-template-rows: auto auto; -`; - -const BottomButton = styled.button( - (props: { active: boolean }) => ` - font-size: 10px; - border: none; - color: white; - margin-right: 4px; - cursor: pointer; - background-color: ${props.active ? "black" : "gray"}; - border-radius: ${defaultBorderRadius}; - padding: 8px; -` -); - -const TextEntryBar = styled.input` - height: ${textEntryBarHeight}; - border-bottom-left-radius: ${defaultBorderRadius}; - border-bottom-right-radius: ${defaultBorderRadius}; - padding: 8px; - border: 1px solid white; - background-color: black; - color: white; - outline: none; -`; - -function ChatTab() { - const dispatch = useDispatch(); - const chatMessages = useSelector(selectChatMessages); - const isStreaming = useSelector((state: RootStore) => state.chat.isStreaming); - const baseUrl = useSelector((state: RootStore) => state.config.apiUrl); - const debugContext = useSelector(selectDebugContext); - - const [includeHighlightedCode, setIncludeHighlightedCode] = useState(true); - const [writeToEditor, setWriteToEditor] = useState(false); - const [waitingForResponse, setWaitingForResponse] = useState(false); - - const highlightedCode = useSelector(selectHighlightedCode); - - const streamToStateThunk = useCallback( - (dispatch: Dispatch<AnyAction>, getResponse: () => Promise<Response>) => { - let streamToCursor = writeToEditor; - getResponse().then((resp) => { - setWaitingForResponse(false); - if (resp.body) { - resp.body.pipeTo( - new WritableStream({ - write(chunk) { - let update = new TextDecoder("utf-8").decode(chunk); - dispatch(streamUpdate(update)); - if (streamToCursor) { - postVscMessage("streamUpdate", { update }); - } - }, - close() { - dispatch(closeStream()); - if (streamToCursor) { - postVscMessage("closeStream", null); - } - }, - }) - ); - } - }); - }, - [writeToEditor] - ); - - const compileHiddenChatMessages = useCallback(async () => { - let messages: ChatMessage[] = []; - if ( - includeHighlightedCode && - highlightedCode?.filepath !== undefined && - highlightedCode?.range !== undefined && - debugContext.filesystem[highlightedCode.filepath] !== undefined - ) { - let fileContents = readRangeInVirtualFileSystem( - highlightedCode, - debugContext.filesystem - ); - if (fileContents) { - messages.push({ - role: "user", - content: fileContents, - }); - } - } else { - // Similarity search over workspace - let data = await vscRequest("queryEmbeddings", { - query: chatMessages[chatMessages.length - 1].content, - }); - let codeContextMessages = data.results.map( - (result: { id: string; document: string }) => { - let msg: ChatMessage = { - role: "user", - content: `File: ${result.id} \n ${result.document}`, - }; - return msg; - } - ); - codeContextMessages.push({ - role: "user", - content: - "Use the above code to help you answer the question below. Answer in asterisk bullet points, and give the full path whenever you reference files.", - }); - messages.push(...codeContextMessages); - } - - let systemMsgContent = writeToEditor - ? "Respond only with the exact code requested, no additional text." - : "Use the above code to help you answer the question below. Respond in markdown if using bullets or other special formatting, being sure to specify language for code blocks."; - - messages.push({ - role: "system", - content: systemMsgContent, - }); - return messages; - }, [highlightedCode, chatMessages, includeHighlightedCode, writeToEditor]); - - useEffect(() => { - if ( - chatMessages.length > 0 && - chatMessages[chatMessages.length - 1].role === "user" && - !isStreaming - ) { - dispatch(setIsStreaming(true)); - streamToStateThunk(dispatch, async () => { - if (chatMessages.length === 0) { - return new Promise((resolve, _) => resolve(new Response())); - } - let hiddenChatMessages = await compileHiddenChatMessages(); - let augmentedMessages = [ - ...chatMessages.slice(0, -1), - ...hiddenChatMessages, - chatMessages[chatMessages.length - 1], - ]; - console.log(augmentedMessages); - // The autogenerated client can't handle streams, so have to go raw - return fetch(`${baseUrl}/chat/complete`, { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ - messages: augmentedMessages, - }), - }); - }); - } - }, [chatMessages, dispatch, isStreaming, highlightedCode]); - - const chatMessagesDiv = useRef<HTMLDivElement>(null); - useEffect(() => { - // Scroll to bottom - let interval = setInterval(() => { - if (chatMessagesDiv.current && !waitingForResponse) { - chatMessagesDiv.current.scrollTop += Math.max( - 4, - 0.05 * chatMessagesDiv.current.scrollHeight - - chatMessagesDiv.current.clientHeight - - chatMessagesDiv.current.scrollTop - ); - if ( - chatMessagesDiv.current.scrollTop >= - chatMessagesDiv.current.scrollHeight - - chatMessagesDiv.current.clientHeight - ) { - clearInterval(interval); - } - } - }, 10); - }, [chatMessages, chatMessagesDiv, waitingForResponse]); - - return ( - <ChatContainer> - <div className="mx-5 overflow-y-scroll" ref={chatMessagesDiv}> - <h1>Chat</h1> - <hr></hr> - <div> - {chatMessages.length > 0 ? ( - chatMessages.map((message, idx) => { - return <MessageDiv key={idx} {...message}></MessageDiv>; - }) - ) : ( - <p className="text-gray-400 m-auto text-center"> - You can ask questions about your codebase or ask for code written - directly in the editor. - </p> - )} - {waitingForResponse && <Loader></Loader>} - </div> - </div> - - <BottomDiv> - <div className="h-12 bg-secondary-"> - <div className="flex items-center p-2"> - {/* <p className="mr-auto text-xs"> - Highlighted code is automatically included in your chat message. - </p> */} - <BottomButton - className="ml-auto" - active={writeToEditor} - onClick={() => { - setWriteToEditor(!writeToEditor); - }} - > - {writeToEditor ? "Writing to editor" : "Write to editor"} - </BottomButton> - - <BottomButton - active={includeHighlightedCode} - onClick={() => { - setIncludeHighlightedCode(!includeHighlightedCode); - }} - > - {includeHighlightedCode - ? "Including highlighted code" - : "Automatically finding relevant code"} - </BottomButton> - </div> - </div> - <TextEntryBar - type="text" - placeholder="Enter your message here" - onKeyDown={(e) => { - if (e.key === "Enter" && e.currentTarget.value !== "") { - console.log("Sending message", e.currentTarget.value); - dispatch( - addMessage({ content: e.currentTarget.value, role: "user" }) - ); - (e.target as any).value = ""; - setWaitingForResponse(true); - } - }} - ></TextEntryBar> - </BottomDiv> - </ChatContainer> - ); -} - -export default ChatTab; diff --git a/extension/react-app/src/tabs/main.tsx b/extension/react-app/src/tabs/main.tsx deleted file mode 100644 index a8b3300d..00000000 --- a/extension/react-app/src/tabs/main.tsx +++ /dev/null @@ -1,189 +0,0 @@ -import React, { useEffect, useState } from "react"; -import { H3, TextArea, Button, Pre, Loader } from "../components"; -import styled from "styled-components"; -import { postVscMessage, withProgress } from "../vscode"; -import { useDebugContextValue } from "../redux/hooks"; -import CodeMultiselect from "../components/CodeMultiselect"; -import { useSelector } from "react-redux"; -import { selectDebugContext } from "../redux/selectors/debugContextSelectors"; -import { useDispatch } from "react-redux"; -import { updateValue } from "../redux/slices/debugContexSlice"; -import { setWorkspacePath } from "../redux/slices/configSlice"; -import { SerializedDebugContext } from "../../../src/client"; -import { useEditCache } from "../util/editCache"; -import { useApi } from "../util/api"; - -const ButtonDiv = styled.div` - display: flex; - justify-content: space-between; - align-items: center; - gap: 4px; - margin: 4px; - flex-wrap: wrap; - - & button { - flex-grow: 1; - } -`; - -function MainTab(props: any) { - const dispatch = useDispatch(); - - const [suggestion, setSuggestion] = useState(""); - const [traceback, setTraceback] = useDebugContextValue("traceback", ""); - const [selectedRanges, setSelectedRanges] = useDebugContextValue( - "rangesInFiles", - [] - ); - - const editCache = useEditCache(); - const { debugApi } = useApi(); - - const [responseLoading, setResponseLoading] = useState(false); - - let debugContext = useSelector(selectDebugContext); - - useEffect(() => { - editCache.preloadEdit(debugContext); - }, [debugContext]); - - function postVscMessageWithDebugContext( - type: string, - overrideDebugContext: SerializedDebugContext | null = null - ) { - postVscMessage(type, { - debugContext: overrideDebugContext || debugContext, - }); - } - - function launchFindSuspiciousCode(newTraceback: string) { - // setTraceback's effects don't occur immediately, so we have to add it to the debug context manually - let updatedDebugContext = { - ...debugContext, - traceback: newTraceback, - }; - postVscMessageWithDebugContext("findSuspiciousCode", updatedDebugContext); - postVscMessageWithDebugContext("preloadEdit", updatedDebugContext); - } - - useEffect(() => { - const eventListener = (event: any) => { - switch (event.data.type) { - case "suggestFix": - case "explainCode": - case "listTenThings": - setSuggestion(event.data.value); - setResponseLoading(false); - break; - case "traceback": - setTraceback(event.data.value); - launchFindSuspiciousCode(event.data.value); - break; - case "workspacePath": - dispatch(setWorkspacePath(event.data.value)); - break; - } - }; - window.addEventListener("message", eventListener); - - return () => window.removeEventListener("message", eventListener); - }, [debugContext, selectedRanges]); - - return ( - <div className="mx-5"> - <h1>Debug Panel</h1> - - <H3>Code Sections</H3> - <CodeMultiselect></CodeMultiselect> - - <H3>Bug Description</H3> - <TextArea - id="bugDescription" - name="bugDescription" - className="bugDescription" - rows={4} - cols={50} - placeholder="Describe your bug..." - ></TextArea> - - <H3>Stack Trace</H3> - <TextArea - id="traceback" - className="traceback" - name="traceback" - rows={4} - cols={50} - placeholder="Paste stack trace here" - onChange={(e) => { - setTraceback(e.target.value); - dispatch(updateValue({ key: "traceback", value: e.target.value })); - // postVscMessageWithDebugContext("findSuspiciousCode"); - }} - onPaste={(e) => { - let pasted = e.clipboardData.getData("text"); - console.log("PASTED", pasted); - setTraceback(pasted); - launchFindSuspiciousCode(pasted); - }} - value={traceback} - ></TextArea> - - <select - hidden - id="relevantVars" - className="relevantVars" - name="relevantVars" - ></select> - - <ButtonDiv> - <Button - onClick={() => { - postVscMessageWithDebugContext("explainCode"); - setResponseLoading(true); - }} - > - Explain Code - </Button> - <Button - onClick={() => { - postVscMessageWithDebugContext("suggestFix"); - setResponseLoading(true); - }} - > - Generate Ideas - </Button> - <Button - disabled={selectedRanges.length === 0} - onClick={async () => { - withProgress("Generating Fix", async () => { - let edits = await editCache.getEdit(debugContext); - postVscMessage("makeEdit", { edits }); - }); - }} - > - Suggest Fix - </Button> - <Button - disabled={selectedRanges.length === 0} - onClick={() => { - postVscMessageWithDebugContext("generateUnitTest"); - }} - > - Create Test - </Button> - </ButtonDiv> - <Loader hidden={!responseLoading}></Loader> - - <Pre - className="fixSuggestion" - hidden={!(typeof suggestion === "string" && suggestion.length > 0)} - > - {suggestion} - </Pre> - - <br></br> - </div> - ); -} - -export default MainTab; diff --git a/extension/react-app/src/tabs/welcome.tsx b/extension/react-app/src/tabs/welcome.tsx deleted file mode 100644 index c29d260a..00000000 --- a/extension/react-app/src/tabs/welcome.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import React from "react"; - -function WelcomeTab() { - return ( - <div className="mx-5"> - <h1>Welcome to Continue</h1> - - <p> - Learn more in the{" "} - <a href="https://www.notion.so/continue-dev/Continue-User-Guide-1c6ad99887d0474d9e42206f6c98efa4"> - Continue User Guide - </a>{" "} - </p> - <p>Send Nate or Ty your feedback:</p> - <p>1. What excites you about Continue?</p> - <p>2. What did you struggle with when using Continue?</p> - <p>3. How do you wish Continue worked?</p> - </div> - ); -} - -export default WelcomeTab; diff --git a/extension/src/bridge.ts b/extension/src/bridge.ts index 92ba4044..55c4cc3b 100644 --- a/extension/src/bridge.ts +++ b/extension/src/bridge.ts @@ -4,14 +4,11 @@ import * as vscode from "vscode"; import { Configuration, DebugApi, - RangeInFile, - SerializedDebugContext, UnittestApi, } from "./client"; import { convertSingleToDoubleQuoteJSON } from "./util/util"; import { getExtensionUri } from "./util/vscode"; import { extensionContext } from "./activation/activate"; -const axios = require("axios").default; const util = require("util"); const exec = util.promisify(require("child_process").exec); @@ -36,21 +33,16 @@ const configuration = new Configuration({ export const debugApi = new DebugApi(configuration); export const unittestApi = new UnittestApi(configuration); -function get_python_path() { - return path.join(getExtensionUri().fsPath, ".."); -} - export function get_api_url() { - let extensionUri = getExtensionUri(); - let configFile = path.join(extensionUri.fsPath, "config/config.json"); - let config = require(configFile); + const extensionUri = getExtensionUri(); + const configFile = path.join(extensionUri.fsPath, "config/config.json"); + const config = require(configFile); if (config.API_URL) { return config.API_URL; } return "http://localhost:65432"; } -const API_URL = get_api_url(); export function getContinueServerUrl() { // If in debug mode, always use 8001 @@ -58,7 +50,7 @@ export function getContinueServerUrl() { extensionContext && extensionContext.extensionMode === vscode.ExtensionMode.Development ) { - return "http://localhost:8001"; + // return "http://localhost:8001"; } return ( vscode.workspace.getConfiguration("continue").get<string>("serverUrl") || @@ -66,10 +58,6 @@ export function getContinueServerUrl() { ); } -function build_python_command(cmd: string): string { - return `cd ${get_python_path()} && source env/bin/activate && ${cmd}`; -} - function listToCmdLineArgs(list: string[]): string { return list.map((el) => `"$(echo "${el}")"`).join(" "); } @@ -103,198 +91,3 @@ export async function runPythonScript( } } } - -function parseStdout( - stdout: string, - key: string, - until_end: boolean = false -): string { - const prompt = `${key}=`; - let lines = stdout.split("\n"); - - let value: string = ""; - for (let i = 0; i < lines.length; i++) { - if (lines[i].startsWith(prompt)) { - if (until_end) { - return lines.slice(i).join("\n").substring(prompt.length); - } else { - return lines[i].substring(prompt.length); - } - } - } - return ""; -} - -export async function askQuestion( - question: string, - workspacePath: string -): Promise<{ answer: string; range: vscode.Range; filename: string }> { - const command = build_python_command( - `python3 ${path.join( - get_python_path(), - "ask.py" - )} ask ${workspacePath} "${question}"` - ); - - const { stdout, stderr } = await exec(command); - if (stderr) { - throw new Error(stderr); - } - // Use the output - const answer = parseStdout(stdout, "Answer"); - const filename = parseStdout(stdout, "Filename"); - const startLineno = parseInt(parseStdout(stdout, "Start lineno")); - const endLineno = parseInt(parseStdout(stdout, "End lineno")); - const range = new vscode.Range( - new vscode.Position(startLineno, 0), - new vscode.Position(endLineno, 0) - ); - if (answer && filename && startLineno && endLineno) { - return { answer, filename, range }; - } else { - throw new Error("Error: No answer found"); - } -} - -export async function apiRequest( - endpoint: string, - options: { - method?: string; - query?: { [key: string]: any }; - body?: { [key: string]: any }; - } -): Promise<any> { - let defaults = { - method: "GET", - query: {}, - body: {}, - }; - options = Object.assign(defaults, options); // Second takes over first - if (endpoint.startsWith("/")) endpoint = endpoint.substring(1); - console.log("API request: ", options.body); - - let resp; - try { - resp = await axios({ - method: options.method, - url: `${API_URL}/${endpoint}`, - data: options.body, - params: options.query, - headers: { - "x-vsc-machine-id": vscode.env.machineId, - }, - }); - } catch (err) { - console.log("Error: ", err); - throw err; - } - - return resp.data; -} - -// Write a docstring for the most specific function or class at the current line in the given file -export async function writeDocstringForFunction( - filename: string, - position: vscode.Position -): Promise<{ lineno: number; docstring: string }> { - let resp = await apiRequest("docstring/forline", { - query: { - filecontents: ( - await vscode.workspace.fs.readFile(vscode.Uri.file(filename)) - ).toString(), - lineno: position.line.toString(), - }, - }); - - const lineno = resp.lineno; - const docstring = resp.completion; - if (lineno && docstring) { - return { lineno, docstring }; - } else { - throw new Error("Error: No docstring returned"); - } -} - -export async function findSuspiciousCode( - ctx: SerializedDebugContext -): Promise<RangeInFile[]> { - if (!ctx.traceback) return []; - let files = await getFileContents( - getFilenamesFromPythonStacktrace(ctx.traceback) - ); - let resp = await debugApi.findSusCodeEndpointDebugFindPost({ - findBody: { - traceback: ctx.traceback, - description: ctx.description, - filesystem: files, - }, - }); - let ranges = resp.response; - if ( - ranges.length <= 1 && - ctx.traceback && - ctx.traceback.includes("AssertionError") - ) { - let parsed_traceback = - await debugApi.parseTracebackEndpointDebugParseTracebackGet({ - traceback: ctx.traceback, - }); - let last_frame = parsed_traceback.frames[0]; - if (!last_frame) return []; - ranges = ( - await runPythonScript("build_call_graph.py", [ - last_frame.filepath, - last_frame.lineno.toString(), - last_frame._function, - ]) - ).value; - } - - return ranges; -} - -export async function writeUnitTestForFunction( - filename: string, - position: vscode.Position -): Promise<string> { - let resp = await apiRequest("unittest/forline", { - method: "POST", - body: { - filecontents: ( - await vscode.workspace.fs.readFile(vscode.Uri.file(filename)) - ).toString(), - lineno: position.line, - userid: vscode.env.machineId, - }, - }); - - return resp.completion; -} - -async function getFileContents( - files: string[] -): Promise<{ [key: string]: string }> { - let contents = await Promise.all( - files.map(async (file: string) => { - return ( - await vscode.workspace.fs.readFile(vscode.Uri.file(file)) - ).toString(); - }) - ); - let fileContents: { [key: string]: string } = {}; - for (let i = 0; i < files.length; i++) { - fileContents[files[i]] = contents[i]; - } - return fileContents; -} - -function getFilenamesFromPythonStacktrace(traceback: string): string[] { - let filenames: string[] = []; - for (let line of traceback.split("\n")) { - let match = line.match(/File "(.*)", line/); - if (match) { - filenames.push(match[1]); - } - } - return filenames; -} |