77
88def save_file_contents (file_path , content ):
99 """Utility function to save content to a file."""
10- with open (file_path , "w" ) as file :
10+ with open (file_path , "w" , newline = '' ) as file :
1111 file .write (content )
1212
1313
@@ -32,30 +32,75 @@ def handle_indent(src: list[str], target: list[str], start: int, end: int) -> li
3232 return [indent + line for line in target ]
3333
3434
35+ def detect_line_ending (content : bytes ) -> str :
36+ """
37+ Detect the dominant line ending in a file.
38+ Returns '\r \n ' for CRLF or '\n ' for LF.
39+ """
40+ if b'\r \n ' in content :
41+ return '\r \n '
42+ return '\n '
43+
44+ def normalize_line_endings (text : str , line_ending : str ) -> str :
45+ """Normalize all line endings in text to the specified ending."""
46+ # First convert all line endings to \n
47+ text = text .replace ('\r \n ' , '\n ' )
48+ # Then convert all \n to desired line ending
49+ if line_ending != '\n ' :
50+ text = text .replace ('\n ' , line_ending )
51+ return text
52+
3553def replace_code_in_file (
3654 file_path : str ,
3755 start_line : int | None ,
3856 end_line : int | None ,
3957 new_code : str ,
4058) -> None :
4159 path = Path (file_path )
42- new_code_lines = new_code .splitlines (keepends = True )
43- if len (new_code_lines ) > 0 and not new_code_lines [- 1 ].endswith ("\n " ):
44- new_code_lines [- 1 ] += "\n "
45-
60+
61+ # Detect line endings from existing file
62+ if path .exists ():
63+ with open (file_path , 'rb' ) as f :
64+ content = f .read ()
65+ line_ending = detect_line_ending (content )
66+ original_content = content .decode ('utf-8' )
67+ else :
68+ line_ending = '\n ' # Default for new files
69+ original_content = ""
70+
71+ # Normalize the new code to match the file's line endings
72+ normalized_new_code = normalize_line_endings (new_code , line_ending )
73+
4674 if path .exists () and start_line is not None and end_line is not None :
47- """Replaces specified lines in a file with new code."""
48- text = path .read_text ()
49-
50- lines = text .splitlines (keepends = True )
51-
52- # Insert the new code at the start line after converting it into a list of lines
53- lines [start_line :end_line ] = handle_indent (lines , new_code_lines , start_line , end_line )
75+ # Split preserving line endings
76+ lines = original_content .splitlines (keepends = True )
77+ new_lines = normalized_new_code .splitlines (keepends = True )
78+
79+ # Handle indentation
80+ indented_new_code = handle_indent (lines , new_lines , start_line , end_line )
81+
82+ # Ensure all new lines have the correct ending
83+ final_new_code = []
84+ for line in indented_new_code :
85+ if not line .endswith (line_ending ):
86+ if line .endswith ('\n ' ) or line .endswith ('\r \n ' ):
87+ line = line .rstrip ('\r \n ' ) + line_ending
88+ else :
89+ line = line + line_ending
90+ final_new_code .append (line )
91+
92+ # Replace the lines
93+ lines [start_line :end_line ] = final_new_code
94+ final_content = '' .join (lines )
5495 else :
55- lines = new_code_lines
56-
57- # Save the modified contents back to the file
58- save_file_contents (file_path , "" .join (lines ))
96+ new_lines = normalized_new_code .splitlines (keepends = True )
97+ if not new_lines [- 1 ].endswith (line_ending ):
98+ new_lines [- 1 ] = new_lines [- 1 ].rstrip ('\r \n ' ) + line_ending
99+ final_content = '' .join (new_lines )
100+
101+ # Write the content back
102+ with open (file_path , 'wb' ) as f :
103+ f .write (final_content .encode ('utf-8' ))
59104
60105
61106class ModifyCode (Step ):
0 commit comments