diff options
-rw-r--r-- | continuedev/src/continuedev/core/autopilot.py | 2 | ||||
-rw-r--r-- | continuedev/src/continuedev/server/ide.py | 7 | ||||
-rw-r--r-- | continuedev/src/continuedev/steps/core/core.py | 22 | ||||
-rw-r--r-- | extension/package-lock.json | 4 | ||||
-rw-r--r-- | extension/package.json | 2 | ||||
-rw-r--r-- | extension/react-app/src/components/ComboBox.tsx | 62 | ||||
-rw-r--r-- | extension/react-app/src/components/ContinueButton.tsx | 3 | ||||
-rw-r--r-- | extension/react-app/src/components/StepContainer.tsx | 3 | ||||
-rw-r--r-- | extension/react-app/src/tabs/gui.tsx | 26 | ||||
-rw-r--r-- | extension/src/continueIdeClient.ts | 4 | ||||
-rw-r--r-- | extension/src/diffs.ts | 3 |
11 files changed, 73 insertions, 65 deletions
diff --git a/continuedev/src/continuedev/core/autopilot.py b/continuedev/src/continuedev/core/autopilot.py index 6e4326f0..02fd61de 100644 --- a/continuedev/src/continuedev/core/autopilot.py +++ b/continuedev/src/continuedev/core/autopilot.py @@ -153,7 +153,7 @@ class Autopilot(ContinueBaseModel): async def handle_highlighted_code(self, range_in_files: List[RangeInFileWithContents]): # If un-highlighting, then remove the range - if len(self._highlighted_ranges) == 1 and len(range_in_files) <= 1 and (len(range_in_files) == 0 or range_in_files[0].range.start == range_in_files[0].range.end): + if len(self._highlighted_ranges) == 1 and len(range_in_files) <= 1 and (len(range_in_files) == 0 or range_in_files[0].range.start == range_in_files[0].range.end) and not self._adding_highlighted_code: self._highlighted_ranges = [] await self.update_subscribers() return diff --git a/continuedev/src/continuedev/server/ide.py b/continuedev/src/continuedev/server/ide.py index ea355d3c..d16bd449 100644 --- a/continuedev/src/continuedev/server/ide.py +++ b/continuedev/src/continuedev/server/ide.py @@ -148,6 +148,8 @@ class IdeProtocolServer(AbstractIdeProtocolServer): self.onCommandOutput(output) elif message_type == "acceptRejectSuggestion": self.onAcceptRejectSuggestion(data["accepted"]) + elif message_type == "acceptRejectDiff": + self.onAcceptRejectDiff(data["accepted"]) elif message_type in ["highlightedCode", "openFiles", "readFile", "editFile", "workspaceDirectory", "getUserSecret", "runCommand", "uniqueId"]: self.sub_queue.post(message_type, data) else: @@ -219,6 +221,11 @@ class IdeProtocolServer(AbstractIdeProtocolServer): "accepted": accepted }) + def onAcceptRejectDiff(self, accepted: bool): + capture_event(self.unique_id, "accept_reject_diff", { + "accepted": accepted + }) + def onFileSystemUpdate(self, update: FileSystemEdit): # Access to Autopilot (so SessionManager) pass diff --git a/continuedev/src/continuedev/steps/core/core.py b/continuedev/src/continuedev/steps/core/core.py index 5577c49a..f22297ae 100644 --- a/continuedev/src/continuedev/steps/core/core.py +++ b/continuedev/src/continuedev/steps/core/core.py @@ -450,40 +450,40 @@ class DefaultModelEditCodeStep(Step): chunk_lines.pop() # because this will be an empty string else: unfinished_line = chunk_lines.pop() - lines.extend(map(lambda l: common_whitespace + l, chunk_lines)) - - if True: - await sendDiffUpdate(lines + [common_whitespace + unfinished_line], sdk) # Deal with newly accumulated lines - for line in chunk_lines: + for i in range(len(chunk_lines)): # Trailing whitespace doesn't matter - line = line.rstrip() + chunk_lines[i] = chunk_lines[i].rstrip() + chunk_lines[i] = common_whitespace + chunk_lines[i] # Lines that should signify the end of generation - if self.is_end_line(line): + if self.is_end_line(chunk_lines[i]): break # Lines that should be ignored, like the <> tags - elif self.line_to_be_ignored(line, completion_lines_covered == 0): + elif self.line_to_be_ignored(chunk_lines[i], completion_lines_covered == 0): continue # Check if we are currently just copying the prefix - elif (lines_of_prefix_copied > 0 or completion_lines_covered == 0) and lines_of_prefix_copied < len(file_prefix.splitlines()) and line == full_file_contents_lines[lines_of_prefix_copied]: + elif (lines_of_prefix_copied > 0 or completion_lines_covered == 0) and lines_of_prefix_copied < len(file_prefix.splitlines()) and chunk_lines[i] == full_file_contents_lines[lines_of_prefix_copied]: # This is a sketchy way of stopping it from repeating the file_prefix. Is a bug if output happens to have a matching line lines_of_prefix_copied += 1 continue # Because really short lines might be expected to be repeated, this is only a !heuristic! # Stop when it starts copying the file_suffix - elif line.strip() == line_below_highlighted_range.strip() and len(line.strip()) > 4 and not (len(original_lines_below_previous_blocks) > 0 and line.strip() == original_lines_below_previous_blocks[0].strip()): + elif chunk_lines[i].strip() == line_below_highlighted_range.strip() and len(chunk_lines[i].strip()) > 4 and not (len(original_lines_below_previous_blocks) > 0 and chunk_lines[i].strip() == original_lines_below_previous_blocks[0].strip()): repeating_file_suffix = True break # If none of the above, insert the line! if False: - await handle_generated_line(line) + await handle_generated_line(chunk_lines[i]) + lines.append(chunk_lines[i]) completion_lines_covered += 1 current_line_in_file += 1 + await sendDiffUpdate(lines + [common_whitespace + unfinished_line], sdk) + # Add the unfinished line if unfinished_line != "" and not self.line_to_be_ignored(unfinished_line, completion_lines_covered == 0) and not self.is_end_line(unfinished_line): unfinished_line = common_whitespace + unfinished_line diff --git a/extension/package-lock.json b/extension/package-lock.json index cb11c5a8..915c228e 100644 --- a/extension/package-lock.json +++ b/extension/package-lock.json @@ -1,12 +1,12 @@ { "name": "continue", - "version": "0.0.115", + "version": "0.0.116", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "continue", - "version": "0.0.115", + "version": "0.0.116", "license": "Apache-2.0", "dependencies": { "@electron/rebuild": "^3.2.10", diff --git a/extension/package.json b/extension/package.json index bbc83e4a..30690397 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.115", + "version": "0.0.116", "publisher": "Continue", "engines": { "vscode": "^1.67.0" diff --git a/extension/react-app/src/components/ComboBox.tsx b/extension/react-app/src/components/ComboBox.tsx index 55496fb9..4dab8bcd 100644 --- a/extension/react-app/src/components/ComboBox.tsx +++ b/extension/react-app/src/components/ComboBox.tsx @@ -1,4 +1,9 @@ -import React, { useCallback, useEffect, useState } from "react"; +import React, { + useCallback, + useEffect, + useImperativeHandle, + useState, +} from "react"; import { useCombobox } from "downshift"; import styled from "styled-components"; import { @@ -151,22 +156,13 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => { const [highlightedCodeSections, setHighlightedCodeSections] = React.useState( props.highlightedCodeSections || [] ); + const inputRef = React.useRef<HTMLInputElement>(null); useEffect(() => { setHighlightedCodeSections(props.highlightedCodeSections || []); }, [props.highlightedCodeSections]); - const { - isOpen, - getToggleButtonProps, - getLabelProps, - getMenuProps, - getInputProps, - highlightedIndex, - getItemProps, - selectedItem, - setInputValue, - } = useCombobox({ + const { getInputProps, ...downshiftProps } = useCombobox({ onInputValueChange({ inputValue }) { if (!inputValue) return; props.onInputValueChange(inputValue); @@ -182,6 +178,24 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => { }, }); + useImperativeHandle(ref, () => downshiftProps, [downshiftProps]); + + useEffect(() => { + if (!inputRef.current) { + return; + } + inputRef.current.focus(); + const handler = (event: any) => { + if (event.data.type === "focusContinueInput") { + inputRef.current!.focus(); + } + }; + window.addEventListener("message", handler); + return () => { + window.removeEventListener("message", handler); + }; + }, [inputRef.current]); + const divRef = React.useRef<HTMLDivElement>(null); const ulRef = React.useRef<HTMLUListElement>(null); const showAbove = () => { @@ -255,7 +269,7 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => { </HeaderButtonWithText> ))} </div> - <div className="flex px-2" ref={divRef} hidden={!isOpen}> + <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" @@ -277,9 +291,9 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => { (event.nativeEvent as any).preventDownshiftDefault = true; } else if ( event.key === "Enter" && - (!isOpen || items.length === 0) + (!downshiftProps.isOpen || items.length === 0) ) { - setInputValue(""); + downshiftProps.setInputValue(""); const value = event.currentTarget.value; if (value !== "") { setPositionInHistory(history.length + 1); @@ -294,7 +308,7 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => { } if (props.onEnter) props.onEnter(event); } else if (event.key === "Tab" && items.length > 0) { - setInputValue(items[0].name); + downshiftProps.setInputValue(items[0].name); event.preventDefault(); } else if ( (event.key === "ArrowUp" || event.key === "ArrowDown") && @@ -311,35 +325,35 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => { ) { setHistory([...history, event.currentTarget.value]); } - setInputValue(history[positionInHistory - 1]); + downshiftProps.setInputValue(history[positionInHistory - 1]); setPositionInHistory((prev) => prev - 1); } else if (event.key === "ArrowDown") { if (positionInHistory < history.length) { - setInputValue(history[positionInHistory + 1]); + downshiftProps.setInputValue(history[positionInHistory + 1]); } setPositionInHistory((prev) => Math.min(prev + 1, history.length) ); } }, - ref: ref as any, + ref: inputRef, })} /> <Ul - {...getMenuProps({ + {...downshiftProps.getMenuProps({ ref: ulRef, })} showAbove={showAbove()} ulHeightPixels={ulRef.current?.getBoundingClientRect().height || 0} > - {isOpen && + {downshiftProps.isOpen && items.map((item, index) => ( <Li style={{ borderTop: index === 0 ? "none" : undefined }} key={`${item.name}${index}`} - {...getItemProps({ item, index })} - highlighted={highlightedIndex === index} - selected={selectedItem === item} + {...downshiftProps.getItemProps({ item, index })} + highlighted={downshiftProps.highlightedIndex === index} + selected={downshiftProps.selectedItem === item} > <span> {item.name}: {item.description} diff --git a/extension/react-app/src/components/ContinueButton.tsx b/extension/react-app/src/components/ContinueButton.tsx index 72f6dcd2..d7739b20 100644 --- a/extension/react-app/src/components/ContinueButton.tsx +++ b/extension/react-app/src/components/ContinueButton.tsx @@ -13,9 +13,8 @@ let StyledButton = styled(Button)` background: #be1b55; &:hover { - transition-delay: 0.5s; transition-property: "background"; - opacity: 0.8; + opacity: 0.7; } `; diff --git a/extension/react-app/src/components/StepContainer.tsx b/extension/react-app/src/components/StepContainer.tsx index 590b1166..d480c565 100644 --- a/extension/react-app/src/components/StepContainer.tsx +++ b/extension/react-app/src/components/StepContainer.tsx @@ -260,6 +260,9 @@ function StepContainer(props: StepContainerProps) { code: ({ node, ...props }) => { return <StyledCode children={props.children[0] as any} />; }, + ul: ({ node, ...props }) => { + return <ul className="ml-0" {...props} />; + }, }} > {props.historyNode.step.description as any} diff --git a/extension/react-app/src/tabs/gui.tsx b/extension/react-app/src/tabs/gui.tsx index c8a42d9a..1ea70dd2 100644 --- a/extension/react-app/src/tabs/gui.tsx +++ b/extension/react-app/src/tabs/gui.tsx @@ -217,25 +217,10 @@ function GUI(props: GUIProps) { [client] ); - useEffect(() => { - if (mainTextInputRef.current) { - mainTextInputRef.current.focus(); - let handler = (event: any) => { - if (event.data.type === "focusContinueInput") { - mainTextInputRef.current?.focus(); - } - }; - window.addEventListener("message", handler); - return () => { - window.removeEventListener("message", handler); - }; - } - }, [mainTextInputRef]); - const onMainTextInput = () => { if (mainTextInputRef.current) { - let input = mainTextInputRef.current.value; - mainTextInputRef.current.value = ""; + const input = (mainTextInputRef.current as any).inputValue; + (mainTextInputRef.current as any).setInputValue(""); if (!client) return; setWaitingForSteps(true); @@ -266,13 +251,6 @@ function GUI(props: GUIProps) { setUserInputQueue((queue) => { return [...queue, input]; }); - - // Delete all context items unless locked - if (!pinned) { - client?.deleteContextAtIndices( - highlightedRanges.map((_, index) => index) - ); - } } }; diff --git a/extension/src/continueIdeClient.ts b/extension/src/continueIdeClient.ts index e6966f41..3615ab92 100644 --- a/extension/src/continueIdeClient.ts +++ b/extension/src/continueIdeClient.ts @@ -423,6 +423,10 @@ class IdeProtocolClient { sendAcceptRejectSuggestion(accepted: boolean) { this.messenger?.send("acceptRejectSuggestion", { accepted }); } + + sendAcceptRejectDiff(accepted: boolean) { + this.messenger?.send("acceptRejectDiff", { accepted }); + } } export default IdeProtocolClient; diff --git a/extension/src/diffs.ts b/extension/src/diffs.ts index 1b8888e8..4fce744c 100644 --- a/extension/src/diffs.ts +++ b/extension/src/diffs.ts @@ -2,6 +2,7 @@ import * as os from "os"; import * as path from "path"; import * as fs from "fs"; import * as vscode from "vscode"; +import { ideProtocolClient } from "./activation/activate"; interface DiffInfo { originalFilepath: string; @@ -133,8 +134,10 @@ export const diffManager = new DiffManager(); export async function acceptDiffCommand(newFilepath?: string) { diffManager.acceptDiff(newFilepath); + ideProtocolClient.sendAcceptRejectDiff(true); } export async function rejectDiffCommand(newFilepath?: string) { diffManager.rejectDiff(newFilepath); + ideProtocolClient.sendAcceptRejectDiff(false); } |