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..8a0deb3 --- /dev/null +++ b/refactor/rewrite.py @@ -0,0 +1,134 @@ +import re +import sys + +from devchat.ide.service import IDEService +from devchat.ide.vscode_services import selected_lines, visible_lines +from devchat.llm import chat + + +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()