summaryrefslogtreecommitdiff
path: root/extension
diff options
context:
space:
mode:
Diffstat (limited to 'extension')
-rw-r--r--extension/package-lock.json64
-rw-r--r--extension/package.json83
-rw-r--r--extension/react-app/package-lock.json60
-rw-r--r--extension/react-app/package.json1
-rw-r--r--extension/react-app/src/components/CodeBlock.tsx1
-rw-r--r--extension/react-app/src/components/ComboBox.tsx146
-rw-r--r--extension/react-app/src/components/StepContainer.tsx67
-rw-r--r--extension/react-app/src/components/index.ts18
-rw-r--r--extension/react-app/src/hooks/ContinueGUIClientProtocol.ts10
-rw-r--r--extension/react-app/src/hooks/useContinueGUIProtocol.ts18
-rw-r--r--extension/react-app/src/tabs/chat/MessageDiv.tsx4
-rw-r--r--extension/react-app/src/tabs/gui.tsx96
-rw-r--r--extension/scripts/continuedev-0.1.1-py3-none-any.whlbin74791 -> 78916 bytes
-rw-r--r--extension/src/continueIdeClient.ts6
-rw-r--r--extension/src/decorations.ts19
15 files changed, 451 insertions, 142 deletions
diff --git a/extension/package-lock.json b/extension/package-lock.json
index aebd0803..b02c4544 100644
--- a/extension/package-lock.json
+++ b/extension/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "continue",
- "version": "0.0.34",
+ "version": "0.0.35",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "continue",
- "version": "0.0.34",
+ "version": "0.0.35",
"license": "Apache-2.0",
"dependencies": {
"@electron/rebuild": "^3.2.10",
@@ -15,6 +15,7 @@
"@styled-icons/heroicons-outline": "^10.47.0",
"@vitejs/plugin-react-swc": "^3.3.2",
"axios": "^1.2.5",
+ "downshift": "^7.6.0",
"highlight.js": "^11.7.0",
"posthog-js": "^1.63.3",
"react-markdown": "^8.0.7",
@@ -2845,6 +2846,11 @@
"integrity": "sha512-FemMreK9xNyL8gQevsdRMrvO4lFCkQP7qbuktn1q8ndcNk1+0mz7lgE7b/sNvbhVgY4w6tMN1FDp6aADjqw2rw==",
"dev": true
},
+ "node_modules/compute-scroll-into-view": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/compute-scroll-into-view/-/compute-scroll-into-view-2.0.4.tgz",
+ "integrity": "sha512-y/ZA3BGnxoM/QHHQ2Uy49CLtnWPbt4tTPpEEZiEmmiWBFKjej7nEyH8Ryz54jH0MLXflUYA3Er2zUxPSJu5R+g=="
+ },
"node_modules/concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
@@ -3261,6 +3267,31 @@
"url": "https://github.com/fb55/domutils?sponsor=1"
}
},
+ "node_modules/downshift": {
+ "version": "7.6.0",
+ "resolved": "https://registry.npmjs.org/downshift/-/downshift-7.6.0.tgz",
+ "integrity": "sha512-VSoTVynTAsabou/hbZ6HJHUVhtBiVOjQoBsCPcQq5eAROIGP+9XKMp9asAKQ3cEcUP4oe0fFdD2pziUjhFY33Q==",
+ "dependencies": {
+ "@babel/runtime": "^7.14.8",
+ "compute-scroll-into-view": "^2.0.4",
+ "prop-types": "^15.7.2",
+ "react-is": "^17.0.2",
+ "tslib": "^2.3.0"
+ },
+ "peerDependencies": {
+ "react": ">=16.12.0"
+ }
+ },
+ "node_modules/downshift/node_modules/react-is": {
+ "version": "17.0.2",
+ "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
+ "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w=="
+ },
+ "node_modules/downshift/node_modules/tslib": {
+ "version": "2.5.3",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.3.tgz",
+ "integrity": "sha512-mSxlJJwl3BMEQCUNnxXBU9jP4JBktcEGhURcPR6VQVlnP0FdDEsIaz0C35dXNGLyRfrATNofF0F5p2KPxQgB+w=="
+ },
"node_modules/dset": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/dset/-/dset-3.1.2.tgz",
@@ -10615,6 +10646,11 @@
"integrity": "sha512-FemMreK9xNyL8gQevsdRMrvO4lFCkQP7qbuktn1q8ndcNk1+0mz7lgE7b/sNvbhVgY4w6tMN1FDp6aADjqw2rw==",
"dev": true
},
+ "compute-scroll-into-view": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/compute-scroll-into-view/-/compute-scroll-into-view-2.0.4.tgz",
+ "integrity": "sha512-y/ZA3BGnxoM/QHHQ2Uy49CLtnWPbt4tTPpEEZiEmmiWBFKjej7nEyH8Ryz54jH0MLXflUYA3Er2zUxPSJu5R+g=="
+ },
"concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
@@ -10911,6 +10947,30 @@
"domhandler": "^5.0.1"
}
},
+ "downshift": {
+ "version": "7.6.0",
+ "resolved": "https://registry.npmjs.org/downshift/-/downshift-7.6.0.tgz",
+ "integrity": "sha512-VSoTVynTAsabou/hbZ6HJHUVhtBiVOjQoBsCPcQq5eAROIGP+9XKMp9asAKQ3cEcUP4oe0fFdD2pziUjhFY33Q==",
+ "requires": {
+ "@babel/runtime": "^7.14.8",
+ "compute-scroll-into-view": "^2.0.4",
+ "prop-types": "^15.7.2",
+ "react-is": "^17.0.2",
+ "tslib": "^2.3.0"
+ },
+ "dependencies": {
+ "react-is": {
+ "version": "17.0.2",
+ "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
+ "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w=="
+ },
+ "tslib": {
+ "version": "2.5.3",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.3.tgz",
+ "integrity": "sha512-mSxlJJwl3BMEQCUNnxXBU9jP4JBktcEGhURcPR6VQVlnP0FdDEsIaz0C35dXNGLyRfrATNofF0F5p2KPxQgB+w=="
+ }
+ }
+ },
"dset": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/dset/-/dset-3.1.2.tgz",
diff --git a/extension/package.json b/extension/package.json
index 1d2fd995..8ccb4b13 100644
--- a/extension/package.json
+++ b/extension/package.json
@@ -14,7 +14,7 @@
"displayName": "Continue",
"pricing": "Free",
"description": "Refine code 10x faster",
- "version": "0.0.34",
+ "version": "0.0.35",
"publisher": "Continue",
"engines": {
"vscode": "^1.74.0"
@@ -55,93 +55,13 @@
},
"commands": [
{
- "command": "continue.writeDocstring",
- "category": "Continue",
- "title": "Write a docstring for the current function"
- },
- {
"command": "continue.openContinueGUI",
"category": "Continue",
"title": "Open Continue GUI"
- },
- {
- "command": "continue.askQuestionFromInput",
- "Category": "Continue",
- "title": "Ask a question from input box"
- },
- {
- "command": "continue.openCapturedTerminal",
- "Category": "Continue",
- "title": "Open Captured Terminal"
- },
- {
- "command": "continue.askQuestion",
- "Category": "Continue",
- "title": "Ask a question from webview"
- },
- {
- "command": "continue.createTerminal",
- "category": "Continue",
- "title": "Create Terminal"
- },
- {
- "command": "continue.debugTest",
- "category": "Continue",
- "title": "Debug Test"
- },
- {
- "command": "continue.suggestionDown",
- "category": "Continue",
- "title": "Suggestion Down"
- },
- {
- "command": "continue.suggestionUp",
- "category": "Continue",
- "title": "Suggestion Up"
- },
- {
- "command": "continue.acceptSuggestion",
- "category": "Continue",
- "title": "Accept Suggestion"
- },
- {
- "command": "continue.rejectSuggestion",
- "category": "Continue",
- "title": "Reject Suggestion"
- },
- {
- "command": "continue.writeUnitTest",
- "title": "Write Unit Test",
- "category": "Continue"
- },
- {
- "command": "continue.findSuspiciousCode",
- "title": "Find Suspicious Code",
- "category": "Continue"
- },
- {
- "command": "continue.focusContinueInput",
- "title": "Focus Continue Input",
- "category": "Continue"
}
],
"keybindings": [
{
- "command": "continue.suggestionDown",
- "mac": "shift+ctrl+down",
- "key": "shift+ctrl+down"
- },
- {
- "command": "continue.suggestionUp",
- "mac": "shift+ctrl+up",
- "key": "shift+ctrl+up"
- },
- {
- "command": "continue.acceptSuggestion",
- "mac": "shift+ctrl+enter",
- "key": "shift+ctrl+enter"
- },
- {
"command": "continue.focusContinueInput",
"mac": "cmd+k",
"key": "ctrl+k"
@@ -214,6 +134,7 @@
"@styled-icons/heroicons-outline": "^10.47.0",
"@vitejs/plugin-react-swc": "^3.3.2",
"axios": "^1.2.5",
+ "downshift": "^7.6.0",
"highlight.js": "^11.7.0",
"posthog-js": "^1.63.3",
"react-markdown": "^8.0.7",
diff --git a/extension/react-app/package-lock.json b/extension/react-app/package-lock.json
index dbcbc5cc..64440da6 100644
--- a/extension/react-app/package-lock.json
+++ b/extension/react-app/package-lock.json
@@ -10,6 +10,7 @@
"dependencies": {
"@styled-icons/heroicons-outline": "^10.47.0",
"@types/vscode-webview": "^1.57.1",
+ "downshift": "^7.6.0",
"posthog-js": "^1.58.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
@@ -1288,6 +1289,11 @@
"url": "https://github.com/sponsors/wooorm"
}
},
+ "node_modules/compute-scroll-into-view": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/compute-scroll-into-view/-/compute-scroll-into-view-2.0.4.tgz",
+ "integrity": "sha512-y/ZA3BGnxoM/QHHQ2Uy49CLtnWPbt4tTPpEEZiEmmiWBFKjej7nEyH8Ryz54jH0MLXflUYA3Er2zUxPSJu5R+g=="
+ },
"node_modules/css-color-keywords": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/css-color-keywords/-/css-color-keywords-1.0.0.tgz",
@@ -1405,6 +1411,26 @@
"integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==",
"dev": true
},
+ "node_modules/downshift": {
+ "version": "7.6.0",
+ "resolved": "https://registry.npmjs.org/downshift/-/downshift-7.6.0.tgz",
+ "integrity": "sha512-VSoTVynTAsabou/hbZ6HJHUVhtBiVOjQoBsCPcQq5eAROIGP+9XKMp9asAKQ3cEcUP4oe0fFdD2pziUjhFY33Q==",
+ "dependencies": {
+ "@babel/runtime": "^7.14.8",
+ "compute-scroll-into-view": "^2.0.4",
+ "prop-types": "^15.7.2",
+ "react-is": "^17.0.2",
+ "tslib": "^2.3.0"
+ },
+ "peerDependencies": {
+ "react": ">=16.12.0"
+ }
+ },
+ "node_modules/downshift/node_modules/react-is": {
+ "version": "17.0.2",
+ "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
+ "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w=="
+ },
"node_modules/electron-to-chromium": {
"version": "1.4.311",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.311.tgz",
@@ -3003,6 +3029,11 @@
"url": "https://github.com/sponsors/wooorm"
}
},
+ "node_modules/tslib": {
+ "version": "2.5.3",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.3.tgz",
+ "integrity": "sha512-mSxlJJwl3BMEQCUNnxXBU9jP4JBktcEGhURcPR6VQVlnP0FdDEsIaz0C35dXNGLyRfrATNofF0F5p2KPxQgB+w=="
+ },
"node_modules/typescript": {
"version": "4.9.5",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz",
@@ -4050,6 +4081,11 @@
"resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz",
"integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg=="
},
+ "compute-scroll-into-view": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/compute-scroll-into-view/-/compute-scroll-into-view-2.0.4.tgz",
+ "integrity": "sha512-y/ZA3BGnxoM/QHHQ2Uy49CLtnWPbt4tTPpEEZiEmmiWBFKjej7nEyH8Ryz54jH0MLXflUYA3Er2zUxPSJu5R+g=="
+ },
"css-color-keywords": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/css-color-keywords/-/css-color-keywords-1.0.0.tgz",
@@ -4131,6 +4167,25 @@
"integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==",
"dev": true
},
+ "downshift": {
+ "version": "7.6.0",
+ "resolved": "https://registry.npmjs.org/downshift/-/downshift-7.6.0.tgz",
+ "integrity": "sha512-VSoTVynTAsabou/hbZ6HJHUVhtBiVOjQoBsCPcQq5eAROIGP+9XKMp9asAKQ3cEcUP4oe0fFdD2pziUjhFY33Q==",
+ "requires": {
+ "@babel/runtime": "^7.14.8",
+ "compute-scroll-into-view": "^2.0.4",
+ "prop-types": "^15.7.2",
+ "react-is": "^17.0.2",
+ "tslib": "^2.3.0"
+ },
+ "dependencies": {
+ "react-is": {
+ "version": "17.0.2",
+ "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
+ "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w=="
+ }
+ }
+ },
"electron-to-chromium": {
"version": "1.4.311",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.311.tgz",
@@ -5138,6 +5193,11 @@
"resolved": "https://registry.npmjs.org/trough/-/trough-2.1.0.tgz",
"integrity": "sha512-AqTiAOLcj85xS7vQ8QkAV41hPDIJ71XJB4RCUrzo/1GM2CQwhkJGaf9Hgr7BOugMRpgGUrqRg/DrBDl4H40+8g=="
},
+ "tslib": {
+ "version": "2.5.3",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.3.tgz",
+ "integrity": "sha512-mSxlJJwl3BMEQCUNnxXBU9jP4JBktcEGhURcPR6VQVlnP0FdDEsIaz0C35dXNGLyRfrATNofF0F5p2KPxQgB+w=="
+ },
"typescript": {
"version": "4.9.5",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz",
diff --git a/extension/react-app/package.json b/extension/react-app/package.json
index 7d1211de..a53fbec8 100644
--- a/extension/react-app/package.json
+++ b/extension/react-app/package.json
@@ -11,6 +11,7 @@
"dependencies": {
"@styled-icons/heroicons-outline": "^10.47.0",
"@types/vscode-webview": "^1.57.1",
+ "downshift": "^7.6.0",
"posthog-js": "^1.58.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
diff --git a/extension/react-app/src/components/CodeBlock.tsx b/extension/react-app/src/components/CodeBlock.tsx
index e0336554..eedae3fb 100644
--- a/extension/react-app/src/components/CodeBlock.tsx
+++ b/extension/react-app/src/components/CodeBlock.tsx
@@ -11,6 +11,7 @@ const StyledPre = styled.pre`
border: 1px solid gray;
border-radius: ${defaultBorderRadius};
background-color: ${vscBackground};
+ padding: 8px;
`;
const StyledCode = styled.code`
diff --git a/extension/react-app/src/components/ComboBox.tsx b/extension/react-app/src/components/ComboBox.tsx
new file mode 100644
index 00000000..1b7c60e6
--- /dev/null
+++ b/extension/react-app/src/components/ComboBox.tsx
@@ -0,0 +1,146 @@
+import React, { useCallback } from "react";
+import { useCombobox } from "downshift";
+import styled from "styled-components";
+import {
+ buttonColor,
+ defaultBorderRadius,
+ secondaryDark,
+ vscBackground,
+} from ".";
+
+const mainInputFontSize = 16;
+const MainTextInput = styled.input`
+ padding: 8px;
+ font-size: ${mainInputFontSize}px;
+ border-radius: ${defaultBorderRadius};
+ border: 1px solid #ccc;
+ margin: 8px auto;
+ width: 100%;
+ background-color: ${vscBackground};
+ color: white;
+ outline: 1px solid orange;
+`;
+
+const UlMaxHeight = 200;
+const Ul = styled.ul<{
+ hidden: boolean;
+ showAbove: boolean;
+ ulHeightPixels: number;
+}>`
+ ${(props) =>
+ props.showAbove
+ ? `transform: translateY(-${props.ulHeightPixels + 8}px);`
+ : `transform: translateY(${2 * mainInputFontSize}px);`}
+ position: absolute;
+ background: ${vscBackground};
+ background-color: ${secondaryDark};
+ color: white;
+ font-family: "Fira Code", monospace;
+ max-height: ${UlMaxHeight}px;
+ overflow: scroll;
+ padding: 0;
+ ${({ hidden }) => hidden && "display: none;"}
+ border-radius: ${defaultBorderRadius};
+ overflow: hidden;
+ border: 0.5px solid gray;
+`;
+
+const Li = styled.li<{
+ highlighted: boolean;
+ selected: boolean;
+ isLastItem: boolean;
+}>`
+ ${({ highlighted }) => highlighted && "background: #aa0000;"}
+ ${({ selected }) => selected && "font-weight: bold;"}
+ padding: 0.5rem 0.75rem;
+ display: flex;
+ flex-direction: column;
+ ${({ isLastItem }) => isLastItem && "border-bottom: 1px solid gray;"}
+ border-top: 1px solid gray;
+ cursor: pointer;
+`;
+
+interface ComboBoxProps {
+ items: { name: string; description: string }[];
+ onInputValueChange: (inputValue: string) => void;
+ disabled?: boolean;
+ onEnter?: (e: React.KeyboardEvent<HTMLInputElement>) => void;
+}
+
+const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => {
+ const [items, setItems] = React.useState(props.items);
+ const {
+ isOpen,
+ getToggleButtonProps,
+ getLabelProps,
+ getMenuProps,
+ getInputProps,
+ highlightedIndex,
+ getItemProps,
+ selectedItem,
+ setInputValue,
+ } = useCombobox({
+ onInputValueChange({ inputValue }) {
+ if (!inputValue) return;
+ props.onInputValueChange(inputValue);
+ setItems(
+ props.items.filter((item) =>
+ item.name.toLowerCase().startsWith(inputValue.toLowerCase())
+ )
+ );
+ },
+ items,
+ itemToString(item) {
+ return item ? item.name : "";
+ },
+ });
+
+ const divRef = React.useRef<HTMLDivElement>(null);
+ const ulRef = React.useRef<HTMLUListElement>(null);
+ const showAbove = () => {
+ return (divRef.current?.getBoundingClientRect().top || 0) > UlMaxHeight;
+ };
+
+ return (
+ <div className="flex px-2" ref={divRef} hidden={!isOpen}>
+ <MainTextInput
+ disabled={props.disabled}
+ placeholder="Ask anything:"
+ {...getInputProps({
+ onKeyDown: (event) => {
+ if (event.key === "Enter" && (!isOpen || items.length === 0)) {
+ // Prevent Downshift's default 'Enter' behavior.
+ (event.nativeEvent as any).preventDownshiftDefault = true;
+ if (props.onEnter) props.onEnter(event);
+ setInputValue("");
+ }
+ },
+ ref: ref as any,
+ })}
+ />
+ <Ul
+ {...getMenuProps({
+ ref: ulRef,
+ })}
+ showAbove={showAbove()}
+ ulHeightPixels={ulRef.current?.getBoundingClientRect().height || 0}
+ >
+ {isOpen &&
+ items.map((item, index) => (
+ <Li
+ key={`${item.name}${index}`}
+ {...getItemProps({ item, index })}
+ highlighted={highlightedIndex === index}
+ selected={selectedItem === item}
+ >
+ <span>
+ {item.name}: {item.description}
+ </span>
+ </Li>
+ ))}
+ </Ul>
+ </div>
+ );
+});
+
+export default ComboBox;
diff --git a/extension/react-app/src/components/StepContainer.tsx b/extension/react-app/src/components/StepContainer.tsx
index 3408053b..ca142b06 100644
--- a/extension/react-app/src/components/StepContainer.tsx
+++ b/extension/react-app/src/components/StepContainer.tsx
@@ -7,6 +7,7 @@ import {
vscBackground,
GradientBorder,
vscBackgroundTransparent,
+ HeaderButton,
} from ".";
import { RangeInFile, FileEdit } from "../../../src/client";
import CodeBlock from "./CodeBlock";
@@ -15,7 +16,7 @@ import SubContainer from "./SubContainer";
import {
ChevronDown,
ChevronRight,
- Backward,
+ XMark,
ArrowPath,
} from "@styled-icons/heroicons-outline";
import { HistoryNode } from "../../../schema/HistoryNode";
@@ -31,6 +32,7 @@ interface StepContainerProps {
onRefinement: (input: string) => void;
onUserInput: (input: string) => void;
onRetry: () => void;
+ onDelete: () => void;
open?: boolean;
}
@@ -54,8 +56,10 @@ const HeaderDiv = styled.div<{ error: boolean }>`
background-color: ${(props) =>
props.error ? "#522" : vscBackgroundTransparent};
display: grid;
- grid-template-columns: 1fr auto;
+ grid-template-columns: 1fr auto auto;
+ grid-gap: 8px;
align-items: center;
+ padding-right: 8px;
`;
const ContentDiv = styled.div`
@@ -64,26 +68,21 @@ const ContentDiv = styled.div`
background-color: ${vscBackground};
`;
-const HeaderButton = styled.button`
- background-color: transparent;
- border: 1px solid white;
- border-radius: ${defaultBorderRadius};
- padding: 2px;
- cursor: pointer;
- color: white;
-
- &:hover {
- background-color: white;
- color: black;
- }
-`;
-
const OnHoverDiv = styled.div`
text-align: center;
padding: 10px;
animation: ${appear} 0.3s ease-in-out;
`;
+const MarkdownPre = styled.pre`
+ background-color: ${secondaryDark};
+ padding: 10px;
+ border-radius: ${defaultBorderRadius};
+ border: 0.5px solid white;
+`;
+
+const MarkdownCode = styled.code``;
+
function StepContainer(props: StepContainerProps) {
const [open, setOpen] = useState(
typeof props.open === "undefined" ? true : props.open
@@ -152,18 +151,28 @@ function StepContainer(props: StepContainerProps) {
<Backward size="1.6em" onClick={props.onReverse}></Backward>
</HeaderButton> */}
- {props.historyNode.observation?.error ? (
+ <>
<HeaderButton
onClick={(e) => {
e.stopPropagation();
- props.onRetry();
+ props.onDelete();
}}
>
- <ArrowPath size="1.6em" onClick={props.onRetry}></ArrowPath>
+ <XMark size="1.6em" onClick={props.onDelete} />
</HeaderButton>
- ) : (
- <></>
- )}
+ {props.historyNode.observation?.error ? (
+ <HeaderButton
+ onClick={(e) => {
+ e.stopPropagation();
+ props.onRetry();
+ }}
+ >
+ <ArrowPath size="1.6em" onClick={props.onRetry} />
+ </HeaderButton>
+ ) : (
+ <></>
+ )}
+ </>
</HeaderDiv>
</GradientBorder>
<ContentDiv hidden={!open}>
@@ -182,7 +191,19 @@ function StepContainer(props: StepContainerProps) {
{props.historyNode.observation.error as string}
</pre>
) : (
- <ReactMarkdown key={1} className="overflow-scroll">
+ <ReactMarkdown
+ key={1}
+ className="overflow-scroll"
+ components={{
+ pre: ({ node, ...props }) => {
+ return (
+ <CodeBlock
+ children={props.children[0] as string}
+ ></CodeBlock>
+ );
+ },
+ }}
+ >
{props.historyNode.step.description as any}
</ReactMarkdown>
)}
diff --git a/extension/react-app/src/components/index.ts b/extension/react-app/src/components/index.ts
index 4966f3e8..525989af 100644
--- a/extension/react-app/src/components/index.ts
+++ b/extension/react-app/src/components/index.ts
@@ -143,3 +143,21 @@ export const appear = keyframes`
transform: translateY(0px);
}
`;
+
+export const HeaderButton = styled.button`
+ background-color: transparent;
+ border: 1px solid white;
+ border-radius: ${defaultBorderRadius};
+ cursor: pointer;
+ color: white;
+
+ &:hover {
+ background-color: white;
+ color: black;
+ }
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ gap: 4px;
+ padding: 1px;
+`;
diff --git a/extension/react-app/src/hooks/ContinueGUIClientProtocol.ts b/extension/react-app/src/hooks/ContinueGUIClientProtocol.ts
index 18a91de7..824bb086 100644
--- a/extension/react-app/src/hooks/ContinueGUIClientProtocol.ts
+++ b/extension/react-app/src/hooks/ContinueGUIClientProtocol.ts
@@ -8,6 +8,16 @@ abstract class AbstractContinueGUIClientProtocol {
abstract sendStepUserInput(input: string, index: number): void;
abstract onStateUpdate(state: any): void;
+
+ abstract onAvailableSlashCommands(
+ callback: (commands: { name: string; description: string }[]) => void
+ ): void;
+
+ abstract sendClear(): void;
+
+ abstract retryAtIndex(index: number): void;
+
+ abstract deleteAtIndex(index: number): void;
}
export default AbstractContinueGUIClientProtocol;
diff --git a/extension/react-app/src/hooks/useContinueGUIProtocol.ts b/extension/react-app/src/hooks/useContinueGUIProtocol.ts
index f27895fb..59397742 100644
--- a/extension/react-app/src/hooks/useContinueGUIProtocol.ts
+++ b/extension/react-app/src/hooks/useContinueGUIProtocol.ts
@@ -45,9 +45,27 @@ class ContinueGUIClientProtocol extends AbstractContinueGUIClientProtocol {
});
}
+ onAvailableSlashCommands(
+ callback: (commands: { name: string; description: string }[]) => void
+ ) {
+ this.messenger.onMessageType("available_slash_commands", (data: any) => {
+ if (data.commands) {
+ callback(data.commands);
+ }
+ });
+ }
+
+ sendClear() {
+ this.messenger.send("clear_history", {});
+ }
+
retryAtIndex(index: number) {
this.messenger.send("retry_at_index", { index });
}
+
+ deleteAtIndex(index: number) {
+ this.messenger.send("delete_at_index", { index });
+ }
}
export default ContinueGUIClientProtocol;
diff --git a/extension/react-app/src/tabs/chat/MessageDiv.tsx b/extension/react-app/src/tabs/chat/MessageDiv.tsx
index 1d7bb5f5..3543dd93 100644
--- a/extension/react-app/src/tabs/chat/MessageDiv.tsx
+++ b/extension/react-app/src/tabs/chat/MessageDiv.tsx
@@ -58,7 +58,9 @@ function MessageDiv(props: ChatMessage) {
}, [richContent, isStreaming]);
useEffect(() => {
- setRichContent([<ReactMarkdown key={1}>{props.content}</ReactMarkdown>]);
+ setRichContent([
+ <ReactMarkdown key={1} children={props.content}></ReactMarkdown>,
+ ]);
}, [props.content]);
return (
diff --git a/extension/react-app/src/tabs/gui.tsx b/extension/react-app/src/tabs/gui.tsx
index 5c75579b..a3a48410 100644
--- a/extension/react-app/src/tabs/gui.tsx
+++ b/extension/react-app/src/tabs/gui.tsx
@@ -4,6 +4,7 @@ import {
vscBackground,
Loader,
MainTextInput,
+ HeaderButton,
} from "../components";
import ContinueButton from "../components/ContinueButton";
import { useCallback, useEffect, useRef, useState } from "react";
@@ -11,7 +12,8 @@ import { History } from "../../../schema/History";
import { HistoryNode } from "../../../schema/HistoryNode";
import StepContainer from "../components/StepContainer";
import useContinueGUIProtocol from "../hooks/useWebsocket";
-
+import { BookOpen, Trash } from "@styled-icons/heroicons-outline";
+import ComboBox from "../components/ComboBox";
let TopGUIDiv = styled.div`
display: grid;
grid-template-columns: 1fr;
@@ -26,6 +28,14 @@ let UserInputQueueItem = styled.div`
text-align: center;
`;
+const TopBar = styled.div`
+ display: flex;
+ flex-direction: row;
+ justify-content: space-between;
+ padding: 8px;
+ align-items: center;
+`;
+
interface GUIProps {
firstObservation?: any;
}
@@ -33,15 +43,18 @@ interface GUIProps {
function GUI(props: GUIProps) {
const [waitingForSteps, setWaitingForSteps] = useState(false);
const [userInputQueue, setUserInputQueue] = useState<string[]>([]);
+ const [availableSlashCommands, setAvailableSlashCommands] = useState<
+ { name: string; description: string }[]
+ >([]);
const [history, setHistory] = useState<History | undefined>();
- // {
+ // {
// timeline: [
// {
// step: {
// name: "Waiting for user input",
// cmd: "python3 /Users/natesesti/Desktop/continue/extension/examples/python/main.py",
// description:
- // "Run `python3 /Users/natesesti/Desktop/continue/extension/examples/python/main.py`",
+ // "Run `python3 /Users/natesesti/Desktop/continue/extension/examples/python/main.py` and ```\nprint(sum(first, second))\n```\n- Testing\n- Testing 2\n- Testing 3",
// },
// observation: {
// title: "ERROR FOUND",
@@ -92,7 +105,7 @@ function GUI(props: GUIProps) {
// prompt:
// "I ran into this problem with my Python code:\n\n Traceback (most recent call last):\n File \"/Users/natesesti/Desktop/continue/extension/examples/python/main.py\", line 7, in <module>\n print(sum(first, second))\n ^^^^^^^^^^^^^^^^^^\n File \"/Users/natesesti/Desktop/continue/extension/examples/python/sum.py\", line 2, in sum\n return a + b\n ~~^~~\nTypeError: unsupported operand type(s) for +: 'int' and 'str'\n\n Below are the files that might need to be fixed:\n\n {code}\n\n This is what the code should be in order to avoid the problem:\n",
// description:
- // "Editing files: /Users/natesesti/Desktop/continue/extension/examples/python/main.py",
+ // "Run `python3 /Users/natesesti/Desktop/continue/extension/examples/python/main.py` and\n```python\nprint(sum(first, second))\n```\n- Testing\n- Testing 2\n- Testing 3",
// },
// output: [
// null,
@@ -154,22 +167,30 @@ function GUI(props: GUIProps) {
// output: [null, null],
// },
// ],
- // current_index: 0,
+ // current_index: 3,
// } as any);
const topGuiDivRef = useRef<HTMLDivElement>(null);
const client = useContinueGUIProtocol();
+ const [scrollTimeout, setScrollTimeout] = useState<NodeJS.Timeout | null>(
+ null
+ );
const scrollToBottom = useCallback(() => {
+ if (scrollTimeout) {
+ clearTimeout(scrollTimeout);
+ }
+ // Debounced smooth scroll to bottom of screen
if (topGuiDivRef.current) {
- setTimeout(() => {
+ const timeout = setTimeout(() => {
window.scrollTo({
top: window.outerHeight,
behavior: "smooth",
});
- }, 100);
+ }, 200);
+ setScrollTimeout(timeout);
}
- }, [topGuiDivRef.current]);
+ }, [topGuiDivRef.current, scrollTimeout]);
useEffect(() => {
console.log("CLIENT ON STATE UPDATE: ", client, client?.onStateUpdate);
@@ -181,13 +202,24 @@ function GUI(props: GUIProps) {
scrollToBottom();
});
+ client?.onAvailableSlashCommands((commands) => {
+ console.log("Received available slash commands: ", commands);
+ setAvailableSlashCommands(
+ commands.map((c) => {
+ return {
+ name: "/" + c.name,
+ description: c.description,
+ };
+ })
+ );
+ });
}, [client]);
useEffect(() => {
scrollToBottom();
}, [waitingForSteps]);
- const mainTextInputRef = useRef<HTMLTextAreaElement>(null);
+ const mainTextInputRef = useRef<HTMLInputElement>(null);
useEffect(() => {
if (mainTextInputRef.current) {
@@ -230,8 +262,6 @@ function GUI(props: GUIProps) {
return [...queue, input];
});
}
- mainTextInputRef.current.value = "";
- mainTextInputRef.current.style.height = "";
}
setWaitingForSteps(true);
@@ -253,6 +283,24 @@ function GUI(props: GUIProps) {
}
}}
>
+ <TopBar>
+ <a href="https://continue.dev/docs" className="no-underline">
+ <HeaderButton style={{ padding: "3px" }}>
+ Continue Docs
+ <BookOpen size="1.6em" />
+ </HeaderButton>
+ </a>
+ <HeaderButton
+ onClick={() => {
+ client?.sendClear();
+ }}
+ style={{ padding: "3px" }}
+ >
+ Clear History
+ <Trash size="1.6em" />
+ </HeaderButton>
+ </TopBar>
+
{typeof client === "undefined" && (
<>
<Loader></Loader>
@@ -280,6 +328,9 @@ function GUI(props: GUIProps) {
client?.retryAtIndex(index);
setWaitingForSteps(true);
}}
+ onDelete={() => {
+ client?.deleteAtIndex(index);
+ }}
/>
);
})}
@@ -291,7 +342,7 @@ function GUI(props: GUIProps) {
})}
</div>
- <MainTextInput
+ <ComboBox
disabled={
history
? history.timeline[history.current_index].step.name ===
@@ -299,22 +350,13 @@ function GUI(props: GUIProps) {
: false
}
ref={mainTextInputRef}
- onKeyDown={(e) => {
- if (e.key === "Enter") {
- onMainTextInput();
- e.stopPropagation();
- e.preventDefault();
- }
- }}
- rows={1}
- onChange={() => {
- const textarea = mainTextInputRef.current!;
- textarea.style.height = ""; /* Reset the height*/
- textarea.style.height = `${Math.min(
- textarea.scrollHeight - 15,
- 500
- )}px`;
+ onEnter={(e) => {
+ onMainTextInput();
+ e.stopPropagation();
+ e.preventDefault();
}}
+ onInputValueChange={() => {}}
+ items={availableSlashCommands}
/>
<ContinueButton onClick={onMainTextInput} />
</TopGUIDiv>
diff --git a/extension/scripts/continuedev-0.1.1-py3-none-any.whl b/extension/scripts/continuedev-0.1.1-py3-none-any.whl
index 42f3d4a3..3d7639a9 100644
--- a/extension/scripts/continuedev-0.1.1-py3-none-any.whl
+++ b/extension/scripts/continuedev-0.1.1-py3-none-any.whl
Binary files differ
diff --git a/extension/src/continueIdeClient.ts b/extension/src/continueIdeClient.ts
index 42671ade..92af6b10 100644
--- a/extension/src/continueIdeClient.ts
+++ b/extension/src/continueIdeClient.ts
@@ -13,6 +13,7 @@ import { FileEditWithFullContents } from "../schema/FileEditWithFullContents";
import fs = require("fs");
import { WebsocketMessenger } from "./util/messenger";
import { CapturedTerminal } from "./terminal/terminalEmulator";
+import { decorationManager } from "./decorations";
class IdeProtocolClient {
private messenger: WebsocketMessenger | null = null;
@@ -277,12 +278,13 @@ class IdeProtocolClient {
undefined,
vscode.ViewColumn.One
).then((editor) => {
- let range = new vscode.Range(
+ const range = new vscode.Range(
edit.range.start.line,
edit.range.start.character,
edit.range.end.line,
- edit.range.end.character + 1
+ edit.range.end.character
);
+
editor.edit((editBuilder) => {
this._makingEdit += 2; // editBuilder.replace takes 2 edits: delete and insert
editBuilder.replace(range, edit.replacement);
diff --git a/extension/src/decorations.ts b/extension/src/decorations.ts
index 456f0c10..d2c94135 100644
--- a/extension/src/decorations.ts
+++ b/extension/src/decorations.ts
@@ -94,15 +94,22 @@ class DecorationManager {
decorationTypes = new Map();
decorationTypes.set(key.decorationType, [key.options]);
this.editorToDecorations.set(key.editorUri, decorationTypes);
- }
-
- const decorations = decorationTypes.get(key.decorationType);
- if (!decorations) {
- decorationTypes.set(key.decorationType, [key.options]);
} else {
- decorations.push(key.options);
+ const decorations = decorationTypes.get(key.decorationType);
+ if (!decorations) {
+ decorationTypes.set(key.decorationType, [key.options]);
+ } else {
+ decorations.push(key.options);
+ }
}
+
this.rerenderDecorations(key.editorUri, key.decorationType);
+
+ vscode.window.onDidChangeTextEditorSelection((event) => {
+ if (event.textEditor.document.fileName === key.editorUri) {
+ this.deleteAllDecorations(key.editorUri);
+ }
+ });
}
deleteDecoration(key: DecorationKey) {