@@ -43,6 +43,10 @@ pub(crate) fn render_tool_output(
4343 let git_styles = GitStyles :: new ( ) ;
4444 let ls_styles = LsStyles :: from_env ( ) ;
4545
46+ if tool_name == Some ( tools:: WRITE_FILE ) {
47+ render_write_file_preview ( renderer, val, & git_styles, & ls_styles) ?;
48+ }
49+
4650 if let Some ( stdout) = val. get ( "stdout" ) . and_then ( |value| value. as_str ( ) ) {
4751 render_stream_section (
4852 renderer,
@@ -510,6 +514,112 @@ fn select_stream_lines<'a>(
510514 ( tail, total, truncated)
511515}
512516
517+ fn render_write_file_preview (
518+ renderer : & mut AnsiRenderer ,
519+ payload : & Value ,
520+ git_styles : & GitStyles ,
521+ ls_styles : & LsStyles ,
522+ ) -> Result < ( ) > {
523+ let path = payload
524+ . get ( "path" )
525+ . and_then ( |value| value. as_str ( ) )
526+ . unwrap_or ( "(unknown path)" ) ;
527+ let mode = payload
528+ . get ( "mode" )
529+ . and_then ( |value| value. as_str ( ) )
530+ . unwrap_or ( "overwrite" ) ;
531+ let bytes_written = payload
532+ . get ( "bytes_written" )
533+ . and_then ( |value| value. as_u64 ( ) )
534+ . unwrap_or ( 0 ) ;
535+
536+ renderer. line ( MessageStyle :: Tool , & format ! ( "[write_file] {path}" ) ) ?;
537+ renderer. line (
538+ MessageStyle :: Info ,
539+ & format ! ( " mode={mode} | bytes={bytes_written}" ) ,
540+ ) ?;
541+
542+ let diff_value = match payload. get ( "diff_preview" ) {
543+ Some ( value) => value,
544+ None => return Ok ( ( ) ) ,
545+ } ;
546+
547+ if diff_value
548+ . get ( "skipped" )
549+ . and_then ( |value| value. as_bool ( ) )
550+ . unwrap_or ( false )
551+ {
552+ let reason = diff_value
553+ . get ( "reason" )
554+ . and_then ( |value| value. as_str ( ) )
555+ . unwrap_or ( "diff preview skipped" ) ;
556+ renderer. line (
557+ MessageStyle :: Info ,
558+ & format ! ( " diff preview skipped: {reason}" ) ,
559+ ) ?;
560+
561+ if let Some ( detail) = diff_value. get ( "detail" ) . and_then ( |value| value. as_str ( ) ) {
562+ renderer. line ( MessageStyle :: Info , & format ! ( " detail: {detail}" ) ) ?;
563+ }
564+
565+ if let Some ( max_bytes) = diff_value. get ( "max_bytes" ) . and_then ( |value| value. as_u64 ( ) ) {
566+ renderer. line (
567+ MessageStyle :: Info ,
568+ & format ! ( " preview limit: {max_bytes} bytes" ) ,
569+ ) ?;
570+ }
571+ return Ok ( ( ) ) ;
572+ }
573+
574+ let diff_content = diff_value
575+ . get ( "content" )
576+ . and_then ( |value| value. as_str ( ) )
577+ . unwrap_or ( "" ) ;
578+
579+ if diff_content. is_empty ( )
580+ && diff_value
581+ . get ( "is_empty" )
582+ . and_then ( |value| value. as_bool ( ) )
583+ . unwrap_or ( false )
584+ {
585+ renderer. line ( MessageStyle :: Info , " No diff changes to display." ) ?;
586+ }
587+
588+ if !diff_content. is_empty ( ) {
589+ renderer. line ( MessageStyle :: Tool , "[diff]" ) ?;
590+ for line in diff_content. lines ( ) {
591+ let display = format ! ( " {line}" ) ;
592+ if let Some ( style) =
593+ select_line_style ( Some ( tools:: WRITE_FILE ) , line, git_styles, ls_styles)
594+ {
595+ renderer. line_with_style ( style, & display) ?;
596+ } else {
597+ renderer. line ( MessageStyle :: Output , & display) ?;
598+ }
599+ }
600+ }
601+
602+ if diff_value
603+ . get ( "truncated" )
604+ . and_then ( |value| value. as_bool ( ) )
605+ . unwrap_or ( false )
606+ {
607+ if let Some ( omitted) = diff_value
608+ . get ( "omitted_line_count" )
609+ . and_then ( |value| value. as_u64 ( ) )
610+ {
611+ renderer. line (
612+ MessageStyle :: Info ,
613+ & format ! ( " … diff truncated ({omitted} lines omitted)" ) ,
614+ ) ?;
615+ } else {
616+ renderer. line ( MessageStyle :: Info , " … diff truncated" ) ?;
617+ }
618+ }
619+
620+ Ok ( ( ) )
621+ }
622+
513623fn render_stream_section (
514624 renderer : & mut AnsiRenderer ,
515625 title : & str ,
@@ -842,7 +952,17 @@ fn select_line_style(
842952 ls : & LsStyles ,
843953) -> Option < Style > {
844954 match tool_name {
845- Some ( "run_terminal_cmd" ) | Some ( "bash" ) => {
955+ Some ( name)
956+ if matches ! (
957+ name,
958+ tools:: RUN_TERMINAL_CMD
959+ | tools:: BASH
960+ | tools:: WRITE_FILE
961+ | tools:: EDIT_FILE
962+ | tools:: APPLY_PATCH
963+ | tools:: SRGN
964+ ) =>
965+ {
846966 let trimmed = line. trim_start ( ) ;
847967 if trimmed. starts_with ( "diff --" )
848968 || trimmed. starts_with ( "index " )
0 commit comments