summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNate Sesti <sestinj@gmail.com>2023-06-21 14:02:56 -0700
committerNate Sesti <sestinj@gmail.com>2023-06-21 14:02:56 -0700
commit287ec48055b86afad2fdd62fdd3f3987077f448b (patch)
tree909e15a69d0f1bd521c9e13721dd9f2ab4d41619
parent5165f4b3a44b3293972657b4c64210d92784b076 (diff)
downloadsncontinue-287ec48055b86afad2fdd62fdd3f3987077f448b.tar.gz
sncontinue-287ec48055b86afad2fdd62fdd3f3987077f448b.tar.bz2
sncontinue-287ec48055b86afad2fdd62fdd3f3987077f448b.zip
first slightly working version of suggestions
-rw-r--r--continuedev/src/continuedev/server/ide.py6
-rw-r--r--continuedev/src/continuedev/server/ide_protocol.py2
-rw-r--r--continuedev/src/continuedev/steps/core/core.py448
-rw-r--r--extension/src/continueIdeClient.ts25
-rw-r--r--extension/src/lang-server/codeLens.ts19
-rw-r--r--extension/src/suggestions.ts60
-rw-r--r--extension/src/util/vscode.ts20
7 files changed, 286 insertions, 294 deletions
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):
diff --git a/extension/src/continueIdeClient.ts b/extension/src/continueIdeClient.ts
index fbad5f5d..fbd00c6e 100644
--- a/extension/src/continueIdeClient.ts
+++ b/extension/src/continueIdeClient.ts
@@ -1,5 +1,8 @@
// import { ShowSuggestionRequest } from "../schema/ShowSuggestionRequest";
-import { showSuggestion, SuggestionRanges } from "./suggestions";
+import {
+ showSuggestion as showSuggestionInEditor,
+ SuggestionRanges,
+} from "./suggestions";
import { openEditorAndRevealRange, getRightViewColumn } from "./util/vscode";
import { FileEdit } from "../schema/FileEdit";
import { RangeInFile } from "../schema/RangeInFile";
@@ -115,7 +118,10 @@ class IdeProtocolClient {
break;
case "setFileOpen":
this.openFile(data.filepath);
- // TODO: Close file
+ // TODO: Close file if False
+ break;
+ case "showSuggestion":
+ this.showSuggestion(data.edit);
break;
case "openGUI":
case "connected":
@@ -157,25 +163,12 @@ class IdeProtocolClient {
isWholeLine: true,
});
editor.setDecorations(decorationType, [range]);
-
- // Listen for changes to cursor position and then remove the decoration (but keep for at least 2 seconds)
- const allowRemoveHighlight = () => {
- const cursorDisposable = vscode.window.onDidChangeTextEditorSelection(
- (event) => {
- if (event.textEditor.document.uri.fsPath === rangeInFile.filepath) {
- cursorDisposable.dispose();
- editor.setDecorations(decorationType, []);
- }
- }
- );
- };
- setTimeout(allowRemoveHighlight, 2000);
}
}
showSuggestion(edit: FileEdit) {
// showSuggestion already exists
- showSuggestion(
+ showSuggestionInEditor(
edit.filepath,
new vscode.Range(
edit.range.start.line,
diff --git a/extension/src/lang-server/codeLens.ts b/extension/src/lang-server/codeLens.ts
index 2a362b62..e8766c3c 100644
--- a/extension/src/lang-server/codeLens.ts
+++ b/extension/src/lang-server/codeLens.ts
@@ -13,8 +13,8 @@ class SuggestionsCodeLensProvider implements vscode.CodeLensProvider {
}
let codeLenses: vscode.CodeLens[] = [];
- for (let suggestion of suggestions) {
- let range = new vscode.Range(
+ for (const suggestion of suggestions) {
+ const range = new vscode.Range(
suggestion.oldRange.start,
suggestion.newRange.end
);
@@ -57,16 +57,16 @@ class PytestCodeLensProvider implements vscode.CodeLensProvider {
document: vscode.TextDocument,
token: vscode.CancellationToken
): vscode.CodeLens[] | Thenable<vscode.CodeLens[]> {
- let codeLenses: vscode.CodeLens[] = [];
+ const codeLenses: vscode.CodeLens[] = [];
let lineno = 1;
- let languageLibrary = getLanguageLibrary(document.fileName);
+ const languageLibrary = getLanguageLibrary(document.fileName);
for (let line of document.getText().split("\n")) {
if (
languageLibrary.lineIsFunctionDef(line) &&
languageLibrary.parseFunctionDefForName(line).startsWith("test_")
) {
- let functionToTest = languageLibrary.parseFunctionDefForName(line);
- let fileAndFunctionNameSpecifier =
+ const functionToTest = languageLibrary.parseFunctionDefForName(line);
+ const fileAndFunctionNameSpecifier =
document.fileName + "::" + functionToTest;
codeLenses.push(
new vscode.CodeLens(new vscode.Range(lineno, 0, lineno, 1), {
@@ -85,12 +85,13 @@ class PytestCodeLensProvider implements vscode.CodeLensProvider {
const allCodeLensProviders: { [langauge: string]: vscode.CodeLensProvider[] } =
{
- python: [new SuggestionsCodeLensProvider(), new PytestCodeLensProvider()],
+ // python: [new SuggestionsCodeLensProvider(), new PytestCodeLensProvider()],
+ "*": [new SuggestionsCodeLensProvider()],
};
export function registerAllCodeLensProviders(context: vscode.ExtensionContext) {
- for (let language in allCodeLensProviders) {
- for (let codeLensProvider of allCodeLensProviders[language]) {
+ for (const language in allCodeLensProviders) {
+ for (const codeLensProvider of allCodeLensProviders[language]) {
context.subscriptions.push(
vscode.languages.registerCodeLensProvider(language, codeLensProvider)
);
diff --git a/extension/src/suggestions.ts b/extension/src/suggestions.ts
index c66fad86..5ac6e095 100644
--- a/extension/src/suggestions.ts
+++ b/extension/src/suggestions.ts
@@ -14,7 +14,7 @@ export const editorToSuggestions: Map<
string, // URI of file
SuggestionRanges[]
> = new Map();
-export let currentSuggestion: Map<string, number> = new Map(); // Map from editor URI to index of current SuggestionRanges in editorToSuggestions
+export const currentSuggestion: Map<string, number> = new Map(); // Map from editor URI to index of current SuggestionRanges in editorToSuggestions
// When tab is reopened, rerender the decorations:
vscode.window.onDidChangeActiveTextEditor((editor) => {
@@ -25,16 +25,16 @@ vscode.workspace.onDidOpenTextDocument((doc) => {
rerenderDecorations(doc.uri.toString());
});
-let newDecorationType = vscode.window.createTextEditorDecorationType({
+const newDecorationType = vscode.window.createTextEditorDecorationType({
backgroundColor: "rgb(0, 255, 0, 0.1)",
isWholeLine: true,
});
-let oldDecorationType = vscode.window.createTextEditorDecorationType({
+const oldDecorationType = vscode.window.createTextEditorDecorationType({
backgroundColor: "rgb(255, 0, 0, 0.1)",
isWholeLine: true,
cursor: "pointer",
});
-let newSelDecorationType = vscode.window.createTextEditorDecorationType({
+const newSelDecorationType = vscode.window.createTextEditorDecorationType({
backgroundColor: "rgb(0, 255, 0, 0.25)",
isWholeLine: true,
after: {
@@ -42,7 +42,7 @@ let newSelDecorationType = vscode.window.createTextEditorDecorationType({
margin: "0 0 0 1em",
},
});
-let oldSelDecorationType = vscode.window.createTextEditorDecorationType({
+const oldSelDecorationType = vscode.window.createTextEditorDecorationType({
backgroundColor: "rgb(255, 0, 0, 0.25)",
isWholeLine: true,
after: {
@@ -52,19 +52,19 @@ let oldSelDecorationType = vscode.window.createTextEditorDecorationType({
});
export function rerenderDecorations(editorUri: string) {
- let suggestions = editorToSuggestions.get(editorUri);
- let idx = currentSuggestion.get(editorUri);
- let editor = vscode.window.visibleTextEditors.find(
+ const suggestions = editorToSuggestions.get(editorUri);
+ const idx = currentSuggestion.get(editorUri);
+ const editor = vscode.window.visibleTextEditors.find(
(editor) => editor.document.uri.toString() === editorUri
);
if (!suggestions || !editor) return;
- let olds: vscode.Range[] = [],
- news: vscode.Range[] = [],
- oldSels: vscode.Range[] = [],
- newSels: vscode.Range[] = [];
+ const olds: vscode.Range[] = [];
+ const news: vscode.Range[] = [];
+ const oldSels: vscode.Range[] = [];
+ const newSels: vscode.Range[] = [];
for (let i = 0; i < suggestions.length; i++) {
- let suggestion = suggestions[i];
+ const suggestion = suggestions[i];
if (typeof idx != "undefined" && idx === i) {
if (suggestion.newSelected) {
olds.push(suggestion.oldRange);
@@ -92,14 +92,14 @@ export function rerenderDecorations(editorUri: string) {
}
export function suggestionDownCommand() {
- let editor = vscode.window.activeTextEditor;
+ const editor = vscode.window.activeTextEditor;
if (!editor) return;
- let editorUri = editor.document.uri.toString();
- let suggestions = editorToSuggestions.get(editorUri);
- let idx = currentSuggestion.get(editorUri);
+ const editorUri = editor.document.uri.toString();
+ const suggestions = editorToSuggestions.get(editorUri);
+ const idx = currentSuggestion.get(editorUri);
if (!suggestions || idx === undefined) return;
- let suggestion = suggestions[idx];
+ const suggestion = suggestions[idx];
if (!suggestion.newSelected) {
suggestion.newSelected = true;
} else if (idx + 1 < suggestions.length) {
@@ -109,14 +109,14 @@ export function suggestionDownCommand() {
}
export function suggestionUpCommand() {
- let editor = vscode.window.activeTextEditor;
+ const editor = vscode.window.activeTextEditor;
if (!editor) return;
- let editorUri = editor.document.uri.toString();
- let suggestions = editorToSuggestions.get(editorUri);
- let idx = currentSuggestion.get(editorUri);
+ const editorUri = editor.document.uri.toString();
+ const suggestions = editorToSuggestions.get(editorUri);
+ const idx = currentSuggestion.get(editorUri);
if (!suggestions || idx === undefined) return;
- let suggestion = suggestions[idx];
+ const suggestion = suggestions[idx];
if (suggestion.newSelected) {
suggestion.newSelected = false;
} else if (idx > 0) {
@@ -130,10 +130,10 @@ function selectSuggestion(
accept: SuggestionSelectionOption,
key: SuggestionRanges | null = null
) {
- let editor = vscode.window.activeTextEditor;
+ const editor = vscode.window.activeTextEditor;
if (!editor) return;
- let editorUri = editor.document.uri.toString();
- let suggestions = editorToSuggestions.get(editorUri);
+ const editorUri = editor.document.uri.toString();
+ const suggestions = editorToSuggestions.get(editorUri);
if (!suggestions) return;
@@ -218,14 +218,14 @@ export async function showSuggestion(
range: vscode.Range,
suggestion: string
): Promise<boolean> {
- let existingCode = await readFileAtRange(
+ 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
- let slines = suggestion.split("\n");
- let elines = existingCode.split("\n");
+ 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]) {
@@ -255,7 +255,7 @@ export async function showSuggestion(
)
);
- let editor = await openEditorAndRevealRange(editorFilename, range);
+ const editor = await openEditorAndRevealRange(editorFilename, range);
if (!editor) return Promise.resolve(false);
return new Promise((resolve, reject) => {
diff --git a/extension/src/util/vscode.ts b/extension/src/util/vscode.ts
index a76b53c7..3110d589 100644
--- a/extension/src/util/vscode.ts
+++ b/extension/src/util/vscode.ts
@@ -118,9 +118,11 @@ export async function readFileAtRange(
)
);
} else {
- let firstLine = lines[range.start.line].slice(range.start.character);
- let lastLine = lines[range.end.line].slice(0, range.end.character);
- let middleLines = lines.slice(range.start.line + 1, range.end.line);
+ const firstLine = lines[range.start.line].slice(
+ range.start.character
+ );
+ const lastLine = lines[range.end.line].slice(0, range.end.character);
+ const middleLines = lines.slice(range.start.line + 1, range.end.line);
resolve([firstLine, ...middleLines, lastLine].join("\n"));
}
}
@@ -144,7 +146,7 @@ export function openEditorAndRevealRange(
setInterval(() => {
resolve(null);
}, 200);
- })
+ });
}
showTextDocumentInProcess = true;
vscode.window
@@ -158,10 +160,10 @@ export function openEditorAndRevealRange(
}
resolve(editor);
showTextDocumentInProcess = false;
- })
- } catch (err) {
- console.log(err);
- }
- });
+ });
+ } catch (err) {
+ console.log(err);
+ }
+ });
});
}