Prepopulate empty patch in example capture (#46480)

Max Brunsfeld created

This makes it a smoother workflow to capture an edit prediction example
from Zed and then write what you'd expect the patch to be.

Release Notes:

- N/A

Change summary

crates/edit_prediction/src/capture_example.rs       | 72 +++++++++++++-
crates/edit_prediction/src/edit_prediction.rs       |  1 
crates/edit_prediction_ui/src/edit_prediction_ui.rs |  2 
3 files changed, 65 insertions(+), 10 deletions(-)

Detailed changes

crates/edit_prediction/src/capture_example.rs 🔗

@@ -9,8 +9,8 @@ use feature_flags::FeatureFlagAppExt as _;
 use gpui::{App, Entity, Task};
 use language::{Buffer, ToPoint as _};
 use project::{Project, WorktreeId};
-use std::{collections::hash_map, fmt::Write as _, path::Path, sync::Arc};
-use text::BufferSnapshot as TextBufferSnapshot;
+use std::{collections::hash_map, fmt::Write as _, ops::Range, path::Path, sync::Arc};
+use text::{BufferSnapshot as TextBufferSnapshot, Point};
 
 pub(crate) const DEFAULT_EXAMPLE_CAPTURE_RATE_PER_10K_PREDICTIONS: u16 = 10;
 
@@ -19,6 +19,7 @@ pub fn capture_example(
     buffer: Entity<Buffer>,
     cursor_anchor: language::Anchor,
     mut events: Vec<StoredEvent>,
+    populate_expected_patch: bool,
     cx: &mut App,
 ) -> Option<Task<Result<ExampleSpec>>> {
     let snapshot = buffer.read(cx).snapshot();
@@ -56,7 +57,7 @@ pub fn capture_example(
             .and_then(|lang| lang.config().line_comments.first())
             .map(|s| s.to_string())
             .unwrap_or_default();
-        let (cursor_excerpt, cursor_offset) = cx
+        let (cursor_excerpt, cursor_offset, cursor_excerpt_range) = cx
             .background_executor()
             .spawn(async move { compute_cursor_excerpt(&snapshot, cursor_anchor) })
             .await;
@@ -73,6 +74,27 @@ pub fn capture_example(
             }
         }
 
+        // Initialize an empty patch with context lines, to make it easy
+        // to write the expected patch by hand.
+        let mut expected_patches = Vec::new();
+        if populate_expected_patch {
+            let mut empty_patch = String::new();
+            let start_row = cursor_excerpt_range.start.row + 1;
+            let row_count = cursor_excerpt_range.end.row - cursor_excerpt_range.start.row + 1;
+            writeln!(&mut empty_patch, "--- a/{}", cursor_path.display()).ok();
+            writeln!(&mut empty_patch, "+++ b/{}", cursor_path.display()).ok();
+            writeln!(
+                &mut empty_patch,
+                "@@ -{},{} +{},{} @@",
+                start_row, row_count, start_row, row_count,
+            )
+            .ok();
+            for line in cursor_excerpt.lines() {
+                writeln!(&mut empty_patch, " {}", line).ok();
+            }
+            expected_patches.push(empty_patch);
+        }
+
         let mut spec = ExampleSpec {
             name: generate_timestamp_name(),
             repository_url,
@@ -83,7 +105,7 @@ pub fn capture_example(
             cursor_path,
             cursor_position: String::new(),
             edit_history,
-            expected_patches: Vec::new(),
+            expected_patches,
         };
         spec.set_cursor_excerpt(&cursor_excerpt, cursor_offset, &line_comment_prefix);
         Ok(spec)
@@ -124,7 +146,7 @@ fn write_event_with_relative_paths(
 fn compute_cursor_excerpt(
     snapshot: &language::BufferSnapshot,
     cursor_anchor: language::Anchor,
-) -> (String, usize) {
+) -> (String, usize, Range<Point>) {
     use text::ToOffset as _;
 
     let cursor_point = cursor_anchor.to_point(snapshot);
@@ -133,8 +155,10 @@ fn compute_cursor_excerpt(
     let context_start_offset = context_range.start.to_offset(snapshot);
     let cursor_offset = cursor_anchor.to_offset(snapshot);
     let cursor_offset_in_excerpt = cursor_offset.saturating_sub(context_start_offset);
-    let excerpt = snapshot.text_for_range(context_range).collect::<String>();
-    (excerpt, cursor_offset_in_excerpt)
+    let excerpt = snapshot
+        .text_for_range(context_range.clone())
+        .collect::<String>();
+    (excerpt, cursor_offset_in_excerpt, context_range)
 }
 
 async fn collect_snapshots(
@@ -375,7 +399,15 @@ mod tests {
 
         let mut example = cx
             .update(|cx| {
-                capture_example(project.clone(), buffer.clone(), Anchor::MIN, events, cx).unwrap()
+                capture_example(
+                    project.clone(),
+                    buffer.clone(),
+                    Anchor::MIN,
+                    events,
+                    true,
+                    cx,
+                )
+                .unwrap()
             })
             .await
             .unwrap();
@@ -443,7 +475,29 @@ mod tests {
                          seven();
                 "}
                 .to_string(),
-                expected_patches: Vec::new()
+                expected_patches: vec![
+                    indoc! {"
+                    --- a/src/main.rs
+                    +++ b/src/main.rs
+                    @@ -1,16 +1,16 @@
+                     fn main() {
+                         // comment 1
+                         one();
+                         two();
+                         // comment 4
+                         three();
+                         four();
+                         // comment 3
+                         five();
+                         six();
+                         seven();
+                         eight();
+                         // comment 2
+                         nine();
+                     }
+                "}
+                    .to_string()
+                ]
             }
         );
     }

crates/edit_prediction_ui/src/edit_prediction_ui.rs 🔗

@@ -154,7 +154,7 @@ fn capture_example_as_markdown(
     let events = ep_store.update(cx, |store, cx| {
         store.edit_history_for_project_with_pause_split_last_event(&project, cx)
     });
-    let example = capture_example(project.clone(), buffer, cursor_anchor, events, cx)?;
+    let example = capture_example(project.clone(), buffer, cursor_anchor, events, true, cx)?;
 
     let examples_dir = AllLanguageSettings::get_global(cx)
         .edit_predictions