Merge pull request #128 from devchat-ai/auto_apply_fix_issue
feat: Enhance issue fixing and add aider integration
This commit is contained in:
commit
a4005b6326
1
.gitignore
vendored
1
.gitignore
vendored
@ -9,3 +9,4 @@ custom/*
|
||||
!custom/config.yml.example
|
||||
|
||||
user_settings.yml
|
||||
.aider*
|
||||
|
@ -117,7 +117,7 @@ class IDEService:
|
||||
return self._result
|
||||
|
||||
@rpc_method
|
||||
def diff_apply(self, filepath, content) -> bool:
|
||||
def diff_apply(self, filepath, content, autoedit: bool = False) -> bool:
|
||||
"""
|
||||
Applies a given diff to a file.
|
||||
|
||||
@ -182,3 +182,25 @@ class IDEService:
|
||||
The extension tools path.
|
||||
"""
|
||||
return self._result
|
||||
|
||||
@rpc_method
|
||||
def select_range(
|
||||
self, fileName: str, startLine: int, startColumn: int, endLine: int, endColumn: int
|
||||
) -> bool:
|
||||
"""
|
||||
Selects a range of text in the specified file.
|
||||
|
||||
Args:
|
||||
fileName: The name of the file.
|
||||
startLine: The starting line of the selection (0-based).
|
||||
startColumn: The starting column of the selection (0-based).
|
||||
endLine: The ending line of the selection (0-based).
|
||||
endColumn: The ending column of the selection (0-based).
|
||||
|
||||
Returns:
|
||||
A boolean indicating whether the selection was successful.
|
||||
|
||||
Note:
|
||||
If startLine is -1, it cancels the current selection.
|
||||
"""
|
||||
return self._result
|
||||
|
@ -10,12 +10,7 @@ def run_code(code: str):
|
||||
|
||||
|
||||
@rpc_call
|
||||
def diff_apply(filepath, content):
|
||||
pass
|
||||
|
||||
|
||||
@rpc_call
|
||||
def get_symbol_defines_in_selected_code():
|
||||
def diff_apply(filepath, content, autoedit=False):
|
||||
pass
|
||||
|
||||
|
||||
|
19
merico/aider/README.md
Normal file
19
merico/aider/README.md
Normal file
@ -0,0 +1,19 @@
|
||||
### 操作指南
|
||||
|
||||
aider工作流命令使用步骤如下:
|
||||
|
||||
1. 确保已经使用 `/aider.files.add` 命令添加了需要处理的文件。
|
||||
2. 输入 `/aider <message>` 命令,其中 `<message>` 是你想要aider执行的任务描述。
|
||||
3. 等待aider生成建议的更改。
|
||||
4. 系统会自动显示每个文件的Diff View,你可以选择是否接受修改。
|
||||
5. 对于多个文件的更改,系统会在每个文件之后询问是否继续查看下一个文件的更改。
|
||||
|
||||
注意事项:
|
||||
- 如果没有添加任何文件到aider,命令将会提示你先使用 'aider.files.add' 命令添加文件。
|
||||
- 你可以使用 `aider.files.remove` 命令从aider中移除文件。
|
||||
- 所有的更改都会在IDE中以Diff View的形式展示,你可以在查看后决定是否应用这些更改。
|
||||
|
||||
使用示例:
|
||||
/aider 重构这段代码以提高性能
|
||||
|
||||
这个命令会让aider分析当前添加的文件,并提供重构建议以提高代码性能。
|
214
merico/aider/command.py
Normal file
214
merico/aider/command.py
Normal file
@ -0,0 +1,214 @@
|
||||
import json
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
from devchat.ide import IDEService
|
||||
|
||||
from lib.chatmark import Button
|
||||
|
||||
GLOBAL_CONFIG_PATH = os.path.join(os.path.expanduser("~"), ".chat", ".workflow_config.json")
|
||||
|
||||
|
||||
def save_config(config_path, item, value):
|
||||
if os.path.exists(config_path):
|
||||
with open(config_path, "r", encoding="utf-8") as f:
|
||||
config = json.load(f)
|
||||
else:
|
||||
config = {}
|
||||
|
||||
config[item] = value
|
||||
with open(config_path, "w", encoding="utf-8") as f:
|
||||
json.dump(config, f, indent=4)
|
||||
|
||||
|
||||
def write_python_path_to_config():
|
||||
"""
|
||||
Write the current system Python path to the configuration.
|
||||
"""
|
||||
python_path = sys.executable
|
||||
save_config(GLOBAL_CONFIG_PATH, "aider_python", python_path)
|
||||
print(f"Python path '{python_path}' has been written to the configuration.")
|
||||
|
||||
|
||||
def get_aider_files():
|
||||
"""
|
||||
从.chat/.aider_files文件中读取aider文件列表
|
||||
"""
|
||||
aider_files_path = os.path.join(".chat", ".aider_files")
|
||||
if not os.path.exists(aider_files_path):
|
||||
return []
|
||||
|
||||
with open(aider_files_path, "r") as f:
|
||||
return [line.strip() for line in f if line.strip()]
|
||||
|
||||
|
||||
def run_aider(message, files):
|
||||
"""
|
||||
运行aider命令
|
||||
"""
|
||||
python = sys.executable
|
||||
model = os.environ.get("LLM_MODEL", "gpt-3.5-turbo-1106")
|
||||
|
||||
cmd = [
|
||||
python,
|
||||
"-m",
|
||||
"aider",
|
||||
"--model",
|
||||
f"openai/{model}",
|
||||
"--yes",
|
||||
"--no-auto-commits",
|
||||
"--dry-run",
|
||||
"--no-pretty",
|
||||
"--message",
|
||||
message,
|
||||
] + files
|
||||
|
||||
process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
|
||||
|
||||
has_started = False
|
||||
aider_output = ""
|
||||
for line in process.stdout:
|
||||
if "run with --help" in line or 'run "aider --help"' in line:
|
||||
has_started = True
|
||||
continue
|
||||
if has_started:
|
||||
aider_output += line
|
||||
print(line, end="", flush=True)
|
||||
|
||||
return_code = process.wait()
|
||||
|
||||
if return_code != 0:
|
||||
for line in process.stderr:
|
||||
print(f"Error: {line.strip()}", file=sys.stderr)
|
||||
sys.exit(return_code)
|
||||
|
||||
return aider_output
|
||||
|
||||
|
||||
def apply_changes(changes, files):
|
||||
"""
|
||||
应用aider生成的更改
|
||||
"""
|
||||
changes_file = ".chat/changes.txt"
|
||||
os.makedirs(os.path.dirname(changes_file), exist_ok=True)
|
||||
with open(changes_file, "w") as f:
|
||||
f.write(changes)
|
||||
|
||||
python = sys.executable
|
||||
model = os.environ.get("LLM_MODEL", "gpt-3.5-turbo-1106")
|
||||
|
||||
cmd = [
|
||||
python,
|
||||
"-m",
|
||||
"aider",
|
||||
"--model",
|
||||
f"openai/{model}",
|
||||
"--yes",
|
||||
"--no-auto-commits",
|
||||
"--apply",
|
||||
changes_file,
|
||||
] + files
|
||||
|
||||
process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
|
||||
|
||||
has_started = False
|
||||
for line in process.stdout:
|
||||
if "Model:" in line:
|
||||
has_started = True
|
||||
continue
|
||||
if has_started:
|
||||
print(line, end="", flush=True)
|
||||
|
||||
return_code = process.wait()
|
||||
|
||||
if return_code != 0:
|
||||
for line in process.stderr:
|
||||
print(f"Error: {line.strip()}", file=sys.stderr)
|
||||
sys.exit(return_code)
|
||||
|
||||
os.remove(changes_file)
|
||||
|
||||
|
||||
def main():
|
||||
"""
|
||||
Main function to run the aider command.
|
||||
|
||||
This function performs the following tasks:
|
||||
1. Checks for correct command-line usage
|
||||
2. Writes the current Python path to the configuration
|
||||
3. Retrieves the list of files to be processed
|
||||
4. Runs the aider command with the given message
|
||||
5. Applies the suggested changes
|
||||
6. Displays the differences in the IDE
|
||||
|
||||
Usage: python command.py <message>
|
||||
"""
|
||||
if len(sys.argv) < 2:
|
||||
print("Usage: python command.py <message>", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
write_python_path_to_config()
|
||||
|
||||
message = sys.argv[1]
|
||||
files = get_aider_files()
|
||||
|
||||
if not files:
|
||||
print(
|
||||
"No files added to aider. Please add files using 'aider.files.add' command.",
|
||||
file=sys.stderr,
|
||||
)
|
||||
sys.exit(1)
|
||||
|
||||
print("Running aider...\n", flush=True)
|
||||
changes = run_aider(message, files)
|
||||
|
||||
if not changes:
|
||||
print("No changes suggested by aider.")
|
||||
sys.exit(0)
|
||||
|
||||
print("\nApplying changes...\n", flush=True)
|
||||
|
||||
# 保存原始文件内容
|
||||
original_contents = {}
|
||||
for file in files:
|
||||
with open(file, "r") as f:
|
||||
original_contents[file] = f.read()
|
||||
|
||||
# 应用更改
|
||||
apply_changes(changes, files)
|
||||
|
||||
# 读取更新后的文件内容
|
||||
updated_contents = {}
|
||||
for file in files:
|
||||
with open(file, "r") as f:
|
||||
updated_contents[file] = f.read()
|
||||
|
||||
# 还原原始文件内容
|
||||
for file in files:
|
||||
with open(file, "w") as f:
|
||||
f.write(original_contents[file])
|
||||
|
||||
# 使用 IDEService 展示差异
|
||||
ide_service = IDEService()
|
||||
for index, file in enumerate(files):
|
||||
ide_service.diff_apply(file, updated_contents[file])
|
||||
if index < len(files) - 1:
|
||||
# 等待用户确认
|
||||
button = Button(
|
||||
["Show Next Changes", "Cancel"],
|
||||
)
|
||||
button.render()
|
||||
|
||||
idx = button.clicked
|
||||
print("click button:", idx)
|
||||
if idx == 0:
|
||||
continue
|
||||
else:
|
||||
break
|
||||
|
||||
print("Changes have been displayed in the IDE.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
9
merico/aider/command.yml
Normal file
9
merico/aider/command.yml
Normal file
@ -0,0 +1,9 @@
|
||||
description: "aider command"
|
||||
workflow_python:
|
||||
env_name: devchat-aider-env
|
||||
version: 3.11.0
|
||||
dependencies: requirements.txt
|
||||
input: required
|
||||
help: README.md
|
||||
steps:
|
||||
- run: $workflow_python $command_path/command.py "$input"
|
20
merico/aider/files/add/README.md
Normal file
20
merico/aider/files/add/README.md
Normal file
@ -0,0 +1,20 @@
|
||||
### aider.files.add
|
||||
|
||||
添加文件到aider处理列表中。
|
||||
|
||||
用法:
|
||||
/aider.files.add <file_path>
|
||||
|
||||
参数:
|
||||
- <file_path>: 要添加的文件路径(必需)
|
||||
|
||||
描述:
|
||||
这个命令将指定的文件添加到aider的处理列表中。添加后,该文件将被包含在后续的aider操作中。
|
||||
|
||||
注意:
|
||||
- 文件路径必须是有效的格式。
|
||||
- 如果文件已经在列表中,它不会被重复添加。
|
||||
- 添加成功后,会显示当前aider文件列表。
|
||||
|
||||
示例:
|
||||
/aider.files.add src/main.py
|
66
merico/aider/files/add/command.py
Normal file
66
merico/aider/files/add/command.py
Normal file
@ -0,0 +1,66 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
|
||||
def is_valid_path(path):
|
||||
"""
|
||||
检查路径是否为有效的文件路径形式
|
||||
"""
|
||||
try:
|
||||
# 尝试规范化路径
|
||||
normalized_path = os.path.normpath(path)
|
||||
# 检查路径是否是绝对路径或相对路径
|
||||
return (
|
||||
os.path.isabs(normalized_path)
|
||||
or not os.path.dirname(normalized_path) == normalized_path
|
||||
)
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
|
||||
def add_file(file_path):
|
||||
# 1. 检查是否为有效的文件路径形式
|
||||
if not is_valid_path(file_path):
|
||||
print(f"Error: '{file_path}' is not a valid file path format.", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
# 获取绝对路径
|
||||
abs_file_path = file_path.strip()
|
||||
|
||||
# 2. 将新增文件路径存储到.chat/.aider_files文件中
|
||||
aider_files_path = os.path.join(".chat", ".aider_files")
|
||||
|
||||
# 确保.chat目录存在
|
||||
os.makedirs(os.path.dirname(aider_files_path), exist_ok=True)
|
||||
|
||||
# 读取现有文件列表
|
||||
existing_files = set()
|
||||
if os.path.exists(aider_files_path):
|
||||
with open(aider_files_path, "r") as f:
|
||||
existing_files = set(line.strip() for line in f)
|
||||
|
||||
# 添加新文件
|
||||
existing_files.add(abs_file_path)
|
||||
|
||||
# 写入更新后的文件列表
|
||||
with open(aider_files_path, "w") as f:
|
||||
for file in sorted(existing_files):
|
||||
f.write(f"{file}\n")
|
||||
|
||||
print(f"Added '{abs_file_path}' to aider files.")
|
||||
print("\nCurrent aider files:")
|
||||
for file in sorted(existing_files):
|
||||
print(f"- {file}")
|
||||
|
||||
|
||||
def main():
|
||||
if len(sys.argv) != 2 or sys.argv[1].strip() == "":
|
||||
print("Usage: /aider.files.add <file_path>", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
file_path = sys.argv[1]
|
||||
add_file(file_path)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
5
merico/aider/files/add/command.yml
Normal file
5
merico/aider/files/add/command.yml
Normal file
@ -0,0 +1,5 @@
|
||||
description: "add files to aider"
|
||||
input: required
|
||||
help: README.md
|
||||
steps:
|
||||
- run: $devchat_python $command_path/command.py "$input"
|
16
merico/aider/files/list/README.md
Normal file
16
merico/aider/files/list/README.md
Normal file
@ -0,0 +1,16 @@
|
||||
### aider.files.list
|
||||
|
||||
列出当前在aider处理列表中的所有文件。
|
||||
|
||||
用法:
|
||||
/aider.files.list
|
||||
|
||||
描述:
|
||||
这个命令会显示所有已添加到aider处理列表中的文件。它提供了一个当前aider正在处理的文件的概览。
|
||||
|
||||
注意:
|
||||
- 如果没有文件被添加到aider,会显示相应的消息。
|
||||
- 文件按字母顺序排序显示。
|
||||
|
||||
示例:
|
||||
/aider.files.list
|
31
merico/aider/files/list/command.py
Normal file
31
merico/aider/files/list/command.py
Normal file
@ -0,0 +1,31 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
|
||||
def list_files():
|
||||
aider_files_path = os.path.join(".chat", ".aider_files")
|
||||
|
||||
# 确保.chat/.aider_files文件存在
|
||||
if not os.path.exists(aider_files_path):
|
||||
print("No files have been added to aider yet.")
|
||||
sys.exit(0)
|
||||
|
||||
# 读取文件列表
|
||||
with open(aider_files_path, "r") as f:
|
||||
files = [line.strip() for line in f]
|
||||
|
||||
# 打印文件列表
|
||||
if files:
|
||||
print("Aider files:")
|
||||
for file in sorted(files):
|
||||
print(f"- {file}")
|
||||
else:
|
||||
print("No files found in aider.")
|
||||
|
||||
|
||||
def main():
|
||||
list_files()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
4
merico/aider/files/list/command.yml
Normal file
4
merico/aider/files/list/command.yml
Normal file
@ -0,0 +1,4 @@
|
||||
description: "list files in aider"
|
||||
help: README.md
|
||||
steps:
|
||||
- run: $devchat_python $command_path/command.py
|
20
merico/aider/files/remove/README.md
Normal file
20
merico/aider/files/remove/README.md
Normal file
@ -0,0 +1,20 @@
|
||||
### aider.files.remove
|
||||
|
||||
从aider处理列表中移除指定的文件。
|
||||
|
||||
用法:
|
||||
/aider.files.remove <file_path>
|
||||
|
||||
参数:
|
||||
- <file_path>: 要移除的文件路径(必需)
|
||||
|
||||
描述:
|
||||
这个命令从aider的处理列表中移除指定的文件。移除后,该文件将不再被包含在后续的aider操作中。
|
||||
|
||||
注意:
|
||||
- 文件路径必须是有效的格式。
|
||||
- 如果指定的文件不在列表中,会显示相应的消息。
|
||||
- 移除成功后,会显示更新后的aider文件列表。
|
||||
|
||||
示例:
|
||||
/aider.files.remove src/main.py
|
72
merico/aider/files/remove/command.py
Normal file
72
merico/aider/files/remove/command.py
Normal file
@ -0,0 +1,72 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
|
||||
def is_valid_path(path):
|
||||
"""
|
||||
检查路径是否为有效的文件路径形式
|
||||
"""
|
||||
try:
|
||||
# 尝试规范化路径
|
||||
normalized_path = os.path.normpath(path)
|
||||
# 检查路径是否是绝对路径或相对路径
|
||||
return (
|
||||
os.path.isabs(normalized_path)
|
||||
or not os.path.dirname(normalized_path) == normalized_path
|
||||
)
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
|
||||
def remove_file(file_path):
|
||||
# 1. 检查是否为有效的文件路径形式
|
||||
if not is_valid_path(file_path):
|
||||
print(f"Error: '{file_path}' is not a valid file path format.", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
# 获取绝对路径
|
||||
abs_file_path = file_path.strip()
|
||||
|
||||
# 2. 从.chat/.aider_files文件中移除指定文件路径
|
||||
aider_files_path = os.path.join(".chat", ".aider_files")
|
||||
|
||||
# 确保.chat目录存在
|
||||
if not os.path.exists(aider_files_path):
|
||||
print(f"Error: '{aider_files_path}' does not exist.", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
# 读取现有文件列表
|
||||
existing_files = set()
|
||||
with open(aider_files_path, "r") as f:
|
||||
existing_files = set(line.strip() for line in f)
|
||||
|
||||
# 检查文件是否在列表中
|
||||
if abs_file_path not in existing_files:
|
||||
print(f"'{abs_file_path}' is not in aider files.")
|
||||
sys.exit(0)
|
||||
|
||||
# 移除文件
|
||||
existing_files.remove(abs_file_path)
|
||||
|
||||
# 写入更新后的文件列表
|
||||
with open(aider_files_path, "w") as f:
|
||||
for file in sorted(existing_files):
|
||||
f.write(f"{file}\n")
|
||||
|
||||
print(f"Removed '{abs_file_path}' from aider files.")
|
||||
print("\nCurrent aider files:")
|
||||
for file in sorted(existing_files):
|
||||
print(f"- {file}")
|
||||
|
||||
|
||||
def main():
|
||||
if len(sys.argv) != 2 or sys.argv[1].strip() == "":
|
||||
print("Usage: /aider.files.remove <file_path>", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
file_path = sys.argv[1]
|
||||
remove_file(file_path)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
5
merico/aider/files/remove/command.yml
Normal file
5
merico/aider/files/remove/command.yml
Normal file
@ -0,0 +1,5 @@
|
||||
description: "remove files from aider"
|
||||
input: required
|
||||
help: README.md
|
||||
steps:
|
||||
- run: $devchat_python $command_path/command.py "$input"
|
2
merico/aider/requirements.txt
Normal file
2
merico/aider/requirements.txt
Normal file
@ -0,0 +1,2 @@
|
||||
git+https://gitee.com/imlaji/aider.git@main
|
||||
git+https://gitee.com/devchat-ai/devchat.git@aider
|
21
merico/ask_issue/README.md
Normal file
21
merico/ask_issue/README.md
Normal file
@ -0,0 +1,21 @@
|
||||
### ask_issue
|
||||
|
||||
自动修复代码中的lint错误。
|
||||
|
||||
用法:
|
||||
/ask_issue
|
||||
|
||||
描述:
|
||||
这个命令帮助开发者自动修复代码中的lint错误。它使用AI分析选中的代码行,识别lint问题,并提供修复建议。
|
||||
|
||||
步骤:
|
||||
1. 在IDE中选择包含lint错误的代码行。
|
||||
2. 运行 /ask_issue 命令。
|
||||
3. 命令会自动获取选中的代码、相关的lint诊断信息,并调用AI生成修复方案。
|
||||
4. AI会提供问题解释和修复后的代码片段。
|
||||
|
||||
注意事项:
|
||||
- 确保在运行命令前已选择包含lint错误的代码行。
|
||||
- 命令会优先处理SonarLint诊断的问题。
|
||||
- AI生成的修复方案会包含问题解释和修改后的代码。
|
||||
- 修改后的代码会以Markdown格式展示,包含足够的上下文信息。
|
4
merico/ask_issue/command.yml
Normal file
4
merico/ask_issue/command.yml
Normal file
@ -0,0 +1,4 @@
|
||||
description: Automatically fix lint errors.
|
||||
help: README.md
|
||||
steps:
|
||||
- run: $devchat_python $command_path/main.py
|
286
merico/ask_issue/main.py
Normal file
286
merico/ask_issue/main.py
Normal file
@ -0,0 +1,286 @@
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
|
||||
from devchat.llm import chat
|
||||
from devchat.memory import FixSizeChatMemory
|
||||
|
||||
from lib.ide_service import IDEService
|
||||
|
||||
|
||||
def extract_edits_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
|
||||
"""
|
||||
index = text.find("```edits")
|
||||
if index == -1:
|
||||
return None
|
||||
else:
|
||||
start = index + len("```edits")
|
||||
end = text.find("```", start)
|
||||
if end == -1:
|
||||
return None
|
||||
else:
|
||||
return text[start:end]
|
||||
|
||||
|
||||
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
|
||||
"""
|
||||
edit_code = extract_edits_block(text)
|
||||
if edit_code:
|
||||
return edit_code
|
||||
|
||||
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
|
||||
SYSTEM_ROLE_DIFF = """
|
||||
You are a code refactoring assistant.
|
||||
Your task is to refactor the user's code to fix lint diagnostics.
|
||||
You will be provided with a code snippet and a list of diagnostics. \
|
||||
Your response should include two parts:
|
||||
|
||||
1. An explanation of the reason for the diagnostics and how to fix them.
|
||||
2. The edited code snippet with the diagnostics fixed, using markdown format for clarity.
|
||||
|
||||
The markdown block for edits should look like this:
|
||||
|
||||
```edits
|
||||
def hello():
|
||||
print("Call hello():")
|
||||
+ print("hello")
|
||||
|
||||
...
|
||||
|
||||
- hello(20)
|
||||
+ hello()
|
||||
```
|
||||
Or like this, if a variable is not defined:
|
||||
|
||||
```edits
|
||||
...
|
||||
+ cur_file = __file__
|
||||
print(cur_file)
|
||||
```
|
||||
Please note the following important points:
|
||||
|
||||
1. The new code should maintain the correct indentation. \
|
||||
The "+ " sign is followed by two spaces for indentation, \
|
||||
which should be included in the edited code.
|
||||
2. In addition to outputting key editing information, \
|
||||
sufficient context (i.e., key information before and after editing) \
|
||||
should also be provided to help locate the specific position of the edited line.
|
||||
3. Don't output all file lines, if some lines are unchanged, \
|
||||
please use "..." to indicate the ignored lines.
|
||||
4. Use "+ " and "- " at start of the line to indicate the addition and deletion of lines.
|
||||
|
||||
Here are some examples of incorrect responses:
|
||||
|
||||
Incorrect example 1, where the indentation is not correct:
|
||||
|
||||
```edits
|
||||
def hello():
|
||||
print("Call hello():")
|
||||
+ print("hello")
|
||||
```
|
||||
In this case, if the "+ " sign and the extra space are removed, \
|
||||
the print("hello") statement will lack the necessary two spaces for correct indentation.
|
||||
|
||||
Incorrect example 2, where no other code lines are provided:
|
||||
|
||||
```edits
|
||||
+ print("hello")
|
||||
```
|
||||
This is an incorrect example because without additional context, \
|
||||
it's unclear where the new print("hello") statement should be inserted.
|
||||
"""
|
||||
|
||||
SYSTEM_ROLE_CODEBLOCK = """
|
||||
你是一个重构工程师,你需要根据错误描述,对代码进行问题修正,只需要关注描述的问题,不需要关注代码中的其他问题。
|
||||
|
||||
输出的修正代码中,如果修改了多个代码段,中间没有修改的代码段,请使用...表示。
|
||||
每一个被修改的代码段,应该包含前后至少3行未修改的代码,作为修改代码段的边界表示。
|
||||
|
||||
输出一个代码块中,例如:
|
||||
```edits
|
||||
def hello():
|
||||
msg = "hello"
|
||||
print(msg)
|
||||
|
||||
...
|
||||
|
||||
if __name__ == "__main__":
|
||||
hello()
|
||||
```
|
||||
"""
|
||||
|
||||
|
||||
LLM_MODEL = os.environ.get("LLM_MODEL", "gpt-3.5-turbo-1106")
|
||||
if LLM_MODEL in [
|
||||
"qwen2-72b-instruct",
|
||||
"qwen-long",
|
||||
"qwen-turbo",
|
||||
"Yi-34B-Chat",
|
||||
"deepseek-coder",
|
||||
"xinghuo-3.5",
|
||||
]:
|
||||
SYSTEM_ROLE = SYSTEM_ROLE_CODEBLOCK
|
||||
else:
|
||||
SYSTEM_ROLE = SYSTEM_ROLE_DIFF
|
||||
MESSAGES_A = [
|
||||
{
|
||||
"role": "system",
|
||||
"content": SYSTEM_ROLE,
|
||||
},
|
||||
]
|
||||
|
||||
# step 3 : call llm to generate fix solutions
|
||||
PROMPT = """
|
||||
|
||||
Here is the code file:
|
||||
|
||||
{file_content}
|
||||
|
||||
There is an issue in the following code:
|
||||
|
||||
{issue_line_code}
|
||||
|
||||
{issue_description}
|
||||
|
||||
Here is the rule description:
|
||||
|
||||
{rule_description}
|
||||
|
||||
Please focus only on the error described in the prompt. \
|
||||
Other errors in the code should be disregarded.
|
||||
|
||||
"""
|
||||
|
||||
memory = FixSizeChatMemory(max_size=20, messages=MESSAGES_A)
|
||||
|
||||
|
||||
@chat(prompt=PROMPT, stream_out=True, memory=memory)
|
||||
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
|
||||
|
||||
|
||||
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:\n\n", rule_description, end="\n\n")
|
||||
|
||||
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)
|
||||
|
||||
print("\n\n", flush=True)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
@ -1,3 +1,23 @@
|
||||
### fix_issue
|
||||
|
||||
### 操作指南
|
||||
自动修复代码中的lint错误。
|
||||
|
||||
用法:
|
||||
/fix_issue
|
||||
|
||||
描述:
|
||||
这个命令帮助开发者自动修复代码中的lint错误。它使用AI分析选中的代码行,识别lint问题,并提供修复建议。然后,它会自动应用这些修复建议,并在IDE中显示更改。
|
||||
|
||||
步骤:
|
||||
1. 在IDE中选择包含lint错误的代码行。
|
||||
2. 运行 /fix_issue 命令。
|
||||
3. 命令会自动获取选中的代码、相关的lint诊断信息,并调用AI生成修复方案。
|
||||
4. AI会提供问题解释和修复后的代码。
|
||||
5. 命令会自动应用这些修复,并在IDE中显示更改。
|
||||
|
||||
注意事项:
|
||||
- 确保在运行命令前已选择包含lint错误的代码行。
|
||||
- 命令会优先处理SonarLint诊断的问题。
|
||||
- 如果安装了aider Python,命令会使用aider来执行AI访问和应用更改。
|
||||
- 如果没有安装aider Python,命令会使用默认实现来生成和应用修复。
|
||||
- 所有的更改都会在IDE中以Diff View的形式展示,你可以在查看后决定是否接受这些更改。
|
||||
|
@ -1,12 +1,34 @@
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
from devchat.llm import chat
|
||||
from devchat.memory import FixSizeChatMemory
|
||||
|
||||
from lib.ide_service import IDEService
|
||||
|
||||
|
||||
def extract_edits_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
|
||||
"""
|
||||
index = text.find("```edits")
|
||||
if index == -1:
|
||||
return None
|
||||
else:
|
||||
start = index + len("```edits")
|
||||
end = text.find("```", start)
|
||||
if end == -1:
|
||||
return None
|
||||
else:
|
||||
return text[start:end]
|
||||
|
||||
|
||||
def extract_markdown_block(text):
|
||||
"""
|
||||
Extracts the first Markdown code block from the given text without the language specifier.
|
||||
@ -14,6 +36,10 @@ def extract_markdown_block(text):
|
||||
:param text: A string containing Markdown text
|
||||
:return: The content of the first Markdown code block, or None if not found
|
||||
"""
|
||||
edit_code = extract_edits_block(text)
|
||||
if edit_code:
|
||||
return edit_code
|
||||
|
||||
pattern = r"```(?:\w+)?\s*\n(.*?)\n```"
|
||||
match = re.search(pattern, text, re.DOTALL)
|
||||
|
||||
@ -55,29 +81,164 @@ def input_issue_descriptions(file_path, issue_line_num):
|
||||
|
||||
|
||||
# step 3 : call llm to generate fix solutions
|
||||
PROMPT = """
|
||||
You are a code refactoring assistant.
|
||||
This is my code file:
|
||||
{file_content}
|
||||
SYSTEM_ROLE_DIFF = """
|
||||
You are a code refactoring assistant. \
|
||||
Your task is to refactor the user's code to fix lint diagnostics. \
|
||||
You will be provided with a code snippet and a list of diagnostics. \
|
||||
Your response should include two parts:
|
||||
|
||||
There is a issue in the following code:
|
||||
{issue_line_code}
|
||||
{issue_description}
|
||||
1. An explanation of the reason for the diagnostics and how to fix them.
|
||||
2. The edited code snippet with the diagnostics fixed, using markdown format for clarity.
|
||||
|
||||
Here is the rule description:
|
||||
{rule_description}
|
||||
The markdown block for edits should look like this:
|
||||
|
||||
Please provide me refactor code to fix this issue.
|
||||
```edits
|
||||
def hello():
|
||||
print("Call hello():")
|
||||
+ print("hello")
|
||||
|
||||
...
|
||||
|
||||
- hello(20)
|
||||
+ hello()
|
||||
```
|
||||
Or like this, if a variable is not defined:
|
||||
|
||||
```edits
|
||||
...
|
||||
+ cur_file = __file__
|
||||
print(cur_file)
|
||||
```
|
||||
Please note the following important points:
|
||||
|
||||
1. The new code should maintain the correct indentation. \
|
||||
The "+ " sign is followed by two spaces for indentation, \
|
||||
which should be included in the edited code.
|
||||
2. In addition to outputting key editing information, \
|
||||
sufficient context (i.e., key information before and after editing) \
|
||||
should also be provided to help locate the specific position of the edited line.
|
||||
3. Don't output all file lines, if some lines are unchanged, \
|
||||
please use "..." to indicate the ignored lines.
|
||||
4. Use "+ " and "- " at start of the line to indicate the addition and deletion of lines.
|
||||
|
||||
Here are some examples of incorrect responses:
|
||||
|
||||
Incorrect example 1, where the indentation is not correct:
|
||||
|
||||
```edits
|
||||
def hello():
|
||||
print("Call hello():")
|
||||
+ print("hello")
|
||||
```
|
||||
In this case, if the "+ " sign and the extra space are removed, \
|
||||
the print("hello") statement will lack the necessary two spaces for correct indentation.
|
||||
|
||||
Incorrect example 2, where no other code lines are provided:
|
||||
|
||||
```edits
|
||||
+ print("hello")
|
||||
```
|
||||
This is an incorrect example because without additional context, \
|
||||
it's unclear where the new print("hello") statement should be inserted.
|
||||
"""
|
||||
|
||||
SYSTEM_ROLE_CODEBLOCK = """
|
||||
你是一个重构工程师,你需要根据错误描述,对代码进行问题修正,只需要关注描述的问题,不需要关注代码中的其他问题。
|
||||
|
||||
输出的修正代码中,如果修改了多个代码段,中间没有修改的代码段,请使用...表示。
|
||||
每一个被修改的代码段,应该包含前后至少3行未修改的代码,作为修改代码段的边界表示。
|
||||
|
||||
输出一个代码块中,例如:
|
||||
```edits
|
||||
def hello():
|
||||
msg = "hello"
|
||||
print(msg)
|
||||
|
||||
...
|
||||
|
||||
if __name__ == "__main__":
|
||||
hello()
|
||||
```
|
||||
"""
|
||||
|
||||
|
||||
@chat(prompt=PROMPT, stream_out=True)
|
||||
LLM_MODEL = os.environ.get("LLM_MODEL", "gpt-3.5-turbo-1106")
|
||||
if LLM_MODEL in [
|
||||
"qwen2-72b-instruct",
|
||||
"qwen-long",
|
||||
"qwen-turbo",
|
||||
"Yi-34B-Chat",
|
||||
"deepseek-coder",
|
||||
"xinghuo-3.5",
|
||||
]:
|
||||
SYSTEM_ROLE = SYSTEM_ROLE_CODEBLOCK
|
||||
else:
|
||||
SYSTEM_ROLE = SYSTEM_ROLE_DIFF
|
||||
MESSAGES_A = [
|
||||
{
|
||||
"role": "system",
|
||||
"content": SYSTEM_ROLE,
|
||||
},
|
||||
]
|
||||
|
||||
# step 3 : call llm to generate fix solutions
|
||||
PROMPT = """
|
||||
|
||||
Here is the code file:
|
||||
|
||||
{file_content}
|
||||
|
||||
There is an issue in the following code:
|
||||
|
||||
{issue_line_code}
|
||||
|
||||
{issue_description}
|
||||
|
||||
Here is the rule description:
|
||||
|
||||
{rule_description}
|
||||
|
||||
Please focus only on the error described in the prompt. \
|
||||
Other errors in the code should be disregarded.
|
||||
|
||||
"""
|
||||
|
||||
memory = FixSizeChatMemory(max_size=20, messages=MESSAGES_A)
|
||||
|
||||
|
||||
@chat(prompt=PROMPT, stream_out=True, memory=memory)
|
||||
def call_llm_to_generate_fix_solutions(
|
||||
file_content, issue_line_code, issue_description, rule_description
|
||||
):
|
||||
pass
|
||||
|
||||
|
||||
APPLY_SYSTEM_PROMPT = """
|
||||
Your task is apply the fix solution to the code, \
|
||||
output the whole new code in markdown code block format.
|
||||
|
||||
Here is the code file:
|
||||
{file_content}
|
||||
|
||||
Here is the fix solution:
|
||||
{fix_solution}
|
||||
|
||||
Some rules for output code:
|
||||
1. Focus on the fix solution, don't focus on other errors in the code.
|
||||
2. Don't change the indentation of the code.
|
||||
3. Don't change lines which are not metioned in fix solution, for example, \
|
||||
don't remove empty lines in code.
|
||||
|
||||
Please output only the whole new code which is the result of \
|
||||
applying the fix solution, and output the whole code.
|
||||
"""
|
||||
|
||||
|
||||
@chat(prompt=APPLY_SYSTEM_PROMPT, stream_out=True, model="deepseek-coder")
|
||||
def apply_fix_solution(file_content, fix_solution):
|
||||
pass
|
||||
|
||||
|
||||
# current file content
|
||||
def get_current_file_content(file_path, issue_line_num):
|
||||
try:
|
||||
@ -117,18 +278,150 @@ def get_rule_description(issue_description):
|
||||
return issue_description
|
||||
|
||||
|
||||
# step 4 : apply fix solutions to code
|
||||
def apply_fix_solutions_to_code():
|
||||
pass
|
||||
def get_file_content(file_path):
|
||||
try:
|
||||
with open(file_path, "r", encoding="utf-8") as file:
|
||||
return file.read()
|
||||
except Exception:
|
||||
print("Error reading file:", file=sys.stderr)
|
||||
return None
|
||||
|
||||
|
||||
# step 0: try parse user input
|
||||
def try_parse_user_input():
|
||||
pass
|
||||
GLOBAL_CONFIG_PATH = os.path.join(os.path.expanduser("~"), ".chat", ".workflow_config.json")
|
||||
|
||||
|
||||
def get_aider_python_path():
|
||||
"""
|
||||
Retrieves the path to the Aider Python executable from the global configuration file.
|
||||
|
||||
Returns:
|
||||
str or None: The path to the Aider Python executable if found in the configuration,
|
||||
or None if the configuration file doesn't exist or the path is not set.
|
||||
"""
|
||||
if os.path.exists(GLOBAL_CONFIG_PATH):
|
||||
with open(GLOBAL_CONFIG_PATH, "r", encoding="utf-8") as f:
|
||||
config = json.load(f)
|
||||
return config.get("aider_python2")
|
||||
return None
|
||||
|
||||
|
||||
def run_aider(message, file_path):
|
||||
"""
|
||||
Run the Aider tool to apply changes to a file based on a given message.
|
||||
|
||||
This function executes the Aider tool with specific parameters to apply changes
|
||||
to the specified file. It captures and returns the output from Aider.
|
||||
|
||||
Args:
|
||||
message (str): The message describing the changes to be made.
|
||||
file_path (str): The path to the file that needs to be modified.
|
||||
|
||||
Returns:
|
||||
str: The output from the Aider tool, containing information about the changes made.
|
||||
|
||||
Raises:
|
||||
SystemExit: If the Aider process returns a non-zero exit code, indicating an error.
|
||||
"""
|
||||
python = get_aider_python_path()
|
||||
model = os.environ.get("LLM_MODEL", "gpt-3.5-turbo-1106")
|
||||
|
||||
cmd = [
|
||||
python,
|
||||
"-m",
|
||||
"aider",
|
||||
"--model",
|
||||
f"openai/{model}",
|
||||
"--yes",
|
||||
"--no-auto-commits",
|
||||
"--dry-run",
|
||||
"--no-pretty",
|
||||
"--message",
|
||||
message,
|
||||
file_path,
|
||||
]
|
||||
|
||||
process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
|
||||
|
||||
has_started = False
|
||||
aider_output = ""
|
||||
for line in process.stdout:
|
||||
if "run with --help" in line or 'run "aider --help"' in line:
|
||||
has_started = True
|
||||
continue
|
||||
if has_started:
|
||||
aider_output += line
|
||||
print(line, end="", flush=True)
|
||||
|
||||
return_code = process.wait()
|
||||
|
||||
if return_code != 0:
|
||||
for line in process.stderr:
|
||||
print(f"Error: {line.strip()}", file=sys.stderr)
|
||||
sys.exit(return_code)
|
||||
|
||||
return aider_output
|
||||
|
||||
|
||||
def apply_changes(changes, file_path):
|
||||
"""
|
||||
Apply the changes to the specified file using aider.
|
||||
|
||||
Args:
|
||||
changes (str): The changes to be applied to the file.
|
||||
file_path (str): The path to the file where changes will be applied.
|
||||
|
||||
This function creates a temporary file with the changes, then uses aider to apply
|
||||
these changes to the specified file. It handles the execution of aider and manages
|
||||
the output and potential errors.
|
||||
"""
|
||||
changes_file = ".chat/changes.txt"
|
||||
os.makedirs(os.path.dirname(changes_file), exist_ok=True)
|
||||
with open(changes_file, "w", encoding="utf-8") as f:
|
||||
f.write(changes)
|
||||
|
||||
python = get_aider_python_path()
|
||||
model = os.environ.get("LLM_MODEL", "gpt-3.5-turbo-1106")
|
||||
|
||||
cmd = [
|
||||
python,
|
||||
"-m",
|
||||
"aider",
|
||||
"--model",
|
||||
f"openai/{model}",
|
||||
"--yes",
|
||||
"--no-auto-commits",
|
||||
"--apply",
|
||||
changes_file,
|
||||
file_path,
|
||||
]
|
||||
|
||||
process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
|
||||
|
||||
has_started = False
|
||||
for line in process.stdout:
|
||||
if "Model:" in line:
|
||||
has_started = True
|
||||
continue
|
||||
if has_started:
|
||||
print(line, end="", flush=True)
|
||||
|
||||
return_code = process.wait()
|
||||
|
||||
if return_code != 0:
|
||||
for line in process.stderr:
|
||||
print(f"Error: {line.strip()}", file=sys.stderr)
|
||||
sys.exit(return_code)
|
||||
|
||||
os.remove(changes_file)
|
||||
|
||||
|
||||
def main():
|
||||
print("start fix issue ...\n\n")
|
||||
"""
|
||||
Main function to fix issues in the selected code.
|
||||
It retrieves the selected code, gets issue descriptions,
|
||||
generates fix solutions using LLM, and applies the changes.
|
||||
"""
|
||||
print("start fix issue ...\n\n", flush=True)
|
||||
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)
|
||||
@ -141,20 +434,71 @@ def main():
|
||||
)
|
||||
sys.exit(0)
|
||||
|
||||
print("make llm prompt ...\n\n")
|
||||
print("make llm prompt ...\n\n", flush=True)
|
||||
current_file_content = get_current_file_content(file_path, issue_line_num)
|
||||
rule_description = get_rule_description(issue_description)
|
||||
print("--->>:", rule_description)
|
||||
# print("Rule description:\n\n", rule_description, end="\n\n")
|
||||
|
||||
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)
|
||||
print("call llm to fix issue ...\n\n", flush=True)
|
||||
|
||||
# ===> 如果aider python已经安装,则直接调用aider来执行AI访问
|
||||
aider_python = get_aider_python_path()
|
||||
|
||||
if aider_python and os.path.exists(aider_python):
|
||||
python_path = os.environ.get("PYTHONPATH", "")
|
||||
if python_path:
|
||||
# remove PYTHONPATH
|
||||
os.environ.pop("PYTHONPATH")
|
||||
# Use aider-based implementation
|
||||
message = f"""
|
||||
Fix issue: {issue_description}
|
||||
Which is reported at line: {issue_line}
|
||||
|
||||
Rule description: {rule_description}
|
||||
"""
|
||||
changes = run_aider(message, file_path)
|
||||
if not changes:
|
||||
print("No changes suggested by aider.")
|
||||
sys.exit(0)
|
||||
|
||||
print("\nApplying changes...\n", flush=True)
|
||||
|
||||
with open(file_path, "r", encoding="utf-8") as f:
|
||||
original_content = f.read()
|
||||
|
||||
apply_changes(changes, file_path)
|
||||
|
||||
with open(file_path, "r", encoding="utf-8") as f:
|
||||
updated_content = f.read()
|
||||
|
||||
with open(file_path, "w", encoding="utf-8") as f:
|
||||
f.write(original_content)
|
||||
|
||||
os.environ["PYTHONPATH"] = python_path
|
||||
|
||||
# Display changes in IDE
|
||||
IDEService().select_range(file_path, -1, -1, -1, -1)
|
||||
IDEService().diff_apply("", updated_content, False)
|
||||
else:
|
||||
print("No aider python found, using default implementation.", end="\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)
|
||||
|
||||
print("\n\n", flush=True)
|
||||
|
||||
print("apply fix solution ...\n\n")
|
||||
updated_content = extract_markdown_block(fix_solutions)
|
||||
if updated_content:
|
||||
# Display changes in IDE
|
||||
IDEService().diff_apply("", updated_content, True)
|
||||
|
||||
print("Changes have been displayed in the IDE.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
Loading…
x
Reference in New Issue
Block a user