File size: 2,983 Bytes
dd87944
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
"""Application de diffs / remplacements sur fichiers."""
from __future__ import annotations

import re
from pathlib import Path
from typing import Any


def apply_replacement(
    path: str | Path,
    old: str,
    new: str,
    *,
    replace_all: bool = False,
) -> dict[str, Any]:
    p = Path(path).expanduser()
    if not p.is_file():
        return {"ok": False, "error": "fichier introuvable"}
    try:
        content = p.read_text(encoding="utf-8", errors="replace")
        count = content.count(old)
        if count == 0:
            return {"ok": False, "error": "old_string introuvable"}
        if not replace_all and count > 1:
            return {"ok": False, "error": f"{count} occurrences — précisez ou replace_all=true"}
        updated = content.replace(old, new) if replace_all else content.replace(old, new, 1)
        p.write_text(updated, encoding="utf-8")
        return {"ok": True, "path": str(p.resolve()), "replacements": count if replace_all else 1}
    except OSError as e:
        return {"ok": False, "error": str(e)}


def apply_unified_diff(path: str | Path, diff_text: str) -> dict[str, Any]:
    """Applique un diff unified simplifié (lignes + / -)."""
    p = Path(path).expanduser()
    if not p.is_file():
        return {"ok": False, "error": "fichier introuvable"}
    try:
        lines = p.read_text(encoding="utf-8", errors="replace").splitlines(keepends=True)
    except OSError as e:
        return {"ok": False, "error": str(e)}

    new_lines: list[str] = []
    idx = 0
    applied = 0
    for raw in diff_text.splitlines():
        if raw.startswith("+++") or raw.startswith("---") or raw.startswith("@@"):
            continue
        if raw.startswith("+"):
            new_lines.append(raw[1:] + ("\n" if not raw[1:].endswith("\n") else ""))
            applied += 1
        elif raw.startswith("-"):
            if idx < len(lines) and lines[idx].rstrip("\n") == raw[1:].rstrip("\n"):
                idx += 1
                applied += 1
            else:
                return {"ok": False, "error": f"ligne à supprimer non trouvée: {raw[1:][:60]}"}
        else:
            if idx < len(lines):
                new_lines.append(lines[idx])
                idx += 1
            elif raw.startswith(" "):
                new_lines.append(raw[1:] + "\n")

    while idx < len(lines):
        new_lines.append(lines[idx])
        idx += 1

    try:
        p.write_text("".join(new_lines), encoding="utf-8")
        return {"ok": True, "path": str(p.resolve()), "applied": applied}
    except OSError as e:
        return {"ok": False, "error": str(e)}


def write_file(path: str | Path, content: str) -> dict[str, Any]:
    p = Path(path).expanduser()
    try:
        p.parent.mkdir(parents=True, exist_ok=True)
        p.write_text(content, encoding="utf-8")
        return {"ok": True, "path": str(p.resolve()), "bytes": len(content.encode())}
    except OSError as e:
        return {"ok": False, "error": str(e)}