From 62c60a1386795c71d6ea7cb2c5a0df63607848ec Mon Sep 17 00:00:00 2001 From: bobo Date: Fri, 9 Feb 2024 11:04:29 +0800 Subject: [PATCH 1/2] feat: Add refactoring commands and utility script - Introduced command configurations for code rewriting, docstring optimization, and variable renaming. - Added a Python utility script for code selection and refactoring operations. - Implemented functionality to interact with IDE services and apply changes. --- refactor/command.yml | 5 ++ refactor/docstring/command.yml | 3 + refactor/names/command.yml | 4 + refactor/rewrite.py | 131 +++++++++++++++++++++++++++++++++ 4 files changed, 143 insertions(+) create mode 100644 refactor/command.yml create mode 100644 refactor/docstring/command.yml create mode 100644 refactor/names/command.yml create mode 100644 refactor/rewrite.py diff --git a/refactor/command.yml b/refactor/command.yml new file mode 100644 index 0000000..bbededf --- /dev/null +++ b/refactor/command.yml @@ -0,0 +1,5 @@ +description: rewrite selected code. +hint: question +input: required +steps: + - run: $devchat_python $command_path/rewrite.py "$input" \ No newline at end of file diff --git a/refactor/docstring/command.yml b/refactor/docstring/command.yml new file mode 100644 index 0000000..61ab988 --- /dev/null +++ b/refactor/docstring/command.yml @@ -0,0 +1,3 @@ +description: Automatically add or refine docstrings to enhance readability and clarity. Select a function or method and execute this command to optimize its documentation. +steps: + - run: $devchat_python $command_path/../rewrite.py "add doc comment" \ No newline at end of file diff --git a/refactor/names/command.yml b/refactor/names/command.yml new file mode 100644 index 0000000..5da4a09 --- /dev/null +++ b/refactor/names/command.yml @@ -0,0 +1,4 @@ +description: Automatically rename poorly-named local variables for improved readability. Select the code segment and execute this command to optimize variable names. +steps: + - run: $devchat_python $command_path/../rewrite.py "Refine internal variable and function names within the code to achieve concise and meaningful identifiers that comply with English naming conventions." + diff --git a/refactor/rewrite.py b/refactor/rewrite.py new file mode 100644 index 0000000..274232d --- /dev/null +++ b/refactor/rewrite.py @@ -0,0 +1,131 @@ +import sys +import re + +from devchat.llm import chat +from devchat.ide.service import IDEService +from devchat.ide.vscode_services import visible_lines, selected_lines + + +def get_selected_code(): + """ + Retrieves the selected lines of code from the user's selection. + + This function extracts the text selected by the user in their IDE or text editor. + If no text has been selected, it prints an error message to stderr and exits the + program with a non-zero status indicating failure. + + Returns: + dict: A dictionary containing the key 'selectedText' with the selected text + as its value. If no text is selected, the program exits. + """ + selected_data = IDEService().get_selected_range().dict() + + miss_selected_error = "Please select some text." + if selected_data["text"] == "": + print(miss_selected_error, file=sys.stderr, flush=True) + sys.exit(-1) + + return selected_data + +def get_visible_code(): + """ + Retrieves visible code from the visible_lines function. + + Returns: + visible_data: The visible code retrieved from the visible_lines function. + """ + visible_data = IDEService().get_visible_range().dict() + return visible_data + + +REWRITE_PROMPT = prompt = """ +Your task is: +{question} +Following the task requirements, modify only the selected portion of the code. \ +Please ensure that the revised code segment maintains the same indentation as the \ +selected code to seamlessly integrate with the existing code structure and maintain \ +correct syntax. Just refactor the selected code. Keep all other information as it is. Here is the relevant context \ +information for your reference: +1. selected code info: {selected_text} +2. current visible code info: {visible_text} +""" +@chat(prompt=REWRITE_PROMPT, stream_out=True) +# pylint: disable=unused-argument +def ai_rewrite(question, selected_text, visible_text): + """ + call ai to rewrite selected code + """ + pass # pylint: disable=unnecessary-pass + +def extract_markdown_block(text): + """ + Extracts the first Markdown code block from the given text without the language specifier. + + :param text: A string containing Markdown text + :return: The content of the first Markdown code block, or None if not found + """ + pattern = r"```(?:\w+)?\s*\n(.*?)\n```" + match = re.search(pattern, text, re.DOTALL) + + if match: + block_content = match.group(1) + return block_content + else: + return text + +def replace_selected(new_code): + selected_data = IDEService().get_selected_code().dict() + select_file = selected_data["abspath"] + select_range = selected_data["range"] # [start_line, start_col, end_line, end_col] + + # Read the file + with open(select_file, "r", encoding="utf-8") as file: + lines = file.readlines() + lines.append("\n") + + # Modify the selected lines + start_line = select_range["start"]["line"] + start_col = select_range["start"]["character"] + end_line = select_range["end"]["line"] + end_col = select_range["end"]["character"] + + # If the selection spans multiple lines, handle the last line and delete the lines in between + if start_line != end_line: + lines[start_line] = lines[start_line][:start_col] + new_code + # Append the text after the selection on the last line + lines[start_line] += lines[end_line][end_col:] + # Delete the lines between start_line and end_line + del lines[start_line + 1 : end_line + 1] + else: + # If the selection is within a single line, remove the selected text + lines[start_line] = lines[start_line][:start_col] + new_code + lines[end_line][end_col:] + + # Combine everything back together + modified_text = "".join(lines) + + # Write the changes back to the file + with open(select_file, "w", encoding="utf-8") as file: + file.write(modified_text) + + +def main(): + question = sys.argv[1] + # prepare code + selected_text = get_selected_code() + visible_text = get_visible_code() + + # rewrite + response = ai_rewrite( + question=question, + selected_text=selected_text, + visible_text=visible_text) + + # apply new code to editor + new_code = extract_markdown_block(response) + IDEService().diff_apply("", new_code) + + sys.exit(0) + + +if __name__ == "__main__": + main() From 91cea1b59cb41118cf02e79f351266ce091b853c Mon Sep 17 00:00:00 2001 From: bobo Date: Fri, 9 Feb 2024 11:09:14 +0800 Subject: [PATCH 2/2] fix lint error --- refactor/rewrite.py | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/refactor/rewrite.py b/refactor/rewrite.py index 274232d..8a0deb3 100644 --- a/refactor/rewrite.py +++ b/refactor/rewrite.py @@ -1,9 +1,9 @@ -import sys import re +import sys -from devchat.llm import chat from devchat.ide.service import IDEService -from devchat.ide.vscode_services import visible_lines, selected_lines +from devchat.ide.vscode_services import selected_lines, visible_lines +from devchat.llm import chat def get_selected_code(): @@ -24,13 +24,14 @@ def get_selected_code(): if selected_data["text"] == "": print(miss_selected_error, file=sys.stderr, flush=True) sys.exit(-1) - + return selected_data + def get_visible_code(): """ Retrieves visible code from the visible_lines function. - + Returns: visible_data: The visible code retrieved from the visible_lines function. """ @@ -44,18 +45,22 @@ def get_visible_code(): Following the task requirements, modify only the selected portion of the code. \ Please ensure that the revised code segment maintains the same indentation as the \ selected code to seamlessly integrate with the existing code structure and maintain \ -correct syntax. Just refactor the selected code. Keep all other information as it is. Here is the relevant context \ +correct syntax. Just refactor the selected code. Keep all other information as it is. \ +Here is the relevant context \ information for your reference: 1. selected code info: {selected_text} 2. current visible code info: {visible_text} """ + + @chat(prompt=REWRITE_PROMPT, stream_out=True) # pylint: disable=unused-argument def ai_rewrite(question, selected_text, visible_text): """ call ai to rewrite selected code """ - pass # pylint: disable=unnecessary-pass + pass # pylint: disable=unnecessary-pass + def extract_markdown_block(text): """ @@ -73,6 +78,7 @@ def extract_markdown_block(text): else: return text + def replace_selected(new_code): selected_data = IDEService().get_selected_code().dict() select_file = selected_data["abspath"] @@ -115,11 +121,8 @@ def main(): visible_text = get_visible_code() # rewrite - response = ai_rewrite( - question=question, - selected_text=selected_text, - visible_text=visible_text) - + response = ai_rewrite(question=question, selected_text=selected_text, visible_text=visible_text) + # apply new code to editor new_code = extract_markdown_block(response) IDEService().diff_apply("", new_code)