1313 from robocop .source_file import SourceFile
1414
1515
16+ class TextEditKind (Enum ):
17+ """
18+ Enumeration of edit operation types.
19+
20+ Attributes:
21+ REPLACEMENT (str): Replace an existing line or part of it with the new content.
22+ INSERTION (str): Insert a new line or lines without changing existing lines.
23+ DELETION (str): Delete line or lines.
24+
25+ """
26+
27+ REPLACEMENT = "replace"
28+ INSERTION = "insert"
29+ DELETION = "delete"
30+
31+
1632@dataclass
1733class TextEdit :
1834 """
@@ -38,11 +54,18 @@ class TextEdit:
3854 rule_id : str
3955 rule_name : str
4056 start_line : int
41- start_col : int
42- end_line : int
43- start_line : int
44- end_col : int
45- replacement : str
57+ start_col : int | None
58+ end_line : int | None
59+ end_col : int | None
60+ replacement : str | None
61+
62+ @property
63+ def kind (self ) -> TextEditKind :
64+ if self .replacement is None :
65+ return TextEditKind .DELETION
66+ if self .end_line is None :
67+ return TextEditKind .INSERTION
68+ return TextEditKind .REPLACEMENT
4669
4770 @classmethod
4871 def replace_at_range (cls , rule_id : str , rule_name : str , diag_range : Range , replacement : str ) -> TextEdit :
@@ -56,6 +79,32 @@ def replace_at_range(cls, rule_id: str, rule_name: str, diag_range: Range, repla
5679 replacement = replacement ,
5780 )
5881
82+ @classmethod
83+ def remove_at_range (cls , rule_id : str , rule_name : str , diag_range : Range ) -> TextEdit :
84+ """Remove lines between start_line and end_line from the edit range."""
85+ return cls (
86+ rule_id = rule_id ,
87+ rule_name = rule_name ,
88+ start_line = diag_range .start .line ,
89+ start_col = None ,
90+ end_line = diag_range .end .line ,
91+ end_col = None ,
92+ replacement = None ,
93+ )
94+
95+ @classmethod
96+ def insert_at_range (cls , rule_id : str , rule_name : str , diag_range : Range , replacement : str ) -> TextEdit :
97+ """Insert new content at start_line."""
98+ return cls (
99+ rule_id = rule_id ,
100+ rule_name = rule_name ,
101+ start_line = diag_range .start .line ,
102+ start_col = None ,
103+ end_line = None ,
104+ end_col = None ,
105+ replacement = replacement ,
106+ )
107+
59108
60109class FixApplicability (Enum ):
61110 """
@@ -220,17 +269,24 @@ def _apply_edit(lines: list[str], edit: TextEdit) -> None:
220269 edit: The edit to apply (uses 1-indexed line/col numbers).
221270
222271 """
223- if edit .end_line > len (lines ) or edit .start_line < 1 :
224- return
225- start_line_idx = edit .start_line - 1
226- end_line_idx = edit .end_line - 1
227- start_col_idx = edit .start_col - 1
228- end_col_idx = edit .end_col - 1
229-
230- if start_line_idx == end_line_idx : # single line
231- line = lines [edit .start_line - 1 ] # TODO: store for diff view, + surrounding lines
232- new_line = line [:start_col_idx ] + edit .replacement + line [end_col_idx :]
233- lines [start_line_idx ] = new_line
234- else : # Multi-line edit
235- # When edit is multiline, we replace the lines fully
236- lines [start_line_idx : end_line_idx + 2 ] = [edit .replacement ]
272+ if edit .kind == TextEditKind .REPLACEMENT :
273+ if edit .end_line > len (lines ) or edit .start_line < 1 :
274+ return
275+ start_line_idx = edit .start_line - 1
276+ end_line_idx = edit .end_line - 1
277+ start_col_idx = edit .start_col - 1
278+ end_col_idx = edit .end_col - 1
279+
280+ if start_line_idx == end_line_idx : # single line
281+ line = lines [edit .start_line - 1 ]
282+ new_line = line [:start_col_idx ] + edit .replacement + line [end_col_idx :]
283+ lines [start_line_idx ] = new_line
284+ else : # Multi-line edit
285+ # When edit is multiline, we replace the lines fully
286+ lines [start_line_idx : end_line_idx + 2 ] = [edit .replacement ]
287+ elif edit .kind == TextEditKind .INSERTION :
288+ start_line_idx = edit .start_line - 1
289+ lines .insert (start_line_idx , edit .replacement )
290+ else : # edit.kind == TextEditKind.DELETION
291+ start_line_idx = edit .start_line - 1
292+ del lines [start_line_idx : edit .end_line ]
0 commit comments