truncate_expected_patch.rs

 1use crate::example::{Example, read_example_files};
 2use crate::reorder_patch::{Hunk, Patch, PatchLine};
 3use clap::Args;
 4use std::path::PathBuf;
 5
 6#[derive(Args, Debug, Clone)]
 7pub struct TruncatePatchArgs {
 8    /// Number of logical groups ahead to leave
 9    #[arg(long)]
10    pub num_groups: usize,
11
12    /// Leave only edits in the file under the cursor
13    #[arg(long, default_value_t = false)]
14    pub current_file_only: bool,
15}
16
17pub fn run_truncate_expected_patch(
18    args: &TruncatePatchArgs,
19    inputs: &[PathBuf],
20) -> anyhow::Result<()> {
21    let stdin_path = PathBuf::from("-");
22    let inputs = if inputs.is_empty() {
23        std::slice::from_ref(&stdin_path)
24    } else {
25        inputs
26    };
27
28    let mut examples = read_example_files(inputs);
29    for example in &mut examples {
30        run_one_input(example, args)?;
31
32        println!("{}", serde_json::to_string(&example)?);
33    }
34    Ok(())
35}
36
37fn run_one_input(example: &mut Example, args: &TruncatePatchArgs) -> anyhow::Result<()> {
38    let mut patch = Patch::parse_unified_diff(&example.spec.expected_patches[0]);
39    let mut groups_left = args.num_groups;
40
41    patch.hunks.retain(|hunk| {
42        if groups_left == 0 {
43            return false;
44        }
45        if starts_new_group(hunk) {
46            groups_left -= 1;
47        }
48
49        if args.current_file_only {
50            return hunk.filename == example.spec.cursor_path.display().to_string();
51        }
52
53        true
54    });
55
56    // Remove all group headers
57    patch.header = String::new();
58    patch.hunks.iter_mut().for_each(|hunk| {
59        hunk.lines.retain(|line| match line {
60            PatchLine::Garbage(line) => !line.starts_with("//"),
61            _ => true,
62        });
63    });
64
65    example.spec.expected_patches[0] = patch.to_string();
66
67    Ok(())
68}
69
70fn starts_new_group(hunk: &Hunk) -> bool {
71    hunk.lines.iter().any(|line| match line {
72        PatchLine::Garbage(content) => content.starts_with("///"),
73        _ => false,
74    })
75}