@@ -62,11 +62,11 @@ impl FileSystemService {
6262 let expanded_path = expand_home ( requested_path. to_path_buf ( ) ) ;
6363
6464 // Resolve the absolute path
65- let absolute_path = expanded_path
66- . as_path ( )
67- . is_absolute ( )
68- . then ( || expanded_path . clone ( ) )
69- . unwrap_or_else ( || env :: current_dir ( ) . unwrap ( ) . join ( & expanded_path ) ) ;
65+ let absolute_path = if expanded_path. as_path ( ) . is_absolute ( ) {
66+ expanded_path . clone ( )
67+ } else {
68+ env :: current_dir ( ) . unwrap ( ) . join ( & expanded_path )
69+ } ;
7070
7171 // Normalize the path
7272 let normalized_requested = normalize_path ( & absolute_path) ;
@@ -121,6 +121,16 @@ impl FileSystemService {
121121 } )
122122 }
123123
124+ fn detect_line_ending ( & self , text : & str ) -> & str {
125+ if text. contains ( "\r \n " ) {
126+ "\r \n "
127+ } else if text. contains ( '\r' ) {
128+ "\r "
129+ } else {
130+ "\n "
131+ }
132+ }
133+
124134 pub async fn zip_directory (
125135 & self ,
126136 input_dir : String ,
@@ -472,6 +482,7 @@ impl FileSystemService {
472482
473483 // Read file content and normalize line endings
474484 let content_str = tokio:: fs:: read_to_string ( & valid_path) . await ?;
485+ let original_line_ending = self . detect_line_ending ( & content_str) ;
475486 let content_str = normalize_line_endings ( & content_str) ;
476487
477488 // Apply edits sequentially
@@ -480,15 +491,13 @@ impl FileSystemService {
480491 for edit in edits {
481492 let normalized_old = normalize_line_endings ( & edit. old_text ) ;
482493 let normalized_new = normalize_line_endings ( & edit. new_text ) ;
483-
484494 // If exact match exists, use it
485495 if modified_content. contains ( & normalized_old) {
486496 modified_content = modified_content. replacen ( & normalized_old, & normalized_new, 1 ) ;
487497 continue ;
488498 }
489499
490500 // Otherwise, try line-by-line matching with flexibility for whitespace
491- // trim ends help to avoid inconsistencies empty lines at the end that may break the comparison
492501 let old_lines: Vec < String > = normalized_old
493502 . trim_end ( )
494503 . split ( '\n' )
@@ -514,7 +523,6 @@ impl FileSystemService {
514523
515524 if is_match {
516525 // Preserve original indentation of first line
517- // leading spaces
518526 let original_indent = content_lines[ i]
519527 . chars ( )
520528 . take_while ( |& c| c. is_whitespace ( ) )
@@ -524,12 +532,12 @@ impl FileSystemService {
524532 . split ( '\n' )
525533 . enumerate ( )
526534 . map ( |( j, line) | {
527- // keep indentation of the first line
535+ // Keep indentation of the first line
528536 if j == 0 {
529537 return format ! ( "{}{}" , original_indent, line. trim_start( ) ) ;
530538 }
531539
532- // For subsequent lines, try to preserve relative indentation
540+ // For subsequent lines, preserve relative indentation and original whitespace type
533541 let old_indent = old_lines
534542 . get ( j)
535543 . map ( |line| {
@@ -544,12 +552,22 @@ impl FileSystemService {
544552 . take_while ( |& c| c. is_whitespace ( ) )
545553 . collect :: < String > ( ) ;
546554
547- let relative_indent = new_indent. len ( ) - old_indent. len ( ) ;
548-
555+ // Use the same whitespace character as original_indent (tabs or spaces)
556+ let indent_char = if original_indent. contains ( '\t' ) {
557+ "\t "
558+ } else {
559+ " "
560+ } ;
561+ let relative_indent = if new_indent. len ( ) >= old_indent. len ( ) {
562+ new_indent. len ( ) - old_indent. len ( )
563+ } else {
564+ 0 // Don't reduce indentation below original
565+ } ;
549566 format ! (
550- "{}{}" ,
551- original_indent,
552- " " . repeat( relative_indent. max( 0 ) ) + line. trim_start( )
567+ "{}{}{}" ,
568+ & original_indent,
569+ & indent_char. repeat( relative_indent) ,
570+ line. trim_start( )
553571 )
554572 } )
555573 . collect ( ) ;
@@ -593,6 +611,7 @@ impl FileSystemService {
593611
594612 if !is_dry_run {
595613 let target = save_to. unwrap_or ( valid_path. as_path ( ) ) ;
614+ let modified_content = modified_content. replace ( "\n " , original_line_ending) ;
596615 tokio:: fs:: write ( target, modified_content) . await ?;
597616 }
598617
0 commit comments