diff options
Diffstat (limited to 'extension')
| -rw-r--r-- | extension/package-lock.json | 4 | ||||
| -rw-r--r-- | extension/package.json | 7 | ||||
| -rw-r--r-- | extension/react-app/src/components/ComboBox.tsx | 65 | ||||
| -rw-r--r-- | extension/react-app/src/components/InputAndButton.tsx | 10 | ||||
| -rw-r--r-- | extension/react-app/src/components/PillButton.tsx | 47 | ||||
| -rw-r--r-- | extension/react-app/src/components/StepContainer.tsx | 19 | ||||
| -rw-r--r-- | extension/react-app/src/components/TextDialog.tsx | 14 | ||||
| -rw-r--r-- | extension/react-app/src/components/index.ts | 23 | ||||
| -rw-r--r-- | extension/react-app/src/index.css | 4 | ||||
| -rw-r--r-- | extension/react-app/src/pages/gui.tsx | 11 | ||||
| -rw-r--r-- | extension/src/activation/activate.ts | 2 | ||||
| -rw-r--r-- | extension/src/activation/environmentSetup.ts | 8 | ||||
| -rw-r--r-- | extension/src/bridge.ts | 6 | ||||
| -rw-r--r-- | extension/src/commands.ts | 7 | ||||
| -rw-r--r-- | extension/src/diffs.ts | 46 | ||||
| -rw-r--r-- | extension/src/lang-server/codeActions.ts | 55 | ||||
| -rw-r--r-- | extension/src/suggestions.ts | 60 | 
17 files changed, 217 insertions, 171 deletions
diff --git a/extension/package-lock.json b/extension/package-lock.json index 6f777c72..e67fa950 100644 --- a/extension/package-lock.json +++ b/extension/package-lock.json @@ -1,12 +1,12 @@  {    "name": "continue", -  "version": "0.0.174", +  "version": "0.0.178",    "lockfileVersion": 2,    "requires": true,    "packages": {      "": {        "name": "continue", -      "version": "0.0.174", +      "version": "0.0.178",        "license": "Apache-2.0",        "dependencies": {          "@electron/rebuild": "^3.2.10", diff --git a/extension/package.json b/extension/package.json index 9fe38f7f..121423ed 100644 --- a/extension/package.json +++ b/extension/package.json @@ -14,7 +14,7 @@    "displayName": "Continue",    "pricing": "Free",    "description": "The open-source coding autopilot", -  "version": "0.0.174", +  "version": "0.0.178",    "publisher": "Continue",    "engines": {      "vscode": "^1.67.0" @@ -106,6 +106,11 @@          "command": "continue.quickTextEntry",          "category": "Continue",          "title": "Quick Text Entry" +      }, +      { +        "command": "continue.quickFix", +        "category": "Continue", +        "title": "Quick Fix"        }      ],      "keybindings": [ diff --git a/extension/react-app/src/components/ComboBox.tsx b/extension/react-app/src/components/ComboBox.tsx index f11e07af..f327e3a3 100644 --- a/extension/react-app/src/components/ComboBox.tsx +++ b/extension/react-app/src/components/ComboBox.tsx @@ -6,6 +6,7 @@ import {    lightGray,    secondaryDark,    vscBackground, +  vscForeground,  } from ".";  import CodeBlock from "./CodeBlock";  import PillButton from "./PillButton"; @@ -37,21 +38,6 @@ const EmptyPillDiv = styled.div`    }  `; -const ContextDropdown = styled.div` -  position: absolute; -  padding: 4px; -  width: calc(100% - 16px - 8px); -  background-color: ${secondaryDark}; -  color: white; -  border-bottom-right-radius: ${defaultBorderRadius}; -  border-bottom-left-radius: ${defaultBorderRadius}; -  /* border: 1px solid white; */ -  border-top: none; -  margin: 8px; -  outline: 1px solid orange; -  z-index: 5; -`; -  const MainTextInput = styled.textarea`    resize: none; @@ -63,7 +49,7 @@ const MainTextInput = styled.textarea`    height: auto;    width: 100%;    background-color: ${secondaryDark}; -  color: white; +  color: ${vscForeground};    z-index: 1;    border: 1px solid transparent; @@ -86,14 +72,15 @@ const Ul = styled.ul<{    position: absolute;    background: ${vscBackground};    background-color: ${secondaryDark}; -  color: white; +  color: ${vscForeground};    max-height: ${UlMaxHeight}px; +  width: calc(100% - 16px);    overflow-y: scroll;    overflow-x: hidden;    padding: 0;    ${({ hidden }) => hidden && "display: none;"}    border-radius: ${defaultBorderRadius}; -  border: 0.5px solid gray; +  outline: 0.5px solid gray;    z-index: 2;    // Get rid of scrollbar and its padding    scrollbar-width: none; @@ -109,6 +96,7 @@ const Li = styled.li<{    selected: boolean;    isLastItem: boolean;  }>` +  background-color: ${secondaryDark};    ${({ highlighted }) => highlighted && "background: #ff000066;"}    ${({ selected }) => selected && "font-weight: bold;"}      padding: 0.5rem 0.75rem; @@ -138,10 +126,6 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => {    // The position of the current command you are typing now, so the one that will be appended to history once you press enter    const [positionInHistory, setPositionInHistory] = React.useState<number>(0);    const [items, setItems] = React.useState(props.items); -  const [hoveringButton, setHoveringButton] = React.useState(false); -  const [hoveringContextDropdown, setHoveringContextDropdown] = -    React.useState(false); -  const [pinned, setPinned] = useState(false);    const [highlightedCodeSections, setHighlightedCodeSections] = React.useState(      props.highlightedCodeSections || []    ); @@ -236,6 +220,9 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => {                  ? "Editing such a large range may be slow"                  : undefined              } +            onlyShowDelete={ +              highlightedCodeSections.length <= 1 || section.editing +            }              editing={section.editing}              pinned={section.pinned}              index={idx} @@ -253,15 +240,6 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => {                  return newSections;                });              }} -            onHover={(val: boolean) => { -              if (val) { -                setHoveringButton(val); -              } else { -                setTimeout(() => { -                  setHoveringButton(val); -                }, 100); -              } -            }}            />          ))}          {props.highlightedCodeSections.length > 0 && @@ -271,11 +249,11 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => {                  props.onToggleAddContext();                }}              > -              Highlight to Add Context +              Highlight code section              </EmptyPillDiv>            ) : (              <HeaderButtonWithText -              text="Add to Context" +              text="Add more code to context"                onClick={() => {                  props.onToggleAddContext();                }} @@ -287,7 +265,7 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => {        <div className="flex px-2" ref={divRef} hidden={!downshiftProps.isOpen}>          <MainTextInput            disabled={props.disabled} -          placeholder={`Ask a question, give instructions, or type '/' to see slash commands. ${getMetaKeyLabel()}⏎ to edit.`} +          placeholder={`Ask a question, give instructions, or type '/' to see slash commands`}            {...getInputProps({              onChange: (e) => {                const target = e.target as HTMLTextAreaElement; @@ -361,6 +339,7 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => {            })}            showAbove={showAbove()}            ulHeightPixels={ulRef.current?.getBoundingClientRect().height || 0} +          hidden={!downshiftProps.isOpen || items.length === 0}          >            {downshiftProps.isOpen &&              items.map((item, index) => ( @@ -387,24 +366,6 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => {              Inserting at cursor            </div>          )} -      <ContextDropdown -        onMouseEnter={() => { -          setHoveringContextDropdown(true); -        }} -        onMouseLeave={() => { -          setHoveringContextDropdown(false); -        }} -        hidden={true || (!hoveringContextDropdown && !hoveringButton)} -      > -        {highlightedCodeSections.map((section, idx) => ( -          <> -            <p>{section.display_name}</p> -            <CodeBlock showCopy={false} key={idx}> -              {section.range.contents} -            </CodeBlock> -          </> -        ))} -      </ContextDropdown>      </>    );  }); diff --git a/extension/react-app/src/components/InputAndButton.tsx b/extension/react-app/src/components/InputAndButton.tsx index 0a8592f2..8019d014 100644 --- a/extension/react-app/src/components/InputAndButton.tsx +++ b/extension/react-app/src/components/InputAndButton.tsx @@ -1,6 +1,6 @@  import React, { useRef } from "react";  import styled from "styled-components"; -import { vscBackground } from "."; +import { vscBackground, vscForeground } from ".";  interface InputAndButtonProps {    onUserInput: (input: string) => void; @@ -16,7 +16,7 @@ const Input = styled.input`    padding: 0.5rem;    border: 1px solid white;    background-color: ${vscBackground}; -  color: white; +  color: ${vscForeground};    border-radius: 4px;    border-top-right-radius: 0;    border-bottom-right-radius: 0; @@ -27,7 +27,7 @@ const Button = styled.button`    padding: 0.5rem;    border: 1px solid white;    background-color: ${vscBackground}; -  color: white; +  color: ${vscForeground};    border-radius: 4px;    border-top-left-radius: 0;    border-bottom-left-radius: 0; @@ -35,8 +35,8 @@ const Button = styled.button`    cursor: pointer;    &:hover { -    background-color: white; -    color: black; +    background-color: ${vscForeground}; +    color: ${vscBackground};    }  `; diff --git a/extension/react-app/src/components/PillButton.tsx b/extension/react-app/src/components/PillButton.tsx index d9d779d1..c24dba83 100644 --- a/extension/react-app/src/components/PillButton.tsx +++ b/extension/react-app/src/components/PillButton.tsx @@ -1,6 +1,11 @@  import { useContext, useState } from "react";  import styled from "styled-components"; -import { StyledTooltip, defaultBorderRadius, secondaryDark } from "."; +import { +  StyledTooltip, +  defaultBorderRadius, +  secondaryDark, +  vscForeground, +} from ".";  import {    Trash,    PaintBrush, @@ -10,7 +15,7 @@ import { GUIClientContext } from "../App";  const Button = styled.button`    border: none; -  color: white; +  color: ${vscForeground};    background-color: ${secondaryDark};    border-radius: ${defaultBorderRadius};    padding: 8px; @@ -27,7 +32,6 @@ const GridDiv = styled.div`    height: 100%;    display: grid;    grid-gap: 0; -  grid-template-columns: 1fr 1fr;    align-items: center;    border-radius: ${defaultBorderRadius}; @@ -69,6 +73,7 @@ interface PillButtonProps {    editing: boolean;    pinned: boolean;    warning?: string; +  onlyShowDelete?: boolean;  }  const PillButton = (props: PillButtonProps) => { @@ -105,19 +110,25 @@ const PillButton = (props: PillButtonProps) => {            }}          >            {isHovered && ( -            <GridDiv> -              <ButtonDiv -                data-tooltip-id={`edit-${props.index}`} -                backgroundColor={"#8800aa55"} -                onClick={() => { -                  client?.setEditingAtIndices([props.index]); -                }} -              > -                <PaintBrush -                  style={{ margin: "auto" }} -                  width="1.6em" -                ></PaintBrush> -              </ButtonDiv> +            <GridDiv +              style={{ +                gridTemplateColumns: props.onlyShowDelete ? "1fr" : "1fr 1fr", +              }} +            > +              {props.onlyShowDelete || ( +                <ButtonDiv +                  data-tooltip-id={`edit-${props.index}`} +                  backgroundColor={"#8800aa55"} +                  onClick={() => { +                    client?.setEditingAtIndices([props.index]); +                  }} +                > +                  <PaintBrush +                    style={{ margin: "auto" }} +                    width="1.6em" +                  ></PaintBrush> +                </ButtonDiv> +              )}                {/* <ButtonDiv              data-tooltip-id={`pin-${props.index}`} @@ -148,8 +159,8 @@ const PillButton = (props: PillButtonProps) => {          </Button>          <StyledTooltip id={`edit-${props.index}`}>            {props.editing -            ? "Editing this range (with rest of file as context)" -            : "Edit this range"} +            ? "Editing this section (with entire file as context)" +            : "Edit this section"}          </StyledTooltip>          <StyledTooltip id={`delete-${props.index}`}>Delete</StyledTooltip>          {props.warning && ( diff --git a/extension/react-app/src/components/StepContainer.tsx b/extension/react-app/src/components/StepContainer.tsx index 93bdbc89..9ab7430c 100644 --- a/extension/react-app/src/components/StepContainer.tsx +++ b/extension/react-app/src/components/StepContainer.tsx @@ -6,6 +6,7 @@ import {    secondaryDark,    vscBackground,    vscBackgroundTransparent, +  vscForeground,  } from ".";  import {    ChevronDown, @@ -52,12 +53,7 @@ const StepContainerDiv = styled.div<{ open: boolean }>`  `;  const HeaderDiv = styled.div<{ error: boolean; loading: boolean }>` -  background-color: ${(props) => -    props.error -      ? "#522" -      : props.loading -      ? vscBackgroundTransparent -      : vscBackground}; +  background-color: ${(props) => (props.error ? "#522" : vscBackground)};    display: grid;    grid-template-columns: 1fr auto auto;    grid-gap: 8px; @@ -120,20 +116,22 @@ const StyledMarkdownPreview = styled(MarkdownPreview)`    }    code { -    color: #f69292; +    color: #f78383;      word-wrap: break-word; +    border-radius: ${defaultBorderRadius}; +    background-color: ${secondaryDark};    }    pre > code {      background-color: ${secondaryDark}; -    color: white; +    color: ${vscForeground};    }    background-color: ${vscBackground};    font-family: "Lexend", sans-serif;    font-size: 13px;    padding: 8px; -  color: white; +  color: ${vscForeground};  `;  // #endregion @@ -267,6 +265,9 @@ function StepContainer(props: StepContainerProps) {            ) : (              <StyledMarkdownPreview                source={props.historyNode.step.description || ""} +              wrapperElement={{ +                "data-color-mode": "dark", +              }}              />            )}          </ContentDiv> diff --git a/extension/react-app/src/components/TextDialog.tsx b/extension/react-app/src/components/TextDialog.tsx index 646d6846..cba3852d 100644 --- a/extension/react-app/src/components/TextDialog.tsx +++ b/extension/react-app/src/components/TextDialog.tsx @@ -1,7 +1,7 @@  // Write a component that displays a dialog box with a text field and a button.  import React, { useEffect, useState } from "react";  import styled from "styled-components"; -import { Button, buttonColor, secondaryDark, vscBackground } from "."; +import { Button, secondaryDark, vscBackground, vscForeground } from ".";  import { isMetaEquivalentKeyPressed } from "../util";  const ScreenCover = styled.div` @@ -21,13 +21,13 @@ const DialogContainer = styled.div`  `;  const Dialog = styled.div` -  background-color: white; +  color: ${vscForeground}; +  background-color: ${vscBackground};    border-radius: 8px;    padding: 8px;    display: flex;    flex-direction: column; -  /* box-shadow: 0 0 10px 0 rgba(255, 255, 255, 0.5); */ -  border: 2px solid ${buttonColor}; +  box-shadow: 0 0 10px 0 ${vscForeground};    width: fit-content;    margin: auto;  `; @@ -38,14 +38,16 @@ const TextArea = styled.textarea`    padding: 8px;    outline: 1px solid black;    resize: none; +  background-color: ${secondaryDark}; +  color: ${vscForeground};    &:focus { -    outline: 1px solid ${buttonColor}; +    outline: 1px solid ${vscForeground};    }  `;  const P = styled.p` -  color: black; +  color: ${vscForeground};    margin: 8px auto;  `; diff --git a/extension/react-app/src/components/index.ts b/extension/react-app/src/components/index.ts index 9ae0f097..cb5e7915 100644 --- a/extension/react-app/src/components/index.ts +++ b/extension/react-app/src/components/index.ts @@ -3,12 +3,16 @@ import styled, { keyframes } from "styled-components";  export const defaultBorderRadius = "5px";  export const lightGray = "rgb(100 100 100)"; -export const secondaryDark = "rgb(45 45 45)"; -export const vscBackground = "rgb(30 30 30)"; +// export const secondaryDark = "rgb(45 45 45)"; +// export const vscBackground = "rgb(30 30 30)";  export const vscBackgroundTransparent = "#1e1e1ede";  export const buttonColor = "rgb(113 28 59)";  export const buttonColorHover = "rgb(113 28 59 0.67)"; +export const secondaryDark = "var(--vscode-textBlockQuote-background)"; +export const vscBackground = "var(--vscode-editor-background)"; +export const vscForeground = "var(--vscode-editor-foreground)"; +  export const Button = styled.button`    padding: 10px 12px;    margin: 8px 0; @@ -46,8 +50,8 @@ export const TextArea = styled.textarea`    resize: vertical;    padding: 4px; -  caret-color: white; -  color: white; +  caret-color: ${vscForeground}; +  color: #{vscForeground};    &:focus {      outline: 1px solid ${buttonColor}; @@ -120,7 +124,7 @@ export const MainTextInput = styled.textarea`    border: 1px solid #ccc;    margin: 8px 8px;    background-color: ${vscBackground}; -  color: white; +  color: ${vscForeground};    outline: 1px solid orange;    resize: none;  `; @@ -137,8 +141,9 @@ export const appear = keyframes`  `;  export const HeaderButton = styled.button<{ inverted: boolean | undefined }>` -  background-color: ${({ inverted }) => (inverted ? "white" : "transparent")}; -  color: ${({ inverted }) => (inverted ? "black" : "white")}; +  background-color: ${({ inverted }) => +    inverted ? vscForeground : "transparent"}; +  color: ${({ inverted }) => (inverted ? vscBackground : vscForeground)};    border: none;    border-radius: ${defaultBorderRadius}; @@ -146,7 +151,9 @@ export const HeaderButton = styled.button<{ inverted: boolean | undefined }>`    &:hover {      background-color: ${({ inverted }) => -      typeof inverted === "undefined" || inverted ? lightGray : "transparent"}; +      typeof inverted === "undefined" || inverted +        ? secondaryDark +        : "transparent"};    }    display: flex;    align-items: center; diff --git a/extension/react-app/src/index.css b/extension/react-app/src/index.css index 6e33c89c..bac7fe97 100644 --- a/extension/react-app/src/index.css +++ b/extension/react-app/src/index.css @@ -14,13 +14,13 @@ html,  body,  #root {    height: 100%; -  background-color: var(--vsc-background); +  background-color: var(--vscode-editor-background);    font-family: "Lexend", sans-serif;  }  body {    padding: 0; -  color: white; +  color: var(--vscode-editor-foreground);    padding: 0px;    margin: 0px;    height: 100%; diff --git a/extension/react-app/src/pages/gui.tsx b/extension/react-app/src/pages/gui.tsx index 64207487..c35cf21b 100644 --- a/extension/react-app/src/pages/gui.tsx +++ b/extension/react-app/src/pages/gui.tsx @@ -1,5 +1,9 @@  import styled from "styled-components"; -import { defaultBorderRadius } from "../components"; +import { +  defaultBorderRadius, +  vscBackground, +  vscForeground, +} from "../components";  import Loader from "../components/Loader";  import ContinueButton from "../components/ContinueButton";  import { FullState, HighlightedRangeContext } from "../../../schema/FullState"; @@ -371,12 +375,13 @@ function GUI(props: GUIProps) {          style={{            position: "fixed",            bottom: "50px", -          backgroundColor: "white", -          color: "black", +          backgroundColor: vscBackground, +          color: vscForeground,            borderRadius: defaultBorderRadius,            padding: "16px",            margin: "16px",            zIndex: 100, +          boxShadow: `0px 0px 10px 0px ${vscForeground}`,          }}          hidden={!showDataSharingInfo}        > diff --git a/extension/src/activation/activate.ts b/extension/src/activation/activate.ts index cd885b12..5c6ffa02 100644 --- a/extension/src/activation/activate.ts +++ b/extension/src/activation/activate.ts @@ -10,6 +10,7 @@ import {    startContinuePythonServer,  } from "./environmentSetup";  import fetch from "node-fetch"; +import registerQuickFixProvider from "../lang-server/codeActions";  // import { CapturedTerminal } from "../terminal/terminalEmulator";  const PACKAGE_JSON_RAW_GITHUB_URL = @@ -55,6 +56,7 @@ export async function activateExtension(context: vscode.ExtensionContext) {    sendTelemetryEvent(TelemetryEvent.ExtensionActivated);    registerAllCodeLensProviders(context);    registerAllCommands(context); +  registerQuickFixProvider();    // Initialize IDE Protocol Client    const serverUrl = getContinueServerUrl(); diff --git a/extension/src/activation/environmentSetup.ts b/extension/src/activation/environmentSetup.ts index df609a34..69a3b75a 100644 --- a/extension/src/activation/environmentSetup.ts +++ b/extension/src/activation/environmentSetup.ts @@ -400,6 +400,14 @@ function serverPath(): string {    return sPath;  } +export function devDataPath(): string { +  const sPath = path.join(getContinueGlobalPath(), "dev_data"); +  if (!fs.existsSync(sPath)) { +    fs.mkdirSync(sPath); +  } +  return sPath; +} +  function serverVersionPath(): string {    return path.join(serverPath(), "server_version.txt");  } diff --git a/extension/src/bridge.ts b/extension/src/bridge.ts index 7e6398be..d614ace4 100644 --- a/extension/src/bridge.ts +++ b/extension/src/bridge.ts @@ -1,11 +1,7 @@  import fetch from "node-fetch";  import * as path from "path";  import * as vscode from "vscode"; -import { -  Configuration, -  DebugApi, -  UnittestApi, -} from "./client"; +import { Configuration, DebugApi, UnittestApi } from "./client";  import { convertSingleToDoubleQuoteJSON } from "./util/util";  import { getExtensionUri } from "./util/vscode";  import { extensionContext } from "./activation/activate"; diff --git a/extension/src/commands.ts b/extension/src/commands.ts index 888f01ed..2b7f4c0c 100644 --- a/extension/src/commands.ts +++ b/extension/src/commands.ts @@ -34,6 +34,13 @@ const commandsMap: { [command: string]: (...args: any) => any } = {    "continue.rejectDiff": rejectDiffCommand,    "continue.acceptAllSuggestions": acceptAllSuggestionsCommand,    "continue.rejectAllSuggestions": rejectAllSuggestionsCommand, +  "continue.quickFix": async (message: string, code: string, edit: boolean) => { +    ideProtocolClient.sendMainUserInput( +      `${ +        edit ? "/edit " : "" +      }${code}\n\nHow do I fix this problem in the above code?: ${message}` +    ); +  },    "continue.focusContinueInput": async () => {      if (focusedOnContinueInput) {        vscode.commands.executeCommand("workbench.action.focusActiveEditorGroup"); diff --git a/extension/src/diffs.ts b/extension/src/diffs.ts index 2860258d..0bab326a 100644 --- a/extension/src/diffs.ts +++ b/extension/src/diffs.ts @@ -4,6 +4,7 @@ import * as fs from "fs";  import * as vscode from "vscode";  import { extensionContext, ideProtocolClient } from "./activation/activate";  import { getMetaKeyLabel } from "./util/util"; +import { devDataPath } from "./activation/environmentSetup";  interface DiffInfo {    originalFilepath: string; @@ -13,7 +14,9 @@ interface DiffInfo {    range: vscode.Range;  } -export const DIFF_DIRECTORY = path.join(os.homedir(), ".continue", "diffs").replace(/^C:/, "c:"); +export const DIFF_DIRECTORY = path +  .join(os.homedir(), ".continue", "diffs") +  .replace(/^C:/, "c:");  class DiffManager {    // Create a temporary file in the global .continue directory which displays the updated version @@ -222,6 +225,8 @@ class DiffManager {          );          this.cleanUpDiff(diffInfo);        }); + +    recordAcceptReject(true, diffInfo);    }    rejectDiff(newFilepath?: string) { @@ -251,11 +256,50 @@ class DiffManager {        .then(() => {          this.cleanUpDiff(diffInfo);        }); + +    recordAcceptReject(false, diffInfo);    }  }  export const diffManager = new DiffManager(); +function recordAcceptReject(accepted: boolean, diffInfo: DiffInfo) { +  const collectOn = vscode.workspace +    .getConfiguration("continue") +    .get<boolean>("dataSwitch"); + +  if (collectOn) { +    const devDataDir = devDataPath(); +    const suggestionsPath = path.join(devDataDir, "suggestions.json"); + +    // Initialize suggestions list +    let suggestions = []; + +    // Check if suggestions.json exists +    if (fs.existsSync(suggestionsPath)) { +      const rawData = fs.readFileSync(suggestionsPath, "utf-8"); +      suggestions = JSON.parse(rawData); +    } + +    // Add the new suggestion to the list +    suggestions.push({ +      accepted, +      timestamp: Date.now(), +      suggestion: diffInfo.originalFilepath, +    }); + +    // Send the suggestion to the server +    ideProtocolClient.sendAcceptRejectSuggestion(accepted); + +    // Write the updated suggestions back to the file +    fs.writeFileSync( +      suggestionsPath, +      JSON.stringify(suggestions, null, 4), +      "utf-8" +    ); +  } +} +  export async function acceptDiffCommand(newFilepath?: string) {    diffManager.acceptDiff(newFilepath);    ideProtocolClient.sendAcceptRejectDiff(true); diff --git a/extension/src/lang-server/codeActions.ts b/extension/src/lang-server/codeActions.ts new file mode 100644 index 00000000..f0d61ace --- /dev/null +++ b/extension/src/lang-server/codeActions.ts @@ -0,0 +1,55 @@ +import * as vscode from "vscode"; + +class ContinueQuickFixProvider implements vscode.CodeActionProvider { +  public static readonly providedCodeActionKinds = [ +    vscode.CodeActionKind.QuickFix, +  ]; + +  provideCodeActions( +    document: vscode.TextDocument, +    range: vscode.Range | vscode.Selection, +    context: vscode.CodeActionContext, +    token: vscode.CancellationToken +  ): vscode.ProviderResult<(vscode.Command | vscode.CodeAction)[]> { +    if (context.diagnostics.length === 0) { +      return []; +    } + +    const createQuickFix = (edit: boolean) => { +      const diagnostic = context.diagnostics[0]; +      const quickFix = new vscode.CodeAction( +        edit ? "Fix with Continue" : "Ask Continue", +        vscode.CodeActionKind.QuickFix +      ); +      quickFix.isPreferred = false; +      const surroundingRange = new vscode.Range( +        Math.max(0, range.start.line - 3), +        0, +        Math.min(document.lineCount, range.end.line + 3), +        0 +      ); +      quickFix.command = { +        command: "continue.quickFix", +        title: "Continue Quick Fix", +        arguments: [ +          diagnostic.message, +          document.getText(surroundingRange), +          edit, +        ], +      }; +      return quickFix; +    }; +    return [createQuickFix(true), createQuickFix(false)]; +  } +} + +export default function registerQuickFixProvider() { +  // In your extension's activate function: +  vscode.languages.registerCodeActionsProvider( +    { language: "*" }, +    new ContinueQuickFixProvider(), +    { +      providedCodeActionKinds: ContinueQuickFixProvider.providedCodeActionKinds, +    } +  ); +} diff --git a/extension/src/suggestions.ts b/extension/src/suggestions.ts index 6e5a444f..c2373223 100644 --- a/extension/src/suggestions.ts +++ b/extension/src/suggestions.ts @@ -1,9 +1,7 @@  import * as vscode from "vscode";  import { sendTelemetryEvent, TelemetryEvent } from "./telemetry";  import { openEditorAndRevealRange } from "./util/vscode"; -import { translate, readFileAtRange } from "./util/vscode"; -import * as fs from "fs"; -import * as path from "path"; +import { translate } from "./util/vscode";  import { registerAllCodeLensProviders } from "./lang-server/codeLens";  import { extensionContext, ideProtocolClient } from "./activation/activate"; @@ -214,62 +212,6 @@ function selectSuggestion(          : suggestion.newRange;    } -  let workspaceDir = vscode.workspace.workspaceFolders -    ? vscode.workspace.workspaceFolders[0]?.uri.fsPath -    : undefined; - -  let collectOn = vscode.workspace -    .getConfiguration("continue") -    .get<boolean>("dataSwitch"); - -  if (workspaceDir && collectOn) { -    let continueDir = path.join(workspaceDir, ".continue"); - -    // Check if .continue directory doesn't exists -    if (!fs.existsSync(continueDir)) { -      fs.mkdirSync(continueDir); -    } - -    let suggestionsPath = path.join(continueDir, "suggestions.json"); - -    // Initialize suggestions list -    let suggestions = []; - -    // Check if suggestions.json exists -    if (fs.existsSync(suggestionsPath)) { -      let rawData = fs.readFileSync(suggestionsPath, "utf-8"); -      suggestions = JSON.parse(rawData); -    } - -    const accepted = -      accept === "new" || (accept === "selected" && suggestion.newSelected); -    suggestions.push({ -      accepted, -      timestamp: Date.now(), -      suggestion: suggestion.newContent, -    }); -    ideProtocolClient.sendAcceptRejectSuggestion(accepted); - -    // Write the updated suggestions back to the file -    fs.writeFileSync( -      suggestionsPath, -      JSON.stringify(suggestions, null, 4), -      "utf-8" -    ); - -    // If it's not already there, add .continue to .gitignore -    const gitignorePath = path.join(workspaceDir, ".gitignore"); -    if (fs.existsSync(gitignorePath)) { -      const gitignoreData = fs.readFileSync(gitignorePath, "utf-8"); -      const gitIgnoreLines = gitignoreData.split("\n"); -      if (!gitIgnoreLines.includes(".continue")) { -        fs.appendFileSync(gitignorePath, "\n.continue\n"); -      } -    } else { -      fs.writeFileSync(gitignorePath, ".continue\n"); -    } -  } -    rangeToDelete = new vscode.Range(      rangeToDelete.start,      new vscode.Position(rangeToDelete.end.line, 0)  | 
