diff options
Diffstat (limited to 'extension')
| -rw-r--r-- | extension/package-lock.json | 64 | ||||
| -rw-r--r-- | extension/package.json | 83 | ||||
| -rw-r--r-- | extension/react-app/package-lock.json | 60 | ||||
| -rw-r--r-- | extension/react-app/package.json | 1 | ||||
| -rw-r--r-- | extension/react-app/src/components/CodeBlock.tsx | 1 | ||||
| -rw-r--r-- | extension/react-app/src/components/ComboBox.tsx | 146 | ||||
| -rw-r--r-- | extension/react-app/src/components/StepContainer.tsx | 67 | ||||
| -rw-r--r-- | extension/react-app/src/components/index.ts | 18 | ||||
| -rw-r--r-- | extension/react-app/src/hooks/ContinueGUIClientProtocol.ts | 10 | ||||
| -rw-r--r-- | extension/react-app/src/hooks/useContinueGUIProtocol.ts | 18 | ||||
| -rw-r--r-- | extension/react-app/src/tabs/chat/MessageDiv.tsx | 4 | ||||
| -rw-r--r-- | extension/react-app/src/tabs/gui.tsx | 96 | ||||
| -rw-r--r-- | extension/scripts/continuedev-0.1.1-py3-none-any.whl | bin | 74791 -> 78916 bytes | |||
| -rw-r--r-- | extension/src/continueIdeClient.ts | 6 | ||||
| -rw-r--r-- | extension/src/decorations.ts | 19 | 
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.whlBinary files differ 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 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) { | 
