Skip to content

Commit

Permalink
Merge pull request #127 from devchat-ai/add_fix_issue_command
Browse files Browse the repository at this point in the history
feat: Add fix_issue command and new IDE service methods
  • Loading branch information
kagami-l authored Jul 2, 2024
2 parents 7b19535 + 8830931 commit d218bf7
Show file tree
Hide file tree
Showing 4 changed files with 198 additions and 0 deletions.
30 changes: 30 additions & 0 deletions lib/ide_service/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -152,3 +152,33 @@ def get_selected_range(self) -> LocationWithText:
if self.ide_name() == "vscode":
return selected_range()
return IdeaIDEService().get_selected_range()

@rpc_method
def get_diagnostics_in_range(self, fileName: str, startLine: int, endLine: int) -> List[str]:
"""
Retrieves diagnostics for a specific range of code in the current IDE.
Returns:
A list of diagnostic messages for the specified range.
"""
return self._result

@rpc_method
def get_collapsed_code(self, fileName: str, startLine: int, endLine: int) -> str:
"""
Retrives collapsed code exclude specfic range of code in the current IDE.
Returns:
The collapsed code.
"""
return self._result

@rpc_method
def get_extension_tools_path(self) -> str:
"""
Retrives extension tools path.
Returns:
The extension tools path.
"""
return self._result
3 changes: 3 additions & 0 deletions merico/fix_issue/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@

### 操作指南

4 changes: 4 additions & 0 deletions merico/fix_issue/command.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
description: Automatically fix lint errors.
help: README.md
steps:
- run: $devchat_python $command_path/main.py
161 changes: 161 additions & 0 deletions merico/fix_issue/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
import os
import re
import sys

from devchat.llm import chat

from lib.ide_service import IDEService


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:
# whether exist ```language?
if text.find("```"):
return None
return text


# step 1 : get selected code
def get_selected_code():
selected_data = IDEService().get_selected_range().dict()

if selected_data["range"]["start"] == -1:
return None, None, None

if selected_data["range"]["start"]["line"] != selected_data["range"]["end"]["line"]:
print("Please select the line code of issue reported.\n\n", file=sys.stderr)
sys.exit(1)

return selected_data["abspath"], selected_data["text"], selected_data["range"]["start"]["line"]


# step 2 : input issue descriptions
def input_issue_descriptions(file_path, issue_line_num):
diagnostics = IDEService().get_diagnostics_in_range(file_path, issue_line_num, issue_line_num)
if not diagnostics:
return None

# select first sonarlint diagnostic
for diagnostic in diagnostics:
if diagnostic.find("<sonar") > 0:
return diagnostic
return diagnostics[0]


# step 3 : call llm to generate fix solutions
PROMPT = """
You are a code refactoring assistant.
This is my code file:
{file_content}
There is a issue in the following code:
{issue_line_code}
{issue_description}
Here is the rule description:
{rule_description}
Please provide me refactor code to fix this issue.
"""


@chat(prompt=PROMPT, stream_out=True)
def call_llm_to_generate_fix_solutions(
file_content, issue_line_code, issue_description, rule_description
):
pass


# current file content
def get_current_file_content(file_path, issue_line_num):
try:
return IDEService().get_collapsed_code(file_path, issue_line_num, issue_line_num)
except Exception:
print("Error reading file:", file=sys.stderr)
return None


# get issue description
def get_rule_description(issue_description):
def parse_source_code(text):
pattern = r"<(\w+):(.+?)>"
match = re.search(pattern, text)

if match:
source = match.group(1)
code = match.group(2)
return source, code
else:
return None, None

issue_source, issue_code = parse_source_code(issue_description)
if issue_source.find("sonar") == -1:
return issue_description

issue_id = issue_code.split(":")[-1]
issue_language = issue_code.split(":")[0]

tools_path = IDEService().get_extension_tools_path()
rules_path = "sonar-rspec"

rule_path = os.path.join(tools_path, rules_path, "rules", issue_id, issue_language, "rule.adoc")
if os.path.exists(rule_path):
with open(rule_path, "r", encoding="utf-8") as file:
return file.read()
return issue_description


# step 4 : apply fix solutions to code
def apply_fix_solutions_to_code():
pass


# step 0: try parse user input
def try_parse_user_input():
pass


def main():
print("start fix issue ...\n\n")
file_path, issue_line, issue_line_num = get_selected_code()
if not file_path or not issue_line:
print("No code selected. Please select the code line you want to fix.", file=sys.stderr)
sys.exit(1)
issue_description = input_issue_descriptions(file_path, issue_line_num)
if not issue_description:
print(
"There are no issues to resolve on the current line. "
"Please select the line where an issue needs to be resolved."
)
sys.exit(0)

print("make llm prompt ...\n\n")
current_file_content = get_current_file_content(file_path, issue_line_num)
rule_description = get_rule_description(issue_description)
print("--->>:", rule_description)

print("call llm to fix issue ...\n\n")
fix_solutions = call_llm_to_generate_fix_solutions(
file_content=current_file_content,
issue_line_code=issue_line,
issue_description=issue_description,
rule_description=rule_description,
)
if not fix_solutions:
sys.exit(1)


if __name__ == "__main__":
main()

0 comments on commit d218bf7

Please sign in to comment.