@@ -37,6 +37,8 @@ pub fn run(cmd: GitCommand, args: &[String], max_lines: Option<usize>, verbose:
3737}
3838
3939fn run_diff ( args : & [ String ] , max_lines : Option < usize > , verbose : u8 ) -> Result < ( ) > {
40+ let timer = tracking:: TimedExecution :: start ( ) ;
41+
4042 // Check if user wants stat output
4143 let wants_stat = args
4244 . iter ( )
@@ -63,6 +65,14 @@ fn run_diff(args: &[String], max_lines: Option<usize>, verbose: u8) -> Result<()
6365
6466 let stdout = String :: from_utf8_lossy ( & output. stdout ) ;
6567 println ! ( "{}" , stdout. trim( ) ) ;
68+
69+ timer. track (
70+ & format ! ( "git diff {}" , args. join( " " ) ) ,
71+ & format ! ( "rtk git diff {} (passthrough)" , args. join( " " ) ) ,
72+ & stdout,
73+ & stdout,
74+ ) ;
75+
6676 return Ok ( ( ) ) ;
6777 }
6878
@@ -75,14 +85,14 @@ fn run_diff(args: &[String], max_lines: Option<usize>, verbose: u8) -> Result<()
7585 }
7686
7787 let output = cmd. output ( ) . context ( "Failed to run git diff" ) ?;
78- let stdout = String :: from_utf8_lossy ( & output. stdout ) ;
88+ let stat_stdout = String :: from_utf8_lossy ( & output. stdout ) ;
7989
8090 if verbose > 0 {
8191 eprintln ! ( "Git diff summary:" ) ;
8292 }
8393
8494 // Print stat summary first
85- println ! ( "{}" , stdout . trim( ) ) ;
95+ println ! ( "{}" , stat_stdout . trim( ) ) ;
8696
8797 // Now get actual diff but compact it
8898 let mut diff_cmd = Command :: new ( "git" ) ;
@@ -94,12 +104,22 @@ fn run_diff(args: &[String], max_lines: Option<usize>, verbose: u8) -> Result<()
94104 let diff_output = diff_cmd. output ( ) . context ( "Failed to run git diff" ) ?;
95105 let diff_stdout = String :: from_utf8_lossy ( & diff_output. stdout ) ;
96106
107+ let mut final_output = stat_stdout. to_string ( ) ;
97108 if !diff_stdout. is_empty ( ) {
98109 println ! ( "\n --- Changes ---" ) ;
99110 let compacted = compact_diff ( & diff_stdout, max_lines. unwrap_or ( 100 ) ) ;
100111 println ! ( "{}" , compacted) ;
112+ final_output. push_str ( "\n --- Changes ---\n " ) ;
113+ final_output. push_str ( & compacted) ;
101114 }
102115
116+ timer. track (
117+ & format ! ( "git diff {}" , args. join( " " ) ) ,
118+ & format ! ( "rtk git diff {}" , args. join( " " ) ) ,
119+ & format ! ( "{}\n {}" , stat_stdout, diff_stdout) ,
120+ & final_output,
121+ ) ;
122+
103123 Ok ( ( ) )
104124}
105125
@@ -259,6 +279,8 @@ pub(crate) fn compact_diff(diff: &str, max_lines: usize) -> String {
259279}
260280
261281fn run_log ( args : & [ String ] , _max_lines : Option < usize > , verbose : u8 ) -> Result < ( ) > {
282+ let timer = tracking:: TimedExecution :: start ( ) ;
283+
262284 let mut cmd = Command :: new ( "git" ) ;
263285 cmd. arg ( "log" ) ;
264286
@@ -277,9 +299,16 @@ fn run_log(args: &[String], _max_lines: Option<usize>, verbose: u8) -> Result<()
277299 cmd. args ( [ "--pretty=format:%h %s (%ar) <%an>" ] ) ;
278300 }
279301
280- if !has_limit_flag {
302+ let limit = if !has_limit_flag {
281303 cmd. arg ( "-10" ) ;
282- }
304+ 10
305+ } else {
306+ // Extract limit from args if provided
307+ args. iter ( )
308+ . find ( |arg| arg. starts_with ( '-' ) && arg. chars ( ) . nth ( 1 ) . map_or ( false , |c| c. is_ascii_digit ( ) ) )
309+ . and_then ( |arg| arg[ 1 ..] . parse :: < usize > ( ) . ok ( ) )
310+ . unwrap_or ( 10 )
311+ } ;
283312
284313 // Only add --no-merges if user didn't explicitly request merge commits
285314 let wants_merges = args
@@ -309,11 +338,38 @@ fn run_log(args: &[String], _max_lines: Option<usize>, verbose: u8) -> Result<()
309338 eprintln ! ( "Git log output:" ) ;
310339 }
311340
312- println ! ( "{}" , stdout. trim( ) ) ;
341+ // Post-process: truncate long messages, cap lines
342+ let filtered = filter_log_output ( & stdout, limit) ;
343+ println ! ( "{}" , filtered) ;
344+
345+ timer. track (
346+ & format ! ( "git log {}" , args. join( " " ) ) ,
347+ & format ! ( "rtk git log {}" , args. join( " " ) ) ,
348+ & stdout,
349+ & filtered,
350+ ) ;
313351
314352 Ok ( ( ) )
315353}
316354
355+ /// Filter git log output: truncate long messages, cap lines
356+ fn filter_log_output ( output : & str , limit : usize ) -> String {
357+ let lines: Vec < & str > = output. lines ( ) . collect ( ) ;
358+ let capped: Vec < String > = lines
359+ . iter ( )
360+ . take ( limit)
361+ . map ( |line| {
362+ if line. len ( ) > 80 {
363+ format ! ( "{}..." , & line[ ..77 ] )
364+ } else {
365+ line. to_string ( )
366+ }
367+ } )
368+ . collect ( ) ;
369+
370+ capped. join ( "\n " ) . trim ( ) . to_string ( )
371+ }
372+
317373/// Format porcelain output into compact RTK status display
318374fn format_status_output ( porcelain : & str ) -> String {
319375 let lines: Vec < & str > = porcelain. lines ( ) . collect ( ) ;
@@ -410,10 +466,44 @@ fn format_status_output(porcelain: &str) -> String {
410466 output. trim_end ( ) . to_string ( )
411467}
412468
469+ /// Minimal filtering for git status with user-provided args
470+ fn filter_status_with_args ( output : & str ) -> String {
471+ let mut result = Vec :: new ( ) ;
472+
473+ for line in output. lines ( ) {
474+ let trimmed = line. trim ( ) ;
475+
476+ // Skip empty lines
477+ if trimmed. is_empty ( ) {
478+ continue ;
479+ }
480+
481+ // Skip common git hints
482+ if trimmed. starts_with ( "(use \" git" ) {
483+ continue ;
484+ }
485+ if trimmed. starts_with ( "(create/copy files" ) {
486+ continue ;
487+ }
488+ if trimmed. contains ( "nothing to commit" ) && trimmed. contains ( "working tree clean" ) {
489+ result. push ( line. to_string ( ) ) ;
490+ break ;
491+ }
492+
493+ result. push ( line. to_string ( ) ) ;
494+ }
495+
496+ if result. is_empty ( ) {
497+ "ok ✓" . to_string ( )
498+ } else {
499+ result. join ( "\n " )
500+ }
501+ }
502+
413503fn run_status ( args : & [ String ] , verbose : u8 ) -> Result < ( ) > {
414504 let timer = tracking:: TimedExecution :: start ( ) ;
415505
416- // If user provided flags, pass through to git without RTK formatting
506+ // If user provided flags, apply minimal filtering
417507 if !args. is_empty ( ) {
418508 let output = Command :: new ( "git" )
419509 . arg ( "status" )
@@ -428,14 +518,15 @@ fn run_status(args: &[String], verbose: u8) -> Result<()> {
428518 eprint ! ( "{}" , stderr) ;
429519 }
430520
431- print ! ( "{}" , stdout) ;
521+ // Apply minimal filtering: strip ANSI, remove hints, empty lines
522+ let filtered = filter_status_with_args ( & stdout) ;
523+ print ! ( "{}" , filtered) ;
432524
433- // Track passthrough mode
434525 timer. track (
435526 & format ! ( "git status {}" , args. join( " " ) ) ,
436- & format ! ( "rtk git status {} (passthrough)" , args. join( " " ) ) ,
437- & stdout,
527+ & format ! ( "rtk git status {}" , args. join( " " ) ) ,
438528 & stdout,
529+ & filtered,
439530 ) ;
440531
441532 return Ok ( ( ) ) ;
@@ -466,6 +557,8 @@ fn run_status(args: &[String], verbose: u8) -> Result<()> {
466557}
467558
468559fn run_add ( files : & [ String ] , verbose : u8 ) -> Result < ( ) > {
560+ let timer = tracking:: TimedExecution :: start ( ) ;
561+
469562 let mut cmd = Command :: new ( "git" ) ;
470563 cmd. arg ( "add" ) ;
471564
@@ -483,6 +576,12 @@ fn run_add(files: &[String], verbose: u8) -> Result<()> {
483576 eprintln ! ( "git add executed" ) ;
484577 }
485578
579+ let raw_output = format ! (
580+ "{}\n {}" ,
581+ String :: from_utf8_lossy( & output. stdout) ,
582+ String :: from_utf8_lossy( & output. stderr)
583+ ) ;
584+
486585 if output. status . success ( ) {
487586 // Count what was added
488587 let status_output = Command :: new ( "git" )
@@ -491,17 +590,26 @@ fn run_add(files: &[String], verbose: u8) -> Result<()> {
491590 . context ( "Failed to check staged files" ) ?;
492591
493592 let stat = String :: from_utf8_lossy ( & status_output. stdout ) ;
494- if stat. trim ( ) . is_empty ( ) {
495- println ! ( "ok (nothing to add)" ) ;
593+ let compact = if stat. trim ( ) . is_empty ( ) {
594+ "ok (nothing to add)" . to_string ( )
496595 } else {
497596 // Parse "1 file changed, 5 insertions(+)" format
498597 let short = stat. lines ( ) . last ( ) . unwrap_or ( "" ) . trim ( ) ;
499598 if short. is_empty ( ) {
500- println ! ( "ok ✓" ) ;
599+ "ok ✓" . to_string ( )
501600 } else {
502- println ! ( "ok ✓ {}" , short) ;
601+ format ! ( "ok ✓ {}" , short)
503602 }
504- }
603+ } ;
604+
605+ println ! ( "{}" , compact) ;
606+
607+ timer. track (
608+ & format ! ( "git add {}" , files. join( " " ) ) ,
609+ & format ! ( "rtk git add {}" , files. join( " " ) ) ,
610+ & raw_output,
611+ & compact,
612+ ) ;
505613 } else {
506614 let stderr = String :: from_utf8_lossy ( & output. stderr ) ;
507615 let stdout = String :: from_utf8_lossy ( & output. stdout ) ;
@@ -518,6 +626,8 @@ fn run_add(files: &[String], verbose: u8) -> Result<()> {
518626}
519627
520628fn run_commit ( message : & str , verbose : u8 ) -> Result < ( ) > {
629+ let timer = tracking:: TimedExecution :: start ( ) ;
630+
521631 if verbose > 0 {
522632 eprintln ! ( "git commit -m \" {}\" " , message) ;
523633 }
@@ -527,24 +637,44 @@ fn run_commit(message: &str, verbose: u8) -> Result<()> {
527637 . output ( )
528638 . context ( "Failed to run git commit" ) ?;
529639
640+ let stdout = String :: from_utf8_lossy ( & output. stdout ) ;
641+ let stderr = String :: from_utf8_lossy ( & output. stderr ) ;
642+ let raw_output = format ! ( "{}\n {}" , stdout, stderr) ;
643+
530644 if output. status . success ( ) {
531- let stdout = String :: from_utf8_lossy ( & output. stdout ) ;
532645 // Extract commit hash from output like "[main abc1234] message"
533- if let Some ( line) = stdout. lines ( ) . next ( ) {
646+ let compact = if let Some ( line) = stdout. lines ( ) . next ( ) {
534647 if let Some ( hash_start) = line. find ( ' ' ) {
535648 let hash = line[ 1 ..hash_start] . split ( ' ' ) . last ( ) . unwrap_or ( "" ) ;
536649 if !hash. is_empty ( ) && hash. len ( ) >= 7 {
537- println ! ( "ok ✓ {}" , & hash[ ..7 . min( hash. len( ) ) ] ) ;
538- return Ok ( ( ) ) ;
650+ format ! ( "ok ✓ {}" , & hash[ ..7 . min( hash. len( ) ) ] )
651+ } else {
652+ "ok ✓" . to_string ( )
539653 }
654+ } else {
655+ "ok ✓" . to_string ( )
540656 }
541- }
542- println ! ( "ok ✓" ) ;
657+ } else {
658+ "ok ✓" . to_string ( )
659+ } ;
660+
661+ println ! ( "{}" , compact) ;
662+
663+ timer. track (
664+ & format ! ( "git commit -m \" {}\" " , message) ,
665+ "rtk git commit" ,
666+ & raw_output,
667+ & compact,
668+ ) ;
543669 } else {
544- let stderr = String :: from_utf8_lossy ( & output. stderr ) ;
545- let stdout = String :: from_utf8_lossy ( & output. stdout ) ;
546670 if stderr. contains ( "nothing to commit" ) || stdout. contains ( "nothing to commit" ) {
547671 println ! ( "ok (nothing to commit)" ) ;
672+ timer. track (
673+ & format ! ( "git commit -m \" {}\" " , message) ,
674+ "rtk git commit" ,
675+ & raw_output,
676+ "ok (nothing to commit)" ,
677+ ) ;
548678 } else {
549679 eprintln ! ( "FAILED: git commit" ) ;
550680 if !stderr. trim ( ) . is_empty ( ) {
@@ -609,6 +739,8 @@ fn run_push(args: &[String], verbose: u8) -> Result<()> {
609739}
610740
611741fn run_pull ( args : & [ String ] , verbose : u8 ) -> Result < ( ) > {
742+ let timer = tracking:: TimedExecution :: start ( ) ;
743+
612744 if verbose > 0 {
613745 eprintln ! ( "git pull" ) ;
614746 }
@@ -623,10 +755,11 @@ fn run_pull(args: &[String], verbose: u8) -> Result<()> {
623755
624756 let stdout = String :: from_utf8_lossy ( & output. stdout ) ;
625757 let stderr = String :: from_utf8_lossy ( & output. stderr ) ;
758+ let raw_output = format ! ( "{}\n {}" , stdout, stderr) ;
626759
627760 if output. status . success ( ) {
628- if stdout. contains ( "Already up to date" ) || stdout. contains ( "Already up-to-date" ) {
629- println ! ( "ok (up-to-date)" ) ;
761+ let compact = if stdout. contains ( "Already up to date" ) || stdout. contains ( "Already up-to-date" ) {
762+ "ok (up-to-date)" . to_string ( )
630763 } else {
631764 // Count files changed
632765 let mut files = 0 ;
@@ -662,11 +795,20 @@ fn run_pull(args: &[String], verbose: u8) -> Result<()> {
662795 }
663796
664797 if files > 0 {
665- println ! ( "ok ✓ {} files +{} -{}" , files, insertions, deletions) ;
798+ format ! ( "ok ✓ {} files +{} -{}" , files, insertions, deletions)
666799 } else {
667- println ! ( "ok ✓" ) ;
800+ "ok ✓" . to_string ( )
668801 }
669- }
802+ } ;
803+
804+ println ! ( "{}" , compact) ;
805+
806+ timer. track (
807+ & format ! ( "git pull {}" , args. join( " " ) ) ,
808+ & format ! ( "rtk git pull {}" , args. join( " " ) ) ,
809+ & raw_output,
810+ & compact,
811+ ) ;
670812 } else {
671813 eprintln ! ( "FAILED: git pull" ) ;
672814 if !stderr. trim ( ) . is_empty ( ) {
0 commit comments