From 94341653cae5b9af6e33f480847dfb562aa7578c Mon Sep 17 00:00:00 2001 From: Nate Sesti <sestinj@gmail.com> Date: Wed, 21 Jun 2023 14:02:56 -0700 Subject: first slightly working version of suggestions --- continuedev/src/continuedev/server/ide.py | 6 +- continuedev/src/continuedev/server/ide_protocol.py | 2 +- continuedev/src/continuedev/steps/core/core.py | 448 ++++++++++----------- 3 files changed, 226 insertions(+), 230 deletions(-) (limited to 'continuedev/src') diff --git a/continuedev/src/continuedev/server/ide.py b/continuedev/src/continuedev/server/ide.py index c83fbc8a..c2ebaccf 100644 --- a/continuedev/src/continuedev/server/ide.py +++ b/continuedev/src/continuedev/server/ide.py @@ -146,8 +146,10 @@ class IdeProtocolServer(AbstractIdeProtocolServer): # ------------------------------- # # Request actions in IDE, doesn't matter which Session - def showSuggestion(): - pass + async def showSuggestion(self, file_edit: FileEdit): + await self._send_json("showSuggestion", { + "edit": file_edit.dict() + }) async def setFileOpen(self, filepath: str, open: bool = True): # Autopilot needs access to this. diff --git a/continuedev/src/continuedev/server/ide_protocol.py b/continuedev/src/continuedev/server/ide_protocol.py index 2dcedc30..79820c36 100644 --- a/continuedev/src/continuedev/server/ide_protocol.py +++ b/continuedev/src/continuedev/server/ide_protocol.py @@ -12,7 +12,7 @@ class AbstractIdeProtocolServer(ABC): """Handle a json message""" @abstractmethod - def showSuggestion(): + def showSuggestion(self, file_edit: FileEdit): """Show a suggestion to the user""" @abstractmethod diff --git a/continuedev/src/continuedev/steps/core/core.py b/continuedev/src/continuedev/steps/core/core.py index 71a5b5b2..eb6a00c6 100644 --- a/continuedev/src/continuedev/steps/core/core.py +++ b/continuedev/src/continuedev/steps/core/core.py @@ -159,253 +159,247 @@ class DefaultModelEditCodeStep(Step): self.name = await models.gpt35.complete(f"Write a very short title to describe this requested change: '{self.user_input}'. This is the title:") return f"`{self.user_input}`\n\n" + description - async def run(self, sdk: ContinueSDK) -> Coroutine[Observation, None, None]: - self.description = f"`{self.user_input}`" - await sdk.update_ui() - - rif_with_contents = [] - for range_in_file in map(lambda x: RangeInFile( - filepath=x.filepath, - # Only consider the range line-by-line. Maybe later don't if it's only a single line. - range=x.range.to_full_lines() - ), self.range_in_files): - file_contents = await sdk.ide.readRangeInFile(range_in_file) - rif_with_contents.append( - RangeInFileWithContents.from_range_in_file(range_in_file, file_contents)) - - rif_dict = {} - for rif in rif_with_contents: - rif_dict[rif.filepath] = rif.contents - - for rif in rif_with_contents: - await sdk.ide.setFileOpen(rif.filepath) - - model_to_use = sdk.models.default - - full_file_contents = await sdk.ide.readFile(rif.filepath) - - full_file_contents_lst = full_file_contents.split("\n") - - max_start_line = rif.range.start.line - min_end_line = rif.range.end.line - cur_start_line = 0 - cur_end_line = len(full_file_contents_lst) - 1 - - def cut_context(model_to_use, total_tokens, cur_start_line, cur_end_line): - - if total_tokens > MAX_TOKENS_FOR_MODEL[model_to_use.name]: - while cur_end_line > min_end_line: - total_tokens -= model_to_use.count_tokens( - full_file_contents_lst[cur_end_line]) - cur_end_line -= 1 - if total_tokens < MAX_TOKENS_FOR_MODEL[model_to_use.name]: - return cur_start_line, cur_end_line - - if total_tokens > MAX_TOKENS_FOR_MODEL[model_to_use.name]: - while cur_start_line < max_start_line: - cur_start_line += 1 - total_tokens -= model_to_use.count_tokens( - full_file_contents_lst[cur_end_line]) - if total_tokens < MAX_TOKENS_FOR_MODEL[model_to_use.name]: - return cur_start_line, cur_end_line - - return cur_start_line, cur_end_line - - if model_to_use.name == "gpt-4": - - total_tokens = model_to_use.count_tokens(full_file_contents + self._prompt) - cur_start_line, cur_end_line = cut_context( - model_to_use, total_tokens, cur_start_line, cur_end_line) - - elif model_to_use.name == "gpt-3.5-turbo" or model_to_use.name == "gpt-3.5-turbo-16k": - - if sdk.models.gpt35.count_tokens(full_file_contents) > MAX_TOKENS_FOR_MODEL["gpt-3.5-turbo"]: - - model_to_use = sdk.models.gpt3516k - total_tokens = model_to_use.count_tokens( - full_file_contents + self._prompt) - cur_start_line, cur_end_line = cut_context( - model_to_use, total_tokens, cur_start_line, cur_end_line) - - else: - - raise Exception("Unknown default model") + async def get_prompt_parts(self, rif: RangeInFileWithContents, sdk: ContinueSDK, full_file_contents: str): + # If using 3.5 and overflows, upgrade to 3.5.16k + model_to_use = sdk.models.default + if model_to_use.name == "gpt-3.5-turbo": + if sdk.models.gpt35.count_tokens(full_file_contents) > MAX_TOKENS_FOR_MODEL["gpt-3.5-turbo"]: + model_to_use = sdk.models.gpt3516k + + # Remove tokens from the end first, and then the start to clear space + # This part finds the start and end lines + full_file_contents_lst = full_file_contents.split("\n") + max_start_line = rif.range.start.line + min_end_line = rif.range.end.line + cur_start_line = 0 + cur_end_line = len(full_file_contents_lst) - 1 + + total_tokens = model_to_use.count_tokens( + full_file_contents + self._prompt) + + if total_tokens > MAX_TOKENS_FOR_MODEL[model_to_use.name]: + while cur_end_line > min_end_line: + total_tokens -= model_to_use.count_tokens( + full_file_contents_lst[cur_end_line]) + cur_end_line -= 1 + if total_tokens < MAX_TOKENS_FOR_MODEL[model_to_use.name]: + return cur_start_line, cur_end_line + + if total_tokens > MAX_TOKENS_FOR_MODEL[model_to_use.name]: + while cur_start_line < max_start_line: + cur_start_line += 1 + total_tokens -= model_to_use.count_tokens( + full_file_contents_lst[cur_end_line]) + if total_tokens < MAX_TOKENS_FOR_MODEL[model_to_use.name]: + return cur_start_line, cur_end_line + + # Now use the found start/end lines to get the prefix and suffix strings + file_prefix = "\n".join( + full_file_contents_lst[cur_start_line:max_start_line]) + file_suffix = "\n".join( + full_file_contents_lst[min_end_line:cur_end_line - 1]) + + # Move any surrounding blank line in rif.contents to the prefix/suffix + # TODO: Keep track of start line of the range, because it's needed below for offset stuff + rif_start_line = rif.range.start.line + if len(rif.contents) > 0: + first_line = rif.contents.splitlines(keepends=True)[0] + while first_line.strip() == "": + file_prefix += first_line + rif.contents = rif.contents[len(first_line):] + first_line = rif.contents.splitlines(keepends=True)[0] - code_before = "\n".join( - full_file_contents_lst[cur_start_line:max_start_line]) - code_after = "\n".join( - full_file_contents_lst[min_end_line:cur_end_line - 1]) + last_line = rif.contents.splitlines(keepends=True)[-1] + while last_line.strip() == "": + file_suffix = last_line + file_suffix + rif.contents = rif.contents[:len( + rif.contents) - len(last_line)] + last_line = rif.contents.splitlines(keepends=True)[-1] - segs = [code_before, code_after] - if segs[0].strip() == "": - segs[0] = segs[0].strip() - if segs[1].strip() == "": - segs[1] = segs[1].strip() + while rif.contents.startswith("\n"): + file_prefix += "\n" + rif.contents = rif.contents[1:] + while rif.contents.endswith("\n"): + file_suffix = "\n" + file_suffix + rif.contents = rif.contents[:-1] - # Move any surrounding blank line in rif.contents to the prefix/suffix - if len(rif.contents) > 0: - first_line = rif.contents.splitlines(keepends=True)[0] - while first_line.strip() == "": - segs[0] += first_line - rif.contents = rif.contents[len(first_line):] - first_line = rif.contents.splitlines(keepends=True)[0] + return file_prefix, rif.contents, file_suffix, model_to_use - last_line = rif.contents.splitlines(keepends=True)[-1] - while last_line.strip() == "": - segs[1] = last_line + segs[1] - rif.contents = rif.contents[:len( - rif.contents) - len(last_line)] - last_line = rif.contents.splitlines(keepends=True)[-1] - - while rif.contents.startswith("\n"): - segs[0] += "\n" - rif.contents = rif.contents[1:] - while rif.contents.endswith("\n"): - segs[1] = "\n" + segs[1] - rif.contents = rif.contents[:-1] - - # .format(code=rif.contents, user_request=self.user_input, file_prefix=segs[0], file_suffix=segs[1]) - prompt = self._prompt - if segs[0].strip() != "": - prompt += dedent(f""" + def compile_prompt(self, file_prefix: str, contents: str, file_suffix: str, sdk: ContinueSDK) -> str: + prompt = self._prompt + if file_prefix.strip() != "": + prompt += dedent(f""" <file_prefix> -{segs[0]} +{file_prefix} </file_prefix>""") - prompt += dedent(f""" + prompt += dedent(f""" <code_to_edit> -{rif.contents} +{contents} </code_to_edit>""") - if segs[1].strip() != "": - prompt += dedent(f""" + if file_suffix.strip() != "": + prompt += dedent(f""" <file_suffix> -{segs[1]} +{file_suffix} </file_suffix>""") - prompt += dedent(f""" + prompt += dedent(f""" <user_request> {self.user_input} </user_request> <modified_code_to_edit> """) - lines = [] - unfinished_line = "" - i = 0 - original_lines = rif.contents.split("\n") - - async def add_line(i: int, line: str): - if i == 0: - # First line indentation, because the model will assume that it is replacing in this way - line = original_lines[0].replace( - original_lines[0].strip(), "") + line - - if i < len(original_lines): - # Replace original line - range = Range.from_shorthand( - rif.range.start.line + i, rif.range.start.character if i == 0 else 0, rif.range.start.line + i + 1, 0) - else: - # Insert a line - range = Range.from_shorthand( - rif.range.start.line + i, 0, rif.range.start.line + i, 0) - - await sdk.ide.applyFileSystemEdit(FileEdit( - filepath=rif.filepath, - range=range, - replacement=line + "\n" - )) - - lines_of_prefix_copied = 0 - line_below_highlighted_range = segs[1].lstrip().split("\n")[0] - should_stop = False - async for chunk in model_to_use.stream_chat(prompt, with_history=await sdk.get_chat_context(), temperature=0): - if should_stop: + return prompt + + def is_end_line(self, line: str) -> bool: + return "</modified_code_to_edit>" in line + + def line_to_be_ignored(self, line: str) -> bool: + return "```" in line or "<modified_code_to_edit>" in line or "<file_prefix>" in line or "</file_prefix>" in line or "<file_suffix>" in line or "</file_suffix>" in line or "<user_request>" in line or "</user_request>" in line or "<code_to_edit>" in line or "</code_to_edit>" in line + + async def stream_rif(self, rif: RangeInFileWithContents, sdk: ContinueSDK): + full_file_contents = await sdk.ide.readFile(rif.filepath) + + file_prefix, contents, file_suffix, model_to_use = await self.get_prompt_parts( + rif, sdk, full_file_contents) + prompt = self.compile_prompt(file_prefix, contents, file_suffix, sdk) + + full_file_contents_lines = full_file_contents.split("\n") + original_lines = rif.contents.split("\n") + i = 0 + lines = [] + unfinished_line = "" + + current_block = [] + offset_from_blocks = 0 + + async def insert_line(line: str, line_no: int): + nonlocal current_block + # Insert line, highlight green, highlight corresponding line red + range = Range.from_shorthand( + line_no, 0, line_no, 0) + red_range = Range.from_shorthand( + line_no + len(current_block), 0, line_no + len(current_block), 0) + + await sdk.ide.applyFileSystemEdit(FileEdit( + filepath=rif.filepath, + range=range, + replacement=line + "\n" + )) + await sdk.ide.highlightCode(RangeInFile(filepath=rif.filepath, range=range), "#00FF0022") + await sdk.ide.highlightCode(RangeInFile(filepath=rif.filepath, range=red_range), "#FF000022") + + async def show_block_as_suggestion(): + nonlocal i, offset_from_blocks, current_block + await sdk.ide.showSuggestion(FileEdit( + filepath=rif.filepath, + range=Range.from_shorthand( + i + offset_from_blocks - len(current_block) + rif.range.start.line, 0, i + offset_from_blocks + rif.range.start.line, 0), + replacement="\n".join(current_block) + "\n" + )) + offset_from_blocks += len(current_block) + current_block.clear() + + async def add_to_block(line: str): + current_block.append(line) + # TODO: This start line might have changed above + # await insert_line(line, i + offset_from_blocks + + # rif.range.start.line) + + async def handle_generated_line(line: str): + nonlocal i, lines, current_block, offset_from_blocks, original_lines + # diff = list(difflib.ndiff(rif.contents.splitlines( + # keepends=True), completion.splitlines(keepends=True))) + if i < len(original_lines) and line == original_lines[i]: + # Line is the same as the original. Start a new block + await show_block_as_suggestion() + else: + # Add to the current block + await add_to_block(line) + + lines_of_prefix_copied = 0 + repeating_file_suffix = False + line_below_highlighted_range = file_suffix.lstrip().split("\n")[0] + async for chunk in model_to_use.stream_chat(prompt, with_history=await sdk.get_chat_context(), temperature=0): + # Stop early if it is repeating the file_suffix + if repeating_file_suffix: + break + + # Accumulate lines + chunk_lines = chunk.split("\n") + chunk_lines[0] = unfinished_line + chunk_lines[0] + if chunk.endswith("\n"): + unfinished_line = "" + chunk_lines.pop() # because this will be an empty string + else: + unfinished_line = chunk_lines.pop() + lines.extend(chunk_lines) + + # Deal with newly accumulated lines + for line in chunk_lines: + # Lines that should signify the end of generation + if self.is_end_line(line): + break + # Lines that should be ignored, like the <> tags + elif self.line_to_be_ignored(line): + continue + # Check if we are currently just copying the prefix + elif (lines_of_prefix_copied > 0 or i == 0) and lines_of_prefix_copied < len(file_prefix.splitlines()) and line == 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: + repeating_file_suffix = True break - chunk_lines = chunk.split("\n") - chunk_lines[0] = unfinished_line + chunk_lines[0] - if chunk.endswith("\n"): - unfinished_line = "" - chunk_lines.pop() # because this will be an empty string - else: - unfinished_line = chunk_lines.pop() - lines.extend(chunk_lines) - - for line in chunk_lines: - if "</modified_code_to_edit>" in line: - break - elif "```" in line or "<modified_code_to_edit>" in line or "<file_prefix>" in line or "</file_prefix>" in line or "<file_suffix>" in line or "</file_suffix>" in line or "<user_request>" in line or "</user_request>" in line or "<code_to_edit>" in line or "</code_to_edit>" in line: - continue - elif (lines_of_prefix_copied > 0 or i == 0) and lines_of_prefix_copied < len(segs[0].splitlines()) and line == full_file_contents_lst[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 - elif i < len(original_lines) and line == original_lines[i]: - i += 1 - continue - # Because really short lines might be expected to be repeated !heuristic! - elif line.strip() == line_below_highlighted_range.strip() and len(line.strip()) > 4: - should_stop = True - break - await add_line(i, line) - i += 1 - - # Add the unfinished line - if unfinished_line != "": - unfinished_line = unfinished_line.replace( - "</modified_code_to_edit>", "").replace("</code_to_edit>", "").replace("```", "").replace("</file_suffix>", "").replace("</file_prefix", "").replace( - "<modified_code_to_edit>", "").replace("<code_to_edit>", "").replace("<file_suffix>", "").replace("<file_prefix", "") - if not i < len(original_lines) or not unfinished_line == original_lines[i]: - await add_line(i, unfinished_line) - lines.append(unfinished_line) - i += 1 - # Remove the leftover original lines - while i < len(original_lines): - range = Range.from_shorthand( - rif.range.start.line + i, rif.range.start.character, rif.range.start.line + i, len(original_lines[i]) + 1) - await sdk.ide.applyFileSystemEdit(FileEdit( - filepath=rif.filepath, - range=range, - replacement="" - )) + # If none of the above, insert the line! + await handle_generated_line(line) i += 1 - completion = "\n".join(lines) - - self._prompt_and_completion += prompt + completion - - diff = list(difflib.ndiff(rif.contents.splitlines( - keepends=True), completion.splitlines(keepends=True))) - - lines_to_highlight = set() - index = 0 - for line in diff: - if line.startswith("-"): - pass - elif line.startswith("+"): - lines_to_highlight.add(index + rif.range.start.line) - index += 1 - elif line.startswith(" "): - index += 1 - - current_hl_start = None - last_hl = None - rifs_to_highlight = [] - for line in lines_to_highlight: - if current_hl_start is None: - current_hl_start = line - elif line != last_hl + 1: - rifs_to_highlight.append(RangeInFile( - filepath=rif.filepath, range=Range.from_shorthand(current_hl_start, 0, last_hl, 0))) - current_hl_start = line - last_hl = line - - if current_hl_start is not None: - rifs_to_highlight.append(RangeInFile( - filepath=rif.filepath, range=Range.from_shorthand(current_hl_start, 0, last_hl, 0))) - - for rif_to_hl in rifs_to_highlight: - await sdk.ide.highlightCode(rif_to_hl) - - await sdk.ide.saveFile(rif.filepath) + # Add the unfinished line + if unfinished_line != "" and not self.line_to_be_ignored(unfinished_line) and not self.is_end_line(unfinished_line): + lines.append(unfinished_line) + await handle_generated_line(unfinished_line) + i += 1 + + # Highlight the remainder of the range red + if i < len(original_lines): + await handle_generated_line("") + # range = Range.from_shorthand( + # i + 1 + offset_from_blocks + rif.range.start.line, 0, len(original_lines) + offset_from_blocks + rif.range.start.line, 0) + # await sdk.ide.highlightCode(RangeInFile(filepath=rif.filepath, range=range), "#FF000022") + + # If the current block isn't empty, add that suggestion + if len(current_block) > 0: + await show_block_as_suggestion() + + # Record the completion + completion = "\n".join(lines) + self._prompt_and_completion += prompt + completion + + async def run(self, sdk: ContinueSDK) -> Coroutine[Observation, None, None]: + self.description = f"`{self.user_input}`" + await sdk.update_ui() + + rif_with_contents = [] + for range_in_file in map(lambda x: RangeInFile( + filepath=x.filepath, + # Only consider the range line-by-line. Maybe later don't if it's only a single line. + range=x.range.to_full_lines() + ), self.range_in_files): + file_contents = await sdk.ide.readRangeInFile(range_in_file) + rif_with_contents.append( + RangeInFileWithContents.from_range_in_file(range_in_file, file_contents)) + + rif_dict = {} + for rif in rif_with_contents: + rif_dict[rif.filepath] = rif.contents + + for rif in rif_with_contents: + await sdk.ide.setFileOpen(rif.filepath) + await self.stream_rif(rif, sdk) + # await sdk.ide.saveFile(rif.filepath) class EditFileStep(Step): -- cgit v1.2.3-70-g09d2 From 8262dd66cefc39f28d75e35e4de389d124aca2c0 Mon Sep 17 00:00:00 2001 From: Nate Sesti <sestinj@gmail.com> Date: Wed, 21 Jun 2023 22:20:01 -0700 Subject: suggestions...closer? --- continuedev/src/continuedev/steps/core/core.py | 77 +++++++++++++++++++++----- extension/package.json | 38 ++++++++++++- extension/src/continueIdeClient.ts | 9 +++ 3 files changed, 109 insertions(+), 15 deletions(-) (limited to 'continuedev/src') diff --git a/continuedev/src/continuedev/steps/core/core.py b/continuedev/src/continuedev/steps/core/core.py index eb6a00c6..1238dfea 100644 --- a/continuedev/src/continuedev/steps/core/core.py +++ b/continuedev/src/continuedev/steps/core/core.py @@ -271,14 +271,21 @@ class DefaultModelEditCodeStep(Step): current_block = [] offset_from_blocks = 0 + last_matched_line = 0 + matched_line = 0 + current_block_start_of_insertion = -1 + lines_covered_in_this_block = 0 + liness_deleted_in_this_block = 0 + lines_same_in_this_block = 0 async def insert_line(line: str, line_no: int): nonlocal current_block # Insert line, highlight green, highlight corresponding line red + red_line = line_no + len(current_block) + 1 range = Range.from_shorthand( line_no, 0, line_no, 0) red_range = Range.from_shorthand( - line_no + len(current_block), 0, line_no + len(current_block), 0) + red_line, 0, red_line, 0) await sdk.ide.applyFileSystemEdit(FileEdit( filepath=rif.filepath, @@ -289,32 +296,73 @@ class DefaultModelEditCodeStep(Step): await sdk.ide.highlightCode(RangeInFile(filepath=rif.filepath, range=red_range), "#FF000022") async def show_block_as_suggestion(): - nonlocal i, offset_from_blocks, current_block + nonlocal i, offset_from_blocks, current_block, current_block_start_of_insertion, matched_line, last_matched_line, lines_covered_in_this_block, liness_deleted_in_this_block + end_line = offset_from_blocks + rif.range.start.line + matched_line + # Delete the green inserted lines, because they will be shown as part of the suggestion + await sdk.ide.applyFileSystemEdit(FileEdit( + filepath=rif.filepath, + range=Range.from_shorthand( + current_block_start_of_insertion, 0, current_block_start_of_insertion + len(current_block), 0), + replacement="" + )) + + lines_deleted_in_this_block = lines_covered_in_this_block - lines_same_in_this_block await sdk.ide.showSuggestion(FileEdit( filepath=rif.filepath, range=Range.from_shorthand( - i + offset_from_blocks - len(current_block) + rif.range.start.line, 0, i + offset_from_blocks + rif.range.start.line, 0), + end_line - lines_deleted_in_this_block, 0, end_line, 0), replacement="\n".join(current_block) + "\n" )) offset_from_blocks += len(current_block) current_block.clear() - async def add_to_block(line: str): + async def add_green_to_block(line: str): + # Keep track of where the first inserted line in this block came from + nonlocal current_block_start_of_insertion + if current_block_start_of_insertion < 0: + current_block_start_of_insertion = i + offset_from_blocks + rif.range.start.line + + # Insert the line, highlight green + await insert_line(line, i + offset_from_blocks + rif.range.start.line) current_block.append(line) - # TODO: This start line might have changed above - # await insert_line(line, i + offset_from_blocks + - # rif.range.start.line) - async def handle_generated_line(line: str): - nonlocal i, lines, current_block, offset_from_blocks, original_lines + def line_matches_something_in_original(line: str) -> int: + nonlocal offset_from_blocks, last_matched_line, matched_line, lines_covered_in_this_block # diff = list(difflib.ndiff(rif.contents.splitlines( # keepends=True), completion.splitlines(keepends=True))) - if i < len(original_lines) and line == original_lines[i]: - # Line is the same as the original. Start a new block - await show_block_as_suggestion() + # TODO: and line.strip() != ""? + for j in range(last_matched_line, len(original_lines)): + if line == original_lines[j]: + last_matched_line = matched_line + lines_covered_in_this_block = j - matched_line + matched_line = j + return j + return -1 + + async def handle_generated_line(line: str): + nonlocal i, lines, current_block, offset_from_blocks, original_lines, current_block_start_of_insertion, matched_line, lines_covered_in_this_block, lines_same_in_this_block + + # Highlight the line to show progress + await sdk.ide.highlightCode(RangeInFile(filepath=rif.filepath, range=Range.from_shorthand( + i + rif.range.start.line, 0, i + rif.range.start.line, 0)), "#FFFFFF22") + + # Check if this line appears to correspond to something in the original + if line_matches_something_in_original(line) >= 0: + if len(current_block) > 0: + # Matches something, add all lines up to this as red in the old block, then show the block + await show_block_as_suggestion() + i -= 1 + # i -= (len(current_block) - + # (matched_line - last_matched_line)) + lines_covered_in_this_block = 0 + lines_same_in_this_block = 0 + + current_block_start_of_insertion = -1 + lines_same_in_this_block += 1 + else: - # Add to the current block - await add_to_block(line) + # No match, insert the line into the replacement but don't change the red highlighting + await add_green_to_block(line) lines_of_prefix_copied = 0 repeating_file_suffix = False @@ -372,6 +420,7 @@ class DefaultModelEditCodeStep(Step): # If the current block isn't empty, add that suggestion if len(current_block) > 0: + matched_line = rif.range.end.line - rif.range.start.line await show_block_as_suggestion() # Record the completion diff --git a/extension/package.json b/extension/package.json index 94a58ebd..a9b8660b 100644 --- a/extension/package.json +++ b/extension/package.json @@ -65,12 +65,48 @@ } } }, - "commands": [], + "commands": [ + { + "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" + } + ], "keybindings": [ { "command": "continue.focusContinueInput", "mac": "cmd+k", "key": "ctrl+k" + }, + { + "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" } ], "menus": { diff --git a/extension/src/continueIdeClient.ts b/extension/src/continueIdeClient.ts index fbd00c6e..b1fcd6fb 100644 --- a/extension/src/continueIdeClient.ts +++ b/extension/src/continueIdeClient.ts @@ -163,6 +163,15 @@ class IdeProtocolClient { isWholeLine: true, }); editor.setDecorations(decorationType, [range]); + + const cursorDisposable = vscode.window.onDidChangeTextEditorSelection( + (event) => { + if (event.textEditor.document.uri.fsPath === rangeInFile.filepath) { + cursorDisposable.dispose(); + editor.setDecorations(decorationType, []); + } + } + ); } } -- cgit v1.2.3-70-g09d2 From 5e583f8300cbc174a8bafb31362f55b3b234d3d2 Mon Sep 17 00:00:00 2001 From: Nate Sesti <sestinj@gmail.com> Date: Thu, 22 Jun 2023 09:34:22 -0700 Subject: committing before I make difflib update to stream --- continuedev/src/continuedev/steps/core/core.py | 66 ++++++++++++++++---------- extension/src/suggestions.ts | 62 ++++++++++++------------ 2 files changed, 72 insertions(+), 56 deletions(-) (limited to 'continuedev/src') diff --git a/continuedev/src/continuedev/steps/core/core.py b/continuedev/src/continuedev/steps/core/core.py index 1238dfea..3c50f586 100644 --- a/continuedev/src/continuedev/steps/core/core.py +++ b/continuedev/src/continuedev/steps/core/core.py @@ -265,7 +265,9 @@ class DefaultModelEditCodeStep(Step): full_file_contents_lines = full_file_contents.split("\n") original_lines = rif.contents.split("\n") - i = 0 + completion_lines_covered = 0 + # In the actual file, as it is with blocks and such + current_line_in_file = rif.range.start.line lines = [] unfinished_line = "" @@ -296,7 +298,7 @@ class DefaultModelEditCodeStep(Step): await sdk.ide.highlightCode(RangeInFile(filepath=rif.filepath, range=red_range), "#FF000022") async def show_block_as_suggestion(): - nonlocal i, offset_from_blocks, current_block, current_block_start_of_insertion, matched_line, last_matched_line, lines_covered_in_this_block, liness_deleted_in_this_block + nonlocal completion_lines_covered, offset_from_blocks, current_block, current_block_start_of_insertion, matched_line, last_matched_line, lines_covered_in_this_block, liness_deleted_in_this_block, current_line_in_file end_line = offset_from_blocks + rif.range.start.line + matched_line # Delete the green inserted lines, because they will be shown as part of the suggestion await sdk.ide.applyFileSystemEdit(FileEdit( @@ -310,9 +312,12 @@ class DefaultModelEditCodeStep(Step): await sdk.ide.showSuggestion(FileEdit( filepath=rif.filepath, range=Range.from_shorthand( - end_line - lines_deleted_in_this_block, 0, end_line, 0), + current_block_start_of_insertion, 0, end_line, 0), replacement="\n".join(current_block) + "\n" )) + + current_line_in_file = end_line + \ + len(current_block) + 1 # CURRENTLY TODO HERE NOTE offset_from_blocks += len(current_block) current_block.clear() @@ -320,46 +325,56 @@ class DefaultModelEditCodeStep(Step): # Keep track of where the first inserted line in this block came from nonlocal current_block_start_of_insertion if current_block_start_of_insertion < 0: - current_block_start_of_insertion = i + offset_from_blocks + rif.range.start.line + current_block_start_of_insertion = current_line_in_file # Insert the line, highlight green - await insert_line(line, i + offset_from_blocks + rif.range.start.line) + await insert_line(line, current_line_in_file) current_block.append(line) - def line_matches_something_in_original(line: str) -> int: + def line_matches_something_in_original(line: str) -> bool: nonlocal offset_from_blocks, last_matched_line, matched_line, lines_covered_in_this_block - # diff = list(difflib.ndiff(rif.contents.splitlines( - # keepends=True), completion.splitlines(keepends=True))) + diff = list(difflib.ndiff( + original_lines[matched_line:], current_block + [line])) + i = current_line_in_file + if diff[i][0] == " ": + last_matched_line = matched_line + matched_line = i + lines_covered_in_this_block = matched_line - last_matched_line + return True + elif diff[i][0] == "-": + last_matched_line = matched_line + matched_line = i + lines_covered_in_this_block = matched_line - last_matched_line + return True + elif diff[i][0] == "+": + return False + # TODO: and line.strip() != ""? - for j in range(last_matched_line, len(original_lines)): + for j in range(matched_line, len(original_lines)): if line == original_lines[j]: last_matched_line = matched_line - lines_covered_in_this_block = j - matched_line matched_line = j - return j - return -1 + lines_covered_in_this_block = matched_line - last_matched_line + return True + return False async def handle_generated_line(line: str): - nonlocal i, lines, current_block, offset_from_blocks, original_lines, current_block_start_of_insertion, matched_line, lines_covered_in_this_block, lines_same_in_this_block + nonlocal completion_lines_covered, lines, current_block, offset_from_blocks, original_lines, current_block_start_of_insertion, matched_line, lines_covered_in_this_block, lines_same_in_this_block, current_line_in_file, completion_lines_covered # Highlight the line to show progress await sdk.ide.highlightCode(RangeInFile(filepath=rif.filepath, range=Range.from_shorthand( - i + rif.range.start.line, 0, i + rif.range.start.line, 0)), "#FFFFFF22") + current_line_in_file, 0, current_line_in_file, 0)), "#FFFFFF22") # Check if this line appears to correspond to something in the original - if line_matches_something_in_original(line) >= 0: + if line_matches_something_in_original(line): if len(current_block) > 0: # Matches something, add all lines up to this as red in the old block, then show the block await show_block_as_suggestion() - i -= 1 - # i -= (len(current_block) - - # (matched_line - last_matched_line)) - lines_covered_in_this_block = 0 + # Begin next block! lines_same_in_this_block = 0 - + lines_covered_in_this_block = 0 current_block_start_of_insertion = -1 lines_same_in_this_block += 1 - else: # No match, insert the line into the replacement but don't change the red highlighting await add_green_to_block(line) @@ -391,7 +406,7 @@ class DefaultModelEditCodeStep(Step): elif self.line_to_be_ignored(line): continue # Check if we are currently just copying the prefix - elif (lines_of_prefix_copied > 0 or i == 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 line == 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 @@ -403,16 +418,17 @@ class DefaultModelEditCodeStep(Step): # If none of the above, insert the line! await handle_generated_line(line) - i += 1 + completion_lines_covered += 1 + current_line_in_file += 1 # Add the unfinished line if unfinished_line != "" and not self.line_to_be_ignored(unfinished_line) and not self.is_end_line(unfinished_line): lines.append(unfinished_line) await handle_generated_line(unfinished_line) - i += 1 + completion_lines_covered += 1 # Highlight the remainder of the range red - if i < len(original_lines): + if completion_lines_covered < len(original_lines): await handle_generated_line("") # range = Range.from_shorthand( # i + 1 + offset_from_blocks + rif.range.start.line, 0, len(original_lines) + offset_from_blocks + rif.range.start.line, 0) diff --git a/extension/src/suggestions.ts b/extension/src/suggestions.ts index 5ac6e095..2e4e0ea2 100644 --- a/extension/src/suggestions.ts +++ b/extension/src/suggestions.ts @@ -218,42 +218,42 @@ export async function showSuggestion( range: vscode.Range, suggestion: string ): Promise<boolean> { - const existingCode = await readFileAtRange( - new vscode.Range(range.start, range.end), - editorFilename - ); + // const existingCode = await readFileAtRange( + // new vscode.Range(range.start, range.end), + // editorFilename + // ); // If any of the outside lines are the same, don't repeat them in the suggestion - const slines = suggestion.split("\n"); - const elines = existingCode.split("\n"); - let linesRemovedBefore = 0; - let linesRemovedAfter = 0; - while (slines.length > 0 && elines.length > 0 && slines[0] === elines[0]) { - slines.shift(); - elines.shift(); - linesRemovedBefore++; - } + // const slines = suggestion.split("\n"); + // const elines = existingCode.split("\n"); + // let linesRemovedBefore = 0; + // let linesRemovedAfter = 0; + // while (slines.length > 0 && elines.length > 0 && slines[0] === elines[0]) { + // slines.shift(); + // elines.shift(); + // linesRemovedBefore++; + // } - while ( - slines.length > 0 && - elines.length > 0 && - slines[slines.length - 1] === elines[elines.length - 1] - ) { - slines.pop(); - elines.pop(); - linesRemovedAfter++; - } + // while ( + // slines.length > 0 && + // elines.length > 0 && + // slines[slines.length - 1] === elines[elines.length - 1] + // ) { + // slines.pop(); + // elines.pop(); + // linesRemovedAfter++; + // } - suggestion = slines.join("\n"); - if (suggestion === "") return Promise.resolve(false); // Don't even make a suggestion if they are exactly the same + // suggestion = slines.join("\n"); + // if (suggestion === "") return Promise.resolve(false); // Don't even make a suggestion if they are exactly the same - range = new vscode.Range( - new vscode.Position(range.start.line + linesRemovedBefore, 0), - new vscode.Position( - range.end.line - linesRemovedAfter, - elines.at(-1)?.length || 0 - ) - ); + // range = new vscode.Range( + // new vscode.Position(range.start.line + linesRemovedBefore, 0), + // new vscode.Position( + // range.end.line - linesRemovedAfter, + // elines.at(-1)?.length || 0 + // ) + // ); const editor = await openEditorAndRevealRange(editorFilename, range); if (!editor) return Promise.resolve(false); -- cgit v1.2.3-70-g09d2 From 0846a5dca6530a5cd6dad97952d2844a463a15e1 Mon Sep 17 00:00:00 2001 From: Nate Sesti <sestinj@gmail.com> Date: Thu, 22 Jun 2023 12:51:07 -0700 Subject: starting to use diff to create blocks --- continuedev/src/continuedev/steps/core/core.py | 62 +++++++++++++++++++++----- 1 file changed, 50 insertions(+), 12 deletions(-) (limited to 'continuedev/src') diff --git a/continuedev/src/continuedev/steps/core/core.py b/continuedev/src/continuedev/steps/core/core.py index 3c50f586..d4ccda58 100644 --- a/continuedev/src/continuedev/steps/core/core.py +++ b/continuedev/src/continuedev/steps/core/core.py @@ -271,7 +271,10 @@ class DefaultModelEditCodeStep(Step): lines = [] unfinished_line = "" - current_block = [] + current_block_added = [] + current_block_removed = [] + last_diff_char = " " + offset_from_blocks = 0 last_matched_line = 0 matched_line = 0 @@ -281,9 +284,9 @@ class DefaultModelEditCodeStep(Step): lines_same_in_this_block = 0 async def insert_line(line: str, line_no: int): - nonlocal current_block + nonlocal current_block_added # Insert line, highlight green, highlight corresponding line red - red_line = line_no + len(current_block) + 1 + red_line = line_no + len(current_block_added) + 1 range = Range.from_shorthand( line_no, 0, line_no, 0) red_range = Range.from_shorthand( @@ -298,7 +301,7 @@ class DefaultModelEditCodeStep(Step): await sdk.ide.highlightCode(RangeInFile(filepath=rif.filepath, range=red_range), "#FF000022") async def show_block_as_suggestion(): - nonlocal completion_lines_covered, offset_from_blocks, current_block, current_block_start_of_insertion, matched_line, last_matched_line, lines_covered_in_this_block, liness_deleted_in_this_block, current_line_in_file + nonlocal completion_lines_covered, offset_from_blocks, current_block_added, current_block_removed, current_block_start_of_insertion, matched_line, last_matched_line, lines_covered_in_this_block, liness_deleted_in_this_block, current_line_in_file end_line = offset_from_blocks + rif.range.start.line + matched_line # Delete the green inserted lines, because they will be shown as part of the suggestion await sdk.ide.applyFileSystemEdit(FileEdit( @@ -333,8 +336,9 @@ class DefaultModelEditCodeStep(Step): def line_matches_something_in_original(line: str) -> bool: nonlocal offset_from_blocks, last_matched_line, matched_line, lines_covered_in_this_block - diff = list(difflib.ndiff( - original_lines[matched_line:], current_block + [line])) + diff = list(filter(lambda x: not x.startswith("?"), difflib.ndiff( + original_lines[matched_line:], current_block + [line]))) + i = current_line_in_file if diff[i][0] == " ": last_matched_line = matched_line @@ -358,16 +362,36 @@ class DefaultModelEditCodeStep(Step): return True return False + def block_not_empty() -> bool: + nonlocal current_block_added, current_block_removed + return len(current_block_added) or len(current_block_removed) + async def handle_generated_line(line: str): - nonlocal completion_lines_covered, lines, current_block, offset_from_blocks, original_lines, current_block_start_of_insertion, matched_line, lines_covered_in_this_block, lines_same_in_this_block, current_line_in_file, completion_lines_covered + nonlocal completion_lines_covered, lines, current_block_added, current_block_removed, offset_from_blocks, original_lines, current_block_start_of_insertion, matched_line, lines_covered_in_this_block, lines_same_in_this_block, current_line_in_file, completion_lines_covered, last_diff_char # Highlight the line to show progress await sdk.ide.highlightCode(RangeInFile(filepath=rif.filepath, range=Range.from_shorthand( current_line_in_file, 0, current_line_in_file, 0)), "#FFFFFF22") - # Check if this line appears to correspond to something in the original - if line_matches_something_in_original(line): - if len(current_block) > 0: + # Get the diff of current block and the original + diff = list(filter(lambda x: not x.startswith("?"), difflib.ndiff( + original_lines[matched_line:], current_block_added + [line]))) + next_diff_char = diff[current_line_in_file][0] + + # If we need to start a new block, end the old one + if next_diff_char != last_diff_char: + await show_block_as_suggestion() + + if next_diff_char == " ": + if block_not_empty(): + await show_block_as_suggestion() + + current_block_start_of_insertion = -1 + lines_same_in_this_block += 1 + + elif next_diff_char == "-": + # Line was removed from the original, add it to the block + if block_not_empty(): # Matches something, add all lines up to this as red in the old block, then show the block await show_block_as_suggestion() # Begin next block! @@ -375,9 +399,23 @@ class DefaultModelEditCodeStep(Step): lines_covered_in_this_block = 0 current_block_start_of_insertion = -1 lines_same_in_this_block += 1 + elif next_diff_char == "+": + # Line was added to the original, add it to the block + + if block_not_empty(): + # Matches something, add all lines up to this as red in the old block, then show the block + await show_block_as_suggestion() + # Begin next block! + lines_same_in_this_block = 0 + lines_covered_in_this_block = 0 + current_block_start_of_insertion = -1 + lines_same_in_this_block += 1 + else: - # No match, insert the line into the replacement but don't change the red highlighting - await add_green_to_block(line) + raise Exception("Unexpected diff character: " + + diff[current_line_in_file][0]) + + last_diff_char = next_diff_char lines_of_prefix_copied = 0 repeating_file_suffix = False -- cgit v1.2.3-70-g09d2 From 99e065d720fa345d96e98468b8a0fc8a7971c83b Mon Sep 17 00:00:00 2001 From: Nate Sesti <sestinj@gmail.com> Date: Thu, 22 Jun 2023 13:04:49 -0700 Subject: more diff work, checkpoint --- continuedev/src/continuedev/steps/core/core.py | 40 +++++++++----------------- 1 file changed, 14 insertions(+), 26 deletions(-) (limited to 'continuedev/src') diff --git a/continuedev/src/continuedev/steps/core/core.py b/continuedev/src/continuedev/steps/core/core.py index d4ccda58..64f53c0f 100644 --- a/continuedev/src/continuedev/steps/core/core.py +++ b/continuedev/src/continuedev/steps/core/core.py @@ -271,6 +271,7 @@ class DefaultModelEditCodeStep(Step): lines = [] unfinished_line = "" + red_or_green_first = "green" current_block_added = [] current_block_removed = [] last_diff_char = " " @@ -362,9 +363,15 @@ class DefaultModelEditCodeStep(Step): return True return False - def block_not_empty() -> bool: - nonlocal current_block_added, current_block_removed - return len(current_block_added) or len(current_block_removed) + def should_end_current_block(next_diff_char: str) -> bool: + nonlocal current_block_added, current_block_removed, last_diff_char + if next_diff_char == " ": + return len(current_block_added) or len(current_block_removed) + elif next_diff_char == "-": + return last_diff_char == "+" and len(current_block_removed) + elif next_diff_char == "+": + return last_diff_char == "-" and len(current_block_added) + raise Exception("Invalid next_diff_char") async def handle_generated_line(line: str): nonlocal completion_lines_covered, lines, current_block_added, current_block_removed, offset_from_blocks, original_lines, current_block_start_of_insertion, matched_line, lines_covered_in_this_block, lines_same_in_this_block, current_line_in_file, completion_lines_covered, last_diff_char @@ -379,37 +386,18 @@ class DefaultModelEditCodeStep(Step): next_diff_char = diff[current_line_in_file][0] # If we need to start a new block, end the old one - if next_diff_char != last_diff_char: + if should_end_current_block(next_diff_char): await show_block_as_suggestion() - - if next_diff_char == " ": - if block_not_empty(): - await show_block_as_suggestion() - current_block_start_of_insertion = -1 lines_same_in_this_block += 1 elif next_diff_char == "-": # Line was removed from the original, add it to the block - if block_not_empty(): - # Matches something, add all lines up to this as red in the old block, then show the block - await show_block_as_suggestion() - # Begin next block! - lines_same_in_this_block = 0 - lines_covered_in_this_block = 0 - current_block_start_of_insertion = -1 - lines_same_in_this_block += 1 + await add_red_to_block(line) + elif next_diff_char == "+": # Line was added to the original, add it to the block - - if block_not_empty(): - # Matches something, add all lines up to this as red in the old block, then show the block - await show_block_as_suggestion() - # Begin next block! - lines_same_in_this_block = 0 - lines_covered_in_this_block = 0 - current_block_start_of_insertion = -1 - lines_same_in_this_block += 1 + await add_green_to_block(line) else: raise Exception("Unexpected diff character: " + -- cgit v1.2.3-70-g09d2 From d36b7b74351581c64a5c4a91949bef9cf611516f Mon Sep 17 00:00:00 2001 From: Nate Sesti <sestinj@gmail.com> Date: Sun, 25 Jun 2023 10:24:05 -0700 Subject: red/green updates --- continuedev/src/continuedev/steps/core/core.py | 83 ++++++++++++++------------ 1 file changed, 45 insertions(+), 38 deletions(-) (limited to 'continuedev/src') diff --git a/continuedev/src/continuedev/steps/core/core.py b/continuedev/src/continuedev/steps/core/core.py index 64f53c0f..539a3990 100644 --- a/continuedev/src/continuedev/steps/core/core.py +++ b/continuedev/src/continuedev/steps/core/core.py @@ -2,7 +2,7 @@ import os import subprocess from textwrap import dedent -from typing import Coroutine, List, Union +from typing import Coroutine, List, Literal, Union from ...models.main import Range from ...libs.llm.prompt_utils import MarkdownStyleEncoderDecoder @@ -271,7 +271,7 @@ class DefaultModelEditCodeStep(Step): lines = [] unfinished_line = "" - red_or_green_first = "green" + red_or_green_first: Literal["green", "red"] = "green" current_block_added = [] current_block_removed = [] last_diff_char = " " @@ -284,46 +284,50 @@ class DefaultModelEditCodeStep(Step): liness_deleted_in_this_block = 0 lines_same_in_this_block = 0 - async def insert_line(line: str, line_no: int): - nonlocal current_block_added - # Insert line, highlight green, highlight corresponding line red - red_line = line_no + len(current_block_added) + 1 - range = Range.from_shorthand( - line_no, 0, line_no, 0) - red_range = Range.from_shorthand( - red_line, 0, red_line, 0) - - await sdk.ide.applyFileSystemEdit(FileEdit( - filepath=rif.filepath, - range=range, - replacement=line + "\n" - )) - await sdk.ide.highlightCode(RangeInFile(filepath=rif.filepath, range=range), "#00FF0022") - await sdk.ide.highlightCode(RangeInFile(filepath=rif.filepath, range=red_range), "#FF000022") + async def insert_line(line: str, line_no: int, color: Literal{"red", "green"}): + if color == "green": + range = Range.from_shorthand( + line_no, 0, line_no, 0) + + await sdk.ide.applyFileSystemEdit(FileEdit( + filepath=rif.filepath, + range=range, + replacement=line + "\n" + )) + + color = '#00FF0022' if color == "green" else "#FF000022" + await sdk.ide.highlightCode(RangeInFile(filepath=rif.filepath, range=range), color) async def show_block_as_suggestion(): nonlocal completion_lines_covered, offset_from_blocks, current_block_added, current_block_removed, current_block_start_of_insertion, matched_line, last_matched_line, lines_covered_in_this_block, liness_deleted_in_this_block, current_line_in_file end_line = offset_from_blocks + rif.range.start.line + matched_line - # Delete the green inserted lines, because they will be shown as part of the suggestion - await sdk.ide.applyFileSystemEdit(FileEdit( - filepath=rif.filepath, - range=Range.from_shorthand( - current_block_start_of_insertion, 0, current_block_start_of_insertion + len(current_block), 0), - replacement="" - )) - - lines_deleted_in_this_block = lines_covered_in_this_block - lines_same_in_this_block - await sdk.ide.showSuggestion(FileEdit( - filepath=rif.filepath, - range=Range.from_shorthand( - current_block_start_of_insertion, 0, end_line, 0), - replacement="\n".join(current_block) + "\n" - )) - - current_line_in_file = end_line + \ - len(current_block) + 1 # CURRENTLY TODO HERE NOTE - offset_from_blocks += len(current_block) - current_block.clear() + + if red_or_green_first == "green": + # Delete the green inserted lines, because they will be shown as part of the suggestion + await sdk.ide.applyFileSystemEdit(FileEdit( + filepath=rif.filepath, + range=Range.from_shorthand( + current_block_start_of_insertion, 0, current_block_start_of_insertion + len(current_block), 0), + replacement="" + )) + + lines_deleted_in_this_block = lines_covered_in_this_block - lines_same_in_this_block + await sdk.ide.showSuggestion(FileEdit( + filepath=rif.filepath, + range=Range.from_shorthand( + current_block_start_of_insertion, 0, end_line, 0), + replacement="\n".join(current_block) + "\n" + )) + current_line_in_file = end_line + \ + len(current_block) + 1 # CURRENTLY TODO HERE NOTE + offset_from_blocks += len(current_block) + current_block.clear() + else: + # Ends in green, so if you want to delete the lines before the matched line, you need to start a new block. + current_block = [ + line for line in original_lines[] + ] + async def add_green_to_block(line: str): # Keep track of where the first inserted line in this block came from @@ -335,6 +339,9 @@ class DefaultModelEditCodeStep(Step): await insert_line(line, current_line_in_file) current_block.append(line) + async def add_red_to_block(line: str): + await insert_line() + def line_matches_something_in_original(line: str) -> bool: nonlocal offset_from_blocks, last_matched_line, matched_line, lines_covered_in_this_block diff = list(filter(lambda x: not x.startswith("?"), difflib.ndiff( -- cgit v1.2.3-70-g09d2 From 035a7cddec9bd26f834bc1c4fadd2cefdbb7b6dd Mon Sep 17 00:00:00 2001 From: Nate Sesti <sestinj@gmail.com> Date: Sun, 25 Jun 2023 20:54:40 -0700 Subject: more streaming --- continuedev/src/continuedev/steps/core/core.py | 47 ++++++++++++++++---------- 1 file changed, 30 insertions(+), 17 deletions(-) (limited to 'continuedev/src') diff --git a/continuedev/src/continuedev/steps/core/core.py b/continuedev/src/continuedev/steps/core/core.py index 539a3990..1ca08951 100644 --- a/continuedev/src/continuedev/steps/core/core.py +++ b/continuedev/src/continuedev/steps/core/core.py @@ -284,7 +284,7 @@ class DefaultModelEditCodeStep(Step): liness_deleted_in_this_block = 0 lines_same_in_this_block = 0 - async def insert_line(line: str, line_no: int, color: Literal{"red", "green"}): + async def insert_line(line: str, line_no: int, color: Literal["red", "green"]): if color == "green": range = Range.from_shorthand( line_no, 0, line_no, 0) @@ -307,7 +307,7 @@ class DefaultModelEditCodeStep(Step): await sdk.ide.applyFileSystemEdit(FileEdit( filepath=rif.filepath, range=Range.from_shorthand( - current_block_start_of_insertion, 0, current_block_start_of_insertion + len(current_block), 0), + current_block_start_of_insertion, 0, current_block_start_of_insertion + len(current_block_added), 0), replacement="" )) @@ -316,36 +316,45 @@ class DefaultModelEditCodeStep(Step): filepath=rif.filepath, range=Range.from_shorthand( current_block_start_of_insertion, 0, end_line, 0), - replacement="\n".join(current_block) + "\n" + replacement="\n".join(current_block_added) + "\n" )) - current_line_in_file = end_line + \ - len(current_block) + 1 # CURRENTLY TODO HERE NOTE - offset_from_blocks += len(current_block) - current_block.clear() else: # Ends in green, so if you want to delete the lines before the matched line, you need to start a new block. - current_block = [ - line for line in original_lines[] - ] + pass + # current_block = [ + # line for line in original_lines[] + # ] + current_line_in_file = end_line + \ + len(current_block_added) + 1 # CURRENTLY TODO HERE NOTE + offset_from_blocks += len(current_block_added) + current_block_added.clear() + current_block_removed.clear() async def add_green_to_block(line: str): # Keep track of where the first inserted line in this block came from - nonlocal current_block_start_of_insertion + nonlocal current_block_start_of_insertion, current_block_added if current_block_start_of_insertion < 0: current_block_start_of_insertion = current_line_in_file # Insert the line, highlight green - await insert_line(line, current_line_in_file) - current_block.append(line) + await insert_line(line, current_line_in_file, "green") + current_block_added.append(line) + range = Range.from_shorthand( + current_line_in_file, 0, current_line_in_file, 0) + await sdk.ide.highlightCode(RangeInFile(filepath=rif.filepath, range=range), "#00FF0022") async def add_red_to_block(line: str): - await insert_line() + # Highlight the current line red and insert + current_block_removed.append(line) + range = Range.from_shorthand( + current_line_in_file, 0, current_line_in_file, 0) + await sdk.ide.highlightCode(RangeInFile(filepath=rif.filepath, range=range), "#FF000022") def line_matches_something_in_original(line: str) -> bool: nonlocal offset_from_blocks, last_matched_line, matched_line, lines_covered_in_this_block diff = list(filter(lambda x: not x.startswith("?"), difflib.ndiff( - original_lines[matched_line:], current_block + [line]))) + original_lines[matched_line:], current_block_added + [line]))) i = current_line_in_file if diff[i][0] == " ": @@ -389,7 +398,7 @@ class DefaultModelEditCodeStep(Step): # Get the diff of current block and the original diff = list(filter(lambda x: not x.startswith("?"), difflib.ndiff( - original_lines[matched_line:], current_block_added + [line]))) + original_lines, lines + [line]))) next_diff_char = diff[current_line_in_file][0] # If we need to start a new block, end the old one @@ -406,6 +415,10 @@ class DefaultModelEditCodeStep(Step): # Line was added to the original, add it to the block await add_green_to_block(line) + elif next_diff_char == " ": + # Line was unchanged, and didn't have to end a block + pass + else: raise Exception("Unexpected diff character: " + diff[current_line_in_file][0]) @@ -468,7 +481,7 @@ class DefaultModelEditCodeStep(Step): # await sdk.ide.highlightCode(RangeInFile(filepath=rif.filepath, range=range), "#FF000022") # If the current block isn't empty, add that suggestion - if len(current_block) > 0: + if len(current_block_added) > 0 or len(current_block_removed) > 0: matched_line = rif.range.end.line - rif.range.start.line await show_block_as_suggestion() -- cgit v1.2.3-70-g09d2 From 3ecd29eb6031be378d8c8f01a1e25259e04087e5 Mon Sep 17 00:00:00 2001 From: Nate Sesti <sestinj@gmail.com> Date: Tue, 27 Jun 2023 00:20:56 -0700 Subject: checkpoint on new streaming --- .../src/continuedev/libs/llm/proxy_server.py | 4 +- continuedev/src/continuedev/steps/core/core.py | 216 ++++++--------------- extension/src/activation/environmentSetup.ts | 6 +- extension/src/continueIdeClient.ts | 6 + extension/src/lang-server/codeLens.ts | 4 +- extension/src/suggestions.ts | 52 +++-- 6 files changed, 106 insertions(+), 182 deletions(-) (limited to 'continuedev/src') diff --git a/continuedev/src/continuedev/libs/llm/proxy_server.py b/continuedev/src/continuedev/libs/llm/proxy_server.py index a29f5c89..78219695 100644 --- a/continuedev/src/continuedev/libs/llm/proxy_server.py +++ b/continuedev/src/continuedev/libs/llm/proxy_server.py @@ -71,7 +71,7 @@ class ProxyServer(LLM): async def complete(self, prompt: str, with_history: List[ChatMessage] = [], **kwargs) -> Coroutine[Any, Any, str]: async with aiohttp.ClientSession() as session: async with session.post(f"{SERVER_URL}/complete", json={ - "chat_history": self.compile_chat_messages(with_history, prompt), + "messages": self.compile_chat_messages(with_history, prompt), "model": self.default_model, "unique_id": self.unique_id, }) as resp: @@ -83,7 +83,7 @@ class ProxyServer(LLM): async def stream_chat(self, prompt, with_history: List[ChatMessage] = [], **kwargs) -> Generator[Union[Any, List, Dict], None, None]: async with aiohttp.ClientSession() as session: async with session.post(f"{SERVER_URL}/stream_complete", json={ - "chat_history": self.compile_chat_messages(with_history, prompt), + "messages": self.compile_chat_messages(with_history, prompt), "model": self.default_model, "unique_id": self.unique_id, }) as resp: diff --git a/continuedev/src/continuedev/steps/core/core.py b/continuedev/src/continuedev/steps/core/core.py index 1ca08951..7a62220b 100644 --- a/continuedev/src/continuedev/steps/core/core.py +++ b/continuedev/src/continuedev/steps/core/core.py @@ -268,166 +268,61 @@ class DefaultModelEditCodeStep(Step): completion_lines_covered = 0 # In the actual file, as it is with blocks and such current_line_in_file = rif.range.start.line - lines = [] - unfinished_line = "" - - red_or_green_first: Literal["green", "red"] = "green" - current_block_added = [] - current_block_removed = [] - last_diff_char = " " + current_block_lines = [] + original_lines_below_previous_blocks = original_lines + current_block_start = -1 offset_from_blocks = 0 - last_matched_line = 0 - matched_line = 0 - current_block_start_of_insertion = -1 - lines_covered_in_this_block = 0 - liness_deleted_in_this_block = 0 - lines_same_in_this_block = 0 - - async def insert_line(line: str, line_no: int, color: Literal["red", "green"]): - if color == "green": - range = Range.from_shorthand( - line_no, 0, line_no, 0) - - await sdk.ide.applyFileSystemEdit(FileEdit( - filepath=rif.filepath, - range=range, - replacement=line + "\n" - )) - - color = '#00FF0022' if color == "green" else "#FF000022" - await sdk.ide.highlightCode(RangeInFile(filepath=rif.filepath, range=range), color) - - async def show_block_as_suggestion(): - nonlocal completion_lines_covered, offset_from_blocks, current_block_added, current_block_removed, current_block_start_of_insertion, matched_line, last_matched_line, lines_covered_in_this_block, liness_deleted_in_this_block, current_line_in_file - end_line = offset_from_blocks + rif.range.start.line + matched_line - - if red_or_green_first == "green": - # Delete the green inserted lines, because they will be shown as part of the suggestion - await sdk.ide.applyFileSystemEdit(FileEdit( - filepath=rif.filepath, - range=Range.from_shorthand( - current_block_start_of_insertion, 0, current_block_start_of_insertion + len(current_block_added), 0), - replacement="" - )) - - lines_deleted_in_this_block = lines_covered_in_this_block - lines_same_in_this_block - await sdk.ide.showSuggestion(FileEdit( - filepath=rif.filepath, - range=Range.from_shorthand( - current_block_start_of_insertion, 0, end_line, 0), - replacement="\n".join(current_block_added) + "\n" - )) - else: - # Ends in green, so if you want to delete the lines before the matched line, you need to start a new block. - pass - # current_block = [ - # line for line in original_lines[] - # ] - - current_line_in_file = end_line + \ - len(current_block_added) + 1 # CURRENTLY TODO HERE NOTE - offset_from_blocks += len(current_block_added) - current_block_added.clear() - current_block_removed.clear() - - async def add_green_to_block(line: str): - # Keep track of where the first inserted line in this block came from - nonlocal current_block_start_of_insertion, current_block_added - if current_block_start_of_insertion < 0: - current_block_start_of_insertion = current_line_in_file - - # Insert the line, highlight green - await insert_line(line, current_line_in_file, "green") - current_block_added.append(line) - range = Range.from_shorthand( - current_line_in_file, 0, current_line_in_file, 0) - await sdk.ide.highlightCode(RangeInFile(filepath=rif.filepath, range=range), "#00FF0022") - - async def add_red_to_block(line: str): - # Highlight the current line red and insert - current_block_removed.append(line) - range = Range.from_shorthand( - current_line_in_file, 0, current_line_in_file, 0) - await sdk.ide.highlightCode(RangeInFile(filepath=rif.filepath, range=range), "#FF000022") - - def line_matches_something_in_original(line: str) -> bool: - nonlocal offset_from_blocks, last_matched_line, matched_line, lines_covered_in_this_block - diff = list(filter(lambda x: not x.startswith("?"), difflib.ndiff( - original_lines[matched_line:], current_block_added + [line]))) - - i = current_line_in_file - if diff[i][0] == " ": - last_matched_line = matched_line - matched_line = i - lines_covered_in_this_block = matched_line - last_matched_line - return True - elif diff[i][0] == "-": - last_matched_line = matched_line - matched_line = i - lines_covered_in_this_block = matched_line - last_matched_line - return True - elif diff[i][0] == "+": - return False - - # TODO: and line.strip() != ""? - for j in range(matched_line, len(original_lines)): - if line == original_lines[j]: - last_matched_line = matched_line - matched_line = j - lines_covered_in_this_block = matched_line - last_matched_line - return True - return False - - def should_end_current_block(next_diff_char: str) -> bool: - nonlocal current_block_added, current_block_removed, last_diff_char - if next_diff_char == " ": - return len(current_block_added) or len(current_block_removed) - elif next_diff_char == "-": - return last_diff_char == "+" and len(current_block_removed) - elif next_diff_char == "+": - return last_diff_char == "-" and len(current_block_added) - raise Exception("Invalid next_diff_char") + + lines_of_prefix_copied = 0 + repeating_file_suffix = False + line_below_highlighted_range = file_suffix.lstrip().split("\n")[0] + lines = [] + unfinished_line = "" async def handle_generated_line(line: str): - nonlocal completion_lines_covered, lines, current_block_added, current_block_removed, offset_from_blocks, original_lines, current_block_start_of_insertion, matched_line, lines_covered_in_this_block, lines_same_in_this_block, current_line_in_file, completion_lines_covered, last_diff_char + nonlocal lines, current_block_start, current_line_in_file, original_lines, original_lines_below_previous_blocks, current_block_lines, offset_from_blocks # Highlight the line to show progress await sdk.ide.highlightCode(RangeInFile(filepath=rif.filepath, range=Range.from_shorthand( - current_line_in_file, 0, current_line_in_file, 0)), "#FFFFFF22") - - # Get the diff of current block and the original - diff = list(filter(lambda x: not x.startswith("?"), difflib.ndiff( - original_lines, lines + [line]))) - next_diff_char = diff[current_line_in_file][0] + current_line_in_file, 0, current_line_in_file, 0)), "#FFFFFF22" if len(current_block_lines) == 0 else "#FFFF0022") + + if len(current_block_lines) == 0: + if len(original_lines_below_previous_blocks) == 0 or line != original_lines_below_previous_blocks[0]: + current_block_lines.append(line) + current_block_start = current_line_in_file + + else: + original_lines_below_previous_blocks = original_lines_below_previous_blocks[ + 1:] + return + + # We are in a block currently, and checking for whether it should be ended + for i in range(len(original_lines_below_previous_blocks)): + og_line = original_lines_below_previous_blocks[i] + if og_line == line and len(og_line.strip()): + # Gather the lines to insert/replace for the suggestion + lines_to_replace = current_block_lines[:i] + original_lines_below_previous_blocks = original_lines_below_previous_blocks[ + i + 1:] + + # Insert the suggestion + await sdk.ide.showSuggestion(FileEdit( + filepath=rif.filepath, + range=Range.from_shorthand( + current_block_start, 0, current_block_start + i, 0), + replacement="\n".join(current_block_lines) + )) + + # Reset current block + offset_from_blocks += len(current_block_lines) + current_line_in_file += len(current_block_lines) + current_block_lines = [] + current_block_start = -1 + return + + current_block_lines.append(line) - # If we need to start a new block, end the old one - if should_end_current_block(next_diff_char): - await show_block_as_suggestion() - current_block_start_of_insertion = -1 - lines_same_in_this_block += 1 - - elif next_diff_char == "-": - # Line was removed from the original, add it to the block - await add_red_to_block(line) - - elif next_diff_char == "+": - # Line was added to the original, add it to the block - await add_green_to_block(line) - - elif next_diff_char == " ": - # Line was unchanged, and didn't have to end a block - pass - - else: - raise Exception("Unexpected diff character: " + - diff[current_line_in_file][0]) - - last_diff_char = next_diff_char - - lines_of_prefix_copied = 0 - repeating_file_suffix = False - line_below_highlighted_range = file_suffix.lstrip().split("\n")[0] async for chunk in model_to_use.stream_chat(prompt, with_history=await sdk.get_chat_context(), temperature=0): # Stop early if it is repeating the file_suffix if repeating_file_suffix: @@ -473,17 +368,14 @@ class DefaultModelEditCodeStep(Step): await handle_generated_line(unfinished_line) completion_lines_covered += 1 - # Highlight the remainder of the range red - if completion_lines_covered < len(original_lines): - await handle_generated_line("") - # range = Range.from_shorthand( - # i + 1 + offset_from_blocks + rif.range.start.line, 0, len(original_lines) + offset_from_blocks + rif.range.start.line, 0) - # await sdk.ide.highlightCode(RangeInFile(filepath=rif.filepath, range=range), "#FF000022") - # If the current block isn't empty, add that suggestion - if len(current_block_added) > 0 or len(current_block_removed) > 0: - matched_line = rif.range.end.line - rif.range.start.line - await show_block_as_suggestion() + if len(current_block_lines) > 0: + await sdk.ide.showSuggestion(FileEdit( + filepath=rif.filepath, + range=Range.from_shorthand( + current_block_start, 0, current_block_start + len(original_lines_below_previous_blocks), 0), + replacement="\n".join(current_block_lines) + )) # Record the completion completion = "\n".join(lines) diff --git a/extension/src/activation/environmentSetup.ts b/extension/src/activation/environmentSetup.ts index 593b727e..cdaf3ac0 100644 --- a/extension/src/activation/environmentSetup.ts +++ b/extension/src/activation/environmentSetup.ts @@ -121,7 +121,7 @@ async function setupPythonEnv() { activateCmd, pipUpgradeCmd, `${pipCmd} install -r requirements.txt`, - ].join(" && "); + ].join(" ; "); const [, stderr] = await runCommand(installRequirementsCommand); if (stderr) { throw new Error(stderr); @@ -255,10 +255,10 @@ export async function downloadPython3() { throw new Error("python3 not found"); } else if (os === "linux") { command = - "sudo apt update && upgrade && sudo apt install python3 python3-pip"; + "sudo apt update ; upgrade ; sudo apt install python3 python3-pip"; } else if (os === "win32") { command = - "wget -O python_installer.exe https://www.python.org/ftp/python/3.11.3/python-3.11.3-amd64.exe && python_installer.exe /quiet InstallAllUsers=1 PrependPath=1 Include_test=0"; + "wget -O python_installer.exe https://www.python.org/ftp/python/3.11.3/python-3.11.3-amd64.exe ; python_installer.exe /quiet InstallAllUsers=1 PrependPath=1 Include_test=0"; pythonCmd = "python"; } diff --git a/extension/src/continueIdeClient.ts b/extension/src/continueIdeClient.ts index b1fcd6fb..877d9f3e 100644 --- a/extension/src/continueIdeClient.ts +++ b/extension/src/continueIdeClient.ts @@ -145,6 +145,7 @@ class IdeProtocolClient { // ------------------------------------ // // On message handlers + private _lastDecorationType: vscode.TextEditorDecorationType | null = null; async highlightCode(rangeInFile: RangeInFile, color: string) { const range = new vscode.Range( rangeInFile.range.start.line, @@ -172,6 +173,11 @@ class IdeProtocolClient { } } ); + + if (this._lastDecorationType) { + editor.setDecorations(this._lastDecorationType, []); + } + this._lastDecorationType = decorationType; } } diff --git a/extension/src/lang-server/codeLens.ts b/extension/src/lang-server/codeLens.ts index e8766c3c..3979b64d 100644 --- a/extension/src/lang-server/codeLens.ts +++ b/extension/src/lang-server/codeLens.ts @@ -20,12 +20,12 @@ class SuggestionsCodeLensProvider implements vscode.CodeLensProvider { ); codeLenses.push( new vscode.CodeLens(range, { - title: "Accept", + title: "Accept ✅", command: "continue.acceptSuggestion", arguments: [suggestion], }), new vscode.CodeLens(range, { - title: "Reject", + title: "Reject ❌", command: "continue.rejectSuggestion", arguments: [suggestion], }) diff --git a/extension/src/suggestions.ts b/extension/src/suggestions.ts index 2e4e0ea2..9b358899 100644 --- a/extension/src/suggestions.ts +++ b/extension/src/suggestions.ts @@ -59,10 +59,35 @@ export function rerenderDecorations(editorUri: string) { ); if (!suggestions || !editor) return; - const olds: vscode.Range[] = []; - const news: vscode.Range[] = []; - const oldSels: vscode.Range[] = []; - const newSels: vscode.Range[] = []; + const rangesWithoutEmptyLastLine = (ranges: vscode.Range[]) => { + const newRanges: vscode.Range[] = []; + for (let i = 0; i < ranges.length; i++) { + const range = ranges[i]; + if ( + range.start.line === range.end.line && + range.start.character === 0 && + range.end.character === 0 + ) { + // Empty range, don't show it + continue; + } + newRanges.push( + new vscode.Range( + range.start.line, + range.start.character, + // Don't include the last line if it is empty + range.end.line - (range.end.character === 0 ? 1 : 0), + range.end.character + ) + ); + } + return newRanges; + }; + + let olds: vscode.Range[] = []; + let news: vscode.Range[] = []; + let oldSels: vscode.Range[] = []; + let newSels: vscode.Range[] = []; for (let i = 0; i < suggestions.length; i++) { const suggestion = suggestions[i]; if (typeof idx != "undefined" && idx === i) { @@ -78,6 +103,13 @@ export function rerenderDecorations(editorUri: string) { news.push(suggestion.newRange); } } + + // Don't highlight the last line if it is empty + olds = rangesWithoutEmptyLastLine(olds); + news = rangesWithoutEmptyLastLine(news); + oldSels = rangesWithoutEmptyLastLine(oldSels); + newSels = rangesWithoutEmptyLastLine(newSels); + editor.setDecorations(oldDecorationType, olds); editor.setDecorations(newDecorationType, news); editor.setDecorations(oldSelDecorationType, oldSels); @@ -174,7 +206,7 @@ function selectSuggestion( rangeToDelete = new vscode.Range( rangeToDelete.start, - new vscode.Position(rangeToDelete.end.line + 1, 0) + new vscode.Position(rangeToDelete.end.line, 0) ); editor.edit((edit) => { edit.delete(rangeToDelete); @@ -261,19 +293,13 @@ export async function showSuggestion( return new Promise((resolve, reject) => { editor! .edit((edit) => { - if (range.end.line + 1 >= editor.document.lineCount) { - suggestion = "\n" + suggestion; - } - edit.insert( - new vscode.Position(range.end.line + 1, 0), - suggestion + "\n" - ); + edit.insert(new vscode.Position(range.end.line, 0), suggestion + "\n"); }) .then( (success) => { if (success) { let suggestionRange = new vscode.Range( - new vscode.Position(range.end.line + 1, 0), + new vscode.Position(range.end.line, 0), new vscode.Position( range.end.line + suggestion.split("\n").length, 0 -- cgit v1.2.3-70-g09d2 From 3d12cc4ac269f90dfe50eef2830887bff6719a33 Mon Sep 17 00:00:00 2001 From: Nate Sesti <sestinj@gmail.com> Date: Tue, 27 Jun 2023 10:42:11 -0700 Subject: checkpoint - working well --- continuedev/src/continuedev/steps/core/core.py | 1 - 1 file changed, 1 deletion(-) (limited to 'continuedev/src') diff --git a/continuedev/src/continuedev/steps/core/core.py b/continuedev/src/continuedev/steps/core/core.py index 7a62220b..ae58cc99 100644 --- a/continuedev/src/continuedev/steps/core/core.py +++ b/continuedev/src/continuedev/steps/core/core.py @@ -316,7 +316,6 @@ class DefaultModelEditCodeStep(Step): # Reset current block offset_from_blocks += len(current_block_lines) - current_line_in_file += len(current_block_lines) current_block_lines = [] current_block_start = -1 return -- cgit v1.2.3-70-g09d2 From bedd5f31e7a1d7b915fbb2a47a92f58035c96415 Mon Sep 17 00:00:00 2001 From: Nate Sesti <sestinj@gmail.com> Date: Tue, 27 Jun 2023 11:03:44 -0700 Subject: stop completion early, accept all improvements --- continuedev/src/continuedev/core/autopilot.py | 2 +- continuedev/src/continuedev/core/sdk.py | 3 +++ continuedev/src/continuedev/steps/core/core.py | 4 +++- extension/src/lang-server/codeLens.ts | 4 ++++ extension/src/suggestions.ts | 2 +- 5 files changed, 12 insertions(+), 3 deletions(-) (limited to 'continuedev/src') diff --git a/continuedev/src/continuedev/core/autopilot.py b/continuedev/src/continuedev/core/autopilot.py index a6e688ae..17eb70b3 100644 --- a/continuedev/src/continuedev/core/autopilot.py +++ b/continuedev/src/continuedev/core/autopilot.py @@ -121,7 +121,7 @@ class Autopilot(ContinueBaseModel): # If a parent step is deleted/cancelled, don't run this step last_depth = self._step_depth i = self.history.current_index - while i >= 0 and self.history.timeline[i].depth == last_depth + 1: + while i >= 0 and self.history.timeline[i].depth == last_depth - 1: if self.history.timeline[i].deleted: return None last_depth = self.history.timeline[i].depth diff --git a/continuedev/src/continuedev/core/sdk.py b/continuedev/src/continuedev/core/sdk.py index d6acc404..8b82aee0 100644 --- a/continuedev/src/continuedev/core/sdk.py +++ b/continuedev/src/continuedev/core/sdk.py @@ -207,3 +207,6 @@ class ContinueSDK(AbstractContinueSDK): async def clear_history(self): await self.__autopilot.clear_history() + + def current_step_was_deleted(self): + return self.history.timeline[self.history.current_index].deleted diff --git a/continuedev/src/continuedev/steps/core/core.py b/continuedev/src/continuedev/steps/core/core.py index ae58cc99..4ec8fe9e 100644 --- a/continuedev/src/continuedev/steps/core/core.py +++ b/continuedev/src/continuedev/steps/core/core.py @@ -323,9 +323,11 @@ class DefaultModelEditCodeStep(Step): current_block_lines.append(line) async for chunk in model_to_use.stream_chat(prompt, with_history=await sdk.get_chat_context(), temperature=0): - # Stop early if it is repeating the file_suffix + # Stop early if it is repeating the file_suffix or the step was deleted if repeating_file_suffix: break + if sdk.current_step_was_deleted(): + return # Accumulate lines chunk_lines = chunk.split("\n") diff --git a/extension/src/lang-server/codeLens.ts b/extension/src/lang-server/codeLens.ts index 3979b64d..629da0b8 100644 --- a/extension/src/lang-server/codeLens.ts +++ b/extension/src/lang-server/codeLens.ts @@ -28,6 +28,10 @@ class SuggestionsCodeLensProvider implements vscode.CodeLensProvider { title: "Reject ❌", command: "continue.rejectSuggestion", arguments: [suggestion], + }), + new vscode.CodeLens(range, { + title: "(⌘⇧↩/⌘⇧⌫ to accept/reject all)", + command: "", }) ); } diff --git a/extension/src/suggestions.ts b/extension/src/suggestions.ts index 4631c33e..209bf8b2 100644 --- a/extension/src/suggestions.ts +++ b/extension/src/suggestions.ts @@ -246,7 +246,7 @@ function handleAllSuggestions(accept: boolean) { if (!suggestions) return; while (suggestions.length > 0) { - selectSuggestion(accept ? "new" : "old"); + selectSuggestion(accept ? "new" : "old", suggestions[0]); } } -- cgit v1.2.3-70-g09d2 From bf998a752a547485189f5ac1dc415d7ec475099e Mon Sep 17 00:00:00 2001 From: Nate Sesti <sestinj@gmail.com> Date: Tue, 27 Jun 2023 11:42:09 -0700 Subject: post-merge fixes --- continuedev/src/continuedev/steps/chat.py | 8 ++++++-- continuedev/src/continuedev/steps/core/core.py | 13 +++++++++++-- extension/src/activation/activate.ts | 15 +++++++++++++-- 3 files changed, 30 insertions(+), 6 deletions(-) (limited to 'continuedev/src') diff --git a/continuedev/src/continuedev/steps/chat.py b/continuedev/src/continuedev/steps/chat.py index 54d9c657..50e0f905 100644 --- a/continuedev/src/continuedev/steps/chat.py +++ b/continuedev/src/continuedev/steps/chat.py @@ -47,9 +47,13 @@ class AddFileStep(Step): except FileNotFoundError: self.description = f"File {self.filename} does not exist." return - currently_open_file = (await sdk.ide.getOpenFiles())[0] + await sdk.ide.setFileOpen(os.path.join(sdk.ide.workspace_directory, self.filename)) - await sdk.ide.setFileOpen(currently_open_file) + + open_files = await sdk.ide.getOpenFiles() + if len(open_files) > 0: + currently_open_file = (await sdk.ide.getOpenFiles())[0] + await sdk.ide.setFileOpen(currently_open_file) class DeleteFileStep(Step): diff --git a/continuedev/src/continuedev/steps/core/core.py b/continuedev/src/continuedev/steps/core/core.py index a487a1b5..9545e9c7 100644 --- a/continuedev/src/continuedev/steps/core/core.py +++ b/continuedev/src/continuedev/steps/core/core.py @@ -9,7 +9,7 @@ from ...libs.llm.prompt_utils import MarkdownStyleEncoderDecoder from ...models.filesystem_edit import EditDiff, FileEdit, FileEditWithFullContents, FileSystemEdit from ...models.filesystem import FileSystem, RangeInFile, RangeInFileWithContents from ...core.observation import Observation, TextObservation, TracebackObservation, UserInputObservation -from ...core.main import Step, SequentialStep +from ...core.main import ChatMessage, Step, SequentialStep from ...libs.util.count_tokens import MAX_TOKENS_FOR_MODEL, DEFAULT_MAX_TOKENS import difflib @@ -322,7 +322,13 @@ class DefaultModelEditCodeStep(Step): current_block_lines.append(line) - async for chunk in model_to_use.stream_chat(prompt, with_history=await sdk.get_chat_context(), temperature=0): + messages = await sdk.get_chat_context() + messages.append(ChatMessage( + role="user", + content=prompt, + summary=self.user_input + )) + async for chunk in model_to_use.stream_chat(messages, temperature=0): # Stop early if it is repeating the file_suffix or the step was deleted if repeating_file_suffix: break @@ -330,6 +336,9 @@ class DefaultModelEditCodeStep(Step): return # Accumulate lines + if "content" not in chunk: + continue + chunk = chunk["content"] chunk_lines = chunk.split("\n") chunk_lines[0] = unfinished_line + chunk_lines[0] if chunk.endswith("\n"): diff --git a/extension/src/activation/activate.ts b/extension/src/activation/activate.ts index 0c92f095..df8b6871 100644 --- a/extension/src/activation/activate.ts +++ b/extension/src/activation/activate.ts @@ -24,8 +24,19 @@ export async function activateExtension( registerAllCodeLensProviders(context); registerAllCommands(context); - // vscode.window.registerWebviewViewProvider("continue.continueGUIView", setupDebugPanel); - await startContinuePythonServer(); + await new Promise((resolve, reject) => { + vscode.window.withProgress( + { + location: vscode.ProgressLocation.Notification, + title: "Starting Continue Server...", + cancellable: false, + }, + async (progress, token) => { + await startContinuePythonServer(); + resolve(null); + } + ); + }); const serverUrl = getContinueServerUrl(); ideProtocolClient = new IdeProtocolClient( -- cgit v1.2.3-70-g09d2