@@ -130,26 +130,56 @@ enum Command {
130130 #[ clap(
131131 about = "Check the difference between this branch and another" ,
132132 long_about = "Compares the files in the current branch with the specified branch and displays the differences" ,
133- after_help = "Example:\n revtool diff dev\n revtool diff main"
133+ after_help = "Example:\n revtool diff dev\n revtool diff main\n revtool diff --content main "
134134 ) ]
135135 Diff {
136136 #[ arg( help = "Branch to compare with current branch" ) ]
137- branch : String
137+ branch : String ,
138+
139+ #[ arg( long, help = "Show content-level diffs for modified files" ) ]
140+ content : bool ,
141+
142+ #[ arg( long, help = "Number of context lines to show around changes" , default_value_t = 3 ) ]
143+ context : usize ,
144+
145+ #[ arg( long, help = "Disable colorized output" ) ]
146+ no_color : bool
138147 } ,
139148
140149 #[ clap(
141150 about = "Shows files and directories changed since the latest snapshot" ,
142151 long_about = "Outputs detailed information about which files have been added, modified, or deleted since the last snapshot" ,
143- after_help = "Example:\n revtool changes"
152+ after_help = "Example:\n revtool changes\n revtool changes --content \n revtool changes --json "
144153 ) ]
145- Changes ,
154+ Changes {
155+ #[ arg( long, help = "Show content-level diffs for modified files" ) ]
156+ content : bool ,
157+
158+ #[ arg( long, help = "Output as JSON instead of formatted text" ) ]
159+ json : bool ,
160+
161+ #[ arg( long, help = "Number of context lines to show around changes" , default_value_t = 3 ) ]
162+ context : usize ,
163+
164+ #[ arg( long, help = "Disable colorized output" ) ]
165+ no_color : bool
166+ } ,
146167
147168 #[ clap(
148169 about = "Show working tree status" ,
149170 long_about = "Shows which files have been modified, added, or deleted since the last snapshot. Similar to 'git status'" ,
150- after_help = "Example:\n revtool status"
171+ after_help = "Example:\n revtool status\n revtool status --content "
151172 ) ]
152- Status ,
173+ Status {
174+ #[ arg( long, help = "Show content-level diffs for modified files" ) ]
175+ content : bool ,
176+
177+ #[ arg( long, help = "Number of context lines to show around changes" , default_value_t = 3 ) ]
178+ context : usize ,
179+
180+ #[ arg( long, help = "Disable colorized output" ) ]
181+ no_color : bool
182+ } ,
153183
154184 #[ clap(
155185 about = "Take a new snapshot (similar to git commit)" ,
@@ -310,11 +340,17 @@ Creates a .rev directory in the current location and initializes a repository st
310340 "diff" => Some ( r#"
311341Compare changes between branches:
312342 revtool diff <branch>
343+ revtool diff --content <branch> # Show content-level diffs
344+ revtool diff --context <n> <branch> # Show n lines of context
313345
314346Examples:
315- revtool diff main # Compare current branch with main
347+ revtool diff main # Compare current branch with main
348+ revtool diff --content main # Show content-level diffs
349+ revtool diff --content --context 5 main # Show content diffs with 5 lines of context
350+ revtool diff --no-color main # Show without colors
316351
317- The diff command shows what changes would be merged if you merged the specified branch."# . to_string ( ) ) ,
352+ The diff command shows what changes would be merged if you merged the specified branch.
353+ With --content, shows line-by-line differences within modified files."# . to_string ( ) ) ,
318354 "status" => Some ( r#"
319355Show the current status of the working directory:
320356 revtool status
@@ -406,6 +442,21 @@ Use 'revtool usage <command>' for detailed help on a specific command.
406442
407443fn run_command ( cmd : Command , interactive : bool ) -> AppResult < ( ) > {
408444 use Command :: * ;
445+
446+ // Special cases that don't require an initialized repository
447+ match & cmd {
448+ // These commands should work without a repository
449+ Usage { .. } => { } ,
450+ Init => { } ,
451+ // All other commands require a repository
452+ _ => {
453+ // Only check for repository if we're not initializing or showing usage
454+ if let Err ( e) = DotRev :: here ( ) {
455+ return Err ( AppError :: DotRevError ( e) ) ;
456+ }
457+ }
458+ }
459+
409460 match cmd {
410461 Usage { command } => {
411462 match command {
@@ -481,9 +532,9 @@ fn run_command(cmd: Command, interactive: bool) -> AppResult<()> {
481532 snapshot_id. to_string( ) . cyan( ) ) ;
482533 Ok ( ( ) )
483534 }
484- Diff { branch } => {
535+ Diff { branch, content , context , no_color } => {
485536 let ( dot_rev, this_branch) = get_repository ( ) ?;
486- let mut store = dot_rev. store ( ) ?;
537+ let store = dot_rev. store ( ) ?;
487538 let that_branch = branch;
488539
489540 if !dot_rev. branch_exists ( & that_branch) ? {
@@ -494,31 +545,29 @@ fn run_command(cmd: Command, interactive: bool) -> AppResult<()> {
494545 let this_tip = dot_rev. branch_snapshot_id ( & this_branch) ?;
495546 let that_tip = dot_rev. branch_snapshot_id ( & that_branch) ?;
496547
497- // Load directory structures
498- let this_snapshot: SnapShot = store. read_json ( this_tip) ?;
499- let that_snapshot: SnapShot = store. read_json ( that_tip) ?;
500-
501- let this_branch_directory: Directory = store. read_json ( this_snapshot. directory ) ?;
502- let that_branch_directory: Directory = store. read_json ( that_snapshot. directory ) ?;
503-
504- // Calculate and display diff
505- let diff = & this_branch_directory. diff ( & that_branch_directory) ;
506- println ! ( "Diff between branch '{}' and '{}':" ,
507- this_branch. green( ) . bold( ) ,
508- that_branch. green( ) . bold( ) ) ;
509-
510- // Custom output for diff to add colors
511- for line in diff. to_string ( ) . lines ( ) {
512- if line. starts_with ( "A " ) {
513- println ! ( "{} {}" , "A" . green( ) . bold( ) , line[ 2 ..] . green( ) ) ;
514- } else if line. starts_with ( "D " ) {
515- println ! ( "{} {}" , "D" . red( ) . bold( ) , line[ 2 ..] . red( ) ) ;
516- } else if line. starts_with ( "M " ) {
517- println ! ( "{} {}" , "M" . yellow( ) . bold( ) , line[ 2 ..] . yellow( ) ) ;
518- } else {
519- println ! ( "{}" , line) ;
520- }
521- }
548+ // Generate snapshot diff
549+ let snapshot_diff = lib:: snapshot_diff:: SnapShotDiff :: generate (
550+ & store,
551+ this_tip,
552+ that_tip,
553+ content
554+ ) . map_err ( |e| AppError :: Other ( format ! ( "Failed to generate diff: {:?}" , e) ) ) ?;
555+
556+ // Import the required types first
557+ use lib:: diff_format;
558+
559+ // Create format options based on user preferences
560+ let format_options = diff_format:: FormatOptions {
561+ use_color : !no_color,
562+ show_content : content,
563+ context_lines : context,
564+ show_stats : true ,
565+ } ;
566+
567+ // Format the diff with colors
568+ let formatter = diff_format:: SnapShotDiffFormatter :: new ( & snapshot_diff, format_options) ;
569+
570+ println ! ( "{}" , formatter) ;
522571
523572 Ok ( ( ) )
524573 }
@@ -548,17 +597,24 @@ fn run_command(cmd: Command, interactive: bool) -> AppResult<()> {
548597 }
549598 } ,
550599
551- Status => {
600+ Status { content , context , no_color } => {
552601 let ( dot_rev, branch) = get_repository ( ) ?;
553602 let mut store = dot_rev. store ( ) ?;
554603 let old_tip: ObjectId = dot_rev. branch_snapshot_id ( & branch) ?;
555604 let ignores: Ignores = dot_rev. ignores ( ) ?;
556605 let cwd = current_dir ( ) ?;
606+
607+ // Calculate directory diff with or without content depending on options
557608 let directory = Directory :: new ( cwd. as_path ( ) , & ignores, & mut store)
558609 . map_err ( |e| AppError :: FailedToReadDirectory ( format ! ( "{:?}" , e) ) ) ?;
559610 let snapshot: SnapShot = store. read_json ( old_tip) ?;
560611 let old_directory: Directory = store. read_json ( snapshot. directory ) ?;
561- let diff = old_directory. diff ( & directory) ;
612+
613+ let diff = if content {
614+ old_directory. diff_with_content ( & directory, true , & store)
615+ } else {
616+ old_directory. diff ( & directory)
617+ } ;
562618
563619 println ! ( "On branch {}" , branch. green( ) . bold( ) ) ;
564620 if diff. added . is_empty ( ) && diff. deleted . is_empty ( ) && diff. modified . is_empty ( ) {
@@ -567,22 +623,25 @@ fn run_command(cmd: Command, interactive: bool) -> AppResult<()> {
567623 println ! ( "\n {}" , "Changes not yet snapped:" . yellow( ) . bold( ) ) ;
568624 println ! ( " (use \" {}\" to create a new snapshot)\n " , "revtool snap -m <message>" . cyan( ) ) ;
569625
570- for file in diff. added . keys ( ) {
571- println ! ( " {}: {}" , "new file" . green( ) . bold( ) , file) ;
572- }
626+ // Import the required types locally
627+ use lib:: diff_format;
573628
574- for file in & diff. deleted {
575- println ! ( " {}: {}" , "deleted" . red( ) . bold( ) , file) ;
576- }
629+ // Use our formatter for consistent display
630+ let format_options = diff_format:: FormatOptions {
631+ use_color : !no_color,
632+ show_content : content,
633+ context_lines : context,
634+ show_stats : true ,
635+ } ;
577636
578- for file in diff. modified . keys ( ) {
579- println ! ( " {}: {}" , "modified" . yellow( ) . bold( ) , file) ;
580- }
637+ let formatter = diff_format:: DiffFormatter :: new ( & diff, format_options) ;
638+ println ! ( "{}" , formatter) ;
581639 }
582640 Ok ( ( ) )
583641 } ,
584642
585643 Log { limit } => {
644+ // Repository existence check is now done at the beginning of the function
586645 let ( dot_rev, branch) = get_repository ( ) ?;
587646 let mut store = dot_rev. store ( ) ?;
588647 let mut snapshot_id = dot_rev. branch_snapshot_id ( & branch) ?;
@@ -673,7 +732,7 @@ fn run_command(cmd: Command, interactive: bool) -> AppResult<()> {
673732 snapshot_id. to_string( ) . cyan( ) ) ;
674733 Ok ( ( ) )
675734 }
676- Changes => {
735+ Changes { content , json , context , no_color } => {
677736 let ( dot_rev, branch) = get_repository ( ) ?;
678737 let mut store = dot_rev. store ( ) ?;
679738 let old_tip = dot_rev. branch_snapshot_id ( & branch) ?;
@@ -688,8 +747,33 @@ fn run_command(cmd: Command, interactive: bool) -> AppResult<()> {
688747 let snapshot: SnapShot = store. read_json ( old_tip) ?;
689748 let old_directory: Directory = store. read_json ( snapshot. directory ) ?;
690749
691- serde_json:: to_writer_pretty ( stdout ( ) , & old_directory. diff ( & directory) )
692- . map_err ( |e| AppError :: FailedToOutputChanges ( format ! ( "{}" , e) ) ) ?;
750+ // Generate diff with or without content
751+ let diff = if content {
752+ old_directory. diff_with_content ( & directory, true , & store)
753+ } else {
754+ old_directory. diff ( & directory)
755+ } ;
756+
757+ if json {
758+ // Output as JSON
759+ serde_json:: to_writer_pretty ( stdout ( ) , & diff)
760+ . map_err ( |e| AppError :: FailedToOutputChanges ( format ! ( "{}" , e) ) ) ?;
761+ } else {
762+ // Import the required types locally
763+ use lib:: diff_format;
764+
765+ // Format with our new formatter
766+ let format_options = diff_format:: FormatOptions {
767+ use_color : !no_color,
768+ show_content : content,
769+ context_lines : context,
770+ show_stats : true ,
771+ } ;
772+
773+ let formatter = diff_format:: DiffFormatter :: new ( & diff, format_options) ;
774+ println ! ( "{}" , formatter) ;
775+ }
776+
693777 Ok ( ( ) )
694778 }
695779 Snap { message } => {
0 commit comments