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