Skip to content

Commit 0450ad8

Browse files
Samuel SchlesingerSamuel Schlesinger
authored andcommitted
boop
1 parent 55100e9 commit 0450ad8

6 files changed

Lines changed: 1361 additions & 54 deletions

File tree

app/main.rs

Lines changed: 133 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -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#"
311341
Compare 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
314346
Examples:
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#"
319355
Show 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

407443
fn 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

Comments
 (0)