mirror of
https://github.com/Aider-AI/aider.git
synced 2025-05-30 09:14:59 +00:00
fix: Implement line-by-line processing for SEARCH/REPLACE and shell code blocks
This commit is contained in:
parent
f198c4a691
commit
72bc851ac0
1 changed files with 51 additions and 76 deletions
|
@ -404,94 +404,69 @@ def strip_filename(filename, fence):
|
||||||
|
|
||||||
|
|
||||||
def find_original_update_blocks(content, fence=DEFAULT_FENCE):
|
def find_original_update_blocks(content, fence=DEFAULT_FENCE):
|
||||||
# make sure we end with a newline, otherwise the regex will miss <<UPD on the last line
|
lines = content.splitlines(keepends=True)
|
||||||
if not content.endswith("\n"):
|
i = 0
|
||||||
content = content + "\n"
|
|
||||||
|
|
||||||
pieces = re.split(split_re, content)
|
|
||||||
|
|
||||||
pieces.reverse()
|
|
||||||
processed = []
|
|
||||||
|
|
||||||
# Keep using the same filename in cases where GPT produces an edit block
|
|
||||||
# without a filename.
|
|
||||||
current_filename = None
|
current_filename = None
|
||||||
try:
|
|
||||||
while pieces:
|
|
||||||
cur = pieces.pop()
|
|
||||||
dump(repr(cur))
|
|
||||||
|
|
||||||
# Check for various shell code blocks
|
while i < len(lines):
|
||||||
shell_starts = [
|
line = lines[i]
|
||||||
"```bash",
|
|
||||||
"```sh",
|
|
||||||
"```shell", # Unix-like shells
|
|
||||||
"```cmd",
|
|
||||||
"```batch", # Windows Command Prompt
|
|
||||||
"```powershell",
|
|
||||||
"```ps1", # Windows PowerShell
|
|
||||||
"```zsh", # Z shell
|
|
||||||
"```fish", # Friendly Interactive Shell
|
|
||||||
"```ksh", # Korn Shell
|
|
||||||
"```csh",
|
|
||||||
"```tcsh", # C Shell and TENEX C Shell
|
|
||||||
]
|
|
||||||
if any(cur.strip().startswith(start) for start in shell_starts):
|
|
||||||
shell_content = []
|
|
||||||
while pieces and not pieces[-1].strip().startswith("```"):
|
|
||||||
shell_content.append(pieces.pop())
|
|
||||||
if pieces and pieces[-1].strip().startswith("```"):
|
|
||||||
pieces.pop() # Remove the closing ```
|
|
||||||
shell_type = cur.strip().split("```")[1]
|
|
||||||
yield f"{shell_type}_command", "".join(shell_content)
|
|
||||||
continue
|
|
||||||
|
|
||||||
if cur in (DIVIDER, UPDATED):
|
# Check for shell code blocks
|
||||||
processed.append(cur)
|
shell_starts = [
|
||||||
raise ValueError(f"Unexpected {cur}")
|
"```bash", "```sh", "```shell", "```cmd", "```batch",
|
||||||
|
"```powershell", "```ps1", "```zsh", "```fish", "```ksh",
|
||||||
|
"```csh", "```tcsh"
|
||||||
|
]
|
||||||
|
if any(line.strip().startswith(start) for start in shell_starts):
|
||||||
|
shell_type = line.strip().split("```")[1]
|
||||||
|
shell_content = []
|
||||||
|
i += 1
|
||||||
|
while i < len(lines) and not lines[i].strip().startswith("```"):
|
||||||
|
shell_content.append(lines[i])
|
||||||
|
i += 1
|
||||||
|
if i < len(lines) and lines[i].strip().startswith("```"):
|
||||||
|
i += 1 # Skip the closing ```
|
||||||
|
yield f"{shell_type}_command", "".join(shell_content)
|
||||||
|
continue
|
||||||
|
|
||||||
if cur.strip() != HEAD:
|
# Check for SEARCH/REPLACE blocks
|
||||||
processed.append(cur)
|
if line.strip() == HEAD:
|
||||||
continue
|
try:
|
||||||
|
filename = find_filename(lines[max(0, i-3):i], fence)
|
||||||
|
if not filename:
|
||||||
|
if current_filename:
|
||||||
|
filename = current_filename
|
||||||
|
else:
|
||||||
|
raise ValueError(missing_filename_err.format(fence=fence))
|
||||||
|
|
||||||
processed.append(cur) # original_marker
|
current_filename = filename
|
||||||
|
|
||||||
filename = find_filename(processed[-2].splitlines(), fence)
|
original_text = []
|
||||||
if not filename:
|
i += 1
|
||||||
if current_filename:
|
while i < len(lines) and not lines[i].strip() == DIVIDER:
|
||||||
filename = current_filename
|
original_text.append(lines[i])
|
||||||
else:
|
i += 1
|
||||||
raise ValueError(missing_filename_err.format(fence=fence))
|
|
||||||
|
|
||||||
current_filename = filename
|
if i >= len(lines) or lines[i].strip() != DIVIDER:
|
||||||
|
raise ValueError(f"Expected `{DIVIDER}`")
|
||||||
|
|
||||||
original_text = pieces.pop()
|
updated_text = []
|
||||||
processed.append(original_text)
|
i += 1
|
||||||
|
while i < len(lines) and not lines[i].strip() == UPDATED:
|
||||||
|
updated_text.append(lines[i])
|
||||||
|
i += 1
|
||||||
|
|
||||||
divider_marker = pieces.pop()
|
if i >= len(lines) or lines[i].strip() != UPDATED:
|
||||||
processed.append(divider_marker)
|
raise ValueError(f"Expected `{UPDATED}`")
|
||||||
if divider_marker.strip() != DIVIDER:
|
|
||||||
raise ValueError(f"Expected `{DIVIDER}` not {divider_marker.strip()}")
|
|
||||||
|
|
||||||
updated_text = pieces.pop()
|
yield filename, "".join(original_text), "".join(updated_text)
|
||||||
processed.append(updated_text)
|
|
||||||
|
|
||||||
updated_marker = pieces.pop()
|
except ValueError as e:
|
||||||
processed.append(updated_marker)
|
processed = "".join(lines[:i+1])
|
||||||
if updated_marker.strip() != UPDATED:
|
err = e.args[0]
|
||||||
raise ValueError(f"Expected `{UPDATED}` not `{updated_marker.strip()}")
|
raise ValueError(f"{processed}\n^^^ {err}")
|
||||||
|
|
||||||
yield filename, original_text, updated_text
|
i += 1
|
||||||
except ValueError as e:
|
|
||||||
processed = "".join(processed)
|
|
||||||
err = e.args[0]
|
|
||||||
raise ValueError(f"{processed}\n^^^ {err}")
|
|
||||||
except IndexError:
|
|
||||||
processed = "".join(processed)
|
|
||||||
raise ValueError(f"{processed}\n^^^ Incomplete SEARCH/REPLACE block.")
|
|
||||||
except Exception:
|
|
||||||
processed = "".join(processed)
|
|
||||||
raise ValueError(f"{processed}\n^^^ Error parsing SEARCH/REPLACE block.")
|
|
||||||
|
|
||||||
|
|
||||||
def find_filename(lines, fence):
|
def find_filename(lines, fence):
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue